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