1/*
2 * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebProcess.h"
28
29#include "AuthenticationManager.h"
30#include "DownloadManager.h"
31#include "InjectedBundle.h"
32#include "InjectedBundleMessageKinds.h"
33#include "InjectedBundleUserMessageCoders.h"
34#include "RunLoop.h"
35#include "SandboxExtension.h"
36#include "WebApplicationCacheManager.h"
37#include "WebContextMessages.h"
38#include "WebCookieManager.h"
39#include "WebCoreArgumentCoders.h"
40#include "WebDatabaseManager.h"
41#include "WebFrame.h"
42#include "WebGeolocationManagerMessages.h"
43#include "WebKeyValueStorageManager.h"
44#include "WebMediaCacheManager.h"
45#include "WebMemorySampler.h"
46#include "WebPage.h"
47#include "WebPageCreationParameters.h"
48#include "WebPlatformStrategies.h"
49#include "WebPreferencesStore.h"
50#include "WebProcessCreationParameters.h"
51#include "WebProcessMessages.h"
52#include "WebProcessProxyMessages.h"
53#include "WebResourceCacheManager.h"
54#include <WebCore/AXObjectCache.h>
55#include <WebCore/ApplicationCacheStorage.h>
56#include <WebCore/CrossOriginPreflightResultCache.h>
57#include <WebCore/Font.h>
58#include <WebCore/Language.h>
59#include <WebCore/Logging.h>
60#include <WebCore/MemoryCache.h>
61#include <WebCore/Page.h>
62#include <WebCore/PageCache.h>
63#include <WebCore/PageGroup.h>
64#include <WebCore/ResourceHandle.h>
65#include <WebCore/SchemeRegistry.h>
66#include <WebCore/SecurityOrigin.h>
67#include <WebCore/Settings.h>
68#include <WebCore/StorageTracker.h>
69#include <wtf/PassRefPtr.h>
70#include <wtf/RandomNumber.h>
71
72#ifndef NDEBUG
73#include <WebCore/GCController.h>
74#endif
75
76#if !OS(WINDOWS)
77#include <unistd.h>
78#endif
79
80#if !ENABLE(PLUGIN_PROCESS)
81#include "NetscapePluginModule.h"
82#endif
83
84using namespace WebCore;
85
86namespace WebKit {
87
88#if OS(WINDOWS)
89static void sleep(unsigned seconds)
90{
91    ::Sleep(seconds * 1000);
92}
93#endif
94
95static void* randomCrashThread(void*)
96{
97    // This delay was chosen semi-arbitrarily. We want the crash to happen somewhat quickly to
98    // enable useful stress testing, but not so quickly that the web process will always crash soon
99    // after launch.
100    static const unsigned maximumRandomCrashDelay = 180;
101
102    sleep(randomNumber() * maximumRandomCrashDelay);
103    CRASH();
104    return 0;
105}
106
107static void startRandomCrashThreadIfRequested()
108{
109    if (!getenv("WEBKIT2_CRASH_WEB_PROCESS_RANDOMLY"))
110        return;
111    createThread(randomCrashThread, 0, "WebKit2: Random Crash Thread");
112}
113
114WebProcess& WebProcess::shared()
115{
116    static WebProcess& process = *new WebProcess;
117    return process;
118}
119
120static const double shutdownTimeout = 60;
121
122WebProcess::WebProcess()
123    : ChildProcess(shutdownTimeout)
124    , m_inDidClose(false)
125    , m_hasSetCacheModel(false)
126    , m_cacheModel(CacheModelDocumentViewer)
127#if USE(ACCELERATED_COMPOSITING) && PLATFORM(MAC)
128    , m_compositingRenderServerPort(MACH_PORT_NULL)
129#endif
130#if PLATFORM(QT)
131    , m_networkAccessManager(0)
132#endif
133    , m_textCheckerState()
134    , m_geolocationManager(this)
135    , m_iconDatabaseProxy(this)
136{
137#if USE(PLATFORM_STRATEGIES)
138    // Initialize our platform strategies.
139    WebPlatformStrategies::initialize();
140#endif // USE(PLATFORM_STRATEGIES)
141
142    WebCore::InitializeLoggingChannelsIfNecessary();
143}
144
145void WebProcess::initialize(CoreIPC::Connection::Identifier serverIdentifier, RunLoop* runLoop)
146{
147    ASSERT(!m_connection);
148
149    m_connection = CoreIPC::Connection::createClientConnection(serverIdentifier, this, runLoop);
150    m_connection->setDidCloseOnConnectionWorkQueueCallback(didCloseOnConnectionWorkQueue);
151    m_connection->setShouldExitOnSyncMessageSendFailure(true);
152
153    m_connection->open();
154
155    m_runLoop = runLoop;
156
157    startRandomCrashThreadIfRequested();
158}
159
160void WebProcess::initializeWebProcess(const WebProcessCreationParameters& parameters, CoreIPC::ArgumentDecoder* arguments)
161{
162    ASSERT(m_pageMap.isEmpty());
163
164    platformInitializeWebProcess(parameters, arguments);
165
166    RefPtr<APIObject> injectedBundleInitializationUserData;
167    InjectedBundleUserMessageDecoder messageDecoder(injectedBundleInitializationUserData);
168    if (!arguments->decode(messageDecoder))
169        return;
170
171    if (!parameters.injectedBundlePath.isEmpty()) {
172        m_injectedBundle = InjectedBundle::create(parameters.injectedBundlePath);
173        m_injectedBundle->setSandboxExtension(SandboxExtension::create(parameters.injectedBundlePathExtensionHandle));
174
175        if (!m_injectedBundle->load(injectedBundleInitializationUserData.get())) {
176            // Don't keep around the InjectedBundle reference if the load fails.
177            m_injectedBundle.clear();
178        }
179    }
180
181#if ENABLE(DATABASE)
182    // Make sure the WebDatabaseManager is initialized so that the Database directory is set.
183    WebDatabaseManager::initialize(parameters.databaseDirectory);
184#endif
185
186#if ENABLE(ICONDATABASE)
187    m_iconDatabaseProxy.setEnabled(parameters.iconDatabaseEnabled);
188#endif
189
190#if ENABLE(DOM_STORAGE)
191    StorageTracker::initializeTracker(parameters.localStorageDirectory);
192    m_localStorageDirectory = parameters.localStorageDirectory;
193#endif
194
195#if ENABLE(OFFLINE_WEB_APPLICATIONS)
196    if (!parameters.applicationCacheDirectory.isEmpty())
197        cacheStorage().setCacheDirectory(parameters.applicationCacheDirectory);
198#endif
199
200    setShouldTrackVisitedLinks(parameters.shouldTrackVisitedLinks);
201    setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
202
203    if (!parameters.languageCode.isEmpty())
204        overrideDefaultLanguage(parameters.languageCode);
205
206    m_textCheckerState = parameters.textCheckerState;
207
208    for (size_t i = 0; i < parameters.urlSchemesRegistererdAsEmptyDocument.size(); ++i)
209        registerURLSchemeAsEmptyDocument(parameters.urlSchemesRegistererdAsEmptyDocument[i]);
210
211    for (size_t i = 0; i < parameters.urlSchemesRegisteredAsSecure.size(); ++i)
212        registerURLSchemeAsSecure(parameters.urlSchemesRegisteredAsSecure[i]);
213
214    for (size_t i = 0; i < parameters.urlSchemesForWhichDomainRelaxationIsForbidden.size(); ++i)
215        setDomainRelaxationForbiddenForURLScheme(parameters.urlSchemesForWhichDomainRelaxationIsForbidden[i]);
216
217    setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
218
219    for (size_t i = 0; i < parameters.mimeTypesWithCustomRepresentation.size(); ++i)
220        m_mimeTypesWithCustomRepresentations.add(parameters.mimeTypesWithCustomRepresentation[i]);
221
222#if PLATFORM(MAC)
223    m_presenterApplicationPid = parameters.presenterApplicationPid;
224#endif
225
226    if (parameters.shouldAlwaysUseComplexTextCodePath)
227        setAlwaysUsesComplexTextCodePath(true);
228
229#if USE(CFURLSTORAGESESSIONS)
230    WebCore::ResourceHandle::setPrivateBrowsingStorageSessionIdentifierBase(parameters.uiProcessBundleIdentifier);
231#endif
232}
233
234void WebProcess::setShouldTrackVisitedLinks(bool shouldTrackVisitedLinks)
235{
236    PageGroup::setShouldTrackVisitedLinks(shouldTrackVisitedLinks);
237}
238
239void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
240{
241    SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
242}
243
244void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
245{
246    SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
247}
248
249void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
250{
251    SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
252}
253
254void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
255{
256    ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
257}
258
259void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
260{
261    WebCore::Font::setCodePath(alwaysUseComplexText ? WebCore::Font::Complex : WebCore::Font::Auto);
262}
263
264void WebProcess::languageChanged(const String& language) const
265{
266    overrideDefaultLanguage(language);
267}
268
269void WebProcess::setVisitedLinkTable(const SharedMemory::Handle& handle)
270{
271    RefPtr<SharedMemory> sharedMemory = SharedMemory::create(handle, SharedMemory::ReadOnly);
272    if (!sharedMemory)
273        return;
274
275    m_visitedLinkTable.setSharedMemory(sharedMemory.release());
276}
277
278void WebProcess::visitedLinkStateChanged(const Vector<WebCore::LinkHash>& linkHashes)
279{
280    // FIXME: We may want to track visited links per WebPageGroup rather than per WebContext.
281    for (size_t i = 0; i < linkHashes.size(); ++i) {
282        HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator it = m_pageGroupMap.begin();
283        HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator end = m_pageGroupMap.end();
284        for (; it != end; ++it)
285            Page::visitedStateChanged(PageGroup::pageGroup(it->second->identifier()), linkHashes[i]);
286    }
287
288    pageCache()->markPagesForVistedLinkStyleRecalc();
289}
290
291void WebProcess::allVisitedLinkStateChanged()
292{
293    // FIXME: We may want to track visited links per WebPageGroup rather than per WebContext.
294    HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator it = m_pageGroupMap.begin();
295    HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::const_iterator end = m_pageGroupMap.end();
296    for (; it != end; ++it)
297        Page::allVisitedStateChanged(PageGroup::pageGroup(it->second->identifier()));
298
299    pageCache()->markPagesForVistedLinkStyleRecalc();
300}
301
302bool WebProcess::isLinkVisited(LinkHash linkHash) const
303{
304    return m_visitedLinkTable.isLinkVisited(linkHash);
305}
306
307void WebProcess::addVisitedLink(WebCore::LinkHash linkHash)
308{
309    if (isLinkVisited(linkHash))
310        return;
311    m_connection->send(Messages::WebContext::AddVisitedLinkHash(linkHash), 0);
312}
313
314#if !PLATFORM(MAC)
315bool WebProcess::fullKeyboardAccessEnabled()
316{
317    return false;
318}
319#endif
320
321void WebProcess::setCacheModel(uint32_t cm)
322{
323    CacheModel cacheModel = static_cast<CacheModel>(cm);
324
325    if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
326        m_hasSetCacheModel = true;
327        m_cacheModel = cacheModel;
328        platformSetCacheModel(cacheModel);
329    }
330}
331
332void WebProcess::calculateCacheSizes(CacheModel cacheModel, uint64_t memorySize, uint64_t diskFreeSize,
333    unsigned& cacheTotalCapacity, unsigned& cacheMinDeadCapacity, unsigned& cacheMaxDeadCapacity, double& deadDecodedDataDeletionInterval,
334    unsigned& pageCacheCapacity, unsigned long& urlCacheMemoryCapacity, unsigned long& urlCacheDiskCapacity)
335{
336    switch (cacheModel) {
337    case CacheModelDocumentViewer: {
338        // Page cache capacity (in pages)
339        pageCacheCapacity = 0;
340
341        // Object cache capacities (in bytes)
342        if (memorySize >= 2048)
343            cacheTotalCapacity = 96 * 1024 * 1024;
344        else if (memorySize >= 1536)
345            cacheTotalCapacity = 64 * 1024 * 1024;
346        else if (memorySize >= 1024)
347            cacheTotalCapacity = 32 * 1024 * 1024;
348        else if (memorySize >= 512)
349            cacheTotalCapacity = 16 * 1024 * 1024;
350
351        cacheMinDeadCapacity = 0;
352        cacheMaxDeadCapacity = 0;
353
354        // Foundation memory cache capacity (in bytes)
355        urlCacheMemoryCapacity = 0;
356
357        // Foundation disk cache capacity (in bytes)
358        urlCacheDiskCapacity = 0;
359
360        break;
361    }
362    case CacheModelDocumentBrowser: {
363        // Page cache capacity (in pages)
364        if (memorySize >= 1024)
365            pageCacheCapacity = 3;
366        else if (memorySize >= 512)
367            pageCacheCapacity = 2;
368        else if (memorySize >= 256)
369            pageCacheCapacity = 1;
370        else
371            pageCacheCapacity = 0;
372
373        // Object cache capacities (in bytes)
374        if (memorySize >= 2048)
375            cacheTotalCapacity = 96 * 1024 * 1024;
376        else if (memorySize >= 1536)
377            cacheTotalCapacity = 64 * 1024 * 1024;
378        else if (memorySize >= 1024)
379            cacheTotalCapacity = 32 * 1024 * 1024;
380        else if (memorySize >= 512)
381            cacheTotalCapacity = 16 * 1024 * 1024;
382
383        cacheMinDeadCapacity = cacheTotalCapacity / 8;
384        cacheMaxDeadCapacity = cacheTotalCapacity / 4;
385
386        // Foundation memory cache capacity (in bytes)
387        if (memorySize >= 2048)
388            urlCacheMemoryCapacity = 4 * 1024 * 1024;
389        else if (memorySize >= 1024)
390            urlCacheMemoryCapacity = 2 * 1024 * 1024;
391        else if (memorySize >= 512)
392            urlCacheMemoryCapacity = 1 * 1024 * 1024;
393        else
394            urlCacheMemoryCapacity =      512 * 1024;
395
396        // Foundation disk cache capacity (in bytes)
397        if (diskFreeSize >= 16384)
398            urlCacheDiskCapacity = 50 * 1024 * 1024;
399        else if (diskFreeSize >= 8192)
400            urlCacheDiskCapacity = 40 * 1024 * 1024;
401        else if (diskFreeSize >= 4096)
402            urlCacheDiskCapacity = 30 * 1024 * 1024;
403        else
404            urlCacheDiskCapacity = 20 * 1024 * 1024;
405
406        break;
407    }
408    case CacheModelPrimaryWebBrowser: {
409        // Page cache capacity (in pages)
410        // (Research indicates that value / page drops substantially after 3 pages.)
411        if (memorySize >= 2048)
412            pageCacheCapacity = 5;
413        else if (memorySize >= 1024)
414            pageCacheCapacity = 4;
415        else if (memorySize >= 512)
416            pageCacheCapacity = 3;
417        else if (memorySize >= 256)
418            pageCacheCapacity = 2;
419        else
420            pageCacheCapacity = 1;
421
422        // Object cache capacities (in bytes)
423        // (Testing indicates that value / MB depends heavily on content and
424        // browsing pattern. Even growth above 128MB can have substantial
425        // value / MB for some content / browsing patterns.)
426        if (memorySize >= 2048)
427            cacheTotalCapacity = 128 * 1024 * 1024;
428        else if (memorySize >= 1536)
429            cacheTotalCapacity = 96 * 1024 * 1024;
430        else if (memorySize >= 1024)
431            cacheTotalCapacity = 64 * 1024 * 1024;
432        else if (memorySize >= 512)
433            cacheTotalCapacity = 32 * 1024 * 1024;
434
435        cacheMinDeadCapacity = cacheTotalCapacity / 4;
436        cacheMaxDeadCapacity = cacheTotalCapacity / 2;
437
438        // This code is here to avoid a PLT regression. We can remove it if we
439        // can prove that the overall system gain would justify the regression.
440        cacheMaxDeadCapacity = std::max(24u, cacheMaxDeadCapacity);
441
442        deadDecodedDataDeletionInterval = 60;
443
444        // Foundation memory cache capacity (in bytes)
445        // (These values are small because WebCore does most caching itself.)
446        if (memorySize >= 1024)
447            urlCacheMemoryCapacity = 4 * 1024 * 1024;
448        else if (memorySize >= 512)
449            urlCacheMemoryCapacity = 2 * 1024 * 1024;
450        else if (memorySize >= 256)
451            urlCacheMemoryCapacity = 1 * 1024 * 1024;
452        else
453            urlCacheMemoryCapacity =      512 * 1024;
454
455        // Foundation disk cache capacity (in bytes)
456        if (diskFreeSize >= 16384)
457            urlCacheDiskCapacity = 175 * 1024 * 1024;
458        else if (diskFreeSize >= 8192)
459            urlCacheDiskCapacity = 150 * 1024 * 1024;
460        else if (diskFreeSize >= 4096)
461            urlCacheDiskCapacity = 125 * 1024 * 1024;
462        else if (diskFreeSize >= 2048)
463            urlCacheDiskCapacity = 100 * 1024 * 1024;
464        else if (diskFreeSize >= 1024)
465            urlCacheDiskCapacity = 75 * 1024 * 1024;
466        else
467            urlCacheDiskCapacity = 50 * 1024 * 1024;
468
469        break;
470    }
471    default:
472        ASSERT_NOT_REACHED();
473    };
474}
475
476WebPage* WebProcess::focusedWebPage() const
477{
478    HashMap<uint64_t, RefPtr<WebPage> >::const_iterator end = m_pageMap.end();
479    for (HashMap<uint64_t, RefPtr<WebPage> >::const_iterator it = m_pageMap.begin(); it != end; ++it) {
480        WebPage* page = (*it).second.get();
481        if (page->windowIsFocused())
482            return page;
483    }
484    return 0;
485}
486
487WebPage* WebProcess::webPage(uint64_t pageID) const
488{
489    return m_pageMap.get(pageID).get();
490}
491
492void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
493{
494    // It is necessary to check for page existence here since during a window.open() (or targeted
495    // link) the WebPage gets created both in the synchronous handler and through the normal way.
496    std::pair<HashMap<uint64_t, RefPtr<WebPage> >::iterator, bool> result = m_pageMap.add(pageID, 0);
497    if (result.second) {
498        ASSERT(!result.first->second);
499        result.first->second = WebPage::create(pageID, parameters);
500
501        // Balanced by an enableTermination in removeWebPage.
502        disableTermination();
503    }
504
505    ASSERT(result.first->second);
506}
507
508void WebProcess::removeWebPage(uint64_t pageID)
509{
510    ASSERT(m_pageMap.contains(pageID));
511
512    m_pageMap.remove(pageID);
513
514    enableTermination();
515}
516
517bool WebProcess::isSeparateProcess() const
518{
519    // If we're running on the main run loop, we assume that we're in a separate process.
520    return m_runLoop == RunLoop::main();
521}
522
523bool WebProcess::shouldTerminate()
524{
525    // Keep running forever if we're running in the same process.
526    if (!isSeparateProcess())
527        return false;
528
529    ASSERT(m_pageMap.isEmpty());
530    ASSERT(!DownloadManager::shared().isDownloading());
531
532    // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
533    bool shouldTerminate = false;
534    if (m_connection->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
535        && !shouldTerminate)
536        return false;
537
538    return true;
539}
540
541void WebProcess::terminate()
542{
543#ifndef NDEBUG
544    gcController().garbageCollectNow();
545    memoryCache()->setDisabled(true);
546#endif
547
548    // Invalidate our connection.
549    m_connection->invalidate();
550    m_connection = nullptr;
551
552    platformTerminate();
553    m_runLoop->stop();
554}
555
556CoreIPC::SyncReplyMode WebProcess::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
557{
558    uint64_t pageID = arguments->destinationID();
559    if (!pageID)
560        return CoreIPC::AutomaticReply;
561
562    WebPage* page = webPage(pageID);
563    if (!page)
564        return CoreIPC::AutomaticReply;
565
566    page->didReceiveSyncMessage(connection, messageID, arguments, reply);
567    return CoreIPC::AutomaticReply;
568}
569
570void WebProcess::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
571{
572    if (messageID.is<CoreIPC::MessageClassWebProcess>()) {
573        didReceiveWebProcessMessage(connection, messageID, arguments);
574        return;
575    }
576
577    if (messageID.is<CoreIPC::MessageClassAuthenticationManager>()) {
578        AuthenticationManager::shared().didReceiveMessage(connection, messageID, arguments);
579        return;
580    }
581
582    if (messageID.is<CoreIPC::MessageClassWebApplicationCacheManager>()) {
583        WebApplicationCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
584        return;
585    }
586
587    if (messageID.is<CoreIPC::MessageClassWebCookieManager>()) {
588        WebCookieManager::shared().didReceiveMessage(connection, messageID, arguments);
589        return;
590    }
591
592    if (messageID.is<CoreIPC::MessageClassWebDatabaseManager>()) {
593        WebDatabaseManager::shared().didReceiveMessage(connection, messageID, arguments);
594        return;
595    }
596
597    if (messageID.is<CoreIPC::MessageClassWebGeolocationManager>()) {
598        m_geolocationManager.didReceiveMessage(connection, messageID, arguments);
599        return;
600    }
601
602    if (messageID.is<CoreIPC::MessageClassWebIconDatabaseProxy>()) {
603        m_iconDatabaseProxy.didReceiveMessage(connection, messageID, arguments);
604        return;
605    }
606
607    if (messageID.is<CoreIPC::MessageClassWebKeyValueStorageManager>()) {
608        WebKeyValueStorageManager::shared().didReceiveMessage(connection, messageID, arguments);
609        return;
610    }
611
612    if (messageID.is<CoreIPC::MessageClassWebMediaCacheManager>()) {
613        WebMediaCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
614        return;
615    }
616
617    if (messageID.is<CoreIPC::MessageClassWebResourceCacheManager>()) {
618        WebResourceCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
619        return;
620    }
621
622    if (messageID.is<CoreIPC::MessageClassInjectedBundle>()) {
623        if (!m_injectedBundle)
624            return;
625        m_injectedBundle->didReceiveMessage(connection, messageID, arguments);
626        return;
627    }
628
629    uint64_t pageID = arguments->destinationID();
630    if (!pageID)
631        return;
632
633    WebPage* page = webPage(pageID);
634    if (!page)
635        return;
636
637    page->didReceiveMessage(connection, messageID, arguments);
638}
639
640void WebProcess::didClose(CoreIPC::Connection*)
641{
642    // When running in the same process the connection will never be closed.
643    ASSERT(isSeparateProcess());
644
645#ifndef NDEBUG
646    m_inDidClose = true;
647
648    // Close all the live pages.
649    Vector<RefPtr<WebPage> > pages;
650    copyValuesToVector(m_pageMap, pages);
651    for (size_t i = 0; i < pages.size(); ++i)
652        pages[i]->close();
653    pages.clear();
654
655    gcController().garbageCollectNow();
656    memoryCache()->setDisabled(true);
657#endif
658
659    // The UI process closed this connection, shut down.
660    m_runLoop->stop();
661}
662
663void WebProcess::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
664{
665    // We received an invalid message, but since this is from the UI process (which we trust),
666    // we'll let it slide.
667}
668
669void WebProcess::syncMessageSendTimedOut(CoreIPC::Connection*)
670{
671}
672
673WebFrame* WebProcess::webFrame(uint64_t frameID) const
674{
675    return m_frameMap.get(frameID);
676}
677
678void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
679{
680    m_frameMap.set(frameID, frame);
681}
682
683void WebProcess::removeWebFrame(uint64_t frameID)
684{
685    m_frameMap.remove(frameID);
686
687    // We can end up here after our connection has closed when WebCore's frame life-support timer
688    // fires when the application is shutting down. There's no need (and no way) to update the UI
689    // process in this case.
690    if (!m_connection)
691        return;
692
693    m_connection->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
694}
695
696WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
697{
698    return m_pageGroupMap.get(pageGroupID).get();
699}
700
701WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
702{
703    std::pair<HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::iterator, bool> result = m_pageGroupMap.add(pageGroupData.pageGroupID, 0);
704    if (result.second) {
705        ASSERT(!result.first->second);
706        result.first->second = WebPageGroupProxy::create(pageGroupData);
707    }
708
709    return result.first->second.get();
710}
711
712void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
713{
714    platformClearResourceCaches(resourceCachesToClear);
715
716    // Toggling the cache model like this forces the cache to evict all its in-memory resources.
717    // FIXME: We need a better way to do this.
718    CacheModel cacheModel = m_cacheModel;
719    setCacheModel(CacheModelDocumentViewer);
720    setCacheModel(cacheModel);
721
722    memoryCache()->evictResources();
723
724    // Empty the cross-origin preflight cache.
725    CrossOriginPreflightResultCache::shared().empty();
726}
727
728void WebProcess::clearApplicationCache()
729{
730#if ENABLE(OFFLINE_WEB_APPLICATIONS)
731    // Empty the application cache.
732    cacheStorage().empty();
733#endif
734}
735
736#if !ENABLE(PLUGIN_PROCESS)
737void WebProcess::getSitesWithPluginData(const Vector<String>& pluginPaths, uint64_t callbackID)
738{
739    LocalTerminationDisabler terminationDisabler(*this);
740
741    HashSet<String> sitesSet;
742
743    for (size_t i = 0; i < pluginPaths.size(); ++i) {
744        RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
745        if (!netscapePluginModule)
746            continue;
747
748        Vector<String> sites = netscapePluginModule->sitesWithData();
749        for (size_t i = 0; i < sites.size(); ++i)
750            sitesSet.add(sites[i]);
751    }
752
753    Vector<String> sites;
754    copyToVector(sitesSet, sites);
755
756    m_connection->send(Messages::WebContext::DidGetSitesWithPluginData(sites, callbackID), 0);
757}
758
759void WebProcess::clearPluginSiteData(const Vector<String>& pluginPaths, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
760{
761    LocalTerminationDisabler terminationDisabler(*this);
762
763    for (size_t i = 0; i < pluginPaths.size(); ++i) {
764        RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
765        if (!netscapePluginModule)
766            continue;
767
768        if (sites.isEmpty()) {
769            // Clear everything.
770            netscapePluginModule->clearSiteData(String(), flags, maxAgeInSeconds);
771            continue;
772        }
773
774        for (size_t i = 0; i < sites.size(); ++i)
775            netscapePluginModule->clearSiteData(sites[i], flags, maxAgeInSeconds);
776    }
777
778    m_connection->send(Messages::WebContext::DidClearPluginSiteData(callbackID), 0);
779}
780#endif
781
782void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
783{
784    WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
785
786    DownloadManager::shared().startDownload(downloadID, initiatingPage, request);
787}
788
789void WebProcess::cancelDownload(uint64_t downloadID)
790{
791    DownloadManager::shared().cancelDownload(downloadID);
792}
793
794void WebProcess::setEnhancedAccessibility(bool flag)
795{
796    WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
797}
798
799void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
800{
801#if ENABLE(MEMORY_SAMPLER)
802    WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval);
803#endif
804}
805
806void WebProcess::stopMemorySampler()
807{
808#if ENABLE(MEMORY_SAMPLER)
809    WebMemorySampler::shared()->stop();
810#endif
811}
812
813void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
814{
815    bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
816    bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
817
818    m_textCheckerState = textCheckerState;
819
820    if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
821        return;
822
823    HashMap<uint64_t, RefPtr<WebPage> >::iterator end = m_pageMap.end();
824    for (HashMap<uint64_t, RefPtr<WebPage> >::iterator it = m_pageMap.begin(); it != end; ++it) {
825        WebPage* page = (*it).second.get();
826        if (continuousSpellCheckingTurnedOff)
827            page->unmarkAllMisspellings();
828        if (grammarCheckingTurnedOff)
829            page->unmarkAllBadGrammar();
830    }
831}
832
833} // namespace WebKit
834