Blob references for System Previews don't get a correct file extension
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebKitCocoa / 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) || PLATFORM(IOS)
31
32 #import "PlatformUtilities.h"
33 #import "Test.h"
34 #import "TestProtocol.h"
35 #import "TestWKWebView.h"
36 #import <WebCore/FileSystem.h>
37 #import <WebKit/_WKDownload.h>
38 #import <WebKit/_WKDownloadDelegate.h>
39 #import <WebKit/WKNavigationDelegatePrivate.h>
40 #import <WebKit/WKProcessPoolPrivate.h>
41 #import <WebKit/WKUIDelegatePrivate.h>
42 #import <WebKit/WKWebView.h>
43 #import <WebKit/WKWebViewConfiguration.h>
44 #import <wtf/MainThread.h>
45 #import <wtf/RetainPtr.h>
46 #import <wtf/text/WTFString.h>
47
48 static bool isDone;
49 static unsigned redirectCount = 0;
50 static bool hasReceivedResponse;
51 static NSURL *sourceURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
52 static WKWebView* expectedOriginatingWebView;
53 static bool expectedUserInitiatedState = false;
54
55 @interface DownloadDelegate : NSObject <_WKDownloadDelegate>
56 @end
57
58 @implementation DownloadDelegate {
59     RetainPtr<_WKDownload> _download;
60     String _destinationPath;
61     long long _expectedContentLength;
62     uint64_t _receivedContentLength;
63 }
64
65 - (void)_downloadDidStart:(_WKDownload *)download
66 {
67     EXPECT_NULL(_download);
68     EXPECT_NOT_NULL(download);
69     EXPECT_TRUE([[[[download request] URL] path] isEqualToString:[sourceURL path]]);
70     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
71     _download = download;
72 }
73
74 - (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response
75 {
76     hasReceivedResponse = true;
77     EXPECT_EQ(_download, download);
78     EXPECT_TRUE(_expectedContentLength == 0);
79     EXPECT_TRUE(_receivedContentLength == 0);
80     EXPECT_TRUE([[[response URL] path] isEqualToString:[sourceURL path]]);
81     _expectedContentLength = [response expectedContentLength];
82 }
83
84 - (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length
85 {
86     EXPECT_EQ(_download, download);
87     _receivedContentLength += length;
88 }
89
90 IGNORE_WARNINGS_BEGIN("deprecated-implementations")
91 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
92 IGNORE_WARNINGS_END
93 {
94     EXPECT_TRUE(hasReceivedResponse);
95     EXPECT_EQ(_download, download);
96
97     WebCore::FileSystem::PlatformFileHandle fileHandle;
98     _destinationPath = WebCore::FileSystem::openTemporaryFile("TestWebKitAPI", fileHandle);
99     EXPECT_TRUE(fileHandle != WebCore::FileSystem::invalidPlatformFileHandle);
100     WebCore::FileSystem::closeFile(fileHandle);
101
102     *allowOverwrite = YES;
103     return _destinationPath;
104 }
105
106 - (void)_downloadDidFinish:(_WKDownload *)download
107 {
108     EXPECT_EQ(_download, download);
109     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
110     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
111     EXPECT_TRUE([[NSFileManager defaultManager] contentsEqualAtPath:_destinationPath andPath:[sourceURL path]]);
112     WebCore::FileSystem::deleteFile(_destinationPath);
113     isDone = true;
114 }
115
116 @end
117
118 TEST(_WKDownload, DownloadDelegate)
119 {
120     RetainPtr<WKProcessPool> processPool = adoptNS([[WKProcessPool alloc] init]);
121     DownloadDelegate *downloadDelegate = [[DownloadDelegate alloc] init];
122     [processPool _setDownloadDelegate:downloadDelegate];
123
124     @autoreleasepool {
125         EXPECT_EQ(downloadDelegate, [processPool _downloadDelegate]);
126     }
127
128     [downloadDelegate release];
129     EXPECT_NULL([processPool _downloadDelegate]);
130 }
131
132 static void runTest(id <WKNavigationDelegate> navigationDelegate, id <_WKDownloadDelegate> downloadDelegate, NSURL *url)
133 {
134     RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
135     [webView setNavigationDelegate:navigationDelegate];
136     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate];
137
138     isDone = false;
139     hasReceivedResponse = false;
140     expectedUserInitiatedState = false;
141     [webView loadRequest:[NSURLRequest requestWithURL:url]];
142     TestWebKitAPI::Util::run(&isDone);
143 }
144
145 @interface DownloadNavigationDelegate : NSObject <WKNavigationDelegate>
146 @end
147
148 @implementation DownloadNavigationDelegate
149 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
150 {
151     decisionHandler(_WKNavigationActionPolicyDownload);
152 }
153 @end
154
155 TEST(_WKDownload, DownloadRequest)
156 {
157     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[DownloadDelegate alloc] init]).get(), sourceURL);
158 }
159
160 @interface ConvertResponseToDownloadNavigationDelegate : NSObject <WKNavigationDelegate>
161 @end
162
163 @implementation ConvertResponseToDownloadNavigationDelegate
164 - (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
165 {
166     decisionHandler(_WKNavigationResponsePolicyBecomeDownload);
167 }
168 @end
169
170 TEST(_WKDownload, ConvertResponseToDownload)
171 {
172     runTest(adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]).get(), adoptNS([[DownloadDelegate alloc] init]).get(), sourceURL);
173 }
174
175 @interface FailingDownloadDelegate : NSObject <_WKDownloadDelegate>
176 @end
177
178 @implementation FailingDownloadDelegate
179
180 - (void)_downloadDidFinish:(_WKDownload *)download
181 {
182     EXPECT_TRUE(false);
183     isDone = true;
184 }
185
186 - (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
187 {
188     isDone = true;
189 }
190
191 - (void)_downloadDidCancel:(_WKDownload *)download
192 {
193     EXPECT_TRUE(false);
194     isDone = true;
195 }
196
197 @end
198
199 TEST(_WKDownload, DownloadMissingResource)
200 {
201     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[FailingDownloadDelegate alloc] init]).get(), [NSURL URLWithString:@"non-existant-scheme://"]);
202 }
203
204 @interface CancelledDownloadDelegate : NSObject <_WKDownloadDelegate>
205 @end
206
207 @implementation CancelledDownloadDelegate
208
209 - (void)_downloadDidStart:(_WKDownload *)download
210 {
211     [download cancel];
212 }
213
214 - (void)_downloadDidFinish:(_WKDownload *)download
215 {
216     EXPECT_TRUE(false);
217     isDone = true;
218 }
219
220 - (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
221 {
222     EXPECT_TRUE(false);
223     isDone = true;
224 }
225
226 - (void)_downloadDidCancel:(_WKDownload *)download
227 {
228     isDone = true;
229 }
230
231 @end
232
233 TEST(_WKDownload, CancelDownload)
234 {
235     runTest(adoptNS([[DownloadNavigationDelegate alloc] init]).get(), adoptNS([[CancelledDownloadDelegate alloc] init]).get(), sourceURL);
236 }
237
238 @interface OriginatingWebViewDownloadDelegate : NSObject <_WKDownloadDelegate>
239 - (instancetype)initWithWebView:(WKWebView *)webView;
240 @end
241
242 @implementation OriginatingWebViewDownloadDelegate {
243     RetainPtr<WKWebView> _webView;
244 }
245
246 - (instancetype)initWithWebView:(WKWebView *)webView
247 {
248     if (!(self = [super init]))
249         return nil;
250
251     _webView = webView;
252     return self;
253 }
254
255 - (void)_downloadDidStart:(_WKDownload *)download
256 {
257     EXPECT_EQ([download originatingWebView], _webView);
258     _webView = nullptr;
259
260     WTF::callOnMainThread([download = retainPtr(download)] {
261         EXPECT_NULL([download originatingWebView]);
262         isDone = true;
263     });
264 }
265
266 @end
267
268 TEST(_WKDownload, OriginatingWebView)
269 {
270     RetainPtr<DownloadNavigationDelegate> navigationDelegate = adoptNS([[DownloadNavigationDelegate alloc] init]);                 
271     RetainPtr<OriginatingWebViewDownloadDelegate> downloadDelegate;
272     @autoreleasepool {
273         RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
274         [webView setNavigationDelegate:navigationDelegate.get()];
275         downloadDelegate = adoptNS([[OriginatingWebViewDownloadDelegate alloc] initWithWebView:webView.get()]);
276         [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
277         [webView loadRequest:[NSURLRequest requestWithURL:sourceURL]];
278     }
279
280     isDone = false;
281     TestWebKitAPI::Util::run(&isDone);
282 }
283
284 @interface DownloadRequestOriginalURLDelegate : NSObject <_WKDownloadDelegate>
285 - (instancetype)initWithExpectedOriginalURL:(NSURL *)expectOriginalURL;
286 @end
287
288 @implementation DownloadRequestOriginalURLDelegate {
289     NSURL *_expectedOriginalURL;
290 }
291
292 - (instancetype)initWithExpectedOriginalURL:(NSURL *)expectedOriginalURL
293 {
294     if (!(self = [super init]))
295         return nil;
296
297     _expectedOriginalURL = expectedOriginalURL;
298     return self;
299 }
300
301 - (void)_downloadDidStart:(_WKDownload *)download
302 {
303     if ([_expectedOriginalURL isEqual:sourceURL])
304         EXPECT_TRUE(!download.request.mainDocumentURL);
305     else
306         EXPECT_TRUE([_expectedOriginalURL isEqual:download.request.mainDocumentURL]);
307     isDone = true;
308 }
309
310 @end
311
312 @interface DownloadRequestOriginalURLNavigationDelegate : NSObject <WKNavigationDelegate>
313 @end
314
315 @implementation DownloadRequestOriginalURLNavigationDelegate
316 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
317 {
318     if ([navigationAction.request.URL isEqual:sourceURL])
319         decisionHandler(_WKNavigationActionPolicyDownload);
320     else
321         decisionHandler(WKNavigationActionPolicyAllow);
322 }
323 @end
324
325 TEST(_WKDownload, DownloadRequestOriginalURL)
326 {
327     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestOriginalURL" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
328     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:originalURL]).get(), originalURL);
329 }
330
331 TEST(_WKDownload, DownloadRequestOriginalURLFrame)
332 {
333     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestOriginalURL2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
334     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:originalURL]).get(), originalURL);
335 }
336
337 TEST(_WKDownload, DownloadRequestOriginalURLDirectDownload)
338 {
339     runTest(adoptNS([[DownloadRequestOriginalURLNavigationDelegate alloc] init]).get(), adoptNS([[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:sourceURL]).get(), sourceURL);
340 }
341
342 TEST(_WKDownload, DownloadRequestOriginalURLDirectDownloadWithLoadedContent)
343 {
344     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
345     [webView setNavigationDelegate:[[DownloadRequestOriginalURLNavigationDelegate alloc] init]];
346     [[[webView configuration] processPool] _setDownloadDelegate:[[DownloadRequestOriginalURLDelegate alloc] initWithExpectedOriginalURL:sourceURL]];
347
348     expectedUserInitiatedState = false;
349     NSURL *contentURL = [[NSBundle mainBundle] URLForResource:@"simple2" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
350     // Here is to test if the original URL can be set correctly when the current document
351     // is completely unrelated to the download.
352     [webView loadRequest:[NSURLRequest requestWithURL:contentURL]];
353     [webView loadRequest:[NSURLRequest requestWithURL:sourceURL]];
354     isDone = false;
355     TestWebKitAPI::Util::run(&isDone);
356 }
357
358 @interface BlobDownloadDelegate : NSObject <_WKDownloadDelegate>
359 @end
360
361 @implementation BlobDownloadDelegate {
362     RetainPtr<_WKDownload> _download;
363     String _destinationPath;
364     long long _expectedContentLength;
365     uint64_t _receivedContentLength;
366 }
367
368 - (void)_downloadDidStart:(_WKDownload *)download
369 {
370     EXPECT_NULL(_download);
371     EXPECT_NOT_NULL(download);
372     EXPECT_TRUE([[[[download request] URL] scheme] isEqualToString:@"blob"]);
373     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
374     _download = download;
375 }
376
377 - (void)_download:(_WKDownload *)download didReceiveResponse:(NSURLResponse *)response
378 {
379     hasReceivedResponse = true;
380     EXPECT_EQ(_download, download);
381     EXPECT_EQ(_expectedContentLength, 0U);
382     EXPECT_EQ(_receivedContentLength, 0U);
383     EXPECT_TRUE([[[response URL] scheme] isEqualToString:@"blob"]);
384     _expectedContentLength = [response expectedContentLength];
385 }
386
387 - (void)_download:(_WKDownload *)download didReceiveData:(uint64_t)length
388 {
389     EXPECT_EQ(_download, download);
390     _receivedContentLength += length;
391 }
392
393 IGNORE_WARNINGS_BEGIN("deprecated-implementations")
394 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
395 IGNORE_WARNINGS_END
396 {
397     EXPECT_TRUE(hasReceivedResponse);
398     EXPECT_EQ(_download, download);
399
400     WebCore::FileSystem::PlatformFileHandle fileHandle;
401     _destinationPath = WebCore::FileSystem::openTemporaryFile("TestWebKitAPI", fileHandle);
402     EXPECT_TRUE(fileHandle != WebCore::FileSystem::invalidPlatformFileHandle);
403     WebCore::FileSystem::closeFile(fileHandle);
404
405     *allowOverwrite = YES;
406     return _destinationPath;
407 }
408
409 - (void)_downloadDidFinish:(_WKDownload *)download
410 {
411     EXPECT_EQ(_download, download);
412     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
413     EXPECT_TRUE(_expectedContentLength == NSURLResponseUnknownLength || static_cast<uint64_t>(_expectedContentLength) == _receivedContentLength);
414     NSString* expectedContent = @"{\"x\":42,\"s\":\"hello, world\"}";
415     NSData* expectedData = [expectedContent dataUsingEncoding:NSUTF8StringEncoding];
416     EXPECT_TRUE([[[NSFileManager defaultManager] contentsAtPath:_destinationPath] isEqualToData:expectedData]);
417     WebCore::FileSystem::deleteFile(_destinationPath);
418     isDone = true;
419 }
420
421 @end
422
423 @interface DownloadBlobURLNavigationDelegate : NSObject <WKNavigationDelegate>
424 @end
425
426 @implementation DownloadBlobURLNavigationDelegate
427 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
428 {
429     if ([navigationAction.request.URL.scheme isEqualToString:@"blob"])
430         decisionHandler(_WKNavigationActionPolicyDownload);
431     else
432         decisionHandler(WKNavigationActionPolicyAllow);
433 }
434 @end
435
436 TEST(_WKDownload, DownloadRequestBlobURL)
437 {
438     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"DownloadRequestBlobURL" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
439     runTest(adoptNS([[DownloadBlobURLNavigationDelegate alloc] init]).get(), adoptNS([[BlobDownloadDelegate alloc] init]).get(), originalURL);
440 }
441
442 @interface RedirectedDownloadDelegate : NSObject <_WKDownloadDelegate>
443 @end
444
445 @implementation RedirectedDownloadDelegate {
446     String _destinationPath;
447 }
448
449 - (void)_downloadDidStart:(_WKDownload *)download
450 {
451     EXPECT_NOT_NULL(download);
452     EXPECT_EQ(expectedOriginatingWebView, download.originatingWebView);
453     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
454 }
455
456 IGNORE_WARNINGS_BEGIN("deprecated-implementations")
457 - (NSString *)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename allowOverwrite:(BOOL *)allowOverwrite
458 IGNORE_WARNINGS_END
459 {
460     WebCore::FileSystem::PlatformFileHandle fileHandle;
461     _destinationPath = WebCore::FileSystem::openTemporaryFile("TestWebKitAPI", fileHandle);
462     EXPECT_TRUE(fileHandle != WebCore::FileSystem::invalidPlatformFileHandle);
463     WebCore::FileSystem::closeFile(fileHandle);
464     *allowOverwrite = YES;
465     return _destinationPath;
466 }
467
468 - (void)_download:(_WKDownload *)download didReceiveServerRedirectToURL:(NSURL *)url
469 {
470     if (!redirectCount)
471         EXPECT_STREQ("http://redirect/?pass", [url.absoluteString UTF8String]);
472     else
473         EXPECT_STREQ("http://pass/", [url.absoluteString UTF8String]);
474     ++redirectCount = true;
475 }
476
477 - (void)_downloadDidFinish:(_WKDownload *)download
478 {
479     EXPECT_EQ(expectedUserInitiatedState, download.wasUserInitiated);
480
481     NSArray<NSURL *> *redirectChain = download.redirectChain;
482     EXPECT_EQ(3U, redirectChain.count);
483     if (redirectChain.count > 0)
484         EXPECT_STREQ("http://redirect/?redirect/?pass", [redirectChain[0].absoluteString UTF8String]);
485     if (redirectChain.count > 1)
486         EXPECT_STREQ("http://redirect/?pass", [redirectChain[1].absoluteString UTF8String]);
487     if (redirectChain.count > 2)
488         EXPECT_STREQ("http://pass/", [redirectChain[2].absoluteString UTF8String]);
489
490     WebCore::FileSystem::deleteFile(_destinationPath);
491     isDone = true;
492 }
493
494 @end
495
496 TEST(_WKDownload, RedirectedDownload)
497 {
498     [TestProtocol registerWithScheme:@"http"];
499
500     redirectCount = 0;
501     isDone = false;
502
503     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
504     auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, 800, 600) configuration:configuration.get()]);
505     auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
506     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
507
508     // Do 2 loads in the same view to make sure the redirect chain is properly cleared between loads.
509     [webView synchronouslyLoadHTMLString:@"<div>First load</div>"];
510     [webView synchronouslyLoadHTMLString:@"<a id='link' href='http://redirect/?redirect/?pass'>test</a>"];
511
512     expectedOriginatingWebView = webView.get();
513     expectedUserInitiatedState = true;
514
515     auto navigationDelegate = adoptNS([[DownloadNavigationDelegate alloc] init]);
516     [webView setNavigationDelegate:navigationDelegate.get()];
517     [webView objectByEvaluatingJavaScriptWithUserGesture:@"document.getElementById('link').click();"];
518
519     isDone = false;
520     TestWebKitAPI::Util::run(&isDone);
521     EXPECT_EQ(1U, redirectCount);
522
523     [TestProtocol unregister];
524 }
525
526 TEST(_WKDownload, RedirectedLoadConvertedToDownload)
527 {
528     [TestProtocol registerWithScheme:@"http"];
529
530     auto navigationDelegate = adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]);
531     auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
532
533     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
534     [webView setNavigationDelegate:navigationDelegate.get()];
535     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
536
537     expectedOriginatingWebView = webView.get();
538     expectedUserInitiatedState = false;
539     isDone = false;
540     redirectCount = 0;
541     hasReceivedResponse = false;
542     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://redirect/?redirect/?pass"]]];
543     TestWebKitAPI::Util::run(&isDone);
544     EXPECT_EQ(0U, redirectCount);
545
546     [TestProtocol unregister];
547 }
548
549 TEST(_WKDownload, RedirectedSubframeLoadConvertedToDownload)
550 {
551     [TestProtocol registerWithScheme:@"http"];
552
553     auto navigationDelegate = adoptNS([[ConvertResponseToDownloadNavigationDelegate alloc] init]);
554     auto downloadDelegate = adoptNS([[RedirectedDownloadDelegate alloc] init]);
555
556     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
557     [webView setNavigationDelegate:navigationDelegate.get()];
558     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
559
560     expectedOriginatingWebView = webView.get();
561     expectedUserInitiatedState = false;
562     isDone = false;
563     redirectCount = 0;
564     hasReceivedResponse = false;
565     [webView loadHTMLString:@"<body><iframe src='http://redirect/?redirect/?pass'></iframe></body>" baseURL:nil];
566     TestWebKitAPI::Util::run(&isDone);
567     EXPECT_EQ(0U, redirectCount);
568
569     [TestProtocol unregister];
570 }
571
572 static bool downloadHasDecidedDestination;
573
574 @interface CancelDownloadWhileDecidingDestinationDelegate : NSObject <_WKDownloadDelegate>
575 @end
576
577 @implementation CancelDownloadWhileDecidingDestinationDelegate
578 - (void)_downloadDidFinish:(_WKDownload *)download
579 {
580     EXPECT_TRUE(false);
581     isDone = true;
582 }
583
584 - (void)_download:(_WKDownload *)download didFailWithError:(NSError *)error
585 {
586     EXPECT_TRUE(false);
587     isDone = true;
588 }
589
590 - (void)_downloadDidCancel:(_WKDownload *)download
591 {
592     isDone = true;
593 }
594
595 - (void)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename completionHandler:(void (^)(BOOL allowOverwrite, NSString *destination))completionHandler
596 {
597     [download cancel];
598     TestWebKitAPI::Util::run(&isDone);
599     completionHandler(YES, @"/tmp/WebKitAPITest/_WKDownload");
600     downloadHasDecidedDestination = true;
601 }
602 @end
603
604 TEST(_WKDownload, DownloadCanceledWhileDecidingDestination)
605 {
606     [TestProtocol registerWithScheme:@"http"];
607
608     auto navigationDelegate = adoptNS([[DownloadNavigationDelegate alloc] init]);
609     auto downloadDelegate = adoptNS([[CancelDownloadWhileDecidingDestinationDelegate alloc] init]);
610
611     auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)]);
612     [webView setNavigationDelegate:navigationDelegate.get()];
613     [[[webView configuration] processPool] _setDownloadDelegate:downloadDelegate.get()];
614
615     isDone = false;
616     downloadHasDecidedDestination = false;
617     [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://pass"]]];
618
619     TestWebKitAPI::Util::run(&downloadHasDecidedDestination);
620
621     [TestProtocol unregister];
622 }
623
624 @interface BlobWithUSDZExtensionDownloadDelegate : NSObject <_WKDownloadDelegate>
625 @end
626
627 @implementation BlobWithUSDZExtensionDownloadDelegate {
628     String _destinationPath;
629 }
630
631 - (void)_download:(_WKDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename completionHandler:(void (^)(BOOL allowOverwrite, NSString *destination))completionHandler
632 {
633     EXPECT_TRUE([filename hasSuffix:@".usdz"]);
634
635     WebCore::FileSystem::PlatformFileHandle fileHandle;
636     _destinationPath = WebCore::FileSystem::openTemporaryFile(filename, fileHandle);
637     EXPECT_TRUE(fileHandle != WebCore::FileSystem::invalidPlatformFileHandle);
638     WebCore::FileSystem::closeFile(fileHandle);
639
640     completionHandler(YES, _destinationPath);
641 }
642
643 - (void)_downloadDidFinish:(_WKDownload *)download
644 {
645     WebCore::FileSystem::deleteFile(_destinationPath);
646     isDone = true;
647 }
648
649 @end
650
651 TEST(_WKDownload, SystemPreviewUSDZBlobNaming)
652 {
653     NSURL *originalURL = [[NSBundle mainBundle] URLForResource:@"SystemPreviewBlobNaming" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
654     runTest(adoptNS([[DownloadBlobURLNavigationDelegate alloc] init]).get(), adoptNS([[BlobWithUSDZExtensionDownloadDelegate alloc] init]).get(), originalURL);
655 }
656
657 #endif
658 #endif