Process swapping on navigation needs to handle server redirects.
[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     [receivedMessages addObject:[message body]];
71     receivedMessage = true;
72 }
73 @end
74
75 @interface PSONNavigationDelegate : NSObject <WKNavigationDelegate>
76 @end
77
78 @implementation PSONNavigationDelegate
79
80 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
81 {
82     seenPIDs.add([webView _webProcessIdentifier]);
83     done = true;
84 }
85
86 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
87 {
88     ++numberOfDecidePolicyCalls;
89     seenPIDs.add([webView _webProcessIdentifier]);
90     decisionHandler(WKNavigationActionPolicyAllow);
91 }
92
93 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
94 {
95     seenPIDs.add([webView _webProcessIdentifier]);
96     serverRedirected = true;
97 }
98
99 @end
100
101 static RetainPtr<WKWebView> createdWebView;
102
103 @interface PSONUIDelegate : NSObject <WKUIDelegatePrivate>
104 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate;
105 @end
106
107 @implementation PSONUIDelegate {
108     RetainPtr<PSONNavigationDelegate> _navigationDelegate;
109 }
110
111 - (instancetype)initWithNavigationDelegate:(PSONNavigationDelegate *)navigationDelegate
112 {
113     if (!(self = [super init]))
114         return nil;
115
116     _navigationDelegate = navigationDelegate;
117     return self;
118 }
119
120 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
121 {
122     createdWebView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration]);
123     [createdWebView setNavigationDelegate:_navigationDelegate.get()];
124     didCreateWebView = true;
125     return createdWebView.get();
126 }
127
128 @end
129
130 @interface PSONScheme : NSObject <WKURLSchemeHandler> {
131     const char* _bytes;
132     HashMap<String, String> _redirects;
133 }
134 - (instancetype)initWithBytes:(const char*)bytes;
135 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString;
136 @end
137
138 @implementation PSONScheme
139
140 - (instancetype)initWithBytes:(const char*)bytes
141 {
142     self = [super init];
143     _bytes = bytes;
144     return self;
145 }
146
147 - (void)addRedirectFromURLString:(NSString *)sourceURLString toURLString:(NSString *)destinationURLString
148 {
149     _redirects.set(sourceURLString, destinationURLString);
150 }
151
152 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
153 {
154     NSURL *finalURL = task.request.URL;
155     auto target = _redirects.get(task.request.URL.absoluteString);
156     if (!target.isEmpty()) {
157         auto redirectResponse = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil]);
158
159         finalURL = [NSURL URLWithString:(NSString *)target];
160         auto request = adoptNS([[NSURLRequest alloc] initWithURL:finalURL]);
161
162         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:redirectResponse.get() newRequest:request.get()];
163     }
164
165     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:finalURL MIMEType:@"text/html" expectedContentLength:1 textEncodingName:nil]);
166     [task didReceiveResponse:response.get()];
167
168     if (_bytes) {
169         RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:(void *)_bytes length:strlen(_bytes) freeWhenDone:NO]);
170         [task didReceiveData:data.get()];
171     } else
172         [task didReceiveData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
173
174     [task didFinish];
175 }
176
177 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
178 {
179 }
180
181 @end
182
183 static const char* testBytes = R"PSONRESOURCE(
184 <head>
185 <script>
186
187 function log(msg)
188 {
189     window.webkit.messageHandlers.pson.postMessage(msg);
190 }
191
192 window.onload = function(evt) {
193     if (window.history.state != "onloadCalled")
194         setTimeout('window.history.replaceState("onloadCalled", "");', 0);
195 }
196
197 window.onpageshow = function(evt) {
198     log("PageShow called. Persisted: " + evt.persisted + ", and window.history.state is: " + window.history.state);
199 }
200
201 </script>
202 </head>
203 )PSONRESOURCE";
204
205 #if PLATFORM(MAC)
206
207 static const char* windowOpenCrossOriginNoOpenerTestBytes = R"PSONRESOURCE(
208 <script>
209 window.onload = function() {
210     window.open("pson2://host/main2.html", "_blank", "noopener");
211 }
212 </script>
213 )PSONRESOURCE";
214
215 static const char* windowOpenCrossOriginWithOpenerTestBytes = R"PSONRESOURCE(
216 <script>
217 window.onload = function() {
218     window.open("pson2://host/main2.html");
219 }
220 </script>
221 )PSONRESOURCE";
222
223 static const char* windowOpenSameOriginNoOpenerTestBytes = R"PSONRESOURCE(
224 <script>
225 window.onload = function() {
226     if (!opener)
227         window.open("pson1://host/main2.html", "_blank", "noopener");
228 }
229 </script>
230 )PSONRESOURCE";
231
232 static const char* dummyBytes = R"PSONRESOURCE(
233 <body>TEST</body>
234 )PSONRESOURCE";
235
236 #endif // PLATFORM(MAC)
237
238 TEST(ProcessSwap, Basic)
239 {
240     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
241     processPoolConfiguration.get().processSwapsOnNavigation = YES;
242     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
243
244     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
245     [webViewConfiguration setProcessPool:processPool.get()];
246     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
247     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
248     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON2"];
249
250     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
251     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
252     [webView setNavigationDelegate:delegate.get()];
253
254     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
255     [webView loadRequest:request];
256
257     TestWebKitAPI::Util::run(&done);
258     done = false;
259
260     auto pid1 = [webView _webProcessIdentifier];
261
262     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main2.html"]];
263     [webView loadRequest:request];
264
265     TestWebKitAPI::Util::run(&done);
266     done = false;
267
268     auto pid2 = [webView _webProcessIdentifier];
269
270     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
271     [webView loadRequest:request];
272
273     TestWebKitAPI::Util::run(&done);
274     done = false;
275
276     auto pid3 = [webView _webProcessIdentifier];
277
278     EXPECT_EQ(pid1, pid2);
279     EXPECT_FALSE(pid2 == pid3);
280
281     // 3 loads, 3 decidePolicy calls (e.g. the load that did perform a process swap should not have generated an additional decidePolicy call)
282     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
283 }
284
285 TEST(ProcessSwap, Back)
286 {
287     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
288     processPoolConfiguration.get().processSwapsOnNavigation = YES;
289     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
290
291     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
292     [webViewConfiguration setProcessPool:processPool.get()];
293     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:testBytes]);
294     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
295     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
296     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
297
298     RetainPtr<PSONMessageHandler> messageHandler = adoptNS([[PSONMessageHandler alloc] init]);
299     [[webViewConfiguration userContentController] addScriptMessageHandler:messageHandler.get() name:@"pson"];
300
301     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
302     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
303     [webView setNavigationDelegate:delegate.get()];
304
305     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
306     [webView loadRequest:request];
307
308     TestWebKitAPI::Util::run(&receivedMessage);
309     receivedMessage = false;
310     TestWebKitAPI::Util::run(&done);
311     done = false;
312
313     auto pid1 = [webView _webProcessIdentifier];
314
315     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson2://host/main2.html"]];
316     [webView loadRequest:request];
317
318     TestWebKitAPI::Util::run(&done);
319     done = false;
320
321     auto pid2 = [webView _webProcessIdentifier];
322
323     [webView goBack];
324
325     TestWebKitAPI::Util::run(&receivedMessage);
326     receivedMessage = false;
327     TestWebKitAPI::Util::run(&done);
328     done = false;
329
330     auto pid3 = [webView _webProcessIdentifier];
331
332     // 3 loads, 3 decidePolicy calls (e.g. any load that performs a process swap should not have generated an
333     // additional decidePolicy call as a result of the process swap)
334     EXPECT_EQ(numberOfDecidePolicyCalls, 3);
335
336     EXPECT_EQ([receivedMessages count], 2u);
337     EXPECT_TRUE([receivedMessages.get()[0] isEqualToString:@"PageShow called. Persisted: false, and window.history.state is: null"]);
338
339     // FIXME: We'd like to get the page restoring from the page cache like before process swapping, which will make Persisted be "true"
340     // For now it's expected to be false"
341     EXPECT_TRUE([receivedMessages.get()[1] isEqualToString:@"PageShow called. Persisted: false, and window.history.state is: onloadCalled"]);
342
343     EXPECT_FALSE(pid1 == pid2);
344     EXPECT_FALSE(pid2 == pid3);
345
346     // FIXME: Ideally we'd like to get process caching happening such that pid1 and pid3 are equal.
347     // But for now they should not be.
348     EXPECT_FALSE(pid1 == pid3);
349 }
350
351 #if PLATFORM(MAC)
352
353 TEST(ProcessSwap, CrossOriginWindowOpenNoOpener)
354 {
355     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
356     processPoolConfiguration.get().processSwapsOnNavigation = YES;
357     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
358
359     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
360     [webViewConfiguration setProcessPool:processPool.get()];
361     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginNoOpenerTestBytes]);
362     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
363     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
364     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
365
366     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
367     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
368     [webView setNavigationDelegate:navigationDelegate.get()];
369     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
370     [webView setUIDelegate:uiDelegate.get()];
371
372     numberOfDecidePolicyCalls = 0;
373     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
374     [webView loadRequest:request];
375
376     TestWebKitAPI::Util::run(&done);
377     done = false;
378
379     TestWebKitAPI::Util::run(&didCreateWebView);
380     didCreateWebView = false;
381
382     TestWebKitAPI::Util::run(&done);
383
384     EXPECT_EQ(2, numberOfDecidePolicyCalls);
385
386     auto pid1 = [webView _webProcessIdentifier];
387     EXPECT_TRUE(!!pid1);
388     auto pid2 = [createdWebView _webProcessIdentifier];
389     EXPECT_TRUE(!!pid2);
390
391     EXPECT_NE(pid1, pid2);
392 }
393
394 TEST(ProcessSwap, CrossOriginWindowOpenWithOpener)
395 {
396     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
397     processPoolConfiguration.get().processSwapsOnNavigation = YES;
398     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
399
400     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
401     [webViewConfiguration setProcessPool:processPool.get()];
402     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenCrossOriginWithOpenerTestBytes]);
403     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] initWithBytes:dummyBytes]);
404     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"PSON1"];
405     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"PSON2"];
406
407     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
408     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
409     [webView setNavigationDelegate:navigationDelegate.get()];
410     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
411     [webView setUIDelegate:uiDelegate.get()];
412
413     numberOfDecidePolicyCalls = 0;
414     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
415     [webView loadRequest:request];
416
417     TestWebKitAPI::Util::run(&done);
418     done = false;
419
420     TestWebKitAPI::Util::run(&didCreateWebView);
421     didCreateWebView = false;
422
423     TestWebKitAPI::Util::run(&done);
424
425     EXPECT_EQ(2, numberOfDecidePolicyCalls);
426
427     auto pid1 = [webView _webProcessIdentifier];
428     EXPECT_TRUE(!!pid1);
429     auto pid2 = [createdWebView _webProcessIdentifier];
430     EXPECT_TRUE(!!pid2);
431
432     // FIXME: This should eventually be false once we support process swapping when there is an opener.
433     EXPECT_EQ(pid1, pid2);
434 }
435
436 TEST(ProcessSwap, SameOriginWindowOpenNoOpener)
437 {
438     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
439     processPoolConfiguration.get().processSwapsOnNavigation = YES;
440     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
441
442     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
443     [webViewConfiguration setProcessPool:processPool.get()];
444     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] initWithBytes:windowOpenSameOriginNoOpenerTestBytes]);
445     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON1"];
446
447     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
448     auto navigationDelegate = adoptNS([[PSONNavigationDelegate alloc] init]);
449     [webView setNavigationDelegate:navigationDelegate.get()];
450     auto uiDelegate = adoptNS([[PSONUIDelegate alloc] initWithNavigationDelegate:navigationDelegate.get()]);
451     [webView setUIDelegate:uiDelegate.get()];
452
453     numberOfDecidePolicyCalls = 0;
454     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson1://host/main1.html"]];
455     [webView loadRequest:request];
456
457     TestWebKitAPI::Util::run(&done);
458     done = false;
459
460     TestWebKitAPI::Util::run(&didCreateWebView);
461     didCreateWebView = false;
462
463     TestWebKitAPI::Util::run(&done);
464
465     EXPECT_EQ(2, numberOfDecidePolicyCalls);
466
467     auto pid1 = [webView _webProcessIdentifier];
468     EXPECT_TRUE(!!pid1);
469     auto pid2 = [createdWebView _webProcessIdentifier];
470     EXPECT_TRUE(!!pid2);
471
472     EXPECT_EQ(pid1, pid2);
473 }
474
475 #endif // PLATFORM(MAC)
476
477 TEST(ProcessSwap, ServerRedirectFromNewWebView)
478 {
479     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
480     processPoolConfiguration.get().processSwapsOnNavigation = YES;
481     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
482
483     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
484     [webViewConfiguration setProcessPool:processPool.get()];
485     RetainPtr<PSONScheme> handler = adoptNS([[PSONScheme alloc] init]);
486     [handler addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
487     [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"pson"];
488
489     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
490     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
491     [webView setNavigationDelegate:delegate.get()];
492
493     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
494     [webView loadRequest:request];
495
496     TestWebKitAPI::Util::run(&serverRedirected);
497     serverRedirected = false;
498
499     seenPIDs.add([webView _webProcessIdentifier]);
500
501     TestWebKitAPI::Util::run(&done);
502     done = false;
503
504     seenPIDs.add([webView _webProcessIdentifier]);
505
506     EXPECT_FALSE(serverRedirected);
507     EXPECT_EQ(2, numberOfDecidePolicyCalls);
508     EXPECT_EQ(1u, seenPIDs.size());
509 }
510
511 TEST(ProcessSwap, ServerRedirect)
512 {
513     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
514     processPoolConfiguration.get().processSwapsOnNavigation = YES;
515     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
516
517     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
518     [webViewConfiguration setProcessPool:processPool.get()];
519     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
520     [handler1 addRedirectFromURLString:@"pson://host/main1.html" toURLString:@"psonredirected://host/main1.html"];
521     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
522     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
523     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"originalload"];
524
525     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
526     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
527     [webView setNavigationDelegate:delegate.get()];
528
529     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"originalload://host/main1.html"]];
530     [webView loadRequest:request];
531
532     TestWebKitAPI::Util::run(&done);
533     done = false;
534
535     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
536
537     EXPECT_EQ(1, numberOfDecidePolicyCalls);
538     EXPECT_EQ(1u, seenPIDs.size());
539     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
540
541     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
542     [webView loadRequest:request];
543
544     TestWebKitAPI::Util::run(&serverRedirected);
545     serverRedirected = false;
546
547     seenPIDs.add([webView _webProcessIdentifier]);
548
549     TestWebKitAPI::Util::run(&done);
550     done = false;
551
552     seenPIDs.add([webView _webProcessIdentifier]);
553
554     EXPECT_FALSE(serverRedirected);
555     EXPECT_EQ(3, numberOfDecidePolicyCalls);
556     EXPECT_EQ(2u, seenPIDs.size());
557 }
558
559 TEST(ProcessSwap, ServerRedirect2)
560 {
561     // This tests a load that *starts out* to the same origin as the previous load, but then redirects to a new origin.
562     auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
563     processPoolConfiguration.get().processSwapsOnNavigation = YES;
564     auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
565
566     auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
567     [webViewConfiguration setProcessPool:processPool.get()];
568     RetainPtr<PSONScheme> handler1 = adoptNS([[PSONScheme alloc] init]);
569     [handler1 addRedirectFromURLString:@"pson://host/main2.html" toURLString:@"psonredirected://host/main1.html"];
570     [webViewConfiguration setURLSchemeHandler:handler1.get() forURLScheme:@"pson"];
571     RetainPtr<PSONScheme> handler2 = adoptNS([[PSONScheme alloc] init]);
572     [webViewConfiguration setURLSchemeHandler:handler2.get() forURLScheme:@"psonredirected"];
573
574     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
575     auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
576     [webView setNavigationDelegate:delegate.get()];
577
578     NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main1.html"]];
579     [webView loadRequest:request];
580
581     TestWebKitAPI::Util::run(&done);
582     done = false;
583
584     auto pidAfterFirstLoad = [webView _webProcessIdentifier];
585
586     EXPECT_FALSE(serverRedirected);
587     EXPECT_EQ(1, numberOfDecidePolicyCalls);
588     EXPECT_EQ(1u, seenPIDs.size());
589     EXPECT_TRUE(*seenPIDs.begin() == pidAfterFirstLoad);
590
591     request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host/main2.html"]];
592     [webView loadRequest:request];
593
594     TestWebKitAPI::Util::run(&serverRedirected);
595     serverRedirected = false;
596
597     seenPIDs.add([webView _webProcessIdentifier]);
598
599     TestWebKitAPI::Util::run(&done);
600     done = false;
601
602     seenPIDs.add([webView _webProcessIdentifier]);
603
604     EXPECT_FALSE(serverRedirected);
605     EXPECT_EQ(3, numberOfDecidePolicyCalls);
606     EXPECT_EQ(2u, seenPIDs.size());
607 }
608
609
610 #endif // WK_API_ENABLED