Clearing Website data for a given session should not shut down cached processes for...
[WebKit.git] / Source / WebKit / UIProcess / WebProcessProxy.cpp
1 /*
2  * Copyright (C) 2010-2019 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 "WebProcessProxy.h"
28
29 #include "APIFrameHandle.h"
30 #include "APIPageGroupHandle.h"
31 #include "APIPageHandle.h"
32 #include "DataReference.h"
33 #include "DownloadProxyMap.h"
34 #include "LoadParameters.h"
35 #include "Logging.h"
36 #include "PluginInfoStore.h"
37 #include "PluginProcessManager.h"
38 #include "ProvisionalPageProxy.h"
39 #include "TextChecker.h"
40 #include "TextCheckerState.h"
41 #include "UserData.h"
42 #include "WebBackForwardListItem.h"
43 #include "WebInspectorUtilities.h"
44 #include "WebNavigationDataStore.h"
45 #include "WebNotificationManagerProxy.h"
46 #include "WebPageGroup.h"
47 #include "WebPageMessages.h"
48 #include "WebPageProxy.h"
49 #include "WebPasteboardProxy.h"
50 #include "WebProcessCache.h"
51 #include "WebProcessDataStoreParameters.h"
52 #include "WebProcessMessages.h"
53 #include "WebProcessPool.h"
54 #include "WebProcessProxyMessages.h"
55 #include "WebSWContextManagerConnectionMessages.h"
56 #include "WebUserContentControllerProxy.h"
57 #include "WebsiteData.h"
58 #include "WebsiteDataFetchOption.h"
59 #include <WebCore/DiagnosticLoggingKeys.h>
60 #include <WebCore/PrewarmInformation.h>
61 #include <WebCore/PublicSuffix.h>
62 #include <WebCore/SuddenTermination.h>
63 #include <stdio.h>
64 #include <wtf/Algorithms.h>
65 #include <wtf/NeverDestroyed.h>
66 #include <wtf/RunLoop.h>
67 #include <wtf/URL.h>
68 #include <wtf/text/CString.h>
69 #include <wtf/text/StringBuilder.h>
70 #include <wtf/text/WTFString.h>
71
72 #if PLATFORM(COCOA)
73 #include "ObjCObjectGraph.h"
74 #include "PDFPlugin.h"
75 #include "UserMediaCaptureManagerProxy.h"
76 #include "VersionChecks.h"
77 #endif
78
79 #if PLATFORM(MAC)
80 #include "HighPerformanceGPUManager.h"
81 #endif
82
83 #if ENABLE(SEC_ITEM_SHIM)
84 #include "SecItemShimProxy.h"
85 #endif
86
87 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
88 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
89
90 namespace WebKit {
91 using namespace WebCore;
92
93 static bool isMainThreadOrCheckDisabled()
94 {
95 #if PLATFORM(IOS_FAMILY)
96     return LIKELY(RunLoop::isMain()) || !linkedOnOrAfter(SDKVersion::FirstWithMainThreadReleaseAssertionInWebPageProxy);
97 #elif PLATFORM(MAC)
98     return LIKELY(RunLoop::isMain()) || !linkedOnOrAfter(SDKVersion::FirstWithMainThreadReleaseAssertionInWebPageProxy);
99 #else
100     return RunLoop::isMain();
101 #endif
102 }
103
104 static HashMap<ProcessIdentifier, WebProcessProxy*>& allProcesses()
105 {
106     ASSERT(isMainThreadOrCheckDisabled());
107     static NeverDestroyed<HashMap<ProcessIdentifier, WebProcessProxy*>> map;
108     return map;
109 }
110
111 WebProcessProxy* WebProcessProxy::processForIdentifier(ProcessIdentifier identifier)
112 {
113     return allProcesses().get(identifier);
114 }
115
116 static WebProcessProxy::WebPageProxyMap& globalPageMap()
117 {
118     ASSERT(isMainThreadOrCheckDisabled());
119     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
120     return pageMap;
121 }
122
123 void WebProcessProxy::forWebPagesWithOrigin(PAL::SessionID sessionID, const SecurityOriginData& origin, const Function<void(WebPageProxy&)>& callback)
124 {
125     for (auto* page : globalPageMap().values()) {
126         if (page->sessionID() != sessionID || SecurityOriginData::fromURL(URL { { }, page->currentURL() }) != origin)
127             continue;
128         callback(*page);
129     }
130 }
131
132 Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed, ShouldLaunchProcess shouldLaunchProcess)
133 {
134     auto proxy = adoptRef(*new WebProcessProxy(processPool, websiteDataStore, isPrewarmed));
135     if (shouldLaunchProcess == ShouldLaunchProcess::Yes)
136         proxy->connect();
137     return proxy;
138 }
139
140 Ref<WebProcessProxy> WebProcessProxy::createForServiceWorkers(WebProcessPool& processPool, RegistrableDomain&& registrableDomain, WebsiteDataStore& websiteDataStore)
141 {
142     auto proxy = adoptRef(*new WebProcessProxy(processPool, &websiteDataStore, IsPrewarmed::No));
143     proxy->m_registrableDomain = WTFMove(registrableDomain);
144     proxy->m_serviceWorkerInformation = ServiceWorkerInformation { WebPageProxyIdentifier::generate(), PageIdentifier::generate() };
145     proxy->connect();
146     return proxy;
147 }
148
149 WebProcessProxy::WebProcessProxy(WebProcessPool& processPool, WebsiteDataStore* websiteDataStore, IsPrewarmed isPrewarmed)
150     : AuxiliaryProcessProxy(processPool.alwaysRunsAtBackgroundPriority())
151     , m_responsivenessTimer(*this)
152     , m_backgroundResponsivenessTimer(*this)
153     , m_processPool(processPool, isPrewarmed == IsPrewarmed::Yes ? IsWeak::Yes : IsWeak::No)
154     , m_mayHaveUniversalFileReadSandboxExtension(false)
155     , m_numberOfTimesSuddenTerminationWasDisabled(0)
156     , m_throttler(*this, processPool.shouldTakeUIBackgroundAssertion())
157     , m_isResponsive(NoOrMaybe::Maybe)
158     , m_visiblePageCounter([this](RefCounterEvent) { updateBackgroundResponsivenessTimer(); })
159     , m_websiteDataStore(websiteDataStore)
160 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
161     , m_userMediaCaptureManagerProxy(makeUnique<UserMediaCaptureManagerProxy>(*this))
162 #endif
163     , m_isPrewarmed(isPrewarmed == IsPrewarmed::Yes)
164 {
165     RELEASE_ASSERT(isMainThreadOrCheckDisabled());
166
167     auto result = allProcesses().add(coreProcessIdentifier(), this);
168     ASSERT_UNUSED(result, result.isNewEntry);
169
170     WebPasteboardProxy::singleton().addWebProcessProxy(*this);
171 }
172
173 WebProcessProxy::~WebProcessProxy()
174 {
175     RELEASE_ASSERT(isMainThreadOrCheckDisabled());
176     ASSERT(m_pageURLRetainCountMap.isEmpty());
177
178     if (m_processPool)
179         m_processPool->clearWebProcessHasUploads(coreProcessIdentifier());
180
181     auto result = allProcesses().remove(coreProcessIdentifier());
182     ASSERT_UNUSED(result, result);
183
184     WebPasteboardProxy::singleton().removeWebProcessProxy(*this);
185
186 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
187     if (state() == State::Running)
188         processPool().stopDisplayLinks(*connection());
189 #endif
190
191     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
192     for (auto& callback : isResponsiveCallbacks)
193         callback(false);
194
195     if (m_webConnection)
196         m_webConnection->invalidate();
197
198     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
199         WebCore::enableSuddenTermination();
200
201 #if PLATFORM(MAC)
202     HighPerformanceGPUManager::singleton().removeProcessRequiringHighPerformance(this);
203 #endif
204 }
205
206 void WebProcessProxy::setIsInProcessCache(bool value)
207 {
208     if (value) {
209         RELEASE_ASSERT(m_pageMap.isEmpty());
210         RELEASE_ASSERT(!m_suspendedPageCount);
211         RELEASE_ASSERT(m_provisionalPages.isEmpty());
212     }
213
214     ASSERT(m_isInProcessCache != value);
215     m_isInProcessCache = value;
216
217     send(Messages::WebProcess::SetIsInProcessCache(m_isInProcessCache), 0);
218
219     if (m_isInProcessCache) {
220         // WebProcessProxy objects normally keep the process pool alive but we do not want this to be the case
221         // for cached processes or it would leak the pool.
222         m_processPool.setIsWeak(IsWeak::Yes);
223     } else {
224         RELEASE_ASSERT(m_processPool);
225         m_processPool.setIsWeak(IsWeak::No);
226     }
227 }
228
229 void WebProcessProxy::setWebsiteDataStore(WebsiteDataStore& dataStore)
230 {
231     ASSERT(!m_websiteDataStore);
232     m_websiteDataStore = &dataStore;
233     updateRegistrationWithDataStore();
234     send(Messages::WebProcess::SetWebsiteDataStoreParameters(processPool().webProcessDataStoreParameters(*this, dataStore)), 0);
235 }
236
237 void WebProcessProxy::updateRegistrationWithDataStore()
238 {
239     if (!m_websiteDataStore)
240         return;
241     
242     bool shouldBeRegistered = processPool().dummyProcessProxy() != this && (pageCount() || provisionalPageCount());
243     if (shouldBeRegistered)
244         m_websiteDataStore->registerProcess(*this);
245     else
246         m_websiteDataStore->unregisterProcess(*this);
247 }
248
249 void WebProcessProxy::addProvisionalPageProxy(ProvisionalPageProxy& provisionalPage)
250 {
251     ASSERT(!m_isInProcessCache);
252     ASSERT(!m_provisionalPages.contains(&provisionalPage));
253     m_provisionalPages.add(&provisionalPage);
254     updateRegistrationWithDataStore();
255 }
256
257 void WebProcessProxy::removeProvisionalPageProxy(ProvisionalPageProxy& provisionalPage)
258 {
259     ASSERT(m_provisionalPages.contains(&provisionalPage));
260     m_provisionalPages.remove(&provisionalPage);
261     updateRegistrationWithDataStore();
262     if (m_provisionalPages.isEmpty())
263         maybeShutDown();
264 }
265
266 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
267 {
268     launchOptions.processType = ProcessLauncher::ProcessType::Web;
269
270     AuxiliaryProcessProxy::getLaunchOptions(launchOptions);
271
272     if (!m_processPool->customWebContentServiceBundleIdentifier().isEmpty())
273         launchOptions.customWebContentServiceBundleIdentifier = m_processPool->customWebContentServiceBundleIdentifier().ascii();
274     if (WebKit::isInspectorProcessPool(processPool()))
275         launchOptions.extraInitializationData.add("inspector-process"_s, "1"_s);
276
277     auto overrideLanguages = m_processPool->configuration().overrideLanguages();
278     if (overrideLanguages.size()) {
279         StringBuilder languageString;
280         for (size_t i = 0; i < overrideLanguages.size(); ++i) {
281             if (i)
282                 languageString.append(',');
283             languageString.append(overrideLanguages[i]);
284         }
285         launchOptions.extraInitializationData.add("OverrideLanguages"_s, languageString.toString());
286     }
287
288     launchOptions.nonValidInjectedCodeAllowed = shouldAllowNonValidInjectedCode();
289
290     if (isPrewarmed())
291         launchOptions.extraInitializationData.add("is-prewarmed"_s, "1"_s);
292
293     if (processPool().shouldMakeNextWebProcessLaunchFailForTesting()) {
294         processPool().setShouldMakeNextWebProcessLaunchFailForTesting(false);
295         launchOptions.shouldMakeProcessLaunchFailForTesting = true;
296     }
297
298     if (m_serviceWorkerInformation) {
299         launchOptions.extraInitializationData.add("service-worker-process"_s, "1"_s);
300         launchOptions.extraInitializationData.add("registrable-domain"_s, m_registrableDomain->string());
301     }
302 }
303
304 #if !PLATFORM(GTK) && !PLATFORM(WPE)
305 void WebProcessProxy::platformGetLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
306 {
307 }
308 #endif
309
310 bool WebProcessProxy::shouldSendPendingMessage(const PendingMessage& message)
311 {
312 #if HAVE(SANDBOX_ISSUE_MACH_EXTENSION_TO_PROCESS_BY_PID)
313     if (message.encoder->messageName() == "LoadRequestWaitingForPID") {
314         auto buffer = message.encoder->buffer();
315         auto bufferSize = message.encoder->bufferSize();
316         std::unique_ptr<IPC::Decoder> decoder = makeUnique<IPC::Decoder>(buffer, bufferSize, nullptr, Vector<IPC::Attachment> { });
317         LoadParameters loadParameters;
318         URL resourceDirectoryURL;
319         WebPageProxyIdentifier pageID;
320         if (decoder->decode(loadParameters) && decoder->decode(resourceDirectoryURL) && decoder->decode(pageID)) {
321             if (auto* page = WebProcessProxy::webPage(pageID)) {
322                 page->maybeInitializeSandboxExtensionHandle(static_cast<WebProcessProxy&>(*this), loadParameters.request.url(), resourceDirectoryURL, loadParameters.sandboxExtensionHandle);
323                 send(Messages::WebPage::LoadRequest(loadParameters), decoder->destinationID());
324             }
325         } else
326             ASSERT_NOT_REACHED();
327         return false;
328     }
329 #endif
330     return true;
331 }
332
333 void WebProcessProxy::connectionWillOpen(IPC::Connection& connection)
334 {
335     ASSERT(this->connection() == &connection);
336
337     // Throttling IPC messages coming from the WebProcesses so that the UIProcess stays responsive, even
338     // if one of the WebProcesses misbehaves.
339     connection.enableIncomingMessagesThrottling();
340
341     // Use this flag to force synchronous messages to be treated as asynchronous messages in the WebProcess.
342     // Otherwise, the WebProcess would process incoming synchronous IPC while waiting for a synchronous IPC
343     // reply from the UIProcess, which would be unsafe.
344     connection.setOnlySendMessagesAsDispatchWhenWaitingForSyncReplyWhenProcessingSuchAMessage(true);
345
346 #if ENABLE(SEC_ITEM_SHIM)
347     SecItemShimProxy::singleton().initializeConnection(connection);
348 #endif
349 }
350
351 void WebProcessProxy::processWillShutDown(IPC::Connection& connection)
352 {
353     ASSERT_UNUSED(connection, this->connection() == &connection);
354
355 #if PLATFORM(MAC) && ENABLE(WEBPROCESS_WINDOWSERVER_BLOCKING)
356     processPool().stopDisplayLinks(connection);
357 #endif
358 }
359
360 void WebProcessProxy::shutDown()
361 {
362     RELEASE_ASSERT(isMainThreadOrCheckDisabled());
363
364     shutDownProcess();
365
366     if (m_webConnection) {
367         m_webConnection->invalidate();
368         m_webConnection = nullptr;
369     }
370
371     m_responsivenessTimer.invalidate();
372     m_backgroundResponsivenessTimer.invalidate();
373     m_tokenForHoldingLockedFiles = nullptr;
374
375     for (auto& frame : copyToVector(m_frameMap.values()))
376         frame->webProcessWillShutDown();
377     m_frameMap.clear();
378
379     for (auto* visitedLinkStore : m_visitedLinkStoresWithUsers.keys())
380         visitedLinkStore->removeProcess(*this);
381     m_visitedLinkStoresWithUsers.clear();
382
383     for (auto* webUserContentControllerProxy : m_webUserContentControllerProxies)
384         webUserContentControllerProxy->removeProcess(*this);
385     m_webUserContentControllerProxies.clear();
386
387     m_userInitiatedActionMap.clear();
388
389     m_processPool->disconnectProcess(this);
390 }
391
392 WebPageProxy* WebProcessProxy::webPage(WebPageProxyIdentifier pageID)
393 {
394     return globalPageMap().get(pageID);
395 }
396
397 #if ENABLE(RESOURCE_LOAD_STATISTICS)
398 void WebProcessProxy::notifyPageStatisticsAndDataRecordsProcessed()
399 {
400     for (auto& page : globalPageMap())
401         page.value->postMessageToInjectedBundle("WebsiteDataScanForRegistrableDomainsFinished", nullptr);
402 }
403
404 void WebProcessProxy::notifyWebsiteDataScanForRegistrableDomainsFinished()
405 {
406     for (auto& page : globalPageMap())
407         page.value->postMessageToInjectedBundle("WebsiteDataScanForRegistrableDomainsFinished", nullptr);
408 }
409
410 void WebProcessProxy::notifyWebsiteDataDeletionForRegistrableDomainsFinished()
411 {
412     for (auto& page : globalPageMap())
413         page.value->postMessageToInjectedBundle("WebsiteDataDeletionForRegistrableDomainsFinished", nullptr);
414 }
415
416 void WebProcessProxy::notifyPageStatisticsTelemetryFinished(API::Object* messageBody)
417 {
418     for (auto& page : globalPageMap())
419         page.value->postMessageToInjectedBundle("ResourceLoadStatisticsTelemetryFinished", messageBody);
420 }
421 #endif
422
423 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, Ref<API::PageConfiguration>&& pageConfiguration)
424 {
425     Ref<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, WTFMove(pageConfiguration));
426
427     addExistingWebPage(webPage.get(), BeginsUsingDataStore::Yes);
428
429     return webPage;
430 }
431
432 void WebProcessProxy::addExistingWebPage(WebPageProxy& webPage, BeginsUsingDataStore beginsUsingDataStore)
433 {
434     ASSERT(!m_pageMap.contains(webPage.identifier()));
435     ASSERT(!globalPageMap().contains(webPage.identifier()));
436     RELEASE_ASSERT(!m_isInProcessCache);
437     ASSERT(!m_websiteDataStore || m_websiteDataStore == &webPage.websiteDataStore());
438
439     if (beginsUsingDataStore == BeginsUsingDataStore::Yes)
440         m_processPool->pageBeginUsingWebsiteDataStore(webPage.identifier(), webPage.websiteDataStore());
441
442     m_pageMap.set(webPage.identifier(), &webPage);
443     globalPageMap().set(webPage.identifier(), &webPage);
444
445     updateRegistrationWithDataStore();
446     updateBackgroundResponsivenessTimer();
447 }
448
449 void WebProcessProxy::markIsNoLongerInPrewarmedPool()
450 {
451     ASSERT(m_isPrewarmed);
452
453     m_isPrewarmed = false;
454     RELEASE_ASSERT(m_processPool);
455     m_processPool.setIsWeak(IsWeak::No);
456
457     send(Messages::WebProcess::MarkIsNoLongerPrewarmed(), 0);
458 }
459
460 void WebProcessProxy::removeWebPage(WebPageProxy& webPage, EndsUsingDataStore endsUsingDataStore)
461 {
462     auto* removedPage = m_pageMap.take(webPage.identifier());
463     ASSERT_UNUSED(removedPage, removedPage == &webPage);
464     removedPage = globalPageMap().take(webPage.identifier());
465     ASSERT_UNUSED(removedPage, removedPage == &webPage);
466
467     if (endsUsingDataStore == EndsUsingDataStore::Yes)
468         m_processPool->pageEndUsingWebsiteDataStore(webPage.identifier(), webPage.websiteDataStore());
469
470     removeVisitedLinkStoreUser(webPage.visitedLinkStore(), webPage.identifier());
471     updateRegistrationWithDataStore();
472
473     updateBackgroundResponsivenessTimer();
474
475     maybeShutDown();
476 }
477
478 void WebProcessProxy::addVisitedLinkStoreUser(VisitedLinkStore& visitedLinkStore, WebPageProxyIdentifier pageID)
479 {
480     auto& users = m_visitedLinkStoresWithUsers.ensure(&visitedLinkStore, [] {
481         return HashSet<WebPageProxyIdentifier> { };
482     }).iterator->value;
483
484     ASSERT(!users.contains(pageID));
485     users.add(pageID);
486
487     if (users.size() == 1 && state() == State::Running)
488         visitedLinkStore.addProcess(*this);
489 }
490
491 void WebProcessProxy::removeVisitedLinkStoreUser(VisitedLinkStore& visitedLinkStore, WebPageProxyIdentifier pageID)
492 {
493     auto it = m_visitedLinkStoresWithUsers.find(&visitedLinkStore);
494     if (it == m_visitedLinkStoresWithUsers.end())
495         return;
496
497     auto& users = it->value;
498     users.remove(pageID);
499     if (users.isEmpty()) {
500         m_visitedLinkStoresWithUsers.remove(it);
501         visitedLinkStore.removeProcess(*this);
502     }
503 }
504
505 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy, WebPageCreationParameters& parameters)
506 {
507     m_webUserContentControllerProxies.add(&proxy);
508     proxy.addProcess(*this, parameters);
509 }
510
511 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
512 {
513     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
514     m_webUserContentControllerProxies.remove(&proxy);
515 }
516
517 void WebProcessProxy::assumeReadAccessToBaseURL(WebPageProxy& page, const String& urlString)
518 {
519     URL url(URL(), urlString);
520     if (!url.isLocalFile())
521         return;
522
523     // There's a chance that urlString does not point to a directory.
524     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
525     URL baseURL(URL(), url.baseAsString());
526     String path = baseURL.fileSystemPath();
527     if (path.isNull())
528         return;
529     
530     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
531     // to have read access to this directory already.
532     m_localPathsWithAssumedReadAccess.add(path);
533     page.addPreviouslyVisitedPath(path);
534 }
535
536 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
537 {
538     if (!url.isLocalFile())
539         return false;
540
541     String path = url.fileSystemPath();
542     auto startsWithURLPath = [&path](const String& assumedAccessPath) {
543         // There are no ".." components, because URL removes those.
544         return path.startsWith(assumedAccessPath);
545     };
546
547     auto& platformPaths = platformPathsWithAssumedReadAccess();
548     auto platformPathsEnd = platformPaths.end();
549     if (std::find_if(platformPaths.begin(), platformPathsEnd, startsWithURLPath) != platformPathsEnd)
550         return true;
551
552     auto localPathsEnd = m_localPathsWithAssumedReadAccess.end();
553     if (std::find_if(m_localPathsWithAssumedReadAccess.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
554         return true;
555
556     return false;
557 }
558
559 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
560 {
561     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
562 }
563
564 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
565 {
566     // FIXME: Consider checking that the URL is valid. Currently, WebProcess sends invalid URLs in many cases, but it probably doesn't have good reasons to do that.
567
568     // Any other non-file URL is OK.
569     if (!url.isLocalFile())
570         return true;
571
572     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
573     if (m_mayHaveUniversalFileReadSandboxExtension)
574         return true;
575
576     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
577     if (hasAssumedReadAccessToURL(url))
578         return true;
579
580     // Items in back/forward list have been already checked.
581     // One case where we don't have sandbox extensions for file URLs in b/f list is if the list has been reinstated after a crash or a browser restart.
582     String path = url.fileSystemPath();
583     for (auto& item : WebBackForwardListItem::allItems().values()) {
584         URL itemURL(URL(), item->url());
585         if (itemURL.isLocalFile() && itemURL.fileSystemPath() == path)
586             return true;
587         URL itemOriginalURL(URL(), item->originalURL());
588         if (itemOriginalURL.isLocalFile() && itemOriginalURL.fileSystemPath() == path)
589             return true;
590     }
591
592     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
593     RELEASE_LOG_ERROR(Loading, "Received an unexpected URL from the web process");
594     return false;
595 }
596
597 #if !PLATFORM(COCOA)
598 bool WebProcessProxy::fullKeyboardAccessEnabled()
599 {
600     return false;
601 }
602 #endif
603
604 bool WebProcessProxy::hasProvisionalPageWithID(WebPageProxyIdentifier pageID) const
605 {
606     for (auto* provisionalPage : m_provisionalPages) {
607         if (provisionalPage->page().identifier() == pageID)
608             return true;
609     }
610     return false;
611 }
612
613 bool WebProcessProxy::isAllowedToUpdateBackForwardItem(WebBackForwardListItem& item) const
614 {
615     if (m_pageMap.contains(item.pageID()))
616         return true;
617
618     if (hasProvisionalPageWithID(item.pageID()))
619         return true;
620
621     if (item.suspendedPage() && item.suspendedPage()->page().identifier() == item.pageID() && &item.suspendedPage()->process() == this)
622         return true;
623
624     return false;
625 }
626
627 void WebProcessProxy::updateBackForwardItem(const BackForwardListItemState& itemState)
628 {
629     auto* item = WebBackForwardListItem::itemForID(itemState.identifier);
630     if (!item || !isAllowedToUpdateBackForwardItem(*item))
631         return;
632
633     item->setPageState(PageState { itemState.pageState });
634 }
635
636 #if ENABLE(NETSCAPE_PLUGIN_API)
637 void WebProcessProxy::getPlugins(bool refresh, CompletionHandler<void(Vector<PluginInfo>&& plugins, Vector<PluginInfo>&& applicationPlugins, Optional<Vector<WebCore::SupportedPluginIdentifier>>&& supportedPluginIdentifiers)>&& completionHandler)
638 {
639     if (refresh)
640         m_processPool->pluginInfoStore().refresh();
641
642     auto supportedPluginIdentifiers = m_processPool->pluginInfoStore().supportedPluginIdentifiers();
643
644     Vector<PluginInfo> plugins;
645     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
646     for (size_t i = 0; i < pluginModules.size(); ++i)
647         plugins.append(pluginModules[i].info);
648
649     Vector<PluginInfo> applicationPlugins;
650 #if ENABLE(PDFKIT_PLUGIN)
651     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
652     if (!m_processPool->omitPDFSupport()) {
653         plugins.append(PDFPlugin::pluginInfo());
654         applicationPlugins.append(PDFPlugin::pluginInfo());
655     }
656 #endif
657     completionHandler(WTFMove(plugins), WTFMove(applicationPlugins), WTFMove(supportedPluginIdentifiers));
658 }
659 #endif // ENABLE(NETSCAPE_PLUGIN_API)
660
661 #if ENABLE(NETSCAPE_PLUGIN_API)
662 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply&& reply)
663 {
664     PluginProcessManager::singleton().getPluginProcessConnection(pluginProcessToken, WTFMove(reply));
665 }
666 #endif
667
668 void WebProcessProxy::getNetworkProcessConnection(Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply&& reply)
669 {
670     m_processPool->getNetworkProcessConnection(*this, WTFMove(reply));
671 }
672
673 #if !PLATFORM(COCOA)
674 bool WebProcessProxy::platformIsBeingDebugged() const
675 {
676     return false;
677 }
678 #endif
679
680 #if !PLATFORM(MAC)
681 bool WebProcessProxy::shouldAllowNonValidInjectedCode() const
682 {
683     return false;
684 }
685 #endif
686
687 void WebProcessProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
688 {
689     if (dispatchMessage(connection, decoder))
690         return;
691
692     if (m_processPool->dispatchMessage(connection, decoder))
693         return;
694
695     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
696         didReceiveWebProcessProxyMessage(connection, decoder);
697         return;
698     }
699
700     // FIXME: Add unhandled message logging.
701 }
702
703 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
704 {
705     if (dispatchSyncMessage(connection, decoder, replyEncoder))
706         return;
707
708     if (m_processPool->dispatchSyncMessage(connection, decoder, replyEncoder))
709         return;
710
711     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
712         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
713         return;
714     }
715
716     // FIXME: Add unhandled message logging.
717 }
718
719 void WebProcessProxy::didClose(IPC::Connection&)
720 {
721     RELEASE_LOG_IF(isReleaseLoggingAllowed(), Process, "%p - WebProcessProxy didClose (web process crash)", this);
722     processDidTerminateOrFailedToLaunch();
723 }
724
725 void WebProcessProxy::processDidTerminateOrFailedToLaunch()
726 {
727     // Protect ourselves, as the call to disconnect() below may otherwise cause us
728     // to be deleted before we can finish our work.
729     Ref<WebProcessProxy> protect(*this);
730
731 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
732     m_userMediaCaptureManagerProxy->clear();
733 #endif
734
735     if (auto* webConnection = this->webConnection())
736         webConnection->didClose();
737
738     auto pages = copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values());
739     auto provisionalPages = WTF::map(m_provisionalPages, [](auto* provisionalPage) { return makeWeakPtr(provisionalPage); });
740
741     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
742     for (auto& callback : isResponsiveCallbacks)
743         callback(false);
744
745     if (m_isInProcessCache) {
746         processPool().webProcessCache().removeProcess(*this, WebProcessCache::ShouldShutDownProcess::No);
747         ASSERT(!m_isInProcessCache);
748     }
749
750     shutDown();
751
752 #if ENABLE(PUBLIC_SUFFIX_LIST)
753     if (pages.size() == 1) {
754         auto& page = *pages[0];
755         String domain = topPrivatelyControlledDomain(URL({ }, page.currentURL()).host().toString());
756         if (!domain.isEmpty())
757             page.logDiagnosticMessageWithEnhancedPrivacy(WebCore::DiagnosticLoggingKeys::domainCausingCrashKey(), domain, WebCore::ShouldSample::No);
758     }
759 #endif
760
761     for (auto& page : pages)
762         page->processDidTerminate(ProcessTerminationReason::Crash);
763
764     for (auto& provisionalPage : provisionalPages) {
765         if (provisionalPage)
766             provisionalPage->processDidTerminate();
767     }
768 }
769
770 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
771 {
772     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
773
774     WebProcessPool::didReceiveInvalidMessage(messageReceiverName, messageName);
775
776     // Terminate the WebProcess.
777     terminate();
778
779     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
780     // callback so we'll explicitly call it here instead.
781     didClose(connection);
782 }
783
784 void WebProcessProxy::didBecomeUnresponsive()
785 {
786     auto protectedThis = makeRef(*this);
787
788     m_isResponsive = NoOrMaybe::No;
789
790     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
791
792     for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
793         page->processDidBecomeUnresponsive();
794
795     bool isWebProcessResponsive = false;
796     for (auto& callback : isResponsiveCallbacks)
797         callback(isWebProcessResponsive);
798
799     // If the web process becomes unresponsive and only runs service workers, kill it ourselves since there are no native clients to do it.
800     if (isRunningServiceWorkers() && m_pageMap.isEmpty()) {
801         RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didBecomeUnresponsive() Terminating service worker-only web process with pid %d because it is unresponsive", this, processIdentifier());
802         terminate();
803     }
804 }
805
806 void WebProcessProxy::didBecomeResponsive()
807 {
808     m_isResponsive = NoOrMaybe::Maybe;
809
810     for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
811         page->processDidBecomeResponsive();
812 }
813
814 void WebProcessProxy::willChangeIsResponsive()
815 {
816     for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
817         page->willChangeProcessIsResponsive();
818 }
819
820 void WebProcessProxy::didChangeIsResponsive()
821 {
822     for (auto& page : copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()))
823         page->didChangeProcessIsResponsive();
824 }
825
826 bool WebProcessProxy::mayBecomeUnresponsive()
827 {
828     return !platformIsBeingDebugged();
829 }
830
831 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
832 {
833     RELEASE_ASSERT(isMainThreadOrCheckDisabled());
834
835     AuxiliaryProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
836
837     if (!IPC::Connection::identifierIsValid(connectionIdentifier)) {
838         RELEASE_LOG_IF(isReleaseLoggingAllowed(), Process, "%p - WebProcessProxy didFinishLaunching - invalid connection identifier (web process failed to launch)", this);
839         processDidTerminateOrFailedToLaunch();
840         return;
841     }
842
843     RELEASE_ASSERT(!m_webConnection);
844     m_webConnection = WebConnectionToWebProcess::create(this);
845
846     m_processPool->processDidFinishLaunching(this);
847     m_backgroundResponsivenessTimer.updateState();
848
849     for (auto* visitedLinkStore : m_visitedLinkStoresWithUsers.keys())
850         visitedLinkStore->addProcess(*this);
851
852 #if PLATFORM(IOS_FAMILY)
853     if (connection()) {
854         if (xpc_connection_t xpcConnection = connection()->xpcConnection())
855             m_throttler.didConnectToProcess(xpc_connection_get_pid(xpcConnection));
856     }
857
858     unblockAccessibilityServerIfNeeded();
859 #endif
860 }
861
862 WebFrameProxy* WebProcessProxy::webFrame(FrameIdentifier frameID) const
863 {
864     if (!WebFrameProxyMap::isValidKey(frameID))
865         return nullptr;
866
867     return m_frameMap.get(frameID);
868 }
869
870 bool WebProcessProxy::canCreateFrame(FrameIdentifier frameID) const
871 {
872     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
873 }
874
875 void WebProcessProxy::frameCreated(FrameIdentifier frameID, WebFrameProxy& frameProxy)
876 {
877     m_frameMap.set(frameID, &frameProxy);
878 }
879
880 void WebProcessProxy::didDestroyFrame(FrameIdentifier frameID)
881 {
882     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
883     // back to the UIProcess, then the frameDestroyed message will still be received because it
884     // gets sent directly to the WebProcessProxy.
885     ASSERT(WebFrameProxyMap::isValidKey(frameID));
886     m_frameMap.remove(frameID);
887 }
888
889 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
890 {
891     for (auto& frame : copyToVector(m_frameMap.values())) {
892         if (frame->page() == page)
893             frame->webProcessWillShutDown();
894     }
895 }
896
897 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
898 {
899     size_t result = 0;
900     for (auto& frame : m_frameMap.values()) {
901         if (frame->page() == page)
902             ++result;
903     }
904     return result;
905 }
906
907 auto WebProcessProxy::visiblePageToken() const -> VisibleWebPageToken
908 {
909     return m_visiblePageCounter.count();
910 }
911
912 RefPtr<API::UserInitiatedAction> WebProcessProxy::userInitiatedActivity(uint64_t identifier)
913 {
914     if (!UserInitiatedActionMap::isValidKey(identifier) || !identifier)
915         return nullptr;
916
917     auto result = m_userInitiatedActionMap.ensure(identifier, [] { return API::UserInitiatedAction::create(); });
918     return result.iterator->value;
919 }
920
921 bool WebProcessProxy::isResponsive() const
922 {
923     return m_responsivenessTimer.isResponsive() && m_backgroundResponsivenessTimer.isResponsive();
924 }
925
926 void WebProcessProxy::didDestroyUserGestureToken(uint64_t identifier)
927 {
928     ASSERT(UserInitiatedActionMap::isValidKey(identifier));
929     m_userInitiatedActionMap.remove(identifier);
930 }
931
932 bool WebProcessProxy::canBeAddedToWebProcessCache() const
933 {
934     if (isRunningServiceWorkers())
935         return false;
936
937     if (WebKit::isInspectorProcessPool(processPool()))
938         return false;
939
940     return true;
941 }
942
943 void WebProcessProxy::maybeShutDown()
944 {
945     if (processPool().dummyProcessProxy() == this && m_pageMap.isEmpty()) {
946         ASSERT(state() == State::Terminated);
947         m_processPool->disconnectProcess(this);
948         return;
949     }
950
951     if (state() == State::Terminated || !canTerminateAuxiliaryProcess())
952         return;
953
954     if (canBeAddedToWebProcessCache() && processPool().webProcessCache().addProcessIfPossible(*this))
955         return;
956
957     shutDown();
958 }
959
960 bool WebProcessProxy::canTerminateAuxiliaryProcess()
961 {
962     if (!m_pageMap.isEmpty() || m_suspendedPageCount || !m_provisionalPages.isEmpty() || m_isInProcessCache || m_shutdownPreventingScopeCount)
963         return false;
964
965     if (!m_processPool->shouldTerminate(this))
966         return false;
967
968     return true;
969 }
970
971 void WebProcessProxy::shouldTerminate(CompletionHandler<void(bool)>&& completionHandler)
972 {
973     bool shouldTerminate = canTerminateAuxiliaryProcess();
974     if (shouldTerminate) {
975         // We know that the web process is going to terminate so start shutting it down in the UI process.
976         shutDown();
977     }
978     completionHandler(shouldTerminate);
979 }
980
981 void WebProcessProxy::updateTextCheckerState()
982 {
983     if (canSendMessage())
984         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
985 }
986
987 void WebProcessProxy::didSaveToPageCache()
988 {
989     m_processPool->processDidCachePage(this);
990 }
991
992 void WebProcessProxy::releasePageCache()
993 {
994     if (canSendMessage())
995         send(Messages::WebProcess::ReleasePageCache(), 0);
996 }
997
998 void WebProcessProxy::windowServerConnectionStateChanged()
999 {
1000     for (const auto& page : m_pageMap.values())
1001         page->activityStateDidChange(ActivityState::IsVisuallyIdle);
1002 }
1003
1004 void WebProcessProxy::fetchWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, CompletionHandler<void(WebsiteData)>&& completionHandler)
1005 {
1006     ASSERT(canSendMessage());
1007     ASSERT_UNUSED(sessionID, sessionID == this->sessionID());
1008
1009     auto token = throttler().backgroundActivityToken();
1010     RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is fetching Website data", this);
1011
1012     connection()->sendWithAsyncReply(Messages::WebProcess::FetchWebsiteData(dataTypes), [this, protectedThis = makeRef(*this), token, completionHandler = WTFMove(completionHandler)] (auto reply) mutable {
1013 #if RELEASE_LOG_DISABLED
1014         UNUSED_PARAM(this);
1015 #endif
1016         completionHandler(WTFMove(reply));
1017         RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done fetching Website data", this);
1018     });
1019 }
1020
1021 void WebProcessProxy::deleteWebsiteData(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, WallTime modifiedSince, CompletionHandler<void()>&& completionHandler)
1022 {
1023     ASSERT(canSendMessage());
1024     ASSERT_UNUSED(sessionID, sessionID == this->sessionID());
1025
1026     auto token = throttler().backgroundActivityToken();
1027     RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data", this);
1028
1029     connection()->sendWithAsyncReply(Messages::WebProcess::DeleteWebsiteData(dataTypes, modifiedSince), [this, protectedThis = makeRef(*this), token, completionHandler = WTFMove(completionHandler)] () mutable {
1030 #if RELEASE_LOG_DISABLED
1031         UNUSED_PARAM(this);
1032 #endif
1033         completionHandler();
1034         RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data", this);
1035     });
1036 }
1037
1038 void WebProcessProxy::deleteWebsiteDataForOrigins(PAL::SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, const Vector<WebCore::SecurityOriginData>& origins, CompletionHandler<void()>&& completionHandler)
1039 {
1040     ASSERT(canSendMessage());
1041     ASSERT_UNUSED(sessionID, sessionID == this->sessionID());
1042
1043     auto token = throttler().backgroundActivityToken();
1044     RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data for several origins", this);
1045
1046     connection()->sendWithAsyncReply(Messages::WebProcess::DeleteWebsiteDataForOrigins(dataTypes, origins), [this, protectedThis = makeRef(*this), token, completionHandler = WTFMove(completionHandler)] () mutable {
1047 #if RELEASE_LOG_DISABLED
1048         UNUSED_PARAM(this);
1049 #endif
1050         completionHandler();
1051         RELEASE_LOG_IF(isReleaseLoggingAllowed(), ProcessSuspension, "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data for several origins", this);
1052     });
1053 }
1054
1055 void WebProcessProxy::requestTermination(ProcessTerminationReason reason)
1056 {
1057     if (state() == State::Terminated)
1058         return;
1059
1060     auto protectedThis = makeRef(*this);
1061     RELEASE_LOG_IF(isReleaseLoggingAllowed(), Process, "%p - WebProcessProxy::requestTermination - reason %d", this, reason);
1062
1063     AuxiliaryProcessProxy::terminate();
1064
1065     if (webConnection())
1066         webConnection()->didClose();
1067
1068     auto provisionalPages = WTF::map(m_provisionalPages, [](auto* provisionalPage) { return makeWeakPtr(provisionalPage); });
1069     auto pages = copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values());
1070
1071     shutDown();
1072
1073     for (auto& page : pages)
1074         page->processDidTerminate(reason);
1075         
1076     for (auto& provisionalPage : provisionalPages) {
1077         if (provisionalPage)
1078             provisionalPage->processDidTerminate();
1079     }
1080 }
1081
1082 bool WebProcessProxy::isReleaseLoggingAllowed() const
1083 {
1084     return !m_websiteDataStore || m_websiteDataStore->sessionID().isAlwaysOnLoggingAllowed();
1085 }
1086
1087 void WebProcessProxy::stopResponsivenessTimer()
1088 {
1089     responsivenessTimer().stop();
1090 }
1091
1092 void WebProcessProxy::enableSuddenTermination()
1093 {
1094     if (state() != State::Running)
1095         return;
1096
1097     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
1098     WebCore::enableSuddenTermination();
1099     --m_numberOfTimesSuddenTerminationWasDisabled;
1100 }
1101
1102 void WebProcessProxy::disableSuddenTermination()
1103 {
1104     if (state() != State::Running)
1105         return;
1106
1107     WebCore::disableSuddenTermination();
1108     ++m_numberOfTimesSuddenTerminationWasDisabled;
1109 }
1110
1111 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
1112 {
1113     struct Transformer final : UserData::Transformer {
1114         Transformer(WebProcessProxy& webProcessProxy)
1115             : m_webProcessProxy(webProcessProxy)
1116         {
1117         }
1118
1119         bool shouldTransformObject(const API::Object& object) const override
1120         {
1121             switch (object.type()) {
1122             case API::Object::Type::FrameHandle:
1123                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
1124
1125             case API::Object::Type::PageHandle:
1126                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
1127
1128             case API::Object::Type::PageGroupHandle:
1129 #if PLATFORM(COCOA)
1130             case API::Object::Type::ObjCObjectGraph:
1131 #endif
1132                 return true;
1133
1134             default:
1135                 return false;
1136             }
1137         }
1138
1139         RefPtr<API::Object> transformObject(API::Object& object) const override
1140         {
1141             switch (object.type()) {
1142             case API::Object::Type::FrameHandle:
1143                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
1144                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
1145
1146             case API::Object::Type::PageGroupHandle:
1147                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
1148
1149             case API::Object::Type::PageHandle:
1150                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
1151                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageProxyID());
1152
1153 #if PLATFORM(COCOA)
1154             case API::Object::Type::ObjCObjectGraph:
1155                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
1156 #endif
1157             default:
1158                 return &object;
1159             }
1160         }
1161
1162         WebProcessProxy& m_webProcessProxy;
1163     };
1164
1165     return UserData::transform(object, Transformer(*this));
1166 }
1167
1168 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
1169 {
1170     struct Transformer final : UserData::Transformer {
1171         bool shouldTransformObject(const API::Object& object) const override
1172         {
1173             switch (object.type()) {
1174             case API::Object::Type::Frame:
1175             case API::Object::Type::Page:
1176             case API::Object::Type::PageGroup:
1177 #if PLATFORM(COCOA)
1178             case API::Object::Type::ObjCObjectGraph:
1179 #endif
1180                 return true;
1181
1182             default:
1183                 return false;
1184             }
1185         }
1186
1187         RefPtr<API::Object> transformObject(API::Object& object) const override
1188         {
1189             switch (object.type()) {
1190             case API::Object::Type::Frame:
1191                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
1192
1193             case API::Object::Type::Page:
1194                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).identifier(), static_cast<const WebPageProxy&>(object).webPageID());
1195
1196             case API::Object::Type::PageGroup:
1197                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
1198
1199 #if PLATFORM(COCOA)
1200             case API::Object::Type::ObjCObjectGraph:
1201                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
1202 #endif
1203
1204             default:
1205                 return &object;
1206             }
1207         }
1208     };
1209
1210     return UserData::transform(object, Transformer());
1211 }
1212
1213 void WebProcessProxy::sendProcessWillSuspendImminently()
1214 {
1215     if (canSendMessage())
1216         send(Messages::WebProcess::ProcessWillSuspendImminently(), 0);
1217 }
1218
1219 void WebProcessProxy::sendPrepareToSuspend()
1220 {
1221     if (canSendMessage())
1222         send(Messages::WebProcess::PrepareToSuspend(), 0);
1223 }
1224
1225 void WebProcessProxy::sendCancelPrepareToSuspend()
1226 {
1227     if (canSendMessage())
1228         send(Messages::WebProcess::CancelPrepareToSuspend(), 0);
1229 }
1230
1231 void WebProcessProxy::sendProcessDidResume()
1232 {
1233     if (canSendMessage())
1234         send(Messages::WebProcess::ProcessDidResume(), 0);
1235 }
1236
1237 void WebProcessProxy::processReadyToSuspend()
1238 {
1239     m_throttler.processReadyToSuspend();
1240 }
1241
1242 void WebProcessProxy::didCancelProcessSuspension()
1243 {
1244     m_throttler.didCancelProcessSuspension();
1245 }
1246
1247 void WebProcessProxy::didSetAssertionState(AssertionState state)
1248 {
1249 #if PLATFORM(IOS_FAMILY)
1250     if (isRunningServiceWorkers())
1251         return;
1252
1253     ASSERT(!m_backgroundToken || !m_foregroundToken);
1254
1255     switch (state) {
1256     case AssertionState::Suspended:
1257         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Suspended) release all assertions for network process", this);
1258         m_foregroundToken = nullptr;
1259         m_backgroundToken = nullptr;
1260         for (auto& page : m_pageMap.values())
1261             page->processWillBecomeSuspended();
1262         break;
1263
1264     case AssertionState::Background:
1265         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Background) taking background assertion for network process", this);
1266         m_backgroundToken = processPool().backgroundWebProcessToken();
1267         m_foregroundToken = nullptr;
1268         break;
1269     
1270     case AssertionState::Foreground:
1271         RELEASE_LOG(ProcessSuspension, "%p - WebProcessProxy::didSetAssertionState(Foreground) taking foreground assertion for network process", this);
1272         m_foregroundToken = processPool().foregroundWebProcessToken();
1273         m_backgroundToken = nullptr;
1274         for (auto& page : m_pageMap.values())
1275             page->processWillBecomeForeground();
1276         break;
1277     
1278     case AssertionState::UnboundedNetworking:
1279         ASSERT_NOT_REACHED();
1280     }
1281
1282     ASSERT(!m_backgroundToken || !m_foregroundToken);
1283 #else
1284     UNUSED_PARAM(state);
1285 #endif
1286 }
1287
1288 void WebProcessProxy::webPageMediaStateDidChange(WebPageProxy&)
1289 {
1290     bool newHasAudibleWebPage = WTF::anyOf(m_pageMap.values(), [] (auto& page) { return page->isPlayingAudio(); });
1291     if (m_hasAudibleWebPage == newHasAudibleWebPage)
1292         return;
1293     m_hasAudibleWebPage = newHasAudibleWebPage;
1294
1295     if (m_hasAudibleWebPage)
1296         processPool().setWebProcessIsPlayingAudibleMedia(coreProcessIdentifier());
1297     else
1298         processPool().clearWebProcessIsPlayingAudibleMedia(coreProcessIdentifier());
1299 }
1300
1301 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
1302 {
1303     if (!isHoldingLockedFiles) {
1304         RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because the WebContent process is no longer holding locked files");
1305         m_tokenForHoldingLockedFiles = nullptr;
1306         return;
1307     }
1308     if (!m_tokenForHoldingLockedFiles) {
1309         RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because the WebContent process is holding locked files");
1310         m_tokenForHoldingLockedFiles = m_throttler.backgroundActivityToken();
1311     }
1312 }
1313
1314 void WebProcessProxy::isResponsive(CompletionHandler<void(bool isWebProcessResponsive)>&& callback)
1315 {
1316     if (m_isResponsive == NoOrMaybe::No) {
1317         if (callback) {
1318             RunLoop::main().dispatch([callback = WTFMove(callback)]() mutable {
1319                 bool isWebProcessResponsive = false;
1320                 callback(isWebProcessResponsive);
1321             });
1322         }
1323         return;
1324     }
1325
1326     if (callback)
1327         m_isResponsiveCallbacks.append(WTFMove(callback));
1328
1329     responsivenessTimer().start();
1330     send(Messages::WebProcess::MainThreadPing(), 0);
1331 }
1332
1333 void WebProcessProxy::isResponsiveWithLazyStop()
1334 {
1335     if (m_isResponsive == NoOrMaybe::No)
1336         return;
1337
1338     if (!responsivenessTimer().hasActiveTimer()) {
1339         // We do not send a ping if we are already waiting for the WebProcess.
1340         // Spamming pings on a slow web process is not helpful.
1341         responsivenessTimer().startWithLazyStop();
1342         send(Messages::WebProcess::MainThreadPing(), 0);
1343     }
1344 }
1345
1346 bool WebProcessProxy::shouldConfigureJSCForTesting() const
1347 {
1348     return processPool().configuration().shouldConfigureJSCForTesting();
1349 }
1350
1351 bool WebProcessProxy::isJITEnabled() const
1352 {
1353     return processPool().configuration().isJITEnabled();
1354 }
1355
1356 void WebProcessProxy::didReceiveMainThreadPing()
1357 {
1358     responsivenessTimer().stop();
1359
1360     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
1361     bool isWebProcessResponsive = true;
1362     for (auto& callback : isResponsiveCallbacks)
1363         callback(isWebProcessResponsive);
1364 }
1365
1366 void WebProcessProxy::didReceiveBackgroundResponsivenessPing()
1367 {
1368     m_backgroundResponsivenessTimer.didReceiveBackgroundResponsivenessPong();
1369 }
1370
1371 void WebProcessProxy::processTerminated()
1372 {
1373     m_responsivenessTimer.processTerminated();
1374     m_backgroundResponsivenessTimer.processTerminated();
1375 }
1376
1377 void WebProcessProxy::logDiagnosticMessageForResourceLimitTermination(const String& limitKey)
1378 {
1379     if (pageCount())
1380         (*pages().begin())->logDiagnosticMessage(DiagnosticLoggingKeys::simulatedPageCrashKey(), limitKey, ShouldSample::No);
1381 }
1382
1383 void WebProcessProxy::didExceedInactiveMemoryLimitWhileActive()
1384 {
1385     for (auto& page : pages())
1386         page->didExceedInactiveMemoryLimitWhileActive();
1387 }
1388
1389 void WebProcessProxy::didExceedActiveMemoryLimit()
1390 {
1391     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedActiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the active memory limit", this, processIdentifier());
1392     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededActiveMemoryLimitKey());
1393     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1394 }
1395
1396 void WebProcessProxy::didExceedInactiveMemoryLimit()
1397 {
1398     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedInactiveMemoryLimit() Terminating WebProcess with pid %d that has exceeded the inactive memory limit", this, processIdentifier());
1399     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededInactiveMemoryLimitKey());
1400     requestTermination(ProcessTerminationReason::ExceededMemoryLimit);
1401 }
1402
1403 void WebProcessProxy::didExceedCPULimit()
1404 {
1405     auto protectedThis = makeRef(*this);
1406
1407     for (auto& page : pages()) {
1408         if (page->isPlayingAudio()) {
1409             RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() WebProcess with pid %d has exceeded the background CPU limit but we are not terminating it because there is audio playing", this, processIdentifier());
1410             return;
1411         }
1412
1413         if (page->hasActiveAudioStream() || page->hasActiveVideoStream()) {
1414             RELEASE_LOG(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() WebProcess with pid %d has exceeded the background CPU limit but we are not terminating it because it is capturing audio / video", this, processIdentifier());
1415             return;
1416         }
1417     }
1418
1419     bool hasVisiblePage = false;
1420     for (auto& page : pages()) {
1421         if (page->isViewVisible()) {
1422             page->didExceedBackgroundCPULimitWhileInForeground();
1423             hasVisiblePage = true;
1424         }
1425     }
1426
1427     // We only notify the client that the process exceeded the CPU limit when it is visible, we do not terminate it.
1428     if (hasVisiblePage)
1429         return;
1430
1431     RELEASE_LOG_ERROR(PerformanceLogging, "%p - WebProcessProxy::didExceedCPULimit() Terminating background WebProcess with pid %d that has exceeded the background CPU limit", this, processIdentifier());
1432     logDiagnosticMessageForResourceLimitTermination(DiagnosticLoggingKeys::exceededBackgroundCPULimitKey());
1433     requestTermination(ProcessTerminationReason::ExceededCPULimit);
1434 }
1435
1436 void WebProcessProxy::updateBackgroundResponsivenessTimer()
1437 {
1438     m_backgroundResponsivenessTimer.updateState();
1439 }
1440
1441 #if !PLATFORM(COCOA)
1442 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess()
1443 {
1444     static NeverDestroyed<HashSet<String>> platformPathsWithAssumedReadAccess;
1445     return platformPathsWithAssumedReadAccess;
1446 }
1447 #endif
1448
1449 void WebProcessProxy::didCollectPrewarmInformation(const WebCore::RegistrableDomain& domain, const WebCore::PrewarmInformation& prewarmInformation)
1450 {
1451     processPool().didCollectPrewarmInformation(domain, prewarmInformation);
1452 }
1453
1454 void WebProcessProxy::activePagesDomainsForTesting(CompletionHandler<void(Vector<String>&&)>&& completionHandler)
1455 {
1456     connection()->sendWithAsyncReply(Messages::WebProcess::GetActivePagesOriginsForTesting(), WTFMove(completionHandler));
1457 }
1458
1459 void WebProcessProxy::didStartProvisionalLoadForMainFrame(const URL& url)
1460 {
1461     RELEASE_ASSERT(!isInProcessCache());
1462
1463     // This process has been used for several registrable domains already.
1464     if (m_registrableDomain && m_registrableDomain->isEmpty())
1465         return;
1466
1467     auto registrableDomain = WebCore::RegistrableDomain { url };
1468     if (m_registrableDomain && *m_registrableDomain != registrableDomain) {
1469         // Null out registrable domain since this process has now been used for several domains.
1470         m_registrableDomain = WebCore::RegistrableDomain { };
1471         return;
1472     }
1473
1474     // Associate the process with this registrable domain.
1475     m_registrableDomain = WTFMove(registrableDomain);
1476 }
1477
1478 void WebProcessProxy::incrementSuspendedPageCount()
1479 {
1480     ++m_suspendedPageCount;
1481     if (m_suspendedPageCount == 1)
1482         send(Messages::WebProcess::SetHasSuspendedPageProxy(true), 0);
1483 }
1484
1485 void WebProcessProxy::decrementSuspendedPageCount()
1486 {
1487     ASSERT(m_suspendedPageCount);
1488     --m_suspendedPageCount;
1489     if (!m_suspendedPageCount) {
1490         send(Messages::WebProcess::SetHasSuspendedPageProxy(false), 0);
1491         maybeShutDown();
1492     }
1493 }
1494
1495 WebProcessPool* WebProcessProxy::processPoolIfExists() const
1496 {
1497     if (m_isPrewarmed || m_isInProcessCache)
1498         RELEASE_LOG_ERROR(Process, "%p - WebProcessProxy::processPoolIfExists: trying to get WebProcessPool from an inactive WebProcessProxy %i", this, processIdentifier());
1499     else
1500         ASSERT(m_processPool);
1501     return m_processPool.get();
1502 }
1503
1504 WebProcessPool& WebProcessProxy::processPool() const
1505 {
1506     ASSERT(m_processPool);
1507     return *m_processPool.get();
1508 }
1509
1510 PAL::SessionID WebProcessProxy::sessionID() const
1511 {
1512     ASSERT(m_websiteDataStore);
1513     return m_websiteDataStore->sessionID();
1514 }
1515
1516 void WebProcessProxy::addPlugInAutoStartOriginHash(String&& pageOrigin, uint32_t hash)
1517 {
1518     processPool().plugInAutoStartProvider().addAutoStartOriginHash(WTFMove(pageOrigin), hash, sessionID());
1519 }
1520
1521 void WebProcessProxy::plugInDidReceiveUserInteraction(uint32_t hash)
1522 {
1523     processPool().plugInAutoStartProvider().didReceiveUserInteraction(hash, sessionID());
1524 }
1525
1526 #if PLATFORM(WATCHOS)
1527
1528 void WebProcessProxy::takeBackgroundActivityTokenForFullscreenInput()
1529 {
1530     if (m_backgroundActivityTokenForFullscreenFormControls)
1531         return;
1532
1533     m_backgroundActivityTokenForFullscreenFormControls = m_throttler.backgroundActivityToken();
1534     RELEASE_LOG(ProcessSuspension, "UIProcess is taking a background assertion because it is presenting fullscreen UI for form controls.");
1535 }
1536
1537 void WebProcessProxy::releaseBackgroundActivityTokenForFullscreenInput()
1538 {
1539     if (!m_backgroundActivityTokenForFullscreenFormControls)
1540         return;
1541
1542     m_backgroundActivityTokenForFullscreenFormControls = nullptr;
1543     RELEASE_LOG(ProcessSuspension, "UIProcess is releasing a background assertion because it has dismissed fullscreen UI for form controls.");
1544 }
1545
1546 #endif
1547
1548 #if ENABLE(SERVICE_WORKER)
1549 void WebProcessProxy::establishServiceWorkerContext(const WebPreferencesStore& store)
1550 {
1551     send(Messages::WebProcess::EstablishWorkerContextConnectionToNetworkProcess { processPool().defaultPageGroup().pageGroupID(), m_serviceWorkerInformation->serviceWorkerPageProxyID, m_serviceWorkerInformation->serviceWorkerPageID, store, *m_registrableDomain }, 0);
1552 }
1553
1554 void WebProcessProxy::setServiceWorkerUserAgent(const String& userAgent)
1555 {
1556     ASSERT(m_serviceWorkerInformation);
1557     send(Messages::WebSWContextManagerConnection::SetUserAgent { userAgent }, 0);
1558 }
1559
1560 void WebProcessProxy::updateServiceWorkerPreferencesStore(const WebPreferencesStore& store)
1561 {
1562     ASSERT(m_serviceWorkerInformation);
1563     send(Messages::WebSWContextManagerConnection::UpdatePreferencesStore { store }, 0);
1564 }
1565 #endif
1566
1567 } // namespace WebKit
1568
1569 #undef MESSAGE_CHECK
1570 #undef MESSAGE_CHECK_URL