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