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