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