REGRESSION: API test failure: _WKDownload.OriginatingWebView
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKit2Cocoa / Download.mm
1 /*
2  * Copyright (C) 2014 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 #import <WebKit/WKFoundation.h>
28
29 #if WK_API_ENABLED
30 #if PLATFORM(MAC) // No downloading on iOS
31
32 #import "PlatformUtilities.h"
33 #import "Test.h"
34 #import <WebCore/FileSystem.h>
35 #import <WebKit/_WKDownload.h>
36 #import <WebKit/_WKDownloadDelegate.h>
37 #import <WebKit/WKNavigationDelegatePrivate.h>
38 #import <WebKit/WKProcessPoolPrivate.h>
39 #import <WebKit/WKWebView.h>
40 #import <WebKit/WKWebViewConfiguration.h>
41 #import <wtf/RetainPtr.h>
42 #import <wtf/text/WTFString.h>
43
44 static bool isDone;
45 static bool hasReceivedResponse;
46 static NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
47
48 @interface DownloadDelegate : NSObject <_WKDownloadDelegate>
49 @end
50
51 @implementation DownloadDelegate {
52     RetainPtr<_WKDownload> _download;
53     String _destinationPath;
54     long long _expectedContentLength;
55     uint64_t _receivedContentLength;
56 }
57
58 - (void)_downloadDidStart:(_WKDownload *)download
59 {
60     EXPECT_NULL(_download);
61     EXPECT_NOT_NULL(download);
62     EXPECT_TRUE([[[[download request] URL] path] isEqualToString:[sourceURL path]]);
63     _download = download;
64 }
65
66 - (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response
67 {
68     hasReceivedResponse = true;
69     EXPECT_EQ(_download, download);
70     EXPECT_TRUE(_expectedContentLength == 0);
71     EXPECT_TRUE(_receivedContentLength == 0);
72     EXPECT_TRUE([[[response URL] path] isEqualToString:[sourceURL path]]);
73     _expectedContentLength = [response expectedContentLength];
74 }
75
76 - (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length
77 {
78     EXPECT_EQ(_download, download);
79     _receivedContentLength += length;
80 }
81
82 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
83 {
84     EXPECT_TRUE(hasReceivedResponse);
85     EXPECT_EQ(_download, download);
86
87     WebCore::PlatformFileHandle fileHandle;
88     _destinationPath = WebCore::openTemporaryFile("TestWebKitAPI", fileHandle);
89     EXPECT_TRUE(fileHandle != WebCore::invalidPlatformFileHandle);
90     WebCore::closeFile(fileHandle);
91
92     *allowOverwrite = YES;
93     return _destinationPath;
94 }
95
96 - (void)_downloadDidFinish:(_WKDownload *)download
97 {
98     EXPECT_EQ(_download, download);
99     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
100     EXPECT_TRUE([[NSFileManager defaultManager] contentsEqualAtPath:_destinationPath andPath:[sourceURL path]]);
101     WebCore::deleteFile(_destinationPath);
102     isDone = true;
103 }
104
105 @end
106
107 TEST(_WKDownload, DownloadDelegate)
108 {
109     RetainPtr<WKProcessPool> processPool = adoptNS([[WKProcessPool alloc] init]);
110     DownloadDelegate *downloadDelegate = [[DownloadDelegate alloc] init];
111     [processPool _setDownloadDelegate:downloadDelegate];
112
113     @autoreleasepool {
114         EXPECT_EQ(downloadDelegate, [processPool _downloadDelegate]);
115     }
116
117     [downloadDelegate release];
118     EXPECT_NULL([processPool _downloadDelegate]);
119 }
120
121 static void runTest(id <WKNavigationDelegate> navigationDelegate, id <_WKDownloadDelegate> downloadDelegate, NSURL *url)
122 {
123     RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
124     [webView setNavigationDelegate:navigationDelegate];
125     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate];
126
127     isDone = false;
128     hasReceivedResponse = false;
129     [webView loadRequest:[NSURLRequest requestWithURL:url]];
130     TestWebKitAPI::Util::run(&isDone);
131 }
132
133 @interface DownloadNavigationDelegate : NSObject <WKNavigationDelegate>
134 @end
135
136 @implementation DownloadNavigationDelegate
137 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
138 {
139     decisionHandler(_WKNavigationActionPolicyDownload);
140 }
141 @end
142
143 TEST(_WKDownload, DownloadRequest)
144 {
145     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[DownloadDelegate alloc] init]).get(), sourceURL);
146 }
147
148 @interface ConvertResponseToDownloadNavigationDelegate : NSObject <WKNavigationDelegate>
149 @end
150
151 @implementation ConvertResponseToDownloadNavigationDelegate
152 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
153 {
154     decisionHandler(_WKNavigationResponsePolicyBecomeDownload);
155 }
156 @end
157
158 TEST(_WKDownload, ConvertResponseToDownload)
159 {
160     runTest(adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]).get(), adoptNS([[DownloadDelegate alloc] init]).get(), sourceURL);
161 }
162
163 @interface FailingDownloadDelegate : NSObject <_WKDownloadDelegate>
164 @end
165
166 @implementation FailingDownloadDelegate
167
168 - (void)_downloadDidFinish:(_WKDownload *)download
169 {
170     EXPECT_TRUE(false);
171     isDone = true;
172 }
173
174 - (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
175 {
176     isDone = true;
177 }
178
179 - (void)_downloadDidCancel:(_WKDownload *)download
180 {
181     EXPECT_TRUE(false);
182     isDone = true;
183 }
184
185 @end
186
187 TEST(_WKDownload, DownloadMissingResource)
188 {
189     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[FailingDownloadDelegate alloc] init]).get(), [NSURL URLWithString:@"non-existant-scheme://"]);
190 }
191
192 @interface CancelledDownloadDelegate : NSObject <_WKDownloadDelegate>
193 @end
194
195 @implementation CancelledDownloadDelegate
196
197 - (void)_downloadDidStart:(_WKDownload *)download
198 {
199     [download cancel];
200 }
201
202 - (void)_downloadDidFinish:(_WKDownload *)download
203 {
204     EXPECT_TRUE(false);
205     isDone = true;
206 }
207
208 - (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
209 {
210     EXPECT_TRUE(false);
211     isDone = true;
212 }
213
214 - (void)_downloadDidCancel:(_WKDownload *)download
215 {
216     isDone = true;
217 }
218
219 @end
220
221 TEST(_WKDownload, CancelDownload)
222 {
223     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[CancelledDownloadDelegate alloc] init]).get(), sourceURL);
224 }
225
226 @interface OriginatingWebViewDownloadDelegate : NSObject <_WKDownloadDelegate>
227 - (instancetype)initWithWebView:(WKWebView *)webView;
228 @end
229
230 @implementation OriginatingWebViewDownloadDelegate {
231     RetainPtr<WKWebView> _webView;
232 }
233
234 - (instancetype)initWithWebView:(WKWebView *)webView
235 {
236     if (!(self = [super init]))
237         return nil;
238
239     _webView = webView;
240     return self;
241 }
242
243 - (void)_downloadDidStart:(_WKDownload *)download
244 {
245     @autoreleasepool {
246         EXPECT_EQ([download originatingWebView], _webView);
247     }
248
249     _webView = nullptr;
250     EXPECT_NULL([download originatingWebView]);
251     isDone = true;
252 }
253
254 @end
255
256 TEST(_WKDownload, OriginatingWebView)
257 {
258     RetainPtr<DownloadNavigationDelegate> navigationDelegate = adoptNS([[DownloadNavigationDelegate alloc] init]);                 
259     RetainPtr<OriginatingWebViewDownloadDelegate> downloadDelegate;
260     @autoreleasepool {
261         RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
262         [webView setNavigationDelegate:navigationDelegate.get()];
263         downloadDelegate = adoptNS([[OriginatingWebViewDownloadDelegate alloc] initWithWebView:webView.get()]);
264         [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
265         [webView loadRequest:[NSURLRequest requestWithURL:sourceURL]];
266     }
267
268     isDone = false;
269     TestWebKitAPI::Util::run(&isDone);
270 }
271
272 @interface DownloadRequestOriginalURLDelegate : NSObject <_WKDownloadDelegate>
273 - (instancetype)initWithExpectedOriginalURL:(NSURL *)expectOriginalURL;
274 @end
275
276 @implementation DownloadRequestOriginalURLDelegate {
277     NSURL *_expectedOriginalURL;
278 }
279
280 - (instancetype)initWithExpectedOriginalURL:(NSURL *)expectedOriginalURL
281 {
282     if (!(self = [super init]))
283         return nil;
284
285     _expectedOriginalURL = expectedOriginalURL;
286     return self;
287 }
288
289 - (void)_downloadDidStart:(_WKDownload *)download
290 {
291     if ([_expectedOriginalURL isEqual:sourceURL])
292         EXPECT_TRUE(!download.request.mainDocumentURL);
293     else
294         EXPECT_TRUE([_expectedOriginalURL isEqual:download.request.mainDocumentURL]);
295     isDone = true;
296 }
297
298 @end
299
300 @interface DownloadRequestOriginalURLNavigationDelegate : NSObject <WKNavigationDelegate>
301 @end
302
303 @implementation DownloadRequestOriginalURLNavigationDelegate
304 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
305 {
306     if ([navigationAction.request.URL isEqual:sourceURL])
307         decisionHandler(_WKNavigationActionPolicyDownload);
308     else
309         decisionHandler(WKNavigationActionPolicyAllow);
310 }
311 @end
312
313 TEST(_WKDownload, DownloadRequestOriginalURL)
314 {
315     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestOriginalURL" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
316     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:originalURL]).get(), originalURL);
317 }
318
319 TEST(_WKDownload, DownloadRequestOriginalURLFrame)
320 {
321     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestOriginalURL2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
322     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:originalURL]).get(), originalURL);
323 }
324
325 TEST(_WKDownload, DownloadRequestOriginalURLDirectDownload)
326 {
327     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:sourceURL]).get(), sourceURL);
328 }
329
330 TEST(_WKDownload, DownloadRequestOriginalURLDirectDownloadWithLoadedContent)
331 {
332     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
333     [webView setNavigationDelegate:[[DownloadRequestOriginalURLNavigationDelegate alloc] init]];
334     [[[webView configuration] processPool] _setDownloadDelegate:[[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:sourceURL]];
335
336     NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
337     // Here is to test if the original URL can be set correctly when the current document
338     // is completely unrelated to the download.
339     [webView loadRequest:[NSURLRequest requestWithURL:contentURL]];
340     [webView loadRequest:[NSURLRequest requestWithURL:sourceURL]];
341     isDone = false;
342     TestWebKitAPI::Util::run(&isDone);
343 }
344
345 @interface BlobDownloadDelegate : NSObject <_WKDownloadDelegate>
346 @end
347
348 @implementation BlobDownloadDelegate {
349     RetainPtr<_WKDownload> _download;
350     String _destinationPath;
351     long long _expectedContentLength;
352     uint64_t _receivedContentLength;
353 }
354
355 - (void)_downloadDidStart:(_WKDownload *)download
356 {
357     EXPECT_NULL(_download);
358     EXPECT_NOT_NULL(download);
359     EXPECT_TRUE([[[[download request] URL] scheme] isEqualToString:@"blob"]);
360     _download = download;
361 }
362
363 - (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response
364 {
365     hasReceivedResponse = true;
366     EXPECT_EQ(_download, download);
367     EXPECT_EQ(_expectedContentLength, 0U);
368     EXPECT_EQ(_receivedContentLength, 0U);
369     EXPECT_TRUE([[[response URL] scheme] isEqualToString:@"blob"]);
370     _expectedContentLength = [response expectedContentLength];
371 }
372
373 - (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length
374 {
375     EXPECT_EQ(_download, download);
376     _receivedContentLength += length;
377 }
378
379 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
380 {
381     EXPECT_TRUE(hasReceivedResponse);
382     EXPECT_EQ(_download, download);
383
384     WebCore::PlatformFileHandle fileHandle;
385     _destinationPath = WebCore::openTemporaryFile("TestWebKitAPI", fileHandle);
386     EXPECT_TRUE(fileHandle != WebCore::invalidPlatformFileHandle);
387     WebCore::closeFile(fileHandle);
388
389     *allowOverwrite = YES;
390     return _destinationPath;
391 }
392
393 - (void)_downloadDidFinish:(_WKDownload *)download
394 {
395     EXPECT_EQ(_download, download);
396     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
397     NSString* expectedContent = @"{\"x\":42,\"s\":\"hello, world\"}";
398     NSData* expectedData = [expectedContent dataUsingEncoding:NSUTF8StringEncoding];
399     EXPECT_TRUE([[[NSFileManager defaultManager] contentsAtPath:_destinationPath] isEqualToData:expectedData]);
400     WebCore::deleteFile(_destinationPath);
401     isDone = true;
402 }
403
404 @end
405
406 @interface DownloadBlobURLNavigationDelegate : NSObject <WKNavigationDelegate>
407 @end
408
409 @implementation DownloadBlobURLNavigationDelegate
410 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
411 {
412     if ([navigationAction.request.URL.scheme isEqualToString:@"blob"])
413         decisionHandler(_WKNavigationActionPolicyDownload);
414     else
415         decisionHandler(WKNavigationActionPolicyAllow);
416 }
417 @end
418
419 TEST(_WKDownload, DownloadRequestBlobURL)
420 {
421     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestBlobURL" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
422     runTest(adoptNS([[DownloadBlobURLNavigationDelegate alloc] init]).get(), adoptNS([[BlobDownloadDelegate alloc] init]).get(), originalURL);
423 }
424
425 #endif
426 #endif