1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "components/update_client/background_downloader_mac_delegate.h"
#import <Foundation/Foundation.h>
#include <cstdint>
#include "base/apple/foundation_util.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/callback.h"
#include "base/hash/hash.h"
#include "base/logging.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "components/update_client/update_client_errors.h"
#include "url/gurl.h"
@implementation UpdateClientDownloadDelegate {
base::FilePath _download_cache;
UpdateClientDelegateDownloadCompleteCallback _download_complete_callback;
UpdateClientDelegateMetricsCollectedCallback _metrics_collected_callback;
UpdateClientDelegateDownloadProgressCallback _progress_callback;
scoped_refptr<base::SequencedTaskRunner> _callback_runner;
}
- (instancetype)
initWithDownloadCache:(base::FilePath)downloadCache
downloadCompleteCallback:
(UpdateClientDelegateDownloadCompleteCallback)downloadCompleteCallback
metricsCollectedCallback:
(UpdateClientDelegateMetricsCollectedCallback)metricsCollectedCallback
progressCallback:
(UpdateClientDelegateDownloadProgressCallback)progressCallback {
if (self = [super init]) {
_download_cache = downloadCache;
_download_complete_callback = downloadCompleteCallback;
_metrics_collected_callback = metricsCollectedCallback;
_progress_callback = progressCallback;
_callback_runner = base::SequencedTaskRunner::GetCurrentDefault();
}
return self;
}
- (void)endTask:(NSURLSessionTask*)task
withLocation:(std::optional<base::FilePath>)location
withError:(int)error {
_callback_runner->PostTask(
FROM_HERE,
base::BindOnce(_download_complete_callback,
update_client::GURLWithNSURL(task.originalRequest.URL),
location.value_or(base::FilePath()), error,
task.countOfBytesReceived,
task.countOfBytesExpectedToReceive));
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession*)session
downloadTask:(NSURLSessionDownloadTask*)downloadTask
didFinishDownloadingToURL:(NSURL*)location {
if (!base::PathExists(_download_cache) &&
!base::CreateDirectory(_download_cache)) {
VLOG(1) << "Failed to create download cache directory at: "
<< _download_cache;
[self endTask:downloadTask
withLocation:std::nullopt
withError:static_cast<int>(update_client::CrxDownloaderError::
MAC_BG_CANNOT_CREATE_DOWNLOAD_CACHE)];
return;
}
const base::FilePath temp_path =
base::apple::NSStringToFilePath(location.path);
base::FilePath cache_path =
_download_cache.Append(update_client::URLToFilename(
update_client::GURLWithNSURL(downloadTask.originalRequest.URL)));
if (!base::Move(temp_path, cache_path)) {
DVLOG(1)
<< "Failed to move the downloaded file from the temporary location: "
<< temp_path << " to: " << cache_path;
[self endTask:downloadTask
withLocation:std::nullopt
withError:static_cast<int>(update_client::CrxDownloaderError::
MAC_BG_MOVE_TO_CACHE_FAIL)];
return;
}
[self endTask:downloadTask
withLocation:cache_path
withError:static_cast<int>(update_client::CrxDownloaderError::NONE)];
}
- (void)URLSession:(NSURLSession*)session
downloadTask:(nonnull NSURLSessionDownloadTask*)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
if (bytesWritten > 0) {
_callback_runner->PostTask(
FROM_HERE, base::BindOnce(_progress_callback,
update_client::GURLWithNSURL(
downloadTask.originalRequest.URL)));
}
}
#pragma mark - NSURLSessionDelegate
- (void)URLSession:(NSURLSession*)session
task:(nonnull NSURLSessionTask*)task
didCompleteWithError:(nullable NSError*)error {
if (error) {
[self endTask:task withLocation:std::nullopt withError:error.code];
}
}
- (void)URLSession:(NSURLSession*)session
task:(NSURLSessionTask*)task
didFinishCollectingMetrics:(NSURLSessionTaskMetrics*)metrics {
_callback_runner->PostTask(
FROM_HERE,
base::BindOnce(_metrics_collected_callback,
update_client::GURLWithNSURL(task.originalRequest.URL),
metrics.taskInterval.duration *
base::TimeTicks::kMillisecondsPerSecond));
}
@end
namespace update_client {
GURL GURLWithNSURL(NSURL* url) {
return url ? GURL(url.absoluteString.UTF8String) : GURL();
}
base::FilePath URLToFilename(const GURL& url) {
uint32_t hash = base::PersistentHash(url.spec());
return base::FilePath(
base::HexEncode(reinterpret_cast<uint8_t*>(&hash), sizeof(hash)));
}
} // namespace update_client
|