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