| /* |
| * Copyright (C) 2022 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 "HTTPServer.h" |
| #import "TestNavigationDelegate.h" |
| #import "Utilities.h" |
| #import <WebKit/WKFrameInfoPrivate.h> |
| #import <WebKit/WKNavigationPrivate.h> |
| #import <WebKit/WKPreferencesPrivate.h> |
| #import <WebKit/WKWebViewPrivateForTesting.h> |
| #import <WebKit/_WKFeature.h> |
| #import <WebKit/_WKFrameTreeNode.h> |
| #import <wtf/BlockPtr.h> |
| |
| namespace TestWebKitAPI { |
| |
| static void enableSiteIsolation(WKWebViewConfiguration *configuration) |
| { |
| auto preferences = [configuration preferences]; |
| for (_WKFeature *feature in [WKPreferences _features]) { |
| if ([feature.key isEqualToString:@"SiteIsolationEnabled"]) { |
| [preferences _setEnabled:YES forFeature:feature]; |
| break; |
| } |
| } |
| } |
| |
| static void enableWindowOpenPSON(WKWebViewConfiguration *configuration) |
| { |
| auto preferences = [configuration preferences]; |
| for (_WKFeature *feature in [WKPreferences _features]) { |
| if ([feature.key isEqualToString:@"ProcessSwapOnCrossSiteWindowOpenEnabled"]) { |
| [preferences _setEnabled:YES forFeature:feature]; |
| break; |
| } |
| } |
| } |
| |
| enum RemoteFrameTag { RemoteFrame }; |
| struct ExpectedFrameTree { |
| std::variant<RemoteFrameTag, String> remoteOrOrigin; |
| Vector<ExpectedFrameTree> children { }; |
| }; |
| |
| static bool frameTreesMatch(_WKFrameTreeNode *actualRoot, const ExpectedFrameTree& expectedRoot) |
| { |
| WKFrameInfo *info = actualRoot.info; |
| if (info._isLocalFrame != std::holds_alternative<String>(expectedRoot.remoteOrOrigin)) |
| return false; |
| |
| if (auto* expectedOrigin = std::get_if<String>(&expectedRoot.remoteOrOrigin)) { |
| WKSecurityOrigin *origin = info.securityOrigin; |
| auto actualOrigin = makeString(String(origin.protocol), "://"_s, String(origin.host), origin.port ? makeString(':', origin.port) : String()); |
| if (actualOrigin != *expectedOrigin) |
| return false; |
| } |
| |
| if (actualRoot.childFrames.count != expectedRoot.children.size()) |
| return false; |
| for (size_t i = 0; i < expectedRoot.children.size(); i++) { |
| if (!frameTreesMatch(actualRoot.childFrames[i], expectedRoot.children[i])) |
| return false; |
| } |
| return true; |
| } |
| |
| static bool frameTreesMatch(NSSet<_WKFrameTreeNode *> *actualFrameTrees, Vector<ExpectedFrameTree>&& expectedFrameTrees) |
| { |
| if (actualFrameTrees.count != expectedFrameTrees.size()) |
| return false; |
| |
| for (_WKFrameTreeNode *root in actualFrameTrees) { |
| auto index = expectedFrameTrees.findIf([&] (auto& expectedFrameTree) { |
| return frameTreesMatch(root, expectedFrameTree); |
| }); |
| if (index == WTF::notFound) |
| return false; |
| expectedFrameTrees.remove(index); |
| } |
| return expectedFrameTrees.isEmpty(); |
| } |
| |
| static RetainPtr<NSSet> frameTrees(WKWebView *webView) |
| { |
| __block RetainPtr<NSSet> result; |
| [webView _frameTrees:^(NSSet<_WKFrameTreeNode *> *frameTrees) { |
| result = frameTrees; |
| }]; |
| while (!result) |
| Util::spinRunLoop(); |
| return result; |
| } |
| |
| static void checkFrameTreesInProcesses(NSSet<_WKFrameTreeNode *> *actualTrees, Vector<ExpectedFrameTree>&& expectedFrameTrees) |
| { |
| EXPECT_TRUE(frameTreesMatch(actualTrees, WTFMove(expectedFrameTrees))); |
| } |
| |
| static void checkFrameTreesInProcesses(WKWebView *webView, Vector<ExpectedFrameTree>&& expectedFrameTrees) |
| { |
| checkFrameTreesInProcesses(frameTrees(webView).get(), WTFMove(expectedFrameTrees)); |
| } |
| |
| enum class FrameType : bool { Local, Remote }; |
| static pid_t findFramePID(NSSet<_WKFrameTreeNode *> *set, FrameType local) |
| { |
| for (_WKFrameTreeNode *node in set) { |
| if (node._isLocalFrame == (local == FrameType::Local)) |
| return node._processIdentifier; |
| } |
| ASSERT_NOT_REACHED(); |
| return 0; |
| } |
| |
| TEST(SiteIsolation, LoadingCallbacksAndPostMessage) |
| { |
| auto exampleHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " alert('parent frame received ' + event.data)" |
| " }, false);" |
| " onload = () => {" |
| " document.getElementById('webkit_frame').contentWindow.postMessage('ping', '*');" |
| " }" |
| "</script>" |
| "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s; |
| |
| auto webkitHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " parent.window.postMessage(event.data + 'pong', { 'targetOrigin' : '*' });" |
| " }, false)" |
| "</script>"_s; |
| |
| bool finishedLoading { false }; |
| size_t framesCommitted { 0 }; |
| HTTPServer server(HTTPServer::UseCoroutines::Yes, [&](Connection connection) -> Task { |
| while (1) { |
| auto request = co_await connection.awaitableReceiveHTTPRequest(); |
| auto path = HTTPServer::parsePath(request); |
| if (path == "/example"_s) { |
| co_await connection.awaitableSend(HTTPResponse(exampleHTML).serialize()); |
| continue; |
| } |
| if (path == "/webkit"_s) { |
| size_t contentLength = 2000000 + webkitHTML.length(); |
| co_await connection.awaitableSend(makeString("HTTP/1.1 200 OK\r\nContent-Length: "_s, contentLength, "\r\n\r\n"_s)); |
| |
| co_await connection.awaitableSend(webkitHTML); |
| co_await connection.awaitableSend(Vector<uint8_t>(1000000, ' ')); |
| |
| while (framesCommitted < 2) |
| Util::spinRunLoop(); |
| Util::runFor(Seconds(0.5)); |
| EXPECT_EQ(framesCommitted, 2u); |
| |
| EXPECT_FALSE(finishedLoading); |
| co_await connection.awaitableSend(Vector<uint8_t>(1000000, ' ')); |
| continue; |
| } |
| EXPECT_FALSE(true); |
| } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| navigationDelegate.get().didCommitLoadWithRequestInFrame = makeBlockPtr([&](WKWebView *, NSURLRequest *, WKFrameInfo *frameInfo) { |
| NSString *url = frameInfo.request.URL.absoluteString; |
| switch (++framesCommitted) { |
| case 1: |
| EXPECT_WK_STREQ(url, "https://example.com/example"); |
| EXPECT_TRUE(frameInfo.isMainFrame); |
| break; |
| case 2: |
| EXPECT_WK_STREQ(url, "https://webkit.org/webkit"); |
| EXPECT_FALSE(frameInfo.isMainFrame); |
| break; |
| default: |
| EXPECT_FALSE(true); |
| break; |
| } |
| }).get(); |
| navigationDelegate.get().didFinishNavigation = makeBlockPtr([&](WKWebView *, WKNavigation *navigation) { |
| if (navigation._request) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://example.com/example"); |
| finishedLoading = true; |
| } |
| }).get(); |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| __block RetainPtr<NSString> alert; |
| auto uiDelegate = adoptNS([TestUIDelegate new]); |
| uiDelegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) { |
| alert = message; |
| completionHandler(); |
| }; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| webView.get().UIDelegate = uiDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| Util::run(&finishedLoading); |
| |
| while (!alert) |
| Util::spinRunLoop(); |
| EXPECT_WK_STREQ(alert.get(), "parent frame received pingpong"); |
| |
| checkFrameTreesInProcesses(webView.get(), { |
| { "https://example.com"_s, |
| { { RemoteFrame } } |
| }, { RemoteFrame, |
| { { "https://webkit.org"_s } } |
| }, |
| }); |
| } |
| |
| TEST(SiteIsolation, BasicPostMessageWindowOpen) |
| { |
| auto exampleHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " w.postMessage('pong', '*');" |
| " }, false);" |
| "</script>"_s; |
| |
| auto webkitHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " alert('opened page received ' + event.data);" |
| " }, false);" |
| "</script>"_s; |
| |
| __block bool openerFinishedLoading { false }; |
| __block bool openedFinishedLoading { false }; |
| HTTPServer server({ |
| { "/example"_s, { exampleHTML } }, |
| { "/webkit"_s, { webkitHTML } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| |
| __block RetainPtr<WKWebView> openerWebView; |
| __block RetainPtr<WKWebView> openedWebView; |
| |
| auto openerNavigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [openerNavigationDelegate allowAnyTLSCertificate]; |
| openerNavigationDelegate.get().didFinishNavigation = ^(WKWebView *opener, WKNavigation *navigation) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://example.com/example"); |
| checkFrameTreesInProcesses(opener, { { "https://example.com"_s } }); |
| openerFinishedLoading = true; |
| }; |
| |
| __block auto openedNavigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [openedNavigationDelegate allowAnyTLSCertificate]; |
| openedNavigationDelegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *navigation) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://webkit.org/webkit"); |
| checkFrameTreesInProcesses(openerWebView.get(), { { "https://example.com"_s }, { RemoteFrame } }); |
| checkFrameTreesInProcesses(openedWebView.get(), { { "https://webkit.org"_s }, { RemoteFrame } }); |
| auto openerFrames = frameTrees(openerWebView.get()); |
| auto openedFrames = frameTrees(openedWebView.get()); |
| EXPECT_NE([openerWebView _webProcessIdentifier], [openedWebView _webProcessIdentifier]); |
| EXPECT_EQ(findFramePID(openerFrames.get(), FrameType::Remote), [openedWebView _webProcessIdentifier]); |
| EXPECT_EQ(findFramePID(openedFrames.get(), FrameType::Remote), [openerWebView _webProcessIdentifier]); |
| openedFinishedLoading = true; |
| }; |
| openedNavigationDelegate.get().decidePolicyForNavigationResponse = ^(WKNavigationResponse *, void (^completionHandler)(WKNavigationResponsePolicy)) { |
| auto openerFrames = frameTrees(openerWebView.get()); |
| checkFrameTreesInProcesses(openerFrames.get(), { { "https://example.com"_s }, { RemoteFrame } }); |
| checkFrameTreesInProcesses(openedWebView.get(), { { "https://example.com"_s } }); |
| EXPECT_EQ([openerWebView _webProcessIdentifier], [openedWebView _webProcessIdentifier]); |
| EXPECT_NE([openedWebView _webProcessIdentifier], [openedWebView _provisionalWebProcessIdentifier]); |
| EXPECT_EQ(findFramePID(openerFrames.get(), FrameType::Remote), [openedWebView _provisionalWebProcessIdentifier]); |
| EXPECT_EQ(findFramePID(openerFrames.get(), FrameType::Local), [openerWebView _webProcessIdentifier]); |
| completionHandler(WKNavigationResponsePolicyAllow); |
| }; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableWindowOpenPSON(configuration); |
| |
| __block RetainPtr<NSString> alert; |
| auto uiDelegate = adoptNS([TestUIDelegate new]); |
| uiDelegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) { |
| alert = message; |
| completionHandler(); |
| }; |
| |
| uiDelegate.get().createWebViewWithConfiguration = ^(WKWebViewConfiguration *configuration, WKNavigationAction *action, WKWindowFeatures *windowFeatures) { |
| openedWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| openedWebView.get().UIDelegate = uiDelegate.get(); |
| openedWebView.get().navigationDelegate = openedNavigationDelegate.get(); |
| return openedWebView.get(); |
| }; |
| |
| openerWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| openerWebView.get().navigationDelegate = openerNavigationDelegate.get(); |
| openerWebView.get().UIDelegate = uiDelegate.get(); |
| openerWebView.get().configuration.preferences.javaScriptCanOpenWindowsAutomatically = YES; |
| [openerWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| Util::run(&openerFinishedLoading); |
| |
| [openerWebView evaluateJavaScript:@"w = window.open('https://webkit.org/webkit')" completionHandler:nil]; |
| |
| Util::run(&openedFinishedLoading); |
| |
| [openedWebView evaluateJavaScript:@"try { window.opener.postMessage('ping', '*'); } catch(e) { alert('error ' + e) }" completionHandler:nil]; |
| |
| while (!alert) |
| Util::spinRunLoop(); |
| EXPECT_WK_STREQ(alert.get(), "opened page received pong"); |
| } |
| |
| TEST(SiteIsolation, PostMessageWithMessagePorts) |
| { |
| auto exampleHTML = "<script>" |
| " const channel = new MessageChannel();" |
| " channel.port1.onmessage = function() {" |
| " alert('parent frame received ' + event.data)" |
| " };" |
| " onload = () => {" |
| " document.getElementById('webkit_frame').contentWindow.postMessage('ping', '*', [channel.port2]);" |
| " }" |
| "</script>" |
| "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s; |
| |
| auto webkitHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " event.ports[0].postMessage('got port and message ' + event.data);" |
| " }, false)" |
| "</script>"_s; |
| |
| bool finishedLoading { false }; |
| HTTPServer server({ |
| { "/example"_s, { exampleHTML } }, |
| { "/webkit"_s, { webkitHTML } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| navigationDelegate.get().didFinishNavigation = makeBlockPtr([&](WKWebView *, WKNavigation *navigation) { |
| if (navigation._request) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://example.com/example"); |
| finishedLoading = true; |
| } |
| }).get(); |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| __block RetainPtr<NSString> alert; |
| auto uiDelegate = adoptNS([TestUIDelegate new]); |
| uiDelegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) { |
| alert = message; |
| completionHandler(); |
| }; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| webView.get().UIDelegate = uiDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| Util::run(&finishedLoading); |
| |
| while (!alert) |
| Util::spinRunLoop(); |
| EXPECT_WK_STREQ(alert.get(), "parent frame received got port and message ping"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = mainFrame.childFrames.firstObject._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, PostMessageWithNotAllowedTargetOrigin) |
| { |
| auto exampleHTML = "<script>" |
| " onload = () => {" |
| " document.getElementById('webkit_frame').contentWindow.postMessage('ping', 'https://foo.org');" |
| " }" |
| "</script>" |
| "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s; |
| |
| auto webkitHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " alert('child frame received ' + event.data)" |
| " }, false);" |
| " setTimeout(() => { alert('child did not receive message'); }, 1000);" |
| "</script>"_s; |
| |
| bool finishedLoading { false }; |
| HTTPServer server(HTTPServer::UseCoroutines::Yes, [&](Connection connection) -> Task { |
| while (1) { |
| auto request = co_await connection.awaitableReceiveHTTPRequest(); |
| auto path = HTTPServer::parsePath(request); |
| if (path == "/example"_s) { |
| co_await connection.awaitableSend(HTTPResponse(exampleHTML).serialize()); |
| continue; |
| } |
| if (path == "/webkit"_s) { |
| co_await connection.awaitableSend(HTTPResponse(webkitHTML).serialize()); |
| continue; |
| } |
| EXPECT_FALSE(true); |
| } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| navigationDelegate.get().didFinishNavigation = makeBlockPtr([&](WKWebView *, WKNavigation *navigation) { |
| if (navigation._request) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://example.com/example"); |
| finishedLoading = true; |
| } |
| }).get(); |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| __block RetainPtr<NSString> alert; |
| auto uiDelegate = adoptNS([TestUIDelegate new]); |
| uiDelegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) { |
| alert = message; |
| completionHandler(); |
| }; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| webView.get().UIDelegate = uiDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| Util::run(&finishedLoading); |
| |
| while (!alert) |
| Util::spinRunLoop(); |
| EXPECT_WK_STREQ(alert.get(), "child did not receive message"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = mainFrame.childFrames.firstObject._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, PostMessageToIFrameWithOpaqueOrigin) |
| { |
| auto exampleHTML = "<script>" |
| " onload = () => {" |
| " try {" |
| " document.getElementById('webkit_frame').contentWindow.postMessage('ping', 'data:');" |
| " } catch (error) {" |
| " alert(error);" |
| " }" |
| " }" |
| "</script>" |
| "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s; |
| |
| auto webkitHTML = "<script>" |
| " window.addEventListener('message', (event) => {" |
| " alert('child frame received ' + event.data)" |
| " }, false);" |
| "</script>"_s; |
| |
| bool finishedLoading { false }; |
| |
| HTTPServer server({ |
| { "/example"_s, { exampleHTML } }, |
| { "/webkit"_s, { webkitHTML } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| navigationDelegate.get().didFinishNavigation = makeBlockPtr([&](WKWebView *, WKNavigation *navigation) { |
| if (navigation._request) { |
| EXPECT_WK_STREQ(navigation._request.URL.absoluteString, "https://example.com/example"); |
| finishedLoading = true; |
| } |
| }).get(); |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| __block RetainPtr<NSString> alert; |
| auto uiDelegate = adoptNS([TestUIDelegate new]); |
| uiDelegate.get().runJavaScriptAlertPanelWithMessage = ^(WKWebView *, NSString *message, WKFrameInfo *, void (^completionHandler)(void)) { |
| alert = message; |
| completionHandler(); |
| }; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| webView.get().UIDelegate = uiDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| Util::run(&finishedLoading); |
| |
| while (!alert) |
| Util::spinRunLoop(); |
| EXPECT_WK_STREQ(alert.get(), "SyntaxError: The string did not match the expected pattern."); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = mainFrame.childFrames.firstObject._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, QueryFramesStateAfterNavigating) |
| { |
| HTTPServer server({ |
| { "/page1.html"_s, { "<iframe src='subframe1.html'></iframe><iframe src='subframe2.html'></iframe><iframe src='subframe3.html'></iframe>"_s } }, |
| { "/page2.html"_s, { "<iframe src='subframe4.html'></iframe>"_s } }, |
| { "/subframe1.html"_s, { "SubFrame1"_s } }, |
| { "/subframe2.html"_s, { "SubFrame2"_s } }, |
| { "/subframe3.html"_s, { "SubFrame3"_s } }, |
| { "/subframe4.html"_s, { "SubFrame4"_s } } |
| }, HTTPServer::Protocol::Http); |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectZero]); |
| [webView synchronouslyLoadRequest:server.request("/page1.html"_s)]; |
| __block bool done = false; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| EXPECT_EQ(mainFrame.childFrames.count, 3U); |
| done = true; |
| }]; |
| Util::run(&done); |
| |
| [webView synchronouslyLoadRequest:server.request("/page2.html"_s)]; |
| done = false; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| EXPECT_EQ(mainFrame.childFrames.count, 1U); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, NavigatingCrossOriginIframeToSameOrigin) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<script>window.location='https://example.com/example_subframe'</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "example.com"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, ParentNavigatingCrossOriginIframeToSameOrigin) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe><script>onload = () => { document.getElementById('webkit_frame').src = 'https://example.com/example_subframe' }</script>"_s } }, |
| { "/example_subframe"_s, { "<script>onload = ()=>{ alert('done') }</script>"_s } }, |
| { "/webkit"_s, { "hi"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "example.com"); |
| done = true; |
| }]; |
| Util::run(&done); |
| |
| checkFrameTreesInProcesses(webView.get(), { |
| { "https://example.com"_s, |
| { { "https://example.com"_s } } |
| } |
| }); |
| } |
| |
| TEST(SiteIsolation, IframeNavigatesSelfWithoutChangingOrigin) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/webkit"_s, { "<script>window.location='/webkit_second'</script>"_s } }, |
| { "/webkit_second"_s, { "<script>alert('done')</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, IframeWithConfirm) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/webkit"_s, { "<script>confirm('confirm message')</script>"_s } }, |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForConfirm], "confirm message"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, IframeWithPrompt) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/webkit"_s, { "<script>prompt('prompt message', 'default input')</script>"_s } }, |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForPromptWithReply:@"default input"], "prompt message"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, GrandchildIframe) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/webkit"_s, { "<iframe srcdoc=\"<script>window.location='https://apple.com/apple'</script>\">"_s } }, |
| { "/apple"_s, { "<script>alert('grandchild loaded successfully')</script>"_s } }, |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "grandchild loaded successfully"); |
| |
| // FIXME: Make the load event on the grandchild frame get called. |
| // (add an onload in the response to /webkit and verify that it is actually called. It is not right now.) |
| } |
| |
| TEST(SiteIsolation, ChildNavigatingToNewDomain) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<script>window.location='https://foo.com/example_subframe'</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "foo.com"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, ChildNavigatingToMainFrameDomain) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<script>window.location='https://example.com/example_subframe'</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "example.com"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, ChildNavigatingToSameDomain) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<script>window.location='https://webkit.org/example_subframe'</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, ChildNavigatingToDomainLoadedOnADifferentPage) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe>"_s } }, |
| { "/webkit"_s, { "<script>alert('done')</script>"_s } }, |
| { "/foo"_s, { "<iframe id='foo'><html><body><p>Hello world.</p></body></html></iframe>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| enableSiteIsolation(configuration); |
| |
| auto firstWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| firstWebView.get().navigationDelegate = navigationDelegate.get(); |
| [firstWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://webkit.org/foo"]]]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block pid_t firstFramePID = 0; |
| __block bool done { false }; |
| [firstWebView _frames:^(_WKFrameTreeNode *mainFrame) { |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| firstFramePID = mainFramePid; |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| |
| done = false; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(mainFramePid, childFramePid); |
| EXPECT_NE(firstFramePID, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| // FIXME: This test times out on the iOS simulator. Investigate and fix. |
| #if PLATFORM(MAC) |
| TEST(SiteIsolation, MainFrameWithTwoIFramesInTheSameProcess) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame_1' src='https://webkit.org/a'></iframe><iframe id='webkit_frame_2' src='https://webkit.org/b'></iframe>"_s } }, |
| { "/a"_s, { "<script>alert('donea')</script>"_s } }, |
| { "/b"_s, { "<script>alert('doneb')</script>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| // FIXME: call enableSiteIsolation to make this actually use site isolation |
| // once we make changes so that this isn't flaky. |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| NSString* alert1 = [webView _test_waitForAlert]; |
| NSString* alert2 = [webView _test_waitForAlert]; |
| if ([alert1 isEqualToString:@"donea"]) |
| EXPECT_WK_STREQ(alert2, "doneb"); |
| else if ([alert1 isEqualToString:@"doneb"]) |
| EXPECT_WK_STREQ(alert2, "donea"); |
| else |
| EXPECT_TRUE(false); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| EXPECT_EQ(mainFrame.childFrames.count, 2u); |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| _WKFrameTreeNode *otherChildFrame = mainFrame.childFrames[1]; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| pid_t otherChildFramePid = otherChildFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| EXPECT_NE(otherChildFramePid, 0); |
| EXPECT_EQ(childFramePid, otherChildFramePid); |
| // FIXME: Switch to EXPECT_NE once siteIsolation is enabled. |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| EXPECT_WK_STREQ(otherChildFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| #endif |
| |
| TEST(SiteIsolation, ChildBeingNavigatedToMainFrameDomainByParent) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe><script>onload = () => { document.getElementById('webkit_frame').src = 'https://example.com/example_subframe' }</script>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<html></html>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| // FIXME: Fix failures and enable site isolation |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| // FIXME: Switch to EXPECT_NE once siteIsolation is enabled. |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "example.com"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| TEST(SiteIsolation, ChildBeingNavigatedToSameDomainByParent) |
| { |
| HTTPServer server({ |
| { "/example"_s, { "<iframe id='webkit_frame' src='https://webkit.org/webkit'></iframe><script>onload = () => { document.getElementById('webkit_frame').src = 'https://webkit.org/example_subframe' }</script>"_s } }, |
| { "/example_subframe"_s, { "<script>alert('done')</script>"_s } }, |
| { "/webkit"_s, { "<html></html>"_s } } |
| }, HTTPServer::Protocol::HttpsProxy); |
| auto navigationDelegate = adoptNS([TestNavigationDelegate new]); |
| [navigationDelegate allowAnyTLSCertificate]; |
| |
| auto configuration = server.httpsProxyConfiguration(); |
| // FIXME: Fix failures and enable site isolation |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration]); |
| webView.get().navigationDelegate = navigationDelegate.get(); |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/example"]]]; |
| EXPECT_WK_STREQ([webView _test_waitForAlert], "done"); |
| |
| __block bool done { false }; |
| [webView _frames:^(_WKFrameTreeNode *mainFrame) { |
| _WKFrameTreeNode *childFrame = mainFrame.childFrames.firstObject; |
| pid_t mainFramePid = mainFrame._processIdentifier; |
| pid_t childFramePid = childFrame._processIdentifier; |
| EXPECT_NE(mainFramePid, 0); |
| EXPECT_NE(childFramePid, 0); |
| // FIXME: Switch to EXPECT_NE once siteIsolation is enabled. |
| EXPECT_EQ(mainFramePid, childFramePid); |
| EXPECT_WK_STREQ(mainFrame.securityOrigin.host, "example.com"); |
| EXPECT_WK_STREQ(childFrame.securityOrigin.host, "webkit.org"); |
| done = true; |
| }]; |
| Util::run(&done); |
| } |
| |
| } |