Title: [229778] trunk
Revision
229778
Author
beid...@apple.com
Date
2018-03-20 17:05:58 -0700 (Tue, 20 Mar 2018)

Log Message

First piece of process swapping on navigation.
https://bugs.webkit.org/show_bug.cgi?id=183665

Reviewed by Andy Estes.

Source/WebCore:

Covered by API test(s)

This patch:
- A new PolicyAction::Suspend for future use in this feature
- Makes sure that loads triggered as part of a process swap do *not* re-consult the policy delegate

* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::continueAfterContentPolicy):

* loader/FrameLoadRequest.h:
(WebCore::FrameLoadRequest::setShouldCheckNavigationPolicy):
(WebCore::FrameLoadRequest::shouldCheckNavigationPolicy const):

* loader/FrameLoader.cpp:
(WebCore::FrameLoader::load):
(WebCore::FrameLoader::loadWithDocumentLoader):
* loader/FrameLoader.h:

* loader/FrameLoaderTypes.h: Add a new Policy type "Suspend" to be used in the future
  by the process-swap-on-navigation mechanism.

* loader/PolicyChecker.cpp:
(WebCore::PolicyChecker::checkNavigationPolicy):
(WebCore::PolicyChecker::checkNewWindowPolicy):

Source/WebKit:

This patch adds the first pieces of the following feature:
"When a navigation originating inside a WKWebView goes to a different origin,
 swap to a new WebProcess for that navigation"

There are significant bugs to be resolved and significant optimizations to be made.
Which is why the feature is disabled by default.

Besides the core logic implementing the feature, this patch does a lot of related
work such as:
- Removing some now-invalid ASSERTs
- Adding some ASSERTs
- Update various switch states to handle the new "Suspend" policy and "NavigationSwap"
  process termination reason

* NetworkProcess/NetworkDataTaskBlob.cpp:
(WebKit::NetworkDataTaskBlob::dispatchDidReceiveResponse):

* NetworkProcess/capture/NetworkDataTaskReplay.cpp:
(WebKit::NetworkCapture::NetworkDataTaskReplay::didReceiveResponse):

* NetworkProcess/cocoa/NetworkSessionCocoa.mm:
(toNSURLSessionResponseDisposition):

* Platform/Logging.h:

* Shared/LoadParameters.cpp:
(WebKit::LoadParameters::encode const):
(WebKit::LoadParameters::decode):
* Shared/LoadParameters.h:

* Shared/ProcessTerminationReason.h: Add "NavigationSwap" as a process termination reason.

* UIProcess/API/APINavigation.h:

* UIProcess/API/APIProcessPoolConfiguration.cpp:
(API::ProcessPoolConfiguration::copy):

* UIProcess/API/C/WKAPICast.h:
(WebKit::toAPI):

* UIProcess/Cocoa/NavigationState.mm:
(WebKit::wkProcessTerminationReason):

* UIProcess/WebFramePolicyListenerProxy.cpp:
(WebKit::WebFramePolicyListenerProxy::WebFramePolicyListenerProxy):
* UIProcess/WebFramePolicyListenerProxy.h:
(WebKit::WebFramePolicyListenerProxy::create):
(WebKit::WebFramePolicyListenerProxy::policyListenerType const):

* UIProcess/WebFrameProxy.cpp:
(WebKit::WebFrameProxy::setUpPolicyListenerProxy):
(WebKit::WebFrameProxy::activePolicyListenerProxy):
* UIProcess/WebFrameProxy.h:

* UIProcess/WebNavigationState.cpp:
(WebKit::WebNavigationState::navigation):
(WebKit::WebNavigationState::takeNavigation):

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::reattachToWebProcess):
(WebKit::WebPageProxy::attachToProcessForNavigation): Pretend that the existing process
  terminated using the new "NavigationSwap" reason, then manually start the next load.
(WebKit::WebPageProxy::loadRequest):
(WebKit::WebPageProxy::loadRequestWithNavigation):
(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::continueNavigationInNewProcess):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
(WebKit::WebPageProxy::decidePolicyForResponse):
(WebKit::WebPageProxy::processDidTerminate):
(WebKit::WebPageProxy::resetState):
(WebKit::WebPageProxy::resetStateAfterProcessExited):
* UIProcess/WebPageProxy.h:

* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigation): Determine which process should be used
  for a proposed navigation, creating a new one if necessary.
* UIProcess/WebProcessPool.h:

* UIProcess/WebStorage/StorageManager.cpp:
(WebKit::StorageManager::SessionStorageNamespace::setAllowedConnection):

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::loadRequest):

Tools:

Expose the "swaps processes on navigation" setting in MiniBrowser UI for testing:

* MiniBrowser/mac/AppDelegate.m:
(defaultConfiguration):
* MiniBrowser/mac/SettingsController.h:
* MiniBrowser/mac/SettingsController.m:
(-[SettingsController _populateMenu]):
(-[SettingsController validateMenuItem:]):
(-[SettingsController processSwapOnNavigationEnabled]):
(-[SettingsController toggleProcessSwapOnNavigation:]):

Makes sure the current behavior is tested:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm: Added.
(-[PSONNavigationDelegate webView:didFinishNavigation:]):
(-[PSONScheme webView:startURLSchemeTask:]):
(-[PSONScheme webView:stopURLSchemeTask:]):
(TEST):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (229777 => 229778)


--- trunk/Source/WebCore/ChangeLog	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/ChangeLog	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1,3 +1,35 @@
+2018-03-20  Brady Eidson  <beid...@apple.com>
+
+        First piece of process swapping on navigation.
+        https://bugs.webkit.org/show_bug.cgi?id=183665
+
+        Reviewed by Andy Estes.
+
+        Covered by API test(s)
+
+        This patch:
+        - A new PolicyAction::Suspend for future use in this feature
+        - Makes sure that loads triggered as part of a process swap do *not* re-consult the policy delegate
+
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::continueAfterContentPolicy):
+
+        * loader/FrameLoadRequest.h:
+        (WebCore::FrameLoadRequest::setShouldCheckNavigationPolicy):
+        (WebCore::FrameLoadRequest::shouldCheckNavigationPolicy const):
+
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::load):
+        (WebCore::FrameLoader::loadWithDocumentLoader):
+        * loader/FrameLoader.h:
+
+        * loader/FrameLoaderTypes.h: Add a new Policy type "Suspend" to be used in the future
+          by the process-swap-on-navigation mechanism.
+
+        * loader/PolicyChecker.cpp:
+        (WebCore::PolicyChecker::checkNavigationPolicy):
+        (WebCore::PolicyChecker::checkNewWindowPolicy):
+
 2018-03-20  Chris Dumez  <cdu...@apple.com>
 
         QuickLook.NavigationDelegate API test is failing on iOS with async policy delegates

Modified: trunk/Source/WebCore/loader/DocumentLoader.cpp (229777 => 229778)


--- trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/DocumentLoader.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -896,6 +896,9 @@
             static_cast<ResourceLoader*>(mainResourceLoader())->didFail(interruptedForPolicyChangeError());
         return;
     }
+    case PolicyAction::Suspend:
+        // It is invalid to get a Suspend policy based on navigation response.
+        RELEASE_ASSERT_NOT_REACHED();
     case PolicyAction::Ignore:
         if (ResourceLoader* mainResourceLoader = this->mainResourceLoader())
             InspectorInstrumentation::continueWithPolicyIgnore(*m_frame, mainResourceLoader->identifier(), *this, m_response);

Modified: trunk/Source/WebCore/loader/FrameLoadRequest.h (229777 => 229778)


--- trunk/Source/WebCore/loader/FrameLoadRequest.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/FrameLoadRequest.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -60,6 +60,9 @@
     void setShouldCheckNewWindowPolicy(bool checkPolicy) { m_shouldCheckNewWindowPolicy = checkPolicy; }
     bool shouldCheckNewWindowPolicy() const { return m_shouldCheckNewWindowPolicy; }
 
+    void setShouldCheckNavigationPolicy(bool checkPolicy) { m_shouldCheckNavigationPolicy = checkPolicy; }
+    bool shouldCheckNavigationPolicy() const { return m_shouldCheckNavigationPolicy; }
+
     const SubstituteData& substituteData() const { return m_substituteData; }
     void setSubstituteData(const SubstituteData& data) { m_substituteData = data; }
     bool hasSubstituteData() { return m_substituteData.isValid(); }
@@ -89,6 +92,7 @@
     SubstituteData m_substituteData;
 
     bool m_shouldCheckNewWindowPolicy { false };
+    bool m_shouldCheckNavigationPolicy { true };
     LockHistory m_lockHistory;
     LockBackForwardList m_lockBackForwardList;
     ShouldSendReferrer m_shouldSendReferrer;

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (229777 => 229778)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -123,6 +123,7 @@
 #include "XMLDocumentParser.h"
 #include <wtf/CompletionHandler.h>
 #include <wtf/Ref.h>
+#include <wtf/SetForScope.h>
 #include <wtf/StdLibExtras.h>
 #include <wtf/SystemTracing.h>
 #include <wtf/text/CString.h>
@@ -1403,6 +1404,7 @@
     Ref<DocumentLoader> loader = m_client.createDocumentLoader(request.resourceRequest(), request.substituteData());
     applyShouldOpenExternalURLsPolicyToNewDocumentLoader(m_frame, loader, request);
 
+    SetForScope<bool> currentLoadShouldCheckNavigationPolicyGuard(m_currentLoadShouldCheckNavigationPolicy, request.shouldCheckNavigationPolicy());
     load(loader.ptr());
 }
 
@@ -1538,6 +1540,11 @@
 
     m_frame.navigationScheduler().cancel(true);
 
+    if (!m_currentLoadShouldCheckNavigationPolicy) {
+        continueLoadAfterNavigationPolicy(loader->request(), formState, true, allowNavigationToInvalidURL);
+        return;
+    }
+
     policyChecker().checkNavigationPolicy(ResourceRequest(loader->request()), false /* didReceiveRedirectResponse */, loader, formState, [this, protectedFrame = makeRef(m_frame), allowNavigationToInvalidURL, completionHandler = completionHandlerCaller.release()] (const ResourceRequest& request, FormState* formState, bool shouldContinue) {
         continueLoadAfterNavigationPolicy(request, formState, shouldContinue, allowNavigationToInvalidURL);
         completionHandler();

Modified: trunk/Source/WebCore/loader/FrameLoader.h (229777 => 229778)


--- trunk/Source/WebCore/loader/FrameLoader.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/FrameLoader.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -461,6 +461,7 @@
     std::optional<ResourceRequestCachePolicy> m_overrideCachePolicyForTesting;
     std::optional<ResourceLoadPriority> m_overrideResourceLoadPriorityForTesting;
     bool m_isStrictRawResourceValidationPolicyDisabledForTesting { false };
+    bool m_currentLoadShouldCheckNavigationPolicy { true };
 
     URL m_previousURL;
     RefPtr<HistoryItem> m_requestedHistoryItem;

Modified: trunk/Source/WebCore/loader/FrameLoaderTypes.h (229777 => 229778)


--- trunk/Source/WebCore/loader/FrameLoaderTypes.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/FrameLoaderTypes.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -41,7 +41,8 @@
 enum class PolicyAction {
     Use,
     Download,
-    Ignore
+    Ignore,
+    Suspend,
 };
 
 enum class ReloadOption {
@@ -158,7 +159,8 @@
         WebCore::PolicyAction,
         WebCore::PolicyAction::Use,
         WebCore::PolicyAction::Download,
-        WebCore::PolicyAction::Ignore
+        WebCore::PolicyAction::Ignore,
+        WebCore::PolicyAction::Suspend
     >;
 };
 

Modified: trunk/Source/WebCore/loader/PolicyChecker.cpp (229777 => 229778)


--- trunk/Source/WebCore/loader/PolicyChecker.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebCore/loader/PolicyChecker.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -159,6 +159,9 @@
             FALLTHROUGH;
         case PolicyAction::Ignore:
             return function({ }, nullptr, false);
+        case PolicyAction::Suspend:
+            LOG(Loading, "PolicyAction::Suspend encountered - Treating as PolicyAction::Ignore for now");
+            return function({ }, nullptr, false);
         case PolicyAction::Use:
             if (!m_frame.loader().client().canHandleRequest(request)) {
                 handleUnimplementablePolicy(m_frame.loader().client().cannotShowURLError(request));
@@ -186,6 +189,9 @@
         case PolicyAction::Ignore:
             function({ }, nullptr, { }, { }, false);
             return;
+        case PolicyAction::Suspend:
+            // It is invalid to get a "Suspend" policy for new windows, as the old document is not going away.
+            RELEASE_ASSERT_NOT_REACHED();
         case PolicyAction::Use:
             function(request, formState.get(), frameName, navigationAction, true);
             return;

Modified: trunk/Source/WebKit/ChangeLog (229777 => 229778)


--- trunk/Source/WebKit/ChangeLog	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/ChangeLog	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1,3 +1,94 @@
+2018-03-20  Brady Eidson  <beid...@apple.com>
+
+        First piece of process swapping on navigation.
+        https://bugs.webkit.org/show_bug.cgi?id=183665
+
+        Reviewed by Andy Estes.
+
+        This patch adds the first pieces of the following feature:
+        "When a navigation originating inside a WKWebView goes to a different origin,
+         swap to a new WebProcess for that navigation"
+
+        There are significant bugs to be resolved and significant optimizations to be made.
+        Which is why the feature is disabled by default.
+
+        Besides the core logic implementing the feature, this patch does a lot of related 
+        work such as:
+        - Removing some now-invalid ASSERTs
+        - Adding some ASSERTs
+        - Update various switch states to handle the new "Suspend" policy and "NavigationSwap"
+          process termination reason
+
+        * NetworkProcess/NetworkDataTaskBlob.cpp:
+        (WebKit::NetworkDataTaskBlob::dispatchDidReceiveResponse):
+
+        * NetworkProcess/capture/NetworkDataTaskReplay.cpp:
+        (WebKit::NetworkCapture::NetworkDataTaskReplay::didReceiveResponse):
+
+        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
+        (toNSURLSessionResponseDisposition):
+
+        * Platform/Logging.h:
+
+        * Shared/LoadParameters.cpp:
+        (WebKit::LoadParameters::encode const):
+        (WebKit::LoadParameters::decode):
+        * Shared/LoadParameters.h:
+
+        * Shared/ProcessTerminationReason.h: Add "NavigationSwap" as a process termination reason.
+
+        * UIProcess/API/APINavigation.h:
+
+        * UIProcess/API/APIProcessPoolConfiguration.cpp:
+        (API::ProcessPoolConfiguration::copy):
+
+        * UIProcess/API/C/WKAPICast.h:
+        (WebKit::toAPI):
+
+        * UIProcess/Cocoa/NavigationState.mm:
+        (WebKit::wkProcessTerminationReason):
+
+        * UIProcess/WebFramePolicyListenerProxy.cpp:
+        (WebKit::WebFramePolicyListenerProxy::WebFramePolicyListenerProxy):
+        * UIProcess/WebFramePolicyListenerProxy.h:
+        (WebKit::WebFramePolicyListenerProxy::create):
+        (WebKit::WebFramePolicyListenerProxy::policyListenerType const):
+
+        * UIProcess/WebFrameProxy.cpp:
+        (WebKit::WebFrameProxy::setUpPolicyListenerProxy):
+        (WebKit::WebFrameProxy::activePolicyListenerProxy):
+        * UIProcess/WebFrameProxy.h:
+
+        * UIProcess/WebNavigationState.cpp:
+        (WebKit::WebNavigationState::navigation):
+        (WebKit::WebNavigationState::takeNavigation):
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::reattachToWebProcess):
+        (WebKit::WebPageProxy::attachToProcessForNavigation): Pretend that the existing process 
+          terminated using the new "NavigationSwap" reason, then manually start the next load.
+        (WebKit::WebPageProxy::loadRequest):
+        (WebKit::WebPageProxy::loadRequestWithNavigation):
+        (WebKit::WebPageProxy::receivedPolicyDecision):
+        (WebKit::WebPageProxy::continueNavigationInNewProcess):
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        (WebKit::WebPageProxy::decidePolicyForResponse):
+        (WebKit::WebPageProxy::processDidTerminate):
+        (WebKit::WebPageProxy::resetState):
+        (WebKit::WebPageProxy::resetStateAfterProcessExited):
+        * UIProcess/WebPageProxy.h:
+
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigation): Determine which process should be used
+          for a proposed navigation, creating a new one if necessary.
+        * UIProcess/WebProcessPool.h:
+
+        * UIProcess/WebStorage/StorageManager.cpp:
+        (WebKit::StorageManager::SessionStorageNamespace::setAllowedConnection):
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::loadRequest):
+
 2018-03-20  Youenn Fablet  <you...@apple.com>
 
         ServiceWorkerClientFetch::didReceiveData should check for m_encodedDataLength

Modified: trunk/Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp (229777 => 229778)


--- trunk/Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/NetworkProcess/NetworkDataTaskBlob.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -317,6 +317,9 @@
             m_buffer.resize(bufferSize);
             read();
             break;
+        case PolicyAction::Suspend:
+            LOG_ERROR("PolicyAction::Suspend encountered - Treating as PolicyAction::Ignore for now");
+            FALLTHROUGH;
         case PolicyAction::Ignore:
             break;
         case PolicyAction::Download:

Modified: trunk/Source/WebKit/NetworkProcess/capture/NetworkDataTaskReplay.cpp (229777 => 229778)


--- trunk/Source/WebKit/NetworkProcess/capture/NetworkDataTaskReplay.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/NetworkProcess/capture/NetworkDataTaskReplay.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -252,6 +252,9 @@
         case WebCore::PolicyAction::Use:
             enqueueEventHandler();
             break;
+        case WebCore::PolicyAction::Suspend:
+            LOG_ERROR("PolicyAction::Suspend encountered - Treating as PolicyAction::Ignore for now");
+            FALLTHROUGH;
         case WebCore::PolicyAction::Ignore:
             complete();
             break;

Modified: trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm (229777 => 229778)


--- trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm	2018-03-21 00:05:58 UTC (rev 229778)
@@ -62,6 +62,9 @@
 static NSURLSessionResponseDisposition toNSURLSessionResponseDisposition(WebCore::PolicyAction disposition)
 {
     switch (disposition) {
+    case WebCore::PolicyAction::Suspend:
+        LOG_ERROR("PolicyAction::Suspend encountered - Treating as PolicyAction::Ignore for now");
+        FALLTHROUGH;
     case WebCore::PolicyAction::Ignore:
         return NSURLSessionResponseCancel;
     case WebCore::PolicyAction::Use:

Modified: trunk/Source/WebKit/Platform/Logging.h (229777 => 229778)


--- trunk/Source/WebKit/Platform/Logging.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/Platform/Logging.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -50,6 +50,7 @@
     M(IPC) \
     M(KeyHandling) \
     M(Layers) \
+    M(Loading) \
     M(Network) \
     M(NetworkCache) \
     M(NetworkCacheSpeculativePreloading) \

Modified: trunk/Source/WebKit/Shared/LoadParameters.cpp (229777 => 229778)


--- trunk/Source/WebKit/Shared/LoadParameters.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/Shared/LoadParameters.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -48,6 +48,7 @@
     encoder << unreachableURLString;
     encoder << provisionalLoadErrorURLString;
     encoder << shouldOpenExternalURLsPolicy;
+    encoder << shouldCheckNavigationPolicy;
     encoder << userData;
 
     platformEncode(encoder);
@@ -102,6 +103,9 @@
     if (!decoder.decode(data.shouldOpenExternalURLsPolicy))
         return false;
 
+    if (!decoder.decode(data.shouldCheckNavigationPolicy))
+        return false;
+
     if (!decoder.decode(data.userData))
         return false;
 

Modified: trunk/Source/WebKit/Shared/LoadParameters.h (229777 => 229778)


--- trunk/Source/WebKit/Shared/LoadParameters.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/Shared/LoadParameters.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -62,6 +62,7 @@
     String provisionalLoadErrorURLString;
 
     uint64_t shouldOpenExternalURLsPolicy;
+    bool shouldCheckNavigationPolicy { true };
     UserData userData;
 
 #if PLATFORM(COCOA)

Modified: trunk/Source/WebKit/Shared/ProcessTerminationReason.h (229777 => 229778)


--- trunk/Source/WebKit/Shared/ProcessTerminationReason.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/Shared/ProcessTerminationReason.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -31,7 +31,8 @@
     ExceededMemoryLimit,
     ExceededCPULimit,
     RequestedByClient,
-    Crash
+    Crash,
+    NavigationSwap,
 };
 
 }

Modified: trunk/Source/WebKit/UIProcess/API/APINavigation.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -36,6 +36,7 @@
 namespace API {
 
 class Navigation : public ObjectImpl<Object::Type::Navigation> {
+    WTF_MAKE_NONCOPYABLE(Navigation);
 public:
     static Ref<Navigation> create(WebKit::WebNavigationState& state)
     {
@@ -64,7 +65,7 @@
 
 private:
     explicit Navigation(WebKit::WebNavigationState&);
-    explicit Navigation(WebKit::WebNavigationState&, WebCore::ResourceRequest&&);
+    Navigation(WebKit::WebNavigationState&, WebCore::ResourceRequest&&);
 
     uint64_t m_navigationID;
     WebCore::ResourceRequest m_request;

Modified: trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -127,6 +127,7 @@
     copy->m_ctDataConnectionServiceType = this->m_ctDataConnectionServiceType;
 #endif
     copy->m_presentingApplicationPID = this->m_presentingApplicationPID;
+    copy->m_processSwapsOnNavigation = this->m_processSwapsOnNavigation;
 
     return copy;
 }

Modified: trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/API/C/WKAPICast.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -236,6 +236,10 @@
         return kWKProcessTerminationReasonExceededMemoryLimit;
     case ProcessTerminationReason::ExceededCPULimit:
         return kWKProcessTerminationReasonExceededCPULimit;
+    case ProcessTerminationReason::NavigationSwap:
+        // We probably shouldn't bother coming up with a new C-API type for process-swapping.
+        // "Requested by client" seems like the best match for existing types.
+        FALLTHROUGH;
     case ProcessTerminationReason::RequestedByClient:
         return kWKProcessTerminationReasonRequestedByClient;
     case ProcessTerminationReason::Crash:

Modified: trunk/Source/WebKit/UIProcess/Cocoa/NavigationState.mm (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/Cocoa/NavigationState.mm	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/Cocoa/NavigationState.mm	2018-03-21 00:05:58 UTC (rev 229778)
@@ -962,6 +962,10 @@
         return _WKProcessTerminationReasonExceededMemoryLimit;
     case ProcessTerminationReason::ExceededCPULimit:
         return _WKProcessTerminationReasonExceededCPULimit;
+    case ProcessTerminationReason::NavigationSwap:
+        // We probably shouldn't bother coming up with a new API type for process-swapping.
+        // "Requested by client" seems like the best match for existing types.
+        FALLTHROUGH;
     case ProcessTerminationReason::RequestedByClient:
         return _WKProcessTerminationReasonRequestedByClient;
     case ProcessTerminationReason::Crash:

Modified: trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -32,8 +32,9 @@
 
 namespace WebKit {
 
-WebFramePolicyListenerProxy::WebFramePolicyListenerProxy(WebFrameProxy* frame, uint64_t listenerID)
+WebFramePolicyListenerProxy::WebFramePolicyListenerProxy(WebFrameProxy* frame, uint64_t listenerID, PolicyListenerType policyType)
     : WebFrameListenerProxy(frame, listenerID)
+    , m_policyType(policyType)
 {
 }
 

Modified: trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebFramePolicyListenerProxy.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -35,13 +35,19 @@
 
 namespace WebKit {
 
+enum class PolicyListenerType {
+    NavigationAction,
+    NewWindowAction,
+    Response,
+};
+
 class WebFramePolicyListenerProxy : public WebFrameListenerProxy {
 public:
     static const Type APIType = Type::FramePolicyListener;
 
-    static Ref<WebFramePolicyListenerProxy> create(WebFrameProxy* frame, uint64_t listenerID)
+    static Ref<WebFramePolicyListenerProxy> create(WebFrameProxy* frame, uint64_t listenerID, PolicyListenerType policyType)
     {
-        return adoptRef(*new WebFramePolicyListenerProxy(frame, listenerID));
+        return adoptRef(*new WebFramePolicyListenerProxy(frame, listenerID, policyType));
     }
 
     void use(std::optional<WebsitePoliciesData>&&);
@@ -48,8 +54,10 @@
     void download();
     void ignore();
 
+    PolicyListenerType policyListenerType() const { return m_policyType; }
+
 private:
-    WebFramePolicyListenerProxy(WebFrameProxy*, uint64_t listenerID);
+    WebFramePolicyListenerProxy(WebFrameProxy*, uint64_t listenerID, PolicyListenerType);
 
     Type type() const override { return APIType; }
 
@@ -56,6 +64,8 @@
 #if DELEGATE_REF_COUNTING_TO_COCOA
     void* operator new(size_t size) { return newObject(size, APIType); }
 #endif
+
+    PolicyListenerType m_policyType;
 };
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebFrameProxy.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -187,14 +187,22 @@
     m_page->receivedPolicyDecision(action, *this, listenerID, navigation, WTFMove(data));
 }
 
-WebFramePolicyListenerProxy& WebFrameProxy::setUpPolicyListenerProxy(uint64_t listenerID)
+WebFramePolicyListenerProxy& WebFrameProxy::setUpPolicyListenerProxy(uint64_t listenerID, PolicyListenerType policyListenerType)
 {
     if (m_activeListener)
         m_activeListener->invalidate();
-    m_activeListener = WebFramePolicyListenerProxy::create(this, listenerID);
+    m_activeListener = WebFramePolicyListenerProxy::create(this, listenerID, policyListenerType);
     return *static_cast<WebFramePolicyListenerProxy*>(m_activeListener.get());
 }
 
+WebFramePolicyListenerProxy* WebFrameProxy::activePolicyListenerProxy()
+{
+    if (!m_activeListener || m_activeListener->type() != WebFramePolicyListenerProxy::APIType)
+        return nullptr;
+
+    return static_cast<WebFramePolicyListenerProxy*>(m_activeListener.get());
+}
+
 void WebFrameProxy::changeWebsiteDataStore(WebsiteDataStore& websiteDataStore)
 {
     if (!m_page)

Modified: trunk/Source/WebKit/UIProcess/WebFrameProxy.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebFrameProxy.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebFrameProxy.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -52,6 +52,7 @@
 class WebFramePolicyListenerProxy;
 class WebPageProxy;
 class WebsiteDataStore;
+enum class PolicyListenerType;
 struct WebsitePoliciesData;
 
 typedef GenericCallback<API::Data*> DataCallback;
@@ -116,7 +117,10 @@
 
     // Policy operations.
     void receivedPolicyDecision(WebCore::PolicyAction, uint64_t listenerID, API::Navigation*, std::optional<WebsitePoliciesData>&&);
-    WebFramePolicyListenerProxy& setUpPolicyListenerProxy(uint64_t listenerID);
+
+    WebFramePolicyListenerProxy& setUpPolicyListenerProxy(uint64_t listenerID, PolicyListenerType);
+    WebFramePolicyListenerProxy* activePolicyListenerProxy();
+
     void changeWebsiteDataStore(WebsiteDataStore&);
 
 #if ENABLE(CONTENT_FILTERING)

Modified: trunk/Source/WebKit/UIProcess/WebNavigationState.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebNavigationState.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebNavigationState.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -79,7 +79,8 @@
 API::Navigation& WebNavigationState::navigation(uint64_t navigationID)
 {
     ASSERT(navigationID);
-    
+    ASSERT(m_navigations.contains(navigationID));
+
     return *m_navigations.get(navigationID);
 }
 
@@ -86,6 +87,7 @@
 Ref<API::Navigation> WebNavigationState::takeNavigation(uint64_t navigationID)
 {
     ASSERT(navigationID);
+    ASSERT(m_navigations.contains(navigationID));
     
     return m_navigations.take(navigationID).releaseNonNull();
 }

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -639,15 +639,31 @@
 
 void WebPageProxy::reattachToWebProcess()
 {
+    auto process = makeRef(m_process->processPool().createNewWebProcessRespectingProcessCountLimit(m_websiteDataStore.get()));
+    reattachToWebProcess(WTFMove(process));
+}
+
+void WebPageProxy::attachToProcessForNavigation(Ref<WebProcessProxy>&& process)
+{
+    // FIXME: If this WebPageProxy is the only one hosted in its WebProcess, does this make it go away?
+    // We need to be prepared to reuse it later.
+    processDidTerminate(ProcessTerminationReason::NavigationSwap);
+
+    // FIXME: this is to fix the ASSERT(isValid()) inside reattachToWebProcess, some other way to fix this is needed.
+    m_isValid = false;
+    reattachToWebProcess(WTFMove(process));
+}
+
+void WebPageProxy::reattachToWebProcess(Ref<WebProcessProxy>&& process)
+{
     ASSERT(!m_isClosed);
     ASSERT(!isValid());
-    ASSERT(m_process->state() == WebProcessProxy::State::Terminated);
 
     m_isValid = true;
     m_process->removeWebPage(*this, m_pageID);
     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
 
-    m_process = m_process->processPool().createNewWebProcessRespectingProcessCountLimit(m_websiteDataStore.get());
+    m_process = WTFMove(process);
 
     ASSERT(m_process->state() != ChildProcessProxy::State::Terminated);
     if (m_process->state() == ChildProcessProxy::State::Running)
@@ -874,7 +890,14 @@
         return nullptr;
 
     auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
+    loadRequestWithNavigation(navigation.get(), WTFMove(request), shouldOpenExternalURLsPolicy, userData, NavigationPolicyCheck::Require);
+    return WTFMove(navigation);
+}
 
+void WebPageProxy::loadRequestWithNavigation(API::Navigation& navigation, ResourceRequest&& request, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, API::Object* userData, NavigationPolicyCheck navigationPolicyCheck)
+{
+    ASSERT(!m_isClosed);
+
     auto transaction = m_pageLoadState.transaction();
 
     auto url = ""
@@ -884,10 +907,11 @@
         reattachToWebProcess();
 
     LoadParameters loadParameters;
-    loadParameters.navigationID = navigation->navigationID();
+    loadParameters.navigationID = navigation.navigationID();
     loadParameters.request = WTFMove(request);
     loadParameters.shouldOpenExternalURLsPolicy = (uint64_t)shouldOpenExternalURLsPolicy;
     loadParameters.userData = UserData(process().transformObjectsToHandles(userData).get());
+    loadParameters.shouldCheckNavigationPolicy = navigationPolicyCheck == NavigationPolicyCheck::Require;
     bool createdExtension = maybeInitializeSandboxExtensionHandle(url, loadParameters.sandboxExtensionHandle);
     if (createdExtension)
         m_process->willAcquireUniversalFileReadSandboxExtension();
@@ -895,8 +919,6 @@
 
     m_process->send(Messages::WebPage::LoadRequest(loadParameters), m_pageID);
     m_process->responsivenessTimer().start();
-
-    return WTFMove(navigation);
 }
 
 RefPtr<API::Navigation> WebPageProxy::loadFile(const String& fileURLString, const String& resourceDirectoryURLString, API::Object* userData)
@@ -2355,6 +2377,21 @@
         return;
     }
 
+    auto* activePolicyListener = frame.activePolicyListenerProxy();
+    if (activePolicyListener) {
+        ASSERT(activePolicyListener->listenerID() == listenerID);
+
+        if (action == PolicyAction::Use && navigation) {
+            auto proposedProcess = process().processPool().processForNavigation(*this, navigation->request().url());
+            if (proposedProcess.ptr() != &process()) {
+                action = ""
+                RunLoop::main().dispatch([this, protectedThis = makeRef(*this), navigation = makeRef(*navigation), proposedProcess = WTFMove(proposedProcess)]() mutable {
+                    continueNavigationInNewProcess(navigation.get(), WTFMove(proposedProcess));
+                });
+            }
+        }
+    }
+
     // If we received a policy decision while in decidePolicyForNavigationAction the decision will 
     // be sent back to the web process by decidePolicyForNavigationAction. 
     if (m_inDecidePolicyForNavigationAction) {
@@ -2368,6 +2405,16 @@
     m_process->send(Messages::WebPage::DidReceivePolicyDecision(frame.frameID(), listenerID, action, navigation ? navigation->navigationID() : 0, downloadID, websitePolicies), m_pageID);
 }
 
+void WebPageProxy::continueNavigationInNewProcess(API::Navigation& navigation, Ref<WebProcessProxy>&& process)
+{
+    LOG(Loading, "Continuing navigation %" PRIu64 " to URL %s in a new web process", navigation.navigationID(), navigation.request().url().string().utf8().data());
+
+    attachToProcessForNavigation(WTFMove(process));
+
+    // FIXME: Work out timing of responding with the last policy delegate, etc
+    loadRequestWithNavigation(navigation, ResourceRequest { navigation.request() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, NavigationPolicyCheck::Bypass);
+}
+
 void WebPageProxy::setUserAgent(String&& userAgent)
 {
     if (m_userAgent == userAgent)
@@ -3768,6 +3815,8 @@
 
 void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const SecurityOriginData& frameSecurityOrigin, uint64_t navigationID, NavigationActionData&& navigationActionData, const FrameInfoData& originatingFrameInfoData, uint64_t originatingPageID, const WebCore::ResourceRequest& originalRequest, ResourceRequest&& request, uint64_t listenerID, const UserData& userData, bool& receivedPolicyAction, uint64_t& newNavigationID, WebCore::PolicyAction& policyAction, DownloadID& downloadID, std::optional<WebsitePoliciesData>& websitePolicies)
 {
+    LOG(Loading, "WebPageProxy::didStartProvisionalLoadForFrame - Target url %s", originalRequest.url().string().utf8().data());
+
     PageClientProtector protector(m_pageClient);
 
     auto transaction = m_pageLoadState.transaction();
@@ -3781,7 +3830,7 @@
     MESSAGE_CHECK_URL(request.url());
     MESSAGE_CHECK_URL(originalRequest.url());
     
-    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
+    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NavigationAction);
     if (!navigationID) {
         auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
         newNavigationID = navigation->navigationID();
@@ -3847,7 +3896,7 @@
     MESSAGE_CHECK(frame);
     MESSAGE_CHECK_URL(request.url());
 
-    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
+    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NewWindowAction);
 
     if (m_navigationClient) {
         RefPtr<API::FrameInfo> sourceFrameInfo;
@@ -3873,9 +3922,11 @@
     MESSAGE_CHECK_URL(request.url());
     MESSAGE_CHECK_URL(response.url());
 
-    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID);
-    if (navigationID)
-        listener->setNavigation(m_navigationState->navigation(navigationID));
+    Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::Response);
+    if (navigationID) {
+        auto& navigation = m_navigationState->navigation(navigationID);
+        listener->setNavigation(navigation);
+    }
 
     if (m_navigationClient) {
         auto navigationResponse = API::NavigationResponse::create(API::FrameInfo::create(*frame, frameSecurityOrigin.securityOrigin()).get(), request, response, canShowMIMEType);
@@ -5590,14 +5641,19 @@
     // There is a nested transaction in resetStateAfterProcessExited() that we don't want to commit before the client call.
     PageLoadState::Transaction transaction = m_pageLoadState.transaction();
 
-    resetStateAfterProcessExited();
+    resetStateAfterProcessExited(reason);
 
-    navigationState().clearAllNavigations();
+    // For bringup of process swapping, NavigationSwap termination will not go out to clients.
+    // If it does *during* process swapping, and the client triggers a reload, that causes bizarre WebKit re-entry.
+    // FIXME: This might have to change
+    if (reason != ProcessTerminationReason::NavigationSwap) {
+        navigationState().clearAllNavigations();
 
-    if (m_navigationClient)
-        m_navigationClient->processDidTerminate(*this, reason);
-    else if (reason != ProcessTerminationReason::RequestedByClient)
-        m_loaderClient->processDidCrash(*this);
+        if (m_navigationClient)
+            m_navigationClient->processDidTerminate(*this, reason);
+        else if (reason != ProcessTerminationReason::RequestedByClient)
+            m_loaderClient->processDidCrash(*this);
+    }
 
     if (m_controlledByAutomation) {
         if (auto* automationSession = process().processPool().automationSession())
@@ -5737,10 +5793,11 @@
 
     CallbackBase::Error error;
     switch (resetStateReason) {
+    case ResetStateReason::NavigationSwap:
+        FALLTHROUGH;
     case ResetStateReason::PageInvalidated:
         error = CallbackBase::Error::OwnerWasInvalidated;
         break;
-
     case ResetStateReason::WebProcessExited:
         error = CallbackBase::Error::ProcessExited;
         break;
@@ -5763,13 +5820,16 @@
 #endif
 }
 
-void WebPageProxy::resetStateAfterProcessExited()
+void WebPageProxy::resetStateAfterProcessExited(ProcessTerminationReason terminationReason)
 {
     if (!isValid())
         return;
 
+#if !ASSERT_DISABLED
     // FIXME: It's weird that resetStateAfterProcessExited() is called even though the process is launching.
-    ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated);
+    if (terminationReason != ProcessTerminationReason::NavigationSwap)
+        ASSERT(m_process->state() == WebProcessProxy::State::Launching || m_process->state() == WebProcessProxy::State::Terminated);
+#endif
 
 #if PLATFORM(IOS)
     m_activityToken = nullptr;
@@ -5786,7 +5846,8 @@
 
     m_pageClient.processDidExit();
 
-    resetState(ResetStateReason::WebProcessExited);
+    auto resetStateReason = terminationReason == ProcessTerminationReason::NavigationSwap ? ResetStateReason::NavigationSwap : ResetStateReason::WebProcessExited;
+    resetState(resetStateReason);
 
     m_pageClient.clearAllEditCommands();
     m_pendingLearnOrIgnoreWordMessageCount = 0;

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1305,9 +1305,10 @@
     enum class ResetStateReason {
         PageInvalidated,
         WebProcessExited,
+        NavigationSwap,
     };
     void resetState(ResetStateReason);
-    void resetStateAfterProcessExited();
+    void resetStateAfterProcessExited(ProcessTerminationReason);
 
     void setUserAgent(String&&);
 
@@ -1441,9 +1442,18 @@
     void setCanShortCircuitHorizontalWheelEvents(bool canShortCircuitHorizontalWheelEvents) { m_canShortCircuitHorizontalWheelEvents = canShortCircuitHorizontalWheelEvents; }
 
     void reattachToWebProcess();
+    void attachToProcessForNavigation(Ref<WebProcessProxy>&&);
+    void reattachToWebProcess(Ref<WebProcessProxy>&&);
+
     RefPtr<API::Navigation> reattachToWebProcessForReload();
     RefPtr<API::Navigation> reattachToWebProcessWithItem(WebBackForwardListItem*);
 
+    enum class NavigationPolicyCheck {
+        Require,
+        Bypass,
+    };
+    void loadRequestWithNavigation(API::Navigation&, WebCore::ResourceRequest&&, WebCore::ShouldOpenExternalURLsPolicy, API::Object* userData, NavigationPolicyCheck);
+
     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);
@@ -1685,7 +1695,6 @@
     void contentFilterDidBlockLoadForFrame(const WebCore::ContentFilterUnblockHandler&, uint64_t frameID);
 #endif
 
-    uint64_t generateNavigationID();
     API::DiagnosticLoggingClient* effectiveDiagnosticLoggingClient(WebCore::ShouldSample);
 
     void dispatchActivityStateChange();
@@ -1732,6 +1741,8 @@
 
     void reportPageLoadResult(const WebCore::ResourceError& = { });
 
+    void continueNavigationInNewProcess(API::Navigation&, Ref<WebProcessProxy>&&);
+
     PageClient& m_pageClient;
     Ref<API::PageConfiguration> m_configuration;
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1940,4 +1940,16 @@
 }
 #endif
 
+Ref<WebProcessProxy> WebProcessPool::processForNavigation(WebPageProxy& page, const URL& targetURL)
+{
+    if (!m_configuration->processSwapsOnNavigation())
+        return page.process();
+
+    auto url = "" { ParsedURLString, page.pageLoadState().url() };
+    if (protocolHostAndPortAreEqual(url, targetURL) || url.isBlankURL())
+        return page.process();
+
+    return createNewWebProcess(page.websiteDataStore());
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -442,6 +442,8 @@
     BackgroundWebProcessToken backgroundWebProcessToken() const { return BackgroundWebProcessToken(m_backgroundWebProcessCounter.count()); }
 #endif
 
+    Ref<WebProcessProxy> processForNavigation(WebPageProxy&, const WebCore::URL&);
+
 private:
     void platformInitialize();
 

Modified: trunk/Source/WebKit/UIProcess/WebStorage/StorageManager.cpp (229777 => 229778)


--- trunk/Source/WebKit/UIProcess/WebStorage/StorageManager.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/UIProcess/WebStorage/StorageManager.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -425,8 +425,6 @@
 
 void StorageManager::SessionStorageNamespace::setAllowedConnection(IPC::Connection* allowedConnection)
 {
-    ASSERT(!allowedConnection || !m_allowedConnection);
-
     m_allowedConnection = allowedConnection;
 }
 

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (229777 => 229778)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1261,6 +1261,7 @@
     FrameLoadRequest frameLoadRequest { *m_mainFrame->coreFrame(), loadParameters.request, ShouldOpenExternalURLsPolicy::ShouldNotAllow };
     ShouldOpenExternalURLsPolicy externalURLsPolicy = static_cast<ShouldOpenExternalURLsPolicy>(loadParameters.shouldOpenExternalURLsPolicy);
     frameLoadRequest.setShouldOpenExternalURLsPolicy(externalURLsPolicy);
+    frameLoadRequest.setShouldCheckNavigationPolicy(loadParameters.shouldCheckNavigationPolicy);
 
     corePage()->userInputBridge().loadRequest(WTFMove(frameLoadRequest));
 

Modified: trunk/Tools/ChangeLog (229777 => 229778)


--- trunk/Tools/ChangeLog	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Tools/ChangeLog	2018-03-21 00:05:58 UTC (rev 229778)
@@ -1,3 +1,29 @@
+2018-03-20  Brady Eidson  <beid...@apple.com>
+
+        First piece of process swapping on navigation.
+        https://bugs.webkit.org/show_bug.cgi?id=183665
+
+        Reviewed by Andy Estes.
+
+        Expose the "swaps processes on navigation" setting in MiniBrowser UI for testing:
+
+        * MiniBrowser/mac/AppDelegate.m:
+        (defaultConfiguration):
+        * MiniBrowser/mac/SettingsController.h:
+        * MiniBrowser/mac/SettingsController.m:
+        (-[SettingsController _populateMenu]):
+        (-[SettingsController validateMenuItem:]):
+        (-[SettingsController processSwapOnNavigationEnabled]):
+        (-[SettingsController toggleProcessSwapOnNavigation:]):
+
+        Makes sure the current behavior is tested:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm: Added.
+        (-[PSONNavigationDelegate webView:didFinishNavigation:]):
+        (-[PSONScheme webView:startURLSchemeTask:]):
+        (-[PSONScheme webView:stopURLSchemeTask:]):
+        (TEST):
+
 2018-03-20  Chris Dumez  <cdu...@apple.com>
 
         QuickLook.NavigationDelegate API test is failing on iOS with async policy delegates

Modified: trunk/Tools/MiniBrowser/mac/AppDelegate.m (229777 => 229778)


--- trunk/Tools/MiniBrowser/mac/AppDelegate.m	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Tools/MiniBrowser/mac/AppDelegate.m	2018-03-21 00:05:58 UTC (rev 229778)
@@ -98,6 +98,8 @@
         processConfiguration.diskCacheSpeculativeValidationEnabled = ![SettingsController shared].networkCacheSpeculativeRevalidationDisabled;
         if ([SettingsController shared].perWindowWebProcessesDisabled)
             processConfiguration.maximumProcessCount = 1;
+        if ([SettingsController shared].processSwapOnNavigationEnabled)
+            processConfiguration.processSwapsOnNavigation = true;
         
         configuration.processPool = [[[WKProcessPool alloc] _initWithConfiguration:processConfiguration] autorelease];
 

Modified: trunk/Tools/MiniBrowser/mac/SettingsController.h (229777 => 229778)


--- trunk/Tools/MiniBrowser/mac/SettingsController.h	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.h	2018-03-21 00:05:58 UTC (rev 229778)
@@ -59,6 +59,7 @@
 @property (nonatomic, readonly) BOOL loadsAllSiteIcons;
 @property (nonatomic, readonly) BOOL usesGameControllerFramework;
 @property (nonatomic, readonly) BOOL networkCacheSpeculativeRevalidationDisabled;
+@property (nonatomic, readonly) BOOL processSwapOnNavigationEnabled;
 
 @property (nonatomic, readonly) NSString *defaultURL;
 

Modified: trunk/Tools/MiniBrowser/mac/SettingsController.m (229777 => 229778)


--- trunk/Tools/MiniBrowser/mac/SettingsController.m	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Tools/MiniBrowser/mac/SettingsController.m	2018-03-21 00:05:58 UTC (rev 229778)
@@ -70,6 +70,7 @@
 
 static NSString * const PerWindowWebProcessesDisabledKey = @"PerWindowWebProcessesDisabled";
 static NSString * const NetworkCacheSpeculativeRevalidationDisabledKey = @"NetworkCacheSpeculativeRevalidationDisabled";
+static NSString * const ProcessSwapOnNavigationKey = @"ProcessSwapOnNavigation";
 
 typedef NS_ENUM(NSInteger, DebugOverylayMenuItemTag) {
     NonFastScrollableRegionOverlayTag = 100,
@@ -179,6 +180,7 @@
     [self _addItemWithTitle:@"Load All Site Icons Per-Page" action:@selector(toggleLoadsAllSiteIcons:) indented:YES];
     [self _addItemWithTitle:@"Use GameController.framework on macOS (Restart required)" action:@selector(toggleUsesGameControllerFramework:) indented:YES];
     [self _addItemWithTitle:@"Disable network cache speculative revalidation" action:@selector(toggleNetworkCacheSpeculativeRevalidationDisabled:) indented:YES];
+    [self _addItemWithTitle:@"Enable Process Swap on Navigation" action:@selector(toggleProcessSwapOnNavigation:) indented:YES];
 
     NSMenuItem *debugOverlaysSubmenuItem = [[NSMenuItem alloc] initWithTitle:@"Debug Overlays" action:nil keyEquivalent:@""];
     NSMenu *debugOverlaysMenu = [[NSMenu alloc] initWithTitle:@"Debug Overlays"];
@@ -270,6 +272,8 @@
         [menuItem setState:[self usesGameControllerFramework] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(toggleNetworkCacheSpeculativeRevalidationDisabled:))
         [menuItem setState:[self networkCacheSpeculativeRevalidationDisabled] ? NSControlStateValueOn : NSControlStateValueOff];
+    else if (action == @selector(toggleProcessSwapOnNavigation:))
+        [menuItem setState:[self processSwapOnNavigationEnabled] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(toggleUseUISideCompositing:))
         [menuItem setState:[self useUISideCompositing] ? NSControlStateValueOn : NSControlStateValueOff];
     else if (action == @selector(togglePerWindowWebProcessesDisabled:))
@@ -485,6 +489,16 @@
     [self _toggleBooleanDefault:NetworkCacheSpeculativeRevalidationDisabledKey];
 }
 
+- (BOOL)processSwapOnNavigationEnabled
+{
+    return [[NSUserDefaults standardUserDefaults] boolForKey:ProcessSwapOnNavigationKey];
+}
+
+- (void)toggleProcessSwapOnNavigation:(id)sender
+{
+    [self _toggleBooleanDefault:ProcessSwapOnNavigationKey];
+}
+
 - (BOOL)isSpaceReservedForBanners
 {
     return [[NSUserDefaults standardUserDefaults] boolForKey:ReserveSpaceForBannersPreferenceKey];

Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (229777 => 229778)


--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-03-20 23:10:36 UTC (rev 229777)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-03-21 00:05:58 UTC (rev 229778)
@@ -183,6 +183,7 @@
 		51714EB81CF8CA17004723C4 /* WebProcessKillIDBCleanup.mm in Sources */ = {isa = PBXBuildFile; fileRef = 51714EB61CF8C7A4004723C4 /* WebProcessKillIDBCleanup.mm */; };
 		517E7E04151119C100D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */; };
 		5182C22E1F2BCE540059BA7C /* WKURLSchemeHandler-leaks.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5182C22D1F2BCB410059BA7C /* WKURLSchemeHandler-leaks.mm */; };
+		518C1153205B0504001FF4AE /* ProcessSwapOnNavigation.mm in Sources */ = {isa = PBXBuildFile; fileRef = 518C1152205B04F9001FF4AE /* ProcessSwapOnNavigation.mm */; };
 		5198A2401EA7E59F008910B7 /* InitialWarmedProcessUsed.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5198A23F1EA7E595008910B7 /* InitialWarmedProcessUsed.mm */; };
 		51A5877D1D1B49CD004BA9AF /* IndexedDBMultiProcess-3.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51A5877C1D1B3D8D004BA9AF /* IndexedDBMultiProcess-3.html */; };
 		51A587851D2739E3004BA9AF /* IndexedDBDatabaseProcessKill-1.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 51A587821D272EB5004BA9AF /* IndexedDBDatabaseProcessKill-1.html */; };
@@ -1363,6 +1364,7 @@
 		517E7DFB15110EA600D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MemoryCachePruneWithinResourceLoadDelegate.mm; sourceTree = "<group>"; };
 		517E7E031511187500D0B008 /* MemoryCachePruneWithinResourceLoadDelegate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = MemoryCachePruneWithinResourceLoadDelegate.html; sourceTree = "<group>"; };
 		5182C22D1F2BCB410059BA7C /* WKURLSchemeHandler-leaks.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "WKURLSchemeHandler-leaks.mm"; sourceTree = "<group>"; };
+		518C1152205B04F9001FF4AE /* ProcessSwapOnNavigation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProcessSwapOnNavigation.mm; sourceTree = "<group>"; };
 		5198A23F1EA7E595008910B7 /* InitialWarmedProcessUsed.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = InitialWarmedProcessUsed.mm; sourceTree = "<group>"; };
 		51A5877C1D1B3D8D004BA9AF /* IndexedDBMultiProcess-3.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBMultiProcess-3.html"; sourceTree = "<group>"; };
 		51A587821D272EB5004BA9AF /* IndexedDBDatabaseProcessKill-1.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "IndexedDBDatabaseProcessKill-1.html"; sourceTree = "<group>"; };
@@ -2177,6 +2179,7 @@
 				83BAEE8C1EF4625500DDE894 /* PluginLoadClientPolicies.mm */,
 				C95501BE19AD2FAF0049BE3E /* Preferences.mm */,
 				7C1AF7931E8DCBAB002645B9 /* PrepareForMoveToWindow.mm */,
+				518C1152205B04F9001FF4AE /* ProcessSwapOnNavigation.mm */,
 				5798E2AF1CAF5C2800C5CBA0 /* ProvisionalURLNotChange.mm */,
 				A1C4FB6C1BACCE50003742D0 /* QuickLook.mm */,
 				1A4F81D01BDFFDCF004E672E /* RemoteObjectRegistry.h */,
@@ -3736,6 +3739,7 @@
 				7CCE7F2F1A411B1000447C4C /* WKBrowsingContextLoadDelegateTest.mm in Sources */,
 				7C54A4BE1AA11CCA00380F78 /* WKBundleFileHandle.cpp in Sources */,
 				5CE354D91E70DA5C00BEFE3B /* WKContentExtensionStore.mm in Sources */,
+				518C1153205B0504001FF4AE /* ProcessSwapOnNavigation.mm in Sources */,
 				2D838B1F1EEF3A5C009B980E /* WKContentViewEditingActions.mm in Sources */,
 				370CE22A1F57343400E7410B /* WKContentViewTargetForAction.mm in Sources */,
 				51D124981E763B02002B2820 /* WKHTTPCookieStore.mm in Sources */,

Added: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (0 => 229778)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	                        (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2018-03-21 00:05:58 UTC (rev 229778)
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#import "config.h"
+
+#import "PlatformUtilities.h"
+#import "Test.h"
+#import <WebKit/WKNavigationDelegate.h>
+#import <WebKit/WKPreferencesPrivate.h>
+#import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKURLSchemeHandler.h>
+#import <WebKit/WKURLSchemeTaskPrivate.h>
+#import <WebKit/WKWebViewConfigurationPrivate.h>
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/WKWebsiteDataStorePrivate.h>
+#import <WebKit/WKWebsiteDataStoreRef.h>
+#import <WebKit/WebKit.h>
+#import <WebKit/_WKExperimentalFeature.h>
+#import <WebKit/_WKProcessPoolConfiguration.h>
+#import <WebKit/_WKWebsiteDataStoreConfiguration.h>
+#import <wtf/Deque.h>
+#import <wtf/HashMap.h>
+#import <wtf/RetainPtr.h>
+#import <wtf/Vector.h>
+#import <wtf/text/StringHash.h>
+#import <wtf/text/WTFString.h>
+
+#if WK_API_ENABLED
+
+static bool done;
+static int numberOfDecidePolicyCalls;
+
+@interface PSONNavigationDelegate : NSObject <WKNavigationDelegate>
+@end
+
+@implementation PSONNavigationDelegate
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
+{
+    done = true;
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+{
+    ++numberOfDecidePolicyCalls;
+    decisionHandler(WKNavigationActionPolicyAllow);
+}
+
+@end
+
+@interface PSONScheme : NSObject <WKURLSchemeHandler> {
+}
+@end
+
+@implementation PSONScheme
+
+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
+{
+    RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
+    [task didReceiveResponse:response.get()];
+    [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
+    [task didFinish];
+}
+
+- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
+{
+}
+
+@end
+
+TEST(ProcessSwap, Basic)
+{
+    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()];
+    RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
+    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:delegate.get()];
+
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pid1 = [webView _webProcessIdentifier];
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main2.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pid2 = [webView _webProcessIdentifier];
+
+    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    auto pid3 = [webView _webProcessIdentifier];
+
+    EXPECT_EQ(pid1, pid2);
+    EXPECT_FALSE(pid2 == pid3);
+
+    // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
+    EXPECT_EQ(numberOfDecidePolicyCalls, 3);
+}
+
+#endif // WK_API_ENABLED
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to