PSON: Don't create a new process when navigating to a blob URL, data URL, and about...
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Apr 2018 20:48:03 +0000 (20:48 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 25 Apr 2018 20:48:03 +0000 (20:48 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184962

Reviewed by Youenn Fablet.

Source/WebCore:

Added NavigationAction::treatAsSameOriginNavigation, which signifies WebKit code to avoid creating
a new WebContent process when navigating to a blob URL, data URL, and about:blank.

Tests: ProcessSwap.SameOriginBlobNavigation
       ProcessSwap.CrossOriginBlobNavigation
       ProcessSwap.NavigateToAboutBlank
       ProcessSwap.NavigateToDataURL

* loader/NavigationAction.cpp:
(WebCore::treatAsSameOriginNavigation):
* loader/NavigationAction.h:
(WebCore::NavigationAction::treatAsSameOriginNavigation const):

Source/WebKit:

Don't create a new WebContent process when navigating to a blob object URL since doing so
can result in a race condition in which the blog URL is removed from the blob registry of
the network process by the time the navigation gets commited. This causes a failure in
fast/dom/HTMLAnchorElement/anchor-download-unset.html and oher layout tests.

In the future, the network process should verify that a given WebContent process has access
to a given blob URL. For now, we rely on WebContent process to tell us whether it can
navigate to a given blob URL or not.

* Shared/NavigationActionData.cpp:
(WebKit::NavigationActionData::encode const): Encode newly added treatAsSameOriginNavigation.
(WebKit::NavigationActionData::decode): Ditto for decoding.
* Shared/NavigationActionData.h:
(WebKit::NavigationActionData::treatAsSameOriginNavigation): Added.
* UIProcess/API/APINavigation.h:
(API::Navigation::setTreatAsSameOriginNavigation): Added.
(API::Navigation::treatAsSameOriginNavigation const): Added.
* UIProcess/API/APIProcessPoolConfiguration.h:
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::decidePolicyForNavigationAction): Use the current process when
treatAsSameOriginNavigation is set to true; i.e. when navigating to a blob URL the current
document has access.
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigation):
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):

Tools:

Added four test cases for navigating to a blob URL, data URL, and about:blank with process-swap-on-navigation turned on.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
(ProcessSwap.SameOriginBlobNavigation): Added.
(ProcessSwap.CrossOriginBlobNavigation): Added.
(ProcessSwap.NavigateToAboutBlank): Added.
(ProcessSwap.NavigateToDataURL): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@231019 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
Source/WebCore/ChangeLog
Source/WebCore/loader/NavigationAction.cpp
Source/WebCore/loader/NavigationAction.h
Source/WebKit/ChangeLog
Source/WebKit/Shared/NavigationActionData.cpp
Source/WebKit/Shared/NavigationActionData.h
Source/WebKit/UIProcess/API/APINavigation.h
Source/WebKit/UIProcess/WebPageProxy.cpp
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

index 122bbcd..bd45321 100644 (file)
@@ -1,3 +1,23 @@
+2018-04-25  Ryosuke Niwa  <rniwa@webkit.org>
+
+        PSON: Don't create a new process when navigating to a blob URL, data URL, and about:blank
+        https://bugs.webkit.org/show_bug.cgi?id=184962
+
+        Reviewed by Youenn Fablet.
+
+        Added NavigationAction::treatAsSameOriginNavigation, which signifies WebKit code to avoid creating
+        a new WebContent process when navigating to a blob URL, data URL, and about:blank.
+
+        Tests: ProcessSwap.SameOriginBlobNavigation
+               ProcessSwap.CrossOriginBlobNavigation
+               ProcessSwap.NavigateToAboutBlank
+               ProcessSwap.NavigateToDataURL
+
+        * loader/NavigationAction.cpp:
+        (WebCore::treatAsSameOriginNavigation):
+        * loader/NavigationAction.h:
+        (WebCore::NavigationAction::treatAsSameOriginNavigation const):
+
 2018-04-25  Zalan Bujtas  <zalan@apple.com>
 
         [LFC] Implement Layout::BlockContainer functions.
index 7514b34..71f13fc 100644 (file)
@@ -44,6 +44,13 @@ NavigationAction::NavigationAction(NavigationAction&&) = default;
 NavigationAction& NavigationAction::operator=(const NavigationAction&) = default;
 NavigationAction& NavigationAction::operator=(NavigationAction&&) = default;
 
+static bool shouldTreatAsSameOriginNavigation(Document& source, const URL& url)
+{
+    return url.isBlankURL()
+        || url.protocolIsData()
+        || (url.protocolIsBlob() && source.securityOrigin().canRequest(url));
+}
+
 NavigationAction::NavigationAction(Document& source, const ResourceRequest& resourceRequest, InitiatedByMainFrame initiatedByMainFrame, NavigationType type, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy, Event* event, const AtomicString& downloadAttribute)
     : m_sourceDocument { makeRefPtr(source) }
     , m_resourceRequest { resourceRequest }
@@ -52,6 +59,7 @@ NavigationAction::NavigationAction(Document& source, const ResourceRequest& reso
     , m_initiatedByMainFrame { initiatedByMainFrame }
     , m_event { event }
     , m_downloadAttribute { downloadAttribute }
+    , m_treatAsSameOriginNavigation { shouldTreatAsSameOriginNavigation(source, resourceRequest.url()) }
 {
 }
 
@@ -76,6 +84,7 @@ NavigationAction::NavigationAction(Document& source, const ResourceRequest& reso
     , m_initiatedByMainFrame { initiatedByMainFrame }
     , m_event { event }
     , m_downloadAttribute { downloadAttribute }
+    , m_treatAsSameOriginNavigation { shouldTreatAsSameOriginNavigation(source, resourceRequest.url()) }
 {
 }
 
index a80a70c..a5af334 100644 (file)
@@ -72,6 +72,8 @@ public:
 
     const AtomicString& downloadAttribute() const { return m_downloadAttribute; }
 
+    bool treatAsSameOriginNavigation() const { return m_treatAsSameOriginNavigation; }
+
     void setIsCrossOriginWindowOpenNavigation(bool value) { m_isCrossOriginWindowOpenNavigation = value; }
     bool isCrossOriginWindowOpenNavigation() const { return m_isCrossOriginWindowOpenNavigation; }
 
@@ -87,6 +89,7 @@ private:
     RefPtr<Event> m_event;
     RefPtr<UserGestureToken> m_userGestureToken { UserGestureIndicator::currentUserGesture() };
     AtomicString m_downloadAttribute;
+    bool m_treatAsSameOriginNavigation;
     bool m_isCrossOriginWindowOpenNavigation { false };
     std::optional<std::pair<uint64_t /* pageID */, uint64_t /* frameID */>> m_opener;
 };
index a249ee6..c9f39d8 100644 (file)
@@ -1,3 +1,37 @@
+2018-04-25  Ryosuke Niwa  <rniwa@webkit.org>
+
+        PSON: Don't create a new process when navigating to a blob URL, data URL, and about:blank
+        https://bugs.webkit.org/show_bug.cgi?id=184962
+
+        Reviewed by Youenn Fablet.
+
+        Don't create a new WebContent process when navigating to a blob object URL since doing so
+        can result in a race condition in which the blog URL is removed from the blob registry of
+        the network process by the time the navigation gets commited. This causes a failure in
+        fast/dom/HTMLAnchorElement/anchor-download-unset.html and oher layout tests.
+
+        In the future, the network process should verify that a given WebContent process has access
+        to a given blob URL. For now, we rely on WebContent process to tell us whether it can
+        navigate to a given blob URL or not.
+
+        * Shared/NavigationActionData.cpp:
+        (WebKit::NavigationActionData::encode const): Encode newly added treatAsSameOriginNavigation.
+        (WebKit::NavigationActionData::decode): Ditto for decoding.
+        * Shared/NavigationActionData.h:
+        (WebKit::NavigationActionData::treatAsSameOriginNavigation): Added.
+        * UIProcess/API/APINavigation.h:
+        (API::Navigation::setTreatAsSameOriginNavigation): Added.
+        (API::Navigation::treatAsSameOriginNavigation const): Added.
+        * UIProcess/API/APIProcessPoolConfiguration.h:
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction): Use the current process when
+        treatAsSameOriginNavigation is set to true; i.e. when navigating to a blob URL the current
+        document has access.
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigation):
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+
 2018-04-25  Megan Gardner  <megan_gardner@apple.com>
 
         Don't activate Selection Assistant unless it is actually needed.
index 600ad59..5133c42 100644 (file)
@@ -47,6 +47,7 @@ void NavigationActionData::encode(IPC::Encoder& encoder) const
     encoder << downloadAttribute;
     encoder << clickLocationInRootViewCoordinates;
     encoder << isRedirect;
+    encoder << treatAsSameOriginNavigation;
     encoder << isCrossOriginWindowOpenNavigation;
     encoder << opener;
 }
@@ -97,6 +98,11 @@ std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& d
     if (!isRedirect)
         return std::nullopt;
 
+    std::optional<bool> treatAsSameOriginNavigation;
+    decoder >> treatAsSameOriginNavigation;
+    if (!treatAsSameOriginNavigation)
+        return std::nullopt;
+
     std::optional<bool> isCrossOriginWindowOpenNavigation;
     decoder >> isCrossOriginWindowOpenNavigation;
     if (!isCrossOriginWindowOpenNavigation)
@@ -107,7 +113,9 @@ std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& d
     if (!opener)
         return std::nullopt;
 
-    return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier), WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates), WTFMove(*isRedirect), *isCrossOriginWindowOpenNavigation, WTFMove(*opener) }};
+    return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier),
+        WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates),
+        WTFMove(*isRedirect), *treatAsSameOriginNavigation, *isCrossOriginWindowOpenNavigation, WTFMove(*opener) }};
 }
 
 } // namespace WebKit
index 32c2059..c231327 100644 (file)
@@ -50,6 +50,7 @@ struct NavigationActionData {
     WTF::String downloadAttribute;
     WebCore::FloatPoint clickLocationInRootViewCoordinates;
     bool isRedirect { false };
+    bool treatAsSameOriginNavigation { false };
     bool isCrossOriginWindowOpenNavigation { false };
     std::optional<std::pair<uint64_t, uint64_t>> opener;
 };
index 9632e2b..1ea94d6 100644 (file)
@@ -84,6 +84,9 @@ public:
     void setShouldForceDownload(bool value) { m_shouldForceDownload = value; }
     bool shouldForceDownload() const { return m_shouldForceDownload; }
 
+    void setTreatAsSameOriginNavigation(bool value) { m_treatAsSameOriginNavigation = value; }
+    bool treatAsSameOriginNavigation() const { return m_treatAsSameOriginNavigation; }
+
     void setIsCrossOriginWindowOpenNavigation(bool value) { m_isCrossOriginWindowOpenNavigation = value; }
     bool isCrossOriginWindowOpenNavigation() const { return m_isCrossOriginWindowOpenNavigation; }
 
@@ -111,6 +114,7 @@ private:
     RefPtr<WebKit::WebBackForwardListItem> m_targetItem;
     RefPtr<WebKit::WebBackForwardListItem> m_fromItem;
     std::optional<WebCore::FrameLoadType> m_backForwardFrameLoadType;
+    bool m_treatAsSameOriginNavigation { false };
     bool m_isCrossOriginWindowOpenNavigation { false };
     std::optional<std::pair<uint64_t, uint64_t>> m_opener;
 };
index 14de5c5..560b883 100644 (file)
@@ -3956,6 +3956,7 @@ void WebPageProxy::decidePolicyForNavigationAction(uint64_t frameID, const Secur
     navigation->setShouldForceDownload(!navigationActionData.downloadAttribute.isNull());
     navigation->setCurrentRequest(ResourceRequest(request), m_process->coreProcessIdentifier());
     navigation->setCurrentRequestIsRedirect(navigationActionData.isRedirect);
+    navigation->setTreatAsSameOriginNavigation(navigationActionData.treatAsSameOriginNavigation);
     navigation->setIsCrossOriginWindowOpenNavigation(navigationActionData.isCrossOriginWindowOpenNavigation);
     navigation->setOpener(navigationActionData.opener);
 
index 2ba440a..ccf4e1f 100644 (file)
@@ -2044,9 +2044,12 @@ Ref<WebProcessProxy> WebProcessPool::processForNavigation(WebPageProxy& page, co
         }
     }
 
+    if (navigation.treatAsSameOriginNavigation())
+        return page.process();
+
     auto targetURL = navigation.currentRequest().url();
     auto url = URL { ParsedURLString, page.pageLoadState().url() };
-    if (!url.isValid() || url.isEmpty() || url.isBlankURL() || protocolHostAndPortAreEqual(url, targetURL))
+    if (!url.isValid() || protocolHostAndPortAreEqual(url, targetURL))
         return page.process();
 
     action = PolicyAction::Suspend;
index ef1c419..7558073 100644 (file)
@@ -864,6 +864,7 @@ void WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction(const Navigat
     navigationActionData.shouldOpenExternalURLsPolicy = navigationAction.shouldOpenExternalURLsPolicy();
     navigationActionData.downloadAttribute = navigationAction.downloadAttribute();
     navigationActionData.isRedirect = didReceiveRedirectResponse;
+    navigationActionData.treatAsSameOriginNavigation = navigationAction.treatAsSameOriginNavigation();
     navigationActionData.isCrossOriginWindowOpenNavigation = navigationAction.isCrossOriginWindowOpenNavigation();
     navigationActionData.opener = navigationAction.opener();
 
index bb5f3ef..9397d24 100644 (file)
@@ -1,3 +1,18 @@
+2018-04-25  Ryosuke Niwa  <rniwa@webkit.org>
+
+        PSON: Don't create a new process when navigating to a blob URL, data URL, and about:blank
+        https://bugs.webkit.org/show_bug.cgi?id=184962
+
+        Reviewed by Youenn Fablet.
+
+        Added four test cases for navigating to a blob URL, data URL, and about:blank with process-swap-on-navigation turned on.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+        (ProcessSwap.SameOriginBlobNavigation): Added.
+        (ProcessSwap.CrossOriginBlobNavigation): Added.
+        (ProcessSwap.NavigateToAboutBlank): Added.
+        (ProcessSwap.NavigateToDataURL): Added.
+
 2018-04-25  Michael Catanzaro  <mcatanzaro@igalia.com>
 
         [WPE] Remove deprecated functions and properties from the API
index 72d88eb..3a37ecd 100644 (file)
@@ -1054,4 +1054,178 @@ TEST(ProcessSwap, LoadUnload)
 }
 #endif // !TARGET_OS_IPHONE
 
+static const char* sameOriginBlobNavigationTestBytes = R"PSONRESOURCE(
+<!DOCTYPE html>
+<html>
+<body>
+<p><a id="link">Click here</a></p>
+<script>
+const blob = new Blob(['<!DOCTYPE html><html><p>PASS</p></html>'], {type: 'text/html'});
+link.href = URL.createObjectURL(blob);
+</script>
+)PSONRESOURCE";
+
+TEST(ProcessSwap, SameOriginBlobNavigation)
+{
+    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] initWithBytes:sameOriginBlobNavigationTestBytes]);
+    [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()];
+    auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    numberOfDecidePolicyCalls = 0;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+
+    [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: nil];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid2 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+    EXPECT_EQ(pid1, pid2);
+}
+
+TEST(ProcessSwap, CrossOriginBlobNavigation)
+{
+    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] initWithBytes:sameOriginBlobNavigationTestBytes]);
+    [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 navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
+    [webView setNavigationDelegate:navigationDelegate.get()];
+    auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    numberOfDecidePolicyCalls = 0;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+
+    bool finishedRunningScript = false;
+    String blobURL;
+    [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').href" completionHandler: [&] (id result, NSError *error) {
+        blobURL = String([NSString stringWithFormat:@"%@", result]);
+        finishedRunningScript = true;
+    }];
+    TestWebKitAPI::Util::run(&finishedRunningScript);
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main1.html"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid2 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    finishedRunningScript = false;
+    String script = "document.getElementById('link').href = '" + blobURL + "'";
+    [webView _evaluateJavaScriptWithoutUserGesture:(NSString *)script completionHandler: [&] (id result, NSError *error) {
+        finishedRunningScript = true;
+    }];
+    TestWebKitAPI::Util::run(&finishedRunningScript);
+
+    // This navigation will fail.
+    [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: [&] (id result, NSError *error) {
+        done = true;
+    }];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid3 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid3);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+    EXPECT_NE(pid1, pid2);
+    EXPECT_EQ(pid2, pid3);
+}
+
+TEST(ProcessSwap, NavigateToAboutBlank)
+{
+    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] initWithBytes:sameOriginBlobNavigationTestBytes]);
+    [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()];
+    auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    numberOfDecidePolicyCalls = 0;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid2 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+    EXPECT_EQ(pid1, pid2);
+}
+
+TEST(ProcessSwap, NavigateToDataURL)
+{
+    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] initWithBytes:sameOriginBlobNavigationTestBytes]);
+    [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()];
+    auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
+    [webView setUIDelegate:uiDelegate.get()];
+
+    numberOfDecidePolicyCalls = 0;
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+
+    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"data:text/plain,PASS"]]];
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+    auto pid2 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+    EXPECT_EQ(pid1, pid2);
+}
+
 #endif // WK_API_ENABLED