2015-11-03 Geoffrey Garen <ggaren@apple.com>
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebProcess.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2012, 2014 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 "APIFrameHandle.h"
30 #include "APIPageGroupHandle.h"
31 #include "APIPageHandle.h"
32 #include "AuthenticationManager.h"
33 #include "ChildProcessMessages.h"
34 #include "CustomProtocolManager.h"
35 #include "DrawingArea.h"
36 #include "EventDispatcher.h"
37 #include "InjectedBundle.h"
38 #include "Logging.h"
39 #include "NetworkConnectionToWebProcessMessages.h"
40 #include "PluginProcessConnectionManager.h"
41 #include "SessionTracker.h"
42 #include "StatisticsData.h"
43 #include "UserData.h"
44 #include "WebConnectionToUIProcess.h"
45 #include "WebCookieManager.h"
46 #include "WebCoreArgumentCoders.h"
47 #include "WebDatabaseManager.h"
48 #include "WebFrame.h"
49 #include "WebFrameNetworkingContext.h"
50 #include "WebGeolocationManager.h"
51 #include "WebIconDatabaseProxy.h"
52 #include "WebMediaCacheManager.h"
53 #include "WebMediaKeyStorageManager.h"
54 #include "WebMemorySampler.h"
55 #include "WebPage.h"
56 #include "WebPageGroupProxy.h"
57 #include "WebPageGroupProxyMessages.h"
58 #include "WebPlatformStrategies.h"
59 #include "WebProcessCreationParameters.h"
60 #include "WebProcessMessages.h"
61 #include "WebProcessPoolMessages.h"
62 #include "WebProcessProxyMessages.h"
63 #include "WebsiteData.h"
64 #include "WebsiteDataTypes.h"
65 #include <JavaScriptCore/JSLock.h>
66 #include <JavaScriptCore/MemoryStatistics.h>
67 #include <WebCore/AXObjectCache.h>
68 #include <WebCore/ApplicationCacheStorage.h>
69 #include <WebCore/AuthenticationChallenge.h>
70 #include <WebCore/CrossOriginPreflightResultCache.h>
71 #include <WebCore/DNS.h>
72 #include <WebCore/FontCache.h>
73 #include <WebCore/FontCascade.h>
74 #include <WebCore/Frame.h>
75 #include <WebCore/FrameLoader.h>
76 #include <WebCore/GCController.h>
77 #include <WebCore/GlyphPage.h>
78 #include <WebCore/IconDatabase.h>
79 #include <WebCore/JSDOMWindow.h>
80 #include <WebCore/Language.h>
81 #include <WebCore/MainFrame.h>
82 #include <WebCore/MemoryCache.h>
83 #include <WebCore/MemoryPressureHandler.h>
84 #include <WebCore/Page.h>
85 #include <WebCore/PageCache.h>
86 #include <WebCore/PageGroup.h>
87 #include <WebCore/PlatformMediaSessionManager.h>
88 #include <WebCore/ResourceHandle.h>
89 #include <WebCore/RuntimeEnabledFeatures.h>
90 #include <WebCore/SchemeRegistry.h>
91 #include <WebCore/SecurityOrigin.h>
92 #include <WebCore/Settings.h>
93 #include <unistd.h>
94 #include <wtf/CurrentTime.h>
95 #include <wtf/HashCountedSet.h>
96 #include <wtf/PassRefPtr.h>
97 #include <wtf/RunLoop.h>
98 #include <wtf/text/StringHash.h>
99
100 #if PLATFORM(COCOA)
101 #include "ObjCObjectGraph.h"
102 #endif
103
104 #if ENABLE(NETWORK_PROCESS)
105 #if PLATFORM(COCOA)
106 #include "CookieStorageShim.h"
107 #endif
108 #include "NetworkProcessConnection.h"
109 #endif
110
111 #if ENABLE(SEC_ITEM_SHIM)
112 #include "SecItemShim.h"
113 #endif
114
115 #if ENABLE(DATABASE_PROCESS)
116 #include "WebToDatabaseProcessConnection.h"
117 #endif
118
119 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
120 #include "WebNotificationManager.h"
121 #endif
122
123 #if ENABLE(BATTERY_STATUS)
124 #include "WebBatteryManager.h"
125 #endif
126
127 #if ENABLE(NETWORK_PROCESS)
128 #include "WebResourceLoadScheduler.h"
129 #endif
130
131 #if ENABLE(REMOTE_INSPECTOR)
132 #include <JavaScriptCore/RemoteInspector.h>
133 #endif
134
135 using namespace JSC;
136 using namespace WebCore;
137
138 // This should be less than plugInAutoStartExpirationTimeThreshold in PlugInAutoStartProvider.
139 static const double plugInAutoStartExpirationTimeUpdateThreshold = 29 * 24 * 60 * 60;
140
141 // This should be greater than tileRevalidationTimeout in TileController.
142 static const double nonVisibleProcessCleanupDelay = 10;
143
144 namespace WebKit {
145
146 WebProcess& WebProcess::singleton()
147 {
148     static WebProcess& process = *new WebProcess;
149     return process;
150 }
151
152 WebProcess::WebProcess()
153     : m_eventDispatcher(EventDispatcher::create())
154 #if PLATFORM(IOS)
155     , m_viewUpdateDispatcher(ViewUpdateDispatcher::create())
156 #endif
157     , m_processSuspensionCleanupTimer(*this, &WebProcess::processSuspensionCleanupTimerFired)
158     , m_inDidClose(false)
159     , m_hasSetCacheModel(false)
160     , m_cacheModel(CacheModelDocumentViewer)
161     , m_fullKeyboardAccessEnabled(false)
162     , m_textCheckerState()
163     , m_iconDatabaseProxy(new WebIconDatabaseProxy(this))
164 #if ENABLE(NETWORK_PROCESS)
165     , m_usesNetworkProcess(false)
166     , m_webResourceLoadScheduler(new WebResourceLoadScheduler)
167     , m_dnsPrefetchHystereris([this](HysteresisState state) { if (state == HysteresisState::Stopped) m_dnsPrefetchedHosts.clear(); })
168 #endif
169 #if ENABLE(NETSCAPE_PLUGIN_API)
170     , m_pluginProcessConnectionManager(PluginProcessConnectionManager::create())
171 #endif
172 #if ENABLE(SERVICE_CONTROLS)
173     , m_hasImageServices(false)
174     , m_hasSelectionServices(false)
175     , m_hasRichContentServices(false)
176 #endif
177     , m_nonVisibleProcessCleanupTimer(*this, &WebProcess::nonVisibleProcessCleanupTimerFired)
178 #if PLATFORM(IOS)
179     , m_webSQLiteDatabaseTracker(*this)
180 #endif
181 {
182     // Initialize our platform strategies.
183     WebPlatformStrategies::initialize();
184
185     // FIXME: This should moved to where WebProcess::initialize is called,
186     // so that ports have a chance to customize, and ifdefs in this file are
187     // limited.
188     addSupplement<WebGeolocationManager>();
189     addSupplement<WebCookieManager>();
190     addSupplement<WebMediaCacheManager>();
191     addSupplement<AuthenticationManager>();
192     addSupplement<WebDatabaseManager>();
193
194 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
195     addSupplement<WebNotificationManager>();
196 #endif
197     addSupplement<CustomProtocolManager>();
198 #if ENABLE(BATTERY_STATUS)
199     addSupplement<WebBatteryManager>();
200 #endif
201 #if ENABLE(ENCRYPTED_MEDIA_V2)
202     addSupplement<WebMediaKeyStorageManager>();
203 #endif
204     m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>());
205
206 #if ENABLE(INDEXED_DATABASE)
207     RuntimeEnabledFeatures::sharedFeatures().setWebkitIndexedDBEnabled(true);
208 #endif
209 }
210
211 WebProcess::~WebProcess()
212 {
213 }
214
215 void WebProcess::initializeProcess(const ChildProcessInitializationParameters& parameters)
216 {
217     platformInitializeProcess(parameters);
218 }
219
220 void WebProcess::initializeConnection(IPC::Connection* connection)
221 {
222     ChildProcess::initializeConnection(connection);
223
224     connection->setShouldExitOnSyncMessageSendFailure(true);
225
226 #if HAVE(QOS_CLASSES)
227     connection->setShouldBoostMainThreadOnSyncMessage(true);
228 #endif
229
230     m_eventDispatcher->initializeConnection(connection);
231 #if PLATFORM(IOS)
232     m_viewUpdateDispatcher->initializeConnection(connection);
233 #endif // PLATFORM(IOS)
234
235 #if ENABLE(NETSCAPE_PLUGIN_API)
236     m_pluginProcessConnectionManager->initializeConnection(connection);
237 #endif
238
239 #if ENABLE(SEC_ITEM_SHIM)
240     SecItemShim::singleton().initializeConnection(connection);
241 #endif
242
243     for (auto& supplement : m_supplements.values())
244         supplement->initializeConnection(connection);
245
246     m_webConnection = WebConnectionToUIProcess::create(this);
247
248     // In order to ensure that the asynchronous messages that are used for notifying the UI process
249     // about when WebFrame objects come and go are always delivered before the synchronous policy messages,
250     // use this flag to force synchronous messages to be treated as asynchronous messages in the UI process
251     // unless when doing so would lead to a deadlock.
252     connection->setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
253 }
254
255 void WebProcess::didCreateDownload()
256 {
257     disableTermination();
258 }
259
260 void WebProcess::didDestroyDownload()
261 {
262     enableTermination();
263 }
264
265 IPC::Connection* WebProcess::downloadProxyConnection()
266 {
267     return parentProcessConnection();
268 }
269
270 AuthenticationManager& WebProcess::downloadsAuthenticationManager()
271 {
272     return *supplement<AuthenticationManager>();
273 }
274
275 void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters)
276 {
277     ASSERT(m_pageMap.isEmpty());
278
279 #if ENABLE(NETWORK_PROCESS)
280     m_usesNetworkProcess = parameters.usesNetworkProcess;
281 #endif
282
283 #if OS(LINUX)
284     WebCore::MemoryPressureHandler::ReliefLogger::setLoggingEnabled(parameters.shouldEnableMemoryPressureReliefLogging);
285 #endif
286
287     platformInitializeWebProcess(WTF::move(parameters));
288
289     WTF::setCurrentThreadIsUserInitiated();
290
291     MemoryPressureHandler::singleton().install();
292
293     if (!parameters.injectedBundlePath.isEmpty())
294         m_injectedBundle = InjectedBundle::create(parameters, transformHandlesToObjects(parameters.initializationUserData.object()).get());
295
296     for (auto& supplement : m_supplements.values())
297         supplement->initialize(parameters);
298
299 #if ENABLE(ICONDATABASE)
300     m_iconDatabaseProxy->setEnabled(parameters.iconDatabaseEnabled);
301 #endif
302
303     if (!parameters.applicationCacheDirectory.isEmpty())
304         ApplicationCacheStorage::singleton().setCacheDirectory(parameters.applicationCacheDirectory);
305
306     setCacheModel(static_cast<uint32_t>(parameters.cacheModel));
307
308     if (!parameters.languages.isEmpty())
309         overrideUserPreferredLanguages(parameters.languages);
310
311     m_textCheckerState = parameters.textCheckerState;
312
313     m_fullKeyboardAccessEnabled = parameters.fullKeyboardAccessEnabled;
314
315     for (auto& scheme : parameters.urlSchemesRegisteredAsEmptyDocument)
316         registerURLSchemeAsEmptyDocument(scheme);
317
318     for (auto& scheme : parameters.urlSchemesRegisteredAsSecure)
319         registerURLSchemeAsSecure(scheme);
320
321     for (auto& scheme : parameters.urlSchemesRegisteredAsBypassingContentSecurityPolicy)
322         registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
323
324     for (auto& scheme : parameters.urlSchemesForWhichDomainRelaxationIsForbidden)
325         setDomainRelaxationForbiddenForURLScheme(scheme);
326
327     for (auto& scheme : parameters.urlSchemesRegisteredAsLocal)
328         registerURLSchemeAsLocal(scheme);
329
330     for (auto& scheme : parameters.urlSchemesRegisteredAsNoAccess)
331         registerURLSchemeAsNoAccess(scheme);
332
333     for (auto& scheme : parameters.urlSchemesRegisteredAsDisplayIsolated)
334         registerURLSchemeAsDisplayIsolated(scheme);
335
336     for (auto& scheme : parameters.urlSchemesRegisteredAsCORSEnabled)
337         registerURLSchemeAsCORSEnabled(scheme);
338
339     WebCore::Settings::setShouldRewriteConstAsVar(parameters.shouldRewriteConstAsVar);
340
341 #if ENABLE(CACHE_PARTITIONING)
342     for (auto& scheme : parameters.urlSchemesRegisteredAsCachePartitioned)
343         registerURLSchemeAsCachePartitioned(scheme);
344 #endif
345
346     setDefaultRequestTimeoutInterval(parameters.defaultRequestTimeoutInterval);
347
348     if (parameters.shouldAlwaysUseComplexTextCodePath)
349         setAlwaysUsesComplexTextCodePath(true);
350
351     if (parameters.shouldUseFontSmoothing)
352         setShouldUseFontSmoothing(true);
353
354 #if PLATFORM(COCOA) || USE(CFNETWORK)
355     SessionTracker::setIdentifierBase(parameters.uiProcessBundleIdentifier);
356 #endif
357
358     if (parameters.shouldUseTestingNetworkSession)
359         NetworkStorageSession::switchToNewTestingSession();
360
361 #if ENABLE(NETWORK_PROCESS)
362     ensureNetworkProcessConnection();
363
364 #if PLATFORM(COCOA)
365     if (usesNetworkProcess())
366         CookieStorageShim::singleton().initialize();
367 #endif
368 #endif
369     setTerminationTimeout(parameters.terminationTimeout);
370
371     resetPlugInAutoStartOriginHashes(parameters.plugInAutoStartOriginHashes);
372     for (auto& origin : parameters.plugInAutoStartOrigins)
373         m_plugInAutoStartOrigins.add(origin);
374
375     setMemoryCacheDisabled(parameters.memoryCacheDisabled);
376
377 #if ENABLE(SERVICE_CONTROLS)
378     setEnabledServices(parameters.hasImageServices, parameters.hasSelectionServices, parameters.hasRichContentServices);
379 #endif
380
381 #if ENABLE(REMOTE_INSPECTOR)
382     audit_token_t auditToken;
383     if (parentProcessConnection()->getAuditToken(auditToken)) {
384         RetainPtr<CFDataRef> auditData = adoptCF(CFDataCreate(nullptr, (const UInt8*)&auditToken, sizeof(auditToken)));
385         Inspector::RemoteInspector::singleton().setParentProcessInformation(presenterApplicationPid(), auditData);
386     }
387 #endif
388
389 #if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
390     for (auto hostIter = parameters.pluginLoadClientPolicies.begin(); hostIter != parameters.pluginLoadClientPolicies.end(); ++hostIter) {
391         for (auto bundleIdentifierIter = hostIter->value.begin(); bundleIdentifierIter != hostIter->value.end(); ++bundleIdentifierIter) {
392             for (auto versionIter = bundleIdentifierIter->value.begin(); versionIter != bundleIdentifierIter->value.end(); ++versionIter)
393                 platformStrategies()->pluginStrategy()->setPluginLoadClientPolicy(static_cast<PluginLoadClientPolicy>(versionIter->value), hostIter->key, bundleIdentifierIter->key, versionIter->key);
394         }
395     }
396 #endif
397 }
398
399 #if ENABLE(NETWORK_PROCESS)
400 void WebProcess::ensureNetworkProcessConnection()
401 {
402     if (!m_usesNetworkProcess)
403         return;
404
405     if (m_networkProcessConnection)
406         return;
407
408     IPC::Attachment encodedConnectionIdentifier;
409
410     if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetNetworkProcessConnection(),
411         Messages::WebProcessProxy::GetNetworkProcessConnection::Reply(encodedConnectionIdentifier), 0))
412         return;
413
414 #if USE(UNIX_DOMAIN_SOCKETS)
415     IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
416 #elif OS(DARWIN)
417     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
418 #else
419     ASSERT_NOT_REACHED();
420 #endif
421     if (IPC::Connection::identifierIsNull(connectionIdentifier))
422         return;
423     m_networkProcessConnection = NetworkProcessConnection::create(connectionIdentifier);
424 }
425 #endif // ENABLE(NETWORK_PROCESS)
426
427 void WebProcess::registerURLSchemeAsEmptyDocument(const String& urlScheme)
428 {
429     SchemeRegistry::registerURLSchemeAsEmptyDocument(urlScheme);
430 }
431
432 void WebProcess::registerURLSchemeAsSecure(const String& urlScheme) const
433 {
434     SchemeRegistry::registerURLSchemeAsSecure(urlScheme);
435 }
436
437 void WebProcess::registerURLSchemeAsBypassingContentSecurityPolicy(const String& urlScheme) const
438 {
439     SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(urlScheme);
440 }
441
442 void WebProcess::setDomainRelaxationForbiddenForURLScheme(const String& urlScheme) const
443 {
444     SchemeRegistry::setDomainRelaxationForbiddenForURLScheme(true, urlScheme);
445 }
446
447 void WebProcess::registerURLSchemeAsLocal(const String& urlScheme) const
448 {
449     SchemeRegistry::registerURLSchemeAsLocal(urlScheme);
450 }
451
452 void WebProcess::registerURLSchemeAsNoAccess(const String& urlScheme) const
453 {
454     SchemeRegistry::registerURLSchemeAsNoAccess(urlScheme);
455 }
456
457 void WebProcess::registerURLSchemeAsDisplayIsolated(const String& urlScheme) const
458 {
459     SchemeRegistry::registerURLSchemeAsDisplayIsolated(urlScheme);
460 }
461
462 void WebProcess::registerURLSchemeAsCORSEnabled(const String& urlScheme) const
463 {
464     SchemeRegistry::registerURLSchemeAsCORSEnabled(urlScheme);
465 }
466
467 #if ENABLE(CACHE_PARTITIONING)
468 void WebProcess::registerURLSchemeAsCachePartitioned(const String& urlScheme) const
469 {
470     SchemeRegistry::registerURLSchemeAsCachePartitioned(urlScheme);
471 }
472 #endif
473
474 void WebProcess::setDefaultRequestTimeoutInterval(double timeoutInterval)
475 {
476     ResourceRequest::setDefaultTimeoutInterval(timeoutInterval);
477 }
478
479 void WebProcess::setAlwaysUsesComplexTextCodePath(bool alwaysUseComplexText)
480 {
481     WebCore::FontCascade::setCodePath(alwaysUseComplexText ? WebCore::FontCascade::Complex : WebCore::FontCascade::Auto);
482 }
483
484 void WebProcess::setShouldUseFontSmoothing(bool useFontSmoothing)
485 {
486     WebCore::FontCascade::setShouldUseSmoothing(useFontSmoothing);
487 }
488
489 void WebProcess::userPreferredLanguagesChanged(const Vector<String>& languages) const
490 {
491     overrideUserPreferredLanguages(languages);
492     languageDidChange();
493 }
494
495 void WebProcess::fullKeyboardAccessModeChanged(bool fullKeyboardAccessEnabled)
496 {
497     m_fullKeyboardAccessEnabled = fullKeyboardAccessEnabled;
498 }
499
500 void WebProcess::ensurePrivateBrowsingSession(SessionID sessionID)
501 {
502 #if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
503     WebFrameNetworkingContext::ensurePrivateBrowsingSession(sessionID);
504 #endif
505 }
506
507 void WebProcess::destroyPrivateBrowsingSession(SessionID sessionID)
508 {
509 #if PLATFORM(COCOA) || USE(CFNETWORK) || USE(SOUP)
510     SessionTracker::destroySession(sessionID);
511 #endif
512 }
513
514 DownloadManager& WebProcess::downloadManager()
515 {
516     ASSERT(!usesNetworkProcess());
517
518     static NeverDestroyed<DownloadManager> downloadManager(this);
519     return downloadManager;
520 }
521
522 #if ENABLE(NETSCAPE_PLUGIN_API)
523 PluginProcessConnectionManager& WebProcess::pluginProcessConnectionManager()
524 {
525     return *m_pluginProcessConnectionManager;
526 }
527 #endif
528
529 void WebProcess::setCacheModel(uint32_t cm)
530 {
531     CacheModel cacheModel = static_cast<CacheModel>(cm);
532
533     if (!m_hasSetCacheModel || cacheModel != m_cacheModel) {
534         m_hasSetCacheModel = true;
535         m_cacheModel = cacheModel;
536         platformSetCacheModel(cacheModel);
537     }
538 }
539
540 WebPage* WebProcess::focusedWebPage() const
541 {    
542     for (auto& page : m_pageMap.values()) {
543         if (page->windowAndWebPageAreFocused())
544             return page.get();
545     }
546     return 0;
547 }
548     
549 WebPage* WebProcess::webPage(uint64_t pageID) const
550 {
551     return m_pageMap.get(pageID);
552 }
553
554 void WebProcess::createWebPage(uint64_t pageID, const WebPageCreationParameters& parameters)
555 {
556     // It is necessary to check for page existence here since during a window.open() (or targeted
557     // link) the WebPage gets created both in the synchronous handler and through the normal way. 
558     HashMap<uint64_t, RefPtr<WebPage>>::AddResult result = m_pageMap.add(pageID, nullptr);
559     if (result.isNewEntry) {
560         ASSERT(!result.iterator->value);
561         result.iterator->value = WebPage::create(pageID, parameters);
562
563         // Balanced by an enableTermination in removeWebPage.
564         disableTermination();
565     } else
566         result.iterator->value->reinitializeWebPage(parameters);
567
568     ASSERT(result.iterator->value);
569 }
570
571 void WebProcess::removeWebPage(uint64_t pageID)
572 {
573     ASSERT(m_pageMap.contains(pageID));
574
575     pageWillLeaveWindow(pageID);
576     m_pageMap.remove(pageID);
577
578     enableTermination();
579 }
580
581 bool WebProcess::shouldTerminate()
582 {
583     ASSERT(m_pageMap.isEmpty());
584     ASSERT(usesNetworkProcess() || !downloadManager().isDownloading());
585
586     // FIXME: the ShouldTerminate message should also send termination parameters, such as any session cookies that need to be preserved.
587     bool shouldTerminate = false;
588     if (parentProcessConnection()->sendSync(Messages::WebProcessProxy::ShouldTerminate(), Messages::WebProcessProxy::ShouldTerminate::Reply(shouldTerminate), 0)
589         && !shouldTerminate)
590         return false;
591
592     return true;
593 }
594
595 void WebProcess::terminate()
596 {
597 #ifndef NDEBUG
598     GCController::singleton().garbageCollectNow();
599     FontCache::singleton().invalidate();
600     MemoryCache::singleton().setDisabled(true);
601 #endif
602
603     m_webConnection->invalidate();
604     m_webConnection = nullptr;
605
606     platformTerminate();
607
608     ChildProcess::terminate();
609 }
610
611 void WebProcess::didReceiveSyncMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
612 {
613     if (messageReceiverMap().dispatchSyncMessage(connection, decoder, replyEncoder))
614         return;
615
616     didReceiveSyncWebProcessMessage(connection, decoder, replyEncoder);
617 }
618
619 void WebProcess::didReceiveMessage(IPC::Connection& connection, IPC::MessageDecoder& decoder)
620 {
621     if (messageReceiverMap().dispatchMessage(connection, decoder))
622         return;
623
624     if (decoder.messageReceiverName() == Messages::WebProcess::messageReceiverName()) {
625         didReceiveWebProcessMessage(connection, decoder);
626         return;
627     }
628
629     if (decoder.messageReceiverName() == Messages::WebPageGroupProxy::messageReceiverName()) {
630         uint64_t pageGroupID = decoder.destinationID();
631         if (!pageGroupID)
632             return;
633         
634         WebPageGroupProxy* pageGroupProxy = webPageGroup(pageGroupID);
635         if (!pageGroupProxy)
636             return;
637         
638         pageGroupProxy->didReceiveMessage(connection, decoder);
639         return;
640     }
641
642     if (decoder.messageReceiverName() == Messages::ChildProcess::messageReceiverName()) {
643         ChildProcess::didReceiveMessage(connection, decoder);
644         return;
645     }
646
647     LOG_ERROR("Unhandled web process message '%s:%s'", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data());
648 }
649
650 void WebProcess::didClose(IPC::Connection&)
651 {
652 #ifndef NDEBUG
653     m_inDidClose = true;
654
655     // Close all the live pages.
656     Vector<RefPtr<WebPage>> pages;
657     copyValuesToVector(m_pageMap, pages);
658     for (auto& page : pages)
659         page->close();
660     pages.clear();
661
662     GCController::singleton().garbageCollectSoon();
663     FontCache::singleton().invalidate();
664     MemoryCache::singleton().setDisabled(true);
665 #endif
666
667 #if ENABLE(VIDEO)
668     // FIXME(146657): This explicit media stop command should not be necessary
669     if (auto* platformMediaSessionManager = PlatformMediaSessionManager::sharedManagerIfExists())
670         platformMediaSessionManager->stopAllMediaPlaybackForProcess();
671 #endif
672
673     // The UI process closed this connection, shut down.
674     stopRunLoop();
675 }
676
677 void WebProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::StringReference, IPC::StringReference)
678 {
679     // We received an invalid message, but since this is from the UI process (which we trust),
680     // we'll let it slide.
681 }
682
683 WebFrame* WebProcess::webFrame(uint64_t frameID) const
684 {
685     return m_frameMap.get(frameID);
686 }
687
688 void WebProcess::addWebFrame(uint64_t frameID, WebFrame* frame)
689 {
690     m_frameMap.set(frameID, frame);
691 }
692
693 void WebProcess::removeWebFrame(uint64_t frameID)
694 {
695     m_frameMap.remove(frameID);
696
697     // We can end up here after our connection has closed when WebCore's frame life-support timer
698     // fires when the application is shutting down. There's no need (and no way) to update the UI
699     // process in this case.
700     if (!parentProcessConnection())
701         return;
702
703     parentProcessConnection()->send(Messages::WebProcessProxy::DidDestroyFrame(frameID), 0);
704 }
705
706 WebPageGroupProxy* WebProcess::webPageGroup(PageGroup* pageGroup)
707 {
708     for (auto& page : m_pageGroupMap.values()) {
709         if (page->corePageGroup() == pageGroup)
710             return page.get();
711     }
712
713     return 0;
714 }
715
716 WebPageGroupProxy* WebProcess::webPageGroup(uint64_t pageGroupID)
717 {
718     return m_pageGroupMap.get(pageGroupID);
719 }
720
721 WebPageGroupProxy* WebProcess::webPageGroup(const WebPageGroupData& pageGroupData)
722 {
723     auto result = m_pageGroupMap.add(pageGroupData.pageGroupID, nullptr);
724     if (result.isNewEntry) {
725         ASSERT(!result.iterator->value);
726         result.iterator->value = WebPageGroupProxy::create(pageGroupData);
727     }
728
729     return result.iterator->value.get();
730 }
731
732 void WebProcess::clearResourceCaches(ResourceCachesToClear resourceCachesToClear)
733 {
734     platformClearResourceCaches(resourceCachesToClear);
735
736     // Toggling the cache model like this forces the cache to evict all its in-memory resources.
737     // FIXME: We need a better way to do this.
738     CacheModel cacheModel = m_cacheModel;
739     setCacheModel(CacheModelDocumentViewer);
740     setCacheModel(cacheModel);
741
742     MemoryCache::singleton().evictResources();
743
744     // Empty the cross-origin preflight cache.
745     CrossOriginPreflightResultCache::singleton().empty();
746 }
747
748 void WebProcess::clearApplicationCache()
749 {
750     // Empty the application cache.
751     ApplicationCacheStorage::singleton().empty();
752 }
753
754 static inline void addCaseFoldedCharacters(StringHasher& hasher, const String& string)
755 {
756     if (string.isEmpty())
757         return;
758     if (string.is8Bit()) {
759         hasher.addCharacters<LChar, CaseFoldingHash::foldCase<LChar>>(string.characters8(), string.length());
760         return;
761     }
762     hasher.addCharacters<UChar, CaseFoldingHash::foldCase<UChar>>(string.characters16(), string.length());
763 }
764
765 static unsigned hashForPlugInOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
766 {
767     // We want to avoid concatenating the strings and then taking the hash, since that could lead to an expensive conversion.
768     // We also want to avoid using the hash() function in StringImpl or CaseFoldingHash because that masks out bits for the use of flags.
769     StringHasher hasher;
770     addCaseFoldedCharacters(hasher, pageOrigin);
771     hasher.addCharacter(0);
772     addCaseFoldedCharacters(hasher, pluginOrigin);
773     hasher.addCharacter(0);
774     addCaseFoldedCharacters(hasher, mimeType);
775     return hasher.hash();
776 }
777
778 bool WebProcess::isPlugInAutoStartOriginHash(unsigned plugInOriginHash, SessionID sessionID)
779 {
780     HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
781     HashMap<unsigned, double>::const_iterator it;
782     bool contains = false;
783
784     if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
785         it = sessionIterator->value.find(plugInOriginHash);
786         contains = it != sessionIterator->value.end();
787     }
788     if (!contains) {
789         sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
790         it = sessionIterator->value.find(plugInOriginHash);
791         if (it == sessionIterator->value.end())
792             return false;
793     }
794     return currentTime() < it->value;
795 }
796
797 bool WebProcess::shouldPlugInAutoStartFromOrigin(WebPage& webPage, const String& pageOrigin, const String& pluginOrigin, const String& mimeType)
798 {
799     if (!pluginOrigin.isEmpty() && m_plugInAutoStartOrigins.contains(pluginOrigin))
800         return true;
801
802 #ifdef ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC
803     // The plugin wasn't in the general whitelist, so check if it similar to the primary plugin for the page (if we've found one).
804     if (webPage.matchesPrimaryPlugIn(pageOrigin, pluginOrigin, mimeType))
805         return true;
806 #else
807     UNUSED_PARAM(webPage);
808 #endif
809
810     // Lastly check against the more explicit hash list.
811     return isPlugInAutoStartOriginHash(hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType), webPage.sessionID());
812 }
813
814 void WebProcess::plugInDidStartFromOrigin(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
815 {
816     if (pageOrigin.isEmpty()) {
817         LOG(Plugins, "Not adding empty page origin");
818         return;
819     }
820
821     unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
822     if (isPlugInAutoStartOriginHash(plugInOriginHash, sessionID)) {
823         LOG(Plugins, "Hash %x already exists as auto-start origin (request for %s)", plugInOriginHash, pageOrigin.utf8().data());
824         return;
825     }
826
827     // We might attempt to start another plugin before the didAddPlugInAutoStartOrigin message
828     // comes back from the parent process. Temporarily add this hash to the list with a thirty
829     // second timeout. That way, even if the parent decides not to add it, we'll only be
830     // incorrect for a little while.
831     m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, currentTime() + 30 * 1000);
832
833     parentProcessConnection()->send(Messages::WebProcessPool::AddPlugInAutoStartOriginHash(pageOrigin, plugInOriginHash, sessionID), 0);
834 }
835
836 void WebProcess::didAddPlugInAutoStartOriginHash(unsigned plugInOriginHash, double expirationTime, SessionID sessionID)
837 {
838     // When called, some web process (which also might be this one) added the origin for auto-starting,
839     // or received user interaction.
840     // Set the bit to avoid having redundantly call into the UI process upon user interaction.
841     m_plugInAutoStartOriginHashes.add(sessionID, HashMap<unsigned, double>()).iterator->value.set(plugInOriginHash, expirationTime);
842 }
843
844 void WebProcess::resetPlugInAutoStartOriginDefaultHashes(const HashMap<unsigned, double>& hashes)
845 {
846     m_plugInAutoStartOriginHashes.clear();
847     m_plugInAutoStartOriginHashes.add(SessionID::defaultSessionID(), HashMap<unsigned, double>()).iterator->value.swap(const_cast<HashMap<unsigned, double>&>(hashes));
848 }
849
850 void WebProcess::resetPlugInAutoStartOriginHashes(const HashMap<SessionID, HashMap<unsigned, double>>& hashes)
851 {
852     m_plugInAutoStartOriginHashes.swap(const_cast<HashMap<SessionID, HashMap<unsigned, double>>&>(hashes));
853 }
854
855 void WebProcess::plugInDidReceiveUserInteraction(const String& pageOrigin, const String& pluginOrigin, const String& mimeType, SessionID sessionID)
856 {
857     if (pageOrigin.isEmpty())
858         return;
859
860     unsigned plugInOriginHash = hashForPlugInOrigin(pageOrigin, pluginOrigin, mimeType);
861     if (!plugInOriginHash)
862         return;
863
864     HashMap<WebCore::SessionID, HashMap<unsigned, double>>::const_iterator sessionIterator = m_plugInAutoStartOriginHashes.find(sessionID);
865     HashMap<unsigned, double>::const_iterator it;
866     bool contains = false;
867     if (sessionIterator != m_plugInAutoStartOriginHashes.end()) {
868         it = sessionIterator->value.find(plugInOriginHash);
869         contains = it != sessionIterator->value.end();
870     }
871     if (!contains) {
872         sessionIterator = m_plugInAutoStartOriginHashes.find(SessionID::defaultSessionID());
873         it = sessionIterator->value.find(plugInOriginHash);
874         if (it == sessionIterator->value.end())
875             return;
876     }
877
878     if (it->value - currentTime() > plugInAutoStartExpirationTimeUpdateThreshold)
879         return;
880
881     parentProcessConnection()->send(Messages::WebProcessPool::PlugInDidReceiveUserInteraction(plugInOriginHash, sessionID), 0);
882 }
883
884 void WebProcess::setPluginLoadClientPolicy(uint8_t policy, const String& host, const String& bundleIdentifier, const String& versionString)
885 {
886 #if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
887     platformStrategies()->pluginStrategy()->setPluginLoadClientPolicy(static_cast<PluginLoadClientPolicy>(policy), host, bundleIdentifier, versionString);
888 #endif
889 }
890
891 void WebProcess::clearPluginClientPolicies()
892 {
893 #if ENABLE(NETSCAPE_PLUGIN_API) && PLATFORM(MAC)
894     platformStrategies()->pluginStrategy()->clearPluginClientPolicies();
895 #endif
896 }
897
898 static void fromCountedSetToHashMap(TypeCountSet* countedSet, HashMap<String, uint64_t>& map)
899 {
900     TypeCountSet::const_iterator end = countedSet->end();
901     for (TypeCountSet::const_iterator it = countedSet->begin(); it != end; ++it)
902         map.set(it->key, it->value);
903 }
904
905 static void getWebCoreMemoryCacheStatistics(Vector<HashMap<String, uint64_t>>& result)
906 {
907     String imagesString(ASCIILiteral("Images"));
908     String cssString(ASCIILiteral("CSS"));
909     String xslString(ASCIILiteral("XSL"));
910     String javaScriptString(ASCIILiteral("JavaScript"));
911     
912     MemoryCache::Statistics memoryCacheStatistics = MemoryCache::singleton().getStatistics();
913     
914     HashMap<String, uint64_t> counts;
915     counts.set(imagesString, memoryCacheStatistics.images.count);
916     counts.set(cssString, memoryCacheStatistics.cssStyleSheets.count);
917     counts.set(xslString, memoryCacheStatistics.xslStyleSheets.count);
918     counts.set(javaScriptString, memoryCacheStatistics.scripts.count);
919     result.append(counts);
920     
921     HashMap<String, uint64_t> sizes;
922     sizes.set(imagesString, memoryCacheStatistics.images.size);
923     sizes.set(cssString, memoryCacheStatistics.cssStyleSheets.size);
924     sizes.set(xslString, memoryCacheStatistics.xslStyleSheets.size);
925     sizes.set(javaScriptString, memoryCacheStatistics.scripts.size);
926     result.append(sizes);
927     
928     HashMap<String, uint64_t> liveSizes;
929     liveSizes.set(imagesString, memoryCacheStatistics.images.liveSize);
930     liveSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.liveSize);
931     liveSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.liveSize);
932     liveSizes.set(javaScriptString, memoryCacheStatistics.scripts.liveSize);
933     result.append(liveSizes);
934     
935     HashMap<String, uint64_t> decodedSizes;
936     decodedSizes.set(imagesString, memoryCacheStatistics.images.decodedSize);
937     decodedSizes.set(cssString, memoryCacheStatistics.cssStyleSheets.decodedSize);
938     decodedSizes.set(xslString, memoryCacheStatistics.xslStyleSheets.decodedSize);
939     decodedSizes.set(javaScriptString, memoryCacheStatistics.scripts.decodedSize);
940     result.append(decodedSizes);
941 }
942
943 void WebProcess::getWebCoreStatistics(uint64_t callbackID)
944 {
945     StatisticsData data;
946     
947     // Gather JavaScript statistics.
948     {
949         JSLockHolder lock(JSDOMWindow::commonVM());
950         data.statisticsNumbers.set(ASCIILiteral("JavaScriptObjectsCount"), JSDOMWindow::commonVM().heap.objectCount());
951         data.statisticsNumbers.set(ASCIILiteral("JavaScriptGlobalObjectsCount"), JSDOMWindow::commonVM().heap.globalObjectCount());
952         data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedObjectsCount"), JSDOMWindow::commonVM().heap.protectedObjectCount());
953         data.statisticsNumbers.set(ASCIILiteral("JavaScriptProtectedGlobalObjectsCount"), JSDOMWindow::commonVM().heap.protectedGlobalObjectCount());
954         
955         std::unique_ptr<TypeCountSet> protectedObjectTypeCounts(JSDOMWindow::commonVM().heap.protectedObjectTypeCounts());
956         fromCountedSetToHashMap(protectedObjectTypeCounts.get(), data.javaScriptProtectedObjectTypeCounts);
957         
958         std::unique_ptr<TypeCountSet> objectTypeCounts(JSDOMWindow::commonVM().heap.objectTypeCounts());
959         fromCountedSetToHashMap(objectTypeCounts.get(), data.javaScriptObjectTypeCounts);
960         
961         uint64_t javaScriptHeapSize = JSDOMWindow::commonVM().heap.size();
962         data.statisticsNumbers.set(ASCIILiteral("JavaScriptHeapSize"), javaScriptHeapSize);
963         data.statisticsNumbers.set(ASCIILiteral("JavaScriptFreeSize"), JSDOMWindow::commonVM().heap.capacity() - javaScriptHeapSize);
964     }
965
966     WTF::FastMallocStatistics fastMallocStatistics = WTF::fastMallocStatistics();
967     data.statisticsNumbers.set(ASCIILiteral("FastMallocReservedVMBytes"), fastMallocStatistics.reservedVMBytes);
968     data.statisticsNumbers.set(ASCIILiteral("FastMallocCommittedVMBytes"), fastMallocStatistics.committedVMBytes);
969     data.statisticsNumbers.set(ASCIILiteral("FastMallocFreeListBytes"), fastMallocStatistics.freeListBytes);
970     
971     // Gather icon statistics.
972     data.statisticsNumbers.set(ASCIILiteral("IconPageURLMappingCount"), iconDatabase().pageURLMappingCount());
973     data.statisticsNumbers.set(ASCIILiteral("IconRetainedPageURLCount"), iconDatabase().retainedPageURLCount());
974     data.statisticsNumbers.set(ASCIILiteral("IconRecordCount"), iconDatabase().iconRecordCount());
975     data.statisticsNumbers.set(ASCIILiteral("IconsWithDataCount"), iconDatabase().iconRecordCountWithData());
976     
977     // Gather font statistics.
978     auto& fontCache = FontCache::singleton();
979     data.statisticsNumbers.set(ASCIILiteral("CachedFontDataCount"), fontCache.fontCount());
980     data.statisticsNumbers.set(ASCIILiteral("CachedFontDataInactiveCount"), fontCache.inactiveFontCount());
981     
982     // Gather glyph page statistics.
983     data.statisticsNumbers.set(ASCIILiteral("GlyphPageCount"), GlyphPage::count());
984     
985     // Get WebCore memory cache statistics
986     getWebCoreMemoryCacheStatistics(data.webCoreCacheStatistics);
987     
988     parentProcessConnection()->send(Messages::WebProcessPool::DidGetStatistics(data, callbackID), 0);
989 }
990
991 void WebProcess::garbageCollectJavaScriptObjects()
992 {
993     GCController::singleton().garbageCollectNow();
994 }
995
996 void WebProcess::setJavaScriptGarbageCollectorTimerEnabled(bool flag)
997 {
998     GCController::singleton().setJavaScriptGarbageCollectorTimerEnabled(flag);
999 }
1000
1001 void WebProcess::handleInjectedBundleMessage(const String& messageName, const UserData& messageBody)
1002 {
1003     InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1004     if (!injectedBundle)
1005         return;
1006
1007     injectedBundle->didReceiveMessage(messageName, transformHandlesToObjects(messageBody.object()).get());
1008 }
1009
1010 void WebProcess::setInjectedBundleParameter(const String& key, const IPC::DataReference& value)
1011 {
1012     InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1013     if (!injectedBundle)
1014         return;
1015
1016     injectedBundle->setBundleParameter(key, value);
1017 }
1018
1019 void WebProcess::setInjectedBundleParameters(const IPC::DataReference& value)
1020 {
1021     InjectedBundle* injectedBundle = WebProcess::singleton().injectedBundle();
1022     if (!injectedBundle)
1023         return;
1024
1025     injectedBundle->setBundleParameters(value);
1026 }
1027
1028 bool WebProcess::usesNetworkProcess() const
1029 {
1030 #if ENABLE(NETWORK_PROCESS)
1031     return m_usesNetworkProcess;
1032 #else
1033     return false;
1034 #endif
1035 }
1036
1037 #if ENABLE(NETWORK_PROCESS)
1038 NetworkProcessConnection* WebProcess::networkConnection()
1039 {
1040     ASSERT(m_usesNetworkProcess);
1041
1042     // If we've lost our connection to the network process (e.g. it crashed) try to re-establish it.
1043     if (!m_networkProcessConnection)
1044         ensureNetworkProcessConnection();
1045     
1046     // If we failed to re-establish it then we are beyond recovery and should crash.
1047     if (!m_networkProcessConnection)
1048         CRASH();
1049     
1050     return m_networkProcessConnection.get();
1051 }
1052
1053 void WebProcess::networkProcessConnectionClosed(NetworkProcessConnection* connection)
1054 {
1055     ASSERT(m_networkProcessConnection);
1056     ASSERT_UNUSED(connection, m_networkProcessConnection == connection);
1057
1058     m_networkProcessConnection = nullptr;
1059     
1060     m_webResourceLoadScheduler->networkProcessCrashed();
1061 }
1062
1063 WebResourceLoadScheduler& WebProcess::webResourceLoadScheduler()
1064 {
1065     return *m_webResourceLoadScheduler;
1066 }
1067 #endif // ENABLED(NETWORK_PROCESS)
1068
1069 #if ENABLE(DATABASE_PROCESS)
1070 void WebProcess::webToDatabaseProcessConnectionClosed(WebToDatabaseProcessConnection* connection)
1071 {
1072     ASSERT(m_webToDatabaseProcessConnection);
1073     ASSERT(m_webToDatabaseProcessConnection == connection);
1074
1075     m_webToDatabaseProcessConnection = nullptr;
1076 }
1077
1078 WebToDatabaseProcessConnection* WebProcess::webToDatabaseProcessConnection()
1079 {
1080     if (!m_webToDatabaseProcessConnection)
1081         ensureWebToDatabaseProcessConnection();
1082
1083     return m_webToDatabaseProcessConnection.get();
1084 }
1085
1086 void WebProcess::ensureWebToDatabaseProcessConnection()
1087 {
1088     if (m_webToDatabaseProcessConnection)
1089         return;
1090
1091     IPC::Attachment encodedConnectionIdentifier;
1092
1093     if (!parentProcessConnection()->sendSync(Messages::WebProcessProxy::GetDatabaseProcessConnection(),
1094         Messages::WebProcessProxy::GetDatabaseProcessConnection::Reply(encodedConnectionIdentifier), 0))
1095         return;
1096
1097 #if USE(UNIX_DOMAIN_SOCKETS)
1098     IPC::Connection::Identifier connectionIdentifier = encodedConnectionIdentifier.releaseFileDescriptor();
1099 #elif OS(DARWIN)
1100     IPC::Connection::Identifier connectionIdentifier(encodedConnectionIdentifier.port());
1101 #else
1102     ASSERT_NOT_REACHED();
1103 #endif
1104     if (IPC::Connection::identifierIsNull(connectionIdentifier))
1105         return;
1106     m_webToDatabaseProcessConnection = WebToDatabaseProcessConnection::create(connectionIdentifier);
1107 }
1108
1109 #endif // ENABLED(DATABASE_PROCESS)
1110
1111 void WebProcess::downloadRequest(uint64_t downloadID, uint64_t initiatingPageID, const ResourceRequest& request)
1112 {
1113     WebPage* initiatingPage = initiatingPageID ? webPage(initiatingPageID) : 0;
1114
1115     ResourceRequest requestWithOriginalURL = request;
1116     if (initiatingPage)
1117         initiatingPage->mainFrame()->loader().setOriginalURLForDownloadRequest(requestWithOriginalURL);
1118
1119     downloadManager().startDownload(downloadID, requestWithOriginalURL);
1120 }
1121
1122 void WebProcess::resumeDownload(uint64_t downloadID, const IPC::DataReference& resumeData, const String& path, const WebKit::SandboxExtension::Handle& sandboxExtensionHandle)
1123 {
1124     downloadManager().resumeDownload(downloadID, resumeData, path, sandboxExtensionHandle);
1125 }
1126
1127 void WebProcess::cancelDownload(uint64_t downloadID)
1128 {
1129     downloadManager().cancelDownload(downloadID);
1130 }
1131
1132 void WebProcess::setEnhancedAccessibility(bool flag)
1133 {
1134     WebCore::AXObjectCache::setEnhancedUserInterfaceAccessibility(flag);
1135 }
1136     
1137 void WebProcess::startMemorySampler(const SandboxExtension::Handle& sampleLogFileHandle, const String& sampleLogFilePath, const double interval)
1138 {
1139 #if ENABLE(MEMORY_SAMPLER)    
1140     WebMemorySampler::singleton()->start(sampleLogFileHandle, sampleLogFilePath, interval);
1141 #else
1142     UNUSED_PARAM(sampleLogFileHandle);
1143     UNUSED_PARAM(sampleLogFilePath);
1144     UNUSED_PARAM(interval);
1145 #endif
1146 }
1147     
1148 void WebProcess::stopMemorySampler()
1149 {
1150 #if ENABLE(MEMORY_SAMPLER)
1151     WebMemorySampler::singleton()->stop();
1152 #endif
1153 }
1154
1155 void WebProcess::setTextCheckerState(const TextCheckerState& textCheckerState)
1156 {
1157     bool continuousSpellCheckingTurnedOff = !textCheckerState.isContinuousSpellCheckingEnabled && m_textCheckerState.isContinuousSpellCheckingEnabled;
1158     bool grammarCheckingTurnedOff = !textCheckerState.isGrammarCheckingEnabled && m_textCheckerState.isGrammarCheckingEnabled;
1159
1160     m_textCheckerState = textCheckerState;
1161
1162     if (!continuousSpellCheckingTurnedOff && !grammarCheckingTurnedOff)
1163         return;
1164
1165     for (auto& page : m_pageMap.values()) {
1166         if (continuousSpellCheckingTurnedOff)
1167             page->unmarkAllMisspellings();
1168         if (grammarCheckingTurnedOff)
1169             page->unmarkAllBadGrammar();
1170     }
1171 }
1172
1173 void WebProcess::releasePageCache()
1174 {
1175     PageCache::singleton().pruneToSizeNow(0, PruningReason::MemoryPressure);
1176 }
1177
1178 void WebProcess::fetchWebsiteData(WebCore::SessionID sessionID, uint64_t websiteDataTypes, uint64_t callbackID)
1179 {
1180     WebsiteData websiteData;
1181
1182     if (websiteDataTypes & WebsiteDataTypeMemoryCache) {
1183         for (auto& origin : MemoryCache::singleton().originsWithCache(sessionID))
1184             websiteData.entries.append(WebsiteData::Entry { origin, WebsiteDataTypeMemoryCache });
1185     }
1186
1187     parentProcessConnection()->send(Messages::WebProcessProxy::DidFetchWebsiteData(callbackID, websiteData), 0);
1188 }
1189
1190 void WebProcess::deleteWebsiteData(SessionID sessionID, uint64_t websiteDataTypes, std::chrono::system_clock::time_point modifiedSince, uint64_t callbackID)
1191 {
1192     UNUSED_PARAM(modifiedSince);
1193
1194     if (websiteDataTypes & WebsiteDataTypeMemoryCache) {
1195         PageCache::singleton().pruneToSizeNow(0, PruningReason::None);
1196         MemoryCache::singleton().evictResources(sessionID);
1197
1198         CrossOriginPreflightResultCache::singleton().empty();
1199     }
1200
1201     parentProcessConnection()->send(Messages::WebProcessProxy::DidDeleteWebsiteData(callbackID), 0);
1202 }
1203
1204 void WebProcess::deleteWebsiteDataForOrigins(WebCore::SessionID sessionID, uint64_t websiteDataTypes, const Vector<WebCore::SecurityOriginData>& originDatas, uint64_t callbackID)
1205 {
1206     if (websiteDataTypes & WebsiteDataTypeMemoryCache) {
1207         HashSet<RefPtr<SecurityOrigin>> origins;
1208         for (auto& originData : originDatas)
1209             origins.add(originData.securityOrigin());
1210
1211         MemoryCache::singleton().removeResourcesWithOrigins(sessionID, origins);
1212     }
1213
1214     parentProcessConnection()->send(Messages::WebProcessProxy::DidDeleteWebsiteDataForOrigins(callbackID), 0);
1215 }
1216
1217 #if !PLATFORM(COCOA)
1218 void WebProcess::initializeProcessName(const ChildProcessInitializationParameters&)
1219 {
1220 }
1221
1222 void WebProcess::initializeSandbox(const ChildProcessInitializationParameters&, SandboxInitializationParameters&)
1223 {
1224 }
1225
1226 void WebProcess::platformInitializeProcess(const ChildProcessInitializationParameters&)
1227 {
1228 }
1229
1230 void WebProcess::updateActivePages()
1231 {
1232 }
1233
1234 #endif
1235
1236 #if PLATFORM(IOS)
1237 void WebProcess::resetAllGeolocationPermissions()
1238 {
1239     for (auto& page : m_pageMap.values()) {
1240         if (Frame* mainFrame = page->mainFrame())
1241             mainFrame->resetAllGeolocationPermission();
1242     }
1243 }
1244 #endif
1245
1246 void WebProcess::actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend shouldAcknowledgeWhenReadyToSuspend)
1247 {
1248     MemoryPressureHandler::singleton().releaseMemory(Critical::Yes, Synchronous::Yes);
1249     setAllLayerTreeStatesFrozen(true);
1250
1251     if (markAllLayersVolatileIfPossible()) {
1252         if (shouldAcknowledgeWhenReadyToSuspend == ShouldAcknowledgeWhenReadyToSuspend::Yes)
1253             parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1254         return;
1255     }
1256     m_shouldAcknowledgeWhenReadyToSuspend = shouldAcknowledgeWhenReadyToSuspend;
1257     m_processSuspensionCleanupTimer.startRepeating(std::chrono::milliseconds(20));
1258 }
1259
1260 void WebProcess::processWillSuspendImminently(bool& handled)
1261 {
1262     if (parentProcessConnection()->inSendSync()) {
1263         // Avoid reentrency bugs such as rdar://problem/21605505 by just bailing
1264         // if we get an incoming ProcessWillSuspendImminently message when waiting for a
1265         // reply to a sync message.
1266         // FIXME: ProcessWillSuspendImminently should not be a sync message.
1267         return;
1268     }
1269
1270     supplement<WebDatabaseManager>()->closeAllDatabases();
1271     actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::No);
1272     handled = true;
1273 }
1274
1275 void WebProcess::prepareToSuspend()
1276 {
1277     actualPrepareToSuspend(ShouldAcknowledgeWhenReadyToSuspend::Yes);
1278 }
1279
1280 void WebProcess::cancelPrepareToSuspend()
1281 {
1282     setAllLayerTreeStatesFrozen(false);
1283
1284     // If we've already finished cleaning up and sent ProcessReadyToSuspend, we
1285     // shouldn't send DidCancelProcessSuspension; the UI process strictly expects one or the other.
1286     if (!m_processSuspensionCleanupTimer.isActive())
1287         return;
1288
1289     m_processSuspensionCleanupTimer.stop();
1290     parentProcessConnection()->send(Messages::WebProcessProxy::DidCancelProcessSuspension(), 0);
1291 }
1292
1293 bool WebProcess::markAllLayersVolatileIfPossible()
1294 {
1295     bool successfullyMarkedAllLayersVolatile = true;
1296     for (auto& page : m_pageMap.values())
1297         successfullyMarkedAllLayersVolatile &= page->markLayersVolatileImmediatelyIfPossible();
1298
1299     return successfullyMarkedAllLayersVolatile;
1300 }
1301
1302 void WebProcess::setAllLayerTreeStatesFrozen(bool frozen)
1303 {
1304     for (auto& page : m_pageMap.values())
1305         page->setLayerTreeStateIsFrozen(frozen);
1306 }
1307
1308 void WebProcess::processSuspensionCleanupTimerFired()
1309 {
1310     if (!markAllLayersVolatileIfPossible())
1311         return;
1312     m_processSuspensionCleanupTimer.stop();
1313     if (m_shouldAcknowledgeWhenReadyToSuspend == ShouldAcknowledgeWhenReadyToSuspend::Yes)
1314         parentProcessConnection()->send(Messages::WebProcessProxy::ProcessReadyToSuspend(), 0);
1315 }
1316     
1317 void WebProcess::processDidResume()
1318 {
1319     m_processSuspensionCleanupTimer.stop();
1320     setAllLayerTreeStatesFrozen(false);
1321 }
1322
1323 void WebProcess::pageDidEnterWindow(uint64_t pageID)
1324 {
1325     m_pagesInWindows.add(pageID);
1326     m_nonVisibleProcessCleanupTimer.stop();
1327 }
1328
1329 void WebProcess::pageWillLeaveWindow(uint64_t pageID)
1330 {
1331     m_pagesInWindows.remove(pageID);
1332
1333     if (m_pagesInWindows.isEmpty() && !m_nonVisibleProcessCleanupTimer.isActive())
1334         m_nonVisibleProcessCleanupTimer.startOneShot(nonVisibleProcessCleanupDelay);
1335 }
1336     
1337 void WebProcess::nonVisibleProcessCleanupTimerFired()
1338 {
1339     ASSERT(m_pagesInWindows.isEmpty());
1340     if (!m_pagesInWindows.isEmpty())
1341         return;
1342
1343 #if PLATFORM(COCOA)
1344     destroyRenderingResources();
1345 #endif
1346 }
1347
1348 RefPtr<API::Object> WebProcess::transformHandlesToObjects(API::Object* object)
1349 {
1350     struct Transformer final : UserData::Transformer {
1351         Transformer(WebProcess& webProcess)
1352             : m_webProcess(webProcess)
1353         {
1354         }
1355
1356         virtual bool shouldTransformObject(const API::Object& object) const override
1357         {
1358             switch (object.type()) {
1359             case API::Object::Type::FrameHandle:
1360                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
1361
1362             case API::Object::Type::PageHandle:
1363                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
1364
1365             case API::Object::Type::PageGroupHandle:
1366 #if PLATFORM(COCOA)
1367             case API::Object::Type::ObjCObjectGraph:
1368 #endif
1369                 return true;
1370
1371             default:
1372                 return false;
1373             }
1374         }
1375
1376         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
1377         {
1378             switch (object.type()) {
1379             case API::Object::Type::FrameHandle:
1380                 return m_webProcess.webFrame(static_cast<const API::FrameHandle&>(object).frameID());
1381
1382             case API::Object::Type::PageGroupHandle:
1383                 return m_webProcess.webPageGroup(static_cast<const API::PageGroupHandle&>(object).webPageGroupData());
1384
1385             case API::Object::Type::PageHandle:
1386                 return m_webProcess.webPage(static_cast<const API::PageHandle&>(object).pageID());
1387
1388 #if PLATFORM(COCOA)
1389             case API::Object::Type::ObjCObjectGraph:
1390                 return m_webProcess.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
1391 #endif
1392             default:
1393                 return &object;
1394             }
1395         }
1396
1397         WebProcess& m_webProcess;
1398     };
1399
1400     return UserData::transform(object, Transformer(*this));
1401 }
1402
1403 RefPtr<API::Object> WebProcess::transformObjectsToHandles(API::Object* object)
1404 {
1405     struct Transformer final : UserData::Transformer {
1406         virtual bool shouldTransformObject(const API::Object& object) const override
1407         {
1408             switch (object.type()) {
1409             case API::Object::Type::BundleFrame:
1410             case API::Object::Type::BundlePage:
1411             case API::Object::Type::BundlePageGroup:
1412 #if PLATFORM(COCOA)
1413             case API::Object::Type::ObjCObjectGraph:
1414 #endif
1415                 return true;
1416
1417             default:
1418                 return false;
1419             }
1420         }
1421
1422         virtual RefPtr<API::Object> transformObject(API::Object& object) const override
1423         {
1424             switch (object.type()) {
1425             case API::Object::Type::BundleFrame:
1426                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrame&>(object).frameID());
1427
1428             case API::Object::Type::BundlePage:
1429                 return API::PageHandle::createAutoconverting(static_cast<const WebPage&>(object).pageID());
1430
1431             case API::Object::Type::BundlePageGroup: {
1432                 WebPageGroupData pageGroupData;
1433                 pageGroupData.pageGroupID = static_cast<const WebPageGroupProxy&>(object).pageGroupID();
1434
1435                 return API::PageGroupHandle::create(WTF::move(pageGroupData));
1436             }
1437
1438 #if PLATFORM(COCOA)
1439             case API::Object::Type::ObjCObjectGraph:
1440                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1441 #endif
1442
1443             default:
1444                 return &object;
1445             }
1446         }
1447     };
1448
1449     return UserData::transform(object, Transformer());
1450 }
1451
1452 void WebProcess::setMemoryCacheDisabled(bool disabled)
1453 {
1454     auto& memoryCache = MemoryCache::singleton();
1455     if (memoryCache.disabled() != disabled)
1456         memoryCache.setDisabled(disabled);
1457 }
1458
1459 #if ENABLE(SERVICE_CONTROLS)
1460 void WebProcess::setEnabledServices(bool hasImageServices, bool hasSelectionServices, bool hasRichContentServices)
1461 {
1462     m_hasImageServices = hasImageServices;
1463     m_hasSelectionServices = hasSelectionServices;
1464     m_hasRichContentServices = hasRichContentServices;
1465 }
1466 #endif
1467
1468 void WebProcess::prefetchDNS(const String& hostname)
1469 {
1470     if (hostname.isEmpty())
1471         return;
1472
1473 #if ENABLE(NETWORK_PROCESS)
1474     if (usesNetworkProcess()) {
1475         if (m_dnsPrefetchedHosts.add(hostname).isNewEntry)
1476             networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::PrefetchDNS(hostname), 0);
1477         // The DNS prefetched hosts cache is only to avoid asking for the same hosts too many times
1478         // in a very short period of time, producing a lot of IPC traffic. So we clear this cache after
1479         // some time of no DNS requests.
1480         m_dnsPrefetchHystereris.impulse();
1481         return;
1482     }
1483 #endif
1484     WebCore::prefetchDNS(hostname);
1485 }
1486
1487 } // namespace WebKit