WebKit Bugzilla
Attachment 359166 Details for
Bug 193361
: Regression(PSON) View becomes blank after click a cross-site download link
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193361-20190115093711.patch (text/plain), 103.93 KB, created by
Chris Dumez
on 2019-01-15 09:37:12 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Chris Dumez
Created:
2019-01-15 09:37:12 PST
Size:
103.93 KB
patch
obsolete
>Subversion Revision: 239987 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index ad34c6dfdd3a5d9bc1f4626d55f9f49871ca405b..8f765312b6ca9f6366f79c4acd8df2bf288dcbb0 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,17 @@ >+2019-01-15 Chris Dumez <cdumez@apple.com> >+ >+ Regression(PSON) View becomes blank after click a cross-site download link >+ https://bugs.webkit.org/show_bug.cgi?id=193361 >+ <rdar://problem/47099573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * loader/FrameLoader.cpp: >+ (WebCore::FrameLoader::commitProvisionalLoad): >+ When restoring from PageCache, make sure we notify the client that the load was committed >+ *before* we tell it that the navigation is complete. This would confuse the ProvisionalPageProxy >+ logic in the UIProcess. >+ > 2019-01-15 Devin Rousso <drousso@apple.com> > > Web Inspector: Audit: provide a way to determine whether a give node has event listeners >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index b1580fc058b537ed1ade5f752e31766fce3bd401..41b282fbdc5bede0b5e5b17d0959d627fd121e7c 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,200 @@ >+2019-01-15 Chris Dumez <cdumez@apple.com> >+ >+ Regression(PSON) View becomes blank after click a cross-site download link >+ https://bugs.webkit.org/show_bug.cgi?id=193361 >+ <rdar://problem/47099573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ The issue tracked by rdar://problem/47099573 is that a provisional load may get >+ canceled (or converted into a download) *after* we've decided to process-swap. >+ In such cases, the view should keep displaying the current site and it should >+ still be interactive. However, with the previous PSON model, the view (pageProxy) >+ would have already swapped to the new process and would end up displaying the >+ initially empty document. >+ >+ To address the issue, this patch introduces the concept of a provisional load >+ in the UIProcess, handled by a ProvisionalPageProxy which has its own privisional >+ process. The WebPageProxy owns the ProvisionalPageProxy but we do not commit the >+ provisional page until after the load was committed in the new process. This means >+ that the view / WebPageProxy keeps using the old process and displays the current >+ content until a load has committed in the provisional page. If no load commits >+ in the provisional process (e.g. because the load is cancelled or converted into >+ a download), then we merely destroy the ProvisionalPageProxy and terminate its >+ process, without impacting the WebPageProxy. >+ >+ * Shared/WebPageCreationParameters.cpp: >+ (WebKit::WebPageCreationParameters::encode const): >+ (WebKit::WebPageCreationParameters::decode): >+ * Shared/WebPageCreationParameters.h: >+ Rename isSwapFromSuspended to isProcessSwap for clarity as we always want to >+ delay attaching the drawing area in case of a process-swap, no matter what >+ now that the previous process is kept alive until the provisional load is >+ committed in the new process. >+ >+ * Shared/WebPolicyAction.h: >+ Drop Suspend policy action. At decidePolicyForNavigationAction time, in case of >+ process-swap, we now tell the previous process to simply ignore the load, while >+ we create a ProvisionalPageProxy to do the new load in a new process. >+ Suspension of the previous page in the old process, happens later, when a load >+ is actually committed in the new process. >+ >+ * Sources.txt: >+ Add new ProvisionalPageProxy file. >+ >+ * UIProcess/API/Cocoa/WKWebView.mm: >+ (-[WKWebView _killWebContentProcessAndResetState]): >+ When calling _killWebContentProcessAndResetState on a WKWebView, kill both the current >+ process and the provisional one, to maintain previous behavior in our API tests. >+ >+ * UIProcess/PageClient.h: >+ Tiny build fix. >+ >+ * UIProcess/ProvisionalPageProxy.cpp: Added. >+ (WebKit::ProvisionalPageProxy::ProvisionalPageProxy): >+ (WebKit::ProvisionalPageProxy::~ProvisionalPageProxy): >+ (WebKit::ProvisionalPageProxy::takeDrawingArea): >+ (WebKit::ProvisionalPageProxy::cancel): >+ (WebKit::ProvisionalPageProxy::initializeWebPage): >+ (WebKit::ProvisionalPageProxy::loadDataWithNavigation): >+ (WebKit::ProvisionalPageProxy::loadRequestWithNavigation): >+ (WebKit::ProvisionalPageProxy::goToBackForwardItem): >+ (WebKit::ProvisionalPageProxy::didCreateMainFrame): >+ (WebKit::ProvisionalPageProxy::didStartProvisionalLoadForFrame): >+ (WebKit::ProvisionalPageProxy::didFailProvisionalLoadForFrame): >+ (WebKit::ProvisionalPageProxy::didCommitLoadForFrame): >+ (WebKit::ProvisionalPageProxy::didReceiveMessage): >+ (WebKit::ProvisionalPageProxy::didReceiveSyncMessage): >+ * UIProcess/ProvisionalPageProxy.h: Added. >+ (WebKit::ProvisionalPageProxy::page): >+ (WebKit::ProvisionalPageProxy::mainFrame const): >+ (WebKit::ProvisionalPageProxy::process): >+ (WebKit::ProvisionalPageProxy::processSwapRequestedByClient const): >+ (WebKit::ProvisionalPageProxy::navigationID const): >+ Add new ProvisionalPageProxy class to wrap the provisional load in the new process >+ after a swap. The provisional page is owned by the WebPageProxy and we only commit >+ the provisional page when the load is committed. Until then, the WebPageProxy keeps >+ using the old process and displaying the current content. >+ >+ * UIProcess/SuspendedPageProxy.cpp: >+ (WebKit::SuspendedPageProxy::~SuspendedPageProxy): >+ (WebKit::SuspendedPageProxy::unsuspend): >+ (WebKit::SuspendedPageProxy::didProcessRequestToSuspend): >+ Unregister the SuspendedPageProxy as an IPC message receiver a little bit earlier >+ when we're going to unsuspend it. This avoids conflicting with the ProvisionalPageProxy >+ which tries to register itself as an IPC message receiver for the same pageID when >+ a process-swap occurs and we're switching to a suspended page. >+ >+ * UIProcess/WebFrameProxy.cpp: >+ (WebKit::WebFrameProxy::isMainFrame const): >+ WebFrameProxy::isMainFrame() relies on checking that the frame is the WebPageProxy's m_mainFrame. >+ Now that the WebPageProxy can have a ProvisionalPageProxy, also check if it is the ProvisionalPageProxy's >+ m_mainFrame to maintain previous behavior. >+ >+ * UIProcess/WebPageProxy.cpp: >+ (WebKit::WebPageProxy::swapToWebProcess): >+ swapToWebProcess() no longer takes care of unsuspending the SuspendedPage because we now call swapToWebProcess() >+ later, when a load is actually committed in the provisional page / process. swapToWebProcess() now also needs >+ to initialize some data members such as the drawing area and the main frame as it is transferring them over from >+ the ProvisionalPageProxy which started the provisional load. >+ >+ (WebKit::WebPageProxy::finishAttachingToWebProcess): >+ We no longer need IsSwapFromSuspended parameter as this is called later now, after a load has actually been >+ committed in the provisional process. >+ >+ (WebKit::WebPageProxy::initializeWebPage): >+ - We no longer need IsSwapFromSuspended parameter as this is called later now, after a load has actually been >+ committed in the provisional process. >+ - Factor some code out to WebPageProxy::setDrawingArea() so that it can be shared with swapToWebProcess(). >+ >+ (WebKit::WebPageProxy::loadRequestWithNavigation): >+ Only call setPendingAPIRequestURL() in loadRequestWithNavigation() only if ShouldTreatAsContinuingLoad is not >+ Yes. This avoids hitting some assertions as this was already called during the first API call if needed. >+ >+ (WebKit::WebPageProxy::receivedNavigationPolicyDecision): >+ In case of process swap, tell the previous process to ignore the load instead of suspending it right away. >+ Suspension now happens later, only if we end up committing the provisional load in the new process. >+ Also discard the SuspendedPage if it failed to suspend (we only reuse its process in this case). This used >+ to happen a bit later but it is clearer if we do this as early as possible I think. >+ >+ (WebKit::WebPageProxy::commitProvisionalPage): >+ When the load is committed in the new process, we call WebPageProxy::commitProvisionalPage(). It takes care of: >+ - Actually swapping the WebPageProxy to the new process by calling processDidTerminate() / swapToWebProcess(). >+ - Suspending the current page. >+ - Letting the client know the load is comitted >+ - Destroy the ProvisionalPageProxy. >+ This work used to happen earlier in continueNavigationInNewProcess(). >+ >+ (WebKit::WebPageProxy::continueNavigationInNewProcess): >+ Moved some of the logic to commitProvisionalPage(). We now merely start the load in a new ProvisionalPageProxy, >+ without actually having the WebPageProxy switch to the new process yet. >+ >+ (WebKit::WebPageProxy::didCreateMainFrame): >+ (WebKit::WebPageProxy::didCreateWindow): >+ Drop some code that is no longer needed, now that the ProvisionalPageProxy takes care of this. >+ >+ (WebKit::WebPageProxy::didDestroyNavigation): >+ On process-swap, when telling the previous process to ignore the load and starting the new load in a new >+ ProvisionalPageProxy, the previous WebPage attempts to destroy the navigation. In this case, we ignore >+ the call since the navigation is merely taken over by the ProvisionalPageProxy. >+ >+ (WebKit::WebPageProxy::didStartProvisionalLoadForFrame): >+ Moved some PSON logic to the ProvisionalPageProxy instead. >+ >+ (WebKit::WebPageProxy::didFailProvisionalLoadForFrame): >+ When didFailProvisionalLoadForFrame() is called for a ProvisionalPageProxy, destroy it. >+ >+ (WebKit::WebPageProxy::decidePolicyForNavigationActionAsync): >+ (WebKit::WebPageProxy::decidePolicyForResponse): >+ Capture the process in the lambda, to make sure we send the policy decision to the same process that >+ asked for it, so as to not get confused by process swaps. >+ >+ (WebKit::WebPageProxy::resetState): >+ Drop some code that is no longer needed. >+ >+ (WebKit::WebPageProxy::creationParameters): >+ Move the hasRegisteredServiceWorkers flag initialization from the call site to here now that we have >+ more than one call site. This was just some bad factoring. >+ >+ (WebKit::WebPageProxy::PageProcessOverride::PageProcessOverride): >+ (WebKit::WebPageProxy::PageProcessOverride::~PageProcessOverride): >+ * UIProcess/WebPageProxy.h: >+ (WebKit::WebPageProxy::temporarilyOverrideProcess): >+ Add utility class to temporarily override the WebPageProxy's m_process with the provisional one when >+ the ProvisionalPageProxy interacts with the WebPageProxy. >+ >+ * UIProcess/WebProcessProxy.cpp: >+ (WebKit::WebProcessProxy::hasProvisionalPageWithID const): >+ (WebKit::WebProcessProxy::updateBackForwardItem): >+ Before updating a BackForwardListItem, we normally make sure the process has a WebPageProxy with the >+ item's pageID. We have to tweak the logic because there may now be no WebPageProxy with this pageID >+ associated with this process yet, because it is still a ProvisionalPageProxy. >+ >+ (WebKit::WebProcessProxy::canTerminateChildProcess): >+ Do not terminate the WebProcess if there are ProvisionalPageProxy objects using it. >+ >+ * UIProcess/WebProcessProxy.h: >+ (WebKit::WebProcessProxy::addProvisionalPageProxy): >+ (WebKit::WebProcessProxy::removeProvisionalPageProxy): >+ >+ * WebKit.xcodeproj/project.pbxproj: >+ >+ * WebProcess/WebPage/WebFrame.cpp: >+ (WebKit::toPolicyAction): >+ (WebKit::WebFrame::didReceivePolicyDecision): >+ Stop dealing with WebPolicyAction::Suspend as it no longer exists. >+ >+ * WebProcess/WebPage/WebPage.cpp: >+ (WebKit::WebPage::reinitializeWebPage): >+ (WebKit::WebPage::didReceivePolicyDecision): >+ >+ (WebKit::WebPage::setIsSuspended): >+ Suspend the Page when setIsSuspended(true) is called, now that there is no longer a WebPolicyAction::Suspend. >+ setIsSuspended(true) IPC is sent when we actually commit the provisional page. >+ >+ * WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm: >+ (WebKit::TiledCoreAnimationDrawingArea::TiledCoreAnimationDrawingArea): >+ > 2019-01-14 Alex Christensen <achristensen@webkit.org> > > Split headerValueForVary into specialized functions for NetworkProcess and WebProcess/WebKitLegacy >diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp >index 4c26a6981b464da5916f05eb7359669157ee9ffe..ebf950ba6c2ed91f6232bd2b5efb9f79557ab58d 100644 >--- a/Source/WebCore/loader/FrameLoader.cpp >+++ b/Source/WebCore/loader/FrameLoader.cpp >@@ -2032,11 +2032,11 @@ void FrameLoader::commitProvisionalLoad() > > Optional<HasInsecureContent> hasInsecureContent = cachedPage->cachedMainFrame()->hasInsecureContent(); > >+ dispatchDidCommitLoad(hasInsecureContent); >+ > // FIXME: This API should be turned around so that we ground CachedPage into the Page. > cachedPage->restore(*m_frame.page()); > >- dispatchDidCommitLoad(hasInsecureContent); >- > #if PLATFORM(IOS_FAMILY) > m_frame.page()->chrome().setDispatchViewportDataDidChangeSuppressed(false); > m_frame.page()->chrome().dispatchViewportPropertiesDidChange(m_frame.page()->viewportArguments()); >diff --git a/Source/WebKit/Shared/WebPageCreationParameters.cpp b/Source/WebKit/Shared/WebPageCreationParameters.cpp >index ca2df40ee1dd2ca36f3a48a04757f97bdbb63647..6d07c03ad8c927e5453c5fda9596709a77261e2b 100644 >--- a/Source/WebKit/Shared/WebPageCreationParameters.cpp >+++ b/Source/WebKit/Shared/WebPageCreationParameters.cpp >@@ -73,7 +73,7 @@ void WebPageCreationParameters::encode(IPC::Encoder& encoder) const > encoder.encodeEnum(layerHostingMode); > encoder << mimeTypesWithCustomContentProviders; > encoder << controlledByAutomation; >- encoder << isSwapFromSuspended; >+ encoder << isProcessSwap; > > #if PLATFORM(MAC) > encoder << colorSpace; >@@ -227,7 +227,7 @@ Optional<WebPageCreationParameters> WebPageCreationParameters::decode(IPC::Decod > return WTF::nullopt; > if (!decoder.decode(parameters.controlledByAutomation)) > return WTF::nullopt; >- if (!decoder.decode(parameters.isSwapFromSuspended)) >+ if (!decoder.decode(parameters.isProcessSwap)) > return WTF::nullopt; > > #if PLATFORM(MAC) >diff --git a/Source/WebKit/Shared/WebPageCreationParameters.h b/Source/WebKit/Shared/WebPageCreationParameters.h >index ae4325cbd5f1e567616586f5e9fa73ee5b35b937..b382ceedd449a8d9a0f8694735f26c0595ddecd8 100644 >--- a/Source/WebKit/Shared/WebPageCreationParameters.h >+++ b/Source/WebKit/Shared/WebPageCreationParameters.h >@@ -129,7 +129,7 @@ struct WebPageCreationParameters { > Vector<String> mimeTypesWithCustomContentProviders; > > bool controlledByAutomation; >- bool isSwapFromSuspended { false }; >+ bool isProcessSwap { false }; > > #if PLATFORM(MAC) > ColorSpaceData colorSpace; >diff --git a/Source/WebKit/Shared/WebPolicyAction.h b/Source/WebKit/Shared/WebPolicyAction.h >index 142a518df097e5ef2fa180484e09d0333c105b81..3971795c46a51b38818c55b76d653a34b5289e9c 100644 >--- a/Source/WebKit/Shared/WebPolicyAction.h >+++ b/Source/WebKit/Shared/WebPolicyAction.h >@@ -29,11 +29,11 @@ > > namespace WebKit { > >+// FIXME: Remove this type and use WebCore::PolicyAction instead. > enum class WebPolicyAction : uint8_t { > Use, > Download, >- Ignore, >- Suspend >+ Ignore > }; > > } >@@ -45,8 +45,7 @@ template<> struct EnumTraits<WebKit::WebPolicyAction> { > WebKit::WebPolicyAction, > WebKit::WebPolicyAction::Use, > WebKit::WebPolicyAction::Download, >- WebKit::WebPolicyAction::Ignore, >- WebKit::WebPolicyAction::Suspend >+ WebKit::WebPolicyAction::Ignore > >; > }; > >diff --git a/Source/WebKit/Sources.txt b/Source/WebKit/Sources.txt >index a0b6f72846041c263a5476710eac987fed1d1604..8aecb86472502d027a34af3719dd828b007db116 100644 >--- a/Source/WebKit/Sources.txt >+++ b/Source/WebKit/Sources.txt >@@ -230,6 +230,7 @@ UIProcess/InspectorTargetProxy.cpp > UIProcess/PageLoadState.cpp > UIProcess/ProcessAssertion.cpp > UIProcess/ProcessThrottler.cpp >+UIProcess/ProvisionalPageProxy.cpp > UIProcess/RemoteWebInspectorProxy.cpp > UIProcess/ResponsivenessTimer.cpp > UIProcess/ServiceWorkerProcessProxy.cpp >diff --git a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >index 074cddfd2784e869128d020bed59213a1cbdde68..4dfad64e0154359280e6168b1f1ed5ebe6d7d9bb 100644 >--- a/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >+++ b/Source/WebKit/UIProcess/API/Cocoa/WKWebView.mm >@@ -44,6 +44,7 @@ > #import "NavigationState.h" > #import "ObjCObjectGraph.h" > #import "PageClient.h" >+#import "ProvisionalPageProxy.h" > #import "RemoteLayerTreeScrollingPerformanceData.h" > #import "RemoteLayerTreeTransaction.h" > #import "RemoteObjectRegistry.h" >@@ -4700,6 +4701,11 @@ - (void)_killWebContentProcessAndResetState > { > Ref<WebKit::WebProcessProxy> protectedProcessProxy(_page->process()); > protectedProcessProxy->requestTermination(WebKit::ProcessTerminationReason::RequestedByClient); >+ >+ if (auto* provisionalPageProxy = _page->provisionalPageProxy()) { >+ Ref<WebKit::WebProcessProxy> protectedProcessProxy(provisionalPageProxy->process()); >+ protectedProcessProxy->requestTermination(WebKit::ProcessTerminationReason::RequestedByClient); >+ } > } > > #if PLATFORM(MAC) >diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h >index 149714ab1d2265a6834d57ef47b116ea4e29e351..82c77322f2df87e3aed5e004c61b2f793950e389 100644 >--- a/Source/WebKit/UIProcess/PageClient.h >+++ b/Source/WebKit/UIProcess/PageClient.h >@@ -48,6 +48,7 @@ > > OBJC_CLASS CALayer; > OBJC_CLASS NSFileWrapper; >+OBJC_CLASS NSMenu; > OBJC_CLASS NSSet; > OBJC_CLASS WKDrawingView; > OBJC_CLASS _WKRemoteObjectRegistry; >diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..f83b9782924fe6178e5622fb54ae1fba831add5d >--- /dev/null >+++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.cpp >@@ -0,0 +1,310 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ProvisionalPageProxy.h" >+ >+#include "APINavigation.h" >+#include "DrawingAreaProxy.h" >+#include "Logging.h" >+#include "PageClient.h" >+#include "WebBackForwardList.h" >+#include "WebBackForwardListItem.h" >+#include "WebErrors.h" >+#include "WebNavigationState.h" >+#include "WebPageMessages.h" >+#include "WebPageProxy.h" >+#include "WebPageProxyMessages.h" >+#include "WebProcessMessages.h" >+#include "WebProcessProxy.h" >+#include <WebCore/ShouldTreatAsContinuingLoad.h> >+ >+namespace WebKit { >+ >+#define RELEASE_LOG_IF_ALLOWED(channel, fmt, ...) RELEASE_LOG_IF(m_page.isAlwaysOnLoggingAllowed(), channel, "%p - ProvisionalPageProxy::" fmt, this, ##__VA_ARGS__) >+ >+ProvisionalPageProxy::ProvisionalPageProxy(WebPageProxy& page, Ref<WebProcessProxy>&& process, std::unique_ptr<SuspendedPageProxy> suspendedPage, uint64_t navigationID, bool isServerRedirect, const WebCore::ResourceRequest& request, ProcessSwapRequestedByClient processSwapRequestedByClient) >+ : m_page(page) >+ , m_process(WTFMove(process)) >+ , m_navigationID(navigationID) >+ , m_isServerRedirect(isServerRedirect) >+ , m_request(request) >+ , m_processSwapRequestedByClient(processSwapRequestedByClient) >+#if PLATFORM(IOS_FAMILY) >+ , m_suspensionToken(m_process->throttler().foregroundActivityToken()) >+#endif >+{ >+ m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID(), *this); >+ m_process->addProvisionalPageProxy(*this); >+ >+ // If we are reattaching to a SuspendedPage, then the WebProcess' WebPage already exists and >+ // WebPageProxy::didCreateMainFrame() will not be called to initialize m_mainFrame. In such >+ // case, we need to initialize m_mainFrame to reflect the fact the the WebProcess' WebPage >+ // already exists and already has a main frame. >+ if (suspendedPage) { >+ ASSERT(&suspendedPage->process() == m_process.ptr()); >+ suspendedPage->unsuspend(); >+ m_mainFrame = WebFrameProxy::create(m_page, suspendedPage->mainFrameID()); >+ m_process->frameCreated(suspendedPage->mainFrameID(), *m_mainFrame); >+ } >+ >+ initializeWebPage(); >+} >+ >+ProvisionalPageProxy::~ProvisionalPageProxy() >+{ >+ m_process->removeProvisionalPageProxy(*this); >+ >+ if (m_wasCommitted) >+ return; >+ >+ m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); >+ m_process->send(Messages::WebPage::Close(), m_page.pageID()); >+ >+ if (m_drawingArea) { >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_drawingArea = nullptr; >+ } >+ >+ RunLoop::main().dispatch([process = m_process.copyRef()] { >+ process->maybeShutDown(); >+ }); >+} >+ >+void ProvisionalPageProxy::processDidTerminate() >+{ >+ m_page.provisionalProcessDidTerminate(); >+} >+ >+std::unique_ptr<DrawingAreaProxy> ProvisionalPageProxy::takeDrawingArea() >+{ >+ return WTFMove(m_drawingArea); >+} >+ >+void ProvisionalPageProxy::cancel() >+{ >+ // If the provisional load started, then indicate that it failed due to cancellation by calling didFailProvisionalLoadForFrame(). >+ if (m_provisionalLoadURL.isEmpty()) >+ return; >+ >+ RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "cancel: Simulating a didFailProvisionalLoadForFrame for pageID = %" PRIu64, m_page.pageID()); >+ ASSERT(m_mainFrame); >+ auto error = WebKit::cancelledError(m_request); >+ error.setType(WebCore::ResourceError::Type::Cancellation); >+ didFailProvisionalLoadForFrame(m_mainFrame->frameID(), { }, m_navigationID, m_provisionalLoadURL, error, UserData { }); // Will delete |this|. >+} >+ >+void ProvisionalPageProxy::processDidFinishLaunching() >+{ >+ finishInitializingWebPageAfterProcessLaunch(); >+} >+ >+void ProvisionalPageProxy::finishInitializingWebPageAfterProcessLaunch() >+{ >+ ASSERT(m_process->state() == WebProcessProxy::State::Running); >+ >+ // FIXME: The WebPageProxy delays adding the visited link store until after the process has launched >+ // so the ProvisionalPageProxy does the same. However, do we really need to? >+ m_process->addVisitedLinkStore(m_page.visitedLinkStore()); >+} >+ >+void ProvisionalPageProxy::initializeWebPage() >+{ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_drawingArea = m_page.pageClient().createDrawingAreaProxy(); >+ >+ auto parameters = m_page.creationParameters(); >+ parameters.isProcessSwap = true; >+ m_process->send(Messages::WebProcess::CreateWebPage(m_page.pageID(), parameters), 0); >+ >+ if (m_process->state() == WebProcessProxy::State::Running) >+ finishInitializingWebPageAfterProcessLaunch(); >+} >+ >+void ProvisionalPageProxy::loadDataWithNavigation(API::Navigation& navigation, const IPC::DataReference& data, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<WebsitePoliciesData>&& websitePolicies) >+{ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.loadDataWithNavigation(navigation, data, MIMEType, encoding, baseURL, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)); >+} >+ >+void ProvisionalPageProxy::loadRequestWithNavigation(API::Navigation& navigation, WebCore::ResourceRequest&& request, WebCore::ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, Optional<WebsitePoliciesData>&& websitePolicies) >+{ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.loadRequestWithNavigation(navigation, WTFMove(request), shouldOpenExternalURLsPolicy, userData, WebCore::ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)); >+} >+ >+void ProvisionalPageProxy::goToBackForwardItem(API::Navigation& navigation, WebBackForwardListItem& item, Optional<WebsitePoliciesData>&& websitePolicies) >+{ >+ auto itemStates = m_page.backForwardList().filteredItemStates([this, targetItem = &item](auto& item) { >+ if (auto* page = item.suspendedPage()) { >+ if (&page->process() == m_process.ptr()) >+ return false; >+ } >+ return &item != targetItem; >+ }); >+ m_process->send(Messages::WebPage::UpdateBackForwardListForReattach(WTFMove(itemStates)), m_page.pageID()); >+ m_process->send(Messages::WebPage::GoToBackForwardItem(navigation.navigationID(), item.itemID(), *navigation.backForwardFrameLoadType(), WebCore::ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)), m_page.pageID()); >+ m_process->responsivenessTimer().start(); >+} >+ >+void ProvisionalPageProxy::didCreateMainFrame(uint64_t frameID) >+{ >+ RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "didCreateMainFrame: pageID = %" PRIu64 ", frameID = %" PRIu64, m_page.pageID(), frameID); >+ ASSERT(!m_mainFrame); >+ >+ m_mainFrame = WebFrameProxy::create(m_page, frameID); >+ >+ // Add the frame to the process wide map. >+ m_process->frameCreated(frameID, *m_mainFrame); >+ >+ // This navigation was destroyed so no need to notify of redirect. >+ if (!m_page.navigationState().hasNavigation(m_navigationID)) >+ return; >+ >+ // Restore the main frame's committed URL as some clients may rely on it until the next load is committed. >+ if (auto* mainFrame = m_page.mainFrame()) >+ m_mainFrame->frameLoadState().setURL(mainFrame->frameLoadState().url()); >+ >+ // Normally, notification of a server redirect comes from the WebContent process. >+ // If we are process swapping in response to a server redirect then that notification will not come from the new WebContent process. >+ // In this case we have the UIProcess synthesize the redirect notification at the appropriate time. >+ if (m_isServerRedirect) { >+ m_mainFrame->frameLoadState().didStartProvisionalLoad(m_request.url()); >+ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), m_navigationID, WTFMove(m_request), { }); >+ } >+} >+ >+void ProvisionalPageProxy::didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, URL&& url, URL&& unreachableURL, const UserData& userData) >+{ >+ // If the previous provisional load used the same process, we may receive IPC for this previous provisional's main frame that we need to ignore. >+ if (!m_mainFrame || m_mainFrame->frameID() != frameID) >+ return; >+ >+ RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "didStartProvisionalLoadForFrame: pageID = %" PRIu64 ", frameID = %" PRIu64 ", navigationID = %" PRIu64, m_page.pageID(), frameID, navigationID); >+ ASSERT(m_provisionalLoadURL.isNull()); >+ m_provisionalLoadURL = url; >+ >+ // Merely following a server side redirect so there is no need to send a didStartProvisionalLoad again. >+ if (m_isServerRedirect) >+ return; >+ >+ // Clients expect the Page's main frame's expectedURL to be the provisional one when a provisional load is started. >+ if (auto* pageMainFrame = m_page.mainFrame()) >+ pageMainFrame->didStartProvisionalLoad(url); >+ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.didStartProvisionalLoadForFrame(frameID, navigationID, WTFMove(url), WTFMove(unreachableURL), userData); >+} >+ >+void ProvisionalPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const WebCore::ResourceError& error, const UserData& userData) >+{ >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ >+ RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "didFailProvisionalLoadForFrame: pageID = %" PRIu64 ", frameID = %" PRIu64 ", navigationID = %" PRIu64, m_page.pageID(), frameID, navigationID); >+ m_provisionalLoadURL = { }; >+ >+ // Make sure the Page's main frame's expectedURL gets cleared since we updated it in didStartProvisionalLoad. >+ if (auto* pageMainFrame = m_page.mainFrame()) >+ pageMainFrame->didFailProvisionalLoad(); >+ >+ m_page.didFailProvisionalLoadForFrame(frameID, frameSecurityOrigin, navigationID, provisionalURL, error, userData); // Will delete |this|. >+} >+ >+void ProvisionalPageProxy::didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData& userData) >+{ >+ // If the previous provisional load used the same process, we may receive IPC for this previous provisional's main frame that we need to ignore. >+ if (!m_mainFrame || m_mainFrame->frameID() != frameID) >+ return; >+ >+ RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "didCommitLoadForFrame: pageID = %" PRIu64 ", frameID = %" PRIu64 ", navigationID = %" PRIu64, m_page.pageID(), frameID, navigationID); >+ m_provisionalLoadURL = { }; >+ m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); >+ >+ m_wasCommitted = true; >+ m_page.commitProvisionalPage(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, containsPluginDocument, forcedHasInsecureContent, userData); // Will delete |this|. >+} >+ >+void ProvisionalPageProxy::didReceiveMessage(IPC::Connection& connection, IPC::Decoder& decoder) >+{ >+ ASSERT(decoder.messageReceiverName() == Messages::WebPageProxy::messageReceiverName()); >+ >+ if (decoder.messageName() == Messages::WebPageProxy::DidStartProgress::name() >+ || decoder.messageName() == Messages::WebPageProxy::DidChangeProgress::name() >+ || decoder.messageName() == Messages::WebPageProxy::BackForwardAddItem::name() >+ || decoder.messageName() == Messages::WebPageProxy::LogDiagnosticMessage::name() >+ || decoder.messageName() == Messages::WebPageProxy::LogDiagnosticMessageWithEnhancedPrivacy::name() >+ || decoder.messageName() == Messages::WebPageProxy::SetNetworkRequestsInProgress::name() >+#if PLATFORM(COCOA) >+ || decoder.messageName() == Messages::WebPageProxy::RegisterWebProcessAccessibilityToken::name() >+#endif >+ || decoder.messageName() == Messages::WebPageProxy::DecidePolicyForNavigationActionAsync::name() >+ || decoder.messageName() == Messages::WebPageProxy::StartURLSchemeTask::name() >+ || decoder.messageName() == Messages::WebPageProxy::DecidePolicyForResponse::name() >+ || decoder.messageName() == Messages::WebPageProxy::DidPerformClientRedirect::name() >+ || decoder.messageName() == Messages::WebPageProxy::DidChangeProvisionalURLForFrame::name() >+ || decoder.messageName() == Messages::WebPageProxy::DidNavigateWithNavigationData::name()) >+ { >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.didReceiveMessage(connection, decoder); >+ return; >+ } >+ >+ if (decoder.messageName() == Messages::WebPageProxy::DidCreateMainFrame::name()) { >+ IPC::handleMessage<Messages::WebPageProxy::DidCreateMainFrame>(decoder, this, &ProvisionalPageProxy::didCreateMainFrame); >+ return; >+ } >+ >+ if (decoder.messageName() == Messages::WebPageProxy::DidStartProvisionalLoadForFrame::name()) { >+ IPC::handleMessage<Messages::WebPageProxy::DidStartProvisionalLoadForFrame>(decoder, this, &ProvisionalPageProxy::didStartProvisionalLoadForFrame); >+ return; >+ } >+ >+ if (decoder.messageName() == Messages::WebPageProxy::DidFailProvisionalLoadForFrame::name()) { >+ IPC::handleMessage<Messages::WebPageProxy::DidFailProvisionalLoadForFrame>(decoder, this, &ProvisionalPageProxy::didFailProvisionalLoadForFrame); >+ return; >+ } >+ >+ if (decoder.messageName() == Messages::WebPageProxy::DidCommitLoadForFrame::name()) { >+ IPC::handleMessage<Messages::WebPageProxy::DidCommitLoadForFrame>(decoder, this, &ProvisionalPageProxy::didCommitLoadForFrame); >+ return; >+ } >+ >+ LOG(ProcessSwapping, "Unhandled message %s::%s from provisional process", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data()); >+} >+ >+void ProvisionalPageProxy::didReceiveSyncMessage(IPC::Connection& connection, IPC::Decoder& decoder, std::unique_ptr<IPC::Encoder>& encoder) >+{ >+ if (decoder.messageName() == Messages::WebPageProxy::BackForwardItemAtIndex::name() || decoder.messageName() == Messages::WebPageProxy::BackForwardGoToItem::name()) { >+ auto pageProcessOverride = m_page.temporarilyOverrideProcess(m_process); >+ m_page.didReceiveSyncMessage(connection, decoder, encoder); >+ return; >+ } >+ >+ LOG(ProcessSwapping, "Unhandled sync message %s::%s from provisional process", decoder.messageReceiverName().toString().data(), decoder.messageName().toString().data()); >+} >+ >+} // namespace WebKit >diff --git a/Source/WebKit/UIProcess/ProvisionalPageProxy.h b/Source/WebKit/UIProcess/ProvisionalPageProxy.h >new file mode 100644 >index 0000000000000000000000000000000000000000..8a0f71df8cb4c7624251e41dc93ace1836491c3e >--- /dev/null >+++ b/Source/WebKit/UIProcess/ProvisionalPageProxy.h >@@ -0,0 +1,95 @@ >+/* >+ * Copyright (C) 2019 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "MessageReceiver.h" >+#include <wtf/WeakPtr.h> >+ >+namespace WebCore { >+class ResourceRequest; >+} >+ >+namespace WebKit { >+ >+class DrawingAreaProxy; >+class SuspendedPageProxy; >+class WebFrameProxy; >+class WebPageProxy; >+class WebProcessProxy; >+ >+class ProvisionalPageProxy : public IPC::MessageReceiver, public CanMakeWeakPtr<ProvisionalPageProxy> { >+ WTF_MAKE_FAST_ALLOCATED; >+public: >+ ProvisionalPageProxy(WebPageProxy&, Ref<WebProcessProxy>&&, std::unique_ptr<SuspendedPageProxy>, uint64_t navigationID, bool isServerRedirect, const WebCore::ResourceRequest&, ProcessSwapRequestedByClient); >+ ~ProvisionalPageProxy(); >+ >+ WebPageProxy& page() { return m_page; } >+ WebFrameProxy* mainFrame() const { return m_mainFrame.get(); } >+ WebProcessProxy& process() { return m_process.get(); } >+ ProcessSwapRequestedByClient processSwapRequestedByClient() const { return m_processSwapRequestedByClient; } >+ uint64_t navigationID() const { return m_navigationID; } >+ >+ DrawingAreaProxy* drawingArea() const { return m_drawingArea.get(); } >+ std::unique_ptr<DrawingAreaProxy> takeDrawingArea(); >+ >+ void loadDataWithNavigation(API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, Optional<WebsitePoliciesData>&& = WTF::nullopt); >+ void loadRequestWithNavigation(API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, Optional<WebsitePoliciesData>&& = WTF::nullopt); >+ void goToBackForwardItem(API::Navigation&, WebBackForwardListItem&, Optional<WebsitePoliciesData>&&); >+ void cancel(); >+ >+ void processDidFinishLaunching(); >+ void processDidTerminate(); >+ >+private: >+ // IPC::MessageReceiver >+ void didReceiveMessage(IPC::Connection&, IPC::Decoder&) final; >+ void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) final; >+ >+ void didCreateMainFrame(uint64_t frameID); >+ void didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, URL&&, URL&& unreachableURL, const UserData&); >+ void didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo&, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData&); >+ void didFailProvisionalLoadForFrame(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const WebCore::ResourceError&, const UserData&); >+ >+ void initializeWebPage(); >+ void finishInitializingWebPageAfterProcessLaunch(); >+ >+ WebPageProxy& m_page; >+ Ref<WebProcessProxy> m_process; >+ std::unique_ptr<DrawingAreaProxy> m_drawingArea; >+ RefPtr<WebFrameProxy> m_mainFrame; >+ uint64_t m_navigationID; >+ bool m_isServerRedirect; >+ WebCore::ResourceRequest m_request; >+ ProcessSwapRequestedByClient m_processSwapRequestedByClient; >+ bool m_wasCommitted { false }; >+ URL m_provisionalLoadURL; >+ >+#if PLATFORM(IOS_FAMILY) >+ ProcessThrottler::BackgroundActivityToken m_suspensionToken; >+#endif >+}; >+ >+} // namespace WebKit >diff --git a/Source/WebKit/UIProcess/SuspendedPageProxy.cpp b/Source/WebKit/UIProcess/SuspendedPageProxy.cpp >index f198a81533f76b2e8e2bf71d4a3b9d2740c95078..ff76d9f7f97ac6fa4fbb302f646661d1678ae257 100644 >--- a/Source/WebKit/UIProcess/SuspendedPageProxy.cpp >+++ b/Source/WebKit/UIProcess/SuspendedPageProxy.cpp >@@ -100,7 +100,9 @@ SuspendedPageProxy::~SuspendedPageProxy() > // If the suspended page was not consumed before getting destroyed, then close the corresponding page > // on the WebProcess side. > m_process->send(Messages::WebPage::Close(), m_page.pageID()); >- m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); >+ >+ if (m_suspensionState == SuspensionState::Suspending) >+ m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); > > // We call maybeShutDown() asynchronously since the SuspendedPage is currently being removed from the WebProcessPool > // and we want to avoid re-entering WebProcessPool methods. >@@ -134,7 +136,6 @@ void SuspendedPageProxy::unsuspend() > ASSERT(m_suspensionState == SuspensionState::Suspended); > > m_suspensionState = SuspensionState::Resumed; >- m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); > m_process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID()); > } > >@@ -151,6 +152,8 @@ void SuspendedPageProxy::didProcessRequestToSuspend(SuspensionState newSuspensio > m_suspensionToken = nullptr; > #endif > >+ m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); >+ > if (m_readyToUnsuspendHandler) > m_readyToUnsuspendHandler(this); > } >diff --git a/Source/WebKit/UIProcess/WebFrameProxy.cpp b/Source/WebKit/UIProcess/WebFrameProxy.cpp >index c77a26b7427c31c828e2eaa221f8070b77add262..53c7196c2aa0a33d220758190cd4bd95a5cd025f 100644 >--- a/Source/WebKit/UIProcess/WebFrameProxy.cpp >+++ b/Source/WebKit/UIProcess/WebFrameProxy.cpp >@@ -27,6 +27,7 @@ > #include "WebFrameProxy.h" > > #include "APINavigation.h" >+#include "ProvisionalPageProxy.h" > #include "WebCertificateInfo.h" > #include "WebFramePolicyListenerProxy.h" > #include "WebPageMessages.h" >@@ -74,7 +75,7 @@ bool WebFrameProxy::isMainFrame() const > if (!m_page) > return false; > >- return this == m_page->mainFrame(); >+ return this == m_page->mainFrame() || (m_page->provisionalPageProxy() && this == m_page->provisionalPageProxy()->mainFrame()); > } > > void WebFrameProxy::loadURL(const URL& url) >diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp >index c8ab70333b4039a8779c4ca3f31e1907563a3369..267e5cd3fcd028b4e2f92cd8b900a1797e5e07ff 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.cpp >+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp >@@ -77,6 +77,7 @@ > #include "PluginInformation.h" > #include "PluginProcessManager.h" > #include "PrintInfo.h" >+#include "ProvisionalPageProxy.h" > #include "SafeBrowsingWarning.h" > #include "ShareSheetCallbackID.h" > #include "SharedBufferDataReference.h" >@@ -545,6 +546,13 @@ PAL::SessionID WebPageProxy::sessionID() const > return m_websiteDataStore->sessionID(); > } > >+DrawingAreaProxy* WebPageProxy::drawingArea() const >+{ >+ if (m_provisionalPage && m_process.ptr() == &m_provisionalPage->process() && m_provisionalPage->drawingArea()) >+ return m_provisionalPage->drawingArea(); >+ return m_drawingArea.get(); >+} >+ > void WebPageProxy::changeWebsiteDataStore(WebsiteDataStore& websiteDataStore) > { > m_process->processPool().pageEndUsingWebsiteDataStore(*this); >@@ -768,38 +776,26 @@ bool WebPageProxy::suspendCurrentPageIfPossible(API::Navigation& navigation, Opt > return true; > } > >-void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, std::unique_ptr<SuspendedPageProxy>&& destinationSuspendedPage, IsSwapFromSuspended isSwapFromSuspended) >+void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, std::unique_ptr<DrawingAreaProxy>&& drawingArea, RefPtr<WebFrameProxy>&& mainFrame) > { > ASSERT(!m_isClosed); > RELEASE_LOG_IF_ALLOWED(Loading, "swapToWebProcess: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID); > > m_process = WTFMove(process); >+ ASSERT(!m_drawingArea); >+ setDrawingArea(WTFMove(drawingArea)); >+ ASSERT(!m_mainFrame); >+ m_mainFrame = WTFMove(mainFrame); > m_isValid = true; > >- // If we are reattaching to a SuspendedPage, then the WebProcess' WebPage already exists and >- // WebPageProxy::didCreateMainFrame() will not be called to initialize m_mainFrame. In such >- // case, we need to initialize m_mainFrame to reflect the fact the the WebProcess' WebPage >- // already exists and already has a main frame. >- if (destinationSuspendedPage) { >- if (!destinationSuspendedPage->failedToSuspend()) { >- ASSERT(!m_mainFrame); >- ASSERT(&destinationSuspendedPage->process() == m_process.ptr()); >- destinationSuspendedPage->unsuspend(); >- m_mainFrame = WebFrameProxy::create(*this, destinationSuspendedPage->mainFrameID()); >- m_process->frameCreated(destinationSuspendedPage->mainFrameID(), *m_mainFrame); >- } else { >- // We failed to suspend the page so destroy it now and merely reuse its WebContent process. >- destinationSuspendedPage = nullptr; >- } >- } >- > m_process->addExistingWebPage(*this, m_pageID, WebProcessProxy::BeginsUsingDataStore::No); > m_process->addMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID, *this); > >- finishAttachingToWebProcess(isSwapFromSuspended); >+ // No need to initialize the WebPage since it was created when we created the ProvisionalPageProxy. >+ finishAttachingToWebProcess(ShouldInitializeWebPage::No); > } > >-void WebPageProxy::finishAttachingToWebProcess(IsSwapFromSuspended isSwapFromSuspended) >+void WebPageProxy::finishAttachingToWebProcess(ShouldInitializeWebPage shouldInitializePage) > { > ASSERT(m_process->state() != ChildProcessProxy::State::Terminated); > >@@ -835,7 +831,8 @@ void WebPageProxy::finishAttachingToWebProcess(IsSwapFromSuspended isSwapFromSus > m_editableImageController = std::make_unique<EditableImageController>(*this); > #endif > >- initializeWebPage(isSwapFromSuspended); >+ if (shouldInitializePage == ShouldInitializeWebPage::Yes) >+ initializeWebPage(); > > m_inspector->updateForNewPageProcess(this); > >@@ -900,12 +897,11 @@ RefPtr<API::Navigation> WebPageProxy::reattachToWebProcessWithItem(WebBackForwar > return WTFMove(navigation); > } > >-void WebPageProxy::initializeWebPage(IsSwapFromSuspended isSwapFromSuspended) >+void WebPageProxy::setDrawingArea(std::unique_ptr<DrawingAreaProxy>&& drawingArea) > { >- ASSERT(isValid()); >- >- m_drawingArea = pageClient().createDrawingAreaProxy(); >- ASSERT(m_drawingArea); >+ m_drawingArea = WTFMove(drawingArea); >+ if (!m_drawingArea) >+ return; > > #if ENABLE(ASYNC_SCROLLING) && PLATFORM(COCOA) > if (m_drawingArea->type() == DrawingAreaTypeRemoteLayerTree) { >@@ -916,15 +912,16 @@ void WebPageProxy::initializeWebPage(IsSwapFromSuspended isSwapFromSuspended) > #endif > } > #endif >+} > >- auto parameters = creationParameters(); >- parameters.isSwapFromSuspended = isSwapFromSuspended == IsSwapFromSuspended::Yes; >+void WebPageProxy::initializeWebPage() >+{ >+ ASSERT(isValid()); > >-#if ENABLE(SERVICE_WORKER) >- parameters.hasRegisteredServiceWorkers = process().processPool().mayHaveRegisteredServiceWorkers(m_websiteDataStore); >-#endif >+ setDrawingArea(pageClient().createDrawingAreaProxy()); >+ ASSERT(m_drawingArea); > >- process().send(Messages::WebProcess::CreateWebPage(m_pageID, parameters), 0); >+ process().send(Messages::WebProcess::CreateWebPage(m_pageID, creationParameters()), 0); > > m_needsToFinishInitializingWebPageAfterProcessLaunch = true; > finishInitializingWebPageAfterProcessLaunch(); >@@ -1076,7 +1073,8 @@ void WebPageProxy::loadRequestWithNavigation(API::Navigation& navigation, Resour > auto transaction = m_pageLoadState.transaction(); > > auto url = request.url(); >- m_pageLoadState.setPendingAPIRequestURL(transaction, url); >+ if (shouldTreatAsContinuingLoad != ShouldTreatAsContinuingLoad::Yes) >+ m_pageLoadState.setPendingAPIRequestURL(transaction, url); > > if (!isValid()) > reattachToWebProcess(); >@@ -1294,6 +1292,10 @@ void WebPageProxy::stopLoading() > } > > m_process->send(Messages::WebPage::StopLoading(), m_pageID); >+ if (m_provisionalPage) { >+ m_provisionalPage->cancel(); >+ m_provisionalPage = nullptr; >+ } > m_process->responsivenessTimer().start(); > } > >@@ -2698,7 +2700,7 @@ void WebPageProxy::receivedNavigationPolicyDecision(WebPolicyAction policyAction > } > > if (processForNavigation.ptr() != &process()) { >- policyAction = isPageOpenedByDOMShowingInitialEmptyDocument() ? WebPolicyAction::Ignore : WebPolicyAction::Suspend; >+ policyAction = WebPolicyAction::Ignore; > RELEASE_LOG_IF_ALLOWED(ProcessSwapping, "decidePolicyForNavigationAction, swapping process %i with process %i for navigation, reason: %{public}s", processIdentifier(), processForNavigation->processIdentifier(), reason.utf8().data()); > LOG(ProcessSwapping, "(ProcessSwapping) Switching from process %i to new process (%i) for navigation %" PRIu64 " '%s'", processIdentifier(), processForNavigation->processIdentifier(), navigation->navigationID(), navigation->loggingString()); > } else >@@ -2707,8 +2709,14 @@ void WebPageProxy::receivedNavigationPolicyDecision(WebPolicyAction policyAction > bool shouldProcessSwap = processForNavigation.ptr() != &process(); > receivedPolicyDecision(policyAction, navigation.ptr(), shouldProcessSwap ? WTF::nullopt : WTFMove(data), WTFMove(sender)); > >- if (shouldProcessSwap) >- continueNavigationInNewProcess(navigation, destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr, WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data)); >+ if (!shouldProcessSwap) >+ return; >+ >+ auto suspendedPage = destinationSuspendedPage ? process().processPool().takeSuspendedPage(*destinationSuspendedPage) : nullptr; >+ if (suspendedPage && suspendedPage->failedToSuspend()) >+ suspendedPage = nullptr; >+ >+ continueNavigationInNewProcess(navigation, WTFMove(suspendedPage), WTFMove(processForNavigation), processSwapRequestedByClient, WTFMove(data)); > }); > } > >@@ -2744,24 +2752,45 @@ void WebPageProxy::receivedPolicyDecision(WebPolicyAction action, API::Navigatio > sender->send(action, navigation ? navigation->navigationID() : 0, downloadID, WTFMove(websitePolicies)); > } > >-void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPageProxy, Ref<WebProcessProxy>&& process, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies) >+void WebPageProxy::commitProvisionalPage(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo& certificateInfo, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData& userData) > { >- RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID); >- LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString()); >+ ASSERT(m_provisionalPage); >+ RELEASE_LOG_IF_ALLOWED(Loading, "commitProvisionalPage: previousPID = %i, newPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_provisionalPage->process().processIdentifier(), m_pageID); > >- Ref<WebProcessProxy> previousProcess = m_process.copyRef(); > Optional<uint64_t> mainFrameIDInPreviousProcess = m_mainFrame ? makeOptional(m_mainFrame->frameID()) : WTF::nullopt; >- auto mainFrameURL = m_mainFrame ? m_mainFrame->url() : URL(); > >- ASSERT(m_process.ptr() != process.ptr()); >+ ASSERT(m_process.ptr() != &m_provisionalPage->process()); > > processDidTerminate(ProcessTerminationReason::NavigationSwap); > > m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); >- bool didSuspendPreviousPage = suspendCurrentPageIfPossible(navigation, mainFrameIDInPreviousProcess, processSwapRequestedByClient); >+ auto* navigation = navigationState().navigation(m_provisionalPage->navigationID()); >+ bool didSuspendPreviousPage = navigation ? suspendCurrentPageIfPossible(*navigation, mainFrameIDInPreviousProcess, m_provisionalPage->processSwapRequestedByClient()) : false; > m_process->removeWebPage(*this, m_pageID, WebProcessProxy::EndsUsingDataStore::No); > >- swapToWebProcess(WTFMove(process), WTFMove(suspendedPageProxy), didSuspendPreviousPage ? IsSwapFromSuspended::Yes : IsSwapFromSuspended::No); >+ // There is no way we'll be able to return to the page in the previous page so close it. >+ if (!didSuspendPreviousPage) >+ m_process->send(Messages::WebPage::Close(), pageID()); >+ >+ swapToWebProcess(m_provisionalPage->process(), m_provisionalPage->takeDrawingArea(), m_provisionalPage->mainFrame()); >+ >+ didCommitLoadForFrame(frameID, navigationID, mimeType, frameHasCustomContentProvider, frameLoadType, certificateInfo, containsPluginDocument, forcedHasInsecureContent, userData); >+ >+ m_provisionalPage = nullptr; >+} >+ >+void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, std::unique_ptr<SuspendedPageProxy>&& suspendedPageProxy, Ref<WebProcessProxy>&& newProcess, ProcessSwapRequestedByClient processSwapRequestedByClient, Optional<WebsitePoliciesData>&& websitePolicies) >+{ >+ RELEASE_LOG_IF_ALLOWED(Loading, "continueNavigationInNewProcess: webPID = %i, pageID = %" PRIu64, m_process->processIdentifier(), m_pageID); >+ LOG(Loading, "Continuing navigation %" PRIu64 " '%s' in a new web process", navigation.navigationID(), navigation.loggingString()); >+ >+ if (m_provisionalPage) { >+ if (m_provisionalPage->navigationID() != navigation.navigationID()) >+ m_provisionalPage->cancel(); >+ m_provisionalPage = nullptr; >+ } >+ >+ m_provisionalPage = std::make_unique<ProvisionalPageProxy>(*this, newProcess.copyRef(), WTFMove(suspendedPageProxy), navigation.navigationID(), navigation.currentRequestIsRedirect(), navigation.currentRequest(), processSwapRequestedByClient); > > if (auto* item = navigation.targetItem()) { > LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data()); >@@ -2769,67 +2798,22 @@ void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, s > auto transaction = m_pageLoadState.transaction(); > m_pageLoadState.setPendingAPIRequestURL(transaction, item->url()); > >- auto itemStates = m_backForwardList->filteredItemStates([this, targetItem = item](WebBackForwardListItem& item) { >- if (auto* page = item.suspendedPage()) { >- if (&page->process() == m_process.ptr()) >- return false; >- } >- return &item != targetItem; >- }); >- m_process->send(Messages::WebPage::UpdateBackForwardListForReattach(WTFMove(itemStates)), m_pageID); >- m_process->send(Messages::WebPage::GoToBackForwardItem(navigation.navigationID(), item->itemID(), *navigation.backForwardFrameLoadType(), ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)), m_pageID); >- m_process->responsivenessTimer().start(); >- >+ m_provisionalPage->goToBackForwardItem(navigation, *item, WTFMove(websitePolicies)); > return; > } > > if (m_backForwardList->currentItem() && (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes)) { > // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update > // it instead of creating a new one. >- m_process->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_pageID); >+ newProcess->send(Messages::WebPage::SetCurrentHistoryItemForReattach(m_backForwardList->currentItem()->itemState()), m_pageID); > } > > // FIXME: Work out timing of responding with the last policy delegate, etc > ASSERT(!navigation.currentRequest().isEmpty()); > if (auto& substituteData = navigation.substituteData()) >- loadDataWithNavigation(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)); >+ m_provisionalPage->loadDataWithNavigation(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get(), WTFMove(websitePolicies)); > else >- loadRequestWithNavigation(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, ShouldTreatAsContinuingLoad::Yes, WTFMove(websitePolicies)); >- >- ASSERT(!m_mainFrame); >- m_mainFrameCreationHandler = [this, weakThis = makeWeakPtr(*this), navigationID = navigation.navigationID(), request = navigation.currentRequest(), mainFrameURL, isServerRedirect = navigation.currentRequestIsRedirect()]() mutable { >- if (!weakThis) >- return; >- >- ASSERT(m_mainFrame); >- // This navigation was destroyed so no need to notify of redirect. >- if (!navigationState().navigation(navigationID)) >- return; >- >- // Restore the main frame's committed URL as some clients may rely on it until the next load is committed. >- m_mainFrame->frameLoadState().setURL(mainFrameURL); >- >- // Normally, notification of a server redirect comes from the WebContent process. >- // If we are process swapping in response to a server redirect then that notification will not come from the new WebContent process. >- // In this case we have the UIProcess synthesize the redirect notification at the appropriate time. >- if (isServerRedirect) { >- m_mainFrame->frameLoadState().didStartProvisionalLoad(request.url()); >- didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), navigationID, WTFMove(request), { }); >- } >- }; >- >- if (!m_process->processPool().configuration().processSwapsOnWindowOpenWithOpener() || !isPageOpenedByDOMShowingInitialEmptyDocument() || !mainFrameIDInPreviousProcess) { >- // There is no way we'll be able to return to the page in the previous page so close it. >- if (!didSuspendPreviousPage) >- previousProcess->send(Messages::WebPage::Close(), m_pageID); >- return; >- } >- >- m_mainFrameWindowCreationHandler = [this, previousProcess = WTFMove(previousProcess), mainFrameIDInPreviousProcess = *mainFrameIDInPreviousProcess](const GlobalWindowIdentifier& windowIdentifier) { >- ASSERT(m_mainFrame); >- GlobalFrameIdentifier navigatedFrameIdentifierInNewProcess { pageID(), m_mainFrame->frameID() }; >- previousProcess->send(Messages::WebPage::FrameBecameRemote(mainFrameIDInPreviousProcess, navigatedFrameIdentifierInNewProcess, windowIdentifier), pageID()); >- }; >+ m_provisionalPage->loadRequestWithNavigation(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, WTFMove(websitePolicies)); > } > > bool WebPageProxy::isPageOpenedByDOMShowingInitialEmptyDocument() const >@@ -3694,11 +3678,6 @@ void WebPageProxy::didCreateMainFrame(uint64_t frameID) > > // Add the frame to the process wide map. > m_process->frameCreated(frameID, *m_mainFrame); >- >- if (m_mainFrameCreationHandler) { >- m_mainFrameCreationHandler(); >- m_mainFrameCreationHandler = nullptr; >- } > } > > void WebPageProxy::didCreateSubframe(uint64_t frameID) >@@ -3723,10 +3702,6 @@ void WebPageProxy::didCreateSubframe(uint64_t frameID) > > void WebPageProxy::didCreateWindow(uint64_t frameID, GlobalWindowIdentifier&& windowIdentifier) > { >- if (m_mainFrame && m_mainFrame->frameID() == frameID) { >- if (auto mainFrameWindowCreationHandler = WTFMove(m_mainFrameWindowCreationHandler)) >- mainFrameWindowCreationHandler(windowIdentifier); >- } > } > > double WebPageProxy::estimatedProgress() const >@@ -3779,6 +3754,10 @@ void WebPageProxy::didDestroyNavigation(uint64_t navigationID) > { > PageClientProtector protector(pageClient()); > >+ // On process-swap, the previous process tries to destroy the navigation but the provisional process is actually taking over the navigation. >+ if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID) >+ return; >+ > // FIXME: Message check the navigationID. > m_navigationState->didDestroyNavigation(navigationID); > } >@@ -3796,14 +3775,6 @@ void WebPageProxy::didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t na > if (frame->isMainFrame() && navigationID) > navigation = navigationState().navigation(navigationID); > >- // If this seemingly new load is actually continuing a server redirect for a previous navigation in a new process, >- // then we ignore this notification. >- if (navigation && navigation->currentRequestIsRedirect()) { >- auto navigationProcessIdentifier = navigation->currentRequestProcessIdentifier(); >- if (navigationProcessIdentifier && *navigationProcessIdentifier != m_process->coreProcessIdentifier()) >- return; >- } >- > LOG(Loading, "WebPageProxy %" PRIu64 " in process pid %i didStartProvisionalLoadForFrame to frameID %" PRIu64 ", navigationID %" PRIu64 ", url %s", m_pageID, m_process->processIdentifier(), frameID, navigationID, url.string().utf8().data()); > RELEASE_LOG_IF_ALLOWED(Loading, "didStartProvisionalLoadForFrame: webPID = %i, pageID = %" PRIu64 ", frameID = %" PRIu64, m_process->processIdentifier(), m_pageID, frameID); > >@@ -3911,6 +3882,11 @@ void WebPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const Securi > > PageClientProtector protector(pageClient()); > >+ if (m_provisionalPage && m_provisionalPage->navigationID() == navigationID && &m_provisionalPage->process() != m_process.ptr()) { >+ // The load did not fail, it merely happening in a new provisional process. >+ return; >+ } >+ > WebFrameProxy* frame = m_process->webFrame(frameID); > MESSAGE_CHECK(frame); > >@@ -3949,6 +3925,10 @@ void WebPageProxy::didFailProvisionalLoadForFrame(uint64_t frameID, const Securi > } > > m_failingProvisionalLoadURL = { }; >+ >+ // If the provisional page's load fails then we destroy the provisional page. >+ if (m_provisionalPage && m_provisionalPage->mainFrame() == frame) >+ m_provisionalPage = nullptr; > } > > void WebPageProxy::clearLoadDependentCallbacks() >@@ -4340,8 +4320,8 @@ void WebPageProxy::decidePolicyForNavigationActionAsync(uint64_t frameID, WebCor > auto* frame = m_process->webFrame(frameID); > MESSAGE_CHECK(frame); > >- decidePolicyForNavigationAction(*frame, WTFMove(frameSecurityOrigin), navigationID, WTFMove(navigationActionData), WTFMove(frameInfoData), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, PolicyDecisionSender::create([this, protectedThis = makeRef(*this), frameID, listenerID] (auto... args) { >- m_process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID); >+ decidePolicyForNavigationAction(*frame, WTFMove(frameSecurityOrigin), navigationID, WTFMove(navigationActionData), WTFMove(frameInfoData), originatingPageID, originalRequest, WTFMove(request), WTFMove(requestBody), WTFMove(redirectResponse), userData, PolicyDecisionSender::create([this, protectedThis = makeRef(*this), frameID, listenerID, process = m_process.copyRef()] (auto... args) { >+ process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID); > })); > } > >@@ -4575,12 +4555,12 @@ void WebPageProxy::decidePolicyForResponse(uint64_t frameID, const SecurityOrigi > MESSAGE_CHECK_URL(response.url()); > > RefPtr<API::Navigation> navigation = navigationID ? m_navigationState->navigation(navigationID) : nullptr; >- auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), frameID, listenerID, navigation = WTFMove(navigation)] (WebPolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning) mutable { >+ auto listener = makeRef(frame->setUpPolicyListenerProxy([this, protectedThis = makeRef(*this), frameID, listenerID, navigation = WTFMove(navigation), process = m_process.copyRef()] (WebPolicyAction policyAction, API::WebsitePolicies*, ProcessSwapRequestedByClient processSwapRequestedByClient, RefPtr<SafeBrowsingWarning>&& safeBrowsingWarning) mutable { > // FIXME: Assert the API::WebsitePolicies* is nullptr here once clients of WKFramePolicyListenerUseWithPolicies go away. > RELEASE_ASSERT(processSwapRequestedByClient == ProcessSwapRequestedByClient::No); > ASSERT_UNUSED(safeBrowsingWarning, !safeBrowsingWarning); >- receivedPolicyDecision(policyAction, navigation.get(), WTF::nullopt, PolicyDecisionSender::create([this, protectedThis = WTFMove(protectedThis), frameID, listenerID] (auto... args) { >- m_process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID); >+ receivedPolicyDecision(policyAction, navigation.get(), WTF::nullopt, PolicyDecisionSender::create([this, protectedThis = WTFMove(protectedThis), frameID, listenerID, process = WTFMove(process)] (auto... args) { >+ process->send(Messages::WebPage::DidReceivePolicyDecision(frameID, listenerID, args...), m_pageID); > })); > }, ShouldExpectSafeBrowsingResult::No)); > >@@ -6400,6 +6380,13 @@ void WebPageProxy::processDidTerminate(ProcessTerminationReason reason) > stopAllURLSchemeTasks(); > } > >+void WebPageProxy::provisionalProcessDidTerminate() >+{ >+ ASSERT(m_provisionalPage); >+ m_provisionalPage->cancel(); >+ m_provisionalPage = nullptr; >+} >+ > static bool shouldReloadAfterProcessTermination(ProcessTerminationReason reason) > { > switch (reason) { >@@ -6487,8 +6474,6 @@ void WebPageProxy::processWillBecomeForeground() > void WebPageProxy::resetState(ResetStateReason resetStateReason) > { > m_mainFrame = nullptr; >- m_mainFrameCreationHandler = nullptr; >- m_mainFrameWindowCreationHandler = nullptr; > > #if PLATFORM(COCOA) > m_scrollingPerformanceData = nullptr; >@@ -6779,6 +6764,10 @@ WebPageCreationParameters WebPageProxy::creationParameters() > parameters.applicationManifest = m_configuration->applicationManifest() ? Optional<WebCore::ApplicationManifest>(m_configuration->applicationManifest()->applicationManifest()) : WTF::nullopt; > #endif > >+#if ENABLE(SERVICE_WORKER) >+ parameters.hasRegisteredServiceWorkers = process().processPool().mayHaveRegisteredServiceWorkers(m_websiteDataStore); >+#endif >+ > parameters.needsFontAttributes = m_needsFontAttributes; > > m_process->addWebUserContentControllerProxy(m_userContentController, parameters); >@@ -8540,6 +8529,21 @@ void WebPageProxy::simulateDeviceOrientationChange(double alpha, double beta, do > m_process->send(Messages::WebPage::SimulateDeviceOrientationChange(alpha, beta, gamma), m_pageID); > } > >+WebPageProxy::PageProcessOverride::PageProcessOverride(WebPageProxy& page, WebProcessProxy& newProcess) >+ : m_page(&page) >+ , m_previousProcess(page.process()) >+{ >+ page.m_process = newProcess; >+} >+ >+WebPageProxy::PageProcessOverride::PageProcessOverride(PageProcessOverride&&) = default; >+ >+WebPageProxy::PageProcessOverride::~PageProcessOverride() >+{ >+ if (m_page) >+ m_page->m_process = WTFMove(m_previousProcess); >+} >+ > #if ENABLE(DATA_DETECTION) > > void WebPageProxy::detectDataInAllFrames(WebCore::DataDetectorTypes types, CompletionHandler<void(const DataDetectionResult&)>&& completionHandler) >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index de98694aa37db3c7f2ce27cc829a9200211de10d..4582f0a17fe11781673bebec65cfd2b0e45ff802 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -225,6 +225,7 @@ class NativeWebKeyboardEvent; > class NativeWebMouseEvent; > class NativeWebWheelEvent; > class PageClient; >+class ProvisionalPageProxy; > class RemoteLayerTreeHost; > class RemoteLayerTreeScrollingPerformanceData; > class RemoteLayerTreeTransaction; >@@ -356,7 +357,7 @@ public: > WebFrameProxy* focusedFrame() const { return m_focusedFrame.get(); } > WebFrameProxy* frameSetLargestFrame() const { return m_frameSetLargestFrame.get(); } > >- DrawingAreaProxy* drawingArea() const { return m_drawingArea.get(); } >+ DrawingAreaProxy* drawingArea() const; > > WebNavigationState& navigationState() { return *m_navigationState.get(); } > >@@ -379,6 +380,7 @@ public: > > bool addsVisitedLinks() const { return m_addsVisitedLinks; } > void setAddsVisitedLinks(bool addsVisitedLinks) { m_addsVisitedLinks = addsVisitedLinks; } >+ VisitedLinkStore& visitedLinkStore() { return m_visitedLinkStore; } > > void exitFullscreenImmediately(); > void fullscreenMayReturnToInline(); >@@ -458,8 +460,8 @@ public: > API::IconLoadingClient& iconLoadingClient() { return *m_iconLoadingClient; } > void setIconLoadingClient(std::unique_ptr<API::IconLoadingClient>&&); > >- enum class IsSwapFromSuspended { No, Yes }; >- void initializeWebPage(IsSwapFromSuspended = IsSwapFromSuspended::No); >+ void initializeWebPage(); >+ void setDrawingArea(std::unique_ptr<DrawingAreaProxy>&&); > > WeakPtr<SecKeyProxyStore> secKeyProxyStore(const WebCore::AuthenticationChallenge&); > >@@ -997,6 +999,7 @@ public: > void processDidBecomeUnresponsive(); > void processDidBecomeResponsive(); > void processDidTerminate(ProcessTerminationReason); >+ void provisionalProcessDidTerminate(); > void dispatchProcessDidTerminate(ProcessTerminationReason); > void willChangeProcessIsResponsive(); > void didChangeProcessIsResponsive(); >@@ -1025,6 +1028,19 @@ public: > WebProcessProxy& process() { return m_process; } > ProcessID processIdentifier() const; > >+ class PageProcessOverride { >+ public: >+ PageProcessOverride(WebPageProxy&, WebProcessProxy& newProcess); >+ PageProcessOverride(PageProcessOverride&&); >+ ~PageProcessOverride(); >+ >+ private: >+ RefPtr<WebPageProxy> m_page; >+ Ref<WebProcessProxy> m_previousProcess; >+ }; >+ >+ PageProcessOverride temporarilyOverrideProcess(WebProcessProxy& newProcess) { return PageProcessOverride(*this, newProcess); } >+ > WebPreferences& preferences() { return m_preferences; } > void setPreferences(WebPreferences&); > >@@ -1415,6 +1431,21 @@ public: > EditableImageController& editableImageController() { return *m_editableImageController; } > #endif > >+ ProvisionalPageProxy* provisionalPageProxy() const { return m_provisionalPage.get(); } >+ void commitProvisionalPage(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo&, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData&); >+ >+ void didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, URL&&, URL&& unreachableURL, const UserData&); >+ void didFailProvisionalLoadForFrame(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const WebCore::ResourceError&, const UserData&); >+ void didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest&&, const UserData&); >+ >+ void loadDataWithNavigation(API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& = WTF::nullopt); >+ void loadRequestWithNavigation(API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& = WTF::nullopt); >+ >+ // IPC::MessageReceiver >+ // Implemented in generated WebPageProxyMessageReceiver.cpp >+ void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override; >+ void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override; >+ > private: > WebPageProxy(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&); > void platformInitialize(); >@@ -1439,12 +1470,6 @@ private: > > void setUserAgent(String&&); > >- // IPC::MessageReceiver >- // Implemented in generated WebPageProxyMessageReceiver.cpp >- void didReceiveMessage(IPC::Connection&, IPC::Decoder&) override; >- void didReceiveSyncMessage(IPC::Connection&, IPC::Decoder&, std::unique_ptr<IPC::Encoder>&) override; >- >- > // IPC::MessageSender > bool sendMessage(std::unique_ptr<IPC::Encoder>, OptionSet<IPC::SendOption>) override; > IPC::Connection* messageSenderConnection() override; >@@ -1466,12 +1491,9 @@ private: > void didCreateSubframe(uint64_t frameID); > void didCreateWindow(uint64_t frameID, WebCore::GlobalWindowIdentifier&&); > >- void didStartProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, URL&&, URL&& unreachableURL, const UserData&); >- void didReceiveServerRedirectForProvisionalLoadForFrame(uint64_t frameID, uint64_t navigationID, WebCore::ResourceRequest&&, const UserData&); > void willPerformClientRedirectForFrame(uint64_t frameID, const String& url, double delay, WebCore::LockBackForwardList); > void didCancelClientRedirectForFrame(uint64_t frameID); > void didChangeProvisionalURLForFrame(uint64_t frameID, uint64_t navigationID, URL&&); >- void didFailProvisionalLoadForFrame(uint64_t frameID, const WebCore::SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, const String& provisionalURL, const WebCore::ResourceError&, const UserData&); > void didCommitLoadForFrame(uint64_t frameID, uint64_t navigationID, const String& mimeType, bool frameHasCustomContentProvider, uint32_t frameLoadType, const WebCore::CertificateInfo&, bool containsPluginDocument, Optional<WebCore::HasInsecureContent> forcedHasInsecureContent, const UserData&); > void didFinishDocumentLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData&); > void didFinishLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData&); >@@ -1575,18 +1597,16 @@ private: > void setCanShortCircuitHorizontalWheelEvents(bool canShortCircuitHorizontalWheelEvents) { m_canShortCircuitHorizontalWheelEvents = canShortCircuitHorizontalWheelEvents; } > > void reattachToWebProcess(); >- void swapToWebProcess(Ref<WebProcessProxy>&&, std::unique_ptr<SuspendedPageProxy>&&, IsSwapFromSuspended); >+ void swapToWebProcess(Ref<WebProcessProxy>&&, std::unique_ptr<DrawingAreaProxy>&&, RefPtr<WebFrameProxy>&& mainFrame); > void didFailToSuspendAfterProcessSwap(); > void didSuspendAfterProcessSwap(); > >- void finishAttachingToWebProcess(IsSwapFromSuspended = IsSwapFromSuspended::No); >+ enum class ShouldInitializeWebPage { No, Yes }; >+ void finishAttachingToWebProcess(ShouldInitializeWebPage = ShouldInitializeWebPage::Yes); > > RefPtr<API::Navigation> reattachToWebProcessForReload(); > RefPtr<API::Navigation> reattachToWebProcessWithItem(WebBackForwardListItem&); > >- void loadDataWithNavigation(API::Navigation&, const IPC::DataReference&, const String& MIMEType, const String& encoding, const String& baseURL, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& = WTF::nullopt); >- void loadRequestWithNavigation(API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, WebCore::ShouldTreatAsContinuingLoad, Optional<WebsitePoliciesData>&& = WTF::nullopt); >- > void requestNotificationPermission(uint64_t notificationID, const String& originString); > void showNotification(const String& title, const String& body, const String& iconURL, const String& tag, const String& lang, WebCore::NotificationDirection, const String& originString, uint64_t notificationID); > void cancelNotification(uint64_t notificationID); >@@ -1952,8 +1972,6 @@ private: > Ref<WebsiteDataStore> m_websiteDataStore; > > RefPtr<WebFrameProxy> m_mainFrame; >- Function<void()> m_mainFrameCreationHandler; >- Function<void(const WebCore::GlobalWindowIdentifier&)> m_mainFrameWindowCreationHandler; > > RefPtr<WebFrameProxy> m_focusedFrame; > RefPtr<WebFrameProxy> m_frameSetLargestFrame; >@@ -2324,6 +2342,8 @@ private: > bool m_needsFontAttributes { false }; > bool m_mayHaveUniversalFileReadSandboxExtension { false }; > >+ std::unique_ptr<ProvisionalPageProxy> m_provisionalPage; >+ > #if HAVE(PENCILKIT) > std::unique_ptr<EditableImageController> m_editableImageController; > #endif >diff --git a/Source/WebKit/UIProcess/WebProcessProxy.cpp b/Source/WebKit/UIProcess/WebProcessProxy.cpp >index db1fd58b93dff5865d13fc541b6e5d8746eb8e0a..6be9dc399e01488da678fb4568ef36b21f3c4876 100644 >--- a/Source/WebKit/UIProcess/WebProcessProxy.cpp >+++ b/Source/WebKit/UIProcess/WebProcessProxy.cpp >@@ -34,6 +34,7 @@ > #include "Logging.h" > #include "PluginInfoStore.h" > #include "PluginProcessManager.h" >+#include "ProvisionalPageProxy.h" > #include "TextChecker.h" > #include "TextCheckerState.h" > #include "UIMessagePortChannelProvider.h" >@@ -584,6 +585,15 @@ bool WebProcessProxy::fullKeyboardAccessEnabled() > } > #endif > >+bool WebProcessProxy::hasProvisionalPageWithID(uint64_t pageID) const >+{ >+ for (auto* provisionalPage : m_provisionalPages) { >+ if (provisionalPage->page().pageID() == pageID) >+ return true; >+ } >+ return false; >+} >+ > void WebProcessProxy::updateBackForwardItem(const BackForwardListItemState& itemState) > { > if (auto* item = WebBackForwardListItem::itemForID(itemState.identifier)) { >@@ -591,7 +601,7 @@ void WebProcessProxy::updateBackForwardItem(const BackForwardListItemState& item > // the back/forward items page. > // e.g. The old web process is navigating to about:blank for suspension. > // We ignore these updates. >- if (m_pageMap.contains(item->pageID())) >+ if (m_pageMap.contains(item->pageID()) || hasProvisionalPageWithID(item->pageID())) > item->setPageState(itemState.pageState); > } > } >@@ -694,6 +704,7 @@ void WebProcessProxy::processDidTerminateOrFailedToLaunch() > webConnection->didClose(); > > auto pages = copyToVectorOf<RefPtr<WebPageProxy>>(m_pageMap.values()); >+ auto provisionalPages = WTF::map(m_provisionalPages, [](auto* provisionalPage) { return makeWeakPtr(provisionalPage); }); > > shutDown(); > >@@ -708,6 +719,11 @@ void WebProcessProxy::processDidTerminateOrFailedToLaunch() > > for (auto& page : pages) > page->processDidTerminate(ProcessTerminationReason::Crash); >+ >+ for (auto& provisionalPage : provisionalPages) { >+ if (provisionalPage) >+ provisionalPage->processDidTerminate(); >+ } > } > > void WebProcessProxy::didReceiveInvalidMessage(IPC::Connection& connection, IPC::StringReference messageReceiverName, IPC::StringReference messageName) >@@ -780,6 +796,12 @@ void WebProcessProxy::didFinishLaunching(ProcessLauncher* launcher, IPC::Connect > page->processDidFinishLaunching(); > } > >+ for (auto* provisionalPage : m_provisionalPages) { >+ ASSERT(this == &provisionalPage->process()); >+ provisionalPage->processDidFinishLaunching(); >+ } >+ >+ > RELEASE_ASSERT(!m_webConnection); > m_webConnection = WebConnectionToWebProcess::create(this); > >@@ -873,7 +895,7 @@ void WebProcessProxy::maybeShutDown() > > bool WebProcessProxy::canTerminateChildProcess() > { >- if (!m_pageMap.isEmpty() || m_processPool->hasSuspendedPageFor(*this)) >+ if (!m_pageMap.isEmpty() || m_processPool->hasSuspendedPageFor(*this) || !m_provisionalPages.isEmpty()) > return false; > > if (!m_processPool->shouldTerminate(this)) >diff --git a/Source/WebKit/UIProcess/WebProcessProxy.h b/Source/WebKit/UIProcess/WebProcessProxy.h >index 75f65a7f7eb1acc819991ce4f9f6986c95b61ff3..5042630de371d85a828374348aa9691739c9cd70 100644 >--- a/Source/WebKit/UIProcess/WebProcessProxy.h >+++ b/Source/WebKit/UIProcess/WebProcessProxy.h >@@ -70,6 +70,7 @@ namespace WebKit { > class NetworkProcessProxy; > class ObjCObjectGraph; > class PageClient; >+class ProvisionalPageProxy; > class UserMediaCaptureManagerProxy; > class VisitedLinkStore; > class WebBackForwardListItem; >@@ -124,6 +125,9 @@ public: > enum class EndsUsingDataStore : bool { No, Yes }; > void removeWebPage(WebPageProxy&, uint64_t pageID, EndsUsingDataStore); > >+ void addProvisionalPageProxy(ProvisionalPageProxy& provisionalPage) { ASSERT(!m_provisionalPages.contains(&provisionalPage)); m_provisionalPages.add(&provisionalPage); } >+ void removeProvisionalPageProxy(ProvisionalPageProxy& provisionalPage) { ASSERT(m_provisionalPages.contains(&provisionalPage)); m_provisionalPages.remove(&provisionalPage); } >+ > typename WebPageProxyMap::ValuesConstIteratorRange pages() const { return m_pageMap.values(); } > unsigned pageCount() const { return m_pageMap.size(); } > unsigned visiblePageCount() const { return m_visiblePageCounter.value(); } >@@ -330,6 +334,8 @@ private: > > void logDiagnosticMessageForResourceLimitTermination(const String& limitKey); > >+ bool hasProvisionalPageWithID(uint64_t pageID) const; >+ > enum class IsWeak { No, Yes }; > template<typename T> class WeakOrStrongPtr { > public: >@@ -373,6 +379,7 @@ private: > > WebPageProxyMap m_pageMap; > WebFrameProxyMap m_frameMap; >+ HashSet<ProvisionalPageProxy*> m_provisionalPages; > UserInitiatedActionMap m_userInitiatedActionMap; > > HashSet<VisitedLinkStore*> m_visitedLinkStores; >diff --git a/Source/WebKit/WebKit.xcodeproj/project.pbxproj b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >index dedbadccd34f0a434d6de1454c44a98922ca01cd..d7da27a051289e7e51f48e2c9eca79fa89112451 100644 >--- a/Source/WebKit/WebKit.xcodeproj/project.pbxproj >+++ b/Source/WebKit/WebKit.xcodeproj/project.pbxproj >@@ -3070,6 +3070,8 @@ > 466BC0381FA266C9002FA9C1 /* WebSWContextManagerConnection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebSWContextManagerConnection.cpp; sourceTree = "<group>"; }; > 466BC0391FA266C9002FA9C1 /* WebSWContextManagerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebSWContextManagerConnection.h; sourceTree = "<group>"; }; > 466BC03A1FA266C9002FA9C1 /* WebSWContextManagerConnection.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WebSWContextManagerConnection.messages.in; sourceTree = "<group>"; }; >+ 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProvisionalPageProxy.h; sourceTree = "<group>"; }; >+ 4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProvisionalPageProxy.cpp; sourceTree = "<group>"; }; > 46A2B6061E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BackgroundProcessResponsivenessTimer.cpp; sourceTree = "<group>"; }; > 46A2B6071E5675A200C3DEDA /* BackgroundProcessResponsivenessTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackgroundProcessResponsivenessTimer.h; sourceTree = "<group>"; }; > 46DF06391F3905E5001980BB /* NetworkCORSPreflightChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NetworkCORSPreflightChecker.cpp; sourceTree = "<group>"; }; >@@ -7312,6 +7314,8 @@ > 86E67A22190F411800004AB7 /* ProcessThrottler.cpp */, > 86E67A21190F411800004AB7 /* ProcessThrottler.h */, > 83048AE51ACA45DC0082C832 /* ProcessThrottlerClient.h */, >+ 4683569B21E81CC7006E27A3 /* ProvisionalPageProxy.cpp */, >+ 4683569A21E81CC7006E27A3 /* ProvisionalPageProxy.h */, > A55BA81B1BA25B1E007CD33D /* RemoteWebInspectorProxy.cpp */, > A55BA8191BA25B1E007CD33D /* RemoteWebInspectorProxy.h */, > A55BA81A1BA25B1E007CD33D /* RemoteWebInspectorProxy.messages.in */, >diff --git a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp >index 00749b477a24ce8ccc82501d94e08b60ee1a6263..ffed00c8206a94f0e4ffc7ff3a8a9dff8613fac8 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebFrame.cpp >+++ b/Source/WebKit/WebProcess/WebPage/WebFrame.cpp >@@ -263,8 +263,6 @@ static WebCore::PolicyAction toPolicyAction(WebPolicyAction policyAction) > return WebCore::PolicyAction::Ignore; > case WebPolicyAction::Download: > return WebCore::PolicyAction::Download; >- case WebPolicyAction::Suspend: >- break; > } > ASSERT_NOT_REACHED(); > return WebCore::PolicyAction::Ignore; >@@ -272,11 +270,8 @@ static WebCore::PolicyAction toPolicyAction(WebPolicyAction policyAction) > > void WebFrame::didReceivePolicyDecision(uint64_t listenerID, WebPolicyAction action, uint64_t navigationID, DownloadID downloadID, Optional<WebsitePoliciesData>&& websitePolicies) > { >- if (!m_coreFrame || !m_policyListenerID || listenerID != m_policyListenerID || !m_policyFunction) { >- if (action == WebPolicyAction::Suspend) >- page()->send(Messages::WebPageProxy::DidFailToSuspendAfterProcessSwap()); >+ if (!m_coreFrame || !m_policyListenerID || listenerID != m_policyListenerID || !m_policyFunction) > return; >- } > > FramePolicyFunction function = WTFMove(m_policyFunction); > bool forNavigationAction = m_policyFunctionForNavigationAction == ForNavigationAction::Yes; >@@ -292,16 +287,7 @@ void WebFrame::didReceivePolicyDecision(uint64_t listenerID, WebPolicyAction act > documentLoader->setNavigationID(navigationID); > } > >- bool shouldSuspend = false; >- if (action == WebPolicyAction::Suspend) { >- shouldSuspend = true; >- action = WebPolicyAction::Ignore; >- } >- > function(toPolicyAction(action)); >- >- if (shouldSuspend) >- page()->suspendForProcessSwap(); > } > > void WebFrame::startDownload(const WebCore::ResourceRequest& request, const String& suggestedName) >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.cpp b/Source/WebKit/WebProcess/WebPage/WebPage.cpp >index 803ba8b995ed3ec831ab46b5397c7662e6a81c65..10e5a77233c9576812a3097e083a15f900fdebe3 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.cpp >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.cpp >@@ -401,7 +401,7 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters) > , m_overrideContentSecurityPolicy { parameters.overrideContentSecurityPolicy } > , m_cpuLimit(parameters.cpuLimit) > #if PLATFORM(MAC) >- , m_shouldAttachDrawingAreaOnPageTransition(parameters.isSwapFromSuspended) >+ , m_shouldAttachDrawingAreaOnPageTransition(parameters.isProcessSwap) > #endif > { > ASSERT(m_pageID); >@@ -471,8 +471,8 @@ WebPage::WebPage(uint64_t pageID, WebPageCreationParameters&& parameters) > m_drawingArea->setPaintingEnabled(false); > m_drawingArea->setShouldScaleViewToFitDocument(parameters.shouldScaleViewToFitDocument); > >- if (parameters.isSwapFromSuspended) >- freezeLayerTree(LayerTreeFreezeReason::SwapFromSuspended); >+ if (parameters.isProcessSwap) >+ freezeLayerTree(LayerTreeFreezeReason::ProcessSwap); > > #if ENABLE(ASYNC_SCROLLING) > m_useAsyncScrolling = parameters.store.getBoolValueForKey(WebPreferencesKey::threadedScrollingEnabledKey()); >@@ -696,7 +696,7 @@ void WebPage::reinitializeWebPage(WebPageCreationParameters&& parameters) > m_drawingArea->updatePreferences(parameters.store); > m_drawingArea->setPaintingEnabled(true); > #if PLATFORM(MAC) >- m_shouldAttachDrawingAreaOnPageTransition = parameters.isSwapFromSuspended; >+ m_shouldAttachDrawingAreaOnPageTransition = parameters.isProcessSwap; > #endif > unfreezeLayerTree(LayerTreeFreezeReason::PageSuspended); > } >@@ -3053,12 +3053,6 @@ void WebPage::didReceivePolicyDecision(uint64_t frameID, uint64_t listenerID, We > WebFrame* frame = WebProcess::singleton().webFrame(frameID); > if (!frame) > return; >- if (policyAction == WebPolicyAction::Suspend) { >- ASSERT(frame == m_mainFrame); >- setIsSuspended(true); >- >- WebProcess::singleton().sendPrewarmInformation(mainWebFrame()->url()); >- } > frame->didReceivePolicyDecision(listenerID, policyAction, navigationID, downloadID, WTFMove(websitePolicies)); > } > >@@ -3100,7 +3094,7 @@ void WebPage::didCompletePageTransition() > > bool isInitialEmptyDocument = !m_mainFrame; > if (!isInitialEmptyDocument) >- unfreezeLayerTree(LayerTreeFreezeReason::SwapFromSuspended); >+ unfreezeLayerTree(LayerTreeFreezeReason::ProcessSwap); > > #if PLATFORM(MAC) > if (m_shouldAttachDrawingAreaOnPageTransition && !isInitialEmptyDocument) { >@@ -6312,6 +6306,10 @@ void WebPage::setIsSuspended(bool suspended) > if (m_isSuspended) { > // Unfrozen on drawing area reset. > freezeLayerTree(LayerTreeFreezeReason::PageSuspended); >+ >+ WebProcess::singleton().sendPrewarmInformation(mainWebFrame()->url()); >+ >+ suspendForProcessSwap(); > } else > m_shouldResetDrawingAreaAfterSuspend = true; > } >diff --git a/Source/WebKit/WebProcess/WebPage/WebPage.h b/Source/WebKit/WebProcess/WebPage/WebPage.h >index 715e124520ff076b960aed70e9b92075a6552aef..f3b934e27da9d5ea5a1bbf55f149f5a8512736e4 100644 >--- a/Source/WebKit/WebProcess/WebPage/WebPage.h >+++ b/Source/WebKit/WebProcess/WebPage/WebPage.h >@@ -696,7 +696,7 @@ public: > ProcessSuspended = 1 << 2, > PageSuspended = 1 << 3, > Printing = 1 << 4, >- SwapFromSuspended = 1 << 5, >+ ProcessSwap = 1 << 5, > }; > void freezeLayerTree(LayerTreeFreezeReason); > void unfreezeLayerTree(LayerTreeFreezeReason); >diff --git a/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm b/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm >index 91ad71ade1b7db4f9dce64d4f330467b22b833cc..83b6599270b51c7bb18efe737a592e02571a2806 100644 >--- a/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm >+++ b/Source/WebKit/WebProcess/WebPage/mac/TiledCoreAnimationDrawingArea.mm >@@ -97,7 +97,7 @@ TiledCoreAnimationDrawingArea::TiledCoreAnimationDrawingArea(WebPage& webPage, c > updateLayerHostingContext(); > setColorSpace(parameters.colorSpace); > >- if (!parameters.isSwapFromSuspended) >+ if (!parameters.isProcessSwap) > attach(); > } > >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 9a262404becda5f199f311ace20ee13433b17357..3249f43e36b8e9f549472d9204b2c681e2a69e00 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,16 @@ >+2019-01-15 Chris Dumez <cdumez@apple.com> >+ >+ Regression(PSON) View becomes blank after click a cross-site download link >+ https://bugs.webkit.org/show_bug.cgi?id=193361 >+ <rdar://problem/47099573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add API test coverage. >+ >+ * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm: >+ (-[PSONNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): >+ > 2019-01-15 Zalan Bujtas <zalan@apple.com> > > [LFC] Use the containing block's padding box to position out-of-flow elements. >diff --git a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm >index f35d8baa353f07024fd40e7d527453a74210c3ba..a445bf1f9cbb2e2c962066472881c5ed49d1ca8e 100644 >--- a/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm >+++ b/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2017 Apple Inc. All rights reserved. >+ * Copyright (C) 2017-2019 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -72,6 +72,7 @@ static bool serverRedirected; > static HashSet<pid_t> seenPIDs; > static bool willPerformClientRedirect; > static bool didPerformClientRedirect; >+static bool shouldConvertToDownload; > static RetainPtr<NSURL> clientRedirectSourceURL; > static RetainPtr<NSURL> clientRedirectDestinationURL; > >@@ -128,6 +129,11 @@ - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigati > didRepondToPolicyDecisionCall = true; > } > >+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler >+{ >+ decisionHandler(shouldConvertToDownload ? _WKNavigationResponsePolicyBecomeDownload : WKNavigationResponsePolicyAllow); >+} >+ > - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation > { > seenPIDs.add([webView _webProcessIdentifier]); >@@ -1405,7 +1411,7 @@ TEST(ProcessSwap, ServerRedirect) > > EXPECT_FALSE(serverRedirected); > EXPECT_EQ(3, numberOfDecidePolicyCalls); >- EXPECT_EQ(2u, seenPIDs.size()); >+ EXPECT_EQ(3u, seenPIDs.size()); > } > > TEST(ProcessSwap, ServerRedirect2) >@@ -1467,6 +1473,109 @@ TEST(ProcessSwap, ServerRedirect2) > EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]); > } > >+static const char* linkToWebKitBytes = R"PSONRESOURCE( >+<body> >+ <a id="testLink" href="pson://www.webkit.org/main.html">Link</a> >+</body> >+)PSONRESOURCE"; >+ >+TEST(ProcessSwap, PolicyCancelAfterServerRedirect) >+{ >+ auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]); >+ processPoolConfiguration.get().processSwapsOnNavigation = YES; >+ auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); >+ >+ auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); >+ [webViewConfiguration setProcessPool:processPool.get()]; >+ auto handler = adoptNS([[PSONScheme alloc] init]); >+ [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes]; >+ [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/ignore.html"]; >+ [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; >+ >+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); >+ auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); >+ [webView setNavigationDelegate:navigationDelegate.get()]; >+ >+ navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) { >+ if ([action.request.URL.absoluteString hasSuffix:@"ignore.html"]) { >+ decisionHandler(WKNavigationActionPolicyCancel); >+ return; >+ } >+ decisionHandler(WKNavigationActionPolicyAllow); >+ }; >+ >+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; >+ [webView loadRequest:request]; >+ >+ TestWebKitAPI::Util::run(&done); >+ done = false; >+ auto pidAfterFirstLoad = [webView _webProcessIdentifier]; >+ >+ EXPECT_EQ(1, numberOfDecidePolicyCalls); >+ >+ [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; >+ >+ TestWebKitAPI::Util::run(&failed); >+ failed = false; >+ done = false; >+ >+ EXPECT_EQ(3, numberOfDecidePolicyCalls); >+ >+ // We should still be on google.com. >+ EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); >+ EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]); >+ >+ [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) { >+ EXPECT_WK_STREQ(@"Link", innerText); >+ done = true; >+ }]; >+ TestWebKitAPI::Util::run(&done); >+ done = false; >+} >+ >+TEST(ProcessSwap, CrossSiteDownload) >+{ >+ auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]); >+ processPoolConfiguration.get().processSwapsOnNavigation = YES; >+ auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); >+ >+ auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); >+ [webViewConfiguration setProcessPool:processPool.get()]; >+ auto handler = adoptNS([[PSONScheme alloc] init]); >+ [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes]; >+ [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:"Hello"]; >+ [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; >+ >+ auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); >+ auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); >+ [webView setNavigationDelegate:navigationDelegate.get()]; >+ >+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; >+ [webView loadRequest:request]; >+ >+ TestWebKitAPI::Util::run(&done); >+ done = false; >+ auto pidAfterFirstLoad = [webView _webProcessIdentifier]; >+ >+ shouldConvertToDownload = true; >+ [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; >+ >+ TestWebKitAPI::Util::run(&failed); >+ failed = false; >+ shouldConvertToDownload = false; >+ >+ // We should still be on google.com. >+ EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); >+ EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]); >+ >+ [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) { >+ EXPECT_WK_STREQ(@"Link", innerText); >+ done = true; >+ }]; >+ TestWebKitAPI::Util::run(&done); >+ done = false; >+} >+ > enum class ShouldEnablePSON { No, Yes }; > static void runClientSideRedirectTest(ShouldEnablePSON shouldEnablePSON) > { >@@ -2232,12 +2341,27 @@ TEST(ProcessSwap, PageShowHide) > > EXPECT_EQ(7u, [receivedMessages count]); > EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow NOT persisted", receivedMessages.get()[0]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[1]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[2]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[3]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[4]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[5]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[6]); >+ if ([receivedMessages.get()[1] hasPrefix:@"pson://www.webkit.org/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[1]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[2]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[1]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[2]); >+ } >+ if ([receivedMessages.get()[3] hasPrefix:@"pson://www.apple.com/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[3]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[4]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[3]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[4]); >+ } >+ if ([receivedMessages.get()[5] hasPrefix:@"pson://www.webkit.org/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[5]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[6]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[5]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[6]); >+ } > } > > // Disabling the page cache explicitly is (for some reason) not available on iOS. >@@ -2307,12 +2431,27 @@ TEST(ProcessSwap, LoadUnload) > > EXPECT_EQ(7u, [receivedMessages count]); > EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[0]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[1]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[2]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[3]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[4]); >- EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[5]); >- EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[6]); >+ if ([receivedMessages.get()[1] hasPrefix:@"pson://www.webkit.org/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[1]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[2]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[1]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[2]); >+ } >+ if ([receivedMessages.get()[3] hasPrefix:@"pson://www.apple.com/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[3]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[4]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[3]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[4]); >+ } >+ if ([receivedMessages.get()[5] hasPrefix:@"pson://www.webkit.org/main.html"]) { >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[5]); >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[6]); >+ } else { >+ EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[5]); >+ EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[6]); >+ } > } > > TEST(ProcessSwap, WebInspector) >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 04a86866ea600d2010291abfbb94b3721d59da54..34c5286d305a3afd6855252081e284c457410503 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,17 @@ >+2019-01-15 Chris Dumez <cdumez@apple.com> >+ >+ Regression(PSON) View becomes blank after click a cross-site download link >+ https://bugs.webkit.org/show_bug.cgi?id=193361 >+ <rdar://problem/47099573> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Skip test testing the cross-process DOMWindow API as I broke it with this patch. >+ The feature is far from ready and off by default anyway. I will add support back >+ in a follow-up. >+ >+ * platform/wk2/TestExpectations: >+ > 2019-01-15 Devin Rousso <drousso@apple.com> > > Web Inspector: Audit: provide a way to determine whether a give node has event listeners >diff --git a/LayoutTests/platform/wk2/TestExpectations b/LayoutTests/platform/wk2/TestExpectations >index 8e959edaffd8927ef9c2aac316e9e3100cd140cb..9d90be8b48e57c960bcda686ce2440d7138bb0f6 100644 >--- a/LayoutTests/platform/wk2/TestExpectations >+++ b/LayoutTests/platform/wk2/TestExpectations >@@ -733,8 +733,8 @@ http/tests/resourceLoadStatistics/remove-blocking-in-redirect.html [ Skip ] > http/tests/resourceLoadStatistics/non-prevalent-resources-can-access-cookies-in-a-third-party-context.html [ Skip ] > http/tests/resourceLoadStatistics/cap-cache-max-age-for-prevalent-resource.html [ Skip ] > >-# Process swapping is only implemented on WebKit2. >-http/tests/navigation/process-swap-window-open.html [ Pass ] >+# This feature is currently disabled by default and unfinished <rdar://problem/38925077>. >+http/tests/navigation/process-swap-window-open.html [ Skip ] > > # Cross-Origin-Resource-Policy response header is only implemented in WebKit2. > http/wpt/cross-origin-resource-policy/ [ Pass ]
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193361
:
358934
|
358950
|
358953
|
358960
|
358961
|
359047
|
359071
|
359086
|
359088
|
359092
|
359119
|
359163
|
359165
|
359166
|
359168
|
359169
|
359176
|
359256
|
359269
|
359274