REGRESSION(PSON, r240660): Navigation over process boundary is flashy when using...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / ProcessSwapOnNavigation.mm
1 /*
2  * Copyright (C) 2017-2019 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "Test.h"
30 #import "TestNavigationDelegate.h"
31 #import "TestWKWebView.h"
32 #import <WebKit/WKBackForwardListItemPrivate.h>
33 #import <WebKit/WKContentRuleListStore.h>
34 #import <WebKit/WKNavigationDelegatePrivate.h>
35 #import <WebKit/WKNavigationPrivate.h>
36 #import <WebKit/WKPreferencesPrivate.h>
37 #import <WebKit/WKProcessPoolPrivate.h>
38 #import <WebKit/WKUIDelegatePrivate.h>
39 #import <WebKit/WKURLSchemeHandler.h>
40 #import <WebKit/WKURLSchemeTaskPrivate.h>
41 #import <WebKit/WKWebViewConfigurationPrivate.h>
42 #import <WebKit/WKWebViewPrivate.h>
43 #import <WebKit/WKWebsiteDataStorePrivate.h>
44 #import <WebKit/WKWebsiteDataStoreRef.h>
45 #import <WebKit/WebKit.h>
46 #import <WebKit/_WKExperimentalFeature.h>
47 #import <WebKit/_WKInspector.h>
48 #import <WebKit/_WKProcessPoolConfiguration.h>
49 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
50 #import <WebKit/_WKWebsitePolicies.h>
51 #import <wtf/Deque.h>
52 #import <wtf/HashMap.h>
53 #import <wtf/HashSet.h>
54 #import <wtf/RetainPtr.h>
55 #import <wtf/Vector.h>
56 #import <wtf/text/StringConcatenateNumbers.h>
57 #import <wtf/text/StringHash.h>
58 #import <wtf/text/WTFString.h>
59
60 @interface WKProcessPool ()
61 - (WKContextRef)_contextForTesting;
62 @end
63
64 static bool done;
65 static bool didStartProvisionalLoad;
66 static bool failed;
67 static bool didCreateWebView;
68 static int numberOfDecidePolicyCalls;
69 static bool didRepondToPolicyDecisionCall;
70
71 #if PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
72 static bool requestedQuickLookPassword;
73 static bool didStartQuickLookLoad;
74 static bool didFinishQuickLookLoad;
75 #endif
76
77 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
78 bool didReceiveAlert;
79 static bool receivedMessage;
80 static bool serverRedirected;
81 static HashSet<pid_t> seenPIDs;
82 static bool willPerformClientRedirect;
83 static bool didPerformClientRedirect;
84 static bool shouldConvertToDownload;
85 static RetainPtr<NSURL> clientRedirectSourceURL;
86 static RetainPtr<NSURL> clientRedirectDestinationURL;
87
88 @interface PSONMessageHandler : NSObject <WKScriptMessageHandler>
89 @end
90
91 @implementation PSONMessageHandler
92 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
93 {
94     if ([message body])
95         [receivedMessages addObject:[message body]];
96     else
97         [receivedMessages addObject:@""];
98
99     receivedMessage = true;
100     if ([message.webView _webProcessIdentifier])
101         seenPIDs.add([message.webView _webProcessIdentifier]);
102 }
103 @end
104
105 @interface PSONNavigationDelegate : NSObject <WKNavigationDelegatePrivate> {
106     @public void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy));
107     @public void (^didStartProvisionalNavigationHandler)();
108     @public void (^didCommitNavigationHandler)();
109 }
110 @end
111
112 @implementation PSONNavigationDelegate
113
114 - (instancetype) init
115 {
116     self = [super init];
117     return self;
118 }
119
120 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
121 {
122     seenPIDs.add([webView _webProcessIdentifier]);
123     failed = true;
124 }
125
126 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
127 {
128     seenPIDs.add([webView _webProcessIdentifier]);
129     done = true;
130 }
131
132 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation
133 {
134     didStartProvisionalLoad = true;
135     if (didStartProvisionalNavigationHandler)
136         didStartProvisionalNavigationHandler();
137 }
138
139 - (void)webView:(WKWebView *)webView didCommitNavigation:(null_unspecified WKNavigation *)navigation
140 {
141     if (didCommitNavigationHandler)
142         didCommitNavigationHandler();
143 }
144
145 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
146 {
147     ++numberOfDecidePolicyCalls;
148     seenPIDs.add([webView _webProcessIdentifier]);
149     if (decidePolicyForNavigationAction)
150         decidePolicyForNavigationAction(navigationAction, decisionHandler);
151     else
152         decisionHandler(WKNavigationActionPolicyAllow);
153     didRepondToPolicyDecisionCall = true;
154 }
155
156 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
157 {
158     decisionHandler(shouldConvertToDownload ? _WKNavigationResponsePolicyBecomeDownload : WKNavigationResponsePolicyAllow);
159 }
160
161 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
162 {
163     seenPIDs.add([webView _webProcessIdentifier]);
164     serverRedirected = true;
165 }
166
167 - (void)_webView:(WKWebView *)webView willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)delay
168 {
169     clientRedirectDestinationURL = URL;
170     willPerformClientRedirect = true;
171 }
172
173 - (void)_webView:(WKWebView *)webView didPerformClientRedirectFromURL:(NSURL *)sourceURL toURL:(NSURL *)destinationURL
174 {
175     EXPECT_TRUE(willPerformClientRedirect);
176     EXPECT_WK_STREQ([clientRedirectDestinationURL absoluteString], [destinationURL absoluteString]);
177     clientRedirectSourceURL = sourceURL;
178     didPerformClientRedirect = true;
179 }
180
181 #if PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 110000
182
183 - (void)_webViewDidRequestPasswordForQuickLookDocument:(WKWebView *)webView
184 {
185     requestedQuickLookPassword = true;
186 }
187
188 - (void)_webView:(WKWebView *)webView didStartLoadForQuickLookDocumentInMainFrameWithFileName:(NSString *)fileName uti:(NSString *)uti
189 {
190     didStartQuickLookLoad = true;
191 }
192
193 - (void)_webView:(WKWebView *)webView didFinishLoadForQuickLookDocumentInMainFrame:(NSData *)documentData
194 {
195     didFinishQuickLookLoad = true;
196 }
197
198 #endif
199
200 @end
201
202 static RetainPtr<WKWebView> createdWebView;
203
204 @interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
205 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
206 @end
207
208 @implementation PSONUIDelegate {
209     RetainPtr<PSONNavigationDelegate> _navigationDelegate;
210 }
211
212 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
213 {
214     if (!(self = [super init]))
215         return nil;
216
217     _navigationDelegate = navigationDelegate;
218     return self;
219 }
220
221 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
222 {
223     createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
224     [createdWebView setNavigationDelegate:_navigationDelegate.get()];
225     didCreateWebView = true;
226     return createdWebView.get();
227 }
228
229 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
230 {
231     didReceiveAlert = true;
232     completionHandler();
233 }
234
235 @end
236
237 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
238     const char* _bytes;
239     HashMap<String, String> _redirects;
240     HashMap<String, RetainPtr<NSData>> _dataMappings;
241 }
242 - (instancetype)initWithBytes:(const char*)bytes;
243 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
244 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data;
245 @end
246
247 @implementation PSONScheme
248
249 - (instancetype)initWithBytes:(const char*)bytes
250 {
251     self = [super init];
252     _bytes = bytes;
253     return self;
254 }
255
256 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
257 {
258     _redirects.set(sourceURLString, destinationURLString);
259 }
260
261 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data
262 {
263     _dataMappings.set(urlString, [NSData dataWithBytesNoCopy:(void*)data length:strlen(data) freeWhenDone:NO]);
264 }
265
266 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
267 {
268     NSURL *finalURL = task.request.URL;
269     auto target = _redirects.get(task.request.URL.absoluteString);
270     if (!target.isEmpty()) {
271         auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
272
273         finalURL = [NSURL URLWithString:(NSString *)target];
274         auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
275
276         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
277     }
278
279     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
280     [task didReceiveResponse:response.get()];
281
282     if (auto data = _dataMappings.get([finalURL absoluteString]))
283         [task didReceiveData:data.get()];
284     else if (_bytes) {
285         RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]);
286         [task didReceiveData:data.get()];
287     } else
288         [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
289
290     [task didFinish];
291 }
292
293 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
294 {
295 }
296
297 @end
298
299 static const char* testBytes = R"PSONRESOURCE(
300 <head>
301 <script>
302
303 function log(msg)
304 {
305     window.webkit.messageHandlers.pson.postMessage(msg);
306 }
307
308 window.onload = function(evt) {
309     if (window.history.state != "onloadCalled")
310         setTimeout('window.history.replaceState("onloadCalled", "");', 0);
311 }
312
313 window.onpageshow = function(evt) {
314     log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state);
315 }
316
317 </script>
318 </head>
319 )PSONRESOURCE";
320
321 static const char* linkToCrossSiteClientSideRedirectBytes = R"PSONRESOURCE(
322 <body>
323   <a id="testLink" href="pson://www.google.com/clientSideRedirect.html">Link to cross-site client-side redirect</a>
324 </body>
325 )PSONRESOURCE";
326
327 static const char* crossSiteClientSideRedirectBytes = R"PSONRESOURCE(
328 <body>
329 <script>
330 onload = () => {
331   location = "pson://www.apple.com/main.html";
332 };
333 </script>
334 </body>
335 )PSONRESOURCE";
336
337 static const char* navigationWithLockedHistoryBytes = R"PSONRESOURCE(
338 <script>
339 let shouldNavigate = true;
340 window.addEventListener('pageshow', function(event) {
341     if (event.persisted) {
342         window.webkit.messageHandlers.pson.postMessage("Was persisted");
343         shouldNavigate = false;
344     }
345 });
346
347 onload = function()
348 {
349     if (!shouldNavigate)
350         return;
351
352     // JS navigation via window.location
353     setTimeout(() => {
354         location = "pson://www.apple.com/main.html";
355     }, 10);
356 }
357 </script>
358 )PSONRESOURCE";
359
360 static const char* pageCache1Bytes = R"PSONRESOURCE(
361 <script>
362 window.addEventListener('pageshow', function(event) {
363     if (event.persisted)
364         window.webkit.messageHandlers.pson.postMessage("Was persisted");
365 });
366 </script>
367 )PSONRESOURCE";
368
369 #if PLATFORM(MAC)
370
371 static const char* windowOpenCrossSiteNoOpenerTestBytes = R"PSONRESOURCE(
372 <script>
373 window.onload = function() {
374     window.open("pson://www.apple.com/main.html", "_blank", "noopener");
375 }
376 </script>
377 )PSONRESOURCE";
378
379 static const char* windowOpenCrossOriginButSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
380 <script>
381 window.onload = function() {
382     window.open("pson://www.webkit.org:8080/main.html", "_blank", "noopener");
383 }
384 </script>
385 )PSONRESOURCE";
386
387 static const char* windowOpenCrossSiteWithOpenerTestBytes = R"PSONRESOURCE(
388 <script>
389 window.onload = function() {
390     window.open("pson://www.apple.com/main.html");
391 }
392 </script>
393 )PSONRESOURCE";
394
395 static const char* windowOpenSameSiteWithOpenerTestBytes = R"PSONRESOURCE(
396 <script>
397 window.onload = function() {
398     w = window.open("pson://www.webkit.org/main2.html");
399 }
400 </script>
401 )PSONRESOURCE";
402
403 static const char* windowOpenSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
404 <script>
405 window.onload = function() {
406     if (!opener)
407         window.open("pson://www.webkit.org/main.html", "_blank", "noopener");
408 }
409 </script>
410 )PSONRESOURCE";
411
412 static const char* targetBlankCrossSiteWithExplicitOpenerTestBytes = R"PSONRESOURCE(
413 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="opener">Link</a>
414 <script>
415 window.onload = function() {
416     testLink.click();
417 }
418 </script>
419 )PSONRESOURCE";
420
421 static const char* targetBlankCrossSiteWithImplicitNoOpenerTestBytes = R"PSONRESOURCE(
422 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html">Link</a>
423 <script>
424 window.onload = function() {
425     testLink.click();
426 }
427 </script>
428 )PSONRESOURCE";
429
430 static const char* targetBlankCrossSiteNoOpenerTestBytes = R"PSONRESOURCE(
431 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="noopener">Link</a>
432 <script>
433 window.onload = function() {
434     testLink.click();
435 }
436 </script>
437 )PSONRESOURCE";
438
439 static const char* targetBlankSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
440 <a id="testLink" target="_blank" href="pson://www.webkit.org/main2.html" rel="noopener">Link</a>
441 <script>
442 window.onload = function() {
443     testLink.click();
444 }
445 </script>
446 )PSONRESOURCE";
447
448 static const char* linkToAppleTestBytes = R"PSONRESOURCE(
449 <script>
450 window.addEventListener('pageshow', function(event) {
451     if (event.persisted)
452         window.webkit.messageHandlers.pson.postMessage("Was persisted");
453 });
454 </script>
455 <a id="testLink" href="pson://www.apple.com/main.html">Navigate</a>
456 )PSONRESOURCE";
457
458 #endif // PLATFORM(MAC)
459
460 static RetainPtr<_WKProcessPoolConfiguration> psonProcessPoolConfiguration()
461 {
462     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
463     processPoolConfiguration.get().processSwapsOnNavigation = YES;
464     processPoolConfiguration.get().usesWebProcessCache = YES;
465     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
466     return processPoolConfiguration;
467 }
468
469 TEST(ProcessSwap, Basic)
470 {
471     auto processPoolConfiguration = psonProcessPoolConfiguration();
472     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
473
474     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
475     [webViewConfiguration setProcessPool:processPool.get()];
476     auto handler = adoptNS([[PSONScheme alloc] init]);
477     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
478
479     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
480     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
481     [webView setNavigationDelegate:delegate.get()];
482
483     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
484     [webView loadRequest:request];
485
486     TestWebKitAPI::Util::run(&done);
487     done = false;
488
489     auto pid1 = [webView _webProcessIdentifier];
490
491     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
492     [webView loadRequest:request];
493
494     TestWebKitAPI::Util::run(&done);
495     done = false;
496
497     auto pid2 = [webView _webProcessIdentifier];
498
499     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
500     [webView loadRequest:request];
501
502     TestWebKitAPI::Util::run(&done);
503     done = false;
504
505     auto pid3 = [webView _webProcessIdentifier];
506
507     EXPECT_EQ(pid1, pid2);
508     EXPECT_FALSE(pid2 == pid3);
509
510     // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
511     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
512 }
513
514 TEST(ProcessSwap, LoadAfterPolicyDecision)
515 {
516     auto processPoolConfiguration = psonProcessPoolConfiguration();
517     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
518
519     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
520     [webViewConfiguration setProcessPool:processPool.get()];
521     auto handler = adoptNS([[PSONScheme alloc] init]);
522     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
523
524     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
525     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
526     [webView setNavigationDelegate:navigationDelegate.get()];
527
528     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
529     [webView loadRequest:request];
530
531     TestWebKitAPI::Util::run(&done);
532     done = false;
533
534     navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) {
535         decisionHandler(WKNavigationActionPolicyAllow);
536
537         // Synchronously navigate again right after answering the policy delegate for the previous navigation.
538         navigationDelegate->decidePolicyForNavigationAction = nil;
539         NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
540         [webView loadRequest:request];
541     };
542
543     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
544     [webView loadRequest:request];
545
546     while (![[[webView URL] absoluteString] isEqualToString:@"pson://www.webkit.org/main2.html"])
547         TestWebKitAPI::Util::spinRunLoop();
548 }
549
550 TEST(ProcessSwap, KillWebContentProcessAfterServerRedirectPolicyDecision)
551 {
552     auto processPoolConfiguration = psonProcessPoolConfiguration();
553     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
554
555     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
556     [webViewConfiguration setProcessPool:processPool.get()];
557     auto handler = adoptNS([[PSONScheme alloc] init]);
558     [handler addRedirectFromURLString:@"pson://www.webkit.org/main2.html" toURLString:@"pson://www.apple.com/main.html"];
559     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
560
561     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
562     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
563     [webView setNavigationDelegate:navigationDelegate.get()];
564
565     [webView configuration].preferences._safeBrowsingEnabled = NO;
566
567     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
568     [webView loadRequest:request];
569
570     TestWebKitAPI::Util::run(&done);
571     done = false;
572
573     __block BOOL isRedirection = NO;
574     navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction * action, void (^decisionHandler)(WKNavigationActionPolicy)) {
575         decisionHandler(WKNavigationActionPolicyAllow);
576         if (!isRedirection) {
577             isRedirection = YES;
578             return;
579         }
580
581         navigationDelegate->decidePolicyForNavigationAction = nil;
582         [webView _killWebContentProcessAndResetState];
583         done = true;
584     };
585
586     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
587     [webView loadRequest:request];
588
589     TestWebKitAPI::Util::run(&done);
590     done = false;
591
592     TestWebKitAPI::Util::spinRunLoop(10);
593     [webView reload];
594
595     TestWebKitAPI::Util::run(&done);
596     done = false;
597 }
598
599 TEST(ProcessSwap, NoSwappingForeTLDPlus2)
600 {
601     auto processPoolConfiguration = psonProcessPoolConfiguration();
602     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
603
604     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
605     [webViewConfiguration setProcessPool:processPool.get()];
606     auto handler = adoptNS([[PSONScheme alloc] init]);
607     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
608
609     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
610     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
611     [webView setNavigationDelegate:delegate.get()];
612
613     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www1.webkit.org/main1.html"]];
614     [webView loadRequest:request];
615
616     TestWebKitAPI::Util::run(&done);
617     done = false;
618
619     auto pid1 = [webView _webProcessIdentifier];
620
621     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www2.webkit.org/main2.html"]];
622     [webView loadRequest:request];
623
624     TestWebKitAPI::Util::run(&done);
625     done = false;
626
627     auto pid2 = [webView _webProcessIdentifier];
628
629     EXPECT_EQ(pid1, pid2);
630
631     EXPECT_EQ(numberOfDecidePolicyCalls, 2);
632 }
633
634 TEST(ProcessSwap, Back)
635 {
636     auto processPoolConfiguration = psonProcessPoolConfiguration();
637     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
638
639     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
640     [webViewConfiguration setProcessPool:processPool.get()];
641     auto handler = adoptNS([[PSONScheme alloc] init]);
642     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
643     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:testBytes];
644     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes];
645     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
646
647     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
648     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
649
650     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
651     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
652     [webView setNavigationDelegate:delegate.get()];
653
654     EXPECT_GT([processPool _maximumSuspendedPageCount], 0U);
655
656     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
657     [webView loadRequest:request];
658
659     TestWebKitAPI::Util::run(&receivedMessage);
660     receivedMessage = false;
661     TestWebKitAPI::Util::run(&done);
662     done = false;
663
664     auto webkitPID = [webView _webProcessIdentifier];
665
666     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
667     [webView loadRequest:request];
668
669     TestWebKitAPI::Util::run(&done);
670     done = false;
671
672     auto applePID = [webView _webProcessIdentifier];
673     EXPECT_NE(webkitPID, applePID);
674
675     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
676     [webView loadRequest:request];
677
678     TestWebKitAPI::Util::run(&done);
679     done = false;
680
681     auto googlePID = [webView _webProcessIdentifier];
682     EXPECT_NE(applePID, googlePID);
683
684     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
685     [webView loadRequest:request];
686
687     TestWebKitAPI::Util::run(&done);
688     done = false;
689
690     auto bingPID = [webView _webProcessIdentifier];
691     EXPECT_NE(googlePID, bingPID);
692
693     [webView goBack]; // Back to google.com.
694
695     TestWebKitAPI::Util::run(&receivedMessage);
696     receivedMessage = false;
697     TestWebKitAPI::Util::run(&done);
698     done = false;
699
700     auto pidAfterFirstBackNavigation = [webView _webProcessIdentifier];
701     EXPECT_EQ(googlePID, pidAfterFirstBackNavigation);
702
703     [webView goBack]; // Back to apple.com.
704
705     TestWebKitAPI::Util::run(&receivedMessage);
706     receivedMessage = false;
707     TestWebKitAPI::Util::run(&done);
708     done = false;
709
710     auto pidAfterSecondBackNavigation = [webView _webProcessIdentifier];
711     if ([processPool _maximumSuspendedPageCount] > 1)
712         EXPECT_EQ(applePID, pidAfterSecondBackNavigation);
713     else {
714         EXPECT_NE(applePID, pidAfterSecondBackNavigation);
715         EXPECT_NE(googlePID, pidAfterSecondBackNavigation);
716     }
717
718
719     // 6 loads, 6 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
720     // additional decidePolicy call as a result of the process swap)
721     EXPECT_EQ(6, numberOfDecidePolicyCalls);
722
723     EXPECT_EQ(5u, [receivedMessages count]);
724     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[0]);
725     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[1]);
726     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[2]);
727     EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[3]);
728
729     // The number of suspended pages we keep around is determined at runtime.
730     if ([processPool _maximumSuspendedPageCount] > 1) {
731         EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[4]);
732         EXPECT_EQ(4u, seenPIDs.size());
733     } else
734         EXPECT_EQ(5u, seenPIDs.size());
735 }
736
737 static const char* pageWithFragmentTestBytes = R"PSONRESOURCE(
738 <div id="foo">TEST</div>
739 )PSONRESOURCE";
740
741 TEST(ProcessSwap, HistoryNavigationToFragmentURL)
742 {
743     auto processPoolConfiguration = psonProcessPoolConfiguration();
744     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
745
746     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
747     [webViewConfiguration setProcessPool:processPool.get()];
748     auto handler = adoptNS([[PSONScheme alloc] init]);
749     [handler addMappingFromURLString:@"pson://www.apple.com/main.html#foo" toData:pageWithFragmentTestBytes];
750     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
751
752     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
753     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
754     [webView setNavigationDelegate:delegate.get()];
755
756     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
757     [webView loadRequest:request];
758
759     TestWebKitAPI::Util::run(&done);
760     done = false;
761
762     auto webkitPID = [webView _webProcessIdentifier];
763
764     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html#foo"]];
765     [webView loadRequest:request];
766
767     TestWebKitAPI::Util::run(&done);
768     done = false;
769
770     auto applePID = [webView _webProcessIdentifier];
771
772     [webView goBack];
773     TestWebKitAPI::Util::run(&done);
774     done = false;
775
776     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
777
778     [webView goForward];
779     TestWebKitAPI::Util::run(&done);
780     done = false;
781
782     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
783
784     bool finishedRunningScript = false;
785     [webView evaluateJavaScript:@"document.getElementById('foo').innerText" completionHandler: [&] (id result, NSError *error) {
786         NSString *innerText = (NSString *)result;
787         EXPECT_WK_STREQ(@"TEST", innerText);
788         finishedRunningScript = true;
789     }];
790     TestWebKitAPI::Util::run(&finishedRunningScript);
791 }
792
793 TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
794 {
795     auto processPoolConfiguration = psonProcessPoolConfiguration();
796     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
797
798     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
799     [webViewConfiguration setProcessPool:processPool.get()];
800     auto handler = adoptNS([[PSONScheme alloc] init]);
801     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
802
803     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
804     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
805     [webView setNavigationDelegate:delegate.get()];
806
807     EXPECT_GT([processPool _maximumSuspendedPageCount], 0U);
808
809     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
810     [webView loadRequest:request];
811
812     TestWebKitAPI::Util::run(&done);
813     done = false;
814
815     auto webkitPID = [webView _webProcessIdentifier];
816
817     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
818     [webView loadRequest:request];
819
820     TestWebKitAPI::Util::run(&done);
821     done = false;
822
823     auto applePID = [webView _webProcessIdentifier];
824     EXPECT_NE(webkitPID, applePID);
825
826     // webkit.org + apple.com processes.
827     EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
828
829     [webView goBack]; // Back to webkit.org.
830     TestWebKitAPI::Util::run(&done);
831     done = false;
832
833     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
834
835     // webkit.org + apple.com processes.
836     EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
837
838     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
839     [webView loadRequest:request];
840
841     TestWebKitAPI::Util::run(&done);
842     done = false;
843
844     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
845
846     // apple.com is not longer present in the back/forward list and there should therefore be no-suspended page for it.
847     while ([processPool _webProcessCountIgnoringPrewarmedAndCached] > 1u)
848         TestWebKitAPI::Util::spinRunLoop();
849 }
850
851 #if PLATFORM(MAC)
852 TEST(ProcessSwap, SuspendedPagesInActivityMonitor)
853 {
854     auto processPoolConfiguration = psonProcessPoolConfiguration();
855     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
856
857     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
858     [webViewConfiguration setProcessPool:processPool.get()];
859     auto handler = adoptNS([[PSONScheme alloc] init]);
860     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
861     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes];
862     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
863
864     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
865     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
866
867     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
868     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
869     [webView setNavigationDelegate:delegate.get()];
870
871     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
872     [webView loadRequest:request];
873
874     TestWebKitAPI::Util::run(&done);
875     done = false;
876
877     auto webkitPID = [webView _webProcessIdentifier];
878     [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) {
879         EXPECT_EQ(1u, activeDomains.count);
880         EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
881         done = true;
882     }];
883     TestWebKitAPI::Util::run(&done);
884     done = false;
885
886     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
887     [webView loadRequest:request];
888
889     TestWebKitAPI::Util::run(&done);
890     done = false;
891
892     auto googlePID = [webView _webProcessIdentifier];
893     EXPECT_NE(webkitPID, googlePID);
894
895     [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID completionHandler:^(NSArray<NSString *> *activeDomains) {
896         EXPECT_EQ(1u, activeDomains.count);
897         EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]);
898         done = true;
899     }];
900     TestWebKitAPI::Util::run(&done);
901     done = false;
902
903     [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) {
904         EXPECT_EQ(1u, activeDomains.count);
905         EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
906         done = true;
907     }];
908     TestWebKitAPI::Util::run(&done);
909     done = false;
910
911     [webView goBack]; // Back to webkit.org.
912
913     TestWebKitAPI::Util::run(&receivedMessage);
914     receivedMessage = false;
915     TestWebKitAPI::Util::run(&done);
916     done = false;
917
918     auto pidAfterBackNavigation = [webView _webProcessIdentifier];
919     EXPECT_EQ(webkitPID, pidAfterBackNavigation);
920
921     [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID completionHandler:^(NSArray<NSString *> *activeDomains) {
922         EXPECT_EQ(1u, activeDomains.count);
923         EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]);
924         done = true;
925     }];
926     TestWebKitAPI::Util::run(&done);
927     done = false;
928
929     [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID completionHandler:^(NSArray<NSString *> *activeDomains) {
930         EXPECT_EQ(1u, activeDomains.count);
931         EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
932         done = true;
933     }];
934     TestWebKitAPI::Util::run(&done);
935     done = false;
936 }
937
938 #endif // PLATFORM(MAC)
939
940 TEST(ProcessSwap, BackWithoutSuspendedPage)
941 {
942     auto processPoolConfiguration = psonProcessPoolConfiguration();
943     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
944
945     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
946     [webViewConfiguration setProcessPool:processPool.get()];
947     auto handler = adoptNS([[PSONScheme alloc] init]);
948     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
949     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
950
951     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
952     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
953
954     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
955     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
956     [webView1 setNavigationDelegate:delegate.get()];
957
958     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
959     [webView1 loadRequest:request];
960
961     TestWebKitAPI::Util::run(&receivedMessage);
962     receivedMessage = false;
963     TestWebKitAPI::Util::run(&done);
964     done = false;
965
966     auto pid1 = [webView1 _webProcessIdentifier];
967     RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState];
968     webView1 = nullptr;
969
970     auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
971     delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
972     [webView2 setNavigationDelegate:delegate.get()];
973
974     [webView2 _restoreSessionState:sessionState.get() andNavigate:NO];
975
976     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
977     [webView2 loadRequest:request];
978
979     TestWebKitAPI::Util::run(&done);
980     done = false;
981
982     auto pid2 = [webView2 _webProcessIdentifier];
983
984     [webView2 goBack];
985
986     TestWebKitAPI::Util::run(&receivedMessage);
987     receivedMessage = false;
988     TestWebKitAPI::Util::run(&done);
989     done = false;
990
991     auto pid3 = [webView2 _webProcessIdentifier];
992
993     EXPECT_FALSE(pid1 == pid2);
994     EXPECT_FALSE(pid2 == pid3);
995 }
996
997 TEST(ProcessSwap, BackNavigationAfterSessionRestore)
998 {
999     auto processPoolConfiguration = psonProcessPoolConfiguration();
1000     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1001
1002     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1003     [webViewConfiguration setProcessPool:processPool.get()];
1004     auto handler = adoptNS([[PSONScheme alloc] init]);
1005     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1006
1007     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1008     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1009     [webView1 setNavigationDelegate:delegate.get()];
1010
1011     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1012     [webView1 loadRequest:request];
1013
1014     TestWebKitAPI::Util::run(&done);
1015     done = false;
1016
1017     auto pid1 = [webView1 _webProcessIdentifier];
1018
1019     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1020     [webView1 loadRequest:request];
1021
1022     TestWebKitAPI::Util::run(&done);
1023     done = false;
1024
1025     auto pid2 = [webView1 _webProcessIdentifier];
1026     EXPECT_NE(pid1, pid2);
1027
1028     RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState];
1029     webView1 = nullptr;
1030
1031     auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1032     delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1033     [webView2 setNavigationDelegate:delegate.get()];
1034
1035     [webView2 _restoreSessionState:sessionState.get() andNavigate:YES];
1036     TestWebKitAPI::Util::run(&done);
1037     done = false;
1038
1039     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView2 URL] absoluteString]);
1040     auto pid3 = [webView2 _webProcessIdentifier];
1041
1042     [webView2 goBack];
1043     TestWebKitAPI::Util::run(&done);
1044     done = false;
1045
1046     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView2 URL] absoluteString]);
1047     auto pid4 = [webView2 _webProcessIdentifier];
1048     EXPECT_NE(pid3, pid4);
1049 }
1050
1051 #if PLATFORM(MAC)
1052
1053 TEST(ProcessSwap, CrossSiteWindowOpenNoOpener)
1054 {
1055     auto processPoolConfiguration = psonProcessPoolConfiguration();
1056     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1057
1058     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1059     [webViewConfiguration setProcessPool:processPool.get()];
1060     auto handler = adoptNS([[PSONScheme alloc] init]);
1061     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteNoOpenerTestBytes];
1062     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1063
1064     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1065     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1066     [webView setNavigationDelegate:navigationDelegate.get()];
1067     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1068     [webView setUIDelegate:uiDelegate.get()];
1069
1070     numberOfDecidePolicyCalls = 0;
1071     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1072     [webView loadRequest:request];
1073
1074     TestWebKitAPI::Util::run(&done);
1075     done = false;
1076
1077     TestWebKitAPI::Util::run(&didCreateWebView);
1078     didCreateWebView = false;
1079
1080     TestWebKitAPI::Util::run(&done);
1081
1082     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1083
1084     auto pid1 = [webView _webProcessIdentifier];
1085     EXPECT_TRUE(!!pid1);
1086     auto pid2 = [createdWebView _webProcessIdentifier];
1087     EXPECT_TRUE(!!pid2);
1088
1089     EXPECT_NE(pid1, pid2);
1090 }
1091
1092 TEST(ProcessSwap, CrossOriginButSameSiteWindowOpenNoOpener)
1093 {
1094     auto processPoolConfiguration = psonProcessPoolConfiguration();
1095     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1096
1097     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1098     [webViewConfiguration setProcessPool:processPool.get()];
1099     auto handler = adoptNS([[PSONScheme alloc] init]);
1100     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossOriginButSameSiteNoOpenerTestBytes];
1101     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1102
1103     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1104     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1105     [webView setNavigationDelegate:navigationDelegate.get()];
1106     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1107     [webView setUIDelegate:uiDelegate.get()];
1108
1109     numberOfDecidePolicyCalls = 0;
1110     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1111     [webView loadRequest:request];
1112
1113     TestWebKitAPI::Util::run(&done);
1114     done = false;
1115
1116     TestWebKitAPI::Util::run(&didCreateWebView);
1117     didCreateWebView = false;
1118
1119     TestWebKitAPI::Util::run(&done);
1120
1121     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1122
1123     auto pid1 = [webView _webProcessIdentifier];
1124     EXPECT_TRUE(!!pid1);
1125     auto pid2 = [createdWebView _webProcessIdentifier];
1126     EXPECT_TRUE(!!pid2);
1127
1128     EXPECT_EQ(pid1, pid2);
1129 }
1130
1131 TEST(ProcessSwap, CrossSiteWindowOpenWithOpener)
1132 {
1133     auto processPoolConfiguration = psonProcessPoolConfiguration();
1134     processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
1135     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1136
1137     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1138     [webViewConfiguration setProcessPool:processPool.get()];
1139     auto handler = adoptNS([[PSONScheme alloc] init]);
1140     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteWithOpenerTestBytes];
1141     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1142
1143     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1144     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1145     [webView setNavigationDelegate:navigationDelegate.get()];
1146     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1147     [webView setUIDelegate:uiDelegate.get()];
1148
1149     numberOfDecidePolicyCalls = 0;
1150     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1151     [webView loadRequest:request];
1152
1153     TestWebKitAPI::Util::run(&done);
1154     done = false;
1155
1156     TestWebKitAPI::Util::run(&didCreateWebView);
1157     didCreateWebView = false;
1158
1159     TestWebKitAPI::Util::run(&done);
1160
1161     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1162
1163     auto pid1 = [webView _webProcessIdentifier];
1164     EXPECT_TRUE(!!pid1);
1165     auto pid2 = [createdWebView _webProcessIdentifier];
1166     EXPECT_TRUE(!!pid2);
1167
1168     EXPECT_NE(pid1, pid2);
1169 }
1170
1171 TEST(ProcessSwap, SameSiteWindowOpenNoOpener)
1172 {
1173     auto processPoolConfiguration = psonProcessPoolConfiguration();
1174     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1175
1176     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1177     [webViewConfiguration setProcessPool:processPool.get()];
1178     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenSameSiteNoOpenerTestBytes]);
1179     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1180
1181     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1182     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1183     [webView setNavigationDelegate:navigationDelegate.get()];
1184     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1185     [webView setUIDelegate:uiDelegate.get()];
1186
1187     numberOfDecidePolicyCalls = 0;
1188     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1189     [webView loadRequest:request];
1190
1191     TestWebKitAPI::Util::run(&done);
1192     done = false;
1193
1194     TestWebKitAPI::Util::run(&didCreateWebView);
1195     didCreateWebView = false;
1196
1197     TestWebKitAPI::Util::run(&done);
1198
1199     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1200
1201     auto pid1 = [webView _webProcessIdentifier];
1202     EXPECT_TRUE(!!pid1);
1203     auto pid2 = [createdWebView _webProcessIdentifier];
1204     EXPECT_TRUE(!!pid2);
1205
1206     EXPECT_EQ(pid1, pid2);
1207 }
1208
1209 TEST(ProcessSwap, CrossSiteBlankTargetWithOpener)
1210 {
1211     auto processPoolConfiguration = psonProcessPoolConfiguration();
1212     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1213
1214     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1215     [webViewConfiguration setProcessPool:processPool.get()];
1216     auto handler = adoptNS([[PSONScheme alloc] init]);
1217     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithExplicitOpenerTestBytes];
1218     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1219
1220     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1221     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1222     [webView setNavigationDelegate:navigationDelegate.get()];
1223     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1224     [webView setUIDelegate:uiDelegate.get()];
1225
1226     numberOfDecidePolicyCalls = 0;
1227     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1228     [webView loadRequest:request];
1229
1230     TestWebKitAPI::Util::run(&done);
1231     done = false;
1232
1233     TestWebKitAPI::Util::run(&didCreateWebView);
1234     didCreateWebView = false;
1235
1236     TestWebKitAPI::Util::run(&done);
1237
1238     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1239
1240     auto pid1 = [webView _webProcessIdentifier];
1241     EXPECT_TRUE(!!pid1);
1242     auto pid2 = [createdWebView _webProcessIdentifier];
1243     EXPECT_TRUE(!!pid2);
1244
1245     EXPECT_EQ(pid1, pid2);
1246 }
1247
1248 TEST(ProcessSwap, CrossSiteBlankTargetImplicitNoOpener)
1249 {
1250     auto processPoolConfiguration = psonProcessPoolConfiguration();
1251     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1252
1253     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1254     [webViewConfiguration setProcessPool:processPool.get()];
1255     auto handler = adoptNS([[PSONScheme alloc] init]);
1256     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithImplicitNoOpenerTestBytes];
1257     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1258
1259     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1260     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1261     [webView setNavigationDelegate:navigationDelegate.get()];
1262     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1263     [webView setUIDelegate:uiDelegate.get()];
1264
1265     numberOfDecidePolicyCalls = 0;
1266     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1267     [webView loadRequest:request];
1268
1269     TestWebKitAPI::Util::run(&done);
1270     done = false;
1271
1272     TestWebKitAPI::Util::run(&didCreateWebView);
1273     didCreateWebView = false;
1274
1275     TestWebKitAPI::Util::run(&done);
1276
1277     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1278
1279     auto pid1 = [webView _webProcessIdentifier];
1280     EXPECT_TRUE(!!pid1);
1281     auto pid2 = [createdWebView _webProcessIdentifier];
1282     EXPECT_TRUE(!!pid2);
1283
1284     EXPECT_NE(pid1, pid2);
1285 }
1286
1287 TEST(ProcessSwap, CrossSiteBlankTargetNoOpener)
1288 {
1289     auto processPoolConfiguration = psonProcessPoolConfiguration();
1290     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1291
1292     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1293     [webViewConfiguration setProcessPool:processPool.get()];
1294     auto handler = adoptNS([[PSONScheme alloc] init]);
1295     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteNoOpenerTestBytes];
1296     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1297
1298     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1299     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1300     [webView setNavigationDelegate:navigationDelegate.get()];
1301     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1302     [webView setUIDelegate:uiDelegate.get()];
1303
1304     numberOfDecidePolicyCalls = 0;
1305     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1306     [webView loadRequest:request];
1307
1308     TestWebKitAPI::Util::run(&done);
1309     done = false;
1310
1311     TestWebKitAPI::Util::run(&didCreateWebView);
1312     didCreateWebView = false;
1313
1314     TestWebKitAPI::Util::run(&done);
1315
1316     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1317
1318     auto pid1 = [webView _webProcessIdentifier];
1319     EXPECT_TRUE(!!pid1);
1320     auto pid2 = [createdWebView _webProcessIdentifier];
1321     EXPECT_TRUE(!!pid2);
1322
1323     EXPECT_NE(pid1, pid2);
1324 }
1325
1326 TEST(ProcessSwap, SameSiteBlankTargetNoOpener)
1327 {
1328     auto processPoolConfiguration = psonProcessPoolConfiguration();
1329     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1330
1331     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1332     [webViewConfiguration setProcessPool:processPool.get()];
1333     auto handler = adoptNS([[PSONScheme alloc] init]);
1334     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankSameSiteNoOpenerTestBytes];
1335     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1336
1337     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1338     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1339     [webView setNavigationDelegate:navigationDelegate.get()];
1340     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1341     [webView setUIDelegate:uiDelegate.get()];
1342
1343     numberOfDecidePolicyCalls = 0;
1344     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1345     [webView loadRequest:request];
1346
1347     TestWebKitAPI::Util::run(&done);
1348     done = false;
1349
1350     TestWebKitAPI::Util::run(&didCreateWebView);
1351     didCreateWebView = false;
1352
1353     TestWebKitAPI::Util::run(&done);
1354
1355     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1356
1357     auto pid1 = [webView _webProcessIdentifier];
1358     EXPECT_TRUE(!!pid1);
1359     auto pid2 = [createdWebView _webProcessIdentifier];
1360     EXPECT_TRUE(!!pid2);
1361
1362     EXPECT_EQ(pid1, pid2);
1363 }
1364
1365 #endif // PLATFORM(MAC)
1366
1367 TEST(ProcessSwap, ServerRedirectFromNewWebView)
1368 {
1369     auto processPoolConfiguration = psonProcessPoolConfiguration();
1370     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1371
1372     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1373     [webViewConfiguration setProcessPool:processPool.get()];
1374     auto handler = adoptNS([[PSONScheme alloc] init]);
1375     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"];
1376     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1377
1378     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1379     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1380     [webView setNavigationDelegate:delegate.get()];
1381
1382     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1383     [webView loadRequest:request];
1384
1385     TestWebKitAPI::Util::run(&serverRedirected);
1386     serverRedirected = false;
1387
1388     seenPIDs.add([webView _webProcessIdentifier]);
1389
1390     TestWebKitAPI::Util::run(&done);
1391     done = false;
1392
1393     seenPIDs.add([webView _webProcessIdentifier]);
1394
1395     EXPECT_FALSE(serverRedirected);
1396     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1397     EXPECT_EQ(1u, seenPIDs.size());
1398 }
1399
1400 TEST(ProcessSwap, ServerRedirect)
1401 {
1402     auto processPoolConfiguration = psonProcessPoolConfiguration();
1403     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1404
1405     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1406     [webViewConfiguration setProcessPool:processPool.get()];
1407     auto handler = adoptNS([[PSONScheme alloc] init]);
1408     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"];
1409     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1410
1411     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1412     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1413     [webView setNavigationDelegate:delegate.get()];
1414
1415     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main1.html"]];
1416     [webView loadRequest:request];
1417
1418     TestWebKitAPI::Util::run(&done);
1419     done = false;
1420
1421     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1422
1423     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1424     EXPECT_EQ(1u, seenPIDs.size());
1425     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
1426
1427     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1428     [webView loadRequest:request];
1429
1430     TestWebKitAPI::Util::run(&serverRedirected);
1431     serverRedirected = false;
1432
1433     seenPIDs.add([webView _webProcessIdentifier]);
1434     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1435         seenPIDs.add(provisionalPID);
1436
1437     TestWebKitAPI::Util::run(&done);
1438     done = false;
1439
1440     seenPIDs.add([webView _webProcessIdentifier]);
1441     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1442         seenPIDs.add(provisionalPID);
1443
1444     EXPECT_FALSE(serverRedirected);
1445     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1446     EXPECT_EQ(2u, seenPIDs.size());
1447 }
1448
1449 TEST(ProcessSwap, ServerRedirect2)
1450 {
1451     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
1452     auto processPoolConfiguration = psonProcessPoolConfiguration();
1453     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1454
1455     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1456     [webViewConfiguration setProcessPool:processPool.get()];
1457     auto handler1 = adoptNS([[PSONScheme alloc] init]);
1458     [handler1 addRedirectFromURLString:@"pson://www.webkit.org/main2.html" toURLString:@"pson://www.apple.com/main.html"];
1459     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
1460     auto handler2 = adoptNS([[PSONScheme alloc] init]);
1461     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
1462
1463     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1464     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1465     [webView setNavigationDelegate:delegate.get()];
1466
1467     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
1468     [webView loadRequest:request];
1469
1470     TestWebKitAPI::Util::run(&done);
1471     done = false;
1472
1473     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1474
1475     EXPECT_FALSE(serverRedirected);
1476     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1477     EXPECT_EQ(1u, seenPIDs.size());
1478     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
1479
1480     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
1481     [webView loadRequest:request];
1482
1483     TestWebKitAPI::Util::run(&serverRedirected);
1484     serverRedirected = false;
1485
1486     seenPIDs.add([webView _webProcessIdentifier]);
1487     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1488         seenPIDs.add(provisionalPID);
1489
1490     TestWebKitAPI::Util::run(&done);
1491     done = false;
1492
1493     seenPIDs.add([webView _webProcessIdentifier]);
1494     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1495         seenPIDs.add(provisionalPID);
1496
1497     EXPECT_FALSE(serverRedirected);
1498     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1499     EXPECT_EQ(2u, seenPIDs.size());
1500
1501     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
1502
1503     [webView goBack];
1504
1505     TestWebKitAPI::Util::run(&done);
1506     done = false;
1507
1508     EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]);
1509 }
1510
1511 TEST(ProcessSwap, ServerRedirectToAboutBlank)
1512 {
1513     auto processPoolConfiguration = psonProcessPoolConfiguration();
1514     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1515
1516     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1517     [webViewConfiguration setProcessPool:processPool.get()];
1518     auto handler = adoptNS([[PSONScheme alloc] init]);
1519     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"about:blank"];
1520     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1521
1522     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1523     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1524     [webView setNavigationDelegate:delegate.get()];
1525
1526     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
1527     [webView loadRequest:request];
1528
1529     TestWebKitAPI::Util::run(&done);
1530     done = false;
1531
1532     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1533
1534     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1535     EXPECT_EQ(1u, seenPIDs.size());
1536     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
1537
1538     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1539     [webView loadRequest:request];
1540
1541     TestWebKitAPI::Util::run(&serverRedirected);
1542     serverRedirected = false;
1543
1544     seenPIDs.add([webView _webProcessIdentifier]);
1545     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1546         seenPIDs.add(provisionalPID);
1547
1548     TestWebKitAPI::Util::run(&done);
1549     done = false;
1550
1551     seenPIDs.add([webView _webProcessIdentifier]);
1552     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1553         seenPIDs.add(provisionalPID);
1554
1555     EXPECT_FALSE(serverRedirected);
1556     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1557     EXPECT_EQ(2u, seenPIDs.size());
1558 }
1559
1560 enum class ShouldCacheProcessFirst { No, Yes };
1561 static void runSameOriginServerRedirectTest(ShouldCacheProcessFirst shouldCacheProcessFirst)
1562 {
1563     auto processPoolConfiguration = psonProcessPoolConfiguration();
1564     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1565     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1566
1567     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1568     [webViewConfiguration setProcessPool:processPool.get()];
1569     auto handler = adoptNS([[PSONScheme alloc] init]);
1570     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:crossSiteClientSideRedirectBytes];
1571     [handler addRedirectFromURLString:@"pson://www.apple.com/main.html" toURLString:@"pson://www.apple.com/main2.html"];
1572     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1573
1574     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1575     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1576     [webView setNavigationDelegate:delegate.get()];
1577
1578     NSURLRequest *request;
1579
1580     if (shouldCacheProcessFirst == ShouldCacheProcessFirst::Yes) {
1581         request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main3.html"]];
1582         [webView loadRequest:request];
1583
1584         TestWebKitAPI::Util::run(&done);
1585         done = false;
1586     }
1587
1588     delegate->didStartProvisionalNavigationHandler = ^{
1589         seenPIDs.add([webView _webProcessIdentifier]);
1590         if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1591             seenPIDs.add(provisionalPID);
1592     };
1593
1594     willPerformClientRedirect = false;
1595     didPerformClientRedirect = false;
1596     serverRedirected = false;
1597     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1598     [webView loadRequest:request];
1599
1600     TestWebKitAPI::Util::run(&willPerformClientRedirect);
1601
1602     seenPIDs.add([webView _webProcessIdentifier]);
1603     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1604         seenPIDs.add(provisionalPID);
1605
1606     TestWebKitAPI::Util::run(&didPerformClientRedirect);
1607     didPerformClientRedirect = false;
1608     willPerformClientRedirect = false;
1609
1610     seenPIDs.add([webView _webProcessIdentifier]);
1611     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1612         seenPIDs.add(provisionalPID);
1613
1614     TestWebKitAPI::Util::run(&serverRedirected);
1615     serverRedirected = false;
1616
1617     seenPIDs.add([webView _webProcessIdentifier]);
1618     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1619         seenPIDs.add(provisionalPID);
1620
1621     TestWebKitAPI::Util::run(&done);
1622     done = false;
1623
1624     seenPIDs.add([webView _webProcessIdentifier]);
1625     if (auto provisionalPID = [webView _provisionalWebProcessIdentifier])
1626         seenPIDs.add(provisionalPID);
1627
1628     EXPECT_EQ(2u, seenPIDs.size());
1629 }
1630
1631 TEST(ProcessSwap, SameOriginServerRedirect)
1632 {
1633     runSameOriginServerRedirectTest(ShouldCacheProcessFirst::No);
1634 }
1635
1636 TEST(ProcessSwap, SameOriginServerRedirectFromCachedProcess)
1637 {
1638     runSameOriginServerRedirectTest(ShouldCacheProcessFirst::Yes);
1639 }
1640
1641 TEST(ProcessSwap, TerminateProcessRightAfterSwap)
1642 {
1643     auto processPoolConfiguration = psonProcessPoolConfiguration();
1644     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1645
1646     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1647     [webViewConfiguration setProcessPool:processPool.get()];
1648     auto handler = adoptNS([[PSONScheme alloc] init]);
1649     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1650
1651     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1652     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1653     [webView setNavigationDelegate:delegate.get()];
1654
1655     [webView configuration].preferences._safeBrowsingEnabled = NO;
1656
1657     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1658     [webView loadRequest:request];
1659
1660     TestWebKitAPI::Util::run(&done);
1661     done = false;
1662
1663     delegate->didStartProvisionalNavigationHandler = ^{
1664         EXPECT_NE(0, [webView _provisionalWebProcessIdentifier]);
1665         kill([webView _provisionalWebProcessIdentifier], 9);
1666     };
1667
1668     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1669     [webView loadRequest:request];
1670
1671     TestWebKitAPI::Util::sleep(0.5);
1672 }
1673
1674 static const char* linkToWebKitBytes = R"PSONRESOURCE(
1675 <body>
1676   <a id="testLink" href="pson://www.webkit.org/main.html">Link</a>
1677 </body>
1678 )PSONRESOURCE";
1679
1680 TEST(ProcessSwap, PolicyCancelAfterServerRedirect)
1681 {
1682     auto processPoolConfiguration = psonProcessPoolConfiguration();
1683     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1684
1685     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1686     [webViewConfiguration setProcessPool:processPool.get()];
1687     auto handler = adoptNS([[PSONScheme alloc] init]);
1688     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes];
1689     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/ignore.html"];
1690     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1691
1692     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1693     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1694     [webView setNavigationDelegate:navigationDelegate.get()];
1695
1696     navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *action, void (^decisionHandler)(WKNavigationActionPolicy)) {
1697         if ([action.request.URL.absoluteString hasSuffix:@"ignore.html"]) {
1698             decisionHandler(WKNavigationActionPolicyCancel);
1699             return;
1700         }
1701         decisionHandler(WKNavigationActionPolicyAllow);
1702     };
1703
1704     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
1705     [webView loadRequest:request];
1706
1707     TestWebKitAPI::Util::run(&done);
1708     done = false;
1709     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1710
1711     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1712
1713     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1714
1715     TestWebKitAPI::Util::run(&failed);
1716     failed = false;
1717     done = false;
1718
1719     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1720
1721     // We should still be on google.com.
1722     EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]);
1723     EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]);
1724
1725     [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) {
1726         EXPECT_WK_STREQ(@"Link", innerText);
1727         done = true;
1728     }];
1729     TestWebKitAPI::Util::run(&done);
1730     done = false;
1731 }
1732
1733 TEST(ProcessSwap, CrossSiteDownload)
1734 {
1735     auto processPoolConfiguration = psonProcessPoolConfiguration();
1736     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1737
1738     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1739     [webViewConfiguration setProcessPool:processPool.get()];
1740     auto handler = adoptNS([[PSONScheme alloc] init]);
1741     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:linkToWebKitBytes];
1742     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:"Hello"];
1743     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1744
1745     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1746     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1747     [webView setNavigationDelegate:navigationDelegate.get()];
1748
1749     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
1750     [webView loadRequest:request];
1751
1752     TestWebKitAPI::Util::run(&done);
1753     done = false;
1754     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1755
1756     shouldConvertToDownload = true;
1757     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1758
1759     TestWebKitAPI::Util::run(&failed);
1760     failed = false;
1761     shouldConvertToDownload = false;
1762
1763     // We should still be on google.com.
1764     EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]);
1765     EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [[webView URL] absoluteString]);
1766
1767     [webView evaluateJavaScript:@"testLink.innerText" completionHandler: [&] (id innerText, NSError *error) {
1768         EXPECT_WK_STREQ(@"Link", innerText);
1769         done = true;
1770     }];
1771     TestWebKitAPI::Util::run(&done);
1772     done = false;
1773 }
1774
1775 #if USE(SYSTEM_PREVIEW)
1776
1777 static const char* systemPreviewSameOriginTestBytes = R"PSONRESOURCE(
1778 <body>
1779     <a id="testLink" rel="ar" href="pson://www.webkit.org/whatever">
1780         <img src="http://www.webkit.org/image">
1781     </a>
1782 </body>
1783 )PSONRESOURCE";
1784
1785 static const char* systemPreviewCrossOriginTestBytes = R"PSONRESOURCE(
1786 <body>
1787     <a id="testLink" rel="ar" href="pson://www.apple.com/whatever">
1788         <img src="http://www.webkit.org/image">
1789     </a>
1790 </body>
1791 )PSONRESOURCE";
1792
1793 TEST(ProcessSwap, SameOriginSystemPreview)
1794 {
1795     auto processPoolConfiguration = psonProcessPoolConfiguration();
1796     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1797
1798     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1799     [webViewConfiguration setProcessPool:processPool.get()];
1800     auto handler = adoptNS([[PSONScheme alloc] init]);
1801     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:systemPreviewSameOriginTestBytes];
1802     [handler addMappingFromURLString:@"pson://www.webkit.org/whatever" toData:"Fake USDZ data"];
1803     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1804
1805     [webViewConfiguration _setSystemPreviewEnabled:YES];
1806
1807     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1808     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1809     [webView setNavigationDelegate:navigationDelegate.get()];
1810
1811     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1812     [webView loadRequest:request];
1813
1814     TestWebKitAPI::Util::run(&done);
1815     done = false;
1816     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1817
1818     didStartProvisionalLoad = false;
1819     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1820
1821     TestWebKitAPI::Util::sleep(0.5);
1822
1823     // We should still be on webkit.org.
1824     EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]);
1825     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]);
1826     EXPECT_FALSE(didStartProvisionalLoad);
1827 }
1828
1829 TEST(ProcessSwap, CrossOriginSystemPreview)
1830 {
1831     auto processPoolConfiguration = psonProcessPoolConfiguration();
1832     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1833
1834     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1835     [webViewConfiguration setProcessPool:processPool.get()];
1836     auto handler = adoptNS([[PSONScheme alloc] init]);
1837     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:systemPreviewCrossOriginTestBytes];
1838     [handler addMappingFromURLString:@"pson://www.apple.com/whatever" toData:"Fake USDZ data"];
1839     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1840
1841     [webViewConfiguration _setSystemPreviewEnabled:YES];
1842
1843     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1844     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1845     [webView setNavigationDelegate:navigationDelegate.get()];
1846
1847     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1848     [webView loadRequest:request];
1849
1850     TestWebKitAPI::Util::run(&done);
1851     done = false;
1852     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1853
1854     didStartProvisionalLoad = false;
1855     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1856
1857     TestWebKitAPI::Util::sleep(0.5);
1858
1859     // We should still be on webkit.org.
1860     EXPECT_EQ(pidAfterFirstLoad, [webView _webProcessIdentifier]);
1861     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]);
1862     EXPECT_FALSE(didStartProvisionalLoad);
1863 }
1864
1865 #endif
1866
1867 enum class ShouldEnablePSON { No, Yes };
1868 static void runClientSideRedirectTest(ShouldEnablePSON shouldEnablePSON)
1869 {
1870     auto processPoolConfiguration = psonProcessPoolConfiguration();
1871     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
1872     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1873
1874     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1875     [webViewConfiguration setProcessPool:processPool.get()];
1876     auto handler = adoptNS([[PSONScheme alloc] init]);
1877     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:linkToCrossSiteClientSideRedirectBytes];
1878     [handler addMappingFromURLString:@"pson://www.google.com/clientSideRedirect.html" toData:crossSiteClientSideRedirectBytes];
1879     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1880
1881     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1882     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1883     [webView setNavigationDelegate:delegate.get()];
1884
1885     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1886     [webView loadRequest:request];
1887
1888     TestWebKitAPI::Util::run(&done);
1889     done = false;
1890
1891     auto webkitPID = [webView _webProcessIdentifier];
1892
1893     // Navigate to the page doing a client-side redirect to apple.com.
1894     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1895
1896     TestWebKitAPI::Util::run(&done);
1897     done = false;
1898
1899     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [[webView URL] absoluteString]);
1900     auto googlePID = [webView _webProcessIdentifier];
1901     if (shouldEnablePSON == ShouldEnablePSON::Yes)
1902         EXPECT_NE(webkitPID, googlePID);
1903     else
1904         EXPECT_EQ(webkitPID, googlePID);
1905
1906     TestWebKitAPI::Util::run(&done);
1907     done = false;
1908
1909     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
1910
1911     auto applePID = [webView _webProcessIdentifier];
1912     if (shouldEnablePSON == ShouldEnablePSON::Yes) {
1913         EXPECT_NE(webkitPID, applePID);
1914         EXPECT_NE(webkitPID, googlePID);
1915     } else {
1916         EXPECT_EQ(webkitPID, applePID);
1917         EXPECT_EQ(webkitPID, googlePID);
1918     }
1919
1920     EXPECT_TRUE(willPerformClientRedirect);
1921     EXPECT_TRUE(didPerformClientRedirect);
1922     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [clientRedirectSourceURL absoluteString]);
1923     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [clientRedirectDestinationURL absoluteString]);
1924
1925     willPerformClientRedirect = false;
1926     didPerformClientRedirect = false;
1927     clientRedirectSourceURL = nullptr;
1928     clientRedirectDestinationURL = nullptr;
1929
1930     // Validate Back/Forward list.
1931     auto* backForwardList = [webView backForwardList];
1932     auto* currentItem = backForwardList.currentItem;
1933     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]);
1934     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]);
1935     EXPECT_TRUE(!backForwardList.forwardItem);
1936
1937     EXPECT_EQ(1U, backForwardList.backList.count);
1938
1939     auto* backItem = backForwardList.backItem;
1940     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]);
1941     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]);
1942
1943     // Navigate back.
1944     [webView goBack];
1945     TestWebKitAPI::Util::run(&done);
1946     done = false;
1947
1948     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]);
1949     EXPECT_FALSE(willPerformClientRedirect);
1950     EXPECT_FALSE(didPerformClientRedirect);
1951
1952     auto pidAfterBackNavigation = [webView _webProcessIdentifier];
1953     if ([processPool _maximumSuspendedPageCount] > 1)
1954         EXPECT_EQ(webkitPID, pidAfterBackNavigation);
1955
1956     // Validate Back/Forward list.
1957     currentItem = backForwardList.currentItem;
1958     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.URL absoluteString]);
1959     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.initialURL absoluteString]);
1960
1961     EXPECT_TRUE(!backForwardList.backItem);
1962     EXPECT_EQ(1U, backForwardList.forwardList.count);
1963
1964     auto* forwardItem = backForwardList.forwardItem;
1965     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.URL absoluteString]);
1966     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.initialURL absoluteString]);
1967
1968     // Navigate forward.
1969     [webView goForward];
1970     TestWebKitAPI::Util::run(&done);
1971     done = false;
1972
1973     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
1974     EXPECT_FALSE(willPerformClientRedirect);
1975     EXPECT_FALSE(didPerformClientRedirect);
1976
1977     auto pidAfterForwardNavigation = [webView _webProcessIdentifier];
1978     EXPECT_EQ(applePID, pidAfterForwardNavigation);
1979
1980     // Validate Back/Forward list.
1981     currentItem = backForwardList.currentItem;
1982     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]);
1983     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]);
1984     EXPECT_TRUE(!backForwardList.forwardItem);
1985
1986     EXPECT_EQ(1U, backForwardList.backList.count);
1987
1988     backItem = backForwardList.backItem;
1989     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]);
1990     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]);
1991 }
1992
1993 TEST(ProcessSwap, CrossSiteClientSideRedirectWithoutPSON)
1994 {
1995     runClientSideRedirectTest(ShouldEnablePSON::No);
1996 }
1997
1998 TEST(ProcessSwap, CrossSiteClientSideRedirectWithPSON)
1999 {
2000     runClientSideRedirectTest(ShouldEnablePSON::Yes);
2001 }
2002
2003 TEST(ProcessSwap, CrossSiteClientSideRedirectFromFileURL)
2004 {
2005     auto processPoolConfiguration = psonProcessPoolConfiguration();
2006     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2007
2008     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2009     [webViewConfiguration setProcessPool:processPool.get()];
2010     auto handler = adoptNS([[PSONScheme alloc] init]);
2011     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
2012
2013     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2014     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2015     [webView setNavigationDelegate:delegate.get()];
2016
2017     willPerformClientRedirect = false;
2018     didPerformClientRedirect = false;
2019
2020     NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"client-side-redirect" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
2021     [webView loadRequest:request];
2022
2023     TestWebKitAPI::Util::run(&done);
2024     done = false;
2025
2026     auto pid1 = [webView _webProcessIdentifier];
2027
2028     TestWebKitAPI::Util::run(&done);
2029     done = false;
2030
2031     auto pid2 = [webView _webProcessIdentifier];
2032     EXPECT_NE(pid1, pid2);
2033
2034     EXPECT_EQ(1U, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
2035     EXPECT_TRUE(willPerformClientRedirect);
2036     EXPECT_TRUE(didPerformClientRedirect);
2037 }
2038
2039 TEST(ProcessSwap, NavigateBackAfterClientSideRedirect)
2040 {
2041     auto processPoolConfiguration = psonProcessPoolConfiguration();
2042     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2043
2044     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2045     [webViewConfiguration setProcessPool:processPool.get()];
2046     auto handler = adoptNS([[PSONScheme alloc] init]);
2047     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:linkToCrossSiteClientSideRedirectBytes];
2048     [handler addMappingFromURLString:@"pson://www.google.com/clientSideRedirect.html" toData:crossSiteClientSideRedirectBytes];
2049     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
2050
2051     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2052     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2053     [webView setNavigationDelegate:delegate.get()];
2054
2055     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2056     [webView loadRequest:request];
2057
2058     TestWebKitAPI::Util::run(&done);
2059     done = false;
2060
2061     auto webkitPID = [webView _webProcessIdentifier];
2062
2063     willPerformClientRedirect = false;
2064     didPerformClientRedirect = false;
2065
2066     // Navigate to the page doing a client-side redirect to apple.com.
2067     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
2068
2069     TestWebKitAPI::Util::run(&done);
2070     done = false;
2071
2072     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [[webView URL] absoluteString]);
2073     auto googlePID = [webView _webProcessIdentifier];
2074     EXPECT_NE(webkitPID, googlePID);
2075
2076     TestWebKitAPI::Util::run(&done);
2077     done = false;
2078
2079     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
2080
2081     auto applePID = [webView _webProcessIdentifier];
2082     EXPECT_NE(webkitPID, applePID);
2083     EXPECT_NE(webkitPID, googlePID);
2084
2085     EXPECT_TRUE(willPerformClientRedirect);
2086     EXPECT_TRUE(didPerformClientRedirect);
2087     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [clientRedirectSourceURL absoluteString]);
2088     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [clientRedirectDestinationURL absoluteString]);
2089
2090     willPerformClientRedirect = false;
2091     didPerformClientRedirect = false;
2092
2093     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
2094     [webView loadRequest:request];
2095
2096     TestWebKitAPI::Util::run(&done);
2097     done = false;
2098
2099     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2100
2101     [webView goBack];
2102
2103     TestWebKitAPI::Util::run(&done);
2104     done = false;
2105
2106     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2107     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
2108
2109     EXPECT_FALSE(willPerformClientRedirect);
2110     EXPECT_FALSE(didPerformClientRedirect);
2111 }
2112
2113 static void runNavigationWithLockedHistoryTest(ShouldEnablePSON shouldEnablePSON)
2114 {
2115     auto processPoolConfiguration = psonProcessPoolConfiguration();
2116     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
2117     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2118
2119     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2120     [webViewConfiguration setProcessPool:processPool.get()];
2121     auto handler = adoptNS([[PSONScheme alloc] init]);
2122     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigationWithLockedHistoryBytes];
2123     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes];
2124     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
2125
2126     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
2127     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
2128
2129     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2130     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2131     [webView setNavigationDelegate:delegate.get()];
2132
2133     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2134     [webView loadRequest:request];
2135
2136     TestWebKitAPI::Util::run(&done);
2137     done = false;
2138
2139     auto webkitPID = [webView _webProcessIdentifier];
2140
2141     // Page redirects to apple.com.
2142     TestWebKitAPI::Util::run(&done);
2143     done = false;
2144
2145     auto applePID = [webView _webProcessIdentifier];
2146     if (shouldEnablePSON == ShouldEnablePSON::Yes)
2147         EXPECT_NE(webkitPID, applePID);
2148     else
2149         EXPECT_EQ(webkitPID, applePID);
2150
2151     auto* backForwardList = [webView backForwardList];
2152     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
2153     EXPECT_TRUE(!backForwardList.forwardItem);
2154     EXPECT_EQ(1U, backForwardList.backList.count);
2155     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
2156
2157     receivedMessage = false;
2158     [webView goBack];
2159     TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache.
2160     receivedMessage = false;
2161     TestWebKitAPI::Util::run(&done);
2162     done = false;
2163
2164     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2165     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]);
2166     EXPECT_TRUE(!backForwardList.backItem);
2167     EXPECT_EQ(1U, backForwardList.forwardList.count);
2168     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]);
2169
2170     [webView goForward];
2171     TestWebKitAPI::Util::run(&done);
2172     TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache.
2173     receivedMessage = false;
2174     done = false;
2175
2176     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2177
2178     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
2179     EXPECT_TRUE(!backForwardList.forwardItem);
2180     EXPECT_EQ(1U, backForwardList.backList.count);
2181     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
2182 }
2183
2184 TEST(ProcessSwap, NavigationWithLockedHistoryWithPSON)
2185 {
2186     runNavigationWithLockedHistoryTest(ShouldEnablePSON::Yes);
2187 }
2188
2189 static void runQuickBackForwardNavigationTest(ShouldEnablePSON shouldEnablePSON)
2190 {
2191     auto processPoolConfiguration = psonProcessPoolConfiguration();
2192     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
2193     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2194
2195     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2196     [webViewConfiguration setProcessPool:processPool.get()];
2197     auto handler = adoptNS([[PSONScheme alloc] init]);
2198     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
2199
2200     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2201     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2202     [webView setNavigationDelegate:delegate.get()];
2203
2204     [webView configuration].preferences._safeBrowsingEnabled = NO;
2205
2206     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2207     [webView loadRequest:request];
2208
2209     TestWebKitAPI::Util::run(&done);
2210     done = false;
2211
2212     auto webkitPID = [webView _webProcessIdentifier];
2213
2214     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2215     [webView loadRequest:request];
2216
2217     TestWebKitAPI::Util::run(&done);
2218     done = false;
2219
2220     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2221
2222     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2223     [webView loadRequest:request];
2224
2225     TestWebKitAPI::Util::run(&done);
2226     done = false;
2227
2228     auto applePID = [webView _webProcessIdentifier];
2229     if (shouldEnablePSON == ShouldEnablePSON::Yes)
2230         EXPECT_NE(webkitPID, applePID);
2231     else
2232         EXPECT_EQ(webkitPID, applePID);
2233
2234     for (unsigned i = 0; i < 10; ++i) {
2235         [webView goBack];
2236         TestWebKitAPI::Util::sleep(0.1);
2237         [webView goForward];
2238         TestWebKitAPI::Util::spinRunLoop(0.1);
2239     }
2240
2241     Vector<String> backForwardListURLs;
2242     auto* backForwardList = [webView backForwardList];
2243     for (unsigned i = 0; i < backForwardList.backList.count; ++i)
2244         backForwardListURLs.append([backForwardList.backList[i].URL absoluteString]);
2245     backForwardListURLs.append([backForwardList.currentItem.URL absoluteString]);
2246     for (unsigned i = 0; i < backForwardList.forwardList.count; ++i)
2247         backForwardListURLs.append([backForwardList.forwardList[i].URL absoluteString]);
2248     EXPECT_EQ(3u, backForwardListURLs.size());
2249     EXPECT_WK_STREQ("pson://www.webkit.org/main1.html", backForwardListURLs[0]);
2250     EXPECT_WK_STREQ("pson://www.webkit.org/main2.html", backForwardListURLs[1]);
2251     EXPECT_WK_STREQ("pson://www.apple.com/main.html", backForwardListURLs[2]);
2252 }
2253
2254 TEST(ProcessSwap, QuickBackForwardNavigationWithoutPSON)
2255 {
2256     runQuickBackForwardNavigationTest(ShouldEnablePSON::No);
2257 }
2258
2259 TEST(ProcessSwap, QuickBackForwardNavigationWithPSON)
2260 {
2261     runQuickBackForwardNavigationTest(ShouldEnablePSON::Yes);
2262 }
2263
2264 TEST(ProcessSwap, NavigationWithLockedHistoryWithoutPSON)
2265 {
2266     runNavigationWithLockedHistoryTest(ShouldEnablePSON::No);
2267 }
2268
2269 static const char* sessionStorageTestBytes = R"PSONRESOURCE(
2270 <head>
2271 <script>
2272
2273 function log(msg)
2274 {
2275     window.webkit.messageHandlers.pson.postMessage(msg);
2276 }
2277
2278 window.onload = function(evt) {
2279     log(sessionStorage.psonKey);
2280     sessionStorage.psonKey = "I exist!";
2281 }
2282
2283 </script>
2284 </head>
2285 )PSONRESOURCE";
2286
2287 TEST(ProcessSwap, SessionStorage)
2288 {
2289     for (int i = 0; i < 5; ++i) {
2290         [receivedMessages removeAllObjects];
2291         auto processPoolConfiguration = psonProcessPoolConfiguration();
2292         auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2293
2294         auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2295         [webViewConfiguration setProcessPool:processPool.get()];
2296         auto handler = adoptNS([[PSONScheme alloc] init]);
2297         [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:sessionStorageTestBytes];
2298         [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2299
2300         auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
2301         [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
2302
2303         auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2304         auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2305         [webView setNavigationDelegate:delegate.get()];
2306
2307         NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2308         [webView loadRequest:request];
2309
2310         TestWebKitAPI::Util::run(&receivedMessage);
2311         receivedMessage = false;
2312         TestWebKitAPI::Util::run(&done);
2313         done = false;
2314
2315         auto webkitPID = [webView _webProcessIdentifier];
2316
2317         request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2318         [webView loadRequest:request];
2319
2320         TestWebKitAPI::Util::run(&done);
2321         done = false;
2322
2323         auto applePID = [webView _webProcessIdentifier];
2324
2325         // Verify the web pages are in different processes
2326         EXPECT_NE(webkitPID, applePID);
2327
2328         request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2329         [webView loadRequest:request];
2330
2331         TestWebKitAPI::Util::run(&receivedMessage);
2332         receivedMessage = false;
2333         TestWebKitAPI::Util::run(&done);
2334         done = false;
2335
2336         // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible.
2337         EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2338
2339         // Verify the sessionStorage values were as expected
2340         EXPECT_EQ([receivedMessages count], 2u);
2341         EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@""]);
2342         EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"I exist!"]);
2343     }
2344 }
2345
2346 TEST(ProcessSwap, ReuseSuspendedProcess)
2347 {
2348     auto processPoolConfiguration = psonProcessPoolConfiguration();
2349     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2350
2351     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2352     [webViewConfiguration setProcessPool:processPool.get()];
2353     auto handler = adoptNS([[PSONScheme alloc] init]);
2354     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2355
2356     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2357     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2358     [webView setNavigationDelegate:delegate.get()];
2359
2360     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2361     [webView loadRequest:request];
2362
2363     TestWebKitAPI::Util::run(&done);
2364     done = false;
2365
2366     auto webkitPID = [webView _webProcessIdentifier];
2367
2368     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]];
2369     [webView loadRequest:request];
2370
2371     TestWebKitAPI::Util::run(&done);
2372     done = false;
2373
2374     auto applePID = [webView _webProcessIdentifier];
2375
2376     EXPECT_NE(webkitPID, applePID);
2377
2378     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2379     [webView loadRequest:request];
2380
2381     TestWebKitAPI::Util::run(&done);
2382     done = false;
2383
2384     // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible.
2385     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2386
2387     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
2388     [webView loadRequest:request];
2389
2390     TestWebKitAPI::Util::run(&done);
2391     done = false;
2392
2393     // We should have gone back to the apple.com process for this load since we reuse SuspendedPages' process when possible.
2394     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2395 }
2396
2397 static const char* failsToEnterPageCacheTestBytes = R"PSONRESOURCE(
2398 <body>
2399 <script>
2400 // Pages with dedicated workers do not go into page cache.
2401 var myWorker = new Worker('worker.js');
2402 </script>
2403 </body>
2404 )PSONRESOURCE";
2405
2406 TEST(ProcessSwap, ReuseSuspendedProcessEvenIfPageCacheFails)
2407 {
2408     auto processPoolConfiguration = psonProcessPoolConfiguration();
2409     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2410
2411     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2412     [webViewConfiguration setProcessPool:processPool.get()];
2413     auto handler = adoptNS([[PSONScheme alloc] init]);
2414     [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:failsToEnterPageCacheTestBytes];
2415     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2416
2417     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2418     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2419     [webView setNavigationDelegate:delegate.get()];
2420
2421     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2422     [webView loadRequest:request];
2423
2424     TestWebKitAPI::Util::run(&done);
2425     done = false;
2426
2427     auto webkitPID = [webView _webProcessIdentifier];
2428
2429     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]];
2430     [webView loadRequest:request];
2431
2432     TestWebKitAPI::Util::run(&done);
2433     done = false;
2434
2435     auto applePID = [webView _webProcessIdentifier];
2436
2437     EXPECT_NE(webkitPID, applePID);
2438
2439     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2440     [webView loadRequest:request];
2441
2442     TestWebKitAPI::Util::run(&done);
2443     done = false;
2444
2445     // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible.
2446     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2447
2448     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
2449     [webView loadRequest:request];
2450
2451     TestWebKitAPI::Util::run(&done);
2452     done = false;
2453
2454     // We should have gone back to the apple.com process for this load since we reuse SuspendedPages' process when possible.
2455     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2456 }
2457
2458 TEST(ProcessSwap, ReuseSuspendedProcessOnBackEvenIfPageCacheFails)
2459 {
2460     auto processPoolConfiguration = psonProcessPoolConfiguration();
2461     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2462
2463     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2464     [webViewConfiguration setProcessPool:processPool.get()];
2465     auto handler = adoptNS([[PSONScheme alloc] init]);
2466     [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:failsToEnterPageCacheTestBytes];
2467     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2468
2469     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2470     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2471     [webView setNavigationDelegate:delegate.get()];
2472
2473     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2474     [webView loadRequest:request];
2475
2476     TestWebKitAPI::Util::run(&done);
2477     done = false;
2478
2479     auto webkitPID = [webView _webProcessIdentifier];
2480
2481     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]];
2482     [webView loadRequest:request];
2483
2484     TestWebKitAPI::Util::run(&done);
2485     done = false;
2486
2487     auto applePID = [webView _webProcessIdentifier];
2488
2489     EXPECT_NE(webkitPID, applePID);
2490
2491     [webView goBack];
2492
2493     TestWebKitAPI::Util::run(&done);
2494     done = false;
2495
2496     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2497 }
2498
2499 static const char* withSubframesTestBytes = R"PSONRESOURCE(
2500 <body>
2501 <iframe src="about:blank"></iframe>
2502 <iframe src="about:blank"></iframe>
2503 </body>
2504 )PSONRESOURCE";
2505
2506 TEST(ProcessSwap, HistoryItemIDConfusion)
2507 {
2508     auto processPoolConfiguration = psonProcessPoolConfiguration();
2509     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2510
2511     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2512     [webViewConfiguration setProcessPool:processPool.get()];
2513     auto handler = adoptNS([[PSONScheme alloc] init]);
2514     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:failsToEnterPageCacheTestBytes];
2515     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:withSubframesTestBytes];
2516     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2517
2518     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2519     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2520     [webView setNavigationDelegate:delegate.get()];
2521
2522     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2523     [webView loadRequest:request];
2524
2525     TestWebKitAPI::Util::run(&done);
2526     done = false;
2527
2528     auto webkitPID = [webView _webProcessIdentifier];
2529
2530     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2531     [webView loadRequest:request];
2532
2533     TestWebKitAPI::Util::run(&done);
2534     done = false;
2535
2536     auto applePID = [webView _webProcessIdentifier];
2537     EXPECT_NE(webkitPID, applePID);
2538
2539     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
2540     [webView loadRequest:request];
2541
2542     TestWebKitAPI::Util::run(&done);
2543     done = false;
2544
2545     auto googlePID = [webView _webProcessIdentifier];
2546     EXPECT_NE(applePID, googlePID);
2547     EXPECT_NE(webkitPID, googlePID);
2548
2549     [webView goBack];
2550
2551     TestWebKitAPI::Util::run(&done);
2552     done = false;
2553
2554     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2555
2556     [webView goBack];
2557
2558     TestWebKitAPI::Util::run(&done);
2559     done = false;
2560
2561     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2562
2563     auto* backForwardList = [webView backForwardList];
2564     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]);
2565     EXPECT_EQ(2U, backForwardList.forwardList.count);
2566     EXPECT_EQ(0U, backForwardList.backList.count);
2567     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardList[0].URL absoluteString]);
2568     EXPECT_WK_STREQ(@"pson://www.google.com/main.html", [backForwardList.forwardList[1].URL absoluteString]);
2569 }
2570
2571 TEST(ProcessSwap, GoToSecondItemInBackHistory)
2572 {
2573     auto processPoolConfiguration = psonProcessPoolConfiguration();
2574     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2575
2576     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2577     [webViewConfiguration setProcessPool:processPool.get()];
2578     auto handler = adoptNS([[PSONScheme alloc] init]);
2579     [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:withSubframesTestBytes];
2580     [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:withSubframesTestBytes];
2581     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:withSubframesTestBytes];
2582     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2583
2584     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2585     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2586     [webView setNavigationDelegate:delegate.get()];
2587
2588     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2589     [webView loadRequest:request];
2590
2591     TestWebKitAPI::Util::run(&done);
2592     done = false;
2593
2594     auto webkitPID = [webView _webProcessIdentifier];
2595
2596     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2597     [webView loadRequest:request];
2598
2599     TestWebKitAPI::Util::run(&done);
2600     done = false;
2601
2602     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2603
2604     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2605     [webView loadRequest:request];
2606
2607     TestWebKitAPI::Util::run(&done);
2608     done = false;
2609
2610     auto applePID = [webView _webProcessIdentifier];
2611     EXPECT_NE(webkitPID, applePID);
2612
2613     [webView goToBackForwardListItem:webView.get().backForwardList.backList[0]];
2614     TestWebKitAPI::Util::run(&done);
2615     done = false;
2616
2617     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2618     EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView URL] absoluteString]);
2619
2620     [webView goToBackForwardListItem:webView.get().backForwardList.forwardList[1]];
2621     TestWebKitAPI::Util::run(&done);
2622     done = false;
2623
2624     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
2625     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
2626 }
2627
2628 TEST(ProcessSwap, PrivateAndRegularSessionsShouldGetDifferentProcesses)
2629 {
2630     auto processPoolConfiguration = psonProcessPoolConfiguration();
2631     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2632
2633     auto privateWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2634     [privateWebViewConfiguration setProcessPool:processPool.get()];
2635     [privateWebViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]];
2636     auto handler = adoptNS([[PSONScheme alloc] init]);
2637     [privateWebViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2638     auto regularWebViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2639     [regularWebViewConfiguration setProcessPool:processPool.get()];
2640     [regularWebViewConfiguration setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
2641     [regularWebViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2642
2643     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2644
2645     auto regularWebView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:regularWebViewConfiguration.get()]);
2646     [regularWebView1 setNavigationDelegate:delegate.get()];
2647
2648     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
2649     [regularWebView1 loadRequest:request];
2650
2651     TestWebKitAPI::Util::run(&done);
2652     done = false;
2653
2654     [regularWebView1 _close];
2655     regularWebView1 = nil;
2656
2657     auto privateWebView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:privateWebViewConfiguration.get()]);
2658     [privateWebView setNavigationDelegate:delegate.get()];
2659
2660     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2661     [privateWebView loadRequest:request];
2662
2663     TestWebKitAPI::Util::run(&done);
2664     done = false;
2665
2666     auto privateSessionWebkitPID = [privateWebView _webProcessIdentifier];
2667
2668     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2669     [privateWebView loadRequest:request];
2670
2671     TestWebKitAPI::Util::run(&done);
2672     done = false;
2673
2674     auto privateSessionApplePID = [privateWebView _webProcessIdentifier];
2675     EXPECT_NE(privateSessionWebkitPID, privateSessionApplePID);
2676
2677     [privateWebView _close];
2678     privateWebView = nil;
2679
2680     auto regularWebView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:regularWebViewConfiguration.get()]);
2681     [regularWebView2 setNavigationDelegate:delegate.get()];
2682
2683     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
2684     [regularWebView2 loadRequest:request];
2685
2686     TestWebKitAPI::Util::run(&done);
2687     done = false;
2688
2689     auto regularSessionGooglePID = [regularWebView2 _webProcessIdentifier];
2690
2691     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2692     [regularWebView2 loadRequest:request];
2693
2694     TestWebKitAPI::Util::run(&done);
2695     done = false;
2696
2697     auto regularSessionWebkitPID = [regularWebView2 _webProcessIdentifier];
2698     EXPECT_NE(regularSessionGooglePID, regularSessionWebkitPID);
2699     EXPECT_NE(privateSessionWebkitPID, regularSessionWebkitPID);
2700 }
2701
2702 static const char* keepNavigatingFrameBytes = R"PSONRESOURCE(
2703 <body>
2704 <iframe id="testFrame1" src="about:blank"></iframe>
2705 <iframe id="testFrame2" src="about:blank"></iframe>
2706 <iframe id="testFrame3" src="about:blank"></iframe>
2707 <script>
2708 window.addEventListener('pagehide', function(event) {
2709     for (var j = 0; j < 10000; j++);
2710 });
2711
2712 var i = 0;
2713 function navigateFrames()
2714 {
2715     testFrame1.src = "pson://www.google.com/main" + i + ".html";
2716     testFrame2.src = "pson://www.google.com/main" + i + ".html";
2717     testFrame3.src = "pson://www.google.com/main" + i + ".html";
2718     i++;
2719 }
2720
2721 navigateFrames();
2722 setInterval(() => {
2723     navigateFrames();
2724 }, 0);
2725 </script>
2726 </body>
2727 )PSONRESOURCE";
2728
2729 enum class RetainPageInBundle { No, Yes };
2730
2731 void testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle retainPageInBundle)
2732 {
2733     auto processPoolConfiguration = psonProcessPoolConfiguration();
2734     if (retainPageInBundle == RetainPageInBundle::Yes)
2735         [processPoolConfiguration setInjectedBundleURL:[[NSBundle mainBundle] URLForResource:@"TestWebKitAPI" withExtension:@"wkbundle"]];
2736     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2737     if (retainPageInBundle == RetainPageInBundle::Yes)
2738         [processPool _setObject:@"BundleRetainPagePlugIn" forBundleParameter:TestWebKitAPI::Util::TestPlugInClassNameParameter];
2739
2740     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2741     [webViewConfiguration setProcessPool:processPool.get()];
2742     auto handler = adoptNS([[PSONScheme alloc] init]);
2743     [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:keepNavigatingFrameBytes];
2744     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2745
2746     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2747     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2748     [webView setNavigationDelegate:delegate.get()];
2749
2750     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2751     [webView loadRequest:request];
2752
2753     TestWebKitAPI::Util::run(&done);
2754     done = false;
2755
2756     auto webkitPID = [webView _webProcessIdentifier];
2757
2758     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2759     [webView loadRequest:request];
2760
2761     TestWebKitAPI::Util::run(&done);
2762     done = false;
2763
2764     auto applePID = [webView _webProcessIdentifier];
2765     EXPECT_NE(webkitPID, applePID);
2766
2767     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2768     [webView loadRequest:request];
2769
2770     TestWebKitAPI::Util::run(&done);
2771     done = false;
2772
2773     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
2774 }
2775
2776 TEST(ProcessSwap, ReuseSuspendedProcessForRegularNavigationRetainBundlePage)
2777 {
2778     testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle::Yes);
2779 }
2780
2781 TEST(ProcessSwap, ReuseSuspendedProcessForRegularNavigation)
2782 {
2783     testReuseSuspendedProcessForRegularNavigation(RetainPageInBundle::No);
2784 }
2785
2786 static const char* mainFramesOnlyMainFrame = R"PSONRESOURCE(
2787 <script>
2788 function loaded() {
2789     setTimeout('window.frames[0].location.href = "pson://www.apple.com/main.html"', 0);
2790 }
2791 </script>
2792 <body onload="loaded();">
2793 Some text
2794 <iframe src="pson://www.webkit.org/iframe.html"></iframe>
2795 </body>
2796 )PSONRESOURCE";
2797
2798 static const char* mainFramesOnlySubframe = R"PSONRESOURCE(
2799 Some content
2800 )PSONRESOURCE";
2801
2802
2803 static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE(
2804 <script>
2805     window.webkit.messageHandlers.pson.postMessage("Done");
2806 </script>
2807 )PSONRESOURCE";
2808
2809 TEST(ProcessSwap, MainFramesOnly)
2810 {
2811     auto processPoolConfiguration = psonProcessPoolConfiguration();
2812     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2813
2814     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2815     [webViewConfiguration setProcessPool:processPool.get()];
2816     auto handler = adoptNS([[PSONScheme alloc] init]);
2817     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:mainFramesOnlyMainFrame];
2818     [handler addMappingFromURLString:@"pson://www.webkit.org/iframe" toData:mainFramesOnlySubframe];
2819     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:mainFramesOnlySubframe2];
2820     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2821
2822     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
2823     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
2824
2825     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2826     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2827     [webView setNavigationDelegate:delegate.get()];
2828
2829     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2830     [webView loadRequest:request];
2831
2832     TestWebKitAPI::Util::run(&receivedMessage);
2833     receivedMessage = false;
2834
2835     EXPECT_EQ(1u, seenPIDs.size());
2836 }
2837
2838 #if PLATFORM(MAC)
2839
2840 static const char* getClientWidthBytes = R"PSONRESOURCE(
2841 <body>
2842 TEST
2843 <script>
2844 function getClientWidth()
2845 {
2846     document.body.offsetTop; // Force layout.
2847     return document.body.clientWidth;
2848 }
2849 </script>
2850 </body>
2851 )PSONRESOURCE";
2852
2853 static unsigned waitUntilClientWidthIs(WKWebView *webView, unsigned expectedClientWidth)
2854 {
2855     int timeout = 10;
2856     unsigned clientWidth = 0;
2857     do {
2858         if (timeout != 10)
2859             TestWebKitAPI::Util::sleep(0.1);
2860
2861         [webView evaluateJavaScript:@"getClientWidth()" completionHandler: [&] (id result, NSError *error) {
2862             clientWidth = [result integerValue];
2863             done = true;
2864         }];
2865         TestWebKitAPI::Util::run(&done);
2866         done = false;
2867         --timeout;
2868     } while (clientWidth != expectedClientWidth && timeout >= 0);
2869
2870     return clientWidth;
2871 }
2872
2873 TEST(ProcessSwap, PageZoomLevelAfterSwap)
2874 {
2875     auto processPoolConfiguration = psonProcessPoolConfiguration();
2876     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2877
2878     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2879     [webViewConfiguration setProcessPool:processPool.get()];
2880     auto handler = adoptNS([[PSONScheme alloc] init]);
2881     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:getClientWidthBytes];
2882     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:getClientWidthBytes];
2883     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2884
2885     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2886     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2887     [webView setNavigationDelegate:delegate.get()];
2888
2889     delegate->didCommitNavigationHandler = ^ {
2890         [webView _setPageZoomFactor:2.0];
2891         delegate->didCommitNavigationHandler = nil;
2892     };
2893
2894     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2895     [webView loadRequest:request];
2896
2897     TestWebKitAPI::Util::run(&done);
2898     done = false;
2899
2900     unsigned clientWidth = waitUntilClientWidthIs(webView.get(), 400);
2901     EXPECT_EQ(400U, clientWidth);
2902
2903     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2904     [webView loadRequest:request];
2905
2906     TestWebKitAPI::Util::run(&done);
2907     done = false;
2908
2909     clientWidth = waitUntilClientWidthIs(webView.get(), 400);
2910     EXPECT_EQ(400U, clientWidth);
2911
2912     // Kill the WebProcess, the page should reload automatically and the page zoom level should be maintained.
2913     kill([webView _webProcessIdentifier], 9);
2914
2915     TestWebKitAPI::Util::run(&done);
2916     done = false;
2917
2918     clientWidth = waitUntilClientWidthIs(webView.get(), 400);
2919     EXPECT_EQ(400U, clientWidth);
2920 }
2921
2922 #endif // PLATFORM(MAC)
2923
2924 static const char* navigateBeforePageLoadEndBytes = R"PSONRESOURCE(
2925 <body>
2926 <a id="testLink" href="pson://www.apple.com/main.html">Link</a>
2927 <script>
2928     testLink.click();
2929 </script>
2930 <p>TEST</p>
2931 <script src="test.js"></script>
2932 <script src="test2.js"></script>
2933 <iframe src="subframe1.html></iframe>
2934 <iframe src="subframe2.html></iframe>
2935 <iframe src="subframe3.html></iframe>
2936 <iframe src="subframe4.html></iframe>
2937 </body>
2938 )PSONRESOURCE";
2939
2940 TEST(ProcessSwap, NavigateCrossSiteBeforePageLoadEnd)
2941 {
2942     auto processPoolConfiguration = psonProcessPoolConfiguration();
2943     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2944
2945     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2946     [webViewConfiguration setProcessPool:processPool.get()];
2947     auto handler = adoptNS([[PSONScheme alloc] init]);
2948     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigateBeforePageLoadEndBytes];
2949     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2950
2951     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2952     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2953     [webView setNavigationDelegate:delegate.get()];
2954
2955     [webView configuration].preferences._safeBrowsingEnabled = NO;
2956
2957     failed = false;
2958     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2959     [webView loadRequest:request];
2960
2961     TestWebKitAPI::Util::run(&done);
2962     done = false;
2963
2964     EXPECT_FALSE(failed);
2965     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
2966 }
2967
2968
2969 TEST(ProcessSwap, DoSameSiteNavigationAfterCrossSiteProvisionalLoadStarted)
2970 {
2971     auto processPoolConfiguration = psonProcessPoolConfiguration();
2972     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2973
2974     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2975     [webViewConfiguration setProcessPool:processPool.get()];
2976     auto handler = adoptNS([[PSONScheme alloc] init]);
2977     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2978
2979     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2980     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2981     [webView setNavigationDelegate:delegate.get()];
2982
2983     [webView configuration].preferences._safeBrowsingEnabled = NO;
2984
2985     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2986     [webView loadRequest:request];
2987
2988     TestWebKitAPI::Util::run(&done);
2989     done = false;
2990
2991     auto webkitPID = [webView _webProcessIdentifier];
2992
2993     delegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) {
2994         decisionHandler(WKNavigationActionPolicyAllow);
2995
2996         delegate->decidePolicyForNavigationAction = nil;
2997         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]]];
2998     };
2999
3000     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
3001     [webView loadRequest:request];
3002
3003     TestWebKitAPI::Util::run(&done);
3004     done = false;
3005
3006     EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[webView URL] absoluteString]);
3007     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
3008 }
3009
3010 TEST(ProcessSwap, SuspendedPageLimit)
3011 {
3012     auto processPoolConfiguration = psonProcessPoolConfiguration();
3013     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
3014
3015     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
3016     [webViewConfiguration setProcessPool:processPool.get()];
3017     auto handler = adoptNS([[PSONScheme alloc] init]);
3018     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
3019
3020     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
3021     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
3022     [webView setNavigationDelegate:delegate.get()];
3023
3024     auto maximumSuspendedPageCount = [processPool _maximumSuspendedPageCount];
3025     EXPECT_GT(maximumSuspendedPageCount, 0U);
3026
3027     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
3028     [webView loadRequest:request];
3029
3030     TestWebKitAPI::Util::run(&done);
3031     done = false;
3032
3033     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
3034     [webView loadRequest:request];
3035
3036     TestWebKitAPI::Util::run(&done);
3037     done = false;
3038
3039     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
3040     [webView loadRequest:request];
3041
3042     TestWebKitAPI::Util::run(&done);
3043     done = false;
3044
3045     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
3046     [webView loadRequest:request];
3047
3048     TestWebKitAPI::Util::run(&done);
3049     done = false;
3050
3051     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.yahoo.com/main.html"]];
3052     [webView loadRequest:request];
3053
3054     TestWebKitAPI::Util::run(&done);
3055     done = false;
3056
3057     // Navigations to 5 different domains, we expect to have seen 5 different PIDs
3058     EXPECT_EQ(5u, seenPIDs.size());
3059
3060     // But not all of those processes should still be alive (1 visible, maximumSuspendedPageCount suspended).
3061     auto expectedProcessCount = 1 + maximumSuspendedPageCount;
3062     int timeout = 20;
3063     while ([processPool _webProcessCountIgnoringPrewarmedAndCached] != expectedProcessCount && timeout >= 0) {
3064         TestWebKitAPI::Util::sleep(0.1);
3065         --timeout;
3066     }
3067
3068     EXPECT_EQ(expectedProcessCount, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3069 }
3070
3071 TEST(ProcessSwap, PageCache1)
3072 {
3073     auto processPoolConfiguration = psonProcessPoolConfiguration();
3074     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
3075
3076     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
3077     [webViewConfiguration setProcessPool:processPool.get()];
3078     auto handler = adoptNS([[PSONScheme alloc] init]);
3079     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes];
3080     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes];
3081     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
3082
3083     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
3084     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
3085
3086     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
3087     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
3088     [webView setNavigationDelegate:delegate.get()];
3089
3090     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
3091
3092     [webView loadRequest:request];
3093     TestWebKitAPI::Util::run(&done);
3094     done = false;
3095
3096     auto pidAfterLoad1 = [webView _webProcessIdentifier];
3097
3098     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3099
3100     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
3101
3102     [webView loadRequest:request];
3103     TestWebKitAPI::Util::run(&done);
3104     done = false;
3105
3106     auto pidAfterLoad2 = [webView _webProcessIdentifier];
3107
3108     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3109     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
3110
3111     [webView goBack];
3112     TestWebKitAPI::Util::run(&receivedMessage);
3113     receivedMessage = false;
3114     TestWebKitAPI::Util::run(&done);
3115     done = false;
3116
3117     auto pidAfterLoad3 = [webView _webProcessIdentifier];
3118
3119     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3120     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
3121     EXPECT_EQ(1u, [receivedMessages count]);
3122     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
3123     EXPECT_EQ(2u, seenPIDs.size());
3124
3125     [webView goForward];
3126     TestWebKitAPI::Util::run(&receivedMessage);
3127     receivedMessage = false;
3128     TestWebKitAPI::Util::run(&done);
3129     done = false;
3130
3131     auto pidAfterLoad4 = [webView _webProcessIdentifier];
3132
3133     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3134     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
3135     EXPECT_EQ(2u, [receivedMessages count]);
3136     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
3137     EXPECT_EQ(2u, seenPIDs.size());
3138 }
3139
3140 TEST(ProcessSwap, PageCacheWhenNavigatingFromJS)
3141 {
3142     auto processPoolConfiguration = psonProcessPoolConfiguration();
3143     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
3144
3145     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
3146     [webViewConfiguration setProcessPool:processPool.get()];
3147     auto handler = adoptNS([[PSONScheme alloc] init]);
3148     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes];
3149     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes];
3150     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
3151
3152     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
3153     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
3154
3155     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
3156     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
3157     [webView setNavigationDelegate:delegate.get()];
3158
3159     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
3160
3161     [webView loadRequest:request];
3162     TestWebKitAPI::Util::run(&done);
3163     done = false;
3164
3165     auto pidAfterLoad1 = [webView _webProcessIdentifier];
3166
3167     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3168
3169     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
3170
3171     [webView loadRequest:request];
3172     TestWebKitAPI::Util::run(&done);
3173     done = false;
3174
3175     auto pidAfterLoad2 = [webView _webProcessIdentifier];
3176
3177     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3178     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
3179
3180     [webView evaluateJavaScript:@"history.back()" completionHandler: nil];
3181     TestWebKitAPI::Util::run(&receivedMessage);
3182     receivedMessage = false;
3183     TestWebKitAPI::Util::run(&done);
3184     done = false;
3185
3186     auto pidAfterLoad3 = [webView _webProcessIdentifier];
3187
3188     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3189     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
3190     EXPECT_EQ(1u, [receivedMessages count]);
3191     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
3192     EXPECT_EQ(2u, seenPIDs.size());
3193
3194     [webView evaluateJavaScript:@"history.forward()" completionHandler: nil];
3195     TestWebKitAPI::Util::run(&receivedMessage);
3196     receivedMessage = false;
3197     TestWebKitAPI::Util::run(&done);
3198     done = false;
3199
3200     auto pidAfterLoad4 = [webView _webProcessIdentifier];
3201
3202     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3203     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
3204     EXPECT_EQ(2u, [receivedMessages count]);
3205     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
3206     EXPECT_EQ(2u, seenPIDs.size());
3207 }
3208
3209 TEST(ProcessSwap, NumberOfPrewarmedProcesses)
3210 {
3211     auto processPoolConfiguration = psonProcessPoolConfiguration();
3212     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
3213
3214     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
3215     [webViewConfiguration setProcessPool:processPool.get()];
3216     auto handler = adoptNS([[PSONScheme alloc] init]);
3217     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
3218
3219     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
3220     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
3221     [webView setNavigationDelegate:delegate.get()];
3222
3223     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
3224     [webView loadRequest:request];
3225     TestWebKitAPI::Util::run(&done);
3226     done = false;
3227
3228     EXPECT_EQ(2u, [processPool _webProcessCount]);
3229     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3230     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
3231
3232     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
3233     [webView loadRequest:request];
3234     TestWebKitAPI::Util::run(&done);
3235     done = false;
3236
3237     EXPECT_EQ(3u, [processPool _webProcessCount]);
3238     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmedAndCached]);
3239     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
3240 }
3241
3242 #if PLATFORM(MAC)
3243
3244 TEST(ProcessSwap, NumberOfCachedProcesses)
3245 {
3246     auto processPoolConfiguration = psonProcessPoolConfiguration();
3247     processPoolConfiguration.get().prewarmsProcessesAutomatically = NO;
3248     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
3249
3250     EXPECT_GT([processPool _maximumSuspendedPageCount], 0u);
3251     EXPECT_GT([processPool _processCacheCapacity], 0u);
3252
3253     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
3254     [webViewConfiguration setProcessPool:processPool.get()];
3255     auto handler = adoptNS([[PSONScheme alloc] init]);
3256
3257     const unsigned maxSuspendedPageCount = [processPool _maximumSuspendedPageCount];
3258     for (unsigned i = 0; i < maxSuspendedPageCount + 2; i++)
3259         [handler addMappingFromURLString:makeString("pson://www.domain-", i, ".com") toData:pageCache1Bytes];
3260     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
3261
3262     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
3263     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
3264     [webView setNavigationDelegate:delegate.get()];
3265
3266     for (unsigned i = 0; i < maxSuspendedPageCount + 1; i++) {
3267         NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:makeString("pson://www.domain-", i, ".com")]];
3268         [webView loadRequest:request];
3269         TestWebKitAPI::Util::run(&done);
3270         done = false;
3271
3272         EXPECT_EQ(i + 1, [processPool _webProcessCount]);