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