Track pages preventing suppression in WebProcessProxy using RefCounter
[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 "APIHistoryClient.h"
31 #include "CustomProtocolManagerProxyMessages.h"
32 #include "DataReference.h"
33 #include "DownloadProxyMap.h"
34 #include "PluginInfoStore.h"
35 #include "PluginProcessManager.h"
36 #include "TextChecker.h"
37 #include "TextCheckerState.h"
38 #include "UserData.h"
39 #include "WebUserContentControllerProxy.h"
40 #include "WebBackForwardListItem.h"
41 #include "WebContext.h"
42 #include "WebInspectorProxy.h"
43 #include "WebNavigationDataStore.h"
44 #include "WebNotificationManagerProxy.h"
45 #include "WebPageGroup.h"
46 #include "WebPageProxy.h"
47 #include "WebPluginSiteDataManager.h"
48 #include "WebProcessMessages.h"
49 #include "WebProcessProxyMessages.h"
50 #include <WebCore/SuddenTermination.h>
51 #include <WebCore/URL.h>
52 #include <stdio.h>
53 #include <wtf/NeverDestroyed.h>
54 #include <wtf/RunLoop.h>
55 #include <wtf/text/CString.h>
56 #include <wtf/text/WTFString.h>
57
58 #if PLATFORM(COCOA)
59 #include "PDFPlugin.h"
60 #endif
61
62 #if ENABLE(SEC_ITEM_SHIM)
63 #include "SecItemShimProxy.h"
64 #endif
65
66 using namespace WebCore;
67
68 #define MESSAGE_CHECK(assertion) MESSAGE_CHECK_BASE(assertion, connection())
69 #define MESSAGE_CHECK_URL(url) MESSAGE_CHECK_BASE(checkURLReceivedFromWebProcess(url), connection())
70
71 namespace WebKit {
72
73 static uint64_t generatePageID()
74 {
75     static uint64_t uniquePageID;
76     return ++uniquePageID;
77 }
78
79 static WebProcessProxy::WebPageProxyMap& globalPageMap()
80 {
81     ASSERT(RunLoop::isMain());
82     static NeverDestroyed<WebProcessProxy::WebPageProxyMap> pageMap;
83     return pageMap;
84 }
85
86 PassRefPtr<WebProcessProxy> WebProcessProxy::create(WebContext& context)
87 {
88     return adoptRef(new WebProcessProxy(context));
89 }
90
91 WebProcessProxy::WebProcessProxy(WebContext& context)
92     : m_responsivenessTimer(this)
93     , m_context(context)
94     , m_mayHaveUniversalFileReadSandboxExtension(false)
95     , m_customProtocolManagerProxy(this, context)
96 #if PLATFORM(COCOA)
97     , m_pagesPreventingSuppressionCounter([this]() { updateProcessSuppressionState(); })
98     , m_processSuppressionEnabled(false)
99 #endif
100     , m_numberOfTimesSuddenTerminationWasDisabled(0)
101     , m_throttler(std::make_unique<ProcessThrottler>(this))
102 {
103     connect();
104 }
105
106 WebProcessProxy::~WebProcessProxy()
107 {
108     if (m_webConnection)
109         m_webConnection->invalidate();
110
111     while (m_numberOfTimesSuddenTerminationWasDisabled-- > 0)
112         WebCore::enableSuddenTermination();
113 }
114
115 void WebProcessProxy::getLaunchOptions(ProcessLauncher::LaunchOptions& launchOptions)
116 {
117     launchOptions.processType = ProcessLauncher::WebProcess;
118 #if ENABLE(INSPECTOR)
119     if (&m_context.get() == &WebInspectorProxy::inspectorContext())
120         launchOptions.extraInitializationData.add(ASCIILiteral("inspector-process"), ASCIILiteral("1"));
121 #endif
122     platformGetLaunchOptions(launchOptions);
123 }
124
125 void WebProcessProxy::connectionWillOpen(IPC::Connection* connection)
126 {
127     ASSERT(this->connection() == connection);
128
129 #if ENABLE(SEC_ITEM_SHIM)
130     SecItemShimProxy::shared().initializeConnection(connection);
131 #endif
132
133     for (WebPageProxyMap::iterator it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it)
134         it->value->connectionWillOpen(connection);
135
136     m_context->processWillOpenConnection(this);
137 }
138
139 void WebProcessProxy::connectionWillClose(IPC::Connection* connection)
140 {
141     ASSERT(this->connection() == connection);
142
143     for (WebPageProxyMap::iterator it = m_pageMap.begin(), end = m_pageMap.end(); it != end; ++it)
144         it->value->connectionWillClose(connection);
145
146     m_context->processWillCloseConnection(this);
147 }
148
149 void WebProcessProxy::disconnect()
150 {
151     clearConnection();
152
153     if (m_webConnection) {
154         m_webConnection->invalidate();
155         m_webConnection = nullptr;
156     }
157
158     m_responsivenessTimer.invalidate();
159     m_tokenForHoldingLockedFiles = nullptr;
160
161     Vector<RefPtr<WebFrameProxy>> frames;
162     copyValuesToVector(m_frameMap, frames);
163
164     for (size_t i = 0, size = frames.size(); i < size; ++i)
165         frames[i]->disconnect();
166     m_frameMap.clear();
167
168     if (m_downloadProxyMap)
169         m_downloadProxyMap->processDidClose();
170
171     for (VisitedLinkProvider* visitedLinkProvider : m_visitedLinkProviders)
172         visitedLinkProvider->removeProcess(*this);
173     m_visitedLinkProviders.clear();
174
175     for (WebUserContentControllerProxy* webUserContentControllerProxy : m_webUserContentControllerProxies)
176         webUserContentControllerProxy->removeProcess(*this);
177     m_webUserContentControllerProxies.clear();
178
179     m_context->disconnectProcess(this);
180 }
181
182 WebPageProxy* WebProcessProxy::webPage(uint64_t pageID)
183 {
184     return globalPageMap().get(pageID);
185 }
186
187 PassRefPtr<WebPageProxy> WebProcessProxy::createWebPage(PageClient& pageClient, const WebPageConfiguration& configuration)
188 {
189     uint64_t pageID = generatePageID();
190     RefPtr<WebPageProxy> webPage = WebPageProxy::create(pageClient, *this, pageID, configuration);
191     m_pageMap.set(pageID, webPage.get());
192     globalPageMap().set(pageID, webPage.get());
193     return webPage.release();
194 }
195
196 void WebProcessProxy::addExistingWebPage(WebPageProxy* webPage, uint64_t pageID)
197 {
198     ASSERT(!m_pageMap.contains(pageID));
199     ASSERT(!globalPageMap().contains(pageID));
200
201     m_pageMap.set(pageID, webPage);
202     globalPageMap().set(pageID, webPage);
203 }
204
205 void WebProcessProxy::removeWebPage(uint64_t pageID)
206 {
207     m_pageMap.remove(pageID);
208     globalPageMap().remove(pageID);
209     
210     Vector<uint64_t> itemIDsToRemove;
211     for (auto& idAndItem : m_backForwardListItemMap) {
212         if (idAndItem.value->pageID() == pageID)
213             itemIDsToRemove.append(idAndItem.key);
214     }
215     for (auto itemID : itemIDsToRemove)
216         m_backForwardListItemMap.remove(itemID);
217
218     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
219     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
220     if (!m_context->usesNetworkProcess() || state() == State::Terminated || !canTerminateChildProcess())
221         return;
222
223     abortProcessLaunchIfNeeded();
224
225 #if PLATFORM(IOS)
226     if (state() == State::Running) {
227         // On iOS deploy a watchdog in the UI process, since the content may be suspended.
228         // 30s should be sufficient for any outstanding activity to complete cleanly.
229         connection()->terminateSoon(30);
230     }
231 #endif
232
233     disconnect();
234 }
235
236 void WebProcessProxy::addVisitedLinkProvider(VisitedLinkProvider& provider)
237 {
238     m_visitedLinkProviders.add(&provider);
239     provider.addProcess(*this);
240 }
241
242 void WebProcessProxy::addWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
243 {
244     m_webUserContentControllerProxies.add(&proxy);
245     proxy.addProcess(*this);
246 }
247
248 void WebProcessProxy::didDestroyVisitedLinkProvider(VisitedLinkProvider& provider)
249 {
250     ASSERT(m_visitedLinkProviders.contains(&provider));
251     m_visitedLinkProviders.remove(&provider);
252 }
253
254 void WebProcessProxy::didDestroyWebUserContentControllerProxy(WebUserContentControllerProxy& proxy)
255 {
256     ASSERT(m_webUserContentControllerProxies.contains(&proxy));
257     m_webUserContentControllerProxies.remove(&proxy);
258 }
259
260 WebBackForwardListItem* WebProcessProxy::webBackForwardItem(uint64_t itemID) const
261 {
262     return m_backForwardListItemMap.get(itemID);
263 }
264
265 void WebProcessProxy::registerNewWebBackForwardListItem(WebBackForwardListItem* item)
266 {
267     // This item was just created by the UIProcess and is being added to the map for the first time
268     // so we should not already have an item for this ID.
269     ASSERT(!m_backForwardListItemMap.contains(item->itemID()));
270
271     m_backForwardListItemMap.set(item->itemID(), item);
272 }
273
274 void WebProcessProxy::assumeReadAccessToBaseURL(const String& urlString)
275 {
276     URL url(URL(), urlString);
277     if (!url.isLocalFile())
278         return;
279
280     // There's a chance that urlString does not point to a directory.
281     // Get url's base URL to add to m_localPathsWithAssumedReadAccess.
282     URL baseURL(URL(), url.baseAsString());
283     
284     // Client loads an alternate string. This doesn't grant universal file read, but the web process is assumed
285     // to have read access to this directory already.
286     m_localPathsWithAssumedReadAccess.add(baseURL.fileSystemPath());
287 }
288
289 bool WebProcessProxy::hasAssumedReadAccessToURL(const URL& url) const
290 {
291     if (!url.isLocalFile())
292         return false;
293
294     String path = url.fileSystemPath();
295     for (const String& assumedAccessPath : m_localPathsWithAssumedReadAccess) {
296         // There are no ".." components, because URL removes those.
297         if (path.startsWith(assumedAccessPath))
298             return true;
299     }
300
301     return false;
302 }
303
304 bool WebProcessProxy::checkURLReceivedFromWebProcess(const String& urlString)
305 {
306     return checkURLReceivedFromWebProcess(URL(URL(), urlString));
307 }
308
309 bool WebProcessProxy::checkURLReceivedFromWebProcess(const URL& url)
310 {
311     // 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.
312
313     // Any other non-file URL is OK.
314     if (!url.isLocalFile())
315         return true;
316
317     // Any file URL is also OK if we've loaded a file URL through API before, granting universal read access.
318     if (m_mayHaveUniversalFileReadSandboxExtension)
319         return true;
320
321     // If we loaded a string with a file base URL before, loading resources from that subdirectory is fine.
322     if (hasAssumedReadAccessToURL(url))
323         return true;
324
325     // Items in back/forward list have been already checked.
326     // 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.
327     String path = url.fileSystemPath();
328     for (WebBackForwardListItemMap::iterator iter = m_backForwardListItemMap.begin(), end = m_backForwardListItemMap.end(); iter != end; ++iter) {
329         if (URL(URL(), iter->value->url()).fileSystemPath() == path)
330             return true;
331         if (URL(URL(), iter->value->originalURL()).fileSystemPath() == path)
332             return true;
333     }
334
335     // A Web process that was never asked to load a file URL should not ever ask us to do anything with a file URL.
336     WTFLogAlways("Received an unexpected URL from the web process: '%s'\n", url.string().utf8().data());
337     return false;
338 }
339
340 #if !PLATFORM(COCOA)
341 bool WebProcessProxy::fullKeyboardAccessEnabled()
342 {
343     return false;
344 }
345 #endif
346
347 void WebProcessProxy::addBackForwardItem(uint64_t itemID, uint64_t pageID, const PageState& pageState)
348 {
349     MESSAGE_CHECK_URL(pageState.mainFrameState.originalURLString);
350     MESSAGE_CHECK_URL(pageState.mainFrameState.urlString);
351
352     auto& backForwardListItem = m_backForwardListItemMap.add(itemID, nullptr).iterator->value;
353     if (!backForwardListItem) {
354         BackForwardListItemState backForwardListItemState;
355         backForwardListItemState.identifier = itemID;
356         backForwardListItemState.pageState = pageState;
357         backForwardListItem = WebBackForwardListItem::create(WTF::move(backForwardListItemState), pageID);
358         return;
359     }
360
361     // Update existing item.
362     backForwardListItem->setPageState(pageState);
363 }
364
365 #if ENABLE(NETSCAPE_PLUGIN_API)
366 void WebProcessProxy::getPlugins(bool refresh, Vector<PluginInfo>& plugins, Vector<PluginInfo>& applicationPlugins)
367 {
368     if (refresh)
369         m_context->pluginInfoStore().refresh();
370
371     Vector<PluginModuleInfo> pluginModules = m_context->pluginInfoStore().plugins();
372     for (size_t i = 0; i < pluginModules.size(); ++i)
373         plugins.append(pluginModules[i].info);
374
375 #if ENABLE(PDFKIT_PLUGIN)
376     // Add built-in PDF last, so that it's not used when a real plug-in is installed.
377     if (!m_context->omitPDFSupport()) {
378         plugins.append(PDFPlugin::pluginInfo());
379         applicationPlugins.append(PDFPlugin::pluginInfo());
380     }
381 #else
382     UNUSED_PARAM(applicationPlugins);
383 #endif
384 }
385 #endif // ENABLE(NETSCAPE_PLUGIN_API)
386
387 #if ENABLE(NETSCAPE_PLUGIN_API)
388 void WebProcessProxy::getPluginProcessConnection(uint64_t pluginProcessToken, PassRefPtr<Messages::WebProcessProxy::GetPluginProcessConnection::DelayedReply> reply)
389 {
390     PluginProcessManager::shared().getPluginProcessConnection(pluginProcessToken, reply);
391 }
392 #endif
393
394 #if ENABLE(NETWORK_PROCESS)
395 void WebProcessProxy::getNetworkProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetNetworkProcessConnection::DelayedReply> reply)
396 {
397     m_context->getNetworkProcessConnection(reply);
398 }
399 #endif // ENABLE(NETWORK_PROCESS)
400
401 #if ENABLE(DATABASE_PROCESS)
402 void WebProcessProxy::getDatabaseProcessConnection(PassRefPtr<Messages::WebProcessProxy::GetDatabaseProcessConnection::DelayedReply> reply)
403 {
404     m_context->getDatabaseProcessConnection(reply);
405 }
406 #endif // ENABLE(DATABASE_PROCESS)
407
408 void WebProcessProxy::didReceiveMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder)
409 {
410     if (dispatchMessage(connection, decoder))
411         return;
412
413     if (m_context->dispatchMessage(connection, decoder))
414         return;
415
416     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
417         didReceiveWebProcessProxyMessage(connection, decoder);
418         return;
419     }
420
421     // FIXME: Add unhandled message logging.
422 }
423
424 void WebProcessProxy::didReceiveSyncMessage(IPC::Connection* connection, IPC::MessageDecoder& decoder, std::unique_ptr<IPC::MessageEncoder>& replyEncoder)
425 {
426     if (dispatchSyncMessage(connection, decoder, replyEncoder))
427         return;
428
429     if (m_context->dispatchSyncMessage(connection, decoder, replyEncoder))
430         return;
431
432     if (decoder.messageReceiverName() == Messages::WebProcessProxy::messageReceiverName()) {
433         didReceiveSyncWebProcessProxyMessage(connection, decoder, replyEncoder);
434         return;
435     }
436
437     // FIXME: Add unhandled message logging.
438 }
439
440 void WebProcessProxy::didClose(IPC::Connection*)
441 {
442     // Protect ourselves, as the call to disconnect() below may otherwise cause us
443     // to be deleted before we can finish our work.
444     Ref<WebProcessProxy> protect(*this);
445
446     webConnection()->didClose();
447
448     Vector<RefPtr<WebPageProxy>> pages;
449     copyValuesToVector(m_pageMap, pages);
450
451     disconnect();
452
453     for (size_t i = 0, size = pages.size(); i < size; ++i)
454         pages[i]->processDidCrash();
455
456 }
457
458 void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection* connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName)
459 {
460     WTFLogAlways("Received an invalid message \"%s.%s\" from the web process.\n", messageReceiverName.toString().data(), messageName.toString().data());
461
462     WebContext::didReceiveInvalidMessage(messageReceiverName, messageName);
463
464     // Terminate the WebProcess.
465     terminate();
466
467     // Since we've invalidated the connection we'll never get a IPC::Connection::Client::didClose
468     // callback so we'll explicitly call it here instead.
469     didClose(connection);
470 }
471
472 void WebProcessProxy::didBecomeUnresponsive(ResponsivenessTimer*)
473 {
474     Vector<RefPtr<WebPageProxy>> pages;
475     copyValuesToVector(m_pageMap, pages);
476     for (size_t i = 0, size = pages.size(); i < size; ++i)
477         pages[i]->processDidBecomeUnresponsive();
478 }
479
480 void WebProcessProxy::interactionOccurredWhileUnresponsive(ResponsivenessTimer*)
481 {
482     Vector<RefPtr<WebPageProxy>> pages;
483     copyValuesToVector(m_pageMap, pages);
484     for (size_t i = 0, size = pages.size(); i < size; ++i)
485         pages[i]->interactionOccurredWhileProcessUnresponsive();
486 }
487
488 void WebProcessProxy::didBecomeResponsive(ResponsivenessTimer*)
489 {
490     Vector<RefPtr<WebPageProxy>> pages;
491     copyValuesToVector(m_pageMap, pages);
492     for (size_t i = 0, size = pages.size(); i < size; ++i)
493         pages[i]->processDidBecomeResponsive();
494 }
495
496 void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connection::Identifier connectionIdentifier)
497 {
498     ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
499
500     for (WebPageProxy* page : m_pageMap.values()) {
501         ASSERT(this == &page->process());
502         page->processDidFinishLaunching();
503     }
504
505     m_webConnection = WebConnectionToWebProcess::create(this);
506
507     m_context->processDidFinishLaunching(this);
508
509 #if PLATFORM(COCOA)
510     updateProcessSuppressionState();
511 #endif
512     
513 #if PLATFORM(IOS) && USE(XPC_SERVICES)
514     xpc_connection_t xpcConnection = connection()->xpcConnection();
515     ASSERT(xpcConnection);
516     m_throttler->didConnnectToProcess(xpc_connection_get_pid(xpcConnection));
517 #endif
518 }
519
520 WebFrameProxy* WebProcessProxy::webFrame(uint64_t frameID) const
521 {
522     if (!WebFrameProxyMap::isValidKey(frameID))
523         return 0;
524
525     return m_frameMap.get(frameID);
526 }
527
528 bool WebProcessProxy::canCreateFrame(uint64_t frameID) const
529 {
530     return WebFrameProxyMap::isValidKey(frameID) && !m_frameMap.contains(frameID);
531 }
532
533 void WebProcessProxy::frameCreated(uint64_t frameID, WebFrameProxy* frameProxy)
534 {
535     ASSERT(canCreateFrame(frameID));
536     m_frameMap.set(frameID, frameProxy);
537 }
538
539 void WebProcessProxy::didDestroyFrame(uint64_t frameID)
540 {
541     // If the page is closed before it has had the chance to send the DidCreateMainFrame message
542     // back to the UIProcess, then the frameDestroyed message will still be received because it
543     // gets sent directly to the WebProcessProxy.
544     ASSERT(WebFrameProxyMap::isValidKey(frameID));
545     m_frameMap.remove(frameID);
546 }
547
548 void WebProcessProxy::disconnectFramesFromPage(WebPageProxy* page)
549 {
550     Vector<RefPtr<WebFrameProxy>> frames;
551     copyValuesToVector(m_frameMap, frames);
552     for (size_t i = 0, size = frames.size(); i < size; ++i) {
553         if (frames[i]->page() == page)
554             frames[i]->disconnect();
555     }
556 }
557
558 size_t WebProcessProxy::frameCountInPage(WebPageProxy* page) const
559 {
560     size_t result = 0;
561     for (HashMap<uint64_t, RefPtr<WebFrameProxy>>::const_iterator iter = m_frameMap.begin(); iter != m_frameMap.end(); ++iter) {
562         if (iter->value->page() == page)
563             ++result;
564     }
565     return result;
566 }
567
568 bool WebProcessProxy::canTerminateChildProcess()
569 {
570     if (!m_pageMap.isEmpty())
571         return false;
572
573     if (m_downloadProxyMap && !m_downloadProxyMap->isEmpty())
574         return false;
575
576     if (!m_context->shouldTerminate(this))
577         return false;
578
579     return true;
580 }
581
582 void WebProcessProxy::shouldTerminate(bool& shouldTerminate)
583 {
584     shouldTerminate = canTerminateChildProcess();
585     if (shouldTerminate) {
586         // We know that the web process is going to terminate so disconnect it from the context.
587         disconnect();
588     }
589 }
590
591 void WebProcessProxy::updateTextCheckerState()
592 {
593     if (canSendMessage())
594         send(Messages::WebProcess::SetTextCheckerState(TextChecker::state()), 0);
595 }
596
597 DownloadProxy* WebProcessProxy::createDownloadProxy(const ResourceRequest& request)
598 {
599 #if ENABLE(NETWORK_PROCESS)
600     ASSERT(!m_context->usesNetworkProcess());
601 #endif
602
603     if (!m_downloadProxyMap)
604         m_downloadProxyMap = std::make_unique<DownloadProxyMap>(this);
605
606     return m_downloadProxyMap->createDownloadProxy(m_context, request);
607 }
608
609 void WebProcessProxy::didNavigateWithNavigationData(uint64_t pageID, const WebNavigationDataStore& store, uint64_t frameID) 
610 {
611     WebPageProxy* page = webPage(pageID);
612     if (!page)
613         return;
614     
615     WebFrameProxy* frame = webFrame(frameID);
616     MESSAGE_CHECK(frame);
617     MESSAGE_CHECK(frame->page() == page);
618     
619     m_context->historyClient().didNavigateWithNavigationData(m_context.ptr(), page, store, frame);
620 }
621
622 void WebProcessProxy::didPerformClientRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
623 {
624     WebPageProxy* page = webPage(pageID);
625     if (!page)
626         return;
627
628     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
629         return;
630     
631     WebFrameProxy* frame = webFrame(frameID);
632     MESSAGE_CHECK(frame);
633     MESSAGE_CHECK(frame->page() == page);
634     MESSAGE_CHECK_URL(sourceURLString);
635     MESSAGE_CHECK_URL(destinationURLString);
636
637     m_context->historyClient().didPerformClientRedirect(m_context.ptr(), page, sourceURLString, destinationURLString, frame);
638 }
639
640 void WebProcessProxy::didPerformServerRedirect(uint64_t pageID, const String& sourceURLString, const String& destinationURLString, uint64_t frameID)
641 {
642     WebPageProxy* page = webPage(pageID);
643     if (!page)
644         return;
645     
646     if (sourceURLString.isEmpty() || destinationURLString.isEmpty())
647         return;
648     
649     WebFrameProxy* frame = webFrame(frameID);
650     MESSAGE_CHECK(frame);
651     MESSAGE_CHECK(frame->page() == page);
652     MESSAGE_CHECK_URL(sourceURLString);
653     MESSAGE_CHECK_URL(destinationURLString);
654
655     m_context->historyClient().didPerformServerRedirect(m_context.ptr(), page, sourceURLString, destinationURLString, frame);
656 }
657
658 void WebProcessProxy::didUpdateHistoryTitle(uint64_t pageID, const String& title, const String& url, uint64_t frameID)
659 {
660     WebPageProxy* page = webPage(pageID);
661     if (!page)
662         return;
663
664     WebFrameProxy* frame = webFrame(frameID);
665     MESSAGE_CHECK(frame);
666     MESSAGE_CHECK(frame->page() == page);
667     MESSAGE_CHECK_URL(url);
668
669     m_context->historyClient().didUpdateHistoryTitle(m_context.ptr(), page, title, url, frame);
670 }
671
672 void WebProcessProxy::didSaveToPageCache()
673 {
674     m_context->processDidCachePage(this);
675 }
676
677 void WebProcessProxy::releasePageCache()
678 {
679     if (canSendMessage())
680         send(Messages::WebProcess::ReleasePageCache(), 0);
681 }
682
683 void WebProcessProxy::windowServerConnectionStateChanged()
684 {
685     for (const auto& page : m_pageMap.values())
686         page->viewStateDidChange(ViewState::IsVisuallyIdle);
687 }
688
689 void WebProcessProxy::requestTermination()
690 {
691     if (state() != State::Running)
692         return;
693
694     ChildProcessProxy::terminate();
695
696     if (webConnection())
697         webConnection()->didClose();
698
699     disconnect();
700 }
701
702 void WebProcessProxy::enableSuddenTermination()
703 {
704     if (state() != State::Running)
705         return;
706
707     ASSERT(m_numberOfTimesSuddenTerminationWasDisabled);
708     WebCore::enableSuddenTermination();
709     --m_numberOfTimesSuddenTerminationWasDisabled;
710 }
711
712 void WebProcessProxy::disableSuddenTermination()
713 {
714     if (state() != State::Running)
715         return;
716
717     WebCore::disableSuddenTermination();
718     ++m_numberOfTimesSuddenTerminationWasDisabled;
719 }
720
721 RefPtr<API::Object> WebProcessProxy::apiObjectByConvertingToHandles(API::Object* object)
722 {
723     return UserData::transform(object, [](const API::Object& object) -> RefPtr<API::Object> {
724         switch (object.type()) {
725         case API::Object::Type::Frame: {
726             auto& frame = static_cast<const WebFrameProxy&>(object);
727             return API::FrameHandle::create(frame.frameID());
728         }
729
730         default:
731             return nullptr;
732         }
733     });
734 }
735
736 void WebProcessProxy::sendProcessWillSuspend()
737 {
738     if (canSendMessage())
739         send(Messages::WebProcess::ProcessWillSuspend(), 0);
740 }
741
742 void WebProcessProxy::sendCancelProcessWillSuspend()
743 {
744     if (canSendMessage())
745         send(Messages::WebProcess::CancelProcessWillSuspend(), 0);
746 }
747     
748 void WebProcessProxy::processReadyToSuspend()
749 {
750     m_throttler->processReadyToSuspend();
751 }
752
753 void WebProcessProxy::didCancelProcessSuspension()
754 {
755     m_throttler->didCancelProcessSuspension();
756 }
757
758 void WebProcessProxy::setIsHoldingLockedFiles(bool isHoldingLockedFiles)
759 {
760     if (!isHoldingLockedFiles) {
761         m_tokenForHoldingLockedFiles = nullptr;
762         return;
763     }
764     if (!m_tokenForHoldingLockedFiles)
765         m_tokenForHoldingLockedFiles = std::make_unique<ProcessThrottler::BackgroundActivityToken>(*m_throttler);
766 }
767
768 } // namespace WebKit