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