Title: [230051] trunk
Revision
230051
Author
cdu...@apple.com
Date
2018-03-28 14:21:43 -0700 (Wed, 28 Mar 2018)

Log Message

Do process swap when opening a cross-origin URL via window.open(url, '_blank', 'noopener')
https://bugs.webkit.org/show_bug.cgi?id=183962
<rdar://problem/38817833>

Reviewed by Brady Eidson.

Source/WebCore:

Pass extra bits of information to the UIProcess via NavigationAction:
- Is it a cross origin navigation caused by window.open()
- Does the navigated frame have an opener

This information is useful to determine on UIProcess side if we want
to swap WebProcess.

* loader/FrameLoadRequest.h:
(WebCore::FrameLoadRequest::setIsCrossOriginWindowOpenNavigation):
(WebCore::FrameLoadRequest::isCrossOriginWindowOpenNavigation const):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::loadURL):
* loader/NavigationAction.h:
(WebCore::NavigationAction::setIsCrossOriginWindowOpenNavigation):
(WebCore::NavigationAction::isCrossOriginWindowOpenNavigation const):
(WebCore::NavigationAction::setOpener):
(WebCore::NavigationAction::opener const):
* page/DOMWindow.cpp:
(WebCore::DOMWindow::createWindow):

Source/WebKit:

Swap WebProcess on for the initial navigation in a new Window that was opened
via window.open(), when the new URL is cross-origin compared to the opener's
origin. For now, we only swap process if 'noopener' property is set when calling
window.open(). This is because we do not support the remote DOMWindows yet.

* Shared/NavigationActionData.cpp:
(WebKit::NavigationActionData::encode const):
(WebKit::NavigationActionData::decode):
* Shared/NavigationActionData.h:
* UIProcess/API/APINavigation.h:
(API::Navigation::setIsCrossOriginWindowOpenNavigation):
(API::Navigation::isCrossOriginWindowOpenNavigation const):
(API::Navigation::setOpener):
(API::Navigation::opener const):
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::decidePolicyForNavigationAction):
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::processForNavigation):
* UIProcess/WebProcessPool.h:
* WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
(WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):

Tools:

Add API test coverage.

* TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
(-[PSONUIDelegate initWithNavigationDelegate:]):
(-[PSONUIDelegate webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (230050 => 230051)


--- trunk/Source/WebCore/ChangeLog	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebCore/ChangeLog	2018-03-28 21:21:43 UTC (rev 230051)
@@ -1,5 +1,33 @@
 2018-03-28  Chris Dumez  <cdu...@apple.com>
 
+        Do process swap when opening a cross-origin URL via window.open(url, '_blank', 'noopener')
+        https://bugs.webkit.org/show_bug.cgi?id=183962
+        <rdar://problem/38817833>
+
+        Reviewed by Brady Eidson.
+
+        Pass extra bits of information to the UIProcess via NavigationAction:
+        - Is it a cross origin navigation caused by window.open()
+        - Does the navigated frame have an opener
+
+        This information is useful to determine on UIProcess side if we want
+        to swap WebProcess.
+
+        * loader/FrameLoadRequest.h:
+        (WebCore::FrameLoadRequest::setIsCrossOriginWindowOpenNavigation):
+        (WebCore::FrameLoadRequest::isCrossOriginWindowOpenNavigation const):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::loadURL):
+        * loader/NavigationAction.h:
+        (WebCore::NavigationAction::setIsCrossOriginWindowOpenNavigation):
+        (WebCore::NavigationAction::isCrossOriginWindowOpenNavigation const):
+        (WebCore::NavigationAction::setOpener):
+        (WebCore::NavigationAction::opener const):
+        * page/DOMWindow.cpp:
+        (WebCore::DOMWindow::createWindow):
+
+2018-03-28  Chris Dumez  <cdu...@apple.com>
+
         Thread safety issue in IDBFactory' shouldThrowSecurityException()
         https://bugs.webkit.org/show_bug.cgi?id=184064
 

Modified: trunk/Source/WebCore/loader/FrameLoadRequest.h (230050 => 230051)


--- trunk/Source/WebCore/loader/FrameLoadRequest.h	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebCore/loader/FrameLoadRequest.h	2018-03-28 21:21:43 UTC (rev 230051)
@@ -84,6 +84,9 @@
 
     InitiatedByMainFrame initiatedByMainFrame() const { return m_initiatedByMainFrame; }
 
+    void setIsCrossOriginWindowOpenNavigation(bool value) { m_isCrossOriginWindowOpenNavigation = value; }
+    bool isCrossOriginWindowOpenNavigation() const { return m_isCrossOriginWindowOpenNavigation; }
+
 private:
     Ref<Document> m_requester;
     Ref<SecurityOrigin> m_requesterSecurityOrigin;
@@ -102,6 +105,7 @@
     ShouldOpenExternalURLsPolicy m_shouldOpenExternalURLsPolicy { ShouldOpenExternalURLsPolicy::ShouldNotAllow };
     AtomicString m_downloadAttribute;
     InitiatedByMainFrame m_initiatedByMainFrame { InitiatedByMainFrame::Unknown };
+    bool m_isCrossOriginWindowOpenNavigation { false };
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/loader/FrameLoader.cpp (230050 => 230051)


--- trunk/Source/WebCore/loader/FrameLoader.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebCore/loader/FrameLoader.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -1306,6 +1306,13 @@
         return;
 
     NavigationAction action { frameLoadRequest.requester(), request, frameLoadRequest.initiatedByMainFrame(), newLoadType, isFormSubmission, event, frameLoadRequest.shouldOpenExternalURLsPolicy(), frameLoadRequest.downloadAttribute() };
+    action.setIsCrossOriginWindowOpenNavigation(frameLoadRequest.isCrossOriginWindowOpenNavigation());
+    if (auto* opener = this->opener()) {
+        auto pageID = opener->loader().client().pageID();
+        auto frameID = opener->loader().client().frameID();
+        if (pageID && frameID)
+            action.setOpener(std::make_pair(*pageID, *frameID));
+    }
 
     if (!targetFrame && !frameName.isEmpty()) {
         action = "" frameLoadRequest));

Modified: trunk/Source/WebCore/loader/NavigationAction.h (230050 => 230051)


--- trunk/Source/WebCore/loader/NavigationAction.h	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebCore/loader/NavigationAction.h	2018-03-28 21:21:43 UTC (rev 230051)
@@ -72,6 +72,12 @@
 
     const AtomicString& downloadAttribute() const { return m_downloadAttribute; }
 
+    void setIsCrossOriginWindowOpenNavigation(bool value) { m_isCrossOriginWindowOpenNavigation = value; }
+    bool isCrossOriginWindowOpenNavigation() const { return m_isCrossOriginWindowOpenNavigation; }
+
+    void setOpener(std::optional<std::pair<uint64_t, uint64_t>>&& opener) { m_opener = WTFMove(opener); }
+    const std::optional<std::pair<uint64_t, uint64_t>>& opener() const { return m_opener; }
+
 private:
     RefPtr<Document> m_sourceDocument;
     ResourceRequest m_resourceRequest;
@@ -81,6 +87,8 @@
     RefPtr<Event> m_event;
     RefPtr<UserGestureToken> m_userGestureToken { UserGestureIndicator::currentUserGesture() };
     AtomicString m_downloadAttribute;
+    bool m_isCrossOriginWindowOpenNavigation { false };
+    std::optional<std::pair<uint64_t /* pageID */, uint64_t /* frameID */>> m_opener;
 };
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/DOMWindow.cpp (230050 => 230051)


--- trunk/Source/WebCore/page/DOMWindow.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebCore/page/DOMWindow.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -2279,6 +2279,8 @@
     if (created) {
         ResourceRequest resourceRequest { completedURL, referrer, UseProtocolCachePolicy };
         FrameLoadRequest frameLoadRequest { *activeWindow.document(), activeWindow.document()->securityOrigin(), resourceRequest, ASCIILiteral("_self"), LockHistory::No, LockBackForwardList::No, MaybeSendReferrer, AllowNavigationToInvalidURL::Yes, NewFrameOpenerPolicy::Allow, activeDocument->shouldOpenExternalURLsPolicyToPropagate(), initiatedByMainFrame };
+        if (openerFrame.document() && !protocolHostAndPortAreEqual(openerFrame.document()->url(), frameLoadRequest.resourceRequest().url()))
+            frameLoadRequest.setIsCrossOriginWindowOpenNavigation(true);
         newFrame->loader().changeLocation(WTFMove(frameLoadRequest));
 
 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)

Modified: trunk/Source/WebKit/ChangeLog (230050 => 230051)


--- trunk/Source/WebKit/ChangeLog	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/ChangeLog	2018-03-28 21:21:43 UTC (rev 230051)
@@ -1,3 +1,34 @@
+2018-03-28  Chris Dumez  <cdu...@apple.com>
+
+        Do process swap when opening a cross-origin URL via window.open(url, '_blank', 'noopener')
+        https://bugs.webkit.org/show_bug.cgi?id=183962
+        <rdar://problem/38817833>
+
+        Reviewed by Brady Eidson.
+
+        Swap WebProcess on for the initial navigation in a new Window that was opened
+        via window.open(), when the new URL is cross-origin compared to the opener's
+        origin. For now, we only swap process if 'noopener' property is set when calling
+        window.open(). This is because we do not support the remote DOMWindows yet.
+
+        * Shared/NavigationActionData.cpp:
+        (WebKit::NavigationActionData::encode const):
+        (WebKit::NavigationActionData::decode):
+        * Shared/NavigationActionData.h:
+        * UIProcess/API/APINavigation.h:
+        (API::Navigation::setIsCrossOriginWindowOpenNavigation):
+        (API::Navigation::isCrossOriginWindowOpenNavigation const):
+        (API::Navigation::setOpener):
+        (API::Navigation::opener const):
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::receivedPolicyDecision):
+        (WebKit::WebPageProxy::decidePolicyForNavigationAction):
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::processForNavigation):
+        * UIProcess/WebProcessPool.h:
+        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
+        (WebKit::WebFrameLoaderClient::dispatchDecidePolicyForNavigationAction):
+
 2018-03-28  Per Arne Vollan  <pvol...@apple.com>
 
         Adopt WEBPROCESS_WINDOWSERVER_BLOCKING compiler guard in WebProcess.

Modified: trunk/Source/WebKit/Shared/NavigationActionData.cpp (230050 => 230051)


--- trunk/Source/WebKit/Shared/NavigationActionData.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/Shared/NavigationActionData.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -47,6 +47,8 @@
     encoder << downloadAttribute;
     encoder << clickLocationInRootViewCoordinates;
     encoder << isRedirect;
+    encoder << isCrossOriginWindowOpenNavigation;
+    encoder << opener;
 }
 
 std::optional<NavigationActionData> NavigationActionData::decode(IPC::Decoder& decoder)
@@ -95,7 +97,17 @@
     if (!isRedirect)
         return std::nullopt;
 
-    return {{ WTFMove(navigationType), WTFMove(modifiers), WTFMove(mouseButton), WTFMove(syntheticClickType), WTFMove(*userGestureTokenIdentifier), WTFMove(*canHandleRequest), WTFMove(shouldOpenExternalURLsPolicy), WTFMove(*downloadAttribute), WTFMove(clickLocationInRootViewCoordinates), WTFMove(*isRedirect) }};
+    std::optional<bool> isCrossOriginWindowOpenNavigation;
+    decoder >> isCrossOriginWindowOpenNavigation;
+    if (!isCrossOriginWindowOpenNavigation)
+        return std::nullopt;
+
+    std::optional<std::optional<std::pair<uint64_t, uint64_t>>> opener;
+    decoder >> opener;
+    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) }};
 }
 
 } // namespace WebKit

Modified: trunk/Source/WebKit/Shared/NavigationActionData.h (230050 => 230051)


--- trunk/Source/WebKit/Shared/NavigationActionData.h	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/Shared/NavigationActionData.h	2018-03-28 21:21:43 UTC (rev 230051)
@@ -50,6 +50,8 @@
     WTF::String downloadAttribute;
     WebCore::FloatPoint clickLocationInRootViewCoordinates;
     bool isRedirect { false };
+    bool isCrossOriginWindowOpenNavigation { false };
+    std::optional<std::pair<uint64_t, uint64_t>> opener;
 };
 
 }

Modified: trunk/Source/WebKit/UIProcess/API/APINavigation.h (230050 => 230051)


--- trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/UIProcess/API/APINavigation.h	2018-03-28 21:21:43 UTC (rev 230051)
@@ -31,7 +31,7 @@
 
 namespace WebCore {
 enum class FrameLoadType;
-};
+}
 
 namespace WebKit {
 class WebBackForwardListItem;
@@ -75,6 +75,12 @@
     void setShouldForceDownload(bool value) { m_shouldForceDownload = value; }
     bool shouldForceDownload() const { return m_shouldForceDownload; }
 
+    void setIsCrossOriginWindowOpenNavigation(bool value) { m_isCrossOriginWindowOpenNavigation = value; }
+    bool isCrossOriginWindowOpenNavigation() const { return m_isCrossOriginWindowOpenNavigation; }
+
+    void setOpener(const std::optional<std::pair<uint64_t, uint64_t>>& opener) { m_opener = opener; }
+    const std::optional<std::pair<uint64_t, uint64_t>>& opener() const { return m_opener; }
+
 #if !LOG_DISABLED
     WTF::String loggingURL() const;
 #endif
@@ -92,6 +98,8 @@
 
     RefPtr<WebKit::WebBackForwardListItem> m_backForwardListItem;
     std::optional<WebCore::FrameLoadType> m_backForwardFrameLoadType;
+    bool m_isCrossOriginWindowOpenNavigation { false };
+    std::optional<std::pair<uint64_t, uint64_t>> m_opener;
 };
 
 } // namespace API

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (230050 => 230051)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -2351,11 +2351,10 @@
         ASSERT(activePolicyListener->listenerID() == listenerID);
 
         if (action == PolicyAction::Use && navigation) {
-            auto proposedProcess = process().processPool().processForNavigation(*this, navigation->request().url());
+            auto proposedProcess = process().processPool().processForNavigation(*this, *navigation, action);
             if (proposedProcess.ptr() != &process()) {
                 LOG(Loading, "Switching to new process for navigation %" PRIu64 " to url '%s' (WebBackForwardListItem %p)", navigation->navigationID(), navigation->loggingURL().utf8().data(), navigation->backForwardListItem());
 
-                action = ""
                 RunLoop::main().dispatch([this, protectedThis = makeRef(*this), navigation = makeRef(*navigation), proposedProcess = WTFMove(proposedProcess)]() mutable {
                     continueNavigationInNewProcess(navigation.get(), WTFMove(proposedProcess));
                 });
@@ -3809,20 +3808,15 @@
     
     uint64_t newNavigationID { 0 };
     Ref<WebFramePolicyListenerProxy> listener = frame->setUpPolicyListenerProxy(listenerID, PolicyListenerType::NavigationAction);
-    if (!navigationID) {
-        auto navigation = m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
-        newNavigationID = navigation->navigationID();
-        navigation->setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
-        navigation->setShouldForceDownload(!navigationActionData.downloadAttribute.isNull());
-        listener->setNavigation(WTFMove(navigation));
-    } else {
-        auto& navigation = m_navigationState->navigation(navigationID);
-        newNavigationID = navigationID;
-        navigation.setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
-        navigation.setShouldForceDownload(!navigationActionData.downloadAttribute.isNull());
-        listener->setNavigation(navigation);
-    }
+    Ref<API::Navigation> navigation = navigationID ? makeRef(m_navigationState->navigation(navigationID)) : m_navigationState->createLoadRequestNavigation(ResourceRequest(request));
 
+    newNavigationID = navigation->navigationID();
+    navigation->setWasUserInitiated(!!navigationActionData.userGestureTokenIdentifier);
+    navigation->setShouldForceDownload(!navigationActionData.downloadAttribute.isNull());
+    navigation->setIsCrossOriginWindowOpenNavigation(navigationActionData.isCrossOriginWindowOpenNavigation);
+    navigation->setOpener(navigationActionData.opener);
+    listener->setNavigation(WTFMove(navigation));
+
 #if ENABLE(CONTENT_FILTERING)
     if (frame->didHandleContentFilterUnblockNavigation(request))
         return receivedPolicyDecision(PolicyAction::Ignore, *frame, listenerID, &m_navigationState->navigation(newNavigationID), { });

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.cpp (230050 => 230051)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -1965,15 +1965,26 @@
 }
 #endif
 
-Ref<WebProcessProxy> WebProcessPool::processForNavigation(WebPageProxy& page, const URL& targetURL)
+Ref<WebProcessProxy> WebProcessPool::processForNavigation(WebPageProxy& page, const API::Navigation& navigation, PolicyAction& action)
 {
     if (!m_configuration->processSwapsOnNavigation())
         return page.process();
 
+    // FIXME: We should support process swap when a window has an opener.
+    if (navigation.opener())
+        return page.process();
+
+    if (navigation.isCrossOriginWindowOpenNavigation()) {
+        action = ""
+        return createNewWebProcess(page.websiteDataStore());
+    }
+
+    auto targetURL = navigation.request().url();
     auto url = "" { ParsedURLString, page.pageLoadState().url() };
-    if (protocolHostAndPortAreEqual(url, targetURL) || url.isBlankURL())
+    if (!url.isValid() || url.isBlankURL() || protocolHostAndPortAreEqual(url, targetURL))
         return page.process();
 
+    action = ""
     return createNewWebProcess(page.websiteDataStore());
 }
 

Modified: trunk/Source/WebKit/UIProcess/WebProcessPool.h (230050 => 230051)


--- trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/UIProcess/WebProcessPool.h	2018-03-28 21:21:43 UTC (rev 230051)
@@ -445,7 +445,7 @@
     BackgroundWebProcessToken backgroundWebProcessToken() const { return BackgroundWebProcessToken(m_backgroundWebProcessCounter.count()); }
 #endif
 
-    Ref<WebProcessProxy> processForNavigation(WebPageProxy&, const WebCore::URL&);
+    Ref<WebProcessProxy> processForNavigation(WebPageProxy&, const API::Navigation&, WebCore::PolicyAction&);
 
 private:
     void platformInitialize();

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp (230050 => 230051)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp	2018-03-28 21:21:43 UTC (rev 230051)
@@ -861,6 +861,8 @@
     navigationActionData.shouldOpenExternalURLsPolicy = navigationAction.shouldOpenExternalURLsPolicy();
     navigationActionData.downloadAttribute = navigationAction.downloadAttribute();
     navigationActionData.isRedirect = didReceiveRedirectResponse;
+    navigationActionData.isCrossOriginWindowOpenNavigation = navigationAction.isCrossOriginWindowOpenNavigation();
+    navigationActionData.opener = navigationAction.opener();
 
     WebCore::Frame* coreFrame = m_frame->coreFrame();
     if (!coreFrame)

Modified: trunk/Tools/ChangeLog (230050 => 230051)


--- trunk/Tools/ChangeLog	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Tools/ChangeLog	2018-03-28 21:21:43 UTC (rev 230051)
@@ -1,3 +1,17 @@
+2018-03-28  Chris Dumez  <cdu...@apple.com>
+
+        Do process swap when opening a cross-origin URL via window.open(url, '_blank', 'noopener')
+        https://bugs.webkit.org/show_bug.cgi?id=183962
+        <rdar://problem/38817833>
+
+        Reviewed by Brady Eidson.
+
+        Add API test coverage.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
+        (-[PSONUIDelegate initWithNavigationDelegate:]):
+        (-[PSONUIDelegate webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:]):
+
 2018-03-28  Carlos Eduardo Ramalho  <cadubent...@gmail.com>
 
         Add Carlos Eduardo Ramalho as contributor

Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm (230050 => 230051)


--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2018-03-28 21:17:14 UTC (rev 230050)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm	2018-03-28 21:21:43 UTC (rev 230051)
@@ -30,6 +30,7 @@
 #import <WebKit/WKNavigationDelegate.h>
 #import <WebKit/WKPreferencesPrivate.h>
 #import <WebKit/WKProcessPoolPrivate.h>
+#import <WebKit/WKUIDelegatePrivate.h>
 #import <WebKit/WKURLSchemeHandler.h>
 #import <WebKit/WKURLSchemeTaskPrivate.h>
 #import <WebKit/WKWebViewConfigurationPrivate.h>
@@ -40,6 +41,7 @@
 #import <WebKit/_WKExperimentalFeature.h>
 #import <WebKit/_WKProcessPoolConfiguration.h>
 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
+#import <WebKit/_WKWebsitePolicies.h>
 #import <wtf/Deque.h>
 #import <wtf/HashMap.h>
 #import <wtf/RetainPtr.h>
@@ -50,6 +52,7 @@
 #if WK_API_ENABLED
 
 static bool done;
+static bool didCreateWebView;
 static int numberOfDecidePolicyCalls;
 
 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
@@ -83,6 +86,35 @@
 
 @end
 
+static RetainPtr<WKWebView> createdWebView;
+
+@interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
+- (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
+@end
+
+@implementation PSONUIDelegate {
+    RetainPtr<PSONNavigationDelegate> _navigationDelegate;
+}
+
+- (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _navigationDelegate = navigationDelegate;
+    return self;
+}
+
+- (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
+{
+    createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
+    [createdWebView setNavigationDelegate:_navigationDelegate.get()];
+    didCreateWebView = true;
+    return createdWebView.get();
+}
+
+@end
+
 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
     const char* _bytes;
 }
@@ -140,6 +172,35 @@
 </head>
 )PSONRESOURCE";
 
+static const char* windowOpenCrossOriginNoOpenerTestBytes = R"PSONRESOURCE(
+<script>
+window._onload_ = function() {
+    window.open("pson2://host/main2.html", "_blank", "noopener");
+}
+</script>
+)PSONRESOURCE";
+
+static const char* windowOpenCrossOriginWithOpenerTestBytes = R"PSONRESOURCE(
+<script>
+window._onload_ = function() {
+    window.open("pson2://host/main2.html");
+}
+</script>
+)PSONRESOURCE";
+
+static const char* windowOpenSameOriginNoOpenerTestBytes = R"PSONRESOURCE(
+<script>
+window._onload_ = function() {
+    if (!opener)
+        window.open("pson1://host/main2.html", "_blank", "noopener");
+}
+</script>
+)PSONRESOURCE";
+
+static const char* dummyBytes = R"PSONRESOURCE(
+<body>TEST</body>
+)PSONRESOURCE";
+
 TEST(ProcessSwap, Basic)
 {
     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
@@ -253,4 +314,126 @@
     EXPECT_FALSE(pid1 == pid3);
 }
 
+TEST(ProcessSwap, CrossOriginWindowOpenNoOpener)
+{
+    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> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginNoOpenerTestBytes]);
+    RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
+    [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
+    [webViewConfiguration setURLSchemeHandler:handler2.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;
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    TestWebKitAPI::Util::run(&didCreateWebView);
+    didCreateWebView = false;
+
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+    auto pid2 = [createdWebView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    EXPECT_NE(pid1, pid2);
+}
+
+TEST(ProcessSwap, CrossOriginWindowOpenWithOpener)
+{
+    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> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginWithOpenerTestBytes]);
+    RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
+    [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
+    [webViewConfiguration setURLSchemeHandler:handler2.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;
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    TestWebKitAPI::Util::run(&didCreateWebView);
+    didCreateWebView = false;
+
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+    auto pid2 = [createdWebView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    // FIXME: This should eventually be false once we support process swapping when there is an opener.
+    EXPECT_EQ(pid1, pid2);
+}
+
+TEST(ProcessSwap, SamOriginWindowOpenNoOpener)
+{
+    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:windowOpenSameOriginNoOpenerTestBytes]);
+    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
+
+    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;
+    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
+    [webView loadRequest:request];
+
+    TestWebKitAPI::Util::run(&done);
+    done = false;
+
+    TestWebKitAPI::Util::run(&didCreateWebView);
+    didCreateWebView = false;
+
+    TestWebKitAPI::Util::run(&done);
+
+    EXPECT_EQ(2, numberOfDecidePolicyCalls);
+
+    auto pid1 = [webView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid1);
+    auto pid2 = [createdWebView _webProcessIdentifier];
+    EXPECT_TRUE(!!pid2);
+
+    EXPECT_EQ(pid1, pid2);
+}
+
 #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