REGRESSION(r225340): WPE port should not be getting EGL X11 types on ANGLE
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / WebsitePolicies.mm
1 /*
2  * Copyright (C) 2016 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 #include "config.h"
27
28 #import "PlatformUtilities.h"
29 #import "TestWKWebView.h"
30 #import <WebKit/WKNavigationDelegatePrivate.h>
31 #import <WebKit/WKPagePrivate.h>
32 #import <WebKit/WKPreferencesRefPrivate.h>
33 #import <WebKit/WKUIDelegatePrivate.h>
34 #import <WebKit/WKURLSchemeTaskPrivate.h>
35 #import <WebKit/WKUserContentControllerPrivate.h>
36 #import <WebKit/WKWebViewPrivate.h>
37 #import <WebKit/WKWebsiteDataStorePrivate.h>
38 #import <WebKit/_WKUserContentExtensionStorePrivate.h>
39 #import <WebKit/_WKWebsiteDataStoreConfiguration.h>
40 #import <WebKit/_WKWebsitePolicies.h>
41 #import <wtf/MainThread.h>
42 #import <wtf/RetainPtr.h>
43 #import <wtf/text/WTFString.h>
44
45 #if PLATFORM(IOS)
46 #import <WebKit/WKWebViewConfigurationPrivate.h>
47 #endif
48
49 #if WK_API_ENABLED
50
51 @interface WKWebView ()
52 - (WKPageRef)_pageForTesting;
53 @end
54
55 static bool doneCompiling;
56 static bool receivedAlert;
57
58 #if PLATFORM(MAC)
59 static std::optional<_WKAutoplayEvent> receivedAutoplayEvent;
60 static std::optional<_WKAutoplayEventFlags> receivedAutoplayEventFlags;
61 #endif
62
63 static size_t alertCount;
64
65 @interface ContentBlockingWebsitePoliciesDelegate : NSObject <WKNavigationDelegate, WKUIDelegate>
66 @end
67
68 @implementation ContentBlockingWebsitePoliciesDelegate
69
70 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
71 {
72     // _webView:decidePolicyForNavigationAction:decisionHandler: should be called instead if it is implemented.
73     EXPECT_TRUE(false);
74     decisionHandler(WKNavigationActionPolicyAllow);
75 }
76
77 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
78 {
79     switch (alertCount++) {
80     case 0:
81         // Default behavior.
82         EXPECT_STREQ("content blockers enabled", message.UTF8String);
83         break;
84     case 1:
85         // After having set websitePolicies.contentBlockersEnabled to false.
86         EXPECT_STREQ("content blockers disabled", message.UTF8String);
87         break;
88     case 2:
89         // After having reloaded without content blockers.
90         EXPECT_STREQ("content blockers disabled", message.UTF8String);
91         break;
92     default:
93         EXPECT_TRUE(false);
94     }
95     receivedAlert = true;
96     completionHandler();
97 }
98
99 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
100 {
101     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
102     switch (alertCount) {
103     case 0:
104         // Verify the content blockers behave correctly with the default behavior.
105         break;
106     case 1:
107         {
108             // Verify disabling content blockers works correctly.
109             websitePolicies.contentBlockersEnabled = false;
110             
111             // Verify calling the decisionHandler asynchronously works correctly.
112             auto decisionHandlerCopy = Block_copy(decisionHandler);
113             callOnMainThread([decisionHandlerCopy, websitePolicies = RetainPtr<_WKWebsitePolicies>(websitePolicies)] {
114                 decisionHandlerCopy(WKNavigationActionPolicyAllow, websitePolicies.get());
115                 Block_release(decisionHandlerCopy);
116             });
117         }
118         return;
119     case 2:
120         // Verify enabling content blockers has no effect when reloading without content blockers.
121         websitePolicies.contentBlockersEnabled = true;
122         break;
123     default:
124         EXPECT_TRUE(false);
125     }
126     decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
127 }
128
129 @end
130
131 TEST(WebKit, WebsitePoliciesContentBlockersEnabled)
132 {
133     [[_WKUserContentExtensionStore defaultStore] _removeAllContentExtensions];
134
135     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
136
137     doneCompiling = false;
138     NSString* contentBlocker = @"[{\"action\":{\"type\":\"css-display-none\",\"selector\":\".hidden\"},\"trigger\":{\"url-filter\":\".*\"}}]";
139     [[_WKUserContentExtensionStore defaultStore] compileContentExtensionForIdentifier:@"WebsitePoliciesTest" encodedContentExtension:contentBlocker completionHandler:^(_WKUserContentFilter *filter, NSError *error) {
140         EXPECT_TRUE(error == nil);
141         [[configuration userContentController] _addUserContentFilter:filter];
142         doneCompiling = true;
143     }];
144     TestWebKitAPI::Util::run(&doneCompiling);
145
146     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
147
148     auto delegate = adoptNS([[ContentBlockingWebsitePoliciesDelegate alloc] init]);
149     [webView setNavigationDelegate:delegate.get()];
150     [webView setUIDelegate:delegate.get()];
151
152     NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"contentBlockerCheck" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
153     alertCount = 0;
154     receivedAlert = false;
155     [webView loadRequest:request];
156     TestWebKitAPI::Util::run(&receivedAlert);
157
158     receivedAlert = false;
159     [webView reload];
160     TestWebKitAPI::Util::run(&receivedAlert);
161
162     receivedAlert = false;
163     [webView _reloadWithoutContentBlockers];
164     TestWebKitAPI::Util::run(&receivedAlert);
165
166     [[_WKUserContentExtensionStore defaultStore] _removeAllContentExtensions];
167 }
168
169 @interface AutoplayPoliciesDelegate : NSObject <WKNavigationDelegate, WKUIDelegatePrivate>
170 @property (nonatomic, copy) _WKWebsiteAutoplayPolicy(^autoplayPolicyForURL)(NSURL *);
171 @property (nonatomic, copy) _WKWebsiteAutoplayQuirk(^allowedAutoplayQuirksForURL)(NSURL *);
172 @end
173
174 @implementation AutoplayPoliciesDelegate
175
176 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
177 {
178     // _webView:decidePolicyForNavigationAction:decisionHandler: should be called instead if it is implemented.
179     EXPECT_TRUE(false);
180     decisionHandler(WKNavigationActionPolicyAllow);
181 }
182
183 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
184 {
185     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
186     if (_allowedAutoplayQuirksForURL)
187         websitePolicies.allowedAutoplayQuirks = _allowedAutoplayQuirksForURL(navigationAction.request.URL);
188     if (_autoplayPolicyForURL)
189         websitePolicies.autoplayPolicy = _autoplayPolicyForURL(navigationAction.request.URL);
190     decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
191 }
192
193 #if PLATFORM(MAC)
194 - (void)_webView:(WKWebView *)webView handleAutoplayEvent:(_WKAutoplayEvent)event withFlags:(_WKAutoplayEventFlags)flags
195 {
196     receivedAutoplayEventFlags = flags;
197     receivedAutoplayEvent = event;
198 }
199 #endif
200
201 @end
202
203 TEST(WebKit, WebsitePoliciesAutoplayEnabled)
204 {
205     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
206
207 #if PLATFORM(IOS)
208     [configuration setAllowsInlineMediaPlayback:YES];
209 #endif
210
211     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
212
213     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
214     [webView setNavigationDelegate:delegate.get()];
215
216     NSURLRequest *requestWithAudio = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
217     NSURLRequest *requestWithoutAudio = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-no-audio-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
218
219     // iOS does not support volume changes to media elements.
220 #if PLATFORM(MAC)
221     NSURLRequest *requestWithoutVolume = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-zero-volume-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
222 #endif
223
224     [delegate setAutoplayPolicyForURL:^(NSURL *) {
225         return _WKWebsiteAutoplayPolicyAllowWithoutSound;
226     }];
227     [webView loadRequest:requestWithAudio];
228     [webView waitForMessage:@"did-not-play"];
229
230     [webView loadRequest:requestWithoutAudio];
231     [webView waitForMessage:@"autoplayed"];
232
233 #if PLATFORM(MAC)
234     [webView loadRequest:requestWithoutVolume];
235     [webView waitForMessage:@"autoplayed"];
236 #endif
237
238     [delegate setAutoplayPolicyForURL:^(NSURL *) {
239         return _WKWebsiteAutoplayPolicyDeny;
240     }];
241
242 #if PLATFORM(MAC)
243     [webView loadRequest:requestWithoutVolume];
244     [webView waitForMessage:@"did-not-play"];
245 #endif
246
247     [webView loadRequest:requestWithAudio];
248     [webView waitForMessage:@"did-not-play"];
249
250     // Test updating website policies.
251     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
252     websitePolicies.autoplayPolicy = _WKWebsiteAutoplayPolicyAllow;
253     [webView _updateWebsitePolicies:websitePolicies];
254     [webView stringByEvaluatingJavaScript:@"playVideo()"];
255     [webView waitForMessage:@"autoplayed"];
256
257     [webView loadRequest:requestWithoutAudio];
258     [webView waitForMessage:@"did-not-play"];
259
260     [delegate setAutoplayPolicyForURL:^(NSURL *) {
261         return _WKWebsiteAutoplayPolicyAllow;
262     }];
263     [webView loadRequest:requestWithAudio];
264     [webView waitForMessage:@"autoplayed"];
265
266     [webView loadRequest:requestWithoutAudio];
267     [webView waitForMessage:@"autoplayed"];
268
269 #if PLATFORM(MAC)
270     [webView loadRequest:requestWithoutVolume];
271     [webView waitForMessage:@"autoplayed"];
272 #endif
273
274     NSURLRequest *requestWithAudioInIFrame = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check-in-iframe" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
275
276     // If the top-level document allows autoplay, any iframes should also autoplay.
277     [delegate setAutoplayPolicyForURL:^(NSURL *url) {
278         if ([url.lastPathComponent isEqualToString:@"autoplay-check-in-iframe.html"])
279             return _WKWebsiteAutoplayPolicyAllow;
280         return _WKWebsiteAutoplayPolicyDeny;
281     }];
282
283     [webView loadRequest:requestWithAudioInIFrame];
284     [webView waitForMessage:@"autoplayed"];
285
286     // If the top-level document disallows autoplay, any iframes should also not autoplay.
287     [delegate setAutoplayPolicyForURL:^(NSURL *url) {
288         if ([url.lastPathComponent isEqualToString:@"autoplay-check-in-iframe.html"])
289             return _WKWebsiteAutoplayPolicyDeny;
290         return _WKWebsiteAutoplayPolicyAllow;
291     }];
292
293     [webView loadRequest:requestWithAudioInIFrame];
294     [webView waitForMessage:@"did-not-play"];
295 }
296
297 #if PLATFORM(MAC)
298 static void runUntilReceivesAutoplayEvent(WKAutoplayEvent event)
299 {
300     while (!receivedAutoplayEvent || *receivedAutoplayEvent != event)
301         CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, true);
302 }
303
304 TEST(WebKit, WebsitePoliciesPlayAfterPreventedAutoplay)
305 {
306     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
307     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 336, 276) configuration:configuration.get()]);
308
309     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
310     [delegate setAutoplayPolicyForURL:^(NSURL *) {
311         return _WKWebsiteAutoplayPolicyDeny;
312     }];
313     [webView setNavigationDelegate:delegate.get()];
314     [webView setUIDelegate:delegate.get()];
315
316     NSPoint playButtonClickPoint = NSMakePoint(20, 256);
317
318     receivedAutoplayEvent = std::nullopt;
319     NSURLRequest *jsPlayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"js-play-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
320     [webView loadRequest:jsPlayRequest];
321     [webView waitForMessage:@"loaded"];
322     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPreventFromAutoplaying);
323
324     [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
325     [webView mouseUpAtPoint:playButtonClickPoint];
326     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
327     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
328
329     receivedAutoplayEvent = std::nullopt;
330     [webView loadHTMLString:@"" baseURL:nil];
331
332     NSURLRequest *autoplayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
333     [webView loadRequest:autoplayRequest];
334     [webView waitForMessage:@"loaded"];
335     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPreventFromAutoplaying);
336     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
337
338     [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
339     [webView mouseUpAtPoint:playButtonClickPoint];
340     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
341     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
342
343     receivedAutoplayEvent = std::nullopt;
344     [webView loadHTMLString:@"" baseURL:nil];
345
346     NSURLRequest *noAutoplayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"no-autoplay-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
347     [webView loadRequest:noAutoplayRequest];
348     [webView waitForMessage:@"loaded"];
349     [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
350     [webView mouseUpAtPoint:playButtonClickPoint];
351     [webView waitForMessage:@"played"];
352     ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
353
354     receivedAutoplayEvent = std::nullopt;
355     [webView loadHTMLString:@"" baseURL:nil];
356
357     [delegate setAutoplayPolicyForURL:^(NSURL *) {
358         return _WKWebsiteAutoplayPolicyAllowWithoutSound;
359     }];
360
361     NSURLRequest *autoplayMutedRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-muted-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
362     [webView loadRequest:autoplayMutedRequest];
363     [webView waitForMessage:@"loaded"];
364     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPreventFromAutoplaying);
365
366     [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
367     [webView mouseUpAtPoint:playButtonClickPoint];
368     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPlayMediaPreventedFromAutoplaying);
369     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
370 }
371
372 TEST(WebKit, WebsitePoliciesPlayingWithoutInterference)
373 {
374     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
375     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 336, 276) configuration:configuration.get()]);
376
377     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
378     [delegate setAutoplayPolicyForURL:^(NSURL *) {
379         return _WKWebsiteAutoplayPolicyAllow;
380     }];
381     [webView setNavigationDelegate:delegate.get()];
382     [webView setUIDelegate:delegate.get()];
383
384     receivedAutoplayEvent = std::nullopt;
385     NSURLRequest *jsPlayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"js-autoplay-audio" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
386     [webView loadRequest:jsPlayRequest];
387     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidAutoplayMediaPastThresholdWithoutUserInterference);
388     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
389 }
390
391 TEST(WebKit, WebsitePoliciesUserInterferenceWithPlaying)
392 {
393     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
394     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 336, 276) configuration:configuration.get()]);
395
396     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
397     [delegate setAutoplayPolicyForURL:^(NSURL *) {
398         return _WKWebsiteAutoplayPolicyAllow;
399     }];
400     [webView setNavigationDelegate:delegate.get()];
401     [webView setUIDelegate:delegate.get()];
402
403     receivedAutoplayEvent = std::nullopt;
404     NSURLRequest *jsPlayRequest = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"js-play-with-controls" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
405     [webView loadRequest:jsPlayRequest];
406     [webView waitForMessage:@"playing"];
407     ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
408
409     WKPageSetMuted([webView _pageForTesting], kWKMediaAudioMuted);
410     runUntilReceivesAutoplayEvent(kWKAutoplayEventUserDidInterfereWithPlayback);
411     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
412
413     receivedAutoplayEvent = std::nullopt;
414     [webView loadRequest:jsPlayRequest];
415     [webView waitForMessage:@"playing"];
416     ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
417
418     const NSPoint muteButtonClickPoint = NSMakePoint(80, 256);
419     [webView mouseDownAtPoint:muteButtonClickPoint simulatePressure:NO];
420     [webView mouseUpAtPoint:muteButtonClickPoint];
421     runUntilReceivesAutoplayEvent(kWKAutoplayEventUserDidInterfereWithPlayback);
422     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
423
424     receivedAutoplayEvent = std::nullopt;
425     [webView loadRequest:jsPlayRequest];
426     [webView waitForMessage:@"playing"];
427     ASSERT_TRUE(receivedAutoplayEvent == std::nullopt);
428
429     const NSPoint playButtonClickPoint = NSMakePoint(20, 256);
430     [webView mouseDownAtPoint:playButtonClickPoint simulatePressure:NO];
431     [webView mouseUpAtPoint:playButtonClickPoint];
432     runUntilReceivesAutoplayEvent(kWKAutoplayEventUserDidInterfereWithPlayback);
433     ASSERT_TRUE(*receivedAutoplayEventFlags & kWKAutoplayEventFlagsHasAudio);
434 }
435
436 struct ParsedRange {
437     ParsedRange(String string)
438     {
439         // This is a strict and unsafe Range header parser adequate only for tests.
440         bool parsingMin = true;
441         size_t min = 0;
442         size_t max = 0;
443         ASSERT(string.length() > 6);
444         ASSERT(string.startsWith("bytes="));
445         for (size_t i = 6; i < string.length(); ++i) {
446             if (isASCIIDigit(string[i])) {
447                 if (parsingMin)
448                     min = min * 10 + string[i] - '0';
449                 else
450                     max = max * 10 + string[i] - '0';
451             } else if (string[i] == '-') {
452                 if (parsingMin)
453                     parsingMin = false;
454                 else
455                     return;
456             } else
457                 return;
458         }
459         if (min <= max)
460             range = std::make_pair(min, max);
461     }
462     std::optional<std::pair<size_t, size_t>> range;
463 };
464
465 @interface TestSchemeHandler : NSObject <WKURLSchemeHandler>
466 - (instancetype)initWithVideoData:(RetainPtr<NSData>&&)data;
467 @end
468
469 @implementation TestSchemeHandler {
470     RetainPtr<NSData> videoData;
471 }
472
473 - (instancetype)initWithVideoData:(RetainPtr<NSData>&&)data
474 {
475     self = [super init];
476     if (!self)
477         return nil;
478     
479     videoData = WTFMove(data);
480     
481     return self;
482 }
483
484 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
485 {
486     if ([task.request.URL.path isEqualToString:@"/should-redirect"]) {
487         [(id<WKURLSchemeTaskPrivate>)task _didPerformRedirection:[[[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:nil expectedContentLength:0 textEncodingName:nil] autorelease] newRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test:///autoplay-check.html"]]];
488         
489         NSData *data = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
490         [task didReceiveResponse:[[[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:data.length textEncodingName:nil] autorelease]];
491         [task didReceiveData:data];
492         [task didFinish];
493         return;
494     }
495     
496     ASSERT_TRUE([task.request.URL.path isEqualToString:@"/test.mp4"]);
497     ParsedRange parsedRange([task.request valueForHTTPHeaderField:@"Range"]);
498     ASSERT_TRUE(!!parsedRange.range);
499     auto& range = *parsedRange.range;
500     
501     NSDictionary *headerFields = @{ @"Content-Length": [@(range.second - range.first) stringValue], @"Content-Range": [NSString stringWithFormat:@"bytes %lu-%lu/%lu", range.first, range.second, [videoData length]] };
502     NSURLResponse *response = [[[NSHTTPURLResponse alloc] initWithURL:task.request.URL statusCode:200 HTTPVersion:(NSString *)kCFHTTPVersion1_1 headerFields:headerFields] autorelease];
503     [task didReceiveResponse:response];
504     [task didReceiveData:[videoData subdataWithRange:NSMakeRange(range.first, range.second - range.first)]];
505     [task didFinish];
506     
507 }
508
509 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)task
510 {
511 }
512
513 @end
514
515 TEST(WebKit, WebsitePoliciesDuringRedirect)
516 {
517     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
518     auto videoData = adoptNS([[NSData alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"test" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"]]);
519     [configuration setURLSchemeHandler:[[[TestSchemeHandler alloc] initWithVideoData:WTFMove(videoData)] autorelease] forURLScheme:@"test"];
520     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
521     
522     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
523     [delegate setAutoplayPolicyForURL:^(NSURL *url) {
524         if ([url.path isEqualToString:@"/should-redirect"])
525             return _WKWebsiteAutoplayPolicyDeny;
526         return _WKWebsiteAutoplayPolicyAllow;
527     }];
528     [webView setNavigationDelegate:delegate.get()];
529     [webView setUIDelegate:delegate.get()];
530     
531     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test:///should-redirect"]]];
532     [webView waitForMessage:@"autoplayed"];
533 }
534
535 TEST(WebKit, WebsitePoliciesUpdates)
536 {
537     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
538     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
539     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
540     [webView setNavigationDelegate:delegate.get()];
541     [webView setUIDelegate:delegate.get()];
542
543     NSURLRequest *requestWithAudio = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
544
545     [delegate setAutoplayPolicyForURL:^(NSURL *) {
546         return _WKWebsiteAutoplayPolicyDeny;
547     }];
548     [webView loadRequest:requestWithAudio];
549     [webView waitForMessage:@"did-not-play"];
550
551     _WKWebsitePolicies *policies = [[[_WKWebsitePolicies alloc] init] autorelease];
552     policies.autoplayPolicy = _WKWebsiteAutoplayPolicyAllow;
553     [webView _updateWebsitePolicies:policies];
554
555     // Now that we updated our policies, a script should be able to autoplay media.
556     [webView stringByEvaluatingJavaScript:@"playVideo()"];
557     [webView waitForMessage:@"autoplayed"];
558
559     [webView stringByEvaluatingJavaScript:@"pauseVideo()"];
560
561     policies = [[[_WKWebsitePolicies alloc] init] autorelease];
562     policies.autoplayPolicy = _WKWebsiteAutoplayPolicyDeny;
563     [webView _updateWebsitePolicies:policies];
564
565     // A script should no longer be able to autoplay media.
566     receivedAutoplayEvent = std::nullopt;
567     [webView stringByEvaluatingJavaScript:@"playVideo()"];
568     runUntilReceivesAutoplayEvent(kWKAutoplayEventDidPreventFromAutoplaying);
569 }
570
571 TEST(WebKit, WebsitePoliciesArbitraryUserGestureQuirk)
572 {
573     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
574     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
575
576     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
577     [webView setNavigationDelegate:delegate.get()];
578
579     WKRetainPtr<WKPreferencesRef> preferences(AdoptWK, WKPreferencesCreate());
580     WKPreferencesSetNeedsSiteSpecificQuirks(preferences.get(), true);
581     WKPageGroupSetPreferences(WKPageGetPageGroup([webView _pageForTesting]), preferences.get());
582
583     [delegate setAllowedAutoplayQuirksForURL:^_WKWebsiteAutoplayQuirk(NSURL *url)
584     {
585         return _WKWebsiteAutoplayQuirkArbitraryUserGestures;
586     }];
587     [delegate setAutoplayPolicyForURL:^(NSURL *)
588     {
589         return _WKWebsiteAutoplayPolicyDeny;
590     }];
591
592     NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
593     [webView loadRequest:request];
594     [webView waitForMessage:@"did-not-play"];
595
596     const NSPoint clickPoint = NSMakePoint(760, 560);
597     [webView mouseDownAtPoint:clickPoint simulatePressure:NO];
598     [webView mouseUpAtPoint:clickPoint];
599
600     [webView stringByEvaluatingJavaScript:@"playVideo()"];
601     [webView waitForMessage:@"autoplayed"];
602 }
603
604 TEST(WebKit, WebsitePoliciesAutoplayQuirks)
605 {
606     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
607     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
608
609     auto delegate = adoptNS([[AutoplayPoliciesDelegate alloc] init]);
610     [webView setNavigationDelegate:delegate.get()];
611
612     WKRetainPtr<WKPreferencesRef> preferences(AdoptWK, WKPreferencesCreate());
613     WKPreferencesSetNeedsSiteSpecificQuirks(preferences.get(), true);
614     WKPageGroupSetPreferences(WKPageGetPageGroup([webView _pageForTesting]), preferences.get());
615
616     NSURLRequest *requestWithAudio = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
617
618     [delegate setAllowedAutoplayQuirksForURL:^_WKWebsiteAutoplayQuirk(NSURL *url) {
619         return _WKWebsiteAutoplayQuirkSynthesizedPauseEvents;
620     }];
621     [delegate setAutoplayPolicyForURL:^(NSURL *) {
622         return _WKWebsiteAutoplayPolicyDeny;
623     }];
624     [webView loadRequest:requestWithAudio];
625     [webView waitForMessage:@"did-not-play"];
626     [webView waitForMessage:@"on-pause"];
627
628     receivedAutoplayEvent = std::nullopt;
629     [webView loadHTMLString:@"" baseURL:nil];
630
631     NSURLRequest *requestWithAudioInFrame = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-check-in-iframe" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
632
633     [delegate setAllowedAutoplayQuirksForURL:^_WKWebsiteAutoplayQuirk(NSURL *url) {
634         if ([url.lastPathComponent isEqualToString:@"autoplay-check-frame.html"])
635             return _WKWebsiteAutoplayQuirkInheritedUserGestures;
636         
637         return _WKWebsiteAutoplayQuirkSynthesizedPauseEvents | _WKWebsiteAutoplayQuirkInheritedUserGestures;
638     }];
639     [delegate setAutoplayPolicyForURL:^(NSURL *) {
640         return _WKWebsiteAutoplayPolicyDeny;
641     }];
642     [webView loadRequest:requestWithAudioInFrame];
643     [webView waitForMessage:@"did-not-play"];
644     [webView waitForMessage:@"on-pause"];
645
646     receivedAutoplayEvent = std::nullopt;
647     [webView loadHTMLString:@"" baseURL:nil];
648
649     NSURLRequest *requestThatInheritsGesture = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"autoplay-inherits-gesture-from-document" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
650     [webView loadRequest:requestThatInheritsGesture];
651     [webView waitForMessage:@"loaded"];
652
653     // Click in the document, but not in the media element.
654     const NSPoint clickPoint = NSMakePoint(760, 560);
655     [webView mouseDownAtPoint:clickPoint simulatePressure:NO];
656     [webView mouseUpAtPoint:clickPoint];
657
658     [webView stringByEvaluatingJavaScript:@"play()"];
659     [webView waitForMessage:@"playing"];
660 }
661 #endif // PLATFORM(MAC)
662
663 TEST(WebKit, InvalidCustomHeaders)
664 {
665     auto websitePolicies = adoptNS([[_WKWebsitePolicies alloc] init]);
666     [websitePolicies setCustomHeaderFields:@{@"invalidheader" : @"", @"noncustom" : @"header", @"    x-Custom ":@"  Needs Canonicalization\t ", @"x-other" : @"other value"}];
667     NSDictionary<NSString *, NSString *> *canonicalized = [websitePolicies customHeaderFields];
668     EXPECT_EQ(canonicalized.count, 2u);
669     EXPECT_STREQ([canonicalized objectForKey:@"x-Custom"].UTF8String, "Needs Canonicalization");
670     EXPECT_STREQ([canonicalized objectForKey:@"x-other"].UTF8String, "other value");
671 }
672
673 static bool firstTestDone;
674 static bool secondTestDone;
675 static bool thirdTestDone;
676 static bool fourthTestDone;
677
678 static void expectHeaders(id <WKURLSchemeTask> task, bool expected)
679 {
680     NSURLRequest *request = task.request;
681     if (expected) {
682         EXPECT_STREQ([[request valueForHTTPHeaderField:@"X-key1"] UTF8String], "value1");
683         EXPECT_STREQ([[request valueForHTTPHeaderField:@"X-key2"] UTF8String], "value2");
684     } else {
685         EXPECT_TRUE([request valueForHTTPHeaderField:@"X-key1"] == nil);
686         EXPECT_TRUE([request valueForHTTPHeaderField:@"X-key2"] == nil);
687     }
688 }
689
690 static void respond(id <WKURLSchemeTask>task, NSString *html = nil)
691 {
692     [task didReceiveResponse:[[[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/html" expectedContentLength:html.length textEncodingName:nil] autorelease]];
693     [task didReceiveData:[html dataUsingEncoding:NSUTF8StringEncoding]];
694     [task didFinish];
695 }
696
697 @interface CustomHeaderFieldsDelegate : NSObject <WKNavigationDelegatePrivate, WKURLSchemeHandler>
698 @end
699
700 @implementation CustomHeaderFieldsDelegate
701
702 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
703 {
704     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
705     [websitePolicies setCustomHeaderFields:@{@"X-key1": @"value1", @"X-key2": @"value2"}];
706     if ([navigationAction.request.URL.path isEqualToString:@"/mainresource"]) {
707         dispatch_async(dispatch_get_main_queue(), ^{
708             decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
709         });
710     } else
711         decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
712 }
713
714 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
715 {
716     NSString *path = urlSchemeTask.request.URL.path;
717     if ([path isEqualToString:@"/mainresource"]) {
718         expectHeaders(urlSchemeTask, true);
719         respond(urlSchemeTask, @"<script>fetch('subresource').then(function(response){fetch('test://differentsecurityorigin/crossoriginsubresource',{mode:'no-cors'})})</script>");
720     } else if ([path isEqualToString:@"/subresource"]) {
721         expectHeaders(urlSchemeTask, true);
722         respond(urlSchemeTask);
723     } else if ([path isEqualToString:@"/crossoriginsubresource"]) {
724         expectHeaders(urlSchemeTask, false);
725         respond(urlSchemeTask);
726         firstTestDone = true;
727     } else if ([path isEqualToString:@"/mainresourcewithiframe"]) {
728         expectHeaders(urlSchemeTask, true);
729         respond(urlSchemeTask, @"<iframe src='test://iframeorigin/iframemainresource'></iframe>");
730     } else if ([path isEqualToString:@"/iframemainresource"]) {
731         expectHeaders(urlSchemeTask, false);
732         respond(urlSchemeTask, @"<script>fetch('iframesubresource').then(function(response){fetch('test://mainframeorigin/originaloriginsubresource',{mode:'no-cors'})})</script>");
733     } else if ([path isEqualToString:@"/iframesubresource"]) {
734         expectHeaders(urlSchemeTask, false);
735         respond(urlSchemeTask);
736     } else if ([path isEqualToString:@"/originaloriginsubresource"]) {
737         expectHeaders(urlSchemeTask, false);
738         respond(urlSchemeTask);
739         secondTestDone = true;
740     } else if ([path isEqualToString:@"/nestedtop"]) {
741         expectHeaders(urlSchemeTask, true);
742         respond(urlSchemeTask, @"<iframe src='test://otherorigin/nestedmid'></iframe>");
743     } else if ([path isEqualToString:@"/nestedmid"]) {
744         expectHeaders(urlSchemeTask, false);
745         respond(urlSchemeTask, @"<iframe src='test://toporigin/nestedbottom'></iframe>");
746     } else if ([path isEqualToString:@"/nestedbottom"]) {
747         expectHeaders(urlSchemeTask, true);
748         respond(urlSchemeTask);
749         thirdTestDone = true;
750     } else if ([path isEqualToString:@"/requestfromaboutblank"]) {
751         expectHeaders(urlSchemeTask, true);
752         respond(urlSchemeTask);
753         fourthTestDone = true;
754     } else
755         EXPECT_TRUE(false);
756 }
757
758 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
759 {
760 }
761
762 @end
763
764 TEST(WebKit, CustomHeaderFields)
765 {
766     auto delegate = adoptNS([[CustomHeaderFieldsDelegate alloc] init]);
767     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
768     [configuration setURLSchemeHandler:delegate.get() forURLScheme:@"test"];
769     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
770     [webView setNavigationDelegate:delegate.get()];
771     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test:///mainresource"]]];
772     TestWebKitAPI::Util::run(&firstTestDone);
773     
774     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://mainframeorigin/mainresourcewithiframe"]]];
775     TestWebKitAPI::Util::run(&secondTestDone);
776
777     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test://toporigin/nestedtop"]]];
778     TestWebKitAPI::Util::run(&thirdTestDone);
779 }
780
781 @interface PopUpPoliciesDelegate : NSObject <WKNavigationDelegate, WKUIDelegatePrivate>
782 @property (nonatomic, copy) _WKWebsitePopUpPolicy(^popUpPolicyForURL)(NSURL *);
783 @end
784
785 @implementation PopUpPoliciesDelegate
786
787 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
788 {
789     // _webView:decidePolicyForNavigationAction:decisionHandler: should be called instead if it is implemented.
790     EXPECT_TRUE(false);
791     decisionHandler(WKNavigationActionPolicyAllow);
792 }
793
794 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
795 {
796     _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
797     if (_popUpPolicyForURL)
798         websitePolicies.popUpPolicy = _popUpPolicyForURL(navigationAction.request.URL);
799     decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
800 }
801
802 - (nullable WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures
803 {
804     return [[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration];
805 }
806
807 @end
808
809 TEST(WebKit, WebsitePoliciesPopUp)
810 {
811     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
812
813     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
814
815     auto delegate = adoptNS([[PopUpPoliciesDelegate alloc] init]);
816     [webView setNavigationDelegate:delegate.get()];
817     [webView setUIDelegate:delegate.get()];
818
819     NSURLRequest *request = [NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"pop-up-check" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]];
820
821     [delegate setPopUpPolicyForURL:^_WKWebsitePopUpPolicy(NSURL *) {
822         return _WKWebsitePopUpPolicyBlock;
823     }];
824
825     [webView loadRequest:request];
826     [webView waitForMessage:@"pop-up-blocked"];
827
828     [delegate setPopUpPolicyForURL:^_WKWebsitePopUpPolicy(NSURL *) {
829         return _WKWebsitePopUpPolicyAllow;
830     }];
831
832     [webView loadRequest:request];
833     [webView waitForMessage:@"pop-up-allowed"];
834 }
835
836 static bool done;
837
838 @interface WebsitePoliciesWebsiteDataStoreDelegate : NSObject <WKNavigationDelegatePrivate, WKURLSchemeHandler, WKUIDelegate>
839 @end
840
841 @implementation WebsitePoliciesWebsiteDataStoreDelegate
842
843 - (void)_webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy, _WKWebsitePolicies *))decisionHandler
844 {
845     NSURL *url = navigationAction.request.URL;
846     if ([url.path isEqualToString:@"/invalid"]) {
847         _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
848         websitePolicies.websiteDataStore = [[[WKWebsiteDataStore alloc] _initWithConfiguration:[[[_WKWebsiteDataStoreConfiguration alloc] init] autorelease]] autorelease];
849
850         bool sawException = false;
851         @try {
852             decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
853         } @catch (NSException *exception) {
854             sawException = true;
855         }
856         EXPECT_TRUE(sawException);
857
858         done = true;
859     }
860     if ([url.path isEqualToString:@"/checkStorage"]
861         || [url.path isEqualToString:@"/checkCookies"]
862         || [url.path isEqualToString:@"/mainFrame"]) {
863         _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
864         websitePolicies.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
865         decisionHandler(WKNavigationActionPolicyAllow, websitePolicies);
866     }
867     if ([url.path isEqualToString:@"/subFrame"]) {
868         _WKWebsitePolicies *websitePolicies = [[[_WKWebsitePolicies alloc] init] autorelease];
869         websitePolicies.websiteDataStore = [WKWebsiteDataStore nonPersistentDataStore];
870         bool sawException = false;
871         @try {
872             decisionHandler(WKNavigationActionPolicyCancel, websitePolicies);
873         } @catch (NSException *exception) {
874             sawException = true;
875         }
876         EXPECT_TRUE(sawException);
877         done = true;
878     }
879 }
880
881 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
882 {
883     NSURL *url = task.request.URL;
884     if ([url.path isEqualToString:@"/checkStorage"]) {
885         NSString *html = @"<script>var oldValue = window.sessionStorage['storageKey']; window.sessionStorage['storageKey'] = 'value'; alert('old value: <' + (oldValue ? 'fail' : '') + '>');</script>";
886         [task didReceiveResponse:[[NSURLResponse alloc] initWithURL:url MIMEType:@"text/html" expectedContentLength:html.length textEncodingName:nil]];
887         [task didReceiveData:[html dataUsingEncoding:NSUTF8StringEncoding]];
888         [task didFinish];
889     }
890 }
891
892 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
893 {
894 }
895
896 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler
897 {
898     EXPECT_STREQ(message.UTF8String, "old value: <>");
899     completionHandler();
900     done = true;
901 }
902
903 @end
904
905 RetainPtr<WKWebView> websiteDataStoreTestWebView()
906 {
907     auto delegate = adoptNS([[WebsitePoliciesWebsiteDataStoreDelegate alloc] init]);
908     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
909     [configuration setURLSchemeHandler:delegate.get() forURLScheme:@"test"];
910     [configuration setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]];
911     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
912     [webView setNavigationDelegate:delegate.get()];
913     [webView setUIDelegate:delegate.get()];
914     return webView;
915 }
916
917 TEST(WebKit, UpdateWebsitePoliciesInvalid)
918 {
919     auto webView = websiteDataStoreTestWebView();
920     auto policies = adoptNS([[_WKWebsitePolicies alloc] init]);
921     [policies setWebsiteDataStore:[WKWebsiteDataStore nonPersistentDataStore]];
922     bool sawException = false;
923     @try {
924         [webView _updateWebsitePolicies:policies.get()];
925     } @catch (NSException *exception) {
926         sawException = true;
927     }
928     EXPECT_TRUE(sawException);
929     
930     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"test:///invalid"]]];
931     TestWebKitAPI::Util::run(&done);
932     
933     done = false;
934     [webView loadHTMLString:@"<iframe src='subFrame'></iframe>" baseURL:[NSURL URLWithString:@"http://webkit.org/mainFrame"]];
935     TestWebKitAPI::Util::run(&done);
936 }
937
938 TEST(WebKit, WebsitePoliciesDataStore)
939 {
940     auto cookieWebView = websiteDataStoreTestWebView();
941     NSString *alertOldCookie = @"<script>var oldCookie = document.cookie; document.cookie = 'key=value'; alert('old value: <' + oldCookie + '>');</script>";
942     [cookieWebView loadHTMLString:alertOldCookie baseURL:[NSURL URLWithString:@"http://example.com/checkCookies"]];
943     TestWebKitAPI::Util::run(&done);
944     done = false;
945     [cookieWebView loadHTMLString:alertOldCookie baseURL:[NSURL URLWithString:@"http://example.com/checkCookies"]];
946     TestWebKitAPI::Util::run(&done);
947 }
948
949 #endif // WK_API_ENABLED