fbe8acc546fc0fa69795ec3acf709534c72317e2
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / ProcessSwapOnNavigation.mm
1 /*
2  * Copyright (C) 2017 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 <WebKit/WKInspector.h>
31 #import <WebKit/WKNavigationDelegatePrivate.h>
32 #import <WebKit/WKNavigationPrivate.h>
33 #import <WebKit/WKPreferencesPrivate.h>
34 #import <WebKit/WKProcessPoolPrivate.h>
35 #import <WebKit/WKUIDelegatePrivate.h>
36 #import <WebKit/WKURLSchemeHandler.h>
37 #import <WebKit/WKURLSchemeTaskPrivate.h>
38 #import <WebKit/WKWebViewConfigurationPrivate.h>
39 #import <WebKit/WKWebViewPrivate.h>
40 #import <WebKit/WKWebsiteDataStorePrivate.h>
41 #import <WebKit/WKWebsiteDataStoreRef.h>
42 #import <WebKit/WebKit.h>
43 #import <WebKit/_WKExperimentalFeature.h>
44 #import <WebKit/_WKProcessPoolConfiguration.h>
45 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
46 #import <WebKit/_WKWebsitePolicies.h>
47 #import <wtf/Deque.h>
48 #import <wtf/HashMap.h>
49 #import <wtf/HashSet.h>
50 #import <wtf/RetainPtr.h>
51 #import <wtf/Vector.h>
52 #import <wtf/text/StringHash.h>
53 #import <wtf/text/WTFString.h>
54
55 #if WK_API_ENABLED
56
57 @interface WKProcessPool ()
58 - (WKContextRef)_contextForTesting;
59 @end
60
61 static bool done;
62 static bool failed;
63 static bool didCreateWebView;
64 static int numberOfDecidePolicyCalls;
65
66 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
67 bool didReceiveAlert;
68 static bool receivedMessage;
69 static bool serverRedirected;
70 static HashSet<pid_t> seenPIDs;
71 static bool willPerformClientRedirect;
72 static bool didPerformClientRedirect;
73 static RetainPtr<NSURL> clientRedirectSourceURL;
74 static RetainPtr<NSURL> clientRedirectDestinationURL;
75
76 @interface PSONMessageHandler : NSObject <WKScriptMessageHandler>
77 @end
78
79 @implementation PSONMessageHandler
80 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
81 {
82     if ([message body])
83         [receivedMessages addObject:[message body]];
84     else
85         [receivedMessages addObject:@""];
86
87     receivedMessage = true;
88     if ([message.webView _webProcessIdentifier])
89         seenPIDs.add([message.webView _webProcessIdentifier]);
90 }
91 @end
92
93 @interface PSONNavigationDelegate : NSObject <WKNavigationDelegate> {
94     @public void (^decidePolicyForNavigationAction)(WKNavigationAction *, void (^)(WKNavigationActionPolicy));
95 }
96 @end
97
98 @implementation PSONNavigationDelegate
99
100 - (instancetype) init
101 {
102     self = [super init];
103     return self;
104 }
105
106 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
107 {
108     seenPIDs.add([webView _webProcessIdentifier]);
109     failed = true;
110 }
111
112 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
113 {
114     seenPIDs.add([webView _webProcessIdentifier]);
115     done = true;
116 }
117
118 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
119 {
120     ++numberOfDecidePolicyCalls;
121     seenPIDs.add([webView _webProcessIdentifier]);
122     if (decidePolicyForNavigationAction)
123         decidePolicyForNavigationAction(navigationAction, decisionHandler);
124     else
125         decisionHandler(WKNavigationActionPolicyAllow);
126 }
127
128 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
129 {
130     seenPIDs.add([webView _webProcessIdentifier]);
131     serverRedirected = true;
132 }
133
134 - (void)_webView:(WKWebView *)webView willPerformClientRedirectToURL:(NSURL *)URL delay:(NSTimeInterval)delay
135 {
136     clientRedirectDestinationURL = URL;
137     willPerformClientRedirect = true;
138 }
139
140 - (void)_webView:(WKWebView *)webView didPerformClientRedirectFromURL:(NSURL *)sourceURL toURL:(NSURL *)destinationURL
141 {
142     EXPECT_TRUE(willPerformClientRedirect);
143     EXPECT_WK_STREQ([clientRedirectDestinationURL absoluteString], [destinationURL absoluteString]);
144     clientRedirectSourceURL = sourceURL;
145     didPerformClientRedirect = true;
146 }
147
148 @end
149
150 static RetainPtr<WKWebView> createdWebView;
151
152 @interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
153 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
154 @end
155
156 @implementation PSONUIDelegate {
157     RetainPtr<PSONNavigationDelegate> _navigationDelegate;
158 }
159
160 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
161 {
162     if (!(self = [super init]))
163         return nil;
164
165     _navigationDelegate = navigationDelegate;
166     return self;
167 }
168
169 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
170 {
171     createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
172     [createdWebView setNavigationDelegate:_navigationDelegate.get()];
173     didCreateWebView = true;
174     return createdWebView.get();
175 }
176
177 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)())completionHandler
178 {
179     didReceiveAlert = true;
180     completionHandler();
181 }
182
183 @end
184
185 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
186     const char* _bytes;
187     HashMap<String, String> _redirects;
188     HashMap<String, RetainPtr<NSData *>> _dataMappings;
189 }
190 - (instancetype)initWithBytes:(const char*)bytes;
191 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
192 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data;
193 @end
194
195 @implementation PSONScheme
196
197 - (instancetype)initWithBytes:(const char*)bytes
198 {
199     self = [super init];
200     _bytes = bytes;
201     return self;
202 }
203
204 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
205 {
206     _redirects.set(sourceURLString, destinationURLString);
207 }
208
209 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data
210 {
211     _dataMappings.set(urlString, [NSData dataWithBytesNoCopy:(void*)data length:strlen(data) freeWhenDone:NO]);
212 }
213
214 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
215 {
216     NSURL *finalURL = task.request.URL;
217     auto target = _redirects.get(task.request.URL.absoluteString);
218     if (!target.isEmpty()) {
219         auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
220
221         finalURL = [NSURL URLWithString:(NSString *)target];
222         auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
223
224         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
225     }
226
227     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
228     [task didReceiveResponse:response.get()];
229
230     if (auto data = _dataMappings.get([finalURL absoluteString]))
231         [task didReceiveData:data.get()];
232     else if (_bytes) {
233         RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]);
234         [task didReceiveData:data.get()];
235     } else
236         [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
237
238     [task didFinish];
239 }
240
241 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
242 {
243 }
244
245 @end
246
247 static const char* testBytes = R"PSONRESOURCE(
248 <head>
249 <script>
250
251 function log(msg)
252 {
253     window.webkit.messageHandlers.pson.postMessage(msg);
254 }
255
256 window.onload = function(evt) {
257     if (window.history.state != "onloadCalled")
258         setTimeout('window.history.replaceState("onloadCalled", "");', 0);
259 }
260
261 window.onpageshow = function(evt) {
262     log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state);
263 }
264
265 </script>
266 </head>
267 )PSONRESOURCE";
268
269 static const char* linkToCrossSiteClientSideRedirectBytes = R"PSONRESOURCE(
270 <body>
271   <a id="testLink" href="pson://www.google.com/clientSideRedirect.html">Link to cross-site client-side redirect</a>
272 </body>
273 )PSONRESOURCE";
274
275 static const char* crossSiteClientSideRedirectBytes = R"PSONRESOURCE(
276 <body>
277 <script>
278 onload = () => {
279   location = "pson://www.apple.com/main.html";
280 };
281 </script>
282 </body>
283 )PSONRESOURCE";
284
285 static const char* navigationWithLockedHistoryBytes = R"PSONRESOURCE(
286 <script>
287 let shouldNavigate = true;
288 window.addEventListener('pageshow', function(event) {
289     if (event.persisted) {
290         window.webkit.messageHandlers.pson.postMessage("Was persisted");
291         shouldNavigate = false;
292     }
293 });
294
295 onload = function()
296 {
297     if (!shouldNavigate)
298         return;
299
300     // JS navigation via window.location
301     setTimeout(() => {
302         location = "pson://www.apple.com/main.html";
303     }, 10);
304 }
305 </script>
306 )PSONRESOURCE";
307
308 static const char* pageCache1Bytes = R"PSONRESOURCE(
309 <script>
310 window.addEventListener('pageshow', function(event) {
311     if (event.persisted)
312         window.webkit.messageHandlers.pson.postMessage("Was persisted");
313 });
314 </script>
315 )PSONRESOURCE";
316
317 #if PLATFORM(MAC)
318
319 static const char* windowOpenCrossSiteNoOpenerTestBytes = R"PSONRESOURCE(
320 <script>
321 window.onload = function() {
322     window.open("pson://www.apple.com/main.html", "_blank", "noopener");
323 }
324 </script>
325 )PSONRESOURCE";
326
327 static const char* windowOpenCrossOriginButSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
328 <script>
329 window.onload = function() {
330     window.open("pson://www.webkit.org:8080/main.html", "_blank", "noopener");
331 }
332 </script>
333 )PSONRESOURCE";
334
335 static const char* windowOpenCrossSiteWithOpenerTestBytes = R"PSONRESOURCE(
336 <script>
337 window.onload = function() {
338     window.open("pson://www.apple.com/main.html");
339 }
340 </script>
341 )PSONRESOURCE";
342
343 static const char* windowOpenSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
344 <script>
345 window.onload = function() {
346     if (!opener)
347         window.open("pson://www.webkit.org/main.html", "_blank", "noopener");
348 }
349 </script>
350 )PSONRESOURCE";
351
352 static const char* targetBlankCrossSiteWithExplicitOpenerTestBytes = R"PSONRESOURCE(
353 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="opener">Link</a>
354 <script>
355 window.onload = function() {
356     testLink.click();
357 }
358 </script>
359 )PSONRESOURCE";
360
361 static const char* targetBlankCrossSiteWithImplicitNoOpenerTestBytes = R"PSONRESOURCE(
362 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html">Link</a>
363 <script>
364 window.onload = function() {
365     testLink.click();
366 }
367 </script>
368 )PSONRESOURCE";
369
370 static const char* targetBlankCrossSiteNoOpenerTestBytes = R"PSONRESOURCE(
371 <a id="testLink" target="_blank" href="pson://www.apple.com/main.html" rel="noopener">Link</a>
372 <script>
373 window.onload = function() {
374     testLink.click();
375 }
376 </script>
377 )PSONRESOURCE";
378
379 static const char* targetBlankSameSiteNoOpenerTestBytes = R"PSONRESOURCE(
380 <a id="testLink" target="_blank" href="pson://www.webkit.org/main2.html" rel="noopener">Link</a>
381 <script>
382 window.onload = function() {
383     testLink.click();
384 }
385 </script>
386 )PSONRESOURCE";
387
388 static const char* linkToAppleTestBytes = R"PSONRESOURCE(
389 <script>
390 window.addEventListener('pageshow', function(event) {
391     if (event.persisted)
392         window.webkit.messageHandlers.pson.postMessage("Was persisted");
393 });
394 </script>
395 <a id="testLink" href="pson://www.apple.com/main.html">Navigate</a>
396 )PSONRESOURCE";
397
398 #endif // PLATFORM(MAC)
399
400 TEST(ProcessSwap, Basic)
401 {
402     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
403     processPoolConfiguration.get().processSwapsOnNavigation = YES;
404     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
405     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
406
407     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
408     [webViewConfiguration setProcessPool:processPool.get()];
409     auto handler = adoptNS([[PSONScheme alloc] init]);
410     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
411
412     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
413     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
414     [webView setNavigationDelegate:delegate.get()];
415
416     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
417     [webView loadRequest:request];
418
419     TestWebKitAPI::Util::run(&done);
420     done = false;
421
422     auto pid1 = [webView _webProcessIdentifier];
423
424     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
425     [webView loadRequest:request];
426
427     TestWebKitAPI::Util::run(&done);
428     done = false;
429
430     auto pid2 = [webView _webProcessIdentifier];
431
432     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
433     [webView loadRequest:request];
434
435     TestWebKitAPI::Util::run(&done);
436     done = false;
437
438     auto pid3 = [webView _webProcessIdentifier];
439
440     EXPECT_EQ(pid1, pid2);
441     EXPECT_FALSE(pid2 == pid3);
442
443     // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
444     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
445 }
446
447 TEST(ProcessSwap, LoadAfterPolicyDecision)
448 {
449     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
450     processPoolConfiguration.get().processSwapsOnNavigation = YES;
451     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
452     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
453
454     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
455     [webViewConfiguration setProcessPool:processPool.get()];
456     auto handler = adoptNS([[PSONScheme alloc] init]);
457     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
458
459     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
460     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
461     [webView setNavigationDelegate:navigationDelegate.get()];
462
463     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
464     [webView loadRequest:request];
465
466     TestWebKitAPI::Util::run(&done);
467     done = false;
468
469     navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) {
470         decisionHandler(WKNavigationActionPolicyAllow);
471
472         // Synchronously navigate again right after answering the policy delegate for the previous navigation.
473         navigationDelegate->decidePolicyForNavigationAction = nil;
474         NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
475         [webView loadRequest:request];
476     };
477
478     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
479     [webView loadRequest:request];
480
481     while (![[[webView URL] absoluteString] isEqualToString:@"pson://www.webkit.org/main2.html"])
482         TestWebKitAPI::Util::spinRunLoop();
483 }
484
485 TEST(ProcessSwap, NoSwappingForeTLDPlus2)
486 {
487     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
488     processPoolConfiguration.get().processSwapsOnNavigation = YES;
489     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
490     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
491
492     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
493     [webViewConfiguration setProcessPool:processPool.get()];
494     auto handler = adoptNS([[PSONScheme alloc] init]);
495     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
496
497     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
498     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
499     [webView setNavigationDelegate:delegate.get()];
500
501     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www1.webkit.org/main1.html"]];
502     [webView loadRequest:request];
503
504     TestWebKitAPI::Util::run(&done);
505     done = false;
506
507     auto pid1 = [webView _webProcessIdentifier];
508
509     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www2.webkit.org/main2.html"]];
510     [webView loadRequest:request];
511
512     TestWebKitAPI::Util::run(&done);
513     done = false;
514
515     auto pid2 = [webView _webProcessIdentifier];
516
517     EXPECT_EQ(pid1, pid2);
518
519     EXPECT_EQ(numberOfDecidePolicyCalls, 2);
520 }
521
522 TEST(ProcessSwap, Back)
523 {
524     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
525     processPoolConfiguration.get().processSwapsOnNavigation = YES;
526     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
527
528     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
529     [webViewConfiguration setProcessPool:processPool.get()];
530     auto handler = adoptNS([[PSONScheme alloc] init]);
531     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
532     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:testBytes];
533     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes];
534     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
535
536     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
537     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
538
539     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
540     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
541     [webView setNavigationDelegate:delegate.get()];
542
543     EXPECT_GT([processPool _maximumSuspendedPageCount], 0U);
544
545     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
546     [webView loadRequest:request];
547
548     TestWebKitAPI::Util::run(&receivedMessage);
549     receivedMessage = false;
550     TestWebKitAPI::Util::run(&done);
551     done = false;
552
553     auto webkitPID = [webView _webProcessIdentifier];
554
555     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
556     [webView loadRequest:request];
557
558     TestWebKitAPI::Util::run(&done);
559     done = false;
560
561     auto applePID = [webView _webProcessIdentifier];
562     EXPECT_NE(webkitPID, applePID);
563
564     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
565     [webView loadRequest:request];
566
567     TestWebKitAPI::Util::run(&done);
568     done = false;
569
570     auto googlePID = [webView _webProcessIdentifier];
571     EXPECT_NE(applePID, googlePID);
572
573     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
574     [webView loadRequest:request];
575
576     TestWebKitAPI::Util::run(&done);
577     done = false;
578
579     auto bingPID = [webView _webProcessIdentifier];
580     EXPECT_NE(googlePID, bingPID);
581
582     [webView goBack]; // Back to google.com.
583
584     TestWebKitAPI::Util::run(&receivedMessage);
585     receivedMessage = false;
586     TestWebKitAPI::Util::run(&done);
587     done = false;
588
589     auto pidAfterFirstBackNavigation = [webView _webProcessIdentifier];
590     EXPECT_EQ(googlePID, pidAfterFirstBackNavigation);
591
592     [webView goBack]; // Back to apple.com.
593
594     TestWebKitAPI::Util::run(&receivedMessage);
595     receivedMessage = false;
596     TestWebKitAPI::Util::run(&done);
597     done = false;
598
599     auto pidAfterSecondBackNavigation = [webView _webProcessIdentifier];
600     if ([processPool _maximumSuspendedPageCount] > 1)
601         EXPECT_EQ(applePID, pidAfterSecondBackNavigation);
602     else {
603         EXPECT_NE(applePID, pidAfterSecondBackNavigation);
604         EXPECT_NE(googlePID, pidAfterSecondBackNavigation);
605     }
606
607
608     // 6 loads, 6 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
609     // additional decidePolicy call as a result of the process swap)
610     EXPECT_EQ(6, numberOfDecidePolicyCalls);
611
612     EXPECT_EQ(5u, [receivedMessages count]);
613     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[0]);
614     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[1]);
615     EXPECT_WK_STREQ(@"PageShow called. Persisted: false, and window.history.state is: null", receivedMessages.get()[2]);
616     EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[3]);
617
618     // The number of suspended pages we keep around is determined at runtime.
619     if ([processPool _maximumSuspendedPageCount] > 1) {
620         EXPECT_WK_STREQ(@"PageShow called. Persisted: true, and window.history.state is: onloadCalled", receivedMessages.get()[4]);
621         EXPECT_EQ(4u, seenPIDs.size());
622     } else
623         EXPECT_EQ(5u, seenPIDs.size());
624 }
625
626 TEST(ProcessSwap, SuspendedPageDiesAfterBackForwardListItemIsGone)
627 {
628     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
629     processPoolConfiguration.get().processSwapsOnNavigation = YES;
630     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
631
632     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
633     [webViewConfiguration setProcessPool:processPool.get()];
634     auto handler = adoptNS([[PSONScheme alloc] init]);
635     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
636
637     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
638     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
639     [webView setNavigationDelegate:delegate.get()];
640
641     EXPECT_GT([processPool _maximumSuspendedPageCount], 0U);
642
643     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
644     [webView loadRequest:request];
645
646     TestWebKitAPI::Util::run(&done);
647     done = false;
648
649     auto webkitPID = [webView _webProcessIdentifier];
650
651     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
652     [webView loadRequest:request];
653
654     TestWebKitAPI::Util::run(&done);
655     done = false;
656
657     auto applePID = [webView _webProcessIdentifier];
658     EXPECT_NE(webkitPID, applePID);
659
660     // webkit.org + apple.com processes.
661     EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]);
662
663     [webView goBack]; // Back to webkit.org.
664     TestWebKitAPI::Util::run(&done);
665     done = false;
666
667     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
668
669     // webkit.org + apple.com processes.
670     EXPECT_EQ(2U, [processPool _webProcessCountIgnoringPrewarmed]);
671
672     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
673     [webView loadRequest:request];
674
675     TestWebKitAPI::Util::run(&done);
676     done = false;
677
678     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
679
680     // apple.com is not longer present in the back/forward list and there should therefore be no-suspended page for it.
681     while ([processPool _webProcessCountIgnoringPrewarmed] > 1u)
682         TestWebKitAPI::Util::spinRunLoop();
683 }
684
685 #if PLATFORM(MAC)
686 TEST(ProcessSwap, SuspendedPagesInActivityMonitor)
687 {
688     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
689     processPoolConfiguration.get().processSwapsOnNavigation = YES;
690     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
691
692     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
693     [webViewConfiguration setProcessPool:processPool.get()];
694     auto handler = adoptNS([[PSONScheme alloc] init]);
695     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
696     [handler addMappingFromURLString:@"pson://www.google.com/main.html" toData:testBytes];
697     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
698
699     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
700     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
701
702     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
703     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
704     [webView setNavigationDelegate:delegate.get()];
705
706     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
707     [webView loadRequest:request];
708
709     TestWebKitAPI::Util::run(&done);
710     done = false;
711
712     auto webkitPID = [webView _webProcessIdentifier];
713     auto* activeDomains = [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID];
714     EXPECT_EQ(1u, activeDomains.count);
715     EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
716
717     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
718     [webView loadRequest:request];
719
720     TestWebKitAPI::Util::run(&done);
721     done = false;
722
723     auto googlePID = [webView _webProcessIdentifier];
724     EXPECT_NE(webkitPID, googlePID);
725
726     activeDomains = [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID];
727     EXPECT_EQ(1u, activeDomains.count);
728     EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]);
729
730     activeDomains = [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID];
731     EXPECT_EQ(1u, activeDomains.count);
732     EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
733
734     [webView goBack]; // Back to webkit.org.
735
736     TestWebKitAPI::Util::run(&receivedMessage);
737     receivedMessage = false;
738     TestWebKitAPI::Util::run(&done);
739     done = false;
740
741     auto pidAfterBackNavigation = [webView _webProcessIdentifier];
742     EXPECT_EQ(webkitPID, pidAfterBackNavigation);
743
744     activeDomains = [processPool _getActivePagesOriginsInWebProcessForTesting:googlePID];
745     EXPECT_EQ(1u, activeDomains.count);
746     EXPECT_WK_STREQ(@"pson://www.google.com", activeDomains[0]);
747
748     activeDomains = [processPool _getActivePagesOriginsInWebProcessForTesting:webkitPID];
749     EXPECT_EQ(1u, activeDomains.count);
750     EXPECT_WK_STREQ(@"pson://www.webkit.org", activeDomains[0]);
751 }
752 #endif // PLATFORM(MAC)
753
754 TEST(ProcessSwap, BackWithoutSuspendedPage)
755 {
756     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
757     processPoolConfiguration.get().processSwapsOnNavigation = YES;
758     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
759
760     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
761     [webViewConfiguration setProcessPool:processPool.get()];
762     auto handler = adoptNS([[PSONScheme alloc] init]);
763     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:testBytes];
764     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
765
766     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
767     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
768
769     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
770     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
771     [webView1 setNavigationDelegate:delegate.get()];
772
773     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
774     [webView1 loadRequest:request];
775
776     TestWebKitAPI::Util::run(&receivedMessage);
777     receivedMessage = false;
778     TestWebKitAPI::Util::run(&done);
779     done = false;
780
781     auto pid1 = [webView1 _webProcessIdentifier];
782     RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState];
783     webView1 = nullptr;
784
785     auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
786     delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
787     [webView2 setNavigationDelegate:delegate.get()];
788
789     [webView2 _restoreSessionState:sessionState.get() andNavigate:NO];
790
791     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
792     [webView2 loadRequest:request];
793
794     TestWebKitAPI::Util::run(&done);
795     done = false;
796
797     auto pid2 = [webView2 _webProcessIdentifier];
798
799     [webView2 goBack];
800
801     TestWebKitAPI::Util::run(&receivedMessage);
802     receivedMessage = false;
803     TestWebKitAPI::Util::run(&done);
804     done = false;
805
806     auto pid3 = [webView2 _webProcessIdentifier];
807
808     EXPECT_FALSE(pid1 == pid2);
809     EXPECT_FALSE(pid2 == pid3);
810 }
811
812 TEST(ProcessSwap, BackNavigationAfterSessionRestore)
813 {
814     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
815     processPoolConfiguration.get().processSwapsOnNavigation = YES;
816     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
817
818     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
819     [webViewConfiguration setProcessPool:processPool.get()];
820     auto handler = adoptNS([[PSONScheme alloc] init]);
821     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
822
823     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
824     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
825     [webView1 setNavigationDelegate:delegate.get()];
826
827     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
828     [webView1 loadRequest:request];
829
830     TestWebKitAPI::Util::run(&done);
831     done = false;
832
833     auto pid1 = [webView1 _webProcessIdentifier];
834
835     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
836     [webView1 loadRequest:request];
837
838     TestWebKitAPI::Util::run(&done);
839     done = false;
840
841     auto pid2 = [webView1 _webProcessIdentifier];
842     EXPECT_NE(pid1, pid2);
843
844     RetainPtr<_WKSessionState> sessionState = [webView1 _sessionState];
845     webView1 = nullptr;
846
847     auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
848     delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
849     [webView2 setNavigationDelegate:delegate.get()];
850
851     [webView2 _restoreSessionState:sessionState.get() andNavigate:YES];
852     TestWebKitAPI::Util::run(&done);
853     done = false;
854
855     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView2 URL] absoluteString]);
856     auto pid3 = [webView2 _webProcessIdentifier];
857
858     [webView2 goBack];
859     TestWebKitAPI::Util::run(&done);
860     done = false;
861
862     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView2 URL] absoluteString]);
863     auto pid4 = [webView2 _webProcessIdentifier];
864     EXPECT_NE(pid3, pid4);
865 }
866
867 #if PLATFORM(MAC)
868
869 TEST(ProcessSwap, CrossSiteWindowOpenNoOpener)
870 {
871     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
872     processPoolConfiguration.get().processSwapsOnNavigation = YES;
873     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
874
875     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
876     [webViewConfiguration setProcessPool:processPool.get()];
877     auto handler = adoptNS([[PSONScheme alloc] init]);
878     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteNoOpenerTestBytes];
879     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
880
881     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
882     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
883     [webView setNavigationDelegate:navigationDelegate.get()];
884     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
885     [webView setUIDelegate:uiDelegate.get()];
886
887     numberOfDecidePolicyCalls = 0;
888     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
889     [webView loadRequest:request];
890
891     TestWebKitAPI::Util::run(&done);
892     done = false;
893
894     TestWebKitAPI::Util::run(&didCreateWebView);
895     didCreateWebView = false;
896
897     TestWebKitAPI::Util::run(&done);
898
899     EXPECT_EQ(2, numberOfDecidePolicyCalls);
900
901     auto pid1 = [webView _webProcessIdentifier];
902     EXPECT_TRUE(!!pid1);
903     auto pid2 = [createdWebView _webProcessIdentifier];
904     EXPECT_TRUE(!!pid2);
905
906     EXPECT_NE(pid1, pid2);
907 }
908
909 TEST(ProcessSwap, CrossOriginButSameSiteWindowOpenNoOpener)
910 {
911     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
912     processPoolConfiguration.get().processSwapsOnNavigation = YES;
913     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
914
915     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
916     [webViewConfiguration setProcessPool:processPool.get()];
917     auto handler = adoptNS([[PSONScheme alloc] init]);
918     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossOriginButSameSiteNoOpenerTestBytes];
919     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
920
921     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
922     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
923     [webView setNavigationDelegate:navigationDelegate.get()];
924     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
925     [webView setUIDelegate:uiDelegate.get()];
926
927     numberOfDecidePolicyCalls = 0;
928     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
929     [webView loadRequest:request];
930
931     TestWebKitAPI::Util::run(&done);
932     done = false;
933
934     TestWebKitAPI::Util::run(&didCreateWebView);
935     didCreateWebView = false;
936
937     TestWebKitAPI::Util::run(&done);
938
939     EXPECT_EQ(2, numberOfDecidePolicyCalls);
940
941     auto pid1 = [webView _webProcessIdentifier];
942     EXPECT_TRUE(!!pid1);
943     auto pid2 = [createdWebView _webProcessIdentifier];
944     EXPECT_TRUE(!!pid2);
945
946     EXPECT_EQ(pid1, pid2);
947 }
948
949 TEST(ProcessSwap, CrossSiteWindowOpenWithOpener)
950 {
951     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
952     processPoolConfiguration.get().processSwapsOnNavigation = YES;
953     processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
954     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
955
956     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
957     [webViewConfiguration setProcessPool:processPool.get()];
958     auto handler = adoptNS([[PSONScheme alloc] init]);
959     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:windowOpenCrossSiteWithOpenerTestBytes];
960     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
961
962     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
963     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
964     [webView setNavigationDelegate:navigationDelegate.get()];
965     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
966     [webView setUIDelegate:uiDelegate.get()];
967
968     numberOfDecidePolicyCalls = 0;
969     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
970     [webView loadRequest:request];
971
972     TestWebKitAPI::Util::run(&done);
973     done = false;
974
975     TestWebKitAPI::Util::run(&didCreateWebView);
976     didCreateWebView = false;
977
978     TestWebKitAPI::Util::run(&done);
979
980     EXPECT_EQ(2, numberOfDecidePolicyCalls);
981
982     auto pid1 = [webView _webProcessIdentifier];
983     EXPECT_TRUE(!!pid1);
984     auto pid2 = [createdWebView _webProcessIdentifier];
985     EXPECT_TRUE(!!pid2);
986
987     EXPECT_NE(pid1, pid2);
988 }
989
990 TEST(ProcessSwap, SameSiteWindowOpenNoOpener)
991 {
992     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
993     processPoolConfiguration.get().processSwapsOnNavigation = YES;
994     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
995
996     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
997     [webViewConfiguration setProcessPool:processPool.get()];
998     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenSameSiteNoOpenerTestBytes]);
999     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1000
1001     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1002     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1003     [webView setNavigationDelegate:navigationDelegate.get()];
1004     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1005     [webView setUIDelegate:uiDelegate.get()];
1006
1007     numberOfDecidePolicyCalls = 0;
1008     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1009     [webView loadRequest:request];
1010
1011     TestWebKitAPI::Util::run(&done);
1012     done = false;
1013
1014     TestWebKitAPI::Util::run(&didCreateWebView);
1015     didCreateWebView = false;
1016
1017     TestWebKitAPI::Util::run(&done);
1018
1019     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1020
1021     auto pid1 = [webView _webProcessIdentifier];
1022     EXPECT_TRUE(!!pid1);
1023     auto pid2 = [createdWebView _webProcessIdentifier];
1024     EXPECT_TRUE(!!pid2);
1025
1026     EXPECT_EQ(pid1, pid2);
1027 }
1028
1029 TEST(ProcessSwap, CrossSiteBlankTargetWithOpener)
1030 {
1031     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1032     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1033     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1034
1035     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1036     [webViewConfiguration setProcessPool:processPool.get()];
1037     auto handler = adoptNS([[PSONScheme alloc] init]);
1038     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithExplicitOpenerTestBytes];
1039     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1040
1041     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1042     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1043     [webView setNavigationDelegate:navigationDelegate.get()];
1044     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1045     [webView setUIDelegate:uiDelegate.get()];
1046
1047     numberOfDecidePolicyCalls = 0;
1048     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1049     [webView loadRequest:request];
1050
1051     TestWebKitAPI::Util::run(&done);
1052     done = false;
1053
1054     TestWebKitAPI::Util::run(&didCreateWebView);
1055     didCreateWebView = false;
1056
1057     TestWebKitAPI::Util::run(&done);
1058
1059     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1060
1061     auto pid1 = [webView _webProcessIdentifier];
1062     EXPECT_TRUE(!!pid1);
1063     auto pid2 = [createdWebView _webProcessIdentifier];
1064     EXPECT_TRUE(!!pid2);
1065
1066     EXPECT_EQ(pid1, pid2);
1067 }
1068
1069 TEST(ProcessSwap, CrossSiteBlankTargetImplicitNoOpener)
1070 {
1071     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1072     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1073     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1074
1075     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1076     [webViewConfiguration setProcessPool:processPool.get()];
1077     auto handler = adoptNS([[PSONScheme alloc] init]);
1078     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteWithImplicitNoOpenerTestBytes];
1079     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1080
1081     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1082     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1083     [webView setNavigationDelegate:navigationDelegate.get()];
1084     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1085     [webView setUIDelegate:uiDelegate.get()];
1086
1087     numberOfDecidePolicyCalls = 0;
1088     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1089     [webView loadRequest:request];
1090
1091     TestWebKitAPI::Util::run(&done);
1092     done = false;
1093
1094     TestWebKitAPI::Util::run(&didCreateWebView);
1095     didCreateWebView = false;
1096
1097     TestWebKitAPI::Util::run(&done);
1098
1099     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1100
1101     auto pid1 = [webView _webProcessIdentifier];
1102     EXPECT_TRUE(!!pid1);
1103     auto pid2 = [createdWebView _webProcessIdentifier];
1104     EXPECT_TRUE(!!pid2);
1105
1106     EXPECT_NE(pid1, pid2);
1107 }
1108
1109 TEST(ProcessSwap, CrossSiteBlankTargetNoOpener)
1110 {
1111     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1112     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1113     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1114
1115     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1116     [webViewConfiguration setProcessPool:processPool.get()];
1117     auto handler = adoptNS([[PSONScheme alloc] init]);
1118     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankCrossSiteNoOpenerTestBytes];
1119     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1120
1121     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1122     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1123     [webView setNavigationDelegate:navigationDelegate.get()];
1124     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1125     [webView setUIDelegate:uiDelegate.get()];
1126
1127     numberOfDecidePolicyCalls = 0;
1128     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1129     [webView loadRequest:request];
1130
1131     TestWebKitAPI::Util::run(&done);
1132     done = false;
1133
1134     TestWebKitAPI::Util::run(&didCreateWebView);
1135     didCreateWebView = false;
1136
1137     TestWebKitAPI::Util::run(&done);
1138
1139     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1140
1141     auto pid1 = [webView _webProcessIdentifier];
1142     EXPECT_TRUE(!!pid1);
1143     auto pid2 = [createdWebView _webProcessIdentifier];
1144     EXPECT_TRUE(!!pid2);
1145
1146     EXPECT_NE(pid1, pid2);
1147 }
1148
1149 TEST(ProcessSwap, SameSiteBlankTargetNoOpener)
1150 {
1151     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1152     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1153     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1154
1155     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1156     [webViewConfiguration setProcessPool:processPool.get()];
1157     auto handler = adoptNS([[PSONScheme alloc] init]);
1158     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:targetBlankSameSiteNoOpenerTestBytes];
1159     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1160
1161     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1162     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1163     [webView setNavigationDelegate:navigationDelegate.get()];
1164     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1165     [webView setUIDelegate:uiDelegate.get()];
1166
1167     numberOfDecidePolicyCalls = 0;
1168     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1169     [webView loadRequest:request];
1170
1171     TestWebKitAPI::Util::run(&done);
1172     done = false;
1173
1174     TestWebKitAPI::Util::run(&didCreateWebView);
1175     didCreateWebView = false;
1176
1177     TestWebKitAPI::Util::run(&done);
1178
1179     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1180
1181     auto pid1 = [webView _webProcessIdentifier];
1182     EXPECT_TRUE(!!pid1);
1183     auto pid2 = [createdWebView _webProcessIdentifier];
1184     EXPECT_TRUE(!!pid2);
1185
1186     EXPECT_EQ(pid1, pid2);
1187 }
1188
1189 #endif // PLATFORM(MAC)
1190
1191 TEST(ProcessSwap, ServerRedirectFromNewWebView)
1192 {
1193     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1194     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1195     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1196
1197     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1198     [webViewConfiguration setProcessPool:processPool.get()];
1199     auto handler = adoptNS([[PSONScheme alloc] init]);
1200     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"];
1201     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1202
1203     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1204     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1205     [webView setNavigationDelegate:delegate.get()];
1206
1207     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1208     [webView loadRequest:request];
1209
1210     TestWebKitAPI::Util::run(&serverRedirected);
1211     serverRedirected = false;
1212
1213     seenPIDs.add([webView _webProcessIdentifier]);
1214
1215     TestWebKitAPI::Util::run(&done);
1216     done = false;
1217
1218     seenPIDs.add([webView _webProcessIdentifier]);
1219
1220     EXPECT_FALSE(serverRedirected);
1221     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1222     EXPECT_EQ(1u, seenPIDs.size());
1223 }
1224
1225 TEST(ProcessSwap, ServerRedirect)
1226 {
1227     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1228     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1229     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1230
1231     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1232     [webViewConfiguration setProcessPool:processPool.get()];
1233     auto handler = adoptNS([[PSONScheme alloc] init]);
1234     [handler addRedirectFromURLString:@"pson://www.webkit.org/main.html" toURLString:@"pson://www.apple.com/main.html"];
1235     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1236
1237     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1238     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1239     [webView setNavigationDelegate:delegate.get()];
1240
1241     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main1.html"]];
1242     [webView loadRequest:request];
1243
1244     TestWebKitAPI::Util::run(&done);
1245     done = false;
1246
1247     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1248
1249     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1250     EXPECT_EQ(1u, seenPIDs.size());
1251     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
1252
1253     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1254     [webView loadRequest:request];
1255
1256     TestWebKitAPI::Util::run(&serverRedirected);
1257     serverRedirected = false;
1258
1259     seenPIDs.add([webView _webProcessIdentifier]);
1260
1261     TestWebKitAPI::Util::run(&done);
1262     done = false;
1263
1264     seenPIDs.add([webView _webProcessIdentifier]);
1265
1266     EXPECT_FALSE(serverRedirected);
1267     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1268     EXPECT_EQ(2u, seenPIDs.size());
1269 }
1270
1271 TEST(ProcessSwap, ServerRedirect2)
1272 {
1273     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
1274     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1275     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1276     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1277
1278     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1279     [webViewConfiguration setProcessPool:processPool.get()];
1280     auto handler1 = adoptNS([[PSONScheme alloc] init]);
1281     [handler1 addRedirectFromURLString:@"pson://www.webkit.org/main2.html" toURLString:@"pson://www.apple.com/main.html"];
1282     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
1283     auto handler2 = adoptNS([[PSONScheme alloc] init]);
1284     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
1285
1286     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1287     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1288     [webView setNavigationDelegate:delegate.get()];
1289
1290     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
1291     [webView loadRequest:request];
1292
1293     TestWebKitAPI::Util::run(&done);
1294     done = false;
1295
1296     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
1297
1298     EXPECT_FALSE(serverRedirected);
1299     EXPECT_EQ(1, numberOfDecidePolicyCalls);
1300     EXPECT_EQ(1u, seenPIDs.size());
1301     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
1302
1303     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
1304     [webView loadRequest:request];
1305
1306     TestWebKitAPI::Util::run(&serverRedirected);
1307     serverRedirected = false;
1308
1309     seenPIDs.add([webView _webProcessIdentifier]);
1310
1311     TestWebKitAPI::Util::run(&done);
1312     done = false;
1313
1314     seenPIDs.add([webView _webProcessIdentifier]);
1315
1316     EXPECT_FALSE(serverRedirected);
1317     EXPECT_EQ(3, numberOfDecidePolicyCalls);
1318     EXPECT_EQ(2u, seenPIDs.size());
1319 }
1320
1321 enum class ShouldEnablePSON { No, Yes };
1322 static void runClientSideRedirectTest(ShouldEnablePSON shouldEnablePSON)
1323 {
1324     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1325     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
1326     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1327
1328     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1329     [webViewConfiguration setProcessPool:processPool.get()];
1330     auto handler = adoptNS([[PSONScheme alloc] init]);
1331     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:linkToCrossSiteClientSideRedirectBytes];
1332     [handler addMappingFromURLString:@"pson://www.google.com/clientSideRedirect.html" toData:crossSiteClientSideRedirectBytes];
1333     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1334
1335     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1336     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1337     [webView setNavigationDelegate:delegate.get()];
1338
1339     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1340     [webView loadRequest:request];
1341
1342     TestWebKitAPI::Util::run(&done);
1343     done = false;
1344
1345     auto webkitPID = [webView _webProcessIdentifier];
1346
1347     // Navigate to the page doing a client-side redirect to apple.com.
1348     [webView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
1349
1350     TestWebKitAPI::Util::run(&done);
1351     done = false;
1352
1353     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [[webView URL] absoluteString]);
1354     auto googlePID = [webView _webProcessIdentifier];
1355     if (shouldEnablePSON == ShouldEnablePSON::Yes)
1356         EXPECT_NE(webkitPID, googlePID);
1357     else
1358         EXPECT_EQ(webkitPID, googlePID);
1359
1360     TestWebKitAPI::Util::run(&done);
1361     done = false;
1362
1363     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
1364
1365     auto applePID = [webView _webProcessIdentifier];
1366     if (shouldEnablePSON == ShouldEnablePSON::Yes) {
1367         EXPECT_NE(webkitPID, applePID);
1368         EXPECT_NE(webkitPID, googlePID);
1369     } else {
1370         EXPECT_EQ(webkitPID, applePID);
1371         EXPECT_EQ(webkitPID, googlePID);
1372     }
1373
1374     EXPECT_TRUE(willPerformClientRedirect);
1375     EXPECT_TRUE(didPerformClientRedirect);
1376     EXPECT_WK_STREQ(@"pson://www.google.com/clientSideRedirect.html", [clientRedirectSourceURL absoluteString]);
1377     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [clientRedirectDestinationURL absoluteString]);
1378
1379     willPerformClientRedirect = false;
1380     didPerformClientRedirect = false;
1381     clientRedirectSourceURL = nullptr;
1382     clientRedirectDestinationURL = nullptr;
1383
1384     // Validate Back/Forward list.
1385     auto* backForwardList = [webView backForwardList];
1386     auto* currentItem = backForwardList.currentItem;
1387     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]);
1388     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]);
1389     EXPECT_TRUE(!backForwardList.forwardItem);
1390
1391     EXPECT_EQ(1U, backForwardList.backList.count);
1392
1393     auto* backItem = backForwardList.backItem;
1394     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]);
1395     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]);
1396
1397     // Navigate back.
1398     [webView goBack];
1399     TestWebKitAPI::Util::run(&done);
1400     done = false;
1401
1402     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [[webView URL] absoluteString]);
1403     EXPECT_FALSE(willPerformClientRedirect);
1404     EXPECT_FALSE(didPerformClientRedirect);
1405
1406     auto pidAfterBackNavigation = [webView _webProcessIdentifier];
1407     if ([processPool _maximumSuspendedPageCount] > 1)
1408         EXPECT_EQ(webkitPID, pidAfterBackNavigation);
1409
1410     // Validate Back/Forward list.
1411     currentItem = backForwardList.currentItem;
1412     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.URL absoluteString]);
1413     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [currentItem.initialURL absoluteString]);
1414
1415     EXPECT_TRUE(!backForwardList.backItem);
1416     EXPECT_EQ(1U, backForwardList.forwardList.count);
1417
1418     auto* forwardItem = backForwardList.forwardItem;
1419     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.URL absoluteString]);
1420     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [forwardItem.initialURL absoluteString]);
1421
1422     // Navigate forward.
1423     [webView goForward];
1424     TestWebKitAPI::Util::run(&done);
1425     done = false;
1426
1427     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[webView URL] absoluteString]);
1428     EXPECT_FALSE(willPerformClientRedirect);
1429     EXPECT_FALSE(didPerformClientRedirect);
1430
1431     auto pidAfterForwardNavigation = [webView _webProcessIdentifier];
1432     EXPECT_EQ(applePID, pidAfterForwardNavigation);
1433
1434     // Validate Back/Forward list.
1435     currentItem = backForwardList.currentItem;
1436     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.URL absoluteString]);
1437     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [currentItem.initialURL absoluteString]);
1438     EXPECT_TRUE(!backForwardList.forwardItem);
1439
1440     EXPECT_EQ(1U, backForwardList.backList.count);
1441
1442     backItem = backForwardList.backItem;
1443     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.URL absoluteString]);
1444     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backItem.initialURL absoluteString]);
1445 }
1446
1447 TEST(ProcessSwap, CrossSiteClientSideRedirectWithoutPSON)
1448 {
1449     runClientSideRedirectTest(ShouldEnablePSON::No);
1450 }
1451
1452 TEST(ProcessSwap, CrossSiteClientSideRedirectWithPSON)
1453 {
1454     runClientSideRedirectTest(ShouldEnablePSON::Yes);
1455 }
1456
1457 static void runNavigationWithLockedHistoryTest(ShouldEnablePSON shouldEnablePSON)
1458 {
1459     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1460     processPoolConfiguration.get().processSwapsOnNavigation = shouldEnablePSON == ShouldEnablePSON::Yes ? YES : NO;
1461     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1462
1463     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1464     [webViewConfiguration setProcessPool:processPool.get()];
1465     auto handler = adoptNS([[PSONScheme alloc] init]);
1466     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:navigationWithLockedHistoryBytes];
1467     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes];
1468     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
1469
1470     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1471     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1472
1473     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1474     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1475     [webView setNavigationDelegate:delegate.get()];
1476
1477     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1478     [webView loadRequest:request];
1479
1480     TestWebKitAPI::Util::run(&done);
1481     done = false;
1482
1483     auto webkitPID = [webView _webProcessIdentifier];
1484
1485     // Page redirects to apple.com.
1486     TestWebKitAPI::Util::run(&done);
1487     done = false;
1488
1489     auto applePID = [webView _webProcessIdentifier];
1490     if (shouldEnablePSON == ShouldEnablePSON::Yes)
1491         EXPECT_NE(webkitPID, applePID);
1492     else
1493         EXPECT_EQ(webkitPID, applePID);
1494
1495     auto* backForwardList = [webView backForwardList];
1496     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
1497     EXPECT_TRUE(!backForwardList.forwardItem);
1498     EXPECT_EQ(1U, backForwardList.backList.count);
1499     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
1500
1501     receivedMessage = false;
1502     [webView goBack];
1503     TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache.
1504     receivedMessage = false;
1505     TestWebKitAPI::Util::run(&done);
1506     done = false;
1507
1508     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
1509     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]);
1510     EXPECT_TRUE(!backForwardList.backItem);
1511     EXPECT_EQ(1U, backForwardList.forwardList.count);
1512     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]);
1513
1514     [webView goForward];
1515     TestWebKitAPI::Util::run(&done);
1516     TestWebKitAPI::Util::run(&receivedMessage); // Should be restored from PageCache.
1517     receivedMessage = false;
1518     done = false;
1519
1520     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
1521
1522     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
1523     EXPECT_TRUE(!backForwardList.forwardItem);
1524     EXPECT_EQ(1U, backForwardList.backList.count);
1525     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
1526 }
1527
1528 TEST(ProcessSwap, NavigationWithLockedHistoryWithPSON)
1529 {
1530     runNavigationWithLockedHistoryTest(ShouldEnablePSON::Yes);
1531 }
1532
1533 TEST(ProcessSwap, NavigationWithLockedHistoryWithoutPSON)
1534 {
1535     runNavigationWithLockedHistoryTest(ShouldEnablePSON::No);
1536 }
1537
1538 static const char* sessionStorageTestBytes = R"PSONRESOURCE(
1539 <head>
1540 <script>
1541
1542 function log(msg)
1543 {
1544     window.webkit.messageHandlers.pson.postMessage(msg);
1545 }
1546
1547 window.onload = function(evt) {
1548     log(sessionStorage.psonKey);
1549     sessionStorage.psonKey = "I exist!";
1550 }
1551
1552 </script>
1553 </head>
1554 )PSONRESOURCE";
1555
1556 TEST(ProcessSwap, SessionStorage)
1557 {
1558     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1559     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1560     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1561
1562     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1563     [webViewConfiguration setProcessPool:processPool.get()];
1564     auto handler = adoptNS([[PSONScheme alloc] init]);
1565     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:sessionStorageTestBytes];
1566     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1567
1568     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1569     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1570
1571     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1572     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1573     [webView setNavigationDelegate:delegate.get()];
1574
1575     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1576     [webView loadRequest:request];
1577
1578     TestWebKitAPI::Util::run(&receivedMessage);
1579     receivedMessage = false;
1580     TestWebKitAPI::Util::run(&done);
1581     done = false;
1582
1583     auto webkitPID = [webView _webProcessIdentifier];
1584
1585     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1586     [webView loadRequest:request];
1587
1588     TestWebKitAPI::Util::run(&done);
1589     done = false;
1590
1591     auto applePID = [webView _webProcessIdentifier];
1592
1593     // Verify the web pages are in different processes
1594     EXPECT_NE(webkitPID, applePID);
1595
1596     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1597     [webView loadRequest:request];
1598
1599     TestWebKitAPI::Util::run(&receivedMessage);
1600     receivedMessage = false;
1601     TestWebKitAPI::Util::run(&done);
1602     done = false;
1603
1604     // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible.
1605     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
1606
1607     // Verify the sessionStorage values were as expected
1608     EXPECT_EQ([receivedMessages count], 2u);
1609     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@""]);
1610     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"I exist!"]);
1611 }
1612
1613 TEST(ProcessSwap, ReuseSuspendedProcess)
1614 {
1615     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1616     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1617     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1618
1619     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1620     [webViewConfiguration setProcessPool:processPool.get()];
1621     auto handler = adoptNS([[PSONScheme alloc] init]);
1622     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1623
1624     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1625     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1626     [webView setNavigationDelegate:delegate.get()];
1627
1628     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
1629     [webView loadRequest:request];
1630
1631     TestWebKitAPI::Util::run(&done);
1632     done = false;
1633
1634     auto webkitPID = [webView _webProcessIdentifier];
1635
1636     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main1.html"]];
1637     [webView loadRequest:request];
1638
1639     TestWebKitAPI::Util::run(&done);
1640     done = false;
1641
1642     auto applePID = [webView _webProcessIdentifier];
1643
1644     EXPECT_NE(webkitPID, applePID);
1645
1646     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
1647     [webView loadRequest:request];
1648
1649     TestWebKitAPI::Util::run(&done);
1650     done = false;
1651
1652     // We should have gone back to the webkit.org process for this load since we reuse SuspendedPages' process when possible.
1653     EXPECT_EQ(webkitPID, [webView _webProcessIdentifier]);
1654
1655     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
1656     [webView loadRequest:request];
1657
1658     TestWebKitAPI::Util::run(&done);
1659     done = false;
1660
1661     // We should have gone back to the apple.com process for this load since we reuse SuspendedPages' process when possible.
1662     EXPECT_EQ(applePID, [webView _webProcessIdentifier]);
1663 }
1664
1665 static const char* mainFramesOnlyMainFrame = R"PSONRESOURCE(
1666 <script>
1667 function loaded() {
1668     setTimeout('window.frames[0].location.href = "pson://www.apple.com/main.html"', 0);
1669 }
1670 </script>
1671 <body onload="loaded();">
1672 Some text
1673 <iframe src="pson://www.webkit.org/iframe.html"></iframe>
1674 </body>
1675 )PSONRESOURCE";
1676
1677 static const char* mainFramesOnlySubframe = R"PSONRESOURCE(
1678 Some content
1679 )PSONRESOURCE";
1680
1681
1682 static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE(
1683 <script>
1684     window.webkit.messageHandlers.pson.postMessage("Done");
1685 </script>
1686 )PSONRESOURCE";
1687
1688 TEST(ProcessSwap, MainFramesOnly)
1689 {
1690     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1691     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1692     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1693
1694     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1695     [webViewConfiguration setProcessPool:processPool.get()];
1696     auto handler = adoptNS([[PSONScheme alloc] init]);
1697     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:mainFramesOnlyMainFrame];
1698     [handler addMappingFromURLString:@"pson://www.webkit.org/iframe" toData:mainFramesOnlySubframe];
1699     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:mainFramesOnlySubframe2];
1700     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1701
1702     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1703     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1704
1705     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1706     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1707     [webView setNavigationDelegate:delegate.get()];
1708
1709     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1710     [webView loadRequest:request];
1711
1712     TestWebKitAPI::Util::run(&receivedMessage);
1713     receivedMessage = false;
1714
1715     EXPECT_EQ(1u, seenPIDs.size());
1716 }
1717
1718 TEST(ProcessSwap, SuspendedPageLimit)
1719 {
1720     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1721     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1722     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1723
1724     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1725     [webViewConfiguration setProcessPool:processPool.get()];
1726     auto handler = adoptNS([[PSONScheme alloc] init]);
1727     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1728
1729     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1730     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1731     [webView setNavigationDelegate:delegate.get()];
1732
1733     auto maximumSuspendedPageCount = [processPool _maximumSuspendedPageCount];
1734     EXPECT_GT(maximumSuspendedPageCount, 0U);
1735
1736     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1737     [webView loadRequest:request];
1738
1739     TestWebKitAPI::Util::run(&done);
1740     done = false;
1741
1742     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1743     [webView loadRequest:request];
1744
1745     TestWebKitAPI::Util::run(&done);
1746     done = false;
1747
1748     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
1749     [webView loadRequest:request];
1750
1751     TestWebKitAPI::Util::run(&done);
1752     done = false;
1753
1754     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.bing.com/main.html"]];
1755     [webView loadRequest:request];
1756
1757     TestWebKitAPI::Util::run(&done);
1758     done = false;
1759
1760     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.yahoo.com/main.html"]];
1761     [webView loadRequest:request];
1762
1763     TestWebKitAPI::Util::run(&done);
1764     done = false;
1765
1766     // Navigations to 5 different domains, we expect to have seen 5 different PIDs
1767     EXPECT_EQ(5u, seenPIDs.size());
1768
1769     // But not all of those processes should still be alive (1 visible, maximumSuspendedPageCount suspended).
1770     EXPECT_EQ([processPool _webProcessCountIgnoringPrewarmed], (1U + maximumSuspendedPageCount));
1771 }
1772
1773 TEST(ProcessSwap, PageCache1)
1774 {
1775     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1776     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1777     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1778
1779     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1780     [webViewConfiguration setProcessPool:processPool.get()];
1781     auto handler = adoptNS([[PSONScheme alloc] init]);
1782     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:pageCache1Bytes];
1783     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:pageCache1Bytes];
1784     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1785
1786     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1787     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1788
1789     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1790     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1791     [webView setNavigationDelegate:delegate.get()];
1792
1793     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1794
1795     [webView loadRequest:request];
1796     TestWebKitAPI::Util::run(&done);
1797     done = false;
1798
1799     auto pidAfterLoad1 = [webView _webProcessIdentifier];
1800
1801     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
1802
1803     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1804
1805     [webView loadRequest:request];
1806     TestWebKitAPI::Util::run(&done);
1807     done = false;
1808
1809     auto pidAfterLoad2 = [webView _webProcessIdentifier];
1810
1811     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
1812     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
1813
1814     [webView goBack];
1815     TestWebKitAPI::Util::run(&receivedMessage);
1816     receivedMessage = false;
1817     TestWebKitAPI::Util::run(&done);
1818     done = false;
1819
1820     auto pidAfterLoad3 = [webView _webProcessIdentifier];
1821
1822     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
1823     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
1824     EXPECT_EQ(1u, [receivedMessages count]);
1825     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
1826     EXPECT_EQ(2u, seenPIDs.size());
1827
1828     [webView goForward];
1829     TestWebKitAPI::Util::run(&receivedMessage);
1830     receivedMessage = false;
1831     TestWebKitAPI::Util::run(&done);
1832     done = false;
1833
1834     auto pidAfterLoad4 = [webView _webProcessIdentifier];
1835
1836     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
1837     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
1838     EXPECT_EQ(2u, [receivedMessages count]);
1839     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
1840     EXPECT_EQ(2u, seenPIDs.size());
1841 }
1842
1843 TEST(ProcessSwap, NumberOfPrewarmedProcesses)
1844 {
1845     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1846     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1847     [processPoolConfiguration setPrewarmsProcessesAutomatically:YES];
1848     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1849
1850     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1851     [webViewConfiguration setProcessPool:processPool.get()];
1852     auto handler = adoptNS([[PSONScheme alloc] init]);
1853     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1854
1855     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1856     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1857     [webView setNavigationDelegate:delegate.get()];
1858
1859     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1860     [webView loadRequest:request];
1861     TestWebKitAPI::Util::run(&done);
1862     done = false;
1863
1864     EXPECT_EQ(2u, [processPool _webProcessCount]);
1865     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
1866     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
1867
1868     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main.html"]];
1869     [webView loadRequest:request];
1870     TestWebKitAPI::Util::run(&done);
1871     done = false;
1872
1873     EXPECT_EQ(3u, [processPool _webProcessCount]);
1874     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
1875     EXPECT_TRUE([processPool _hasPrewarmedWebProcess]);
1876 }
1877
1878 static const char* visibilityBytes = R"PSONRESOURCE(
1879 <script>
1880 window.addEventListener('pageshow', function(event) {
1881     var msg = window.location.href + " - pageshow ";
1882     msg += event.persisted ? "persisted" : "NOT persisted";
1883     window.webkit.messageHandlers.pson.postMessage(msg);
1884 });
1885
1886 window.addEventListener('pagehide', function(event) {
1887     var msg = window.location.href + " - pagehide ";
1888     msg += event.persisted ? "persisted" : "NOT persisted";
1889     window.webkit.messageHandlers.pson.postMessage(msg);
1890 });
1891 </script>
1892 )PSONRESOURCE";
1893
1894 TEST(ProcessSwap, PageShowHide)
1895 {
1896     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1897     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1898     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1899
1900     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1901     [webViewConfiguration setProcessPool:processPool.get()];
1902     auto handler = adoptNS([[PSONScheme alloc] init]);
1903     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:visibilityBytes];
1904     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:visibilityBytes];
1905     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1906
1907     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1908     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1909
1910     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1911     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1912     [webView setNavigationDelegate:delegate.get()];
1913
1914     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1915
1916     [webView loadRequest:request];
1917     TestWebKitAPI::Util::run(&receivedMessage);
1918     receivedMessage = false;
1919     TestWebKitAPI::Util::run(&done);
1920     done = false;
1921
1922     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1923
1924     [webView loadRequest:request];
1925     TestWebKitAPI::Util::run(&receivedMessage);
1926     receivedMessage = false;
1927     TestWebKitAPI::Util::run(&done);
1928     done = false;
1929
1930     [webView goBack];
1931     TestWebKitAPI::Util::run(&receivedMessage);
1932     receivedMessage = false;
1933     TestWebKitAPI::Util::run(&done);
1934     done = false;
1935
1936     [webView goForward];
1937     TestWebKitAPI::Util::run(&receivedMessage);
1938     receivedMessage = false;
1939     TestWebKitAPI::Util::run(&done);
1940     done = false;
1941
1942     EXPECT_EQ(7u, [receivedMessages count]);
1943     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow NOT persisted", receivedMessages.get()[0]);
1944     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[1]);
1945     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow NOT persisted", receivedMessages.get()[2]);
1946     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pagehide persisted", receivedMessages.get()[3]);
1947     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pageshow persisted", receivedMessages.get()[4]);
1948     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - pagehide persisted", receivedMessages.get()[5]);
1949     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - pageshow persisted", receivedMessages.get()[6]);
1950 }
1951
1952 // Disabling the page cache explicitly is (for some reason) not available on iOS.
1953 #if !TARGET_OS_IPHONE
1954 static const char* loadUnloadBytes = R"PSONRESOURCE(
1955 <script>
1956 window.addEventListener('unload', function(event) {
1957     var msg = window.location.href + " - unload";
1958     window.webkit.messageHandlers.pson.postMessage(msg);
1959 });
1960
1961 window.addEventListener('load', function(event) {
1962     var msg = window.location.href + " - load";
1963     window.webkit.messageHandlers.pson.postMessage(msg);
1964 });
1965 </script>
1966 )PSONRESOURCE";
1967
1968 TEST(ProcessSwap, LoadUnload)
1969 {
1970     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1971     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1972     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1973
1974     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1975     [webViewConfiguration setProcessPool:processPool.get()];
1976     auto handler = adoptNS([[PSONScheme alloc] init]);
1977     [handler addMappingFromURLString:@"pson://www.webkit.org/main.html" toData:loadUnloadBytes];
1978     [handler addMappingFromURLString:@"pson://www.apple.com/main.html" toData:loadUnloadBytes];
1979     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1980
1981     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1982     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1983     [[webViewConfiguration preferences] _setUsesPageCache:NO];
1984
1985     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1986     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1987     [webView setNavigationDelegate:delegate.get()];
1988
1989     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
1990
1991     [webView loadRequest:request];
1992     TestWebKitAPI::Util::run(&receivedMessage);
1993     receivedMessage = false;
1994     TestWebKitAPI::Util::run(&done);
1995     done = false;
1996
1997     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
1998
1999     [webView loadRequest:request];
2000     TestWebKitAPI::Util::run(&receivedMessage);
2001     receivedMessage = false;
2002     TestWebKitAPI::Util::run(&done);
2003     done = false;
2004
2005     [webView goBack];
2006     TestWebKitAPI::Util::run(&receivedMessage);
2007     receivedMessage = false;
2008     TestWebKitAPI::Util::run(&done);
2009     done = false;
2010
2011     [webView goForward];
2012     TestWebKitAPI::Util::run(&receivedMessage);
2013     receivedMessage = false;
2014     TestWebKitAPI::Util::run(&done);
2015     done = false;
2016
2017     EXPECT_EQ(7u, [receivedMessages count]);
2018     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[0]);
2019     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[1]);
2020     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[2]);
2021     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - unload", receivedMessages.get()[3]);
2022     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - load", receivedMessages.get()[4]);
2023     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html - unload", receivedMessages.get()[5]);
2024     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html - load", receivedMessages.get()[6]);
2025 }
2026
2027 TEST(ProcessSwap, DisableForInspector)
2028 {
2029     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2030     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2031     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2032
2033     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2034     [webViewConfiguration setProcessPool:processPool.get()];
2035     webViewConfiguration.get().preferences._developerExtrasEnabled = YES;
2036
2037     auto handler = adoptNS([[PSONScheme alloc] init]);
2038     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2039
2040     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2041     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2042     [webView setNavigationDelegate:delegate.get()];
2043
2044     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2045     [webView loadRequest:request];
2046
2047     TestWebKitAPI::Util::run(&done);
2048     done = false;
2049
2050     auto pid1 = [webView _webProcessIdentifier];
2051
2052     // FIXME: use ObjC equivalent for WKInspectorRef when available.
2053     WKInspectorShow(WKPageGetInspector([webView _pageRefForTransitionToWKWebView]));
2054
2055     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
2056     [webView loadRequest:request];
2057
2058     TestWebKitAPI::Util::run(&done);
2059     done = false;
2060
2061     auto pid2 = [webView _webProcessIdentifier];
2062
2063     WKInspectorClose(WKPageGetInspector([webView _pageRefForTransitionToWKWebView]));
2064
2065     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2066     [webView loadRequest:request];
2067
2068     TestWebKitAPI::Util::run(&done);
2069     done = false;
2070
2071     auto pid3 = [webView _webProcessIdentifier];
2072
2073     EXPECT_EQ(pid1, pid2);
2074     EXPECT_FALSE(pid2 == pid3);
2075     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
2076 }
2077
2078 #endif // !TARGET_OS_IPHONE
2079
2080 static const char* sameOriginBlobNavigationTestBytes = R"PSONRESOURCE(
2081 <!DOCTYPE html>
2082 <html>
2083 <body>
2084 <p><a id="link">Click here</a></p>
2085 <script>
2086 const blob = new Blob(['<!DOCTYPE html><html><p>PASS</p></html>'], {type: 'text/html'});
2087 link.href = URL.createObjectURL(blob);
2088 </script>
2089 )PSONRESOURCE";
2090
2091 TEST(ProcessSwap, SameOriginBlobNavigation)
2092 {
2093     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2094     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2095     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2096
2097     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2098     [webViewConfiguration setProcessPool:processPool.get()];
2099     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
2100     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2101
2102     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2103     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2104     [webView setNavigationDelegate:navigationDelegate.get()];
2105     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2106     [webView setUIDelegate:uiDelegate.get()];
2107
2108     numberOfDecidePolicyCalls = 0;
2109     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2110
2111     TestWebKitAPI::Util::run(&done);
2112     done = false;
2113     auto pid1 = [webView _webProcessIdentifier];
2114     EXPECT_TRUE(!!pid1);
2115
2116     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: nil];
2117
2118     TestWebKitAPI::Util::run(&done);
2119     done = false;
2120     auto pid2 = [webView _webProcessIdentifier];
2121     EXPECT_TRUE(!!pid2);
2122     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2123     EXPECT_EQ(pid1, pid2);
2124 }
2125
2126 TEST(ProcessSwap, CrossOriginBlobNavigation)
2127 {
2128     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2129     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2130     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2131
2132     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2133     [webViewConfiguration setProcessPool:processPool.get()];
2134     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
2135     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2136
2137     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2138     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2139     [webView setNavigationDelegate:navigationDelegate.get()];
2140     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2141     [webView setUIDelegate:uiDelegate.get()];
2142
2143     numberOfDecidePolicyCalls = 0;
2144     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2145     TestWebKitAPI::Util::run(&done);
2146     done = false;
2147     auto pid1 = [webView _webProcessIdentifier];
2148     EXPECT_TRUE(!!pid1);
2149
2150     bool finishedRunningScript = false;
2151     String blobURL;
2152     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').href" completionHandler: [&] (id result, NSError *error) {
2153         blobURL = String([NSString stringWithFormat:@"%@", result]);
2154         finishedRunningScript = true;
2155     }];
2156     TestWebKitAPI::Util::run(&finishedRunningScript);
2157
2158     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]]];
2159     TestWebKitAPI::Util::run(&done);
2160     done = false;
2161     auto pid2 = [webView _webProcessIdentifier];
2162     EXPECT_TRUE(!!pid2);
2163
2164     finishedRunningScript = false;
2165     String script = "document.getElementById('link').href = '" + blobURL + "'";
2166     [webView _evaluateJavaScriptWithoutUserGesture:(NSString *)script completionHandler: [&] (id result, NSError *error) {
2167         finishedRunningScript = true;
2168     }];
2169     TestWebKitAPI::Util::run(&finishedRunningScript);
2170
2171     // This navigation will fail.
2172     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: [&] (id result, NSError *error) {
2173         done = true;
2174     }];
2175     TestWebKitAPI::Util::run(&done);
2176     done = false;
2177     auto pid3 = [webView _webProcessIdentifier];
2178     EXPECT_TRUE(!!pid3);
2179
2180     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2181     EXPECT_NE(pid1, pid2);
2182     EXPECT_EQ(pid2, pid3);
2183 }
2184
2185 TEST(ProcessSwap, NavigateToAboutBlank)
2186 {
2187     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2188     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2189     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2190
2191     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2192     [webViewConfiguration setProcessPool:processPool.get()];
2193     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
2194     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2195
2196     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2197     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2198     [webView setNavigationDelegate:navigationDelegate.get()];
2199     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2200     [webView setUIDelegate:uiDelegate.get()];
2201
2202     numberOfDecidePolicyCalls = 0;
2203     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2204     TestWebKitAPI::Util::run(&done);
2205     done = false;
2206     auto pid1 = [webView _webProcessIdentifier];
2207     EXPECT_TRUE(!!pid1);
2208
2209     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
2210     TestWebKitAPI::Util::run(&done);
2211     done = false;
2212     auto pid2 = [webView _webProcessIdentifier];
2213     EXPECT_TRUE(!!pid2);
2214
2215     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2216     EXPECT_EQ(pid1, pid2);
2217 }
2218
2219 TEST(ProcessSwap, NavigateToDataURL)
2220 {
2221     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2222     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2223     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2224
2225     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2226     [webViewConfiguration setProcessPool:processPool.get()];
2227     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
2228     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2229
2230     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2231     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2232     [webView setNavigationDelegate:navigationDelegate.get()];
2233     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2234     [webView setUIDelegate:uiDelegate.get()];
2235
2236     numberOfDecidePolicyCalls = 0;
2237     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2238     TestWebKitAPI::Util::run(&done);
2239     done = false;
2240     auto pid1 = [webView _webProcessIdentifier];
2241     EXPECT_TRUE(!!pid1);
2242
2243     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"data:text/plain,PASS"]]];
2244     TestWebKitAPI::Util::run(&done);
2245     done = false;
2246     auto pid2 = [webView _webProcessIdentifier];
2247     EXPECT_TRUE(!!pid2);
2248
2249     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2250     EXPECT_EQ(pid1, pid2);
2251 }
2252
2253 TEST(ProcessSwap, ProcessReuse)
2254 {
2255     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2256     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
2257     [processPoolConfiguration setAlwaysKeepAndReuseSwappedProcesses:YES];
2258     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2259
2260     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2261     [webViewConfiguration setProcessPool:processPool.get()];
2262     auto handler = adoptNS([[PSONScheme alloc] init]);
2263     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2264
2265     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2266     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2267     [webView setNavigationDelegate:delegate.get()];
2268
2269     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2270     [webView loadRequest:request];
2271
2272     TestWebKitAPI::Util::run(&done);
2273     done = false;
2274
2275     auto pid1 = [webView _webProcessIdentifier];
2276
2277     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2278     [webView loadRequest:request];
2279
2280     TestWebKitAPI::Util::run(&done);
2281     done = false;
2282
2283     auto pid2 = [webView _webProcessIdentifier];
2284
2285     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main2.html"]];
2286     [webView loadRequest:request];
2287
2288     TestWebKitAPI::Util::run(&done);
2289     done = false;
2290
2291     auto pid3 = [webView _webProcessIdentifier];
2292
2293     // Two process swaps have occurred, but we should only have ever seen 2 pids.
2294     EXPECT_EQ(2u, seenPIDs.size());
2295     EXPECT_NE(pid1, pid2);
2296     EXPECT_NE(pid2, pid3);
2297     EXPECT_EQ(pid1, pid3);
2298 }
2299
2300 TEST(ProcessSwap, ProcessReuseeTLDPlus2)
2301 {
2302     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2303     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
2304     [processPoolConfiguration setAlwaysKeepAndReuseSwappedProcesses:YES];
2305     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2306
2307     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2308     [webViewConfiguration setProcessPool:processPool.get()];
2309     auto handler = adoptNS([[PSONScheme alloc] init]);
2310     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2311
2312     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2313     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2314     [webView setNavigationDelegate:delegate.get()];
2315
2316     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www1.webkit.org/main1.html"]];
2317     [webView loadRequest:request];
2318
2319     TestWebKitAPI::Util::run(&done);
2320     done = false;
2321
2322     auto pid1 = [webView _webProcessIdentifier];
2323
2324     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2325     [webView loadRequest:request];
2326
2327     TestWebKitAPI::Util::run(&done);
2328     done = false;
2329
2330     auto pid2 = [webView _webProcessIdentifier];
2331
2332     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www2.webkit.org/main2.html"]];
2333     [webView loadRequest:request];
2334
2335     TestWebKitAPI::Util::run(&done);
2336     done = false;
2337
2338     auto pid3 = [webView _webProcessIdentifier];
2339
2340     // Two process swaps have occurred, but we should only have ever seen 2 pids.
2341     EXPECT_EQ(2u, seenPIDs.size());
2342     EXPECT_NE(pid1, pid2);
2343     EXPECT_NE(pid2, pid3);
2344     EXPECT_EQ(pid1, pid3);
2345 }
2346
2347 static const char* navigateToInvalidURLTestBytes = R"PSONRESOURCE(
2348 <!DOCTYPE html>
2349 <html>
2350 <body onload="setTimeout(() => alert('DONE'), 0); location.href = 'http://A=a%B=b'">
2351 )PSONRESOURCE";
2352
2353 TEST(ProcessSwap, NavigateToInvalidURL)
2354 {
2355     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2356     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2357     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2358
2359     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2360     [webViewConfiguration setProcessPool:processPool.get()];
2361     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToInvalidURLTestBytes]);
2362     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2363
2364     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2365     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2366     [webView setNavigationDelegate:navigationDelegate.get()];
2367     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2368     [webView setUIDelegate:uiDelegate.get()];
2369
2370     numberOfDecidePolicyCalls = 0;
2371     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2372     TestWebKitAPI::Util::run(&done);
2373     done = false;
2374     auto pid1 = [webView _webProcessIdentifier];
2375     EXPECT_TRUE(!!pid1);
2376
2377     TestWebKitAPI::Util::run(&didReceiveAlert);
2378     didReceiveAlert = false;
2379     auto pid2 = [webView _webProcessIdentifier];
2380     EXPECT_TRUE(!!pid2);
2381
2382     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2383     EXPECT_EQ(pid1, pid2);
2384 }
2385
2386 static const char* navigateToDataURLThenBackBytes = R"PSONRESOURCE(
2387 <script>
2388 onpageshow = function(event) {
2389     // Location changes need to happen outside the onload handler to generate history entries.
2390     setTimeout(function() {
2391       window.location.href = "data:text/html,<body onload='history.back()'></body>";
2392     }, 0);
2393 }
2394
2395 </script>
2396 )PSONRESOURCE";
2397
2398 TEST(ProcessSwap, NavigateToDataURLThenBack)
2399 {
2400     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2401     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2402     processPoolConfiguration.get().pageCacheEnabled = NO;
2403     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2404
2405     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2406     [webViewConfiguration setProcessPool:processPool.get()];
2407     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:navigateToDataURLThenBackBytes]);
2408     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2409
2410     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2411     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2412     [webView setNavigationDelegate:navigationDelegate.get()];
2413
2414     numberOfDecidePolicyCalls = 0;
2415     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]]];
2416     TestWebKitAPI::Util::run(&done);
2417     done = false;
2418     auto pid1 = [webView _webProcessIdentifier];
2419
2420     TestWebKitAPI::Util::run(&done);
2421     done = false;
2422     auto pid2 = [webView _webProcessIdentifier];
2423
2424     TestWebKitAPI::Util::run(&done);
2425     done = false;
2426     auto pid3 = [webView _webProcessIdentifier];
2427
2428     EXPECT_EQ(3, numberOfDecidePolicyCalls);
2429     EXPECT_EQ(1u, seenPIDs.size());
2430     EXPECT_EQ(pid1, pid2);
2431     EXPECT_EQ(pid2, pid3);
2432 }
2433
2434 TEST(ProcessSwap, APIControlledProcessSwapping)
2435 {
2436     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2437     auto handler = adoptNS([[PSONScheme alloc] initWithBytes:"Hello World!"]);
2438     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2439
2440     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2441     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2442     [webView setNavigationDelegate:navigationDelegate.get()];
2443
2444     numberOfDecidePolicyCalls = 0;
2445     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/1"]]];
2446     TestWebKitAPI::Util::run(&done);
2447     done = false;
2448     auto pid1 = [webView _webProcessIdentifier];
2449
2450     // Navigating from the above URL to this URL normally should not process swap.
2451     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/2"]]];
2452     TestWebKitAPI::Util::run(&done);
2453     done = false;
2454     auto pid2 = [webView _webProcessIdentifier];
2455
2456     EXPECT_EQ(1u, seenPIDs.size());
2457     EXPECT_EQ(pid1, pid2);
2458
2459     // Navigating from the above URL to this URL normally should not process swap,
2460     // but we'll explicitly ask for a swap.
2461     navigationDelegate->decidePolicyForNavigationAction = ^(WKNavigationAction *, void (^decisionHandler)(WKNavigationActionPolicy)) {
2462         decisionHandler(_WKNavigationActionPolicyAllowInNewProcess);
2463     };
2464     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webit.org/3"]]];
2465     TestWebKitAPI::Util::run(&done);
2466     done = false;
2467     auto pid3 = [webView _webProcessIdentifier];
2468
2469     EXPECT_EQ(3, numberOfDecidePolicyCalls);
2470     EXPECT_EQ(2u, seenPIDs.size());
2471     EXPECT_NE(pid1, pid3);
2472 }
2473
2474 enum class ExpectSwap { No, Yes };
2475 static void runProcessSwapDueToRelatedWebViewTest(NSURL* relatedViewURL, NSURL* targetURL, ExpectSwap expectSwap)
2476 {
2477     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2478     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2479     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
2480     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2481
2482     auto webView1Configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
2483     [webView1Configuration setProcessPool:processPool.get()];
2484     auto handler = adoptNS([[PSONScheme alloc] init]);
2485     [webView1Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2486
2487     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView1Configuration.get()]);
2488     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2489     [webView1 setNavigationDelegate:delegate.get()];
2490
2491     numberOfDecidePolicyCalls = 0;
2492     NSURLRequest *request = [NSURLRequest requestWithURL:relatedViewURL];
2493     [webView1 loadRequest:request];
2494
2495     TestWebKitAPI::Util::run(&done);
2496     done = false;
2497
2498     auto pid1 = [webView1 _webProcessIdentifier];
2499
2500     auto webView2Configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
2501     [webView2Configuration setProcessPool:processPool.get()];
2502     [webView2Configuration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2503     webView2Configuration.get()._relatedWebView = webView1.get(); // webView2 will be related to webView1 and webView1's URL will be used for process swap decision.
2504     auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webView2Configuration.get()]);
2505     [webView2 setNavigationDelegate:delegate.get()];
2506
2507     request = [NSURLRequest requestWithURL:targetURL];
2508     [webView2 loadRequest:request];
2509
2510     TestWebKitAPI::Util::run(&done);
2511     done = false;
2512
2513     auto pid2 = [webView2 _webProcessIdentifier];
2514
2515     if (expectSwap == ExpectSwap::No)
2516         EXPECT_TRUE(pid1 == pid2);
2517     else
2518         EXPECT_FALSE(pid1 == pid2);
2519
2520     EXPECT_EQ(2, numberOfDecidePolicyCalls);
2521 }
2522
2523 TEST(ProcessSwap, ProcessSwapDueToRelatedView)
2524 {
2525     runProcessSwapDueToRelatedWebViewTest([NSURL URLWithString:@"pson://www.webkit.org/main1.html"], [NSURL URLWithString:@"pson://www.apple.com/main2.html"], ExpectSwap::Yes);
2526 }
2527
2528 TEST(ProcessSwap, NoProcessSwapDueToRelatedView)
2529 {
2530     runProcessSwapDueToRelatedWebViewTest([NSURL URLWithString:@"pson://www.webkit.org/main1.html"], [NSURL URLWithString:@"pson://www.webkit.org/main2.html"], ExpectSwap::No);
2531 }
2532
2533 TEST(ProcessSwap, TerminatedSuspendedPageProcess)
2534 {
2535     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2536     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2537     processPoolConfiguration.get().prewarmsProcessesAutomatically = YES;
2538     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2539
2540     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2541     [webViewConfiguration setProcessPool:processPool.get()];
2542     auto handler = adoptNS([[PSONScheme alloc] init]);
2543     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2544
2545     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2546     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2547     [webView setNavigationDelegate:delegate.get()];
2548
2549     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2550     [webView loadRequest:request];
2551
2552     TestWebKitAPI::Util::run(&done);
2553     done = false;
2554
2555     auto pid1 = [webView _webProcessIdentifier];
2556
2557     @autoreleasepool {
2558         auto webViewConfiguration2 = adoptNS([[WKWebViewConfiguration alloc] init]);
2559         [webViewConfiguration2 setProcessPool:processPool.get()];
2560         [webViewConfiguration2 _setRelatedWebView:webView.get()]; // Make sure it uses the same process.
2561         auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration2.get()]);
2562         [webView2 setNavigationDelegate:delegate.get()];
2563
2564         request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]];
2565         [webView2 loadRequest:request];
2566
2567         TestWebKitAPI::Util::run(&done);
2568         done = false;
2569
2570         auto pid2 = [webView2 _webProcessIdentifier];
2571         EXPECT_EQ(pid1, pid2);
2572
2573         request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.google.com/main2.html"]];
2574         [webView loadRequest:request];
2575
2576         TestWebKitAPI::Util::run(&done);
2577         done = false;
2578
2579         [webView2 _killWebContentProcessAndResetState];
2580         webView2 = nullptr;
2581         webViewConfiguration2 = nullptr;
2582     }
2583
2584     auto pid3 = [webView _webProcessIdentifier];
2585     EXPECT_NE(pid1, pid3);
2586
2587     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main2.html"]];
2588     [webView loadRequest:request];
2589
2590     TestWebKitAPI::Util::run(&done);
2591     done = false;
2592
2593     auto pid4 = [webView _webProcessIdentifier];
2594     EXPECT_NE(pid1, pid4);
2595     EXPECT_NE(pid3, pid4);
2596 }
2597
2598 TEST(ProcessSwap, NavigateBackAndForth)
2599 {
2600     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2601     processPoolConfiguration.get().processSwapsOnNavigation = YES;
2602     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2603
2604     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2605     [webViewConfiguration setProcessPool:processPool.get()];
2606     auto handler = adoptNS([[PSONScheme alloc] init]);
2607     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
2608
2609     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2610     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2611     [webView setNavigationDelegate:delegate.get()];
2612
2613     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main.html"]];
2614     [webView loadRequest:request];
2615
2616     TestWebKitAPI::Util::run(&done);
2617     done = false;
2618
2619     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.apple.com/main.html"]];
2620     [webView loadRequest:request];
2621
2622     TestWebKitAPI::Util::run(&done);
2623     done = false;
2624
2625     auto* backForwardList = [webView backForwardList];
2626     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
2627     EXPECT_TRUE(!backForwardList.forwardItem);
2628     EXPECT_EQ(1U, backForwardList.backList.count);
2629     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
2630
2631     [webView goBack];
2632     TestWebKitAPI::Util::run(&done);
2633     done = false;
2634
2635     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.currentItem.URL absoluteString]);
2636     EXPECT_TRUE(!backForwardList.backItem);
2637     EXPECT_EQ(1U, backForwardList.forwardList.count);
2638     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.forwardItem.URL absoluteString]);
2639
2640     [webView goForward];
2641     TestWebKitAPI::Util::run(&done);
2642     done = false;
2643
2644     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [backForwardList.currentItem.URL absoluteString]);
2645     EXPECT_TRUE(!backForwardList.forwardItem);
2646     EXPECT_EQ(1U, backForwardList.backList.count);
2647     EXPECT_WK_STREQ(@"pson://www.webkit.org/main.html", [backForwardList.backItem.URL absoluteString]);
2648 }
2649
2650 #if PLATFORM(MAC)
2651
2652 TEST(ProcessSwap, GoBackToSuspendedPageWithMainFrameIDThatIsNotOne)
2653 {
2654     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
2655     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
2656     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
2657
2658     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
2659     [webViewConfiguration setProcessPool:processPool.get()];
2660     auto handler = adoptNS([[PSONScheme alloc] init]);
2661     [handler addMappingFromURLString:@"pson://www.webkit.org/main1.html" toData:targetBlankSameSiteNoOpenerTestBytes];
2662     [handler addMappingFromURLString:@"pson://www.webkit.org/main2.html" toData:linkToAppleTestBytes];
2663     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
2664
2665     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
2666     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
2667
2668     auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
2669     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
2670     [webView1 setNavigationDelegate:navigationDelegate.get()];
2671     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
2672     [webView1 setUIDelegate:uiDelegate.get()];
2673
2674     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html"]];
2675
2676     [webView1 loadRequest:request];
2677     TestWebKitAPI::Util::run(&done);
2678     done = false;
2679
2680     EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html", [[webView1 URL] absoluteString]);
2681     auto pid1 = [webView1 _webProcessIdentifier];
2682
2683     TestWebKitAPI::Util::run(&didCreateWebView);
2684     didCreateWebView = false;
2685
2686     TestWebKitAPI::Util::run(&done);
2687     done = false;
2688
2689     // New WKWebView has now navigated to webkit.org.
2690     EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]);
2691     auto pid2 = [createdWebView _webProcessIdentifier];
2692     EXPECT_EQ(pid1, pid2);
2693
2694     // Click link in new WKWebView so that it navigates cross-site to apple.com.
2695     [createdWebView evaluateJavaScript:@"testLink.click()" completionHandler:nil];
2696     TestWebKitAPI::Util::run(&done);
2697     done = false;
2698
2699     // New WKWebView has now navigated to apple.com.
2700     EXPECT_WK_STREQ(@"pson://www.apple.com/main.html", [[createdWebView URL] absoluteString]);
2701     auto pid3 = [createdWebView _webProcessIdentifier];
2702     EXPECT_NE(pid1, pid3); // Should have process-swapped.
2703
2704     // Navigate back to the suspended page (should use the page cache).
2705     [createdWebView goBack];
2706     TestWebKitAPI::Util::run(&receivedMessage);
2707     receivedMessage = false;
2708
2709     EXPECT_WK_STREQ(@"pson://www.webkit.org/main2.html", [[createdWebView URL] absoluteString]);
2710     auto pid4 = [createdWebView _webProcessIdentifier];
2711     EXPECT_EQ(pid1, pid4); // Should have process-swapped to the original "suspended" process.
2712
2713     // Do a fragment navigation in the original WKWebView and make sure this does not crash.
2714     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://www.webkit.org/main1.html#testLink"]];
2715     [webView1 loadRequest:request];
2716     TestWebKitAPI::Util::run(&done);
2717     done = false;
2718
2719     EXPECT_WK_STREQ(@"pson://www.webkit.org/main1.html#testLink", [[webView1 URL] absoluteString]);
2720     auto pid5 = [createdWebView _webProcessIdentifier];
2721     EXPECT_EQ(pid1, pid5);
2722 }
2723
2724 #endif // PLATFORM(MAC)
2725
2726 #endif // WK_API_ENABLED