[Content Filtering] Determine navigation and content policy before continuing to...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKit2Cocoa / ContentFiltering.mm
1 /*
2  * Copyright (C) 2015 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 #if WK_API_ENABLED && PLATFORM(MAC)
29
30 #import "MockContentFilterSettings.h"
31 #import "PlatformUtilities.h"
32 #import "TestProtocol.h"
33 #import "WKWebViewConfigurationExtras.h"
34 #import <WebKit/WKBrowsingContextController.h>
35 #import <WebKit/WKNavigationDelegatePrivate.h>
36 #import <WebKit/WKProcessPoolPrivate.h>
37 #import <WebKit/WKWebView.h>
38 #import <WebKit/_WKDownloadDelegate.h>
39 #import <wtf/RetainPtr.h>
40
41 using Decision = WebCore::MockContentFilterSettings::Decision;
42 using DecisionPoint = WebCore::MockContentFilterSettings::DecisionPoint;
43
44 static bool isDone;
45
46 @interface MockContentFilterEnabler : NSObject <NSCopying, NSSecureCoding>
47 - (instancetype)initWithDecision:(Decision)decision decisionPoint:(DecisionPoint)decisionPoint;
48 @end
49
50 @implementation MockContentFilterEnabler {
51     Decision _decision;
52     DecisionPoint _decisionPoint;
53 }
54
55 + (BOOL)supportsSecureCoding
56 {
57     return YES;
58 }
59
60 - (id)copyWithZone:(NSZone *)zone
61 {
62     return [self retain];
63 }
64
65 - (instancetype)initWithCoder:(NSCoder *)decoder
66 {
67     return [super init];
68 }
69
70 - (instancetype)initWithDecision:(Decision)decision decisionPoint:(DecisionPoint)decisionPoint
71 {
72     if (!(self = [super init]))
73         return nil;
74
75     _decision = decision;
76     _decisionPoint = decisionPoint;
77     return self;
78 }
79
80 - (void)encodeWithCoder:(NSCoder *)coder
81 {
82     [coder encodeInt:static_cast<int>(_decision) forKey:@"Decision"];
83     [coder encodeInt:static_cast<int>(_decisionPoint) forKey:@"DecisionPoint"];
84 }
85
86 @end
87
88 static RetainPtr<WKWebViewConfiguration> configurationWithContentFilterSettings(Decision decision, DecisionPoint decisionPoint)
89 {
90     auto configuration = retainPtr([WKWebViewConfiguration testwebkitapi_configurationWithTestPlugInClassName:@"ContentFilteringPlugIn"]);
91     auto contentFilterEnabler = adoptNS([[MockContentFilterEnabler alloc] initWithDecision:decision decisionPoint:decisionPoint]);
92     [[configuration processPool] _setObject:contentFilterEnabler.get() forBundleParameter:NSStringFromClass([MockContentFilterEnabler class])];
93     return configuration;
94 }
95
96 @interface ServerRedirectNavigationDelegate : NSObject <WKNavigationDelegate>
97 @end
98
99 @implementation ServerRedirectNavigationDelegate
100
101 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation
102 {
103     EXPECT_WK_STREQ(webView.URL.absoluteString, @"http://redirect/?pass");
104 }
105
106 - (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
107 {
108     EXPECT_WK_STREQ(webView.URL.absoluteString, @"http://pass/");
109 }
110
111 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
112 {
113     isDone = true;
114 }
115
116 @end
117
118 TEST(ContentFiltering, URLAfterServerRedirect)
119 {
120     @autoreleasepool {
121         [NSURLProtocol registerClass:[TestProtocol class]];
122         [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
123
124         auto configuration = configurationWithContentFilterSettings(Decision::Allow, DecisionPoint::AfterAddData);
125         auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
126         auto navigationDelegate = adoptNS([[ServerRedirectNavigationDelegate alloc] init]);
127         [webView setNavigationDelegate:navigationDelegate.get()];
128         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://redirect?pass"]]];
129         TestWebKitAPI::Util::run(&isDone);
130
131         [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
132         [NSURLProtocol unregisterClass:[TestProtocol class]];
133     }
134 }
135
136 @interface BecomeDownloadDelegate : NSObject <WKNavigationDelegate>
137 @end
138
139 @implementation BecomeDownloadDelegate
140
141 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
142 {
143     decisionHandler(_WKNavigationResponsePolicyBecomeDownload);
144 }
145
146 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error
147 {
148     isDone = true;
149 }
150
151 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
152 {
153     isDone = true;
154 }
155
156 @end
157
158 static bool downloadDidStart;
159
160 @interface ContentFilteringDownloadDelegate : NSObject <_WKDownloadDelegate>
161 @end
162
163 @implementation ContentFilteringDownloadDelegate
164
165 - (void)_downloadDidStart:(_WKDownload *)download
166 {
167     downloadDidStart = true;
168 }
169
170 @end
171
172 static void downloadTest(Decision decision, DecisionPoint decisionPoint)
173 {
174     @autoreleasepool {
175         [NSURLProtocol registerClass:[TestProtocol class]];
176         [WKBrowsingContextController registerSchemeForCustomProtocol:[TestProtocol scheme]];
177
178         auto configuration = configurationWithContentFilterSettings(decision, decisionPoint);
179         auto downloadDelegate = adoptNS([[ContentFilteringDownloadDelegate alloc] init]);
180         [[configuration processPool] _setDownloadDelegate:downloadDelegate.get()];
181         auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration.get()]);
182         auto navigationDelegate = adoptNS([[BecomeDownloadDelegate alloc] init]);
183         [webView setNavigationDelegate:navigationDelegate.get()];
184         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://redirect/?download"]]];
185
186         isDone = false;
187         downloadDidStart = false;
188         TestWebKitAPI::Util::run(&isDone);
189
190         const bool downloadShouldStart = decision == Decision::Allow || decisionPoint > DecisionPoint::AfterResponse;
191         EXPECT_EQ(downloadShouldStart, downloadDidStart);
192
193         [WKBrowsingContextController unregisterSchemeForCustomProtocol:[TestProtocol scheme]];
194         [NSURLProtocol unregisterClass:[TestProtocol class]];
195     }
196 }
197
198 TEST(ContentFiltering, AllowDownloadAfterWillSendRequest)
199 {
200     downloadTest(Decision::Allow, DecisionPoint::AfterWillSendRequest);
201 }
202
203 TEST(ContentFiltering, BlockDownloadAfterWillSendRequest)
204 {
205     downloadTest(Decision::Block, DecisionPoint::AfterWillSendRequest);
206 }
207
208 TEST(ContentFiltering, AllowDownloadAfterRedirect)
209 {
210     downloadTest(Decision::Allow, DecisionPoint::AfterRedirect);
211 }
212
213 TEST(ContentFiltering, BlockDownloadAfterRedirect)
214 {
215     downloadTest(Decision::Block, DecisionPoint::AfterRedirect);
216 }
217
218 TEST(ContentFiltering, AllowDownloadAfterResponse)
219 {
220     downloadTest(Decision::Allow, DecisionPoint::AfterResponse);
221 }
222
223 TEST(ContentFiltering, BlockDownloadAfterResponse)
224 {
225     downloadTest(Decision::Block, DecisionPoint::AfterResponse);
226 }
227
228 TEST(ContentFiltering, AllowDownloadAfterAddData)
229 {
230     downloadTest(Decision::Allow, DecisionPoint::AfterAddData);
231 }
232
233 TEST(ContentFiltering, BlockDownloadAfterAddData)
234 {
235     downloadTest(Decision::Block, DecisionPoint::AfterAddData);
236 }
237
238 TEST(ContentFiltering, AllowDownloadAfterFinishedAddingData)
239 {
240     downloadTest(Decision::Allow, DecisionPoint::AfterFinishedAddingData);
241 }
242
243 TEST(ContentFiltering, BlockDownloadAfterFinishedAddingData)
244 {
245     downloadTest(Decision::Block, DecisionPoint::AfterFinishedAddingData);
246 }
247
248 TEST(ContentFiltering, AllowDownloadNever)
249 {
250     downloadTest(Decision::Allow, DecisionPoint::Never);
251 }
252
253 TEST(ContentFiltering, BlockDownloadNever)
254 {
255     downloadTest(Decision::Block, DecisionPoint::Never);
256 }
257
258 #endif // WK_API_ENABLED