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