cae2872345431da85cf4aa2e9aff6b0f29d294da
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebProcess.cpp
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 "WebResourceCacheManager.h"
37 #include "WebContextMessages.h"
38 #include "WebCoreArgumentCoders.h"
39 #include "WebDatabaseManager.h"
40 #include "WebFrame.h"
41 #include "WebGeolocationManagerMessages.h"
42 #include "WebMemorySampler.h"
43 #include "WebPage.h"
44 #include "WebPageCreationParameters.h"
45 #include "WebPlatformStrategies.h"
46 #include "WebPreferencesStore.h"
47 #include "WebProcessCreationParameters.h"
48 #include "WebProcessMessages.h"
49 #include "WebProcessProxyMessages.h"
50 #include <WebCore/ApplicationCacheStorage.h>
51 #include <WebCore/CrossOriginPreflightResultCache.h>
52 #include <WebCore/Font.h>
53 #include <WebCore/Language.h>
54 #include <WebCore/MemoryCache.h>
55 #include <WebCore/Page.h>
56 #include <WebCore/PageGroup.h>
57 #include <WebCore/SchemeRegistry.h>
58 #include <WebCore/SecurityOrigin.h>
59 #include <WebCore/Settings.h>
60 #include <wtf/PassRefPtr.h>
61 #include <wtf/RandomNumber.h>
62
63 #ifndef NDEBUG
64 #include <WebCore/MemoryCache.h>
65 #include <WebCore/GCController.h>
66 #endif
67
68 #if !OS(WINDOWS)
69 #include <unistd.h>
70 #endif
71
72 #if !ENABLE(PLUGIN_PROCESS)
73 #include "NetscapePluginModule.h"
74 #endif
75
76 using namespace WebCore;
77
78 namespace WebKit {
79
80 #if OS(WINDOWS)
81 static void sleep(unsigned seconds)
82 {
83     ::Sleep(seconds * 1000);
84 }
85 #endif
86
87 static void* randomCrashThread(void*)
88 {
89     // This delay was chosen semi-arbitrarily. We want the crash to happen somewhat quickly to
90     // enable useful stress testing, but not so quickly that the web process will always crash soon
91     // after launch.
92     static const unsigned maximumRandomCrashDelay = 180;
93
94     sleep(randomNumber() * maximumRandomCrashDelay);
95     CRASH();
96     return 0;
97 }
98
99 static void startRandomCrashThreadIfRequested()
100 {
101     if (!getenv("WEBKIT2_CRASH_WEB_PROCESS_RANDOMLY"))
102         return;
103     createThread(randomCrashThread, 0, "WebKit2: Random Crash Thread");
104 }
105
106 WebProcess& WebProcess::shared()
107 {
108     static WebProcess& process = *new WebProcess;
109     return process;
110 }
111
112 WebProcess::WebProcess()
113     : m_inDidClose(false)
114     , m_hasSetCacheModel(false)
115     , m_cacheModel(CacheModelDocumentViewer)
116 #if USE(ACCELERATED_COMPOSITING) && PLATFORM(MAC)
117     , m_compositingRenderServerPort(MACH_PORT_NULL)
118 #endif
119 #if PLATFORM(QT)
120     , m_networkAccessManager(0)
121 #endif
122     , m_textCheckerState()
123     , m_geolocationManager(this)
124 {
125 #if USE(PLATFORM_STRATEGIES)
126     // Initialize our platform strategies.
127     WebPlatformStrategies::initialize();
128 #endif // USE(PLATFORM_STRATEGIES)
129 }
130
131 void WebProcess::initialize(CoreIPC::Connection::Identifier serverIdentifier, RunLoop* runLoop)
132 {
133     ASSERT(!m_connection);
134
135     m_connection = CoreIPC::Connection::createClientConnection(serverIdentifier, this, runLoop);
136     m_connection->setDidCloseOnConnectionWorkQueueCallback(didCloseOnConnectionWorkQueue);
137
138     m_connection->open();
139
140     m_runLoop = runLoop;
141
142     startRandomCrashThreadIfRequested();
143 }
144
145 void WebProcess::initializeWebProcess(const WebProcessCreationParameters& parameters, CoreIPC::ArgumentDecoder* arguments)
146 {
147     ASSERT(m_pageMap.isEmpty());
148
149     platformInitializeWebProcess(parameters, arguments);
150
151     RefPtr<APIObject> injectedBundleInitializationUserData;
152     InjectedBundleUserMessageDecoder messageDecoder(injectedBundleInitializationUserData);
153     if (!arguments->decode(messageDecoder))
154         return;
155
156     if (!parameters.injectedBundlePath.isEmpty()) {
157         m_injectedBundle = InjectedBundle::create(parameters.injectedBundlePath);
158         m_injectedBundle->setSandboxExtension(SandboxExtension::create(parameters.injectedBundlePathExtensionHandle));
159
160         if (!m_injectedBundle->load(injectedBundleInitializationUserData.get())) {
161             // Don't keep around the InjectedBundle reference if the load fails.
162             m_injectedBundle.clear();
163         }
164     }
165
166 #if ENABLE(DATABASE)
167     // Make sure the WebDatabaseManager is initialized so that the Database directory is set.
168     WebDatabaseManager::initialize(parameters.databaseDirectory);
169 #endif
170
171 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
172     if (!parameters.applicationCacheDirectory.isEmpty())
173         cacheStorage().setCacheDirectory(parameters.applicationCacheDirectory);
174 #endif
175
176     setShouldTrackVisitedLinks(parameters.shouldTrackVisitedLinks);
177     setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
178
179     if (!parameters.languageCode.isEmpty())
180         overrideDefaultLanguage(parameters.languageCode);
181
182     m_textCheckerState = parameters.textCheckerState;
183
184     for (size_t i = 0; i < parameters.urlSchemesRegistererdAsEmptyDocument.size(); ++i)
185         registerURLSchemeAsEmptyDocument(parameters.urlSchemesRegistererdAsEmptyDocument[i]);
186
187     for (size_t i = 0; i < parameters.urlSchemesRegisteredAsSecure.size(); ++i)
188         registerURLSchemeAsSecure(parameters.urlSchemesRegisteredAsSecure[i]);
189
190     for (size_t i = 0; i < parameters.urlSchemesForWhichDomainRelaxationIsForbidden.size(); ++i)
191         setDomainRelaxationForbiddenForURLScheme(parameters.urlSchemesForWhichDomainRelaxationIsForbidden[i]);
192
193     for (size_t i = 0; i < parameters.mimeTypesWithCustomRepresentation.size(); ++i)
194         m_mimeTypesWithCustomRepresentations.add(parameters.mimeTypesWithCustomRepresentation[i]);
195
196     if (parameters.clearResourceCaches)
197         clearResourceCaches();
198     if (parameters.clearApplicationCache)
199         clearApplicationCache();
200     
201 #if PLATFORM(MAC)
202     m_presenterApplicationPid = parameters.presenterApplicationPid;
203 #endif
204
205     if (parameters.shouldAlwaysUseComplexTextCodePath)
206         setAlwaysUsesComplexTextCodePath(true);
207 }
208
209 void WebProcess::setShouldTrackVisitedLinks(bool shouldTrackVisitedLinks)
210 {
211     PageGroup::setShouldTrackVisitedLinks(shouldTrackVisitedLinks);
212 }
213
214 void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
215 {
216     SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
217 }
218
219 void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
220 {
221     SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
222 }
223
224 void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
225 {
226     SecurityOrigin::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
227 }
228
229 void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
230 {
231     WebCore::Font::setCodePath(alwaysUseComplexText ? WebCore::Font::Complex : WebCore::Font::Auto);
232 }
233
234 void WebProcess::languageChanged(const String& language) const
235 {
236     overrideDefaultLanguage(language);
237 }
238
239 void WebProcess::setVisitedLinkTable(const SharedMemory::Handle& handle)
240 {
241     RefPtr<SharedMemory> sharedMemory = SharedMemory::create(handle, SharedMemory::ReadOnly);
242     if (!sharedMemory)
243         return;
244
245     m_visitedLinkTable.setSharedMemory(sharedMemory.release());
246 }
247
248 PageGroup* WebProcess::sharedPageGroup()
249 {
250     return PageGroup::pageGroup("WebKit2Group");
251 }
252
253 void WebProcess::visitedLinkStateChanged(const Vector<WebCore::LinkHash>& linkHashes)
254 {
255     for (size_t i = 0; i < linkHashes.size(); ++i)
256         Page::visitedStateChanged(sharedPageGroup(), linkHashes[i]);
257 }
258
259 void WebProcess::allVisitedLinkStateChanged()
260 {
261     Page::allVisitedStateChanged(sharedPageGroup());
262 }
263
264 bool WebProcess::isLinkVisited(LinkHash linkHash) const
265 {
266     return m_visitedLinkTable.isLinkVisited(linkHash);
267 }
268
269 void WebProcess::addVisitedLink(WebCore::LinkHash linkHash)
270 {
271     if (isLinkVisited(linkHash))
272         return;
273     m_connection->send(Messages::WebContext::AddVisitedLinkHash(linkHash), 0);
274 }
275
276 void WebProcess::setCacheModel(uint32_t cm)
277 {
278     CacheModel cacheModel = static_cast<CacheModel>(cm);
279
280     if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
281         m_hasSetCacheModel = true;
282         m_cacheModel = cacheModel;
283         platformSetCacheModel(cacheModel);
284     }
285 }
286
287 void WebProcess::calculateCacheSizes(CacheModel cacheModel, uint64_t memorySize, uint64_t diskFreeSize,
288     unsigned& cacheTotalCapacity, unsigned& cacheMinDeadCapacity, unsigned& cacheMaxDeadCapacity, double& deadDecodedDataDeletionInterval,
289     unsigned& pageCacheCapacity, unsigned long& urlCacheMemoryCapacity, unsigned long& urlCacheDiskCapacity)
290 {
291     switch (cacheModel) {
292     case CacheModelDocumentViewer: {
293         // Page cache capacity (in pages)
294         pageCacheCapacity = 0;
295
296         // Object cache capacities (in bytes)
297         if (memorySize >= 2048)
298             cacheTotalCapacity = 96 * 1024 * 1024;
299         else if (memorySize >= 1536)
300             cacheTotalCapacity = 64 * 1024 * 1024;
301         else if (memorySize >= 1024)
302             cacheTotalCapacity = 32 * 1024 * 1024;
303         else if (memorySize >= 512)
304             cacheTotalCapacity = 16 * 1024 * 1024;
305
306         cacheMinDeadCapacity = 0;
307         cacheMaxDeadCapacity = 0;
308
309         // Foundation memory cache capacity (in bytes)
310         urlCacheMemoryCapacity = 0;
311
312         // Foundation disk cache capacity (in bytes)
313         urlCacheDiskCapacity = 0;
314
315         break;
316     }
317     case CacheModelDocumentBrowser: {
318         // Page cache capacity (in pages)
319         if (memorySize >= 1024)
320             pageCacheCapacity = 3;
321         else if (memorySize >= 512)
322             pageCacheCapacity = 2;
323         else if (memorySize >= 256)
324             pageCacheCapacity = 1;
325         else
326             pageCacheCapacity = 0;
327
328         // Object cache capacities (in bytes)
329         if (memorySize >= 2048)
330             cacheTotalCapacity = 96 * 1024 * 1024;
331         else if (memorySize >= 1536)
332             cacheTotalCapacity = 64 * 1024 * 1024;
333         else if (memorySize >= 1024)
334             cacheTotalCapacity = 32 * 1024 * 1024;
335         else if (memorySize >= 512)
336             cacheTotalCapacity = 16 * 1024 * 1024;
337
338         cacheMinDeadCapacity = cacheTotalCapacity / 8;
339         cacheMaxDeadCapacity = cacheTotalCapacity / 4;
340
341         // Foundation memory cache capacity (in bytes)
342         if (memorySize >= 2048)
343             urlCacheMemoryCapacity = 4 * 1024 * 1024;
344         else if (memorySize >= 1024)
345             urlCacheMemoryCapacity = 2 * 1024 * 1024;
346         else if (memorySize >= 512)
347             urlCacheMemoryCapacity = 1 * 1024 * 1024;
348         else
349             urlCacheMemoryCapacity =      512 * 1024; 
350
351         // Foundation disk cache capacity (in bytes)
352         if (diskFreeSize >= 16384)
353             urlCacheDiskCapacity = 50 * 1024 * 1024;
354         else if (diskFreeSize >= 8192)
355             urlCacheDiskCapacity = 40 * 1024 * 1024;
356         else if (diskFreeSize >= 4096)
357             urlCacheDiskCapacity = 30 * 1024 * 1024;
358         else
359             urlCacheDiskCapacity = 20 * 1024 * 1024;
360
361         break;
362     }
363     case CacheModelPrimaryWebBrowser: {
364         // Page cache capacity (in pages)
365         // (Research indicates that value / page drops substantially after 3 pages.)
366         if (memorySize >= 2048)
367             pageCacheCapacity = 5;
368         else if (memorySize >= 1024)
369             pageCacheCapacity = 4;
370         else if (memorySize >= 512)
371             pageCacheCapacity = 3;
372         else if (memorySize >= 256)
373             pageCacheCapacity = 2;
374         else
375             pageCacheCapacity = 1;
376
377         // Object cache capacities (in bytes)
378         // (Testing indicates that value / MB depends heavily on content and
379         // browsing pattern. Even growth above 128MB can have substantial 
380         // value / MB for some content / browsing patterns.)
381         if (memorySize >= 2048)
382             cacheTotalCapacity = 128 * 1024 * 1024;
383         else if (memorySize >= 1536)
384             cacheTotalCapacity = 96 * 1024 * 1024;
385         else if (memorySize >= 1024)
386             cacheTotalCapacity = 64 * 1024 * 1024;
387         else if (memorySize >= 512)
388             cacheTotalCapacity = 32 * 1024 * 1024;
389
390         cacheMinDeadCapacity = cacheTotalCapacity / 4;
391         cacheMaxDeadCapacity = cacheTotalCapacity / 2;
392
393         // This code is here to avoid a PLT regression. We can remove it if we
394         // can prove that the overall system gain would justify the regression.
395         cacheMaxDeadCapacity = std::max(24u, cacheMaxDeadCapacity);
396
397         deadDecodedDataDeletionInterval = 60;
398
399         // Foundation memory cache capacity (in bytes)
400         // (These values are small because WebCore does most caching itself.)
401         if (memorySize >= 1024)
402             urlCacheMemoryCapacity = 4 * 1024 * 1024;
403         else if (memorySize >= 512)
404             urlCacheMemoryCapacity = 2 * 1024 * 1024;
405         else if (memorySize >= 256)
406             urlCacheMemoryCapacity = 1 * 1024 * 1024;
407         else
408             urlCacheMemoryCapacity =      512 * 1024; 
409
410         // Foundation disk cache capacity (in bytes)
411         if (diskFreeSize >= 16384)
412             urlCacheDiskCapacity = 175 * 1024 * 1024;
413         else if (diskFreeSize >= 8192)
414             urlCacheDiskCapacity = 150 * 1024 * 1024;
415         else if (diskFreeSize >= 4096)
416             urlCacheDiskCapacity = 125 * 1024 * 1024;
417         else if (diskFreeSize >= 2048)
418             urlCacheDiskCapacity = 100 * 1024 * 1024;
419         else if (diskFreeSize >= 1024)
420             urlCacheDiskCapacity = 75 * 1024 * 1024;
421         else
422             urlCacheDiskCapacity = 50 * 1024 * 1024;
423
424         break;
425     }
426     default:
427         ASSERT_NOT_REACHED();
428     };
429 }
430
431 WebPage* WebProcess::webPage(uint64_t pageID) const
432 {
433     return m_pageMap.get(pageID).get();
434 }
435
436 void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
437 {
438     // It is necessary to check for page existence here since during a window.open() (or targeted
439     // link) the WebPage gets created both in the synchronous handler and through the normal way. 
440     std::pair<HashMap<uint64_t, RefPtr<WebPage> >::iterator, bool> result = m_pageMap.add(pageID, 0);
441     if (result.second) {
442         ASSERT(!result.first->second);
443         result.first->second = WebPage::create(pageID, parameters);
444     }
445
446     ASSERT(result.first->second);
447 }
448
449 void WebProcess::removeWebPage(uint64_t pageID)
450 {
451     m_pageMap.remove(pageID);
452
453     shutdownIfPossible();
454 }
455
456 bool WebProcess::isSeparateProcess() const
457 {
458     // If we're running on the main run loop, we assume that we're in a separate process.
459     return m_runLoop == RunLoop::main();
460 }
461  
462 void WebProcess::shutdownIfPossible()
463 {
464     if (!m_pageMap.isEmpty())
465         return;
466
467     if (m_inDidClose)
468         return;
469
470     if (DownloadManager::shared().isDownloading())
471         return;
472
473     // Keep running forever if we're running in the same process.
474     if (!isSeparateProcess())
475         return;
476
477     // Actually shut down the process.
478
479 #ifndef NDEBUG
480     gcController().garbageCollectNow();
481     memoryCache()->setDisabled(true);
482 #endif
483
484     // Invalidate our connection.
485     m_connection->invalidate();
486     m_connection = nullptr;
487
488     platformShutdown();
489
490     m_runLoop->stop();
491 }
492
493 CoreIPC::SyncReplyMode WebProcess::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
494 {   
495     uint64_t pageID = arguments->destinationID();
496     if (!pageID)
497         return CoreIPC::AutomaticReply;
498     
499     WebPage* page = webPage(pageID);
500     if (!page)
501         return CoreIPC::AutomaticReply;
502     
503     page->didReceiveSyncMessage(connection, messageID, arguments, reply);
504     return CoreIPC::AutomaticReply;
505 }
506
507 void WebProcess::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
508 {
509     if (messageID.is<CoreIPC::MessageClassWebProcess>()) {
510         didReceiveWebProcessMessage(connection, messageID, arguments);
511         return;
512     }
513
514     if (messageID.is<CoreIPC::MessageClassAuthenticationManager>()) {
515         AuthenticationManager::shared().didReceiveMessage(connection, messageID, arguments);
516         return;
517     }
518
519     if (messageID.is<CoreIPC::MessageClassWebResourceCacheManager>()) {
520         WebResourceCacheManager::shared().didReceiveMessage(connection, messageID, arguments);
521         return;
522     }
523
524     if (messageID.is<CoreIPC::MessageClassWebDatabaseManager>()) {
525         WebDatabaseManager::shared().didReceiveMessage(connection, messageID, arguments);
526         return;
527     }
528
529     if (messageID.is<CoreIPC::MessageClassWebGeolocationManager>()) {
530         m_geolocationManager.didReceiveMessage(connection, messageID, arguments);
531         return;
532     }
533
534     if (messageID.is<CoreIPC::MessageClassInjectedBundle>()) {
535         if (!m_injectedBundle)
536             return;
537         m_injectedBundle->didReceiveMessage(connection, messageID, arguments);    
538         return;
539     }
540
541     uint64_t pageID = arguments->destinationID();
542     if (!pageID)
543         return;
544     
545     WebPage* page = webPage(pageID);
546     if (!page)
547         return;
548     
549     page->didReceiveMessage(connection, messageID, arguments);
550 }
551
552 void WebProcess::didClose(CoreIPC::Connection*)
553 {
554     // When running in the same process the connection will never be closed.
555     ASSERT(isSeparateProcess());
556
557 #ifndef NDEBUG
558     m_inDidClose = true;
559
560     // Close all the live pages.
561     Vector<RefPtr<WebPage> > pages;
562     copyValuesToVector(m_pageMap, pages);
563     for (size_t i = 0; i < pages.size(); ++i)
564         pages[i]->close();
565     pages.clear();
566
567     gcController().garbageCollectNow();
568     memoryCache()->setDisabled(true);
569 #endif    
570
571     // The UI process closed this connection, shut down.
572     m_runLoop->stop();
573 }
574
575 void WebProcess::didReceiveInvalidMessage(CoreIPC::Connection*, CoreIPC::MessageID)
576 {
577     // We received an invalid message, but since this is from the UI process (which we trust),
578     // we'll let it slide.
579 }
580
581 NO_RETURN void WebProcess::didFailToSendSyncMessage(CoreIPC::Connection*)
582 {
583     // We were making a synchronous call to a UI process that doesn't exist any more.
584     // Callers are unlikely to be prepared for an error like this, so it's best to exit immediately.
585     exit(0);
586 }
587
588 WebFrame* WebProcess::webFrame(uint64_t frameID) const
589 {
590     return m_frameMap.get(frameID);
591 }
592
593 void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
594 {
595     m_frameMap.set(frameID, frame);
596 }
597
598 void WebProcess::removeWebFrame(uint64_t frameID)
599 {
600     m_frameMap.remove(frameID);
601
602     // We can end up here after our connection has closed when WebCore's frame life-support timer
603     // fires when the application is shutting down. There's no need (and no way) to update the UI
604     // process in this case.
605     if (!m_connection)
606         return;
607
608     m_connection->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
609 }
610
611 WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
612 {
613     return m_pageGroupMap.get(pageGroupID).get();
614 }
615
616 WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
617 {
618     std::pair<HashMap<uint64_t, RefPtr<WebPageGroupProxy> >::iterator, bool> result = m_pageGroupMap.add(pageGroupData.pageGroupID, 0);
619     if (result.second) {
620         ASSERT(!result.first->second);
621         result.first->second = WebPageGroupProxy::create(pageGroupData);
622     }
623
624     return result.first->second.get();
625 }
626
627 void WebProcess::clearResourceCaches()
628 {
629     platformClearResourceCaches();
630
631     // Toggling the cache model like this forces the cache to evict all its in-memory resources.
632     // FIXME: We need a better way to do this.
633     CacheModel cacheModel = m_cacheModel;
634     setCacheModel(CacheModelDocumentViewer);
635     setCacheModel(cacheModel);
636
637     memoryCache()->evictResources();
638
639     // Empty the cross-origin preflight cache.
640     CrossOriginPreflightResultCache::shared().empty();
641 }
642
643 void WebProcess::clearApplicationCache()
644 {
645 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
646     // Empty the application cache.
647     cacheStorage().empty();
648 #endif
649 }
650
651 #if !ENABLE(PLUGIN_PROCESS)
652 void WebProcess::getSitesWithPluginData(const Vector<String>& pluginPaths, uint64_t callbackID)
653 {
654     HashSet<String> sitesSet;
655
656     for (size_t i = 0; i < pluginPaths.size(); ++i) {
657         RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
658         if (!netscapePluginModule)
659             continue;
660
661         Vector<String> sites = netscapePluginModule->sitesWithData();
662         for (size_t i = 0; i < sites.size(); ++i)
663             sitesSet.add(sites[i]);
664     }
665
666     Vector<String> sites;
667     copyToVector(sitesSet, sites);
668
669     m_connection->send(Messages::WebContext::DidGetSitesWithPluginData(sites, callbackID), 0);
670     shutdownIfPossible();
671 }
672
673 void WebProcess::clearPluginSiteData(const Vector<String>& pluginPaths, const Vector<String>& sites, uint64_t flags, uint64_t maxAgeInSeconds, uint64_t callbackID)
674 {
675     for (size_t i = 0; i < pluginPaths.size(); ++i) {
676         RefPtr<NetscapePluginModule> netscapePluginModule = NetscapePluginModule::getOrCreate(pluginPaths[i]);
677         if (!netscapePluginModule)
678             continue;
679
680         if (sites.isEmpty()) {
681             // Clear everything.
682             netscapePluginModule->clearSiteData(String(), flags, maxAgeInSeconds);
683             continue;
684         }
685
686         for (size_t i = 0; i < sites.size(); ++i)
687             netscapePluginModule->clearSiteData(sites[i], flags, maxAgeInSeconds);
688     }
689
690     m_connection->send(Messages::WebContext::DidClearPluginSiteData(callbackID), 0);
691     shutdownIfPossible();
692 }
693 #endif
694
695 void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
696 {
697     WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
698
699     DownloadManager::shared().startDownload(downloadID, initiatingPage, request);
700 }
701
702 void WebProcess::cancelDownload(uint64_t downloadID)
703 {
704     DownloadManager::shared().cancelDownload(downloadID);
705 }
706
707 void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
708 {
709 #if ENABLE(MEMORY_SAMPLER)    
710     WebMemorySampler::shared()->start(sampleLogFileHandle, sampleLogFilePath, interval);
711 #endif
712 }
713     
714 void WebProcess::stopMemorySampler()
715 {
716 #if ENABLE(MEMORY_SAMPLER)
717     WebMemorySampler::shared()->stop();
718 #endif
719 }
720
721 void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
722 {
723     m_textCheckerState = textCheckerState;
724 }
725
726 } // namespace WebKit