PSON: Don't create a new process when navigating to a blob URL, data URL, and about...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / ProcessSwapOnNavigation.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "Test.h"
30 #import <WebKit/WKNavigationDelegate.h>
31 #import <WebKit/WKNavigationPrivate.h>
32 #import <WebKit/WKPreferencesPrivate.h>
33 #import <WebKit/WKProcessPoolPrivate.h>
34 #import <WebKit/WKUIDelegatePrivate.h>
35 #import <WebKit/WKURLSchemeHandler.h>
36 #import <WebKit/WKURLSchemeTaskPrivate.h>
37 #import <WebKit/WKWebViewConfigurationPrivate.h>
38 #import <WebKit/WKWebViewPrivate.h>
39 #import <WebKit/WKWebsiteDataStorePrivate.h>
40 #import <WebKit/WKWebsiteDataStoreRef.h>
41 #import <WebKit/WebKit.h>
42 #import <WebKit/_WKExperimentalFeature.h>
43 #import <WebKit/_WKProcessPoolConfiguration.h>
44 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
45 #import <WebKit/_WKWebsitePolicies.h>
46 #import <wtf/Deque.h>
47 #import <wtf/HashMap.h>
48 #import <wtf/HashSet.h>
49 #import <wtf/RetainPtr.h>
50 #import <wtf/Vector.h>
51 #import <wtf/text/StringHash.h>
52 #import <wtf/text/WTFString.h>
53
54 #if WK_API_ENABLED
55
56 static bool done;
57 static bool didCreateWebView;
58 static int numberOfDecidePolicyCalls;
59
60 static RetainPtr<NSMutableArray> receivedMessages = adoptNS([@[] mutableCopy]);
61 static bool receivedMessage;
62 static bool serverRedirected;
63 static HashSet<pid_t> seenPIDs;
64 @interface PSONMessageHandler : NSObject <WKScriptMessageHandler>
65 @end
66
67 @implementation PSONMessageHandler
68 - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message
69 {
70     if ([message body])
71         [receivedMessages addObject:[message body]];
72     else
73         [receivedMessages addObject:@""];
74
75     receivedMessage = true;
76     if ([message.webView _webProcessIdentifier])
77         seenPIDs.add([message.webView _webProcessIdentifier]);
78 }
79 @end
80
81 @interface PSONNavigationDelegate : NSObject <WKNavigationDelegate>
82 @end
83
84 @implementation PSONNavigationDelegate
85
86 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
87 {
88     seenPIDs.add([webView _webProcessIdentifier]);
89     done = true;
90 }
91
92 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
93 {
94     ++numberOfDecidePolicyCalls;
95     seenPIDs.add([webView _webProcessIdentifier]);
96     decisionHandler(WKNavigationActionPolicyAllow);
97 }
98
99 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
100 {
101     seenPIDs.add([webView _webProcessIdentifier]);
102     serverRedirected = true;
103 }
104
105 @end
106
107 static RetainPtr<WKWebView> createdWebView;
108
109 @interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
110 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
111 @end
112
113 @implementation PSONUIDelegate {
114     RetainPtr<PSONNavigationDelegate> _navigationDelegate;
115 }
116
117 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
118 {
119     if (!(self = [super init]))
120         return nil;
121
122     _navigationDelegate = navigationDelegate;
123     return self;
124 }
125
126 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
127 {
128     createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
129     [createdWebView setNavigationDelegate:_navigationDelegate.get()];
130     didCreateWebView = true;
131     return createdWebView.get();
132 }
133
134 @end
135
136 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
137     const char* _bytes;
138     HashMap<String, String> _redirects;
139     HashMap<String, RetainPtr<NSData *>> _dataMappings;
140 }
141 - (instancetype)initWithBytes:(const char*)bytes;
142 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
143 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data;
144 @end
145
146 @implementation PSONScheme
147
148 - (instancetype)initWithBytes:(const char*)bytes
149 {
150     self = [super init];
151     _bytes = bytes;
152     return self;
153 }
154
155 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
156 {
157     _redirects.set(sourceURLString, destinationURLString);
158 }
159
160 - (void)addMappingFromURLString:(NSString *)urlString toData:(const char*)data
161 {
162     _dataMappings.set(urlString, [NSData dataWithBytesNoCopy:(void*)data length:strlen(data) freeWhenDone:NO]);
163 }
164
165 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
166 {
167     NSURL *finalURL = task.request.URL;
168     auto target = _redirects.get(task.request.URL.absoluteString);
169     if (!target.isEmpty()) {
170         auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
171
172         finalURL = [NSURL URLWithString:(NSString *)target];
173         auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
174
175         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
176     }
177
178     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
179     [task didReceiveResponse:response.get()];
180
181     if (auto data = _dataMappings.get([finalURL absoluteString]))
182         [task didReceiveData:data.get()];
183     else if (_bytes) {
184         RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]);
185         [task didReceiveData:data.get()];
186     } else
187         [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
188
189     [task didFinish];
190 }
191
192 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
193 {
194 }
195
196 @end
197
198 static const char* testBytes = R"PSONRESOURCE(
199 <head>
200 <script>
201
202 function log(msg)
203 {
204     window.webkit.messageHandlers.pson.postMessage(msg);
205 }
206
207 window.onload = function(evt) {
208     if (window.history.state != "onloadCalled")
209         setTimeout('window.history.replaceState("onloadCalled", "");', 0);
210 }
211
212 window.onpageshow = function(evt) {
213     log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state);
214 }
215
216 </script>
217 </head>
218 )PSONRESOURCE";
219
220 #if PLATFORM(MAC)
221
222 static const char* windowOpenCrossOriginNoOpenerTestBytes = R"PSONRESOURCE(
223 <script>
224 window.onload = function() {
225     window.open("pson2://host/main2.html", "_blank", "noopener");
226 }
227 </script>
228 )PSONRESOURCE";
229
230 static const char* windowOpenCrossOriginWithOpenerTestBytes = R"PSONRESOURCE(
231 <script>
232 window.onload = function() {
233     window.open("pson2://host/main2.html");
234 }
235 </script>
236 )PSONRESOURCE";
237
238 static const char* windowOpenSameOriginNoOpenerTestBytes = R"PSONRESOURCE(
239 <script>
240 window.onload = function() {
241     if (!opener)
242         window.open("pson1://host/main2.html", "_blank", "noopener");
243 }
244 </script>
245 )PSONRESOURCE";
246
247 static const char* dummyBytes = R"PSONRESOURCE(
248 <body>TEST</body>
249 )PSONRESOURCE";
250
251 #endif // PLATFORM(MAC)
252
253 TEST(ProcessSwap, Basic)
254 {
255     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
256     processPoolConfiguration.get().processSwapsOnNavigation = YES;
257     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
258
259     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
260     [webViewConfiguration setProcessPool:processPool.get()];
261     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
262     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
263     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
264
265     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
266     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
267     [webView setNavigationDelegate:delegate.get()];
268
269     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
270     [webView loadRequest:request];
271
272     TestWebKitAPI::Util::run(&done);
273     done = false;
274
275     auto pid1 = [webView _webProcessIdentifier];
276
277     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main2.html"]];
278     [webView loadRequest:request];
279
280     TestWebKitAPI::Util::run(&done);
281     done = false;
282
283     auto pid2 = [webView _webProcessIdentifier];
284
285     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
286     [webView loadRequest:request];
287
288     TestWebKitAPI::Util::run(&done);
289     done = false;
290
291     auto pid3 = [webView _webProcessIdentifier];
292
293     EXPECT_EQ(pid1, pid2);
294     EXPECT_FALSE(pid2 == pid3);
295
296     // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
297     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
298 }
299
300 TEST(ProcessSwap, Back)
301 {
302     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
303     processPoolConfiguration.get().processSwapsOnNavigation = YES;
304     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
305
306     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
307     [webViewConfiguration setProcessPool:processPool.get()];
308     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:testBytes]);
309     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
310     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
311     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
312
313     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
314     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
315
316     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
317     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
318     [webView setNavigationDelegate:delegate.get()];
319
320     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
321     [webView loadRequest:request];
322
323     TestWebKitAPI::Util::run(&receivedMessage);
324     receivedMessage = false;
325     TestWebKitAPI::Util::run(&done);
326     done = false;
327
328     auto pid1 = [webView _webProcessIdentifier];
329
330     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
331     [webView loadRequest:request];
332
333     TestWebKitAPI::Util::run(&done);
334     done = false;
335
336     auto pid2 = [webView _webProcessIdentifier];
337
338     [webView goBack];
339
340     TestWebKitAPI::Util::run(&receivedMessage);
341     receivedMessage = false;
342     TestWebKitAPI::Util::run(&done);
343     done = false;
344
345     auto pid3 = [webView _webProcessIdentifier];
346
347     // 3 loads, 3 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
348     // additional decidePolicy call as a result of the process swap)
349     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
350
351     EXPECT_EQ([receivedMessages count], 2u);
352     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"PageShow called. Persisted: false, and window.history.state is: null"]);
353     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"PageShow called. Persisted: true, and window.history.state is: onloadCalled"]);
354
355     EXPECT_EQ(2u, seenPIDs.size());
356
357     EXPECT_FALSE(pid1 == pid2);
358     EXPECT_FALSE(pid2 == pid3);
359     EXPECT_TRUE(pid1 == pid3);
360 }
361
362 #if PLATFORM(MAC)
363
364 TEST(ProcessSwap, CrossOriginWindowOpenNoOpener)
365 {
366     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
367     processPoolConfiguration.get().processSwapsOnNavigation = YES;
368     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
369
370     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
371     [webViewConfiguration setProcessPool:processPool.get()];
372     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginNoOpenerTestBytes]);
373     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
374     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
375     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
376
377     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
378     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
379     [webView setNavigationDelegate:navigationDelegate.get()];
380     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
381     [webView setUIDelegate:uiDelegate.get()];
382
383     numberOfDecidePolicyCalls = 0;
384     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
385     [webView loadRequest:request];
386
387     TestWebKitAPI::Util::run(&done);
388     done = false;
389
390     TestWebKitAPI::Util::run(&didCreateWebView);
391     didCreateWebView = false;
392
393     TestWebKitAPI::Util::run(&done);
394
395     EXPECT_EQ(2, numberOfDecidePolicyCalls);
396
397     auto pid1 = [webView _webProcessIdentifier];
398     EXPECT_TRUE(!!pid1);
399     auto pid2 = [createdWebView _webProcessIdentifier];
400     EXPECT_TRUE(!!pid2);
401
402     EXPECT_NE(pid1, pid2);
403 }
404
405 TEST(ProcessSwap, CrossOriginWindowOpenWithOpener)
406 {
407     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
408     processPoolConfiguration.get().processSwapsOnNavigation = YES;
409     processPoolConfiguration.get().processSwapsOnWindowOpenWithOpener = YES;
410     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
411
412     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
413     [webViewConfiguration setProcessPool:processPool.get()];
414     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginWithOpenerTestBytes]);
415     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
416     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
417     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
418
419     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
420     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
421     [webView setNavigationDelegate:navigationDelegate.get()];
422     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
423     [webView setUIDelegate:uiDelegate.get()];
424
425     numberOfDecidePolicyCalls = 0;
426     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
427     [webView loadRequest:request];
428
429     TestWebKitAPI::Util::run(&done);
430     done = false;
431
432     TestWebKitAPI::Util::run(&didCreateWebView);
433     didCreateWebView = false;
434
435     TestWebKitAPI::Util::run(&done);
436
437     EXPECT_EQ(2, numberOfDecidePolicyCalls);
438
439     auto pid1 = [webView _webProcessIdentifier];
440     EXPECT_TRUE(!!pid1);
441     auto pid2 = [createdWebView _webProcessIdentifier];
442     EXPECT_TRUE(!!pid2);
443
444     EXPECT_NE(pid1, pid2);
445 }
446
447 TEST(ProcessSwap, SameOriginWindowOpenNoOpener)
448 {
449     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
450     processPoolConfiguration.get().processSwapsOnNavigation = YES;
451     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
452
453     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
454     [webViewConfiguration setProcessPool:processPool.get()];
455     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenSameOriginNoOpenerTestBytes]);
456     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
457
458     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
459     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
460     [webView setNavigationDelegate:navigationDelegate.get()];
461     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
462     [webView setUIDelegate:uiDelegate.get()];
463
464     numberOfDecidePolicyCalls = 0;
465     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
466     [webView loadRequest:request];
467
468     TestWebKitAPI::Util::run(&done);
469     done = false;
470
471     TestWebKitAPI::Util::run(&didCreateWebView);
472     didCreateWebView = false;
473
474     TestWebKitAPI::Util::run(&done);
475
476     EXPECT_EQ(2, numberOfDecidePolicyCalls);
477
478     auto pid1 = [webView _webProcessIdentifier];
479     EXPECT_TRUE(!!pid1);
480     auto pid2 = [createdWebView _webProcessIdentifier];
481     EXPECT_TRUE(!!pid2);
482
483     EXPECT_EQ(pid1, pid2);
484 }
485
486 #endif // PLATFORM(MAC)
487
488 TEST(ProcessSwap, ServerRedirectFromNewWebView)
489 {
490     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
491     processPoolConfiguration.get().processSwapsOnNavigation = YES;
492     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
493
494     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
495     [webViewConfiguration setProcessPool:processPool.get()];
496     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
497     [handler addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
498     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
499
500     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
501     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
502     [webView setNavigationDelegate:delegate.get()];
503
504     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
505     [webView loadRequest:request];
506
507     TestWebKitAPI::Util::run(&serverRedirected);
508     serverRedirected = false;
509
510     seenPIDs.add([webView _webProcessIdentifier]);
511
512     TestWebKitAPI::Util::run(&done);
513     done = false;
514
515     seenPIDs.add([webView _webProcessIdentifier]);
516
517     EXPECT_FALSE(serverRedirected);
518     EXPECT_EQ(2, numberOfDecidePolicyCalls);
519     EXPECT_EQ(1u, seenPIDs.size());
520 }
521
522 TEST(ProcessSwap, ServerRedirect)
523 {
524     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
525     processPoolConfiguration.get().processSwapsOnNavigation = YES;
526     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
527
528     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
529     [webViewConfiguration setProcessPool:processPool.get()];
530     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
531     [handler1 addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
532     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
533     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
534     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"originalload"];
535
536     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
537     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
538     [webView setNavigationDelegate:delegate.get()];
539
540     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"originalload://host/main1.html"]];
541     [webView loadRequest:request];
542
543     TestWebKitAPI::Util::run(&done);
544     done = false;
545
546     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
547
548     EXPECT_EQ(1, numberOfDecidePolicyCalls);
549     EXPECT_EQ(1u, seenPIDs.size());
550     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
551
552     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
553     [webView loadRequest:request];
554
555     TestWebKitAPI::Util::run(&serverRedirected);
556     serverRedirected = false;
557
558     seenPIDs.add([webView _webProcessIdentifier]);
559
560     TestWebKitAPI::Util::run(&done);
561     done = false;
562
563     seenPIDs.add([webView _webProcessIdentifier]);
564
565     EXPECT_FALSE(serverRedirected);
566     EXPECT_EQ(3, numberOfDecidePolicyCalls);
567     EXPECT_EQ(2u, seenPIDs.size());
568 }
569
570 TEST(ProcessSwap, ServerRedirect2)
571 {
572     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
573     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
574     processPoolConfiguration.get().processSwapsOnNavigation = YES;
575     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
576
577     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
578     [webViewConfiguration setProcessPool:processPool.get()];
579     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
580     [handler1 addRedirectFromURLString:@"pson://host/main2.html" toURLString:@"psonredirected://host/main1.html"];
581     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
582     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
583     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
584
585     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
586     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
587     [webView setNavigationDelegate:delegate.get()];
588
589     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
590     [webView loadRequest:request];
591
592     TestWebKitAPI::Util::run(&done);
593     done = false;
594
595     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
596
597     EXPECT_FALSE(serverRedirected);
598     EXPECT_EQ(1, numberOfDecidePolicyCalls);
599     EXPECT_EQ(1u, seenPIDs.size());
600     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
601
602     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main2.html"]];
603     [webView loadRequest:request];
604
605     TestWebKitAPI::Util::run(&serverRedirected);
606     serverRedirected = false;
607
608     seenPIDs.add([webView _webProcessIdentifier]);
609
610     TestWebKitAPI::Util::run(&done);
611     done = false;
612
613     seenPIDs.add([webView _webProcessIdentifier]);
614
615     EXPECT_FALSE(serverRedirected);
616     EXPECT_EQ(3, numberOfDecidePolicyCalls);
617     EXPECT_EQ(2u, seenPIDs.size());
618 }
619
620 static const char* sessionStorageTestBytes = R"PSONRESOURCE(
621 <head>
622 <script>
623
624 function log(msg)
625 {
626     window.webkit.messageHandlers.pson.postMessage(msg);
627 }
628
629 window.onload = function(evt) {
630     log(sessionStorage.psonKey);
631     sessionStorage.psonKey = "I exist!";
632 }
633
634 </script>
635 </head>
636 )PSONRESOURCE";
637
638 TEST(ProcessSwap, SessionStorage)
639 {
640     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
641     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
642     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
643
644     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
645     [webViewConfiguration setProcessPool:processPool.get()];
646     auto handler1 = adoptNS([[PSONScheme alloc] initWithBytes:sessionStorageTestBytes]);
647     auto handler2 = adoptNS([[PSONScheme alloc] init]);
648     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
649     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
650
651     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
652     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
653
654     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
655     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
656     [webView setNavigationDelegate:delegate.get()];
657
658     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
659     [webView loadRequest:request];
660
661     TestWebKitAPI::Util::run(&receivedMessage);
662     receivedMessage = false;
663     TestWebKitAPI::Util::run(&done);
664     done = false;
665
666     auto pid1 = [webView _webProcessIdentifier];
667
668     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
669     [webView loadRequest:request];
670
671     TestWebKitAPI::Util::run(&done);
672     done = false;
673
674     auto pid2 = [webView _webProcessIdentifier];
675
676     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
677     [webView loadRequest:request];
678
679     TestWebKitAPI::Util::run(&receivedMessage);
680     receivedMessage = false;
681     TestWebKitAPI::Util::run(&done);
682     done = false;
683
684     auto pid3 = [webView _webProcessIdentifier];
685
686     // Verify the web pages are in different processes
687     EXPECT_NE(pid1, pid2);
688     EXPECT_NE(pid1, pid3);
689     EXPECT_NE(pid2, pid3);
690
691     // Verify the sessionStorage values were as expected
692     EXPECT_EQ([receivedMessages count], 2u);
693     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@""]);
694     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"I exist!"]);
695 }
696
697 static const char* mainFramesOnlyMainFrame = R"PSONRESOURCE(
698 <script>
699 function loaded() {
700     setTimeout('window.frames[0].location.href = "pson2://host2/main.html"', 0);
701 }
702 </script>
703 <body onload="loaded();">
704 Some text
705 <iframe src="pson1://host/iframe.html"></iframe>
706 </body>
707 )PSONRESOURCE";
708
709 static const char* mainFramesOnlySubframe = R"PSONRESOURCE(
710 Some content
711 )PSONRESOURCE";
712
713
714 static const char* mainFramesOnlySubframe2 = R"PSONRESOURCE(
715 <script>
716     window.webkit.messageHandlers.pson.postMessage("Done");
717 </script>
718 )PSONRESOURCE";
719
720 TEST(ProcessSwap, MainFramesOnly)
721 {
722     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
723     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
724     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
725
726     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
727     [webViewConfiguration setProcessPool:processPool.get()];
728     auto handler = adoptNS([[PSONScheme alloc] init]);
729     [handler addMappingFromURLString:@"pson1://host/main.html" toData:mainFramesOnlyMainFrame];
730     [handler addMappingFromURLString:@"pson1://host/iframe" toData:mainFramesOnlySubframe];
731     [handler addMappingFromURLString:@"pson2://host2/main.html" toData:mainFramesOnlySubframe2];
732     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
733     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
734
735     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
736     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
737
738     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
739     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
740     [webView setNavigationDelegate:delegate.get()];
741
742     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
743     [webView loadRequest:request];
744
745     TestWebKitAPI::Util::run(&receivedMessage);
746     receivedMessage = false;
747
748     EXPECT_EQ(1u, seenPIDs.size());
749 }
750
751 TEST(ProcessSwap, OnePreviousProcessRemains)
752 {
753     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
754     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
755     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
756
757     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
758     [webViewConfiguration setProcessPool:processPool.get()];
759     auto handler = adoptNS([[PSONScheme alloc] init]);
760     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
761
762     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
763     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
764     [webView setNavigationDelegate:delegate.get()];
765
766     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
767     [webView loadRequest:request];
768
769     TestWebKitAPI::Util::run(&done);
770     done = false;
771
772     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host2/main.html"]];
773     [webView loadRequest:request];
774
775     TestWebKitAPI::Util::run(&done);
776     done = false;
777
778     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
779     [webView loadRequest:request];
780
781     TestWebKitAPI::Util::run(&done);
782     done = false;
783
784     // Navigations to 3 different domains, we expect to have seen 3 different PIDs
785     EXPECT_EQ(3u, seenPIDs.size());
786
787     // But only 2 of those processes should still be alive
788     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
789 }
790
791 static const char* pageCache1Bytes = R"PSONRESOURCE(
792 <script>
793 window.addEventListener('pageshow', function(event) {
794     if (event.persisted)
795         window.webkit.messageHandlers.pson.postMessage("Was persisted");
796 });
797 </script>
798 )PSONRESOURCE";
799
800 TEST(ProcessSwap, PageCache1)
801 {
802     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
803     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
804     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
805
806     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
807     [webViewConfiguration setProcessPool:processPool.get()];
808     auto handler = adoptNS([[PSONScheme alloc] init]);
809     [handler addMappingFromURLString:@"pson1://host/main.html" toData:pageCache1Bytes];
810     [handler addMappingFromURLString:@"pson2://host/main.html" toData:pageCache1Bytes];
811     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
812     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
813
814     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
815     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
816
817     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
818     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
819     [webView setNavigationDelegate:delegate.get()];
820
821     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
822
823     [webView loadRequest:request];
824     TestWebKitAPI::Util::run(&done);
825     done = false;
826
827     auto pidAfterLoad1 = [webView _webProcessIdentifier];
828
829     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
830
831     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
832
833     [webView loadRequest:request];
834     TestWebKitAPI::Util::run(&done);
835     done = false;
836
837     auto pidAfterLoad2 = [webView _webProcessIdentifier];
838
839     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
840     EXPECT_NE(pidAfterLoad1, pidAfterLoad2);
841
842     [webView goBack];
843     TestWebKitAPI::Util::run(&receivedMessage);
844     receivedMessage = false;
845     TestWebKitAPI::Util::run(&done);
846     done = false;
847
848     auto pidAfterLoad3 = [webView _webProcessIdentifier];
849
850     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
851     EXPECT_EQ(pidAfterLoad1, pidAfterLoad3);
852     EXPECT_EQ(1u, [receivedMessages count]);
853     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"Was persisted" ]);
854     EXPECT_EQ(2u, seenPIDs.size());
855
856     [webView goForward];
857     TestWebKitAPI::Util::run(&receivedMessage);
858     receivedMessage = false;
859     TestWebKitAPI::Util::run(&done);
860     done = false;
861
862     auto pidAfterLoad4 = [webView _webProcessIdentifier];
863
864     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
865     EXPECT_EQ(pidAfterLoad2, pidAfterLoad4);
866     EXPECT_EQ(2u, [receivedMessages count]);
867     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"Was persisted" ]);
868     EXPECT_EQ(2u, seenPIDs.size());
869 }
870
871 TEST(ProcessSwap, NumberOfPrewarmedProcesses)
872 {
873     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
874     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
875     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
876
877     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
878     [webViewConfiguration setProcessPool:processPool.get()];
879     auto handler = adoptNS([[PSONScheme alloc] init]);
880     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
881
882     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
883     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
884     [webView setNavigationDelegate:delegate.get()];
885
886     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
887     [webView loadRequest:request];
888     TestWebKitAPI::Util::run(&done);
889     done = false;
890
891     EXPECT_EQ(2u, [processPool _webProcessCount]);
892     EXPECT_EQ(1u, [processPool _webProcessCountIgnoringPrewarmed]);
893     EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
894
895     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
896     [webView loadRequest:request];
897     TestWebKitAPI::Util::run(&done);
898     done = false;
899
900     EXPECT_EQ(3u, [processPool _webProcessCount]);
901     EXPECT_EQ(2u, [processPool _webProcessCountIgnoringPrewarmed]);
902     EXPECT_EQ(1u, [processPool _prewarmedWebProcessCount]);
903 }
904
905 static const char* visibilityBytes = R"PSONRESOURCE(
906 <script>
907 window.addEventListener('pageshow', function(event) {
908     var msg = window.location.href + " - pageshow ";
909     msg += event.persisted ? "persisted" : "NOT persisted";
910     window.webkit.messageHandlers.pson.postMessage(msg);
911 });
912
913 window.addEventListener('pagehide', function(event) {
914     var msg = window.location.href + " - pagehide ";
915     msg += event.persisted ? "persisted" : "NOT persisted";
916     window.webkit.messageHandlers.pson.postMessage(msg);
917 });
918 </script>
919 )PSONRESOURCE";
920
921 TEST(ProcessSwap, PageShowHide)
922 {
923     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
924     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
925     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
926
927     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
928     [webViewConfiguration setProcessPool:processPool.get()];
929     auto handler = adoptNS([[PSONScheme alloc] init]);
930     [handler addMappingFromURLString:@"pson1://host/main.html" toData:visibilityBytes];
931     [handler addMappingFromURLString:@"pson2://host/main.html" toData:visibilityBytes];
932     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
933     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
934
935     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
936     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
937
938     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
939     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
940     [webView setNavigationDelegate:delegate.get()];
941
942     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
943
944     [webView loadRequest:request];
945     TestWebKitAPI::Util::run(&receivedMessage);
946     receivedMessage = false;
947     TestWebKitAPI::Util::run(&done);
948     done = false;
949
950     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
951
952     [webView loadRequest:request];
953     TestWebKitAPI::Util::run(&receivedMessage);
954     receivedMessage = false;
955     TestWebKitAPI::Util::run(&done);
956     done = false;
957
958     [webView goBack];
959     TestWebKitAPI::Util::run(&receivedMessage);
960     receivedMessage = false;
961     TestWebKitAPI::Util::run(&done);
962     done = false;
963
964     [webView goForward];
965     TestWebKitAPI::Util::run(&receivedMessage);
966     receivedMessage = false;
967     TestWebKitAPI::Util::run(&done);
968     done = false;
969
970     EXPECT_EQ(7u, [receivedMessages count]);
971     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"pson1://host/main.html - pageshow NOT persisted" ]);
972     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"pson1://host/main.html - pagehide persisted" ]);
973     EXPECT_TRUE([receivedMessages.get()[2] isEqualToString:@"pson2://host/main.html - pageshow NOT persisted" ]);
974     EXPECT_TRUE([receivedMessages.get()[3] isEqualToString:@"pson2://host/main.html - pagehide persisted" ]);
975     EXPECT_TRUE([receivedMessages.get()[4] isEqualToString:@"pson1://host/main.html - pageshow persisted" ]);
976     EXPECT_TRUE([receivedMessages.get()[5] isEqualToString:@"pson1://host/main.html - pagehide persisted" ]);
977     EXPECT_TRUE([receivedMessages.get()[6] isEqualToString:@"pson2://host/main.html - pageshow persisted" ]);
978 }
979
980 // Disabling the page cache explicitly is (for some reason) not available on iOS.
981 #if !TARGET_OS_IPHONE
982 static const char* loadUnloadBytes = R"PSONRESOURCE(
983 <script>
984 window.addEventListener('unload', function(event) {
985     var msg = window.location.href + " - unload";
986     window.webkit.messageHandlers.pson.postMessage(msg);
987 });
988
989 window.addEventListener('load', function(event) {
990     var msg = window.location.href + " - load";
991     window.webkit.messageHandlers.pson.postMessage(msg);
992 });
993 </script>
994 )PSONRESOURCE";
995
996 TEST(ProcessSwap, LoadUnload)
997 {
998     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
999     [processPoolConfiguration setProcessSwapsOnNavigation:YES];
1000     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1001
1002     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1003     [webViewConfiguration setProcessPool:processPool.get()];
1004     auto handler = adoptNS([[PSONScheme alloc] init]);
1005     [handler addMappingFromURLString:@"pson1://host/main.html" toData:loadUnloadBytes];
1006     [handler addMappingFromURLString:@"pson2://host/main.html" toData:loadUnloadBytes];
1007     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
1008     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
1009
1010     auto messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
1011     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
1012     [[webViewConfiguration preferences] _setUsesPageCache:NO];
1013
1014     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1015     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1016     [webView setNavigationDelegate:delegate.get()];
1017
1018     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main.html"]];
1019
1020     [webView loadRequest:request];
1021     TestWebKitAPI::Util::run(&receivedMessage);
1022     receivedMessage = false;
1023     TestWebKitAPI::Util::run(&done);
1024     done = false;
1025
1026     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main.html"]];
1027
1028     [webView loadRequest:request];
1029     TestWebKitAPI::Util::run(&receivedMessage);
1030     receivedMessage = false;
1031     TestWebKitAPI::Util::run(&done);
1032     done = false;
1033
1034     [webView goBack];
1035     TestWebKitAPI::Util::run(&receivedMessage);
1036     receivedMessage = false;
1037     TestWebKitAPI::Util::run(&done);
1038     done = false;
1039
1040     [webView goForward];
1041     TestWebKitAPI::Util::run(&receivedMessage);
1042     receivedMessage = false;
1043     TestWebKitAPI::Util::run(&done);
1044     done = false;
1045
1046     EXPECT_EQ(7u, [receivedMessages count]);
1047     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"pson1://host/main.html - load" ]);
1048     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"pson1://host/main.html - unload" ]);
1049     EXPECT_TRUE([receivedMessages.get()[2] isEqualToString:@"pson2://host/main.html - load" ]);
1050     EXPECT_TRUE([receivedMessages.get()[3] isEqualToString:@"pson2://host/main.html - unload" ]);
1051     EXPECT_TRUE([receivedMessages.get()[4] isEqualToString:@"pson1://host/main.html - load" ]);
1052     EXPECT_TRUE([receivedMessages.get()[5] isEqualToString:@"pson1://host/main.html - unload" ]);
1053     EXPECT_TRUE([receivedMessages.get()[6] isEqualToString:@"pson2://host/main.html - load" ]);
1054 }
1055 #endif // !TARGET_OS_IPHONE
1056
1057 static const char* sameOriginBlobNavigationTestBytes = R"PSONRESOURCE(
1058 <!DOCTYPE html>
1059 <html>
1060 <body>
1061 <p><a id="link">Click here</a></p>
1062 <script>
1063 const blob = new Blob(['<!DOCTYPE html><html><p>PASS</p></html>'], {type: 'text/html'});
1064 link.href = URL.createObjectURL(blob);
1065 </script>
1066 )PSONRESOURCE";
1067
1068 TEST(ProcessSwap, SameOriginBlobNavigation)
1069 {
1070     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1071     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1072     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1073
1074     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1075     [webViewConfiguration setProcessPool:processPool.get()];
1076     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1077     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1078
1079     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1080     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1081     [webView setNavigationDelegate:navigationDelegate.get()];
1082     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1083     [webView setUIDelegate:uiDelegate.get()];
1084
1085     numberOfDecidePolicyCalls = 0;
1086     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1087
1088     TestWebKitAPI::Util::run(&done);
1089     done = false;
1090     auto pid1 = [webView _webProcessIdentifier];
1091     EXPECT_TRUE(!!pid1);
1092
1093     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: nil];
1094
1095     TestWebKitAPI::Util::run(&done);
1096     done = false;
1097     auto pid2 = [webView _webProcessIdentifier];
1098     EXPECT_TRUE(!!pid2);
1099     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1100     EXPECT_EQ(pid1, pid2);
1101 }
1102
1103 TEST(ProcessSwap, CrossOriginBlobNavigation)
1104 {
1105     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1106     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1107     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1108
1109     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1110     [webViewConfiguration setProcessPool:processPool.get()];
1111     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1112     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
1113     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
1114
1115     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1116     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1117     [webView setNavigationDelegate:navigationDelegate.get()];
1118     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1119     [webView setUIDelegate:uiDelegate.get()];
1120
1121     numberOfDecidePolicyCalls = 0;
1122     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]]];
1123     TestWebKitAPI::Util::run(&done);
1124     done = false;
1125     auto pid1 = [webView _webProcessIdentifier];
1126     EXPECT_TRUE(!!pid1);
1127
1128     bool finishedRunningScript = false;
1129     String blobURL;
1130     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').href" completionHandler: [&] (id result, NSError *error) {
1131         blobURL = String([NSString stringWithFormat:@"%@", result]);
1132         finishedRunningScript = true;
1133     }];
1134     TestWebKitAPI::Util::run(&finishedRunningScript);
1135
1136     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main1.html"]]];
1137     TestWebKitAPI::Util::run(&done);
1138     done = false;
1139     auto pid2 = [webView _webProcessIdentifier];
1140     EXPECT_TRUE(!!pid2);
1141
1142     finishedRunningScript = false;
1143     String script = "document.getElementById('link').href = '" + blobURL + "'";
1144     [webView _evaluateJavaScriptWithoutUserGesture:(NSString *)script completionHandler: [&] (id result, NSError *error) {
1145         finishedRunningScript = true;
1146     }];
1147     TestWebKitAPI::Util::run(&finishedRunningScript);
1148
1149     // This navigation will fail.
1150     [webView _evaluateJavaScriptWithoutUserGesture:@"document.getElementById('link').click()" completionHandler: [&] (id result, NSError *error) {
1151         done = true;
1152     }];
1153     TestWebKitAPI::Util::run(&done);
1154     done = false;
1155     auto pid3 = [webView _webProcessIdentifier];
1156     EXPECT_TRUE(!!pid3);
1157
1158     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1159     EXPECT_NE(pid1, pid2);
1160     EXPECT_EQ(pid2, pid3);
1161 }
1162
1163 TEST(ProcessSwap, NavigateToAboutBlank)
1164 {
1165     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1166     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1167     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1168
1169     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1170     [webViewConfiguration setProcessPool:processPool.get()];
1171     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1172     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1173
1174     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1175     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1176     [webView setNavigationDelegate:navigationDelegate.get()];
1177     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1178     [webView setUIDelegate:uiDelegate.get()];
1179
1180     numberOfDecidePolicyCalls = 0;
1181     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1182     TestWebKitAPI::Util::run(&done);
1183     done = false;
1184     auto pid1 = [webView _webProcessIdentifier];
1185     EXPECT_TRUE(!!pid1);
1186
1187     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"about:blank"]]];
1188     TestWebKitAPI::Util::run(&done);
1189     done = false;
1190     auto pid2 = [webView _webProcessIdentifier];
1191     EXPECT_TRUE(!!pid2);
1192
1193     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1194     EXPECT_EQ(pid1, pid2);
1195 }
1196
1197 TEST(ProcessSwap, NavigateToDataURL)
1198 {
1199     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
1200     processPoolConfiguration.get().processSwapsOnNavigation = YES;
1201     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
1202
1203     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
1204     [webViewConfiguration setProcessPool:processPool.get()];
1205     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:sameOriginBlobNavigationTestBytes]);
1206     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
1207
1208     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
1209     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
1210     [webView setNavigationDelegate:navigationDelegate.get()];
1211     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
1212     [webView setUIDelegate:uiDelegate.get()];
1213
1214     numberOfDecidePolicyCalls = 0;
1215     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]]];
1216     TestWebKitAPI::Util::run(&done);
1217     done = false;
1218     auto pid1 = [webView _webProcessIdentifier];
1219     EXPECT_TRUE(!!pid1);
1220
1221     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"data:text/plain,PASS"]]];
1222     TestWebKitAPI::Util::run(&done);
1223     done = false;
1224     auto pid2 = [webView _webProcessIdentifier];
1225     EXPECT_TRUE(!!pid2);
1226
1227     EXPECT_EQ(2, numberOfDecidePolicyCalls);
1228     EXPECT_EQ(pid1, pid2);
1229 }
1230
1231 #endif // WK_API_ENABLED