Try to fix the 32-bit build.
[WebKit-https.git] / Source / WebKit2 / UIProcess / WebProcessProxy.cpp
1 /*
2  * Copyright (C) 2010-2016 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 "CustomProtocolManagerProxyMessages.h"
33 #include "DataReference.h"
34 #include "DownloadProxyMap.h"
35 #include "PluginInfoStore.h"
36 #include "PluginProcessManager.h"
37 #include "TextChecker.h"
38 #include "TextCheckerState.h"
39 #include "UserData.h"
40 #include "WebBackForwardListItem.h"
41 #include "WebIconDatabase.h"
42 #include "WebInspectorProxy.h"
43 #include "WebNavigationDataStore.h"
44 #include "WebNotificationManagerProxy.h"
45 #include "WebPageGroup.h"
46 #include "WebPageProxy.h"
47 #include "WebPasteboardProxy.h"
48 #include "WebProcessMessages.h"
49 #include "WebProcessPool.h"
50 #include "WebProcessProxyMessages.h"
51 #include "WebUserContentControllerProxy.h"
52 #include "WebsiteData.h"
53 #include <WebCore/SuddenTermination.h>
54 #include <WebCore/URL.h>
55 #include <stdio.h>
56 #include <wtf/NeverDestroyed.h>
57 #include <wtf/RunLoop.h>
58 #include <wtf/text/CString.h>
59 #include <wtf/text/WTFString.h>
60
61 #if PLATFORM(COCOA)
62 #include "ObjCObjectGraph.h"
63 #include "PDFPlugin.h"
64 #endif
65
66 #if ENABLE(SEC_ITEM_SHIM)
67 #include "SecItemShimProxy.h"
68 #endif
69
70 using namespace WebCore;
71
72 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
73 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
74
75 namespace WebKit {
76
77 static uint64_t generatePageID()
78 {
79     static uint64_t uniquePageID;
80     return ++uniquePageID;
81 }
82
83 static WebProcessProxy::WebPageProxyMap& globalPageMap()
84 {
85     ASSERT(RunLoop::isMain());
86     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
87     return pageMap;
88 }
89
90 Ref<WebProcessProxy> WebProcessProxy::create(WebProcessPool& processPool)
91 {
92     return adoptRef(*new WebProcessProxy(processPool));
93 }
94
95 WebProcessProxy::WebProcessProxy(WebProcessPool& processPool)
96     : m_responsivenessTimer(*this)
97     , m_processPool(processPool)
98     , m_mayHaveUniversalFileReadSandboxExtension(false)
99     , m_customProtocolManagerProxy(this, processPool)
100     , m_numberOfTimesSuddenTerminationWasDisabled(0)
101     , m_throttler(*this)
102     , m_isResponsive(NoOrMaybe::Maybe)
103 {
104     WebPasteboardProxy::singleton().addWebProcessProxy(*this);
105
106     connect();
107 }
108
109 WebProcessProxy::~WebProcessProxy()
110 {
111     ASSERT(m_pageURLRetainCountMap.isEmpty());
112
113     if (m_webConnection)
114         m_webConnection->invalidate();
115
116     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
117         WebCore::enableSuddenTermination();
118 }
119
120 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
121 {
122     launchOptions.processType = ProcessLauncher::ProcessType::Web;
123
124     ChildProcessProxy::getLaunchOptions(launchOptions);
125
126     if (WebInspectorProxy::isInspectorProcessPool(m_processPool))
127         launchOptions.extraInitializationData.add(ASCIILiteral("inspector-process"), ASCIILiteral("1"));
128
129     auto overrideLanguages = m_processPool->configuration().overrideLanguages();
130     if (overrideLanguages.size()) {
131         StringBuilder languageString;
132         for (size_t i = 0; i < overrideLanguages.size(); ++i) {
133             if (i)
134                 languageString.append(',');
135             languageString.append(overrideLanguages[i]);
136         }
137         launchOptions.extraInitializationData.add(ASCIILiteral("OverrideLanguages"), languageString.toString());
138     }
139 }
140
141 void WebProcessProxy::connectionWillOpen(IPC::Connection& connection)
142 {
143     ASSERT(this->connection() == &connection);
144
145 #if ENABLE(SEC_ITEM_SHIM)
146     SecItemShimProxy::singleton().initializeConnection(connection);
147 #endif
148
149     for (auto& page : m_pageMap.values())
150         page->connectionWillOpen(connection);
151 }
152
153 void WebProcessProxy::processWillShutDown(IPC::Connection& connection)
154 {
155     ASSERT_UNUSED(connection, this->connection() == &connection);
156
157     for (auto& page : m_pageMap.values())
158         page->webProcessWillShutDown();
159
160     releaseRemainingIconsForPageURLs();
161 }
162
163 void WebProcessProxy::shutDown()
164 {
165     shutDownProcess();
166
167     if (m_webConnection) {
168         m_webConnection->invalidate();
169         m_webConnection = nullptr;
170     }
171
172     m_responsivenessTimer.invalidate();
173     m_tokenForHoldingLockedFiles = nullptr;
174
175     Vector<RefPtr<WebFrameProxy>> frames;
176     copyValuesToVector(m_frameMap, frames);
177
178     for (size_t i = 0, size = frames.size(); i < size; ++i)
179         frames[i]->webProcessWillShutDown();
180     m_frameMap.clear();
181
182     for (VisitedLinkStore* visitedLinkStore : m_visitedLinkStores)
183         visitedLinkStore->removeProcess(*this);
184     m_visitedLinkStores.clear();
185
186     for (WebUserContentControllerProxy* webUserContentControllerProxy : m_webUserContentControllerProxies)
187         webUserContentControllerProxy->removeProcess(*this);
188     m_webUserContentControllerProxies.clear();
189
190     m_userInitiatedActionMap.clear();
191
192     m_processPool->disconnectProcess(this);
193 }
194
195 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
196 {
197     return globalPageMap().get(pageID);
198 }
199
200 Ref<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, Ref<API::PageConfiguration>&& pageConfiguration)
201 {
202     uint64_t pageID = generatePageID();
203     Ref<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, pageID, WTFMove(pageConfiguration));
204
205     m_pageMap.set(pageID, webPage.ptr());
206     globalPageMap().set(pageID, webPage.ptr());
207
208     return webPage;
209 }
210
211 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
212 {
213     ASSERT(!m_pageMap.contains(pageID));
214     ASSERT(!globalPageMap().contains(pageID));
215
216     m_pageMap.set(pageID, webPage);
217     globalPageMap().set(pageID, webPage);
218 }
219
220 void WebProcessProxy::removeWebPage(uint64_t pageID)
221 {
222     m_pageMap.remove(pageID);
223     globalPageMap().remove(pageID);
224     
225     Vector<uint64_t> itemIDsToRemove;
226     for (auto& idAndItem : m_backForwardListItemMap) {
227         if (idAndItem.value->pageID() == pageID)
228             itemIDsToRemove.append(idAndItem.key);
229     }
230     for (auto itemID : itemIDsToRemove)
231         m_backForwardListItemMap.remove(itemID);
232
233     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
234     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
235     if (state() == State::Terminated || !canTerminateChildProcess())
236         return;
237
238     shutDown();
239 }
240
241 void WebProcessProxy::addVisitedLinkStore(VisitedLinkStore& store)
242 {
243     m_visitedLinkStores.add(&store);
244     store.addProcess(*this);
245 }
246
247 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
248 {
249     m_webUserContentControllerProxies.add(&proxy);
250     proxy.addProcess(*this);
251 }
252
253 void WebProcessProxy::didDestroyVisitedLinkStore(VisitedLinkStore& store)
254 {
255     ASSERT(m_visitedLinkStores.contains(&store));
256     m_visitedLinkStores.remove(&store);
257 }
258
259 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
260 {
261     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
262     m_webUserContentControllerProxies.remove(&proxy);
263 }
264
265 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
266 {
267     return m_backForwardListItemMap.get(itemID);
268 }
269
270 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
271 {
272     // This item was just created by the UIProcess and is being added to the map for the first time
273     // so we should not already have an item for this ID.
274     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
275
276     m_backForwardListItemMap.set(item->itemID(), item);
277 }
278
279 void WebProcessProxy::removeBackForwardItem(uint64_t itemID)
280 {
281     m_backForwardListItemMap.remove(itemID);
282 }
283
284 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
285 {
286     URL url(URL(), urlString);
287     if (!url.isLocalFile())
288         return;
289
290     // There's a chance that urlString does not point to a directory.
291     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
292     URL baseURL(URL(), url.baseAsString());
293     
294     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
295     // to have read access to this directory already.
296     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
297 }
298
299 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
300 {
301     if (!url.isLocalFile())
302         return false;
303
304     String path = url.fileSystemPath();
305     auto startsWithURLPath = [&path](const String& assumedAccessPath) {
306         // There are no ".." components, because URL removes those.
307         return path.startsWith(assumedAccessPath);
308     };
309
310     auto& platformPaths = platformPathsWithAssumedReadAccess();
311     auto platformPathsEnd = platformPaths.end();
312     if (std::find_if(platformPaths.begin(), platformPathsEnd, startsWithURLPath) != platformPathsEnd)
313         return true;
314
315     auto localPathsEnd = m_localPathsWithAssumedReadAccess.end();
316     if (std::find_if(m_localPathsWithAssumedReadAccess.begin(), localPathsEnd, startsWithURLPath) != localPathsEnd)
317         return true;
318
319     return false;
320 }
321
322 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
323 {
324     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
325 }
326
327 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
328 {
329     // 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.
330
331     // Any other non-file URL is OK.
332     if (!url.isLocalFile())
333         return true;
334
335     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
336     if (m_mayHaveUniversalFileReadSandboxExtension)
337         return true;
338
339     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
340     if (hasAssumedReadAccessToURL(url))
341         return true;
342
343     // Items in back/forward list have been already checked.
344     // 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.
345     String path = url.fileSystemPath();
346     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
347         URL itemURL(URL(), iter->value->url());
348         if (itemURL.isLocalFile() && itemURL.fileSystemPath() == path)
349             return true;
350         URL itemOriginalURL(URL(), iter->value->originalURL());
351         if (itemOriginalURL.isLocalFile() && itemOriginalURL.fileSystemPath() == path)
352             return true;
353     }
354
355     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
356     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
357     return false;
358 }
359
360 #if !PLATFORM(COCOA)
361 bool WebProcessProxy::fullKeyboardAccessEnabled()
362 {
363     return false;
364 }
365 #endif
366
367 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
368 {
369     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
370     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
371
372     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
373     if (!backForwardListItem) {
374         BackForwardListItemState backForwardListItemState;
375         backForwardListItemState.identifier = itemID;
376         backForwardListItemState.pageState = pageState;
377         backForwardListItem = WebBackForwardListItem::create(WTFMove(backForwardListItemState), pageID);
378         return;
379     }
380
381     // Update existing item.
382     backForwardListItem->setPageState(pageState);
383 }
384
385 #if ENABLE(NETSCAPE_PLUGIN_API)
386 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
387 {
388     if (refresh)
389         m_processPool->pluginInfoStore().refresh();
390
391     Vector<PluginModuleInfo> pluginModules = m_processPool->pluginInfoStore().plugins();
392     for (size_t i = 0; i < pluginModules.size(); ++i)
393         plugins.append(pluginModules[i].info);
394
395 #if ENABLE(PDFKIT_PLUGIN)
396     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
397     if (!m_processPool->omitPDFSupport()) {
398         plugins.append(PDFPlugin::pluginInfo());
399         applicationPlugins.append(PDFPlugin::pluginInfo());
400     }
401 #else
402     UNUSED_PARAM(applicationPlugins);
403 #endif
404 }
405 #endif // ENABLE(NETSCAPE_PLUGIN_API)
406
407 #if ENABLE(NETSCAPE_PLUGIN_API)
408 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
409 {
410     PluginProcessManager::singleton().getPluginProcessConnection(pluginProcessToken, reply);
411 }
412 #endif
413
414 void WebProcessProxy::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
415 {
416     m_processPool->getNetworkProcessConnection(reply);
417 }
418
419 #if ENABLE(DATABASE_PROCESS)
420 void WebProcessProxy::getDatabaseProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply> reply)
421 {
422     m_processPool->getDatabaseProcessConnection(reply);
423 }
424 #endif // ENABLE(DATABASE_PROCESS)
425
426 void WebProcessProxy::retainIconForPageURL(const String& pageURL)
427 {
428     WebIconDatabase* iconDatabase = processPool().iconDatabase();
429     if (!iconDatabase || pageURL.isEmpty())
430         return;
431
432     // Track retain counts so we can release them if the WebProcess terminates early.
433     auto result = m_pageURLRetainCountMap.add(pageURL, 1);
434     if (!result.isNewEntry)
435         ++result.iterator->value;
436
437     iconDatabase->retainIconForPageURL(pageURL);
438 }
439
440 void WebProcessProxy::releaseIconForPageURL(const String& pageURL)
441 {
442     WebIconDatabase* iconDatabase = processPool().iconDatabase();
443     if (!iconDatabase || pageURL.isEmpty())
444         return;
445
446     // Track retain counts so we can release them if the WebProcess terminates early.
447     auto result = m_pageURLRetainCountMap.find(pageURL);
448     if (result == m_pageURLRetainCountMap.end())
449         return;
450
451     --result->value;
452     if (!result->value)
453         m_pageURLRetainCountMap.remove(result);
454
455     iconDatabase->releaseIconForPageURL(pageURL);
456 }
457
458 void WebProcessProxy::releaseRemainingIconsForPageURLs()
459 {
460     WebIconDatabase* iconDatabase = processPool().iconDatabase();
461     if (!iconDatabase)
462         return;
463
464     for (auto& entry : m_pageURLRetainCountMap) {
465         uint64_t count = entry.value;
466         for (uint64_t i = 0; i < count; ++i)
467             iconDatabase->releaseIconForPageURL(entry.key);
468     }
469
470     m_pageURLRetainCountMap.clear();
471 }
472
473 void WebProcessProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder)
474 {
475     if (dispatchMessage(connection, decoder))
476         return;
477
478     if (m_processPool->dispatchMessage(connection, decoder))
479         return;
480
481     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
482         didReceiveWebProcessProxyMessage(connection, decoder);
483         return;
484     }
485
486     // FIXME: Add unhandled message logging.
487 }
488
489 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& replyEncoder)
490 {
491     if (dispatchSyncMessage(connection, decoder, replyEncoder))
492         return;
493
494     if (m_processPool->dispatchSyncMessage(connection, decoder, replyEncoder))
495         return;
496
497     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
498         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
499         return;
500     }
501
502     // FIXME: Add unhandled message logging.
503 }
504
505 void WebProcessProxy::didClose(IPC::Connection&)
506 {
507     // Protect ourselves, as the call to disconnect() below may otherwise cause us
508     // to be deleted before we can finish our work.
509     Ref<WebProcessProxy> protect(*this);
510
511     webConnection()->didClose();
512
513     Vector<RefPtr<WebPageProxy>> pages;
514     copyValuesToVector(m_pageMap, pages);
515
516     shutDown();
517
518     for (size_t i = 0, size = pages.size(); i < size; ++i)
519         pages[i]->processDidCrash();
520
521 }
522
523 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
524 {
525     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
526
527     WebProcessPool::didReceiveInvalidMessage(messageReceiverName, messageName);
528
529     // Terminate the WebProcess.
530     terminate();
531
532     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
533     // callback so we'll explicitly call it here instead.
534     didClose(connection);
535 }
536
537 void WebProcessProxy::didBecomeUnresponsive()
538 {
539     m_isResponsive = NoOrMaybe::No;
540
541     Vector<RefPtr<WebPageProxy>> pages;
542     copyValuesToVector(m_pageMap, pages);
543
544     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
545
546     for (auto& page : pages)
547         page->processDidBecomeUnresponsive();
548
549     bool isWebProcessResponsive = false;
550     for (auto& callback : isResponsiveCallbacks)
551         callback(isWebProcessResponsive);
552 }
553
554 void WebProcessProxy::didBecomeResponsive()
555 {
556     m_isResponsive = NoOrMaybe::Maybe;
557
558     Vector<RefPtr<WebPageProxy>> pages;
559     copyValuesToVector(m_pageMap, pages);
560     for (auto& page : pages)
561         page->processDidBecomeResponsive();
562 }
563
564 void WebProcessProxy::willChangeIsResponsive()
565 {
566     Vector<RefPtr<WebPageProxy>> pages;
567     copyValuesToVector(m_pageMap, pages);
568     for (auto& page : pages)
569         page->willChangeProcessIsResponsive();
570 }
571
572 void WebProcessProxy::didChangeIsResponsive()
573 {
574     Vector<RefPtr<WebPageProxy>> pages;
575     copyValuesToVector(m_pageMap, pages);
576     for (auto& page : pages)
577         page->didChangeProcessIsResponsive();
578 }
579
580 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
581 {
582     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
583
584     for (WebPageProxy* page : m_pageMap.values()) {
585         ASSERT(this == &page->process());
586         page->processDidFinishLaunching();
587     }
588
589     m_webConnection = WebConnectionToWebProcess::create(this);
590
591     m_processPool->processDidFinishLaunching(this);
592
593 #if PLATFORM(IOS)
594     if (connection()) {
595         if (xpc_connection_t xpcConnection = connection()->xpcConnection())
596             m_throttler.didConnectToProcess(xpc_connection_get_pid(xpcConnection));
597     }
598 #endif
599 }
600
601 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
602 {
603     if (!WebFrameProxyMap::isValidKey(frameID))
604         return 0;
605
606     return m_frameMap.get(frameID);
607 }
608
609 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
610 {
611     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
612 }
613
614 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
615 {
616     ASSERT(canCreateFrame(frameID));
617     m_frameMap.set(frameID, frameProxy);
618 }
619
620 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
621 {
622     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
623     // back to the UIProcess, then the frameDestroyed message will still be received because it
624     // gets sent directly to the WebProcessProxy.
625     ASSERT(WebFrameProxyMap::isValidKey(frameID));
626     m_frameMap.remove(frameID);
627 }
628
629 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
630 {
631     Vector<RefPtr<WebFrameProxy>> frames;
632     copyValuesToVector(m_frameMap, frames);
633     for (size_t i = 0, size = frames.size(); i < size; ++i) {
634         if (frames[i]->page() == page)
635             frames[i]->webProcessWillShutDown();
636     }
637 }
638
639 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
640 {
641     size_t result = 0;
642     for (HashMap<uint64_t, RefPtr<WebFrameProxy>>::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
643         if (iter->value->page() == page)
644             ++result;
645     }
646     return result;
647 }
648
649 RefPtr<API::UserInitiatedAction> WebProcessProxy::userInitiatedActivity(uint64_t identifier)
650 {
651     if (!UserInitiatedActionMap::isValidKey(identifier) || !identifier)
652         return nullptr;
653
654     auto result = m_userInitiatedActionMap.ensure(identifier, [] { return API::UserInitiatedAction::create(); });
655     return result.iterator->value;
656 }
657
658 void WebProcessProxy::didDestroyUserGestureToken(uint64_t identifier)
659 {
660     ASSERT(UserInitiatedActionMap::isValidKey(identifier));
661     m_userInitiatedActionMap.remove(identifier);
662 }
663
664 bool WebProcessProxy::canTerminateChildProcess()
665 {
666     if (!m_pageMap.isEmpty())
667         return false;
668
669     if (!m_processPool->shouldTerminate(this))
670         return false;
671
672     return true;
673 }
674
675 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
676 {
677     shouldTerminate = canTerminateChildProcess();
678     if (shouldTerminate) {
679         // We know that the web process is going to terminate so start shutting it down in the UI process.
680         shutDown();
681     }
682 }
683
684 void WebProcessProxy::updateTextCheckerState()
685 {
686     if (canSendMessage())
687         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
688 }
689
690 void WebProcessProxy::didSaveToPageCache()
691 {
692     m_processPool->processDidCachePage(this);
693 }
694
695 void WebProcessProxy::releasePageCache()
696 {
697     if (canSendMessage())
698         send(Messages::WebProcess::ReleasePageCache(), 0);
699 }
700
701 void WebProcessProxy::windowServerConnectionStateChanged()
702 {
703     for (const auto& page : m_pageMap.values())
704         page->viewStateDidChange(ViewState::IsVisuallyIdle);
705 }
706
707 void WebProcessProxy::fetchWebsiteData(SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, Function<void (WebsiteData)> completionHandler)
708 {
709     ASSERT(canSendMessage());
710
711     auto token = throttler().backgroundActivityToken();
712     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is taking a background assertion because the Web process is fetching Website data", this);
713
714     connection()->sendWithReply(Messages::WebProcess::FetchWebsiteData(sessionID, dataTypes), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
715         if (!reply) {
716             completionHandler(WebsiteData { });
717             return;
718         }
719
720         completionHandler(WTFMove(std::get<0>(*reply)));
721         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is releasing a background assertion because the Web process is done fetching Website data", this);
722     });
723 }
724
725 void WebProcessProxy::deleteWebsiteData(SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, std::chrono::system_clock::time_point modifiedSince, Function<void ()> completionHandler)
726 {
727     ASSERT(canSendMessage());
728
729     auto token = throttler().backgroundActivityToken();
730     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data", this);
731
732     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteData(sessionID, dataTypes, modifiedSince), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
733         completionHandler();
734         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data", this);
735     });
736 }
737
738 void WebProcessProxy::deleteWebsiteDataForOrigins(SessionID sessionID, OptionSet<WebsiteDataType> dataTypes, const Vector<RefPtr<WebCore::SecurityOrigin>>& origins, Function<void ()> completionHandler)
739 {
740     ASSERT(canSendMessage());
741
742     auto token = throttler().backgroundActivityToken();
743     RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is taking a background assertion because the Web process is deleting Website data for several origins", this);
744
745     Vector<SecurityOriginData> originData;
746     for (auto& origin : origins)
747         originData.append(SecurityOriginData::fromSecurityOrigin(*origin));
748
749     connection()->sendWithReply(Messages::WebProcess::DeleteWebsiteDataForOrigins(sessionID, dataTypes, originData), 0, RunLoop::main(), [this, token, completionHandler = WTFMove(completionHandler), sessionID](auto reply) {
750         completionHandler();
751         RELEASE_LOG_IF(sessionID.isAlwaysOnLoggingAllowed(), "%p - WebProcessProxy is releasing a background assertion because the Web process is done deleting Website data for several origins", this);
752     });
753 }
754
755 void WebProcessProxy::requestTermination()
756 {
757     if (state() != State::Running)
758         return;
759
760     ChildProcessProxy::terminate();
761
762     if (webConnection())
763         webConnection()->didClose();
764
765     shutDown();
766 }
767
768 void WebProcessProxy::enableSuddenTermination()
769 {
770     if (state() != State::Running)
771         return;
772
773     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
774     WebCore::enableSuddenTermination();
775     --m_numberOfTimesSuddenTerminationWasDisabled;
776 }
777
778 void WebProcessProxy::disableSuddenTermination()
779 {
780     if (state() != State::Running)
781         return;
782
783     WebCore::disableSuddenTermination();
784     ++m_numberOfTimesSuddenTerminationWasDisabled;
785 }
786
787 RefPtr<API::Object> WebProcessProxy::transformHandlesToObjects(API::Object* object)
788 {
789     struct Transformer final : UserData::Transformer {
790         Transformer(WebProcessProxy& webProcessProxy)
791             : m_webProcessProxy(webProcessProxy)
792         {
793         }
794
795         bool shouldTransformObject(const API::Object& object) const override
796         {
797             switch (object.type()) {
798             case API::Object::Type::FrameHandle:
799                 return static_cast<const API::FrameHandle&>(object).isAutoconverting();
800
801             case API::Object::Type::PageHandle:
802                 return static_cast<const API::PageHandle&>(object).isAutoconverting();
803
804             case API::Object::Type::PageGroupHandle:
805 #if PLATFORM(COCOA)
806             case API::Object::Type::ObjCObjectGraph:
807 #endif
808                 return true;
809
810             default:
811                 return false;
812             }
813         }
814
815         RefPtr<API::Object> transformObject(API::Object& object) const override
816         {
817             switch (object.type()) {
818             case API::Object::Type::FrameHandle:
819                 ASSERT(static_cast<API::FrameHandle&>(object).isAutoconverting());
820                 return m_webProcessProxy.webFrame(static_cast<API::FrameHandle&>(object).frameID());
821
822             case API::Object::Type::PageGroupHandle:
823                 return WebPageGroup::get(static_cast<API::PageGroupHandle&>(object).webPageGroupData().pageGroupID);
824
825             case API::Object::Type::PageHandle:
826                 ASSERT(static_cast<API::PageHandle&>(object).isAutoconverting());
827                 return m_webProcessProxy.webPage(static_cast<API::PageHandle&>(object).pageID());
828
829 #if PLATFORM(COCOA)
830             case API::Object::Type::ObjCObjectGraph:
831                 return m_webProcessProxy.transformHandlesToObjects(static_cast<ObjCObjectGraph&>(object));
832 #endif
833             default:
834                 return &object;
835             }
836         }
837
838         WebProcessProxy& m_webProcessProxy;
839     };
840
841     return UserData::transform(object, Transformer(*this));
842 }
843
844 RefPtr<API::Object> WebProcessProxy::transformObjectsToHandles(API::Object* object)
845 {
846     struct Transformer final : UserData::Transformer {
847         bool shouldTransformObject(const API::Object& object) const override
848         {
849             switch (object.type()) {
850             case API::Object::Type::Frame:
851             case API::Object::Type::Page:
852             case API::Object::Type::PageGroup:
853 #if PLATFORM(COCOA)
854             case API::Object::Type::ObjCObjectGraph:
855 #endif
856                 return true;
857
858             default:
859                 return false;
860             }
861         }
862
863         RefPtr<API::Object> transformObject(API::Object& object) const override
864         {
865             switch (object.type()) {
866             case API::Object::Type::Frame:
867                 return API::FrameHandle::createAutoconverting(static_cast<const WebFrameProxy&>(object).frameID());
868
869             case API::Object::Type::Page:
870                 return API::PageHandle::createAutoconverting(static_cast<const WebPageProxy&>(object).pageID());
871
872             case API::Object::Type::PageGroup:
873                 return API::PageGroupHandle::create(WebPageGroupData(static_cast<const WebPageGroup&>(object).data()));
874
875 #if PLATFORM(COCOA)
876             case API::Object::Type::ObjCObjectGraph:
877                 return transformObjectsToHandles(static_cast<ObjCObjectGraph&>(object));
878 #endif
879
880             default:
881                 return &object;
882             }
883         }
884     };
885
886     return UserData::transform(object, Transformer());
887 }
888
889 void WebProcessProxy::sendProcessWillSuspendImminently()
890 {
891     if (!canSendMessage())
892         return;
893
894     bool handled = false;
895     sendSync(Messages::WebProcess::ProcessWillSuspendImminently(), Messages::WebProcess::ProcessWillSuspendImminently::Reply(handled), 0, std::chrono::seconds(1));
896 }
897
898 void WebProcessProxy::sendPrepareToSuspend()
899 {
900     if (canSendMessage())
901         send(Messages::WebProcess::PrepareToSuspend(), 0);
902 }
903
904 void WebProcessProxy::sendCancelPrepareToSuspend()
905 {
906     if (canSendMessage())
907         send(Messages::WebProcess::CancelPrepareToSuspend(), 0);
908 }
909
910 void WebProcessProxy::sendProcessDidResume()
911 {
912     if (canSendMessage())
913         send(Messages::WebProcess::ProcessDidResume(), 0);
914 }
915
916 void WebProcessProxy::processReadyToSuspend()
917 {
918     m_throttler.processReadyToSuspend();
919 }
920
921 void WebProcessProxy::didCancelProcessSuspension()
922 {
923     m_throttler.didCancelProcessSuspension();
924 }
925
926 void WebProcessProxy::reinstateNetworkProcessAssertionState(NetworkProcessProxy& newNetworkProcessProxy)
927 {
928 #if PLATFORM(IOS)
929     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
930
931     // The network process crashed; take new tokens for the new network process.
932     if (m_backgroundTokenForNetworkProcess)
933         m_backgroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().backgroundActivityToken();
934     else if (m_foregroundTokenForNetworkProcess)
935         m_foregroundTokenForNetworkProcess = newNetworkProcessProxy.throttler().foregroundActivityToken();
936 #else
937     UNUSED_PARAM(newNetworkProcessProxy);
938 #endif
939 }
940
941 void WebProcessProxy::didSetAssertionState(AssertionState state)
942 {
943 #if PLATFORM(IOS)
944     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
945
946     switch (state) {
947     case AssertionState::Suspended:
948         RELEASE_LOG("%p - WebProcessProxy::didSetAssertionState(Suspended) release all assertions for network process", this);
949         m_foregroundTokenForNetworkProcess = nullptr;
950         m_backgroundTokenForNetworkProcess = nullptr;
951         for (auto& page : m_pageMap.values())
952             page->processWillBecomeSuspended();
953         break;
954
955     case AssertionState::Background:
956         RELEASE_LOG("%p - WebProcessProxy::didSetAssertionState(Background) taking background assertion for network process", this);
957         m_backgroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().backgroundActivityToken();
958         m_foregroundTokenForNetworkProcess = nullptr;
959         break;
960     
961     case AssertionState::Foreground:
962         RELEASE_LOG("%p - WebProcessProxy::didSetAssertionState(Foreground) taking foreground assertion for network process", this);
963         m_foregroundTokenForNetworkProcess = processPool().ensureNetworkProcess().throttler().foregroundActivityToken();
964         m_backgroundTokenForNetworkProcess = nullptr;
965         for (auto& page : m_pageMap.values())
966             page->processWillBecomeForeground();
967         break;
968     }
969
970     ASSERT(!m_backgroundTokenForNetworkProcess || !m_foregroundTokenForNetworkProcess);
971 #else
972     UNUSED_PARAM(state);
973 #endif
974 }
975     
976 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
977 {
978     if (!isHoldingLockedFiles) {
979         RELEASE_LOG("UIProcess is releasing a background assertion because the WebContent process is no longer holding locked files");
980         m_tokenForHoldingLockedFiles = nullptr;
981         return;
982     }
983     if (!m_tokenForHoldingLockedFiles) {
984         RELEASE_LOG("UIProcess is taking a background assertion because the WebContent process is holding locked files");
985         m_tokenForHoldingLockedFiles = m_throttler.backgroundActivityToken();
986     }
987 }
988
989 void WebProcessProxy::isResponsive(std::function<void(bool isWebProcessResponsive)> callback)
990 {
991     if (m_isResponsive == NoOrMaybe::No) {
992         if (callback) {
993             RunLoop::main().dispatch([callback = WTFMove(callback)] {
994                 bool isWebProcessResponsive = false;
995                 callback(isWebProcessResponsive);
996             });
997         }
998         return;
999     }
1000
1001     if (callback)
1002         m_isResponsiveCallbacks.append(callback);
1003
1004     responsivenessTimer().start();
1005     send(Messages::WebProcess::MainThreadPing(), 0);
1006 }
1007
1008 void WebProcessProxy::didReceiveMainThreadPing()
1009 {
1010     responsivenessTimer().stop();
1011
1012     auto isResponsiveCallbacks = WTFMove(m_isResponsiveCallbacks);
1013     bool isWebProcessResponsive = true;
1014     for (auto& callback : isResponsiveCallbacks)
1015         callback(isWebProcessResponsive);
1016 }
1017
1018 #if !PLATFORM(COCOA)
1019 const HashSet<String>& WebProcessProxy::platformPathsWithAssumedReadAccess()
1020 {
1021     static NeverDestroyed<HashSet<String>> platformPathsWithAssumedReadAccess;
1022     return platformPathsWithAssumedReadAccess;
1023 }
1024 #endif
1025
1026 } // namespace WebKit