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