Unreviewed, rolling out r245418.
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / WKNavigationResponse.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 "TCPServer.h"
29 #import "Test.h"
30 #import "Utilities.h"
31 #import <WebKit/WKNavigationResponsePrivate.h>
32 #import <WebKit/WKProcessPoolPrivate.h>
33 #import <WebKit/WebKit.h>
34 #import <wtf/RetainPtr.h>
35
36 static bool isDone;
37
38 @interface WKNavigationResponseTestNavigationDelegate : NSObject <WKNavigationDelegate>
39 @property (nonatomic) BOOL expectation;
40 @end
41
42 @implementation WKNavigationResponseTestNavigationDelegate
43
44 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
45 {
46     EXPECT_EQ(navigationResponse.canShowMIMEType, self.expectation);
47     decisionHandler(WKNavigationResponsePolicyAllow);
48 }
49
50 - (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation
51 {
52     isDone = true;
53 }
54
55 @end
56
57 @interface WKNavigationResponseTestSchemeHandler : NSObject <WKURLSchemeHandler>
58 @property (nonatomic, copy) NSString *mimeType;
59 @end
60
61 @implementation WKNavigationResponseTestSchemeHandler
62
63 - (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)task
64 {
65     RetainPtr<NSURLResponse> response = adoptNS([[NSURLResponse alloc] initWithURL:[NSURL URLWithString:@"test:///json-response"] MIMEType:self.mimeType expectedContentLength:1 textEncodingName:nil]);
66     [task didReceiveResponse:response.get()];
67     [task didReceiveData:[@"{\"data\":1234}" dataUsingEncoding:NSUTF8StringEncoding]];
68     [task didFinish];
69 }
70
71 - (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask { }
72
73 @end
74
75 TEST(WebKit, WKNavigationResponseJSONMIMEType)
76 {
77     isDone = false;
78     auto schemeHandler = adoptNS([[WKNavigationResponseTestSchemeHandler alloc] init]);
79     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
80     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];
81     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
82     auto navigationDelegate = adoptNS([[WKNavigationResponseTestNavigationDelegate alloc] init]);
83     webView.get().navigationDelegate = navigationDelegate.get();
84
85     schemeHandler.get().mimeType = @"application/json";
86     navigationDelegate.get().expectation = YES;
87
88     NSURL *testURL = [NSURL URLWithString:@"test:///json-response"];
89     [webView loadRequest:[NSURLRequest requestWithURL:testURL]];
90     TestWebKitAPI::Util::run(&isDone);
91 }
92
93 TEST(WebKit, WKNavigationResponseJSONMIMEType2)
94 {
95     isDone = false;
96     auto schemeHandler = adoptNS([[WKNavigationResponseTestSchemeHandler alloc] init]);
97     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
98     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];
99     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
100     auto navigationDelegate = adoptNS([[WKNavigationResponseTestNavigationDelegate alloc] init]);
101     webView.get().navigationDelegate = navigationDelegate.get();
102
103     schemeHandler.get().mimeType = @"application/vnd.api+json";
104     navigationDelegate.get().expectation = YES;
105
106     NSURL *testURL = [NSURL URLWithString:@"test:///json-response"];
107     [webView loadRequest:[NSURLRequest requestWithURL:testURL]];
108     TestWebKitAPI::Util::run(&isDone);
109 }
110
111 TEST(WebKit, WKNavigationResponseUnknownMIMEType)
112 {
113     isDone = false;
114     auto schemeHandler = adoptNS([[WKNavigationResponseTestSchemeHandler alloc] init]);
115     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
116     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];
117     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
118     auto navigationDelegate = adoptNS([[WKNavigationResponseTestNavigationDelegate alloc] init]);
119     webView.get().navigationDelegate = navigationDelegate.get();
120
121     schemeHandler.get().mimeType = @"garbage/json";
122     navigationDelegate.get().expectation = NO;
123
124     NSURL *testURL = [NSURL URLWithString:@"test:///json-response"];
125     [webView loadRequest:[NSURLRequest requestWithURL:testURL]];
126     TestWebKitAPI::Util::run(&isDone);
127 }
128
129 TEST(WebKit, WKNavigationResponsePDFType)
130 {
131     isDone = false;
132     auto schemeHandler = adoptNS([[WKNavigationResponseTestSchemeHandler alloc] init]);
133     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
134     [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"test"];
135     auto webView = adoptNS([[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
136     auto navigationDelegate = adoptNS([[WKNavigationResponseTestNavigationDelegate alloc] init]);
137     webView.get().navigationDelegate = navigationDelegate.get();
138
139     [[[webView configuration] processPool] _addSupportedPlugin: @"" named: @"com.apple.webkit.builtinpdfplugin" withMimeTypes: [NSSet setWithArray: @[ @"application/pdf" ]] withExtensions: [NSSet setWithArray: @[ ]]];
140
141     schemeHandler.get().mimeType = @"application/pdf";
142     navigationDelegate.get().expectation = YES;
143
144     NSURL *testURL = [NSURL URLWithString:@"test:///pdf-response"];
145     [webView loadRequest:[NSURLRequest requestWithURL:testURL]];
146     TestWebKitAPI::Util::run(&isDone);
147 }
148
149 @interface NavigationResponseTestDelegate : NSObject <WKNavigationDelegate>
150
151 @property (nonatomic, readonly) WKNavigationResponse *navigationResponse;
152 @property (nonatomic) WKNavigationResponsePolicy navigationPolicy;
153
154 @end
155
156 @implementation NavigationResponseTestDelegate {
157     RetainPtr<WKNavigationResponse> _navigationResponse;
158     bool _hasReceivedResponseCallback;
159     bool _hasReceivedNavigationFinishedCallback;
160 }
161
162 - (WKNavigationResponse *)navigationResponse
163 {
164     return _navigationResponse.get();
165 }
166
167 - (void)waitForNavigationResponseCallback
168 {
169     _hasReceivedResponseCallback = false;
170     TestWebKitAPI::Util::run(&_hasReceivedResponseCallback);
171 }
172
173 - (void)waitForNavigationFinishedCallback
174 {
175     _hasReceivedNavigationFinishedCallback = false;
176     TestWebKitAPI::Util::run(&_hasReceivedNavigationFinishedCallback);
177 }
178
179 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
180 {
181     decisionHandler(WKNavigationActionPolicyAllow);
182 }
183
184 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
185 {
186     _hasReceivedNavigationFinishedCallback = true;
187 }
188
189 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
190 {
191     decisionHandler(WKNavigationResponsePolicyAllow);
192     _navigationResponse = navigationResponse;
193     _hasReceivedResponseCallback = true;
194 }
195
196 @end
197
198 static void readRequest(int socket)
199 {
200     char readBuffer[1000];
201     auto bytesRead = ::read(socket, readBuffer, sizeof(readBuffer));
202     EXPECT_GT(bytesRead, 0);
203     EXPECT_TRUE(static_cast<size_t>(bytesRead) < sizeof(readBuffer));
204 }
205
206 static void writeResponse(int socket, NSString *response)
207 {
208     const char* bytes = response.UTF8String;
209     auto bytesWritten = ::write(socket, bytes, strlen(bytes));
210     EXPECT_EQ(static_cast<size_t>(bytesWritten), strlen(bytes));
211 }
212
213 TEST(WebKit, WKNavigationResponseDownloadAttribute)
214 {
215     auto getDownloadResponse = [] (RetainPtr<NSString> body) -> RetainPtr<WKNavigationResponse> {
216         TestWebKitAPI::TCPServer server([body](int socket) {
217             readRequest(socket);
218             unsigned bodyLength = [body length];
219             writeResponse(socket, [NSString stringWithFormat:
220                 @"HTTP/1.1 200 OK\r\n"
221                 "Content-Length: %d\r\n\r\n"
222                 "%@",
223                 bodyLength,
224                 body.get()
225             ]);
226             readRequest(socket);
227             writeResponse(socket,
228                 @"HTTP/1.1 200 OK\r\n"
229                 "Content-Length: 6\r\n"
230                 "Content-Disposition: attachment; filename=fromHeader.txt;\r\n\r\n"
231                 "Hello!"
232             );
233         });
234         auto delegate = adoptNS([NavigationResponseTestDelegate new]);
235         auto webView = adoptNS([WKWebView new]);
236         [webView setNavigationDelegate:delegate.get()];
237
238         [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://127.0.0.1:%d/", server.port()]]]];
239         [delegate waitForNavigationFinishedCallback];
240
241         [webView evaluateJavaScript:@"document.getElementById('link').click();" completionHandler:nil];
242         [delegate waitForNavigationResponseCallback];
243         EXPECT_STREQ([delegate navigationResponse].response.suggestedFilename.UTF8String, "fromHeader.txt");
244         return [delegate navigationResponse];
245     };
246     auto shouldBeFromDownloadAttribute = getDownloadResponse(@"<a id='link' href='/fromHref.txt' download='fromDownloadAttribute.txt'>Click Me!</a>");
247     auto shouldBeNull = getDownloadResponse(@"<a id='link' href='/fromHref.txt'>Click Me!</a>");
248     auto shouldBeEmpty = getDownloadResponse(@"<a id='link' href='/fromHref.txt' download=''>Click Me!</a>");
249     
250     EXPECT_STREQ([shouldBeFromDownloadAttribute _downloadAttribute].UTF8String, "fromDownloadAttribute.txt");
251     EXPECT_STREQ([shouldBeEmpty _downloadAttribute].UTF8String, "");
252     EXPECT_NOT_NULL([shouldBeEmpty _downloadAttribute]);
253     EXPECT_NULL([shouldBeNull _downloadAttribute]);
254 }