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