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