| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/web/download/crw_web_view_download.h" |
| |
| #import <WebKit/WebKit.h> |
| |
| #import "base/files/file_path.h" |
| #import "base/files/file_util.h" |
| #import "base/functional/callback_helpers.h" |
| #import "base/ios/block_types.h" |
| #import "base/strings/sys_string_conversions.h" |
| #import "base/task/thread_pool.h" |
| |
| @interface CRWWebViewDownload () <WKDownloadDelegate> |
| |
| // Request URL called for the download. |
| @property(nonatomic, strong) NSURLRequest* request; |
| |
| // Download object of a web resource. |
| @property(nonatomic, strong) WKDownload* download; |
| |
| @end |
| |
| @implementation CRWWebViewDownload { |
| BOOL _isLocalDownload; |
| } |
| |
| - (instancetype)initWithPath:(NSString*)destination |
| request:(NSURLRequest*)request |
| webview:(WKWebView*)webview |
| delegate:(id<CRWWebViewDownloadDelegate>)delegate { |
| self = [super init]; |
| if (self) { |
| self.destinationPath = destination; |
| self.request = request; |
| self.webView = webview; |
| self.delegate = delegate; |
| } |
| return self; |
| } |
| |
| - (void)startDownload { |
| if ([self.request.URL isFileURL]) { |
| [self startLocalDownload]; |
| return; |
| } |
| [self.webView startDownloadUsingRequest:self.request |
| completionHandler:^(WKDownload* download) { |
| download.delegate = self; |
| self.download = download; |
| }]; |
| } |
| |
| - (void)cancelDownload:(ProceduralBlock)completion { |
| if (_isLocalDownload) { |
| if (completion) { |
| completion(); |
| } |
| return; |
| } |
| [self.download cancel:^(NSData* resumeData) { |
| if (completion) { |
| completion(); |
| } |
| }]; |
| } |
| |
| #pragma mark - WKDownloadDelegate |
| |
| - (void)download:(WKDownload*)download |
| decideDestinationUsingResponse:(NSURLResponse*)response |
| suggestedFilename:(NSString*)suggestedFilename |
| completionHandler: |
| (void (^)(NSURL* destination))completionHandler { |
| NSURL* destinationURL = [NSURL fileURLWithPath:self.destinationPath]; |
| completionHandler(destinationURL); |
| } |
| |
| - (void)downloadDidFinish:(WKDownload*)download { |
| [self.delegate downloadDidFinish]; |
| } |
| |
| - (void)download:(WKDownload*)download |
| didFailWithError:(NSError*)error |
| resumeData:(NSData*)resumeData { |
| [self.delegate downloadDidFailWithError:error]; |
| } |
| |
| #pragma mark - Private |
| |
| // Start a `local download` which is really a copy from the request URL to the |
| // destination path. |
| - (void)startLocalDownload { |
| _isLocalDownload = YES; |
| __weak __typeof(self) weakSelf = self; |
| base::FilePath sourcePath(base::SysNSStringToUTF8(self.request.URL.path)); |
| base::FilePath destPath(base::SysNSStringToUTF8(self.destinationPath)); |
| |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, |
| {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, |
| base::BindOnce(&base::CopyFile, sourcePath, destPath), |
| base::BindOnce(^(bool result) { |
| if (result) { |
| [weakSelf.delegate downloadDidFinish]; |
| } else { |
| NSError* error = [NSError errorWithDomain:NSCocoaErrorDomain |
| code:NSFileReadUnknownError |
| userInfo:nil]; |
| [weakSelf.delegate downloadDidFailWithError:error]; |
| } |
| })); |
| } |
| |
| @end |