| /* |
| * Copyright (C) 2017-2020 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 "DeprecatedGlobalValues.h" |
| #import "HTTPServer.h" |
| #import "PlatformUtilities.h" |
| #import "Test.h" |
| #import "TestNavigationDelegate.h" |
| #import "TestWKWebView.h" |
| #import "UserMediaCaptureUIDelegate.h" |
| #import <WebKit/WKBackForwardListItemPrivate.h> |
| #import <WebKit/WKContentRuleListStore.h> |
| #import <WebKit/WKHTTPCookieStorePrivate.h> |
| #import <WebKit/WKNavigationDelegatePrivate.h> |
| #import <WebKit/WKNavigationPrivate.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> |
| #import <WebKit/WKWebViewPrivateForTesting.h> |
| #import <WebKit/WKWebpagePreferences.h> |
| #import <WebKit/WKWebpagePreferencesPrivate.h> |
| #import <WebKit/WKWebsiteDataStorePrivate.h> |
| #import <WebKit/WKWebsiteDataStoreRef.h> |
| #import <WebKit/WebKit.h> |
| #import <WebKit/_WKExperimentalFeature.h> |
| #import <WebKit/_WKInspector.h> |
| #import <WebKit/_WKProcessPoolConfiguration.h> |
| #import <WebKit/_WKWebsiteDataStoreConfiguration.h> |
| #import <wtf/BlockPtr.h> |
| #import <wtf/Deque.h> |
| #import <wtf/HashMap.h> |
| #import <wtf/HashSet.h> |
| #import <wtf/RetainPtr.h> |
| #import <wtf/Vector.h> |
| #import <wtf/text/StringConcatenateNumbers.h> |
| #import <wtf/text/StringHash.h> |
| #import <wtf/text/WTFString.h> |
| |
| @interface WKProcessPool () |
| - (WKContextRef)_contextForTesting; |
| @end |
| |
| static bool didStartProvisionalLoad; |
| static bool failed; |
| static int numberOfDecidePolicyCalls; |
| static bool didRepondToPolicyDecisionCall; |
| |
| #if PLATFORM(IOS_FAMILY) |
| static bool requestedQuickLookPassword; |
| static bool didStartQuickLookLoad; |
| static bool didFinishQuickLookLoad; |
| #endif |
| |
| bool didReceiveAlert; |
| static bool receivedMessage; |
| static bool serverRedirected; |
| static HashSet<pid_t> seenPIDs; |
| static bool willPerformClientRedirect; |
| static bool didPerformClientRedirect; |
| static bool shouldConvertToDownload; |
| static bool didCloseWindow; |
| static RetainPtr<NSURL> clientRedirectSourceURL; |
| static RetainPtr<NSURL> clientRedirectDestinationURL; |
| |
| static bool didChangeCaptivePortalMode; |
| static bool captivePortalModeBeforeChange; |
| static bool captivePortalModeAfterChange; |
| |
| @interface CaptivePortalModeKVO : NSObject { |
| @public |
| } |
| @end |
| |
| @implementation CaptivePortalModeKVO |
| |
| - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context |
| { |
| ASSERT([keyPath isEqualToString:@"_captivePortalModeEnabled"]); |
| ASSERT([[object class] isEqual:[WKWebpagePreferences class]]); |
| |
| captivePortalModeBeforeChange = [[change objectForKey:NSKeyValueChangeOldKey] boolValue]; |
| captivePortalModeAfterChange = [[change objectForKey:NSKeyValueChangeNewKey] boolValue]; |
| didChangeCaptivePortalMode = true; |
| } |
| |
| @end |
| |
| @interface PSONMessageHandler : NSObject <WKScriptMessageHandler> |
| @end |
| |
| @implementation PSONMessageHandler |
| - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message |
| { |
| if ([message body]) |
| [receivedMessages addObject:[message body]]; |
| else |
| [receivedMessages addObject:@""]; |
| |
| receivedMessage = true; |
| if ([message.webView _webProcessIdentifier]) |
| seenPIDs.add([message.webView _webProcessIdentifier]); |
| } |
| @end |
| |
| @interface PSONNavigationDelegate : NSObject <WKNavigationDelegatePrivate> { |
| @public void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy)); |
| @public void (^didStartProvisionalNavigationHandler)(); |
| @public void (^didCommitNavigationHandler)(); |
| } |
| @end |
| |
| @implementation PSONNavigationDelegate |
| |
| - (instancetype) init |
| { |
| self = [super init]; |
| return self; |
| } |
| |
| - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error |
| { |
| seenPIDs.add([webView _webProcessIdentifier]); |
| failed = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation |
| { |
| seenPIDs.add([webView _webProcessIdentifier]); |
| done = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView navigation:(WKNavigation *)navigation didSameDocumentNavigation:(_WKSameDocumentNavigationType)navigationType |
| { |
| if (navigationType != _WKSameDocumentNavigationTypeAnchorNavigation) |
| return; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| done = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler |
| { |
| EXPECT_WK_STREQ(challenge.protectionSpace.authenticationMethod, NSURLAuthenticationMethodServerTrust); |
| completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); |
| } |
| |
| - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation |
| { |
| didStartProvisionalLoad = true; |
| if (didStartProvisionalNavigationHandler) |
| didStartProvisionalNavigationHandler(); |
| } |
| |
| - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation |
| { |
| if (didCommitNavigationHandler) |
| didCommitNavigationHandler(); |
| } |
| |
| - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler |
| { |
| ++numberOfDecidePolicyCalls; |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (decidePolicyForNavigationAction) |
| decidePolicyForNavigationAction(navigationAction, decisionHandler); |
| else |
| decisionHandler(WKNavigationActionPolicyAllow); |
| didRepondToPolicyDecisionCall = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler |
| { |
| decisionHandler(shouldConvertToDownload ? WKNavigationResponsePolicyDownload : WKNavigationResponsePolicyAllow); |
| } |
| |
| - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation |
| { |
| seenPIDs.add([webView _webProcessIdentifier]); |
| serverRedirected = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)delay |
| { |
| clientRedirectDestinationURL = URL; |
| willPerformClientRedirect = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView didPerformClientRedirectFromURL:(NSURL *)sourceURL toURL:(NSURL *)destinationURL |
| { |
| EXPECT_TRUE(willPerformClientRedirect); |
| EXPECT_WK_STREQ([clientRedirectDestinationURL absoluteString], [destinationURL absoluteString]); |
| clientRedirectSourceURL = sourceURL; |
| didPerformClientRedirect = true; |
| } |
| |
| - (void)webViewWebContentProcessDidTerminate:(WKWebView *)webView |
| { |
| [webView reload]; |
| } |
| |
| #if PLATFORM(IOS_FAMILY) |
| |
| - (void)_webViewDidRequestPasswordForQuickLookDocument:(WKWebView *)webView |
| { |
| requestedQuickLookPassword = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:(NSString *)fileName uti:(NSString *)uti |
| { |
| didStartQuickLookLoad = true; |
| } |
| |
| - (void)_webView:(WKWebView *)webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)documentData |
| { |
| didFinishQuickLookLoad = true; |
| } |
| |
| #endif |
| |
| @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; |
| } |
| |
| - (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()]; |
| [createdWebView setUIDelegate:self]; |
| didCreateWebView = true; |
| return createdWebView.get(); |
| } |
| |
| - (void)webViewDidClose:(WKWebView *)webView |
| { |
| EXPECT_EQ(createdWebView.get(), webView); |
| createdWebView = nullptr; |
| didCloseWindow = true; |
| } |
| |
| - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler |
| { |
| didReceiveAlert = true; |
| completionHandler(); |
| } |
| |
| @end |
| |
| @interface PSONScheme : NSObject <WKURLSchemeHandler> { |
| const char* _bytes; |
| HashMap<String, String> _redirects; |
| HashMap<String, RetainPtr<NSData>> _dataMappings; |
| HashSet<id <WKURLSchemeTask>> _runningTasks; |
| bool _shouldRespondAsynchronously; |
| } |
| - (instancetype)initWithBytes:(const char*)bytes; |
| - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString; |
| - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data; |
| @end |
| |
| @implementation PSONScheme |
| |
| - (instancetype)initWithBytes:(const char*)bytes |
| { |
| self = [super init]; |
| _bytes = bytes; |
| return self; |
| } |
| |
| - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString |
| { |
| _redirects.set(sourceURLString, destinationURLString); |
| } |
| |
| - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data |
| { |
| _dataMappings.set(urlString, [NSData dataWithBytesNoCopy:(void*)data length:strlen(data) freeWhenDone:NO]); |
| } |
| |
| - (void)setShouldRespondAsynchronously:(BOOL)value |
| { |
| _shouldRespondAsynchronously = value; |
| } |
| |
| - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task |
| { |
| if ([(id<WKURLSchemeTaskPrivate>)task _requestOnlyIfCached]) { |
| [task didFailWithError:[NSError errorWithDomain:@"TestWebKitAPI" code:1 userInfo:nil]]; |
| return; |
| } |
| |
| _runningTasks.add(task); |
| |
| auto doAsynchronouslyIfNecessary = [self, strongSelf = retainPtr(self), task = retainPtr(task)](Function<void(id <WKURLSchemeTask>)>&& f, double delay) { |
| if (!_shouldRespondAsynchronously) |
| return f(task.get()); |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_main_queue(), makeBlockPtr([self, strongSelf, task, f = WTFMove(f)] { |
| if (_runningTasks.contains(task.get())) |
| f(task.get()); |
| }).get()); |
| }; |
| |
| NSURL *finalURL = task.request.URL; |
| auto target = _redirects.get(task.request.URL.absoluteString); |
| if (!target.isEmpty()) { |
| auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]); |
| |
| finalURL = [NSURL URLWithString:(NSString *)target]; |
| auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]); |
| |
| [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()]; |
| } |
| |
| doAsynchronouslyIfNecessary([finalURL = retainPtr(finalURL)](id <WKURLSchemeTask> task) { |
| NSMutableDictionary* headerDictionary = [NSMutableDictionary dictionary]; |
| [headerDictionary setObject:@"text/html" forKey:@"Content-Type"]; |
| [headerDictionary setObject:@"1" forKey:@"Content-Length"]; |
| |
| auto response = adoptNS([[NSHTTPURLResponse alloc] initWithURL:finalURL.get() statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerDictionary]); |
| [task didReceiveResponse:response.get()]; |
| }, 0.1); |
| |
| doAsynchronouslyIfNecessary([self, finalURL = retainPtr(finalURL)](id <WKURLSchemeTask> task) { |
| if (auto data = _dataMappings.get([finalURL absoluteString])) |
| [task didReceiveData:data.get()]; |
| else if (_bytes) { |
| RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]); |
| [task didReceiveData:data.get()]; |
| } else |
| [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]]; |
| }, 0.2); |
| |
| doAsynchronouslyIfNecessary([self](id <WKURLSchemeTask> task) { |
| [task didFinish]; |
| _runningTasks.remove(task); |
| }, 0.3); |
| } |
| |
| - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task |
| { |
| _runningTasks.remove(task); |
| } |
| |
| @end |
| |
| static const char* testBytes = R"PSONRESOURCE( |
| <head> |
| <script> |
| |
| function log(msg) |
| { |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| } |
| |
| window.onload = function(evt) { |
| if (window.history.state != "onloadCalled") |
| setTimeout('window.history.replaceState("onloadCalled", "");', 0); |
| } |
| |
| window.onpageshow = function(evt) { |
| log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state); |
| } |
| |
| </script> |
| </head> |
| )PSONRESOURCE"; |
| |
| static const char* linkToCrossSiteClientSideRedirectBytes = R"PSONRESOURCE( |
| <body> |
| <a id="testLink" href="pson://www.google.com/clientSideRedirect.html">Link to cross-site client-side redirect</a> |
| </body> |
| )PSONRESOURCE"; |
| |
| static const char* crossSiteClientSideRedirectBytes = R"PSONRESOURCE( |
| <body> |
| <script> |
| onload = () => { |
| location = "pson://www.apple.com/main.html"; |
| }; |
| </script> |
| </body> |
| )PSONRESOURCE"; |
| |
| static const char* navigationWithLockedHistoryBytes = R"PSONRESOURCE( |
| <script> |
| let shouldNavigate = true; |
| window.addEventListener('pageshow', function(event) { |
| if (event.persisted) { |
| window.webkit.messageHandlers.pson.postMessage("Was persisted"); |
| shouldNavigate = false; |
| } |
| }); |
| |
| onload = function() |
| { |
| if (!shouldNavigate) |
| return; |
| |
| // JS navigation via window.location |
| setTimeout(() => { |
| location = "pson://www.apple.com/main.html"; |
| }, 10); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* pageCache1Bytes = R"PSONRESOURCE( |
| <script> |
| window.addEventListener('pageshow', function(event) { |
| if (event.persisted) |
| window.webkit.messageHandlers.pson.postMessage("Was persisted"); |
| }); |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenCrossSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| window.open("pson://www.apple.com/main.html", "_blank", "noopener"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenCrossOriginButSameSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| window.open("pson://www.webkit.org:8080/main.html", "_blank", "noopener"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenCrossSiteWithOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| window.open("pson://www.apple.com/main.html"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenSameSiteWithOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| w = window.open("pson://www.webkit.org/main2.html"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenSameSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| if (!opener) |
| window.open("pson://www.webkit.org/popup.html", "_blank", "noopener"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* windowOpenWithNameSameSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| if (!opener) |
| window.open("pson://www.webkit.org/popup.html", "foo", "noopener"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* targetBlankCrossSiteWithExplicitOpenerTestBytes = R"PSONRESOURCE( |
| <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="opener">Link</a> |
| <script> |
| window.onload = function() { |
| testLink.click(); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* targetBlankCrossSiteWithImplicitNoOpenerTestBytes = R"PSONRESOURCE( |
| <a id="testLink" target="_blank" href="pson://www.apple.com/main.html">Link</a> |
| <script> |
| window.onload = function() { |
| testLink.click(); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* targetBlankCrossSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="noopener">Link</a> |
| <script> |
| window.onload = function() { |
| testLink.click(); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* targetBlankSameSiteNoOpenerTestBytes = R"PSONRESOURCE( |
| <a id="testLink" target="_blank" href="pson://www.webkit.org/main2.html" rel="noopener">Link</a> |
| <script> |
| window.onload = function() { |
| testLink.click(); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| #if PLATFORM(MAC) |
| static const char* linkToAppleTestBytes = R"PSONRESOURCE( |
| <script> |
| window.addEventListener('pageshow', function(event) { |
| if (event.persisted) |
| window.webkit.messageHandlers.pson.postMessage("Was persisted"); |
| }); |
| </script> |
| <a id="testLink" href="pson://www.apple.com/main.html">Navigate</a> |
| )PSONRESOURCE"; |
| #endif |
| |
| static RetainPtr<_WKProcessPoolConfiguration> psonProcessPoolConfiguration() |
| { |
| auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]); |
| processPoolConfiguration.get().processSwapsOnNavigation = YES; |
| processPoolConfiguration.get().usesWebProcessCache = YES; |
| processPoolConfiguration.get().prewarmsProcessesAutomatically = YES; |
| processPoolConfiguration.get().processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol = YES; |
| return processPoolConfiguration; |
| } |
| |
| enum class SchemeHandlerShouldBeAsync { No, Yes }; |
| static void runBasicTest(SchemeHandlerShouldBeAsync schemeHandlerShouldBeAsync) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler setShouldRespondAsynchronously:(schemeHandlerShouldBeAsync == SchemeHandlerShouldBeAsync::Yes)]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(pid1, pid2); |
| EXPECT_FALSE(pid2 == pid3); |
| |
| // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call) |
| EXPECT_EQ(numberOfDecidePolicyCalls, 3); |
| } |
| |
| TEST(ProcessSwap, Basic) |
| { |
| runBasicTest(SchemeHandlerShouldBeAsync::No); |
| } |
| |
| TEST(ProcessSwap, BasicWithAsyncSchemeHandler) |
| { |
| runBasicTest(SchemeHandlerShouldBeAsync::Yes); |
| } |
| |
| TEST(ProcessSwap, NoProcessSwappingWithinSameNonHTTPFamilyProtocol) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigationWithinSameNonHTTPFamilyProtocol = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"CUSTOM"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"custom://abc/main1.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"custom://def/main2.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"custom://ghi/main3.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); |
| |
| // Switch to the file protocol. |
| [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid2, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, LoadAfterPolicyDecision) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| |
| // Synchronously navigate again right after answering the policy delegate for the previous navigation. |
| navigationDelegate->decidePolicyForNavigationAction = nil; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| while (![[[webView URL] absoluteString] isEqualToString:@"pson://www.webkit.org/main2.html"]) |
| TestWebKitAPI::Util::spinRunLoop(); |
| } |
| |
| TEST(ProcessSwap, KillWebContentProcessAfterServerRedirectPolicyDecision) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addRedirectFromURLString:@"pson://www.webkit.org/main2.html" toURLString:@"pson://www.apple.com/main.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| __block BOOL isRedirection = NO; |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction * action, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| if (!isRedirection) { |
| isRedirection = YES; |
| return; |
| } |
| |
| navigationDelegate->decidePolicyForNavigationAction = nil; |
| [webView _killWebContentProcessAndResetState]; |
| done = true; |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::spinRunLoop(10); |
| [webView reload]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, KillProvisionalWebContentProcessThenStartNewLoad) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // When the provisional load starts in the provisional process, kill the WebView's processes. |
| navigationDelegate->didStartProvisionalNavigationHandler = ^{ |
| [webView _killWebContentProcessAndResetState]; |
| done = true; |
| }; |
| |
| // Start a new cross-site load, which should happen in a new provisional process. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| navigationDelegate->didStartProvisionalNavigationHandler = nil; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, NoSwappingForeTLDPlus2) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www1.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www2.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(pid1, pid2); |
| |
| EXPECT_EQ(numberOfDecidePolicyCalls, 2); |
| } |
| |
| TEST(ProcessSwap, Back) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:testBytes]; |
| [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_GT([processPool _maximumSuspendedPageCount], 0U); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto googlePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(applePID, googlePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto bingPID = [webView _webProcessIdentifier]; |
| EXPECT_NE(googlePID, bingPID); |
| |
| [webView goBack]; // Back to google.com. |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterFirstBackNavigation = [webView _webProcessIdentifier]; |
| EXPECT_EQ(googlePID, pidAfterFirstBackNavigation); |
| |
| [webView goBack]; // Back to apple.com. |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterSecondBackNavigation = [webView _webProcessIdentifier]; |
| if ([processPool _maximumSuspendedPageCount] > 1) |
| EXPECT_EQ(applePID, pidAfterSecondBackNavigation); |
| else { |
| EXPECT_NE(applePID, pidAfterSecondBackNavigation); |
| EXPECT_NE(googlePID, pidAfterSecondBackNavigation); |
| } |
| |
| |
| // 6 loads, 6 decidePolicy calls (e.g. any load that performs a process swap should not have generated an |
| // additional decidePolicy call as a result of the process swap) |
| EXPECT_EQ(6, numberOfDecidePolicyCalls); |
| |
| EXPECT_EQ(5u, [receivedMessages count]); |
| EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[0]); |
| EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[1]); |
| EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[2]); |
| EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[3]); |
| |
| // The number of suspended pages we keep around is determined at runtime. |
| if ([processPool _maximumSuspendedPageCount] > 1) { |
| EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[4]); |
| EXPECT_EQ(4u, seenPIDs.size()); |
| } else |
| EXPECT_EQ(5u, seenPIDs.size()); |
| } |
| |
| static const char* pageWithFragmentTestBytes = R"PSONRESOURCE( |
| <div id="foo">TEST</div> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, HistoryNavigationToFragmentURL) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html#foo" toData:pageWithFragmentTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html#foo"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| |
| bool finishedRunningScript = false; |
| [webView evaluateJavaScript:@"document.getElementById('foo').innerText" completionHandler: [&] (id result, NSError *error) { |
| NSString *innerText = (NSString *)result; |
| EXPECT_WK_STREQ(@"TEST", innerText); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| } |
| |
| TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_GT([processPool _maximumSuspendedPageCount], 0U); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| |
| // webkit.org + apple.com processes. |
| EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| [webView goBack]; // Back to webkit.org. |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| // webkit.org + apple.com processes. |
| EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| // apple.com is not longer present in the back/forward list and there should therefore be no-suspended page for it. |
| while ([processPool _webProcessCountIgnoringPrewarmedAndCached] > 1u) |
| TestWebKitAPI::Util::spinRunLoop(); |
| } |
| |
| #if PLATFORM(MAC) |
| TEST(ProcessSwap, SuspendedPagesInActivityMonitor) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes]; |
| [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) { |
| EXPECT_EQ(1u, activeDomains.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto googlePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, googlePID); |
| |
| [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID completionHandler:^(NSArray<NSString *> *activeDomains) { |
| EXPECT_EQ(1u, activeDomains.count); |
| EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) { |
| EXPECT_EQ(1u, activeDomains.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; // Back to webkit.org. |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterBackNavigation = [webView _webProcessIdentifier]; |
| EXPECT_EQ(webkitPID, pidAfterBackNavigation); |
| |
| [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID completionHandler:^(NSArray<NSString *> *activeDomains) { |
| EXPECT_EQ(1u, activeDomains.count); |
| EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) { |
| EXPECT_EQ(1u, activeDomains.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| TEST(ProcessSwap, BackWithoutSuspendedPage) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState]; |
| webView1 = nullptr; |
| |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| [webView2 _restoreSessionState:sessionState.get() andNavigate:NO]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView2 _webProcessIdentifier]; |
| |
| [webView2 goBack]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView2 _webProcessIdentifier]; |
| |
| EXPECT_FALSE(pid1 == pid2); |
| EXPECT_FALSE(pid2 == pid3); |
| } |
| |
| TEST(ProcessSwap, BackNavigationAfterSessionRestore) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView1 _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState]; |
| webView1 = nullptr; |
| |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| [webView2 _restoreSessionState:sessionState.get() andNavigate:YES]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView2 URL] absoluteString]); |
| auto pid3 = [webView2 _webProcessIdentifier]; |
| |
| [webView2 goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView2 URL] absoluteString]); |
| auto pid4 = [webView2 _webProcessIdentifier]; |
| EXPECT_NE(pid3, pid4); |
| } |
| |
| TEST(ProcessSwap, CrossSiteWindowOpenNoOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.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, CrossOriginButSameSiteWindowOpenNoOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossOriginButSameSiteNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.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); |
| |
| // Since there is no opener, we process-swap, even though the navigation is same-site. |
| EXPECT_NE(pid1, pid2); |
| } |
| |
| TEST(ProcessSwap, CrossSiteWindowOpenWithOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteWithOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.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); |
| } |
| |
| enum class ExpectSwap { No, Yes }; |
| enum class WindowHasName : bool { No, Yes }; |
| static void runSameSiteWindowOpenNoOpenerTest(WindowHasName windowHasName, ExpectSwap expectSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| if (windowHasName == WindowHasName::Yes) |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenWithNameSameSiteNoOpenerTestBytes]; |
| else |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenSameSiteNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.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); |
| |
| // Since there is no opener, we process-swap, even though the navigation is same-site. |
| if (expectSwap == ExpectSwap::Yes) |
| EXPECT_NE(pid1, pid2); |
| else |
| EXPECT_EQ(pid1, pid2); |
| |
| done = false; |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/popup2.html"]]; |
| [createdWebView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| EXPECT_EQ(pid2, [createdWebView _webProcessIdentifier]); |
| |
| // Since the window was opened via JS, it should be able to close itself. |
| didCloseWindow = false; |
| [createdWebView evaluateJavaScript:@"window.close()" completionHandler:nil]; |
| TestWebKitAPI::Util::run(&didCloseWindow); |
| } |
| |
| TEST(ProcessSwap, SameSiteWindowOpenNoOpener) |
| { |
| // We process-swap even though the navigation is same-site, because the popup has no opener. |
| runSameSiteWindowOpenNoOpenerTest(WindowHasName::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, SameSiteWindowOpenWithNameNoOpener) |
| { |
| // We currently do no process-swap when navigating same-site a popup without opener if the window |
| // has a name. We should be able to support this but we would need to pass the window name over |
| // to the new process. |
| runSameSiteWindowOpenNoOpenerTest(WindowHasName::Yes, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, CrossSiteBlankTargetWithOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithExplicitOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| EXPECT_EQ(pid1, pid2); |
| } |
| |
| TEST(ProcessSwap, CrossSiteBlankTargetImplicitNoOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithImplicitNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| EXPECT_NE(pid1, pid2); |
| } |
| |
| TEST(ProcessSwap, CrossSiteBlankTargetNoOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| EXPECT_NE(pid1, pid2); |
| } |
| |
| TEST(ProcessSwap, SameSiteBlankTargetNoOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankSameSiteNoOpenerTestBytes]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| // Since there is no opener, we process-swap, even though the navigation is same-site. |
| EXPECT_NE(pid1, pid2); |
| } |
| |
| TEST(ProcessSwap, ServerRedirectFromNewWebView) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&serverRedirected); |
| serverRedirected = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| |
| EXPECT_FALSE(serverRedirected); |
| EXPECT_EQ(2, numberOfDecidePolicyCalls); |
| EXPECT_EQ(1u, seenPIDs.size()); |
| } |
| |
| TEST(ProcessSwap, ServerRedirect) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| EXPECT_EQ(1u, seenPIDs.size()); |
| EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&serverRedirected); |
| serverRedirected = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| EXPECT_FALSE(serverRedirected); |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| TEST(ProcessSwap, ServerRedirect2) |
| { |
| // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin. |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler1 = adoptNS([[PSONScheme alloc] init]); |
| [handler1 addRedirectFromURLString:@"pson://www.webkit.org/main2.html" toURLString:@"pson://www.apple.com/main.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"]; |
| auto handler2 = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| EXPECT_FALSE(serverRedirected); |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| EXPECT_EQ(1u, seenPIDs.size()); |
| EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&serverRedirected); |
| serverRedirected = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| EXPECT_FALSE(serverRedirected); |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]); |
| } |
| |
| TEST(ProcessSwap, ServerRedirectToAboutBlank) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"about:blank"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| EXPECT_EQ(1u, seenPIDs.size()); |
| EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&serverRedirected); |
| serverRedirected = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| EXPECT_FALSE(serverRedirected); |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| enum class ShouldCacheProcessFirst { No, Yes }; |
| static void runSameOriginServerRedirectTest(ShouldCacheProcessFirst shouldCacheProcessFirst) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigation = YES; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:crossSiteClientSideRedirectBytes]; |
| [handler addRedirectFromURLString:@"pson://www.apple.com/main.html" toURLString:@"pson://www.apple.com/main2.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request; |
| |
| if (shouldCacheProcessFirst == ShouldCacheProcessFirst::Yes) { |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main3.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| delegate->didStartProvisionalNavigationHandler = ^{ |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| }; |
| |
| willPerformClientRedirect = false; |
| didPerformClientRedirect = false; |
| serverRedirected = false; |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&willPerformClientRedirect); |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&didPerformClientRedirect); |
| didPerformClientRedirect = false; |
| willPerformClientRedirect = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&serverRedirected); |
| serverRedirected = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| seenPIDs.add([webView _webProcessIdentifier]); |
| if (auto provisionalPID = [webView _provisionalWebProcessIdentifier]) |
| seenPIDs.add(provisionalPID); |
| |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| TEST(ProcessSwap, SameOriginServerRedirect) |
| { |
| runSameOriginServerRedirectTest(ShouldCacheProcessFirst::No); |
| } |
| |
| TEST(ProcessSwap, SameOriginServerRedirectFromCachedProcess) |
| { |
| runSameOriginServerRedirectTest(ShouldCacheProcessFirst::Yes); |
| } |
| |
| TEST(ProcessSwap, TerminateProcessRightAfterSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| delegate->didStartProvisionalNavigationHandler = ^{ |
| EXPECT_NE(0, [webView _provisionalWebProcessIdentifier]); |
| kill([webView _provisionalWebProcessIdentifier], 9); |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::sleep(0.5); |
| } |
| |
| static const char* linkToWebKitBytes = R"PSONRESOURCE( |
| <body> |
| <a id="testLink" href="pson://www.webkit.org/main.html">Link</a> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, PolicyCancelAfterServerRedirect) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes]; |
| [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/ignore.html"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| if ([action.request.URL.absoluteString hasSuffix:@"ignore.html"]) { |
| decisionHandler(WKNavigationActionPolicyCancel); |
| return; |
| } |
| decisionHandler(WKNavigationActionPolicyAllow); |
| }; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::run(&failed); |
| failed = false; |
| done = false; |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| // We should still be on google.com. |
| EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) { |
| EXPECT_WK_STREQ(@"Link", innerText); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, CrossSiteDownload) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:"Hello"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| shouldConvertToDownload = true; |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::run(&failed); |
| failed = false; |
| shouldConvertToDownload = false; |
| |
| // We should still be on google.com. |
| EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) { |
| EXPECT_WK_STREQ(@"Link", innerText); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| #if USE(SYSTEM_PREVIEW) |
| |
| static const char* systemPreviewSameOriginTestBytes = R"PSONRESOURCE( |
| <body> |
| <a id="testLink" rel="ar" href="pson://www.webkit.org/whatever"> |
| <img src="http://www.webkit.org/image"> |
| </a> |
| </body> |
| )PSONRESOURCE"; |
| |
| static const char* systemPreviewCrossOriginTestBytes = R"PSONRESOURCE( |
| <body> |
| <a id="testLink" rel="ar" href="pson://www.apple.com/whatever"> |
| <img src="http://www.webkit.org/image"> |
| </a> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, SameOriginSystemPreview) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:systemPreviewSameOriginTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/whatever" toData:"Fake USDZ data"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| [webViewConfiguration _setSystemPreviewEnabled:YES]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| didStartProvisionalLoad = false; |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::sleep(0.5); |
| |
| // We should still be on webkit.org. |
| EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| EXPECT_FALSE(didStartProvisionalLoad); |
| } |
| |
| TEST(ProcessSwap, CrossOriginSystemPreview) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:systemPreviewCrossOriginTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/whatever" toData:"Fake USDZ data"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| [webViewConfiguration _setSystemPreviewEnabled:YES]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pidAfterFirstLoad = [webView _webProcessIdentifier]; |
| |
| didStartProvisionalLoad = false; |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::sleep(0.5); |
| |
| // We should still be on webkit.org. |
| EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| EXPECT_FALSE(didStartProvisionalLoad); |
| } |
| |
| #endif |
| |
| enum class ShouldEnablePSON { No, Yes }; |
| static void runClientSideRedirectTest(ShouldEnablePSON shouldEnablePSON) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:linkToCrossSiteClientSideRedirectBytes]; |
| [handler addMappingFromURLString:@"pson://www.google.com/clientSideRedirect.html" toData:crossSiteClientSideRedirectBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| // Navigate to the page doing a client-side redirect to apple.com. |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [[webView URL] absoluteString]); |
| auto googlePID = [webView _webProcessIdentifier]; |
| if (shouldEnablePSON == ShouldEnablePSON::Yes) |
| EXPECT_NE(webkitPID, googlePID); |
| else |
| EXPECT_EQ(webkitPID, googlePID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| if (shouldEnablePSON == ShouldEnablePSON::Yes) { |
| EXPECT_NE(webkitPID, applePID); |
| EXPECT_NE(webkitPID, googlePID); |
| } else { |
| EXPECT_EQ(webkitPID, applePID); |
| EXPECT_EQ(webkitPID, googlePID); |
| } |
| |
| EXPECT_TRUE(willPerformClientRedirect); |
| EXPECT_TRUE(didPerformClientRedirect); |
| EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [clientRedirectSourceURL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [clientRedirectDestinationURL absoluteString]); |
| |
| willPerformClientRedirect = false; |
| didPerformClientRedirect = false; |
| clientRedirectSourceURL = nullptr; |
| clientRedirectDestinationURL = nullptr; |
| |
| // Validate Back/Forward list. |
| auto* backForwardList = [webView backForwardList]; |
| auto* currentItem = backForwardList.currentItem; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| |
| auto* backItem = backForwardList.backItem; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]); |
| |
| // Navigate back. |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| EXPECT_FALSE(willPerformClientRedirect); |
| EXPECT_FALSE(didPerformClientRedirect); |
| |
| auto pidAfterBackNavigation = [webView _webProcessIdentifier]; |
| if ([processPool _maximumSuspendedPageCount] > 1) |
| EXPECT_EQ(webkitPID, pidAfterBackNavigation); |
| |
| // Validate Back/Forward list. |
| currentItem = backForwardList.currentItem; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.initialURL absoluteString]); |
| |
| EXPECT_TRUE(!backForwardList.backItem); |
| EXPECT_EQ(1U, backForwardList.forwardList.count); |
| |
| auto* forwardItem = backForwardList.forwardItem; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.initialURL absoluteString]); |
| |
| // Navigate forward. |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_FALSE(willPerformClientRedirect); |
| EXPECT_FALSE(didPerformClientRedirect); |
| |
| auto pidAfterForwardNavigation = [webView _webProcessIdentifier]; |
| EXPECT_EQ(applePID, pidAfterForwardNavigation); |
| |
| // Validate Back/Forward list. |
| currentItem = backForwardList.currentItem; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| |
| backItem = backForwardList.backItem; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]); |
| } |
| |
| TEST(ProcessSwap, CrossSiteClientSideRedirectWithoutPSON) |
| { |
| runClientSideRedirectTest(ShouldEnablePSON::No); |
| } |
| |
| TEST(ProcessSwap, CrossSiteClientSideRedirectWithPSON) |
| { |
| runClientSideRedirectTest(ShouldEnablePSON::Yes); |
| } |
| |
| TEST(ProcessSwap, CrossSiteClientSideRedirectFromFileURL) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| willPerformClientRedirect = false; |
| didPerformClientRedirect = false; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"client-side-redirect" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_TRUE(willPerformClientRedirect); |
| EXPECT_TRUE(didPerformClientRedirect); |
| } |
| |
| TEST(ProcessSwap, NavigateBackAfterClientSideRedirect) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:linkToCrossSiteClientSideRedirectBytes]; |
| [handler addMappingFromURLString:@"pson://www.google.com/clientSideRedirect.html" toData:crossSiteClientSideRedirectBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| willPerformClientRedirect = false; |
| didPerformClientRedirect = false; |
| |
| // Navigate to the page doing a client-side redirect to apple.com. |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [[webView URL] absoluteString]); |
| auto googlePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, googlePID); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| EXPECT_NE(webkitPID, googlePID); |
| |
| EXPECT_TRUE(willPerformClientRedirect); |
| EXPECT_TRUE(didPerformClientRedirect); |
| EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [clientRedirectSourceURL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [clientRedirectDestinationURL absoluteString]); |
| |
| willPerformClientRedirect = false; |
| didPerformClientRedirect = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| EXPECT_FALSE(willPerformClientRedirect); |
| EXPECT_FALSE(didPerformClientRedirect); |
| } |
| |
| static void runNavigationWithLockedHistoryTest(ShouldEnablePSON shouldEnablePSON) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigationWithLockedHistoryBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| // Page redirects to apple.com. |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| if (shouldEnablePSON == ShouldEnablePSON::Yes) |
| EXPECT_NE(webkitPID, applePID); |
| else |
| EXPECT_EQ(webkitPID, applePID); |
| |
| auto* backForwardList = [webView backForwardList]; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]); |
| |
| receivedMessage = false; |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache. |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.backItem); |
| EXPECT_EQ(1U, backForwardList.forwardList.count); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache. |
| receivedMessage = false; |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]); |
| } |
| |
| TEST(ProcessSwap, NavigationWithLockedHistoryWithPSON) |
| { |
| runNavigationWithLockedHistoryTest(ShouldEnablePSON::Yes); |
| } |
| |
| static void runQuickBackForwardNavigationTest(ShouldEnablePSON shouldEnablePSON) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| if (shouldEnablePSON == ShouldEnablePSON::Yes) |
| EXPECT_NE(webkitPID, applePID); |
| else |
| EXPECT_EQ(webkitPID, applePID); |
| |
| for (unsigned i = 0; i < 10; ++i) { |
| [webView goBack]; |
| TestWebKitAPI::Util::sleep(0.1); |
| [webView goForward]; |
| TestWebKitAPI::Util::spinRunLoop(); |
| } |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| Vector<String> backForwardListURLs; |
| auto* backForwardList = [webView backForwardList]; |
| for (unsigned i = 0; i < backForwardList.backList.count; ++i) |
| backForwardListURLs.append([backForwardList.backList[i].URL absoluteString]); |
| backForwardListURLs.append([backForwardList.currentItem.URL absoluteString]); |
| for (unsigned i = 0; i < backForwardList.forwardList.count; ++i) |
| backForwardListURLs.append([backForwardList.forwardList[i].URL absoluteString]); |
| RELEASE_ASSERT(backForwardListURLs.size() == 3u); |
| EXPECT_WK_STREQ("pson://www.webkit.org/main1.html", backForwardListURLs[0]); |
| EXPECT_WK_STREQ("pson://www.webkit.org/main2.html", backForwardListURLs[1]); |
| EXPECT_WK_STREQ("pson://www.apple.com/main.html", backForwardListURLs[2]); |
| } |
| |
| TEST(ProcessSwap, QuickBackForwardNavigationWithoutPSON) |
| { |
| runQuickBackForwardNavigationTest(ShouldEnablePSON::No); |
| } |
| |
| TEST(ProcessSwap, QuickBackForwardNavigationWithPSON) |
| { |
| runQuickBackForwardNavigationTest(ShouldEnablePSON::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigationWithLockedHistoryWithoutPSON) |
| { |
| runNavigationWithLockedHistoryTest(ShouldEnablePSON::No); |
| } |
| |
| static const char* sessionStorageTestBytes = R"PSONRESOURCE( |
| <head> |
| <script> |
| |
| function log(msg) |
| { |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| } |
| |
| window.onload = function(evt) { |
| log(sessionStorage.psonKey); |
| sessionStorage.psonKey = "I exist!"; |
| } |
| |
| </script> |
| </head> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, SessionStorage) |
| { |
| for (int i = 0; i < 5; ++i) { |
| [receivedMessages removeAllObjects]; |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:sessionStorageTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| // Verify the web pages are in different processes |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible. |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| // Verify the sessionStorage values were as expected |
| EXPECT_EQ([receivedMessages count], 2u); |
| EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@""]); |
| EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"I exist!"]); |
| } |
| } |
| |
| TEST(ProcessSwap, ReuseSuspendedProcess) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().usesWebProcessCache = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible. |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should have gone back to the apple.com process for this load since we reuse SuspendedPages' process when possible. |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| } |
| |
| static const char* failsToEnterPageCacheTestBytes = R"PSONRESOURCE( |
| <body> |
| <script> |
| // Pages with dedicated workers do not go into back/forward cache. |
| var myWorker = new Worker('worker.js'); |
| </script> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, ReuseSuspendedProcessEvenIfPageCacheFails) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:failsToEnterPageCacheTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible. |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should have gone back to the apple.com process for this load since we reuse SuspendedPages' process when possible. |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, ReuseSuspendedProcessOnBackEvenIfPageCacheFails) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:failsToEnterPageCacheTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| static const char* withSubframesTestBytes = R"PSONRESOURCE( |
| <body> |
| <iframe src="about:blank"></iframe> |
| <iframe src="about:blank"></iframe> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, HistoryItemIDConfusion) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:failsToEnterPageCacheTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:withSubframesTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto googlePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(applePID, googlePID); |
| EXPECT_NE(webkitPID, googlePID); |
| |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| auto* backForwardList = [webView backForwardList]; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_EQ(2U, backForwardList.forwardList.count); |
| EXPECT_EQ(0U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardList[0].URL absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [backForwardList.forwardList[1].URL absoluteString]); |
| } |
| |
| TEST(ProcessSwap, GoToSecondItemInBackHistory) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:withSubframesTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:withSubframesTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:withSubframesTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| |
| [webView goToBackForwardListItem:webView.get().backForwardList.backList[0]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]); |
| |
| [webView goToBackForwardListItem:webView.get().backForwardList.forwardList[1]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| } |
| |
| TEST(ProcessSwap, PrivateAndRegularSessionsShouldGetDifferentProcesses) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto privateWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [privateWebViewConfiguration setProcessPool:processPool.get()]; |
| [privateWebViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [privateWebViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| auto regularWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [regularWebViewConfiguration setProcessPool:processPool.get()]; |
| [regularWebViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]]; |
| [regularWebViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| |
| auto regularWebView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:regularWebViewConfiguration.get()]); |
| [regularWebView1 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [regularWebView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [regularWebView1 _close]; |
| regularWebView1 = nil; |
| |
| auto privateWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:privateWebViewConfiguration.get()]); |
| [privateWebView setNavigationDelegate:delegate.get()]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [privateWebView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto privateSessionWebkitPID = [privateWebView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [privateWebView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto privateSessionApplePID = [privateWebView _webProcessIdentifier]; |
| EXPECT_NE(privateSessionWebkitPID, privateSessionApplePID); |
| |
| [privateWebView _close]; |
| privateWebView = nil; |
| |
| auto regularWebView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:regularWebViewConfiguration.get()]); |
| [regularWebView2 setNavigationDelegate:delegate.get()]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [regularWebView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto regularSessionGooglePID = [regularWebView2 _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [regularWebView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto regularSessionWebkitPID = [regularWebView2 _webProcessIdentifier]; |
| EXPECT_NE(regularSessionGooglePID, regularSessionWebkitPID); |
| EXPECT_NE(privateSessionWebkitPID, regularSessionWebkitPID); |
| } |
| |
| static const char* keepNavigatingFrameBytes = R"PSONRESOURCE( |
| <body> |
| <iframe id="testFrame1" src="about:blank"></iframe> |
| <iframe id="testFrame2" src="about:blank"></iframe> |
| <iframe id="testFrame3" src="about:blank"></iframe> |
| <script> |
| window.addEventListener('pagehide', function(event) { |
| for (var j = 0; j < 10000; j++); |
| }); |
| |
| var i = 0; |
| function navigateFrames() |
| { |
| testFrame1.src = "pson://www.google.com/main" + i + ".html"; |
| testFrame2.src = "pson://www.google.com/main" + i + ".html"; |
| testFrame3.src = "pson://www.google.com/main" + i + ".html"; |
| i++; |
| } |
| |
| navigateFrames(); |
| setInterval(() => { |
| navigateFrames(); |
| }, 0); |
| </script> |
| </body> |
| )PSONRESOURCE"; |
| |
| enum class RetainPageInBundle { No, Yes }; |
| |
| void testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle retainPageInBundle) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| if (retainPageInBundle == RetainPageInBundle::Yes) |
| [processPoolConfiguration setInjectedBundleURL:[[NSBundle mainBundle] URLForResource:@"TestWebKitAPI" withExtension:@"wkbundle"]]; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| if (retainPageInBundle == RetainPageInBundle::Yes) |
| [processPool _setObject:@"BundleRetainPagePlugIn" forBundleParameter:TestWebKitAPI::Util::TestPlugInClassNameParameter]; |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:keepNavigatingFrameBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, ReuseSuspendedProcessForRegularNavigationRetainBundlePage) |
| { |
| testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle::Yes); |
| } |
| |
| TEST(ProcessSwap, ReuseSuspendedProcessForRegularNavigation) |
| { |
| testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle::No); |
| } |
| |
| static const char* mainFramesOnlyMainFrame = R"PSONRESOURCE( |
| <script> |
| function loaded() { |
| setTimeout('window.frames[0].location.href = "pson://www.apple.com/main.html"', 0); |
| } |
| </script> |
| <body onload="loaded();"> |
| Some text |
| <iframe src="pson://www.webkit.org/iframe.html"></iframe> |
| </body> |
| )PSONRESOURCE"; |
| |
| static const char* mainFramesOnlySubframe = R"PSONRESOURCE( |
| Some content |
| )PSONRESOURCE"; |
| |
| |
| static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE( |
| <script> |
| window.webkit.messageHandlers.pson.postMessage("Done"); |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, MainFramesOnly) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:mainFramesOnlyMainFrame]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/iframe" toData:mainFramesOnlySubframe]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:mainFramesOnlySubframe2]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| |
| EXPECT_EQ(1u, seenPIDs.size()); |
| } |
| |
| #if PLATFORM(MAC) |
| |
| static const char* getClientWidthBytes = R"PSONRESOURCE( |
| <body> |
| TEST |
| <script> |
| function getClientWidth() |
| { |
| document.body.offsetTop; // Force layout. |
| return document.body.clientWidth; |
| } |
| </script> |
| </body> |
| )PSONRESOURCE"; |
| |
| static unsigned waitUntilClientWidthIs(WKWebView *webView, unsigned expectedClientWidth) |
| { |
| int timeout = 10; |
| unsigned clientWidth = 0; |
| do { |
| if (timeout != 10) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| [webView evaluateJavaScript:@"getClientWidth()" completionHandler: [&] (id result, NSError *error) { |
| clientWidth = [result integerValue]; |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| --timeout; |
| } while (clientWidth != expectedClientWidth && timeout >= 0); |
| |
| return clientWidth; |
| } |
| |
| TEST(ProcessSwap, PageZoomLevelAfterSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:getClientWidthBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:getClientWidthBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| delegate->didCommitNavigationHandler = ^ { |
| [webView _setPageZoomFactor:2.0]; |
| delegate->didCommitNavigationHandler = nil; |
| }; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| unsigned clientWidth = waitUntilClientWidthIs(webView.get(), 400); |
| EXPECT_EQ(400U, clientWidth); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| clientWidth = waitUntilClientWidthIs(webView.get(), 400); |
| EXPECT_EQ(400U, clientWidth); |
| |
| // Kill the WebProcess, the page should reload automatically and the page zoom level should be maintained. |
| kill([webView _webProcessIdentifier], 9); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| clientWidth = waitUntilClientWidthIs(webView.get(), 400); |
| EXPECT_EQ(400U, clientWidth); |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| static const char* mediaTypeBytes = R"PSONRESOURCE( |
| <style> |
| @media screen { |
| .print{ |
| visibility: hidden; |
| } |
| } |
| |
| @media print { |
| .screen{ |
| visibility: hidden; |
| } |
| } |
| </style> |
| <body> |
| <div class="screen">Screen</div> |
| <div class="print">Print</div> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, MediaTypeAfterSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:mediaTypeBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:mediaTypeBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| NSString *innerText = [[webView stringByEvaluatingJavaScript:@"document.body.innerText"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; |
| EXPECT_TRUE([innerText isEqualToString:@"Screen"]); |
| |
| webView.get().mediaType = @"print"; |
| |
| innerText = [[webView stringByEvaluatingJavaScript:@"document.body.innerText"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; |
| EXPECT_TRUE([innerText isEqualToString:@"Print"]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| innerText = [[webView stringByEvaluatingJavaScript:@"document.body.innerText"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; |
| EXPECT_TRUE([innerText isEqualToString:@"Print"]); |
| |
| // Kill the WebProcess, the page should reload automatically and the media type should be maintained. |
| kill([webView _webProcessIdentifier], 9); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| innerText = [[webView stringByEvaluatingJavaScript:@"document.body.innerText"] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; |
| EXPECT_TRUE([innerText isEqualToString:@"Print"]); |
| } |
| |
| static const char* navigateBeforePageLoadEndBytes = R"PSONRESOURCE( |
| <body> |
| <a id="testLink" href="pson://www.apple.com/main.html">Link</a> |
| <script> |
| testLink.click(); |
| </script> |
| <p>TEST</p> |
| <script src="test.js"></script> |
| <script src="test2.js"></script> |
| <iframe src="subframe1.html></iframe> |
| <iframe src="subframe2.html></iframe> |
| <iframe src="subframe3.html></iframe> |
| <iframe src="subframe4.html></iframe> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, NavigateCrossSiteBeforePageLoadEnd) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigateBeforePageLoadEndBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| failed = false; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_FALSE(failed); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| } |
| |
| static void runCancelCrossSiteProvisionalLoadTest(ShouldEnablePSON shouldEnablePSON) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| failed = false; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_FALSE(failed); |
| |
| navigationDelegate->didStartProvisionalNavigationHandler = ^{ |
| [webView stopLoading]; |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&failed); |
| failed = false; |
| } |
| |
| TEST(ProcessSwap, CancelCrossSiteProvisionalLoadWithoutPSON) |
| { |
| runCancelCrossSiteProvisionalLoadTest(ShouldEnablePSON::No); |
| } |
| |
| TEST(ProcessSwap, CancelCrossSiteProvisionalLoadWithPSON) |
| { |
| runCancelCrossSiteProvisionalLoadTest(ShouldEnablePSON::Yes); |
| } |
| |
| TEST(ProcessSwap, DoSameSiteNavigationAfterCrossSiteProvisionalLoadStarted) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| delegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| |
| delegate->decidePolicyForNavigationAction = nil; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]]; |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[webView URL] absoluteString]); |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, SuspendedPageLimit) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| auto maximumSuspendedPageCount = [processPool _maximumSuspendedPageCount]; |
| EXPECT_GT(maximumSuspendedPageCount, 0U); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.yahoo.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Navigations to 5 different domains, we expect to have seen 5 different PIDs |
| EXPECT_EQ(5u, seenPIDs.size()); |
| |
| // But not all of those processes should still be alive (1 visible, maximumSuspendedPageCount suspended). |
| auto expectedProcessCount = 1 + maximumSuspendedPageCount; |
| int timeout = 20; |
| while ([processPool _webProcessCountIgnoringPrewarmedAndCached] != expectedProcessCount && timeout >= 0) { |
| TestWebKitAPI::Util::sleep(0.1); |
| --timeout; |
| } |
| |
| EXPECT_EQ(expectedProcessCount, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| } |
| |
| TEST(ProcessSwap, PageCache1) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad1 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad2 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_NE(pidAfterLoad1, pidAfterLoad2); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad1, pidAfterLoad3); |
| EXPECT_EQ(1u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad4 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad2, pidAfterLoad4); |
| EXPECT_EQ(2u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| TEST(ProcessSwap, NavigateBackAfterCrossOriginClientRedirect) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://webkit.org/navigated_from" toData:"<a href='pson://apple.com/'>hello</a>"]; |
| [handler addMappingFromURLString:@"pson://apple.com/" toData:"<script>window.location.href='pson://webkit.org/redirected_to'</script>redirecting..."]; |
| [handler addMappingFromURLString:@"pson://webkit.org/redirected_to" toData:"<p>hello again</p>"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://webkit.org/navigated_from"]]]; |
| [webView _test_waitForDidFinishNavigation]; |
| |
| [webView evaluateJavaScript:@"document.querySelector('a').click()" completionHandler:nil]; |
| [webView _test_waitForDidFinishNavigation]; |
| [webView _test_waitForDidFinishNavigation]; |
| EXPECT_WK_STREQ([webView objectByEvaluatingJavaScript:@"window.location.href"], "pson://webkit.org/redirected_to"); |
| [webView goBack]; |
| [webView _test_waitForDidFinishNavigation]; |
| EXPECT_WK_STREQ([webView objectByEvaluatingJavaScript:@"window.location.href"], "pson://webkit.org/navigated_from"); |
| } |
| |
| TEST(ProcessSwap, BackForwardCacheSkipBackForwardListItem) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html#foo"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_EQ(1U, [[[webView backForwardList] backList] count]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| // Go 2 items back. |
| EXPECT_EQ(2U, [[[webView backForwardList] backList] count]); |
| [webView goToBackForwardListItem:[[webView backForwardList] itemAtIndex:-2]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| |
| // Go 2 items forward. |
| EXPECT_EQ(2U, [[[webView backForwardList] forwardList] count]); |
| [webView goToBackForwardListItem:[[webView backForwardList] itemAtIndex:2]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| // Go back. |
| EXPECT_EQ(2U, [[[webView backForwardList] backList] count]); |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html#foo", [[webView URL] absoluteString]); |
| } |
| |
| TEST(ProcessSwap, ClearWebsiteDataWithSuspendedPage) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().usesWebProcessCache = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad1 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pidAfterLoad1, pidAfterLoad2); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad3 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pidAfterLoad2, pidAfterLoad3); |
| |
| __block bool readyToContinue = false; |
| [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate] modifiedSince:[NSDate distantPast] completionHandler:^() { |
| readyToContinue = true; |
| }]; |
| TestWebKitAPI::Util::run(&readyToContinue); |
| } |
| |
| TEST(ProcessSwap, PageCacheAfterProcessSwapByClient) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad1 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| // We force a proces-swap via client API. |
| delegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(_WKNavigationActionPolicyAllowInNewProcess); |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad2 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_NE(pidAfterLoad1, pidAfterLoad2); |
| |
| delegate->decidePolicyForNavigationAction = nil; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad1, pidAfterLoad3); |
| EXPECT_EQ(1u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad4 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad2, pidAfterLoad4); |
| EXPECT_EQ(2u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| TEST(ProcessSwap, PageCacheWhenNavigatingFromJS) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad1 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad2 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_NE(pidAfterLoad1, pidAfterLoad2); |
| |
| [webView evaluateJavaScript:@"history.back()" completionHandler: nil]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad1, pidAfterLoad3); |
| EXPECT_EQ(1u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| |
| [webView evaluateJavaScript:@"history.forward()" completionHandler: nil]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pidAfterLoad4 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_EQ(pidAfterLoad2, pidAfterLoad4); |
| EXPECT_EQ(2u, [receivedMessages count]); |
| EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| } |
| |
| #if PLATFORM(MAC) // WebProcessCache is disabled on devices with too little RAM. |
| |
| TEST(ProcessSwap, UseWebProcessCacheAfterTermination) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| int webkitPID = 0; |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| webkitPID = [webView _webProcessIdentifier]; |
| } |
| |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]); |
| |
| __block bool webProcessTerminated = false; |
| [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView *) { |
| webProcessTerminated = true; |
| }]; |
| |
| kill(applePID, 9); |
| TestWebKitAPI::Util::run(&webProcessTerminated); |
| webProcessTerminated = false; |
| |
| EXPECT_EQ(0, [webView _webProcessIdentifier]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]); |
| } |
| |
| TEST(ProcessSwap, ProcessCrashedWhileInTheCache) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| int webkitPID = 0; |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| webkitPID = [webView _webProcessIdentifier]; |
| } |
| |
| while ([processPool _processCacheSize] != 1) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| kill(webkitPID, 9); |
| |
| while ([processPool _processCacheSize]) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, ProcessTerminatedWhileInTheCache) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| int webkitPID = 0; |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| webkitPID = [webView _webProcessIdentifier]; |
| } |
| |
| while ([processPool _processCacheSize] != 1) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| EXPECT_TRUE([processPool _requestWebProcessTermination:webkitPID]); |
| TestWebKitAPI::Util::spinRunLoop(100); |
| |
| EXPECT_EQ(0U, [processPool _processCacheSize]); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, UseWebProcessCacheForLoadInNewView) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| |
| int webkitPID = 0; |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| // Process launch should be delayed until a load actually happens. |
| EXPECT_EQ(0, [webView _webProcessIdentifier]); |
| TestWebKitAPI::Util::sleep(0.1); |
| EXPECT_EQ(0, [webView _webProcessIdentifier]); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| webkitPID = [webView _webProcessIdentifier]; |
| EXPECT_NE(0, webkitPID); |
| } |
| |
| while ([processPool _processCacheSize] != 1) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]); |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]); |
| } |
| |
| while ([processPool _processCacheSize] != 1) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmed]); |
| |
| @autoreleasepool { |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]); |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| TEST(ProcessSwap, NumberOfPrewarmedProcesses) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(2u, [processPool _webProcessCount]); |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_TRUE([processPool _hasPrewarmedWebProcess]); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(3u, [processPool _webProcessCount]); |
| EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_TRUE([processPool _hasPrewarmedWebProcess]); |
| } |
| |
| #if PLATFORM(MAC) |
| |
| TEST(ProcessSwap, NumberOfCachedProcesses) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().prewarmsProcessesAutomatically = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| EXPECT_GT([processPool _maximumSuspendedPageCount], 0u); |
| EXPECT_GT([processPool _processCacheCapacity], 0u); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| |
| const unsigned maxSuspendedPageCount = [processPool _maximumSuspendedPageCount]; |
| for (unsigned i = 0; i < maxSuspendedPageCount + 2; i++) |
| [handler addMappingFromURLString:makeString("pson://www.domain-", i, ".com") toData:pageCache1Bytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| for (unsigned i = 0; i < maxSuspendedPageCount + 1; i++) { |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:makeString("pson://www.domain-", i, ".com")]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(i + 1, [processPool _webProcessCount]); |
| EXPECT_EQ(i + 1, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_FALSE([processPool _hasPrewarmedWebProcess]); |
| } |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:makeString("pson://www.domain-", maxSuspendedPageCount + 1, ".com")]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| int timeout = 100; |
| while (([processPool _webProcessCount] > (maxSuspendedPageCount + 2) && [processPool _webProcessCountIgnoringPrewarmedAndCached] > (maxSuspendedPageCount + 1)) && timeout > 0) { |
| TestWebKitAPI::Util::sleep(0.1); |
| --timeout; |
| } |
| |
| EXPECT_EQ(maxSuspendedPageCount + 2, [processPool _webProcessCount]); |
| EXPECT_EQ(maxSuspendedPageCount + 1, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_FALSE([processPool _hasPrewarmedWebProcess]); |
| |
| static bool readyToContinue = false; |
| [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore _allWebsiteDataTypesIncludingPrivate] modifiedSince:[NSDate distantPast] completionHandler:^() { |
| readyToContinue = true; |
| }]; |
| TestWebKitAPI::Util::run(&readyToContinue); |
| |
| timeout = 100; |
| while ([processPool _webProcessCount] > 1 && timeout > 0) { |
| TestWebKitAPI::Util::sleep(0.1); |
| --timeout; |
| } |
| |
| EXPECT_EQ(1u, [processPool _webProcessCount]); |
| EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]); |
| EXPECT_FALSE([processPool _hasPrewarmedWebProcess]); |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| static const char* visibilityBytes = R"PSONRESOURCE( |
| <script> |
| window.addEventListener('pageshow', function(event) { |
| var msg = window.location.href + " - pageshow "; |
| msg += event.persisted ? "persisted" : "NOT persisted"; |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| }); |
| |
| window.addEventListener('pagehide', function(event) { |
| var msg = window.location.href + " - pagehide "; |
| msg += event.persisted ? "persisted" : "NOT persisted"; |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| }); |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, PageShowHide) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:visibilityBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:visibilityBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| while ([receivedMessages count] < 7) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| EXPECT_EQ(7u, [receivedMessages count]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow NOT persisted", receivedMessages.get()[0]); |
| if ([receivedMessages.get()[1] hasPrefix:@"pson://www.webkit.org/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[1]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[2]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[1]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[2]); |
| } |
| if ([receivedMessages.get()[3] hasPrefix:@"pson://www.apple.com/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[3]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[4]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[3]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[4]); |
| } |
| if ([receivedMessages.get()[5] hasPrefix:@"pson://www.webkit.org/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[5]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[6]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[5]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[6]); |
| } |
| } |
| |
| // Disabling the back/forward cache explicitly is (for some reason) not available on iOS. |
| #if !TARGET_OS_IPHONE |
| static const char* loadUnloadBytes = R"PSONRESOURCE( |
| <script> |
| window.addEventListener('unload', function(event) { |
| var msg = window.location.href + " - unload"; |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| }); |
| |
| window.addEventListener('load', function(event) { |
| var msg = window.location.href + " - load"; |
| window.webkit.messageHandlers.pson.postMessage(msg); |
| }); |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, LoadUnload) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:loadUnloadBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:loadUnloadBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| [[webViewConfiguration preferences] _setUsesPageCache:NO]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| while ([receivedMessages count] < 7) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| EXPECT_EQ(7u, [receivedMessages count]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[0]); |
| if ([receivedMessages.get()[1] hasPrefix:@"pson://www.webkit.org/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[1]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[2]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[1]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[2]); |
| } |
| if ([receivedMessages.get()[3] hasPrefix:@"pson://www.apple.com/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[3]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[4]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[3]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[4]); |
| } |
| if ([receivedMessages.get()[5] hasPrefix:@"pson://www.webkit.org/main.html"]) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[5]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[6]); |
| } else { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[5]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[6]); |
| } |
| } |
| |
| TEST(ProcessSwap, WebInspector) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get().preferences._developerExtrasEnabled = YES; |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| [[webView _inspector] show]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| [[webView _inspector] close]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(pid1, pid2); // We should have swapped. |
| EXPECT_NE(pid2, pid3); // We should have swapped again. |
| EXPECT_EQ(numberOfDecidePolicyCalls, 3); |
| } |
| |
| TEST(ProcessSwap, WebInspectorDelayedProcessLaunch) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get().preferences._developerExtrasEnabled = YES; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| EXPECT_EQ(0, [webView _webProcessIdentifier]); |
| TestWebKitAPI::Util::spinRunLoop(100); |
| EXPECT_EQ(0, [webView _webProcessIdentifier]); |
| |
| [[webView _inspector] show]; |
| EXPECT_TRUE([[webView _inspector] isConnected]); |
| |
| // Trying to inspect the view should launch a WebProcess. |
| while (![webView _webProcessIdentifier]) |
| TestWebKitAPI::Util::spinRunLoop(10); |
| EXPECT_NE(0, [webView _webProcessIdentifier]); |
| |
| [[webView _inspector] close]; |
| } |
| |
| #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 = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto 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://www.webkit.org/main.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 = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto 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://www.webkit.org/main.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:@"pson://www.apple.com/main.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 = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto 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://www.webkit.org/main.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 = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto 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://www.webkit.org/main.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); |
| } |
| |
| TEST(ProcessSwap, ProcessReuse) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| // Two process swaps have occurred, but we should only have ever seen 2 pids. |
| EXPECT_EQ(2u, seenPIDs.size()); |
| EXPECT_NE(pid1, pid2); |
| EXPECT_NE(pid2, pid3); |
| EXPECT_EQ(pid1, pid3); |
| } |
| |
| TEST(ProcessSwap, ProcessReuseeTLDPlus2) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www1.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www2.webkit.org/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| // Two process swaps have occurred, but we should only have ever seen 2 pids. |
| EXPECT_EQ(2u, seenPIDs.size()); |
| EXPECT_NE(pid1, pid2); |
| EXPECT_NE(pid2, pid3); |
| EXPECT_EQ(pid1, pid3); |
| } |
| |
| TEST(ProcessSwap, ConcurrentHistoryNavigations) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| |
| auto* backForwardList = [webView backForwardList]; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.backItem); |
| EXPECT_EQ(1U, backForwardList.forwardList.count); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]); |
| |
| // Concurrent requests to go forward, which process swaps. |
| [webView goForward]; |
| [webView goForward]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.backItem); |
| EXPECT_EQ(1U, backForwardList.forwardList.count); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]); |
| } |
| |
| TEST(ProcessSwap, NavigateToInvalidURL) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| |
| __block bool evaluated = false; |
| [webView evaluateJavaScript:@"var err = 'no error'; try { location.href = 'http://A=a%B=b' } catch(e) { err=e; }; err.message" completionHandler:^(id result, NSError *error) { |
| EXPECT_WK_STREQ(result, "Invalid URL"); |
| EXPECT_NULL(error); |
| evaluated = true; |
| }]; |
| |
| TestWebKitAPI::Util::run(&evaluated); |
| |
| TestWebKitAPI::Util::spinRunLoop(1); |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| EXPECT_EQ(1, numberOfDecidePolicyCalls); |
| EXPECT_EQ(pid1, pid2); |
| } |
| |
| static const char* navigateToDataURLThenBackBytes = R"PSONRESOURCE( |
| <script> |
| onpageshow = function(event) { |
| if (sessionStorage.getItem('navigated') == 'true') { |
| sessionStorage.clear(); |
| return; |
| } |
| sessionStorage.setItem('navigated', 'true'); |
| |
| // Location changes need to happen outside the onload handler to generate history entries. |
| setTimeout(function() { |
| window.location.href = "data:text/html,<body onload='history.back()'></body>"; |
| }, 0); |
| } |
| |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, NavigateToDataURLThenBack) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().pageCacheEnabled = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get()._allowTopNavigationToDataURLs = YES; |
| auto handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToDataURLThenBackBytes]); |
| [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()]; |
| |
| numberOfDecidePolicyCalls = 0; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_EQ(1u, seenPIDs.size()); |
| EXPECT_EQ(pid1, pid2); |
| EXPECT_EQ(pid2, pid3); |
| } |
| |
| TEST(ProcessSwap, NavigateCrossSiteWithPageCacheDisabled) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().pageCacheEnabled = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto applePID = [webView _webProcessIdentifier]; |
| |
| EXPECT_NE(webkitPID, applePID); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(applePID, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, APIControlledProcessSwapping) |
| { |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| auto handler = adoptNS([[PSONScheme alloc] initWithBytes:"Hello World!"]); |
| [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()]; |
| |
| numberOfDecidePolicyCalls = 0; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/1"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| // Navigating from the above URL to this URL normally should not process swap. |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/2"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid2 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(1u, seenPIDs.size()); |
| EXPECT_EQ(pid1, pid2); |
| |
| // Navigating from the above URL to this URL normally should not process swap, |
| // but we'll explicitly ask for a swap. |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(_WKNavigationActionPolicyAllowInNewProcess); |
| }; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/3"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid3 = [webView _webProcessIdentifier]; |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_EQ(2u, seenPIDs.size()); |
| EXPECT_NE(pid1, pid3); |
| } |
| |
| enum class WithDelay : bool { No, Yes }; |
| static void runAPIControlledProcessSwappingThenBackTest(WithDelay withDelay) |
| { |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| auto handler = adoptNS([[PSONScheme alloc] initWithBytes:"Hello World!"]); |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(_WKNavigationActionPolicyAllowInNewProcess); |
| }; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| // Give time to the suspended WebPage to close. |
| if (withDelay == WithDelay::Yes) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| navigationDelegate->decidePolicyForNavigationAction = nil; |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, APIControlledProcessSwappingThenBackWithDelay) |
| { |
| runAPIControlledProcessSwappingThenBackTest(WithDelay::Yes); |
| } |
| |
| TEST(ProcessSwap, APIControlledProcessSwappingThenBackWithoutDelay) |
| { |
| runAPIControlledProcessSwappingThenBackTest(WithDelay::No); |
| } |
| |
| static const char* navigateToCrossSiteThenBackFromJSBytes = R"PSONRESOURCE( |
| <script> |
| onpageshow = function(event) { |
| // Location changes need to happen outside the onload handler to generate history entries. |
| setTimeout(function() { |
| window.location.href = "pson://www.apple.com/main.html"; |
| }, 0); |
| } |
| |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* navigateBackFromJSBytes = R"PSONRESOURCE( |
| <body onload='history.back()'></body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, NavigateToCrossSiteThenBackFromJS) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().pageCacheEnabled = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigateToCrossSiteThenBackFromJSBytes]; // Navigates to "pson://www.apple.com/main.html". |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:navigateBackFromJSBytes]; |
| [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()]; |
| |
| numberOfDecidePolicyCalls = 0; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); // Should have process-swapped when going from webkit.org to apple.com. |
| |
| // Page now calls history.back() to navigate back to webkit.org. |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| |
| // Should have process-swapped when going from apple.com to webkit.org. |
| // PID is not necessarily webkitPID because PageCache is disabled. |
| EXPECT_NE(applePID, [webView _webProcessIdentifier]); |
| } |
| |
| static const char* crossSiteFormSubmissionBytes = R"PSONRESOURCE( |
| <body> |
| <form action="pson://www.apple.com/main.html" method="post"> |
| Name: <input type="text" name="name" placeholder="Name"> |
| <input id="submitButton" type="submit"> |
| </form> |
| </body> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, SwapOnFormSubmission) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:crossSiteFormSubmissionBytes]; |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto webkitPID = [webView _webProcessIdentifier]; |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| |
| [webView evaluateJavaScript:@"submitButton.click()" completionHandler:nil]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto applePID = [webView _webProcessIdentifier]; |
| EXPECT_NE(webkitPID, applePID); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView reload]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| EXPECT_EQ(applePID, [webView _webProcessIdentifier]); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| #if !PLATFORM(IOS_FAMILY) |
| // This is not guaranteed on iOS because the WebProcess cache is disabled on devices with too little RAM. |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| #else |
| EXPECT_NE(applePID, [webView _webProcessIdentifier]); |
| #endif |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]); |
| } |
| |
| TEST(ProcessSwap, ClosePageAfterCrossSiteProvisionalLoad) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| didStartProvisionalLoad = false; |
| [webView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]]; |
| |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(WKNavigationActionPolicyAllow); |
| |
| [webView _close]; |
| done = true; |
| }; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::sleep(0.5); |
| } |
| |
| static Vector<bool> loadingStateChanges; |
| static unsigned urlChangeCount; |
| |
| @interface PSONLoadingObserver : NSObject |
| @end |
| |
| @implementation PSONLoadingObserver |
| |
| -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context |
| { |
| WKWebView *webView = (WKWebView *)context; |
| |
| if ([keyPath isEqualToString:@"loading"]) |
| loadingStateChanges.append([webView isLoading]); |
| else if ([keyPath isEqualToString:@"URL"]) |
| ++urlChangeCount; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| } |
| |
| @end |
| |
| TEST(ProcessSwap, LoadingStateAfterPolicyDecision) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto loadObserver = adoptNS([[PSONLoadingObserver alloc] init]); |
| [webView addObserver:loadObserver.get() forKeyPath:@"loading" options:0 context:webView.get()]; |
| [webView addObserver:loadObserver.get() forKeyPath:@"URL" options:0 context:webView.get()]; |
| |
| urlChangeCount = 0; |
| didStartProvisionalLoad = false; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]]; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_TRUE([webView isLoading]); |
| |
| EXPECT_EQ(1U, loadingStateChanges.size()); |
| EXPECT_TRUE(loadingStateChanges[0]); |
| EXPECT_EQ(1U, urlChangeCount); |
| |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_TRUE([webView isLoading]); |
| |
| decisionHandler(WKNavigationActionPolicyAllow); |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_TRUE([webView isLoading]); |
| }; |
| |
| EXPECT_EQ(1U, loadingStateChanges.size()); |
| |
| TestWebKitAPI::Util::run(&didStartProvisionalLoad); |
| didStartProvisionalLoad = false; |
| |
| EXPECT_EQ(1U, loadingStateChanges.size()); |
| EXPECT_EQ(1U, urlChangeCount); |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_TRUE([webView isLoading]); |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| EXPECT_FALSE([webView isLoading]); |
| |
| EXPECT_EQ(2U, loadingStateChanges.size()); |
| EXPECT_FALSE(loadingStateChanges[1]); |
| EXPECT_EQ(1U, urlChangeCount); |
| |
| [webView removeObserver:loadObserver.get() forKeyPath:@"loading" context:webView.get()]; |
| [webView removeObserver:loadObserver.get() forKeyPath:@"URL" context:webView.get()]; |
| } |
| |
| static const char* saveOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| savedOpener = opener; |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, OpenerLinkAfterAPIControlledProcessSwappingOfOpener) |
| { |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:windowOpenSameSiteWithOpenerTestBytes]; // Opens "pson://www.webkit.org/main2.html". |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:saveOpenerTestBytes]; |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid1, [createdWebView _webProcessIdentifier]); |
| |
| // Auxiliary window should have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener.location.href" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We force a proces-swap via client API. |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(_WKNavigationActionPolicyAllowInNewProcess); |
| }; |
| |
| // Navigating from the above URL to this URL normally should not process swap. |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main3.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| bool hasOpener = true; |
| int timeout = 50; |
| do { |
| if (timeout != 50) |
| TestWebKitAPI::Util::sleep(0.1); |
| |
| // Auxiliary window's opener should no longer have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpenerString, NSError *error) { |
| hasOpener = [hasOpenerString isEqualToString:@"true"]; |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } while (hasOpener && (--timeout)); |
| EXPECT_FALSE(hasOpener); |
| |
| [createdWebView evaluateJavaScript:@"savedOpener.closed ? 'true' : 'false'" completionHandler: [&] (id savedOpenerIsClosed, NSError *error) { |
| EXPECT_WK_STREQ(@"true", savedOpenerIsClosed); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, OpenerLinkAfterAPIControlledProcessSwappingOfOpenee) |
| { |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:windowOpenSameSiteWithOpenerTestBytes]; // Opens "pson://www.webkit.org/main2.html". |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:saveOpenerTestBytes]; |
| [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()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(pid1, [createdWebView _webProcessIdentifier]); |
| |
| // Auxiliary window should have an opener. |
| [webView evaluateJavaScript:@"w.opener.location.href" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We force a proces-swap via client API. |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(_WKNavigationActionPolicyAllowInNewProcess); |
| }; |
| |
| // Navigating from the above URL to this URL normally should not process swap. |
| [createdWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main3.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| // Auxiliary window's opener should no longer have an opener. |
| [webView evaluateJavaScript:@"w.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"false", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| static void runProcessSwapDueToRelatedWebViewTest(NSURL* relatedViewURL, NSURL* targetURL, ExpectSwap expectSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView1Configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webView1Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView1Configuration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| numberOfDecidePolicyCalls = 0; |
| NSURLRequest *request = [NSURLRequest requestWithURL:relatedViewURL]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| |
| auto webView2Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView2Configuration setProcessPool:processPool.get()]; |
| [webView2Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| webView2Configuration.get()._relatedWebView = webView1.get(); // webView2 will be related to webView1 and webView1's URL will be used for process swap decision. |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView2Configuration.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| request = [NSURLRequest requestWithURL:targetURL]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView2 _webProcessIdentifier]; |
| |
| if (expectSwap == ExpectSwap::No) |
| EXPECT_TRUE(pid1 == pid2); |
| else |
| EXPECT_FALSE(pid1 == pid2); |
| |
| EXPECT_EQ(2, numberOfDecidePolicyCalls); |
| } |
| |
| TEST(ProcessSwap, ProcessSwapDueToRelatedView) |
| { |
| runProcessSwapDueToRelatedWebViewTest([NSURL URLWithString:@"pson://www.webkit.org/main1.html"], [NSURL URLWithString:@"pson://www.apple.com/main2.html"], ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NoProcessSwapDueToRelatedView) |
| { |
| runProcessSwapDueToRelatedWebViewTest([NSURL URLWithString:@"pson://www.webkit.org/main1.html"], [NSURL URLWithString:@"pson://www.webkit.org/main2.html"], ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, RelatedWebViewBeforeWebProcessLaunch) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView1Configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webView1Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView1Configuration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| auto webView2Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView2Configuration setProcessPool:processPool.get()]; |
| [webView2Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| webView2Configuration.get()._relatedWebView = webView1.get(); // webView2 will be related to webView1 and webView1's URL will be used for process swap decision. |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView2Configuration.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView2 _webProcessIdentifier]; |
| |
| EXPECT_EQ(pid1, pid2); // WebViews are related so they should share the same process. |
| } |
| |
| TEST(ProcessSwap, ReloadRelatedWebViewAfterCrash) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView1Configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webView1Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView1Configuration.get()]); |
| auto delegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| __block bool didCrash = false; |
| [delegate setWebContentProcessDidTerminate:^(WKWebView *view) { |
| [view reload]; |
| didCrash = true; |
| }]; |
| [delegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| auto webView2Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView2Configuration setProcessPool:processPool.get()]; |
| [webView2Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| webView2Configuration.get()._relatedWebView = webView1.get(); // webView2 will be related to webView1 and webView1's URL will be used for process swap decision. |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView2Configuration.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView2 _webProcessIdentifier]; |
| |
| EXPECT_EQ(pid1, pid2); // WebViews are related so they should share the same process. |
| |
| [webView1 _close]; |
| webView1 = nullptr; |
| |
| kill(pid1, 9); |
| |
| TestWebKitAPI::Util::run(&didCrash); |
| didCrash = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, TerminatedSuspendedPageProcess) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| @autoreleasepool { |
| auto webViewConfiguration2 = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration2 setProcessPool:processPool.get()]; |
| [webViewConfiguration2 _setRelatedWebView:webView.get()]; // Make sure it uses the same process. |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration2.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView2 _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView2 _killWebContentProcessAndResetState]; |
| webView2 = nullptr; |
| webViewConfiguration2 = nullptr; |
| } |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid3); |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid4 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid4); |
| EXPECT_NE(pid3, pid4); |
| } |
| |
| TEST(ProcessSwap, CommittedProcessCrashDuringCrossSiteNavigation) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [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()]; |
| |
| done = false; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| static bool didKill = false; |
| navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) { |
| decisionHandler(WKNavigationActionPolicyAllow); // Will ask the load to proceed in a new provisional WebProcess since the navigation is cross-site. |
| |
| // Simulate a crash of the committed WebProcess while the provisional navigation starts in the new provisional WebProcess. |
| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ |
| kill(pid1, 9); |
| didKill = true; |
| }); |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&didKill); |
| |
| TestWebKitAPI::Util::sleep(0.5); |
| } |
| |
| TEST(ProcessSwap, NavigateBackAndForth) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto* backForwardList = [webView backForwardList]; |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]); |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.backItem); |
| EXPECT_EQ(1U, backForwardList.forwardList.count); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]); |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]); |
| EXPECT_TRUE(!backForwardList.forwardItem); |
| EXPECT_EQ(1U, backForwardList.backList.count); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]); |
| } |
| |
| TEST(ProcessSwap, SwapOnLoadHTMLString) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| numberOfDecidePolicyCalls = 0; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| NSString *htmlString = @"<html><body>substituteData</body></html>"; |
| [webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:@"http://example.com"]]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| EXPECT_EQ(2, numberOfDecidePolicyCalls); |
| |
| [webView evaluateJavaScript:@"document.body.innerText" completionHandler:^(id innerText, NSError *error) { |
| EXPECT_WK_STREQ(@"substituteData", (NSString *)innerText); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, EphemeralWebStorage) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/iframe.html" toData:"<script>window.localStorage.setItem('c','d')</script>"]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://webkit.org/"]]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.localStorage.setItem('a','b')" completionHandler:^(id, NSError *) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.sessionStorage.setItem('b','a')" completionHandler:^(id, NSError *) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://example.com/"]]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://webkit.org/"]]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.localStorage.getItem('a')" completionHandler:^(id result, NSError *) { |
| EXPECT_TRUE([@"b" isEqualToString:result]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.sessionStorage.getItem('b')" completionHandler:^(id result, NSError *) { |
| EXPECT_TRUE([@"a" isEqualToString:result]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView loadHTMLString:@"<html><iframe src='pson://www.webkit.org/iframe.html'></iframe></html>" baseURL:[NSURL URLWithString:@"http://www.example.com/"]]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.localStorage.getItem('a')" completionHandler:^(id result, NSError *) { |
| EXPECT_FALSE([@"b" isEqualToString:result]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| |
| done = false; |
| [webView evaluateJavaScript:@"window.sessionStorage.getItem('b')" completionHandler:^(id result, NSError *) { |
| EXPECT_FALSE([@"a" isEqualToString:result]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| } |
| |
| TEST(ProcessSwap, UsePrewarmedProcessAfterTerminatingNetworkProcess) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto websiteDataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get().websiteDataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:websiteDataStoreConfiguration.get()]).get(); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::spinRunLoop(1); |
| |
| [webViewConfiguration.get().websiteDataStore _terminateNetworkProcess]; |
| |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, UseSessionCookiesAfterProcessSwapInPrivateBrowsing) |
| { |
| auto originalCookieAcceptPolicy = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy]; |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| RetainPtr<WKWebsiteDataStore> ephemeralStore = [WKWebsiteDataStore nonPersistentDataStore]; |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get().websiteDataStore = ephemeralStore.get(); |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| __block bool setPolicy = false; |
| [webView.get().configuration.websiteDataStore.httpCookieStore _setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways completionHandler:^{ |
| setPolicy = true; |
| }]; |
| TestWebKitAPI::Util::run(&setPolicy); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"SetSessionCookie" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| // Should process-swap. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| // Should process-swap. |
| request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"GetSessionCookie" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid2, pid3); |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| |
| EXPECT_EQ(1u, [receivedMessages count]); |
| EXPECT_WK_STREQ(@"foo=bar", receivedMessages.get()[0]); |
| |
| setPolicy = false; |
| [webView.get().configuration.websiteDataStore.httpCookieStore _setCookieAcceptPolicy:originalCookieAcceptPolicy completionHandler:^{ |
| setPolicy = true; |
| }]; |
| TestWebKitAPI::Util::run(&setPolicy); |
| } |
| |
| TEST(ProcessSwap, UseSessionCookiesAfterProcessSwapInNonDefaultPersistentSession) |
| { |
| auto originalCookieAcceptPolicy = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy]; |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| |
| // Prevent WebProcess reuse. |
| processPoolConfiguration.get().usesWebProcessCache = NO; |
| processPoolConfiguration.get().pageCacheEnabled = NO; |
| processPoolConfiguration.get().prewarmsProcessesAutomatically = NO; |
| |
| auto websiteDataStoreConfiguration = adoptNS([[_WKWebsiteDataStoreConfiguration alloc] init]); |
| auto customDataStore = adoptNS([[WKWebsiteDataStore alloc] _initWithConfiguration:websiteDataStoreConfiguration.get()]); |
| |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get().websiteDataStore = customDataStore.get(); |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"testHandler"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| __block bool setPolicy = false; |
| [webView.get().configuration.websiteDataStore.httpCookieStore _setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways completionHandler:^{ |
| setPolicy = true; |
| }]; |
| TestWebKitAPI::Util::run(&setPolicy); |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"SetSessionCookie" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| // Should process-swap. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| // Should process-swap. |
| request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"GetSessionCookie" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid3 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid2, pid3); |
| EXPECT_NE(pid1, pid3); |
| |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| |
| EXPECT_EQ(1u, [receivedMessages count]); |
| EXPECT_WK_STREQ(@"foo=bar", receivedMessages.get()[0]); |
| |
| setPolicy = false; |
| [webView.get().configuration.websiteDataStore.httpCookieStore _setCookieAcceptPolicy:originalCookieAcceptPolicy completionHandler:^{ |
| setPolicy = true; |
| }]; |
| TestWebKitAPI::Util::run(&setPolicy); |
| } |
| |
| TEST(ProcessSwap, ProcessSwapInRelatedView) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView1Configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webView1Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView1Configuration.get()]); |
| |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto applePID = [webView1 _webProcessIdentifier]; |
| |
| auto webView2Configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webView2Configuration setProcessPool:processPool.get()]; |
| [webView2Configuration _setRelatedWebView:webView1.get()]; |
| [webView2Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView2Configuration.get()]); |
| [webView2 _restoreSessionState:webView1.get()._sessionState andNavigate:NO]; |
| |
| [webView2 setNavigationDelegate:delegate.get()]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView2 loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView2 _webProcessIdentifier]; |
| EXPECT_NE(applePID, webkitPID); |
| } |
| |
| TEST(ProcessSwap, TerminateProcessAfterProcessSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| [webView setAllowsBackForwardNavigationGestures:YES]; |
| |
| auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| __block bool webProcessTerminated = false; |
| [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView *) { |
| webProcessTerminated = true; |
| }]; |
| [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| // Make sure there is a gesture controller. |
| #if PLATFORM(MAC) |
| [webView _setCustomSwipeViewsTopContentInset:2.]; |
| #endif |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_NE(webkitPID, [webView _webProcessIdentifier]); |
| |
| webProcessTerminated = false; |
| kill([webView _webProcessIdentifier], 9); |
| |
| TestWebKitAPI::Util::run(&webProcessTerminated); |
| |
| TestWebKitAPI::Util::spinRunLoop(1); |
| |
| [webView reload]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| #if PLATFORM(IOS_FAMILY) |
| static bool viewHasSwipeGestures(UIView *view) |
| { |
| unsigned swipeGestureCount = 0; |
| for (UIGestureRecognizer *recognizer in view.gestureRecognizers) { |
| if ([recognizer isKindOfClass:NSClassFromString(@"UIScreenEdgePanGestureRecognizer")]) |
| swipeGestureCount++; |
| } |
| |
| return swipeGestureCount == 2; |
| } |
| #endif |
| |
| TEST(ProcessSwap, SwapWithGestureController) |
| { |
| @autoreleasepool { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Ensure a ViewGestureController is created. |
| [webView setAllowsBackForwardNavigationGestures:YES]; |
| #if PLATFORM(MAC) |
| [webView _setCustomSwipeViewsTopContentInset:2.]; |
| #endif |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| #if PLATFORM(IOS_FAMILY) |
| EXPECT_TRUE(viewHasSwipeGestures(webView.get())); |
| #endif |
| } |
| } |
| |
| TEST(ProcessSwap, CrashWithGestureController) |
| { |
| @autoreleasepool { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| auto navigationDelegate = adoptNS([[TestNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| __block bool webProcessTerminated = false; |
| [navigationDelegate setWebContentProcessDidTerminate:^(WKWebView *) { |
| webProcessTerminated = true; |
| }]; |
| [navigationDelegate setDidFinishNavigation:^(WKWebView *, WKNavigation *) { |
| done = true; |
| }]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Ensure a ViewGestureController is created. |
| [webView setAllowsBackForwardNavigationGestures:YES]; |
| #if PLATFORM(MAC) |
| [webView _setCustomSwipeViewsTopContentInset:2.]; |
| #endif |
| |
| webProcessTerminated = false; |
| kill([webView _webProcessIdentifier], 9); |
| |
| TestWebKitAPI::Util::run(&webProcessTerminated); |
| |
| TestWebKitAPI::Util::spinRunLoop(1); |
| |
| [webView reload]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| #if PLATFORM(IOS_FAMILY) |
| EXPECT_TRUE(viewHasSwipeGestures(webView.get())); |
| #endif |
| } |
| } |
| |
| #if PLATFORM(MAC) |
| |
| TEST(ProcessSwap, NavigateCrossOriginWithOpenee) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:windowOpenSameSiteWithOpenerTestBytes]; // Opens "pson://www.webkit.org/main2.html". |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"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()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ([webView _webProcessIdentifier], [createdWebView _webProcessIdentifier]); |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]); |
| |
| // New window should have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"true", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Navigate cross-origin. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]); |
| |
| // Auxiliary window should still have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"true", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should not have process-swapped since an auxiliary window has an opener link to us. |
| EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]); |
| } |
| |
| static const char* crossSiteLinkWithOpenerTestBytes = R"PSONRESOURCE( |
| <script> |
| function saveOpenee() |
| { |
| openee = window.open("", "foo"); |
| } |
| </script> |
| <a id="testLink" target="foo" href="pson://www.webkit.org/main2.html">Link</a> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, NavigateCrossOriginWithOpener) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:crossSiteLinkWithOpenerTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"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()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Opens "pson://www.webkit.org/main2.html" in an auxiliary window. |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ([webView _webProcessIdentifier], [createdWebView _webProcessIdentifier]); |
| auto webkitPID = [webView _webProcessIdentifier]; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]); |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]); |
| |
| [webView evaluateJavaScript:@"saveOpenee()" completionHandler: [&] (id, NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"openee.location.href" completionHandler: [&] (id openeeURL, NSError *error) { |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", openeeURL); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // New window should have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"true", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Navigate auxiliary window cross-origin. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [createdWebView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[createdWebView URL] absoluteString]); |
| |
| // Auxiliary window should still have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"true", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| [createdWebView evaluateJavaScript:@"window.opener.closed ? 'true' : 'false'" completionHandler: [&] (id openerIsClosed, NSError *error) { |
| EXPECT_WK_STREQ(@"false", openerIsClosed); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // We should not have process-swapped since the auxiliary window has an opener. |
| EXPECT_EQ(webkitPID, [createdWebView _webProcessIdentifier]); |
| |
| // Have the openee disown its opener. |
| [createdWebView evaluateJavaScript:@"window.opener = null" completionHandler: [&] (id, NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Auxiliary window should not have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"false", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Navigate openee cross-origin again. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [createdWebView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // Auxiliary window should not have an opener. |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id hasOpener, NSError *error) { |
| EXPECT_WK_STREQ(@"false", hasOpener); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[createdWebView URL] absoluteString]); |
| // We still should not have process-swapped since the auxiliary window's opener still has a handle to its openee. |
| EXPECT_EQ(webkitPID, [createdWebView _webProcessIdentifier]); |
| |
| [webView evaluateJavaScript:@"openee.closed ? 'true' : 'false'" completionHandler: [&] (id openeeIsClosed, NSError *error) { |
| EXPECT_WK_STREQ(@"false", openeeIsClosed); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, GoBackToSuspendedPageWithMainFrameIDThatIsNotOne) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:targetBlankSameSiteNoOpenerTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:linkToAppleTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:navigationDelegate.get()]; |
| auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]); |
| [webView1 setUIDelegate:uiDelegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]]; |
| |
| [webView1 loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView1 URL] absoluteString]); |
| auto pid1 = [webView1 _webProcessIdentifier]; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // New WKWebView has now navigated to webkit.org. |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| |
| // We process-swap since there is no opener relationship. |
| EXPECT_NE(pid1, pid2); |
| |
| // Click link in new WKWebView so that it navigates cross-site to apple.com. |
| [createdWebView evaluateJavaScript:@"testLink.click()" completionHandler:nil]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| // New WKWebView has now navigated to apple.com. |
| EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[createdWebView URL] absoluteString]); |
| auto pid3 = [createdWebView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid3); // Should have process-swapped. |
| |
| // Navigate back to the suspended page (should use the back/forward cache). |
| [createdWebView goBack]; |
| TestWebKitAPI::Util::run(&receivedMessage); |
| receivedMessage = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]); |
| auto pid4 = [createdWebView _webProcessIdentifier]; |
| EXPECT_EQ(pid2, pid4); // Should have process-swapped to the original "suspended" process. |
| |
| // Do a fragment navigation in the original WKWebView and make sure this does not crash. |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html#testLink"]]; |
| [webView1 loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html#testLink", [[webView1 URL] absoluteString]); |
| auto pid5 = [createdWebView _webProcessIdentifier]; |
| EXPECT_EQ(pid2, pid5); |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| static const char* tallPageBytes = R"PSONRESOURCE( |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta name='viewport' content='width=device-width, initial-scale=1'> |
| <style> |
| body { |
| margin: 0; |
| width: 100%; |
| height: 10000px; |
| } |
| </style> |
| </head> |
| <body> |
| <script> |
| // Pages with dedicated workers do not go into back/forward cache. |
| var myWorker = new Worker('worker.js'); |
| </script> |
| <a id="testLink" href="pson://www.apple.com/main.html">Test</a> |
| </body> |
| </html> |
| )PSONRESOURCE"; |
| |
| static unsigned waitUntilScrollPositionIsRestored(WKWebView *webView) |
| { |
| unsigned scrollPosition = 0; |
| do { |
| [webView evaluateJavaScript:@"window.scrollY" completionHandler: [&] (id result, NSError *error) { |
| scrollPosition = [result integerValue]; |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } while (!scrollPosition); |
| |
| return scrollPosition; |
| } |
| |
| TEST(ProcessSwap, ScrollPositionRestoration) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:tallPageBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"scroll(0, 5000)" completionHandler: [&] (id result, NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| do { |
| TestWebKitAPI::Util::sleep(0.05); |
| } while (lroundf([[[webView backForwardList] currentItem] _scrollPosition].y) != 5000); |
| |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler: nil]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.scrollY" completionHandler: [&] (id result, NSError *error) { |
| EXPECT_EQ(0, [result integerValue]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto scrollPosition = waitUntilScrollPositionIsRestored(webView.get()); |
| EXPECT_EQ(5000U, scrollPosition); |
| |
| [webView evaluateJavaScript:@"scroll(0, 4000)" completionHandler: [&] (id result, NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| do { |
| TestWebKitAPI::Util::sleep(0.05); |
| } while (lroundf([[[webView backForwardList] currentItem] _scrollPosition].y) != 4000); |
| |
| [webView evaluateJavaScript:@"testLink.click()" completionHandler: nil]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.scrollY" completionHandler: [&] (id result, NSError *error) { |
| EXPECT_EQ(0, [result integerValue]); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| scrollPosition = waitUntilScrollPositionIsRestored(webView.get()); |
| EXPECT_EQ(4000U, scrollPosition); |
| } |
| |
| static NSString *blockmeFilter = @"[{\"action\":{\"type\":\"block\"},\"trigger\":{\"url-filter\":\".*blockme.html\"}}]"; |
| |
| static const char* contentBlockingAfterProcessSwapTestBytes = R"PSONRESOURCE( |
| <body> |
| <script> |
| let wasSubframeLoaded = false; |
| // Pages with dedicated workers do not go into back/forward cache. |
| var myWorker = new Worker('worker.js'); |
| </script> |
| <iframe src="blockme.html"></iframe> |
| </body> |
| )PSONRESOURCE"; |
| |
| static const char* markSubFrameAsLoadedTestBytes = R"PSONRESOURCE( |
| <script> |
| top.wasSubframeLoaded = true; |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, ContentBlockingAfterProcessSwap) |
| { |
| [[WKContentRuleListStore defaultStore] removeContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" completionHandler:^(NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| |
| __block bool doneCompiling = false; |
| [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" encodedContentRuleList:blockmeFilter completionHandler:^(WKContentRuleList *ruleList, NSError *error) { |
| |
| EXPECT_NOT_NULL(ruleList); |
| EXPECT_NULL(error); |
| |
| [webViewConfiguration.get().userContentController addContentRuleList:ruleList]; |
| |
| doneCompiling = true; |
| }]; |
| TestWebKitAPI::Util::run(&doneCompiling); |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:contentBlockingAfterProcessSwapTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/blockme.html" toData:markSubFrameAsLoadedTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:contentBlockingAfterProcessSwapTestBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/blockme.html" toData:markSubFrameAsLoadedTestBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.wasSubframeLoaded ? 'FAIL' : 'PASS'" completionHandler: [&] (id result, NSError *error) { |
| NSString *blockSuccess = (NSString *)result; |
| EXPECT_WK_STREQ(@"PASS", blockSuccess); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.wasSubframeLoaded ? 'FAIL' : 'PASS'" completionHandler: [&] (id result, NSError *error) { |
| NSString *blockSuccess = (NSString *)result; |
| EXPECT_WK_STREQ(@"PASS", blockSuccess); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.wasSubframeLoaded ? 'FAIL' : 'PASS'" completionHandler: [&] (id result, NSError *error) { |
| NSString *blockSuccess = (NSString *)result; |
| EXPECT_WK_STREQ(@"PASS", blockSuccess); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"window.wasSubframeLoaded ? 'FAIL' : 'PASS'" completionHandler: [&] (id result, NSError *error) { |
| NSString *blockSuccess = (NSString *)result; |
| EXPECT_WK_STREQ(@"PASS", blockSuccess); |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [[WKContentRuleListStore defaultStore] removeContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" completionHandler:^(NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| static const char* notifyLoadedBytes = R"PSONRESOURCE( |
| <script> |
| window.webkit.messageHandlers.pson.postMessage("Loaded"); |
| </script> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, ContentExtensionBlocksMainLoadThenReloadWithoutExtensions) |
| { |
| [[WKContentRuleListStore defaultStore] removeContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" completionHandler:^(NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get()._allowTopNavigationToDataURLs = YES; |
| |
| RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| __block bool doneCompiling = false; |
| [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" encodedContentRuleList:blockmeFilter completionHandler:^(WKContentRuleList *ruleList, NSError *error) { |
| |
| EXPECT_NOT_NULL(ruleList); |
| EXPECT_NULL(error); |
| |
| [webViewConfiguration.get().userContentController addContentRuleList:ruleList]; |
| |
| doneCompiling = true; |
| }]; |
| TestWebKitAPI::Util::run(&doneCompiling); |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.apple.com/blockme.html" toData:notifyLoadedBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| receivedMessage = false; |
| failed = false; |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/blockme.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&failed); |
| failed = false; |
| EXPECT_FALSE(receivedMessage); |
| |
| [webView _loadAlternateHTMLString:@"Blocked" baseURL:[NSURL URLWithString:@"data:text/html,"] forUnreachableURL:[NSURL URLWithString:@"pson://www.apple.com/blockme.html"]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView _reloadWithoutContentBlockers]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_FALSE(failed); |
| EXPECT_TRUE(receivedMessage); |
| EXPECT_WK_STREQ(@"pson://www.apple.com/blockme.html", [[webView URL] absoluteString]); |
| |
| [[WKContentRuleListStore defaultStore] removeContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" completionHandler:^(NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, LoadAlternativeHTML) |
| { |
| [[WKContentRuleListStore defaultStore] removeContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" completionHandler:^(NSError *error) { |
| done = true; |
| }]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| webViewConfiguration.get()._allowTopNavigationToDataURLs = YES; |
| |
| RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]); |
| [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"]; |
| |
| __block bool doneCompiling = false; |
| [[WKContentRuleListStore defaultStore] compileContentRuleListForIdentifier:@"ContentBlockingAfterProcessSwapExtension" encodedContentRuleList:blockmeFilter completionHandler:^(WKContentRuleList *ruleList, NSError *error) { |
| |
| EXPECT_NOT_NULL(ruleList); |
| EXPECT_NULL(error); |
| |
| [webViewConfiguration.get().userContentController addContentRuleList:ruleList]; |
| |
| doneCompiling = true; |
| }]; |
| TestWebKitAPI::Util::run(&doneCompiling); |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.apple.com/blockme.html" toData:notifyLoadedBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| receivedMessage = false; |
| failed = false; |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/blockme.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&failed); |
| failed = false; |
| EXPECT_FALSE(receivedMessage); |
| |
| [webView _loadAlternateHTMLString:@"Blocked" baseURL:[NSURL URLWithString:@"foo:blockedWarning.html"] forUnreachableURL:[NSURL URLWithString:@"pson://www.apple.com/blockme.html"]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| #if ENABLE(MEDIA_STREAM) |
| |
| static bool isCapturing = false; |
| static bool isNotCapturing = false; |
| @interface GetUserMediaUIDelegate : UserMediaCaptureUIDelegate |
| - (void)_webView:(WKWebView *)webView mediaCaptureStateDidChange:(_WKMediaCaptureStateDeprecated)state; |
| @end |
| |
| @implementation GetUserMediaUIDelegate |
| - (void)_webView:(WKWebView *)webView mediaCaptureStateDidChange:(_WKMediaCaptureStateDeprecated)state |
| { |
| isCapturing = state == _WKMediaCaptureStateDeprecatedActiveCamera; |
| isNotCapturing = !state; |
| } |
| @end |
| |
| static const char* getUserMediaBytes = R"PSONRESOURCE( |
| <head> |
| <body> |
| <script> |
| navigator.mediaDevices.getUserMedia({video: true}); |
| </script> |
| </body> |
| </head> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, GetUserMediaCaptureState) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().pageCacheEnabled = NO; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| auto preferences = [webViewConfiguration.get() preferences]; |
| preferences._mediaCaptureRequiresSecureConnection = NO; |
| webViewConfiguration.get()._mediaCaptureEnabled = YES; |
| preferences._mockCaptureDevicesEnabled = YES; |
| preferences._getUserMediaRequiresFocus = NO; |
| |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/getUserMedia.html" toData:getUserMediaBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.org/test.html" toData:""]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| webView.get()._mediaCaptureReportingDelayForTesting = 1; |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| auto uiDelegate = adoptNS([[GetUserMediaUIDelegate alloc] init]); |
| [webView setUIDelegate: uiDelegate.get()]; |
| |
| auto request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/getUserMedia.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&isCapturing); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.org/test.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| TestWebKitAPI::Util::run(&isNotCapturing); |
| |
| EXPECT_FALSE(isCapturing); |
| EXPECT_FALSE(pid1 == pid2); |
| |
| isCapturing = false; |
| [webView goBack]; |
| |
| TestWebKitAPI::Util::run(&isCapturing); |
| isCapturing = false; |
| isNotCapturing = true; |
| } |
| |
| #endif |
| |
| #if !PLATFORM(MAC) |
| static void traverseLayerTree(CALayer *layer, void(^block)(CALayer *)) |
| { |
| for (CALayer *child in layer.sublayers) |
| traverseLayerTree(child, block); |
| block(layer); |
| } |
| |
| static bool hasOverlay(CALayer *layer) |
| { |
| __block bool hasViewOverlay = false; |
| traverseLayerTree(layer, ^(CALayer *layer) { |
| if ([layer.name containsString:@"View overlay container"]) |
| hasViewOverlay = true; |
| }); |
| return hasViewOverlay; |
| } |
| #endif |
| |
| TEST(ProcessSwap, PageOverlayLayerPersistence) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| [processPoolConfiguration setInjectedBundleURL:[[NSBundle mainBundle] URLForResource:@"TestWebKitAPI" withExtension:@"wkbundle"]]; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| [processPool _setObject:@"PageOverlayPlugIn" forBundleParameter:TestWebKitAPI::Util::TestPlugInClassNameParameter]; |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/page-overlay" toData:""]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/page-overlay" toData:""]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| auto request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/page-overlay"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView waitForNextPresentationUpdate]; |
| |
| // We can only look for the overlay layer in the UI-side layer tree on platforms |
| // that use UI-side compositing. |
| #if !PLATFORM(MAC) |
| EXPECT_TRUE(hasOverlay([webView layer])); |
| #endif |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/page-overlay"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView waitForNextPresentationUpdate]; |
| |
| [webView goBack]; // Back to webkit.org. |
| |
| [webView waitForNextPresentationUpdate]; |
| |
| #if !PLATFORM(MAC) |
| EXPECT_TRUE(hasOverlay([webView layer])); |
| #endif |
| } |
| |
| #if PLATFORM(IOS) |
| |
| #if __IPHONE_OS_VERSION_MIN_REQUIRED > 130400 |
| TEST(ProcessSwap, QuickLookRequestsPasswordAfterSwap) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| auto* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"password-protected" withExtension:@"pages" subdirectory:@"TestWebKitAPI.resources"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&didStartQuickLookLoad); |
| didStartQuickLookLoad = false; |
| |
| TestWebKitAPI::Util::run(&requestedQuickLookPassword); |
| requestedQuickLookPassword = false; |
| |
| TestWebKitAPI::Util::run(&didFinishQuickLookLoad); |
| didFinishQuickLookLoad = false; |
| } |
| #endif |
| |
| static const char* minimumWidthPageBytes = R"PSONRESOURCE( |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <style> |
| div { |
| margin: 0; |
| width: 100%; |
| height: 10000px; |
| } |
| </style> |
| </head> |
| <body> |
| <div>Test</a> |
| </body> |
| </html> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, PassMinimumDeviceWidthOnNewWebView) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:minimumWidthPageBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| auto preferences = [[webView configuration] preferences]; |
| [preferences _setShouldIgnoreMetaViewport:YES]; |
| [webView _setMinimumEffectiveDeviceWidth:1024]; |
| |
| auto* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| bool finishedRunningScript = false; |
| [webView evaluateJavaScript:@"window.innerWidth" completionHandler: [&] (id result, NSError *error) { |
| NSNumber *width = (NSNumber *)result; |
| EXPECT_EQ(1024, [width intValue]); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| } |
| |
| #endif |
| |
| TEST(ProcessSwap, SuspendAllMediaPlayback) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone; |
| #if TARGET_OS_IPHONE |
| configuration.get().allowsInlineMediaPlayback = YES; |
| #endif |
| [configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); |
| |
| __block bool loaded = false; |
| [webView performAfterLoading:^{ loaded = true; }]; |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| |
| TestWebKitAPI::Util::run(&loaded); |
| |
| [webView _suspendAllMediaPlayback]; |
| |
| __block bool notPlaying = false; |
| [webView performAfterReceivingMessage:@"not playing" action:^() { notPlaying = true; }]; |
| [webView synchronouslyLoadTestPageNamed:@"video-with-audio"]; |
| TestWebKitAPI::Util::run(¬Playing); |
| } |
| |
| TEST(ProcessSwap, PassSandboxExtension) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone; |
| #if TARGET_OS_IPHONE |
| configuration.get().allowsInlineMediaPlayback = YES; |
| #endif |
| [configuration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]); |
| |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| NSURL *file = [[NSBundle mainBundle] URLForResource:@"autoplay-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadFileURL:file allowingReadAccessToURL:file.URLByDeletingLastPathComponent]; |
| [webView waitForMessage:@"loaded"]; |
| |
| EXPECT_WK_STREQ(webView.get()._resourceDirectoryURL.path, file.URLByDeletingLastPathComponent.path); |
| } |
| |
| #if PLATFORM(MAC) |
| |
| static const char* pageThatOpensBytes = R"PSONRESOURCE( |
| <script> |
| window.onload = function() { |
| window.open("pson://www.webkit.org/window.html", "_blank"); |
| } |
| </script> |
| )PSONRESOURCE"; |
| |
| static const char* openedPage = "Hello World"; |
| |
| TEST(ProcessSwap, SameSiteWindowWithOpenerNavigateToFile) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageThatOpensBytes]; |
| [handler addMappingFromURLString:@"pson://www.webkit.org/window.html" toData:openedPage]; |
| [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; |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(2, numberOfDecidePolicyCalls); |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| EXPECT_EQ(pid1, pid2); |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"blinking-div" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| EXPECT_TRUE([url.scheme isEqualToString:@"file"]); |
| |
| [createdWebView loadRequest:[NSURLRequest requestWithURL:url]]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| auto pid3 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid3); |
| EXPECT_NE(pid2, pid3); |
| |
| [createdWebView goBack]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(4, numberOfDecidePolicyCalls); |
| auto pid4 = [createdWebView _webProcessIdentifier]; |
| EXPECT_NE(pid3, pid4); |
| |
| [createdWebView goForward]; |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| EXPECT_EQ(5, numberOfDecidePolicyCalls); |
| auto pid5 = [createdWebView _webProcessIdentifier]; |
| EXPECT_NE(pid4, pid5); |
| } |
| |
| #endif // PLATFORM(MAC) |
| |
| |
| static const char* responsivePageBytes = R"PSONRESOURCE( |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| )PSONRESOURCE"; |
| |
| TEST(ProcessSwap, ResizeWebViewDuringCrossSiteProvisionalNavigation) |
| { |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:responsivePageBytes]; |
| [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:responsivePageBytes]; |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 800) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| [webView configuration].preferences.fraudulentWebsiteWarningEnabled = NO; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| __block bool finishedRunningScript = false; |
| [webView evaluateJavaScript:@"window.innerWidth" completionHandler:^(id result, NSError *error) { |
| NSNumber *width = (NSNumber *)result; |
| EXPECT_EQ(800, [width intValue]); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| |
| delegate->didStartProvisionalNavigationHandler = ^{ |
| EXPECT_NE(0, [webView _provisionalWebProcessIdentifier]); |
| [webView setFrame:CGRectMake(0, 0, 200, 200)]; |
| }; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| [webView _doAfterNextPresentationUpdate:^{ |
| [webView evaluateJavaScript:@"window.innerWidth" completionHandler:^(id result, NSError *error) { |
| NSNumber *width = (NSNumber *)result; |
| EXPECT_EQ(200, [width intValue]); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| }]; |
| } |
| |
| TEST(WebProcessCache, ClearWhenEnteringCache) |
| { |
| auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]); |
| processPoolConfiguration.get().usesWebProcessCache = YES; |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| auto handler = adoptNS([[PSONScheme alloc] init]); |
| [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"]; |
| |
| @autoreleasepool { |
| auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 800) configuration:webViewConfiguration.get()]); |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 800) configuration:webViewConfiguration.get()]); |
| auto webView3 = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 800) configuration:webViewConfiguration.get()]); |
| |
| auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView1 setNavigationDelegate:delegate.get()]; |
| [webView2 setNavigationDelegate:delegate.get()]; |
| [webView3 setNavigationDelegate:delegate.get()]; |
| |
| NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]; |
| [webView1 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]; |
| [webView2 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]]; |
| [webView3 loadRequest:request]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| } |
| |
| TestWebKitAPI::Util::spinRunLoop(); |
| |
| // Clear the WebProcess cache while the processes are being checked for responsiveness. |
| [processPool _clearWebProcessCache]; |
| } |
| |
| TEST(ProcessSwap, ResponsePolicyDownloadAfterCOOPProcessSwap) |
| { |
| using namespace TestWebKitAPI; |
| |
| HTTPServer server({ |
| { "/source.html"_s, { "foo"_s } }, |
| { "/destination.html"_s, { { { "Content-Type"_s, "text/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, "bar"_s } }, |
| }, HTTPServer::Protocol::Https); |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) { |
| if ([feature.key isEqualToString:@"CrossOriginOpenerPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| else if ([feature.key isEqualToString:@"CrossOriginEmbedderPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| } |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| done = false; |
| [webView loadRequest:server.request("/source.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| // The next navigation will get converted into a download via decidePolicyForNavigationResponse. |
| shouldConvertToDownload = true; |
| |
| done = false; |
| failed = false; |
| [webView loadRequest:server.request("/destination.html"_s)]; |
| Util::run(&failed); |
| failed = false; |
| shouldConvertToDownload = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| // The layer tree should no longer be frozen since the navigation didn't happen. |
| __block bool isFrozen = true; |
| do { |
| Util::sleep(0.1); |
| done = false; |
| [webView _isLayerTreeFrozenForTesting:^(BOOL frozen) { |
| isFrozen = frozen; |
| done = true; |
| }]; |
| Util::run(&done); |
| } while (isFrozen); |
| } |
| |
| TEST(ProcessSwap, NavigateBackAfterNavigatingAwayFromCOOP) |
| { |
| using namespace TestWebKitAPI; |
| |
| HTTPServer server({ |
| { "/source.html"_s, { { { "Content-Type"_s, "text/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, "foo"_s } }, |
| { "/destination.html"_s, { "bar"_s } }, |
| }, HTTPServer::Protocol::Https); |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) { |
| if ([feature.key isEqualToString:@"CrossOriginOpenerPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| else if ([feature.key isEqualToString:@"CrossOriginEmbedderPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| } |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| done = false; |
| [webView loadRequest:server.request("/source.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView loadRequest:server.request("/destination.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView goBack]; |
| Util::run(&done); |
| done = false; |
| } |
| |
| enum class IsSameOrigin : bool { No, Yes }; |
| enum class DoServerSideRedirect : bool { No, Yes }; |
| static void runCOOPProcessSwapTest(ASCIILiteral sourceCOOP, ASCIILiteral sourceCOEP, ASCIILiteral destinationCOOP, ASCIILiteral destinationCOEP, IsSameOrigin isSameOrigin, DoServerSideRedirect doServerSideRedirect, ExpectSwap expectSwap) |
| { |
| using namespace TestWebKitAPI; |
| |
| HashMap<String, String> sourceHeaders; |
| sourceHeaders.add("Content-Type"_s, "text/html"_s); |
| if (sourceCOOP) |
| sourceHeaders.add("Cross-Origin-Opener-Policy"_s, sourceCOOP); |
| if (sourceCOEP) |
| sourceHeaders.add("Cross-Origin-Embedder-Policy"_s, sourceCOEP); |
| |
| HashMap<String, String> destinationHeaders; |
| destinationHeaders.add("Content-Type"_s, "text/html"_s); |
| if (destinationCOOP) |
| destinationHeaders.add("Cross-Origin-Opener-Policy"_s, destinationCOOP); |
| if (destinationCOEP) |
| destinationHeaders.add("Cross-Origin-Embedder-Policy"_s, destinationCOEP); |
| HTTPResponse destinationResponse(WTFMove(destinationHeaders), "popup"_s); |
| |
| HTTPServer server(std::initializer_list<std::pair<String, HTTPResponse>> { }, HTTPServer::Protocol::Https); |
| |
| auto popupURL = isSameOrigin == IsSameOrigin::Yes ? "popup.html"_str : makeString("https://localhost:", server.port(), "/popup.html"); |
| auto popupSource = makeString("<script>onload = () => { w = open('", popupURL, "', 'foo'); };</script>"); |
| server.addResponse("/main.html"_s, HTTPResponse { WTFMove(sourceHeaders), WTFMove(popupSource) }); |
| |
| if (doServerSideRedirect == DoServerSideRedirect::Yes) { |
| HashMap<String, String> redirectHeaders; |
| String redirectionURL = isSameOrigin == IsSameOrigin::Yes ? makeString("https://127.0.0.1:", server.port(), "/popup-after-redirection.html") : makeString("https://localhost:", server.port(), "/popup-after-redirection.html"); |
| redirectHeaders.add("location"_s, WTFMove(redirectionURL)); |
| HTTPResponse redirectResponse(301, WTFMove(redirectHeaders)); |
| |
| server.addResponse("/popup.html"_s, WTFMove(redirectResponse)); |
| server.addResponse("/popup-after-redirection.html"_s, WTFMove(destinationResponse)); |
| } else |
| server.addResponse("/popup.html"_s, WTFMove(destinationResponse)); |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| bool sourceShouldBeCrossOriginIsolated = sourceCOOP == "same-origin"_s && sourceCOEP == "require-corp"_s; |
| bool destinationShouldBeCrossOriginIsolated = destinationCOOP == "same-origin"_s && destinationCOEP == "require-corp"_s; |
| EXPECT_TRUE(sourceShouldBeCrossOriginIsolated == destinationShouldBeCrossOriginIsolated || expectSwap == ExpectSwap::Yes); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| [webViewConfiguration preferences].javaScriptCanOpenWindowsAutomatically = YES; |
| for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) { |
| if ([feature.key isEqualToString:@"CrossOriginOpenerPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| else if ([feature.key isEqualToString:@"CrossOriginEmbedderPolicyEnabled"]) |
| [[webViewConfiguration preferences] _setEnabled:YES forExperimentalFeature:feature]; |
| } |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| |
| __block unsigned numberOfProvisionalLoads = 0; |
| navigationDelegate->didStartProvisionalNavigationHandler = ^{ |
| ++numberOfProvisionalLoads; |
| }; |
| |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]); |
| [webView setUIDelegate:uiDelegate.get()]; |
| |
| failed = false; |
| serverRedirected = false; |
| numberOfDecidePolicyCalls = 0; |
| [webView loadRequest:server.request("/main.html"_s)]; |
| |
| TestWebKitAPI::Util::run(&done); |
| done = false; |
| |
| TestWebKitAPI::Util::run(&didCreateWebView); |
| didCreateWebView = false; |
| |
| TestWebKitAPI::Util::run(&done); |
| |
| if (doServerSideRedirect == DoServerSideRedirect::Yes) { |
| EXPECT_EQ(3, numberOfDecidePolicyCalls); |
| EXPECT_TRUE(serverRedirected); |
| } else { |
| EXPECT_EQ(2, numberOfDecidePolicyCalls); |
| EXPECT_FALSE(serverRedirected); |
| } |
| EXPECT_EQ(2U, numberOfProvisionalLoads); // One in each view. |
| EXPECT_FALSE(failed); // There should be no didFailProvisionalLoad call. |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid1); |
| auto pid2 = [createdWebView _webProcessIdentifier]; |
| EXPECT_TRUE(!!pid2); |
| |
| if (expectSwap == ExpectSwap::Yes) |
| EXPECT_NE(pid1, pid2); |
| else |
| EXPECT_EQ(pid1, pid2); |
| |
| bool finishedRunningScript = false; |
| [webView evaluateJavaScript:@"w.closed ? 'true' : 'false'" completionHandler: [&] (id result, NSError *error) { |
| NSString *isClosed = (NSString *)result; |
| if (expectSwap == ExpectSwap::Yes) |
| EXPECT_WK_STREQ(@"true", isClosed); |
| else |
| EXPECT_WK_STREQ(@"false", isClosed); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [webView evaluateJavaScript:@"w.name" completionHandler: [&] (id result, NSError *error) { |
| NSString *windowName = (NSString *)result; |
| if (expectSwap == ExpectSwap::No && isSameOrigin == IsSameOrigin::Yes) |
| EXPECT_WK_STREQ(@"foo", windowName); |
| else |
| EXPECT_WK_STREQ(@"", windowName); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [webView evaluateJavaScript:@"self.crossOriginIsolated ? 'isolated' : 'not-isolated'" completionHandler: [&] (id result, NSError *error) { |
| NSString *crossOriginIsolated = (NSString *)result; |
| if (sourceShouldBeCrossOriginIsolated) |
| EXPECT_WK_STREQ(@"isolated", crossOriginIsolated); |
| else |
| EXPECT_WK_STREQ(@"not-isolated", crossOriginIsolated); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [webView evaluateJavaScript:@"self.SharedArrayBuffer ? 'has-sab' : 'does-not-have-sab'" completionHandler: [&] (id result, NSError *error) { |
| NSString *hasSAB = (NSString *)result; |
| if (sourceShouldBeCrossOriginIsolated) |
| EXPECT_WK_STREQ(@"has-sab", hasSAB); |
| else |
| EXPECT_WK_STREQ(@"does-not-have-sab", hasSAB); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| |
| // Openee should not have an opener or a name. |
| finishedRunningScript = false; |
| [createdWebView evaluateJavaScript:@"window.opener ? 'true' : 'false'" completionHandler: [&] (id result, NSError *error) { |
| NSString *hasOpener = (NSString *)result; |
| if (expectSwap == ExpectSwap::Yes) |
| EXPECT_WK_STREQ(@"false", hasOpener); |
| else |
| EXPECT_WK_STREQ(@"true", hasOpener); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [createdWebView evaluateJavaScript:@"window.name" completionHandler: [&] (id result, NSError *error) { |
| NSString *windowName = (NSString *)result; |
| if (expectSwap == ExpectSwap::Yes) |
| EXPECT_WK_STREQ(@"", windowName); |
| else |
| EXPECT_WK_STREQ(@"foo", windowName); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| |
| finishedRunningScript = false; |
| [createdWebView evaluateJavaScript:@"document.body.innerText" completionHandler: [&] (id result, NSError *error) { |
| NSString *innerText = (NSString *)result; |
| EXPECT_WK_STREQ(@"popup", innerText); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [createdWebView evaluateJavaScript:@"self.crossOriginIsolated ? 'isolated' : 'not-isolated'" completionHandler: [&] (id result, NSError *error) { |
| NSString *crossOriginIsolated = (NSString *)result; |
| if (destinationShouldBeCrossOriginIsolated) |
| EXPECT_WK_STREQ(@"isolated", crossOriginIsolated); |
| else |
| EXPECT_WK_STREQ(@"not-isolated", crossOriginIsolated); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| finishedRunningScript = false; |
| [createdWebView evaluateJavaScript:@"self.SharedArrayBuffer ? 'has-sab' : 'does-not-have-sab'" completionHandler: [&] (id result, NSError *error) { |
| NSString *hasSAB = (NSString *)result; |
| if (destinationShouldBeCrossOriginIsolated) |
| EXPECT_WK_STREQ(@"has-sab", hasSAB); |
| else |
| EXPECT_WK_STREQ(@"does-not-have-sab", hasSAB); |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| |
| createdWebView = nullptr; |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginToCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest({ }, { }, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginToCOOPSameOrigin2) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, { }, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginToCOOPSameOrigin3) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, { }, "same-origin"_s, "unsafe-none"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginToCOOPSameOrigin4) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, "unsafe-none"_s, "same-origin"_s, "unsafe-none"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginToCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest({ }, { }, "same-origin"_s, "require-corp"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, { }, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOrigin2) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, "unsafe-none"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOrigin3) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "unsafe-none"_s, "unsafe-none"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, { }, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginAllowPopup) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, { }, { }, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginAllowPopup2) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, { }, "unsafe-none"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginAllowPopup3) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, "unsafe-none"_s, "unsafe-none"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginAllowPopup4) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, "unsafe-none"_s, "unsafe-none"_s, "unsafe-none"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPAndCOEPSameOriginAllowPopup) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, "require-corp"_s, { }, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginToCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginToCOOPSameOrigin2) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "unsafe-none"_s, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginToCOOPSameOrigin3) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "unsafe-none"_s, "same-origin"_s, "unsafe-none"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPAndCOEPSameOriginToCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, "same-origin"_s, "require-corp"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPAndCOEPSameOriginToCOOPSameOrigin) |
| { |
| // Should swap because the destination is missing COEP. |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginToCOOPAndCOEPSameOrigin) |
| { |
| // Should swap because the source is missing COEP. |
| runCOOPProcessSwapTest("same-origin"_s, { }, "same-origin"_s, "require-corp"_s, IsSameOrigin::Yes, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPSameOriginToCOOPSameOriginWithRedirect) |
| { |
| // We expect a swap because the redirect doesn't have COOP=same-origin. |
| runCOOPProcessSwapTest("same-origin"_s, { }, "same-origin"_s, { }, IsSameOrigin::Yes, DoServerSideRedirect::Yes, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginFromCOOPAndCOEPSameOriginToCOOPAndCOEPSameOriginWithRedirect) |
| { |
| // We expect a swap because the redirect doesn't have COOP=same-origin and COEP=require-corp. |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, "same-origin"_s, "require-corp"_s, IsSameOrigin::Yes, DoServerSideRedirect::Yes, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingSameOriginWithoutCOOPWithRedirect) |
| { |
| runCOOPProcessSwapTest({ }, { }, { }, { }, IsSameOrigin::Yes, DoServerSideRedirect::Yes, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginToCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest({ }, { }, "same-origin"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginToCOOPSameOrigin2) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, { }, "same-origin"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginToCOOPSameOrigin3) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, { }, "same-origin"_s, "unsafe-none"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginToCOOPSameOrigin4) |
| { |
| runCOOPProcessSwapTest("unsafe-none"_s, "unsafe-none"_s, "same-origin"_s, "unsafe-none"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginToCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest({ }, { }, "same-origin"_s, "require-corp"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, { }, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOrigin2) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, "unsafe-none"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOrigin3) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "unsafe-none"_s, "unsafe-none"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOrigin4) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "unsafe-none"_s, "unsafe-none"_s, "unsafe-none"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, { }, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginToCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, "same-origin"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPAndCOEPSameOriginToCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, "same-origin"_s, "require-corp"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPAndCOEPSameOriginToCOOPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, "require-corp"_s, "same-origin"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginToCOOPAndCOEPSameOrigin) |
| { |
| runCOOPProcessSwapTest("same-origin"_s, { }, "same-origin"_s, "require-corp"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::Yes); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginAllowPopup) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, { }, { }, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginAllowPopup2) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, { }, "unsafe-none"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginAllowPopup3) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, "unsafe-none"_s, "unsafe-none"_s, { }, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| TEST(ProcessSwap, NavigatingCrossOriginFromCOOPSameOriginAllowPopup4) |
| { |
| runCOOPProcessSwapTest("same-origin-allow-popup"_s, "unsafe-none"_s, "unsafe-none"_s, "unsafe-none"_s, IsSameOrigin::No, DoServerSideRedirect::No, ExpectSwap::No); |
| } |
| |
| static bool isJITEnabled(WKWebView *webView) |
| { |
| __block bool gotResponse = false; |
| __block bool isJITEnabledResult = false; |
| [webView _isJITEnabled:^(BOOL isJITEnabled) { |
| isJITEnabledResult = isJITEnabled; |
| gotResponse = true; |
| }]; |
| TestWebKitAPI::Util::run(&gotResponse); |
| EXPECT_NE([webView _webProcessIdentifier], 0); |
| return isJITEnabledResult; |
| } |
| |
| enum class ShouldBeEnabled : bool { No, Yes }; |
| enum class IsShowingInitialEmptyDocument : bool { No, Yes }; |
| static void checkSettingsControlledByCaptivePortalMode(WKWebView *webView, ShouldBeEnabled shouldBeEnabled, IsShowingInitialEmptyDocument isShowingInitialEmptyDocument = IsShowingInitialEmptyDocument::No) |
| { |
| auto runJSCheck = [&](const String& js) -> bool { |
| bool finishedRunningScript = false; |
| bool checkResult = false; |
| [webView evaluateJavaScript:js completionHandler:[&] (id result, NSError *error) { |
| EXPECT_NULL(error); |
| checkResult = [result boolValue]; |
| finishedRunningScript = true; |
| }]; |
| TestWebKitAPI::Util::run(&finishedRunningScript); |
| return checkResult; |
| }; |
| |
| EXPECT_EQ(runJSCheck("!!window.WebGL2RenderingContext"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // WebGL2. |
| EXPECT_EQ(runJSCheck("!!window.Gamepad"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // Gamepad API. |
| EXPECT_EQ(runJSCheck("!!window.RemotePlayback"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // Remote Playback. |
| EXPECT_EQ(runJSCheck("!!window.FileSystemHandle"_s), isShowingInitialEmptyDocument != IsShowingInitialEmptyDocument::Yes && shouldBeEnabled == ShouldBeEnabled::Yes); // File System Access. |
| EXPECT_EQ(runJSCheck("!!window.HTMLModelElement"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // AR (Model) |
| EXPECT_EQ(runJSCheck("!!window.PictureInPictureEvent"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // Picture in Picture API. |
| EXPECT_EQ(runJSCheck("!!window.SpeechRecognitionEvent"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // Speech recognition. |
| #if ENABLE(NOTIFICATIONS) |
| EXPECT_EQ(runJSCheck("!!window.Notification"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // Notification API. |
| #endif |
| EXPECT_EQ(runJSCheck("!!window.WebXRSystem"_s), false); // WebXR (currently always disabled). |
| EXPECT_EQ(runJSCheck("!!window.AudioContext"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // WebAudio. |
| EXPECT_EQ(runJSCheck("!!window.RTCPeerConnection"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // WebRTC Peer Connection. |
| EXPECT_EQ(runJSCheck("!!window.RTCRtpScriptTransform"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // WebRTC Script Transform |
| EXPECT_EQ(runJSCheck("!!navigator.mediaDevices"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // GetUserMedia (Media Capture). |
| EXPECT_EQ(runJSCheck("!!navigator.getUserMedia"_s), false); // Legacy GetUserMedia (currently always disabled). |
| EXPECT_EQ(runJSCheck("!!window.MathMLElement"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // MathML. |
| EXPECT_EQ(runJSCheck("!!window.MathMLMathElement"_s), shouldBeEnabled == ShouldBeEnabled::Yes); // MathML. |
| EXPECT_EQ(runJSCheck("!!window.PushManager"_s), isShowingInitialEmptyDocument != IsShowingInitialEmptyDocument::Yes && shouldBeEnabled == ShouldBeEnabled::Yes); // Push API. |
| EXPECT_EQ(runJSCheck("!!window.PushSubscription"_s), isShowingInitialEmptyDocument != IsShowingInitialEmptyDocument::Yes && shouldBeEnabled == ShouldBeEnabled::Yes); // Push API. |
| EXPECT_EQ(runJSCheck("!!window.PushSubscriptionOptions"_s), isShowingInitialEmptyDocument != IsShowingInitialEmptyDocument::Yes && shouldBeEnabled == ShouldBeEnabled::Yes); // Push API. |
| String mathMLCheck = makeString("document.createElementNS('http://www.w3.org/1998/Math/MathML','mspace').__proto__ == ", shouldBeEnabled == ShouldBeEnabled::Yes ? "MathMLElement" : "Element", ".prototype"); |
| EXPECT_EQ(runJSCheck(mathMLCheck), true); // MathML. |
| } |
| |
| @interface CaptivePortalMessageHandler : NSObject <WKScriptMessageHandler, WKNavigationDelegate> |
| @end |
| |
| @implementation CaptivePortalMessageHandler |
| |
| - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message |
| { |
| receivedScriptMessage = true; |
| scriptMessages.append(message); |
| } |
| |
| @end |
| |
| void configureCaptivePortalWKWebViewConfiguration(WKWebViewConfiguration *config) |
| { |
| [config.preferences _setMediaDevicesEnabled:YES]; |
| config.preferences._mediaCaptureRequiresSecureConnection = NO; |
| [config.preferences _setNotificationsEnabled:YES]; |
| |
| for (_WKExperimentalFeature *feature in [WKPreferences _experimentalFeatures]) { |
| if ([feature.key isEqualToString:@"ModelElementEnabled"] |
| || [feature.key isEqualToString:@"PushAPIEnabled"] |
| || [feature.key isEqualToString:@"WebRTCEncodedTransformEnabled"]) { |
| [config.preferences _setEnabled:YES forFeature:feature]; |
| } |
| } |
| } |
| |
| TEST(ProcessSwap, NavigatingToCaptivePortalMode) |
| { |
| auto messageHandler = adoptNS([[CaptivePortalMessageHandler alloc] init]); |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| configureCaptivePortalWKWebViewConfiguration(webViewConfiguration.get()); |
| [webViewConfiguration.get().userContentController addScriptMessageHandler:messageHandler.get() name:@"testHandler"]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::Yes, IsShowingInitialEmptyDocument::Yes); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::Yes); |
| |
| finishedNavigation = false; |
| receivedScriptMessage = false; |
| url = [[NSBundle mainBundle] URLForResource:@"CaptivePortalPDF" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_FALSE(receivedScriptMessage); |
| EXPECT_TRUE(scriptMessages.isEmpty()); |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_FALSE(preferences._captivePortalModeEnabled); |
| [preferences _setCaptivePortalModeEnabled:YES]; |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| finishedNavigation = false; |
| url = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| // We should have process-swap for transitioning to captive portal mode. |
| EXPECT_NE(pid1, [webView _webProcessIdentifier]); |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No); |
| |
| finishedNavigation = false; |
| receivedScriptMessage = false; |
| url = [[NSBundle mainBundle] URLForResource:@"CaptivePortalPDF" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_TRUE(receivedScriptMessage); |
| EXPECT_WK_STREQ("Error loading PDF", getNextMessage().body); |
| } |
| |
| TEST(ProcessSwap, CaptivePortalModeSystemSettingChange) |
| { |
| auto kvo = adoptNS([CaptivePortalModeKVO new]); |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| [webViewConfiguration.get().defaultWebpagePreferences addObserver:kvo.get() forKeyPath:@"_captivePortalModeEnabled" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| EXPECT_FALSE(didChangeCaptivePortalMode); |
| |
| finishedNavigation = false; |
| // Now change the global setting. |
| [WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES]; |
| |
| TestWebKitAPI::Util::run(&didChangeCaptivePortalMode); |
| EXPECT_FALSE(captivePortalModeBeforeChange); |
| EXPECT_TRUE(captivePortalModeAfterChange); |
| EXPECT_TRUE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| |
| // This should cause the WebView to reload with a WebProcess in captive portal mode. |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| |
| pid_t pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| didChangeCaptivePortalMode = false; |
| finishedNavigation = false; |
| [WKProcessPool _clearCaptivePortalModeEnabledGloballyForTesting]; |
| |
| TestWebKitAPI::Util::run(&didChangeCaptivePortalMode); |
| EXPECT_TRUE(captivePortalModeBeforeChange); |
| EXPECT_FALSE(captivePortalModeAfterChange); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| pid_t pid3 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid2, pid3); |
| } |
| |
| #if PLATFORM(IOS) |
| |
| TEST(ProcessSwap, CannotDisableCaptivePortalModeWithoutBrowserEntitlement) |
| { |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| configureCaptivePortalWKWebViewConfiguration(webViewConfiguration.get()); |
| [webViewConfiguration.get().defaultWebpagePreferences _setCaptivePortalModeEnabled:YES]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No, IsShowingInitialEmptyDocument::Yes); |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_TRUE(preferences._captivePortalModeEnabled); |
| bool didThrowWhenTryingToDisableCaptivePortalMode = false; |
| // TestWebKitAPI doesn't have the web browser entitlement and thus shouldn't be able to disable captive portal mode. |
| @try { |
| [preferences _setCaptivePortalModeEnabled:NO]; |
| } @catch (NSException *exception) { |
| didThrowWhenTryingToDisableCaptivePortalMode = true; |
| } |
| EXPECT_TRUE(didThrowWhenTryingToDisableCaptivePortalMode); |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); // Shouldn't have process-swapped since we're staying in captive portal mode. |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No); |
| } |
| |
| #else |
| |
| TEST(ProcessSwap, CaptivePortalModeEnabledByDefaultThenOptOut) |
| { |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| configureCaptivePortalWKWebViewConfiguration(webViewConfiguration.get()); |
| [webViewConfiguration.get().defaultWebpagePreferences _setCaptivePortalModeEnabled:YES]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No, IsShowingInitialEmptyDocument::Yes); |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_TRUE(preferences._captivePortalModeEnabled); |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No); |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); |
| |
| finishedNavigation = false; |
| url = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| EXPECT_EQ(pid1, [webView _webProcessIdentifier]); // Shouldn't have process-swapped since we're staying in captive portal mode. |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::No); |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_TRUE(preferences._captivePortalModeEnabled); |
| [preferences _setCaptivePortalModeEnabled:NO]; // Opt out of captive portal mode for this load. |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| finishedNavigation = false; |
| url = [[NSBundle mainBundle] URLForResource:@"simple3" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| // We should have process-swapped to get out of captive portal mode. |
| EXPECT_NE(pid1, [webView _webProcessIdentifier]); |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| checkSettingsControlledByCaptivePortalMode(webView.get(), ShouldBeEnabled::Yes); |
| |
| // captive portal mode should be disabled in new WebViews since it is not enabled globally. |
| auto webViewConfiguration2 = adoptNS([WKWebViewConfiguration new]); |
| configureCaptivePortalWKWebViewConfiguration(webViewConfiguration2.get()); |
| EXPECT_TRUE([webViewConfiguration2.get().defaultWebpagePreferences _captivePortalModeEnabled] == NO); |
| auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration2.get()]); |
| [webView2 setNavigationDelegate:delegate.get()]; |
| EXPECT_TRUE(isJITEnabled(webView2.get())); |
| checkSettingsControlledByCaptivePortalMode(webView2.get(), ShouldBeEnabled::Yes, IsShowingInitialEmptyDocument::Yes); |
| pid_t pid2 = [webView2 _webProcessIdentifier]; |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = nil; |
| |
| finishedNavigation = false; |
| url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView2 loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| EXPECT_TRUE(isJITEnabled(webView2.get())); |
| checkSettingsControlledByCaptivePortalMode(webView2.get(), ShouldBeEnabled::Yes); |
| EXPECT_EQ(pid2, [webView2 _webProcessIdentifier]); |
| } |
| |
| TEST(ProcessSwap, CaptivePortalModeSystemSettingChangeDoesNotReloadViewsWhenModeIsSetExplicitly1) |
| { |
| // Captive portal mode is disabled globally and explicitly opted out via defaultWebpagePreferences. |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| [webViewConfiguration.get().defaultWebpagePreferences _setCaptivePortalModeEnabled:NO]; // Explicitly opt out via default WKWebpagePreferences. |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| finishedNavigation = false; |
| // Now change the global setting. |
| [WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES]; |
| |
| // This should not reload the web view since the view has explicitly opted out of captive portal mode. |
| TestWebKitAPI::Util::sleep(0.5); |
| EXPECT_FALSE(finishedNavigation); |
| |
| pid_t pid2 = [webView _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| [WKProcessPool _clearCaptivePortalModeEnabledGloballyForTesting]; |
| } |
| |
| TEST(ProcessSwap, CaptivePortalModeSystemSettingChangeDoesNotReloadViewsWhenModeIsSetExplicitly2) |
| { |
| // Captive portal mode is enabled globally but explicitly opted out via defaultWebpagePreferences. |
| [WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES]; |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_TRUE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| [webViewConfiguration.get().defaultWebpagePreferences _setCaptivePortalModeEnabled:NO]; // Explicitly opt out via default WKWebpagePreferences. |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| finishedNavigation = false; |
| // Now change the global setting. |
| [WKProcessPool _clearCaptivePortalModeEnabledGloballyForTesting]; |
| |
| // This should not reload the web view since the view has explicitly opted out of captive portal mode. |
| TestWebKitAPI::Util::sleep(0.5); |
| EXPECT_FALSE(finishedNavigation); |
| |
| pid_t pid2 = [webView _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| } |
| |
| TEST(ProcessSwap, CaptivePortalModeSystemSettingChangeDoesNotReloadViewsWhenModeIsSetExplicitly3) |
| { |
| // Captive portal mode is disabled globally and explicitly opted out for the load. |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_FALSE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_FALSE(preferences._captivePortalModeEnabled); |
| [preferences _setCaptivePortalModeEnabled:NO]; // Explicitly Opt out of captive portal mode for this load. |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| finishedNavigation = false; |
| // Now change the global setting. |
| [WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES]; |
| |
| // This should not reload the web view since the view has explicitly opted out of captive portal mode. |
| TestWebKitAPI::Util::sleep(0.5); |
| EXPECT_FALSE(finishedNavigation); |
| |
| pid_t pid2 = [webView _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| [WKProcessPool _clearCaptivePortalModeEnabledGloballyForTesting]; |
| } |
| |
| TEST(ProcessSwap, CaptivePortalModeSystemSettingChangeDoesNotReloadViewsWhenModeIsSetExplicitly4) |
| { |
| // Captive portal mode is enabled globally but explicitly opted out for the load. |
| [WKProcessPool _setCaptivePortalModeEnabledGloballyForTesting:YES]; |
| |
| auto webViewConfiguration = adoptNS([WKWebViewConfiguration new]); |
| EXPECT_TRUE(webViewConfiguration.get().defaultWebpagePreferences._captivePortalModeEnabled); |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]); |
| auto delegate = adoptNS([TestNavigationDelegate new]); |
| [webView setNavigationDelegate:delegate.get()]; |
| |
| EXPECT_FALSE(isJITEnabled(webView.get())); |
| |
| __block bool finishedNavigation = false; |
| delegate.get().didFinishNavigation = ^(WKWebView *, WKNavigation *) { |
| finishedNavigation = true; |
| }; |
| |
| delegate.get().decidePolicyForNavigationActionWithPreferences = ^(WKNavigationAction *action, WKWebpagePreferences *preferences, void (^completionHandler)(WKNavigationActionPolicy, WKWebpagePreferences *)) { |
| EXPECT_TRUE(preferences._captivePortalModeEnabled); |
| [preferences _setCaptivePortalModeEnabled:NO]; // Explicitly Opt out of captive portal mode for this load. |
| completionHandler(WKNavigationActionPolicyAllow, preferences); |
| }; |
| |
| NSURL *url = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; |
| [webView loadRequest:[NSURLRequest requestWithURL:url]]; |
| TestWebKitAPI::Util::run(&finishedNavigation); |
| |
| pid_t pid1 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, 0); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| finishedNavigation = false; |
| // Now change the global setting. |
| [WKProcessPool _clearCaptivePortalModeEnabledGloballyForTesting]; |
| |
| // This should not reload the web view since the view has explicitly opted out of captive portal mode. |
| TestWebKitAPI::Util::sleep(0.5); |
| EXPECT_FALSE(finishedNavigation); |
| |
| pid_t pid2 = [webView _webProcessIdentifier]; |
| EXPECT_EQ(pid1, pid2); |
| |
| EXPECT_TRUE(isJITEnabled(webView.get())); |
| |
| } |
| |
| #endif |
| |
| #if PLATFORM(IOS_FAMILY) |
| TEST(ProcessSwap, ContentModeInCaseOfCoopProcessSwap) |
| { |
| using namespace TestWebKitAPI; |
| |
| HTTPServer server({ |
| { "/source.html"_s, { "foo"_s } }, |
| { "/destination.html"_s, { { { "Content-Type"_s, "text/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, "bar"_s } }, |
| }, HTTPServer::Protocol::Https); |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| |
| auto webpagePreferences = adoptNS([[WKWebpagePreferences alloc] init]); |
| [webpagePreferences setPreferredContentMode:WKContentModeDesktop]; |
| [webViewConfiguration setDefaultWebpagePreferences:webpagePreferences.get()]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| done = false; |
| [webView loadRequest:server.request("/source.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| [webView loadRequest:server.request("/destination.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| [webView goBack]; // Back to source.html. |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| } |
| |
| TEST(ProcessSwap, ContentModeInCaseOfPSONThenCoopProcessSwap) |
| { |
| using namespace TestWebKitAPI; |
| |
| HTTPServer server1({ |
| { "/source.html"_s, { "foo"_s } }, |
| }, HTTPServer::Protocol::Https); |
| |
| HTTPServer server2({ |
| { "/destination.html"_s, { { { "Content-Type"_s, "text/html"_s }, { "Cross-Origin-Opener-Policy"_s, "same-origin"_s } }, "bar"_s } }, |
| }, HTTPServer::Protocol::Http); |
| |
| auto processPoolConfiguration = psonProcessPoolConfiguration(); |
| auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]); |
| |
| auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]); |
| [webViewConfiguration setProcessPool:processPool.get()]; |
| |
| auto webpagePreferences = adoptNS([[WKWebpagePreferences alloc] init]); |
| [webpagePreferences setPreferredContentMode:WKContentModeDesktop]; |
| [webViewConfiguration setDefaultWebpagePreferences:webpagePreferences.get()]; |
| |
| auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768) configuration:webViewConfiguration.get()]); |
| auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]); |
| [webView setNavigationDelegate:navigationDelegate.get()]; |
| |
| done = false; |
| [webView loadRequest:server1.request("/source.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| |
| auto pid1 = [webView _webProcessIdentifier]; |
| |
| [webView loadRequest:server2.request("/destination.html"_s)]; |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| |
| auto pid2 = [webView _webProcessIdentifier]; |
| EXPECT_NE(pid1, pid2); |
| |
| [webView goBack]; // Back to source.html. |
| Util::run(&done); |
| done = false; |
| |
| [webView evaluateJavaScript:@"navigator.userAgent;" completionHandler:^(id _Nullable response, NSError * _Nullable error) { |
| done = true; |
| |
| ASSERT_TRUE(!error); |
| NSString *userAgent = (NSString *)response; |
| ASSERT_TRUE([userAgent containsString:@"Macintosh; Intel Mac"]); |
| }]; |
| Util::run(&done); |
| done = false; |
| } |
| #endif // PLATFORM(IOS_FAMILY) |