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