diff options
Diffstat (limited to 'chromium/components/download/internal')
31 files changed, 841 insertions, 140 deletions
diff --git a/chromium/components/download/internal/background_service/blob_task_proxy.cc b/chromium/components/download/internal/background_service/blob_task_proxy.cc index ab525937720..4c0813902d0 100644 --- a/chromium/components/download/internal/background_service/blob_task_proxy.cc +++ b/chromium/components/download/internal/background_service/blob_task_proxy.cc @@ -61,7 +61,7 @@ void BlobTaskProxy::SaveAsBlobOnIO(std::unique_ptr<std::string> data, // Build blob data. This has to do a copy into blob's internal storage. std::string blob_uuid = base::GenerateGUID(); auto builder = std::make_unique<storage::BlobDataBuilder>(blob_uuid); - builder->AppendData(*data.get()); + builder->AppendData(*data); blob_data_handle_ = blob_storage_context_->AddFinishedBlob(std::move(builder)); diff --git a/chromium/components/download/internal/background_service/controller_impl.cc b/chromium/components/download/internal/background_service/controller_impl.cc index 5b602187936..2150eca0b17 100644 --- a/chromium/components/download/internal/background_service/controller_impl.cc +++ b/chromium/components/download/internal/background_service/controller_impl.cc @@ -1051,7 +1051,7 @@ void ControllerImpl::KillTimedOutUploads() { void ControllerImpl::NotifyClientsOfStartup(bool state_lost) { auto categorized = util::MapEntriesToMetadataForClients( - clients_->GetRegisteredClients(), model_->PeekEntries()); + clients_->GetRegisteredClients(), model_->PeekEntries(), driver_.get()); for (auto client_id : clients_->GetRegisteredClients()) { base::ThreadTaskRunnerHandle::Get()->PostTask( diff --git a/chromium/components/download/internal/background_service/controller_impl_unittest.cc b/chromium/components/download/internal/background_service/controller_impl_unittest.cc index 66d8ff523da..1e4f96bab34 100644 --- a/chromium/components/download/internal/background_service/controller_impl_unittest.cc +++ b/chromium/components/download/internal/background_service/controller_impl_unittest.cc @@ -437,8 +437,8 @@ TEST_F(DownloadServiceControllerImplTest, SuccessfulInitWithExistingDownload) { std::vector<Entry> entries = {entry1, entry2, entry3}; std::vector<DownloadMetaData> expected_downloads = { - util::BuildDownloadMetaData(&entry1), - util::BuildDownloadMetaData(&entry2)}; + util::BuildDownloadMetaData(&entry1, driver_), + util::BuildDownloadMetaData(&entry2, driver_)}; EXPECT_CALL(*client_, OnServiceInitialized(false, testing::UnorderedElementsAreArray( diff --git a/chromium/components/download/internal/background_service/entry_utils.cc b/chromium/components/download/internal/background_service/entry_utils.cc index 8738cb02350..4402d4c9647 100644 --- a/chromium/components/download/internal/background_service/entry_utils.cc +++ b/chromium/components/download/internal/background_service/entry_utils.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "components/download/internal/background_service/download_driver.h" #include "components/download/internal/background_service/entry.h" #include "components/download/public/background_service/download_metadata.h" @@ -24,7 +25,8 @@ uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client, std::map<DownloadClient, std::vector<DownloadMetaData>> MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients, - const std::vector<Entry*>& entries) { + const std::vector<Entry*>& entries, + DownloadDriver* driver) { std::map<DownloadClient, std::vector<DownloadMetaData>> categorized; for (auto* entry : entries) { @@ -32,7 +34,7 @@ MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients, if (clients.find(client) == clients.end()) client = DownloadClient::INVALID; - categorized[client].push_back(BuildDownloadMetaData(entry)); + categorized[client].push_back(BuildDownloadMetaData(entry, driver)); } return categorized; @@ -86,14 +88,22 @@ bool EntryBetterThan(const Entry& lhs, const Entry& rhs) { return lhs.create_time < rhs.create_time; } -DownloadMetaData BuildDownloadMetaData(Entry* entry) { +DownloadMetaData BuildDownloadMetaData(Entry* entry, DownloadDriver* driver) { DCHECK(entry); DownloadMetaData meta_data; meta_data.guid = entry->guid; if (entry->state == Entry::State::COMPLETE) { meta_data.completion_info = CompletionInfo(entry->target_file_path, entry->bytes_downloaded); + // If the download is completed, the |current_size| needs to pull from entry + // since the history db record has been deleted. + meta_data.current_size = entry->bytes_downloaded; + return meta_data; } + + auto driver_entry = driver->Find(entry->guid); + if (driver_entry) + meta_data.current_size = driver_entry->bytes_downloaded; return meta_data; } diff --git a/chromium/components/download/internal/background_service/entry_utils.h b/chromium/components/download/internal/background_service/entry_utils.h index 410383c50b6..a519d759e24 100644 --- a/chromium/components/download/internal/background_service/entry_utils.h +++ b/chromium/components/download/internal/background_service/entry_utils.h @@ -17,6 +17,7 @@ namespace download { +class DownloadDriver; struct DownloadMetaData; struct Entry; @@ -35,7 +36,8 @@ uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client, // not be included. std::map<DownloadClient, std::vector<DownloadMetaData>> MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients, - const std::vector<Entry*>& entries); + const std::vector<Entry*>& entries, + DownloadDriver* driver); // Gets the least strict scheduling criteria from |entries|, the criteria is // used to schedule platform background tasks. @@ -46,8 +48,9 @@ Criteria GetSchedulingCriteria(const Model::EntryList& entries, // |rhs| based on their priority and cancel time. bool EntryBetterThan(const Entry& lhs, const Entry& rhs); -// Builds a download meta data based on |entry|. -DownloadMetaData BuildDownloadMetaData(Entry* entry); +// Builds a download meta data based on |entry| and the states from |driver| in +// the history db. +DownloadMetaData BuildDownloadMetaData(Entry* entry, DownloadDriver* driver); } // namespace util } // namespace download diff --git a/chromium/components/download/internal/background_service/entry_utils_unittest.cc b/chromium/components/download/internal/background_service/entry_utils_unittest.cc index fda16a7f2a8..75f36afc8be 100644 --- a/chromium/components/download/internal/background_service/entry_utils_unittest.cc +++ b/chromium/components/download/internal/background_service/entry_utils_unittest.cc @@ -7,6 +7,7 @@ #include <algorithm> #include "components/download/internal/background_service/test/entry_utils.h" +#include "components/download/internal/background_service/test/test_download_driver.h" #include "components/download/public/background_service/clients.h" #include "components/download/public/background_service/download_metadata.h" #include "testing/gtest/include/gtest/gtest.h" @@ -35,21 +36,23 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) { Entry entry5 = test::BuildBasicEntry(Entry::State::AVAILABLE); std::vector<Entry*> entries = {&entry1, &entry2, &entry3, &entry4, &entry5}; + test::TestDownloadDriver driver; std::vector<DownloadMetaData> expected_list = { - util::BuildDownloadMetaData(&entry1), - util::BuildDownloadMetaData(&entry2), - util::BuildDownloadMetaData(&entry3), - util::BuildDownloadMetaData(&entry4), - util::BuildDownloadMetaData(&entry5)}; + util::BuildDownloadMetaData(&entry1, &driver), + util::BuildDownloadMetaData(&entry2, &driver), + util::BuildDownloadMetaData(&entry3, &driver), + util::BuildDownloadMetaData(&entry4, &driver), + util::BuildDownloadMetaData(&entry5, &driver)}; std::vector<DownloadMetaData> expected_pruned_list = { - util::BuildDownloadMetaData(&entry1), - util::BuildDownloadMetaData(&entry2), - util::BuildDownloadMetaData(&entry3), - util::BuildDownloadMetaData(&entry5)}; + util::BuildDownloadMetaData(&entry1, &driver), + util::BuildDownloadMetaData(&entry2, &driver), + util::BuildDownloadMetaData(&entry3, &driver), + util::BuildDownloadMetaData(&entry5, &driver)}; + // If DownloadClient::TEST isn't a valid Client, all of the associated entries // should move to the DownloadClient::INVALID bucket. - auto mapped1 = - util::MapEntriesToMetadataForClients(std::set<DownloadClient>(), entries); + auto mapped1 = util::MapEntriesToMetadataForClients( + std::set<DownloadClient>(), entries, &driver); EXPECT_EQ(1U, mapped1.size()); EXPECT_NE(mapped1.end(), mapped1.find(DownloadClient::INVALID)); EXPECT_EQ(mapped1.end(), mapped1.find(DownloadClient::TEST)); @@ -62,7 +65,8 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) { // If DownloadClient::TEST is a valid Client, it should have the associated // entries. std::set<DownloadClient> clients = {DownloadClient::TEST}; - auto mapped2 = util::MapEntriesToMetadataForClients(clients, entries); + auto mapped2 = + util::MapEntriesToMetadataForClients(clients, entries, &driver); EXPECT_EQ(1U, mapped2.size()); EXPECT_NE(mapped2.end(), mapped2.find(DownloadClient::TEST)); EXPECT_EQ(mapped2.end(), mapped2.find(DownloadClient::INVALID)); @@ -136,15 +140,22 @@ TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaData) { Entry entry = test::BuildBasicEntry(Entry::State::PAUSED); entry.target_file_path = base::FilePath::FromUTF8Unsafe("123"); entry.bytes_downloaded = 200u; - auto meta_data = util::BuildDownloadMetaData(&entry); + test::TestDownloadDriver driver; + + auto meta_data = util::BuildDownloadMetaData(&entry, &driver); EXPECT_EQ(entry.guid, meta_data.guid); + // Incomplete downloads don't copy the following data. EXPECT_FALSE(meta_data.completion_info.has_value()); + // Current size is always pulled from driver, and we don't persist the current + // size in each OnDownloadUpdated call in DownloadDriver. + EXPECT_EQ(0u, meta_data.current_size); + entry = test::BuildBasicEntry(Entry::State::COMPLETE); entry.target_file_path = base::FilePath::FromUTF8Unsafe("123"); entry.bytes_downloaded = 100u; - meta_data = util::BuildDownloadMetaData(&entry); + meta_data = util::BuildDownloadMetaData(&entry, &driver); EXPECT_EQ(entry.guid, meta_data.guid); EXPECT_TRUE(meta_data.completion_info.has_value()); EXPECT_EQ(entry.target_file_path, meta_data.completion_info->path); @@ -152,4 +163,21 @@ TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaData) { meta_data.completion_info->bytes_downloaded); } +// Test to verify the current size is correctly built into the meta data. +TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaDataCurrentSize) { + Entry entry = test::BuildBasicEntry(Entry::State::PAUSED); + entry.target_file_path = base::FilePath::FromUTF8Unsafe("123"); + entry.bytes_downloaded = 0u; + + test::TestDownloadDriver driver; + DriverEntry driver_entry; + driver_entry.guid = entry.guid; + driver_entry.bytes_downloaded = 100u; + driver.AddTestData({driver_entry}); + + auto meta_data = util::BuildDownloadMetaData(&entry, &driver); + meta_data = util::BuildDownloadMetaData(&entry, &driver); + EXPECT_EQ(driver_entry.bytes_downloaded, meta_data.current_size); +} + } // namespace download diff --git a/chromium/components/download/internal/background_service/in_memory_download_driver.cc b/chromium/components/download/internal/background_service/in_memory_download_driver.cc index 99ba0970550..50eeda0460c 100644 --- a/chromium/components/download/internal/background_service/in_memory_download_driver.cc +++ b/chromium/components/download/internal/background_service/in_memory_download_driver.cc @@ -131,7 +131,7 @@ base::Optional<DriverEntry> InMemoryDownloadDriver::Find( base::Optional<DriverEntry> entry; auto it = downloads_.find(guid); if (it != downloads_.end()) - entry = CreateDriverEntry(*it->second.get()); + entry = CreateDriverEntry(*it->second); return entry; } diff --git a/chromium/components/download/internal/background_service/in_memory_download_driver.h b/chromium/components/download/internal/background_service/in_memory_download_driver.h index b1594999c72..c28df4c386e 100644 --- a/chromium/components/download/internal/background_service/in_memory_download_driver.h +++ b/chromium/components/download/internal/background_service/in_memory_download_driver.h @@ -11,6 +11,7 @@ #include <memory> #include "base/macros.h" +#include "base/single_thread_task_runner.h" #include "components/download/internal/background_service/in_memory_download.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" diff --git a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc index c89ae3a0cdc..e04ec21317e 100644 --- a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc +++ b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc @@ -44,7 +44,7 @@ class MockDelegate : public InMemoryDownload::Delegate { // InMemoryDownload::Delegate implementation. MOCK_METHOD1(OnDownloadProgress, void(InMemoryDownload*)); - void OnDownloadComplete(InMemoryDownload* download) { + void OnDownloadComplete(InMemoryDownload* download) override { if (run_loop_.running()) run_loop_.Quit(); } diff --git a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc index 18ab129af56..74ceabe5538 100644 --- a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc +++ b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc @@ -34,8 +34,7 @@ MATCHER_P(BatteryStatusEqual, value, "") { class TestNetworkChangeNotifier : public net::NetworkChangeNotifier { public: TestNetworkChangeNotifier() - : net::NetworkChangeNotifier(), - conn_type_(ConnectionType::CONNECTION_UNKNOWN) {} + : conn_type_(ConnectionType::CONNECTION_UNKNOWN) {} // net::NetworkChangeNotifier implementation. ConnectionType GetCurrentConnectionType() const override { @@ -129,7 +128,7 @@ class DeviceStatusListenerTest : public testing::Test { // Simulates a network change call, the event will be sent to client // immediately. void ChangeNetworkTypeImmediately(ConnectionType type) { - DCHECK(listener_.get()); + DCHECK(listener_); static_cast<NetworkStatusListener::Observer*>(listener_.get()) ->OnNetworkChanged(type); } diff --git a/chromium/components/download/internal/common/BUILD.gn b/chromium/components/download/internal/common/BUILD.gn index bb3a9299559..42ed3007fc8 100644 --- a/chromium/components/download/internal/common/BUILD.gn +++ b/chromium/components/download/internal/common/BUILD.gn @@ -14,7 +14,6 @@ source_set("internal") { sources = [ "base_file.cc", - "base_file_posix.cc", "base_file_win.cc", "download_create_info.cc", "download_file_factory.cc", @@ -35,12 +34,14 @@ source_set("internal") { "download_utils.cc", "download_worker.cc", "download_worker.h", + "in_progress_download_manager.cc", "parallel_download_job.cc", "parallel_download_job.h", "parallel_download_utils.cc", "parallel_download_utils.h", "rate_estimator.cc", "resource_downloader.cc", + "resource_downloader.h", "save_package_download_job.cc", "save_package_download_job.h", "stream_handle_input_stream.cc", @@ -61,6 +62,10 @@ source_set("internal") { "//services/metrics/public/cpp:ukm_builders", "//services/network/public/cpp", ] + + if (is_posix || is_fuchsia) { + sources += [ "base_file_posix.cc" ] + } } # tests need to access both public and internal sources. So in the component diff --git a/chromium/components/download/internal/common/DEPS b/chromium/components/download/internal/common/DEPS index 65c70055f64..a5df1addd5a 100644 --- a/chromium/components/download/internal/common/DEPS +++ b/chromium/components/download/internal/common/DEPS @@ -6,10 +6,12 @@ include_rules = [ "+components/ukm/test_ukm_recorder.h", "+crypto", "+mojo/public/c/system", + "+mojo/public/cpp/bindings", "+net/base/filename_util.h", "+net/base/load_flags.h", "+net/base/io_buffer.h", "+net/base/net_errors.h", + "+net/cert/cert_status_flags.h", "+net/http/http_content_disposition.h", "+net/http/http_request_headers.h", "+net/http/http_response_headers.h", @@ -18,4 +20,5 @@ include_rules = [ "+net/traffic_annotation/network_traffic_annotation.h", "+services/metrics/public/cpp", "+services/network/public/cpp", + "+services/network/public/mojom", ] diff --git a/chromium/components/download/internal/common/base_file.cc b/chromium/components/download/internal/common/base_file.cc index fce4f343809..03416fb14a8 100644 --- a/chromium/components/download/internal/common/base_file.cc +++ b/chromium/components/download/internal/common/base_file.cc @@ -13,6 +13,7 @@ #include "base/format_macros.h" #include "base/logging.h" #include "base/macros.h" +#include "base/numerics/safe_conversions.h" #include "base/pickle.h" #include "base/strings/stringprintf.h" #include "base/threading/thread_restrictions.h" @@ -137,14 +138,6 @@ DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset, // belong to the same download will be grouped together. CONDITIONAL_TRACE( NESTABLE_ASYNC_BEGIN0("download", "DownloadFileWrite", download_id_)); - int write_result = file_.Write(offset, data, data_len); - DCHECK_NE(0, write_result); - - // Report errors on file writes. - if (write_result < 0) - return LogSystemError("Write", logging::GetLastSystemErrorCode()); - - DCHECK_EQ(static_cast<size_t>(write_result), data_len); if (bytes_so_far_ != offset) { // A hole is created in the file. @@ -152,7 +145,28 @@ DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset, secure_hash_.reset(); } - bytes_so_far_ += data_len; + // Writes to the file. + int64_t len = base::saturated_cast<int64_t>(data_len); + const char* current_data = data; + int64_t current_offset = offset; + while (len > 0) { + // |write_result| may be less than |len|, and return an error on the next + // write call when the disk is unavaliable. + int write_result = file_.Write(current_offset, current_data, len); + DCHECK_NE(0, write_result); + + // Report errors on file writes. + if (write_result < 0) + return LogSystemError("Write", logging::GetLastSystemErrorCode()); + + // Update status. + DCHECK_LE(write_result, len); + len -= write_result; + current_data += write_result; + current_offset += write_result; + bytes_so_far_ += write_result; + } + CONDITIONAL_TRACE(NESTABLE_ASYNC_END1("download", "DownloadFileWrite", download_id_, "bytes", data_len)); diff --git a/chromium/components/download/internal/common/base_file_win.cc b/chromium/components/download/internal/common/base_file_win.cc index df78b6956d5..11796902e9a 100644 --- a/chromium/components/download/internal/common/base_file_win.cc +++ b/chromium/components/download/internal/common/base_file_win.cc @@ -257,25 +257,22 @@ DownloadInterruptReason MapShFileOperationCodes(int code) { if (result == DOWNLOAD_INTERRUPT_REASON_FILE_FAILED) { UMA_HISTOGRAM_CUSTOM_ENUMERATION( "Download.MapWinShErrorFileFailed", code, - base::CustomHistogram::ArrayToCustomRanges( - kAllSpecialShFileOperationCodes, - arraysize(kAllSpecialShFileOperationCodes))); + base::CustomHistogram::ArrayToCustomEnumRanges( + kAllSpecialShFileOperationCodes)); } if (result == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED) { UMA_HISTOGRAM_CUSTOM_ENUMERATION( "Download.MapWinShErrorAccessDenied", code, - base::CustomHistogram::ArrayToCustomRanges( - kAllSpecialShFileOperationCodes, - arraysize(kAllSpecialShFileOperationCodes))); + base::CustomHistogram::ArrayToCustomEnumRanges( + kAllSpecialShFileOperationCodes)); } if (result == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR) { UMA_HISTOGRAM_CUSTOM_ENUMERATION( "Download.MapWinShErrorTransientError", code, - base::CustomHistogram::ArrayToCustomRanges( - kAllSpecialShFileOperationCodes, - arraysize(kAllSpecialShFileOperationCodes))); + base::CustomHistogram::ArrayToCustomEnumRanges( + kAllSpecialShFileOperationCodes)); } if (result != DOWNLOAD_INTERRUPT_REASON_NONE) @@ -302,7 +299,7 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions( source.append(1, L'\0'); target.append(1, L'\0'); - SHFILEOPSTRUCT move_info = {0}; + SHFILEOPSTRUCT move_info = {nullptr}; move_info.wFunc = FO_MOVE; move_info.pFrom = source.c_str(); move_info.pTo = target.c_str(); diff --git a/chromium/components/download/internal/common/download_file_impl.cc b/chromium/components/download/internal/common/download_file_impl.cc index 7acae0764dd..05d8f7c5c19 100644 --- a/chromium/components/download/internal/common/download_file_impl.cc +++ b/chromium/components/download/internal/common/download_file_impl.cc @@ -9,7 +9,7 @@ #include "base/bind.h" #include "base/files/file_util.h" -#include "base/message_loop/message_loop.h" +#include "base/message_loop/message_loop_current.h" #include "base/strings/stringprintf.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/time/time.h" @@ -147,7 +147,7 @@ DownloadFileImpl::DownloadFileImpl( bytes_seen_without_parallel_streams_(0), is_paused_(false), download_id_(download_id), - main_task_runner_(base::MessageLoop::current()->task_runner()), + main_task_runner_(base::MessageLoopCurrent::Get()->task_runner()), observer_(observer), weak_factory_(this) { TRACE_EVENT_INSTANT0("download", "DownloadFileCreated", @@ -229,7 +229,7 @@ void DownloadFileImpl::AddInputStream(std::unique_ptr<InputStream> stream, CancelRequest(offset); return; } - + DCHECK(source_streams_.find(offset) == source_streams_.end()); source_streams_[offset] = std::make_unique<SourceStream>(offset, length, std::move(stream)); OnSourceStreamAdded(source_streams_[offset].get()); @@ -504,7 +504,7 @@ void DownloadFileImpl::StreamActive(SourceStream* source_stream, DCHECK_GE(incoming_data_size, bytes_to_write); reason = WriteDataToFile( source_stream->offset() + source_stream->bytes_written(), - incoming_data.get()->data(), bytes_to_write); + incoming_data->data(), bytes_to_write); disk_writes_time_ += (base::TimeTicks::Now() - write_start); bytes_seen_ += bytes_to_write; total_incoming_data_size += bytes_to_write; diff --git a/chromium/components/download/internal/common/download_file_unittest.cc b/chromium/components/download/internal/common/download_file_unittest.cc index 91c9d212691..f0f2204d6a5 100644 --- a/chromium/components/download/internal/common/download_file_unittest.cc +++ b/chromium/components/download/internal/common/download_file_unittest.cc @@ -201,7 +201,7 @@ class DownloadFileTest : public testing::Test { bool calculate_hash, const DownloadItem::ReceivedSlices& received_slices) { // There can be only one. - DCHECK(!download_file_.get()); + DCHECK(!download_file_); input_stream_ = new StrictMock<MockInputStream>(); @@ -721,8 +721,8 @@ void TestRenameCompletionCallback(const base::Closure& closure, // succeed. // // Note that there is only one queue of tasks to run, and that is in the tests' -// base::MessageLoop::current(). Each RunLoop processes that queue until it sees -// a QuitClosure() targeted at itself, at which point it stops processing. +// base::MessageLoopCurrent::Get(). Each RunLoop processes that queue until it +// sees a QuitClosure() targeted at itself, at which point it stops processing. TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) { ASSERT_TRUE(CreateDownloadFile(0, true)); base::FilePath initial_path(download_file_->FullPath()); @@ -1042,8 +1042,8 @@ TEST_F(DownloadFileTest, SecondStreamStartingOffsetAlreadyWritten) { .RetiresOnSaturation(); download_file_->AddInputStream( - std::unique_ptr<MockInputStream>(additional_streams_[0]), 0, - DownloadSaveInfo::kLengthFullContent); + std::unique_ptr<MockInputStream>(additional_streams_[0]), + strlen(kTestData1), DownloadSaveInfo::kLengthFullContent); // The stream should get terminated and reset the callback. EXPECT_TRUE(sink_callback_.is_null()); diff --git a/chromium/components/download/internal/common/download_item_impl.cc b/chromium/components/download/internal/common/download_item_impl.cc index 7181a2ca5c8..817deacd108 100644 --- a/chromium/components/download/internal/common/download_item_impl.cc +++ b/chromium/components/download/internal/common/download_item_impl.cc @@ -147,6 +147,8 @@ std::string GetDownloadDangerNames(DownloadDangerType type) { return "DANGEROUS_HOST"; case DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: return "POTENTIALLY_UNWANTED"; + case DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY: + return "WHITELISTED_BY_POLICY"; default: NOTREACHED(); return "UNKNOWN_DANGER_TYPE"; @@ -418,7 +420,7 @@ DownloadItemImpl::~DownloadItemImpl() { // Should always have been nuked before now, at worst in // DownloadManager shutdown. - DCHECK(!download_file_.get()); + DCHECK(!download_file_); CHECK(!is_updating_observers_); for (auto& observer : observers_) @@ -957,6 +959,11 @@ bool DownloadItemImpl::IsTransient() const { return transient_; } +bool DownloadItemImpl::IsParallelDownload() const { + bool is_parallelizable = job_ ? job_->IsParallelizable() : false; + return is_parallelizable && download::IsParallelDownloadEnabled(); +} + void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type, DownloadInterruptReason reason) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -1040,7 +1047,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const { IsPaused() ? 'T' : 'F', DebugResumeModeString(GetResumeMode()), auto_resume_count_, GetDangerType(), AllDataSaved() ? 'T' : 'F', GetLastModifiedTime().c_str(), GetETag().c_str(), - download_file_.get() ? "true" : "false", url_list.c_str(), + download_file_ ? "true" : "false", url_list.c_str(), GetFullPath().value().c_str(), GetTargetFilePath().value().c_str(), GetReferrerUrl().spec().c_str(), GetSiteUrl().spec().c_str()); } else { @@ -1383,17 +1390,18 @@ void DownloadItemImpl::Start( std::unique_ptr<DownloadFile> file, std::unique_ptr<DownloadRequestHandleInterface> req_handle, const DownloadCreateInfo& new_create_info, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, net::URLRequestContextGetter* url_request_context_getter) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!download_file_.get()); + DCHECK(!download_file_); DVLOG(20) << __func__ << "() this=" << DebugString(true); RecordDownloadCountWithSource(START_COUNT, download_source_); download_file_ = std::move(file); job_ = DownloadJobFactory::CreateJob( this, std::move(req_handle), new_create_info, false, - std::move(shared_url_loader_factory), url_request_context_getter); + std::move(url_loader_factory_getter), url_request_context_getter); if (job_->IsParallelizable()) { RecordParallelizableDownloadCount(START_COUNT, IsParallelDownloadEnabled()); } @@ -1422,23 +1430,20 @@ void DownloadItemImpl::Start( // If a resumption attempted failed, or if the download was DOA, then the // download should go back to being interrupted. if (new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) { - DCHECK(!download_file_.get()); + DCHECK(!download_file_); // Download requests that are interrupted by Start() should result in a // DownloadCreateInfo with an intact DownloadSaveInfo. DCHECK(new_create_info.save_info); - int64_t offset = new_create_info.save_info->offset; std::unique_ptr<crypto::SecureHash> hash_state = new_create_info.save_info->hash_state ? new_create_info.save_info->hash_state->Clone() : nullptr; - destination_info_.received_bytes = offset; hash_state_ = std::move(hash_state); destination_info_.hash.clear(); deferred_interrupt_reason_ = new_create_info.result; - received_slices_.clear(); TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL); DetermineDownloadTarget(); return; @@ -1473,9 +1478,8 @@ void DownloadItemImpl::Start( if (state_ == RESUMING_INTERNAL) UpdateValidatorsOnResumption(new_create_info); - // If the download is not parallel download during resumption, clear the - // |received_slices_|. - if (!job_->IsParallelizable() && !received_slices_.empty()) { + // If the download is not parallel, clear the |received_slices_|. + if (!received_slices_.empty() && !job_->IsParallelizable()) { destination_info_.received_bytes = GetMaxContiguousDataBlockSizeFromBeginning(received_slices_); received_slices_.clear(); @@ -1715,7 +1719,7 @@ void DownloadItemImpl::OnDownloadCompleting() { DCHECK(!GetTargetFilePath().empty()); DCHECK(!IsDangerous()); - DCHECK(download_file_.get()); + DCHECK(download_file_); // Unilaterally rename; even if it already has the right name, // we need theannotation. DownloadFile::RenameCompletionCallback callback = @@ -1727,7 +1731,9 @@ void DownloadItemImpl::OnDownloadCompleting() { base::Unretained(download_file_.get()), GetTargetFilePath(), delegate_->GetApplicationClientIdForFileScanning(), - GetURL(), GetReferrerUrl(), std::move(callback))); + delegate_->IsOffTheRecord() ? GURL() : GetURL(), + delegate_->IsOffTheRecord() ? GURL() : GetReferrerUrl(), + std::move(callback))); } void DownloadItemImpl::OnDownloadRenamedToFinalName( @@ -2229,7 +2235,8 @@ void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) { if ((danger_type_ == DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS || danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE || danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT || - danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) && + danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT || + danger_type_ == DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY) && (danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST || danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL || danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT || @@ -2341,6 +2348,9 @@ void DownloadItemImpl::ResumeInterruptedDownload( for (const auto& header : request_headers_) { download_params->add_request_header(header.first, header.second); } + // The offset is calculated after decompression, so the range request cannot + // involve any compression, + download_params->add_request_header("Accept-Encoding", "identity"); auto entry = delegate_->GetInProgressEntry(this); if (entry) diff --git a/chromium/components/download/internal/common/download_item_impl_unittest.cc b/chromium/components/download/internal/common/download_item_impl_unittest.cc index 8515eb822f6..1503ec33b07 100644 --- a/chromium/components/download/internal/common/download_item_impl_unittest.cc +++ b/chromium/components/download/internal/common/download_item_impl_unittest.cc @@ -66,7 +66,7 @@ base::HistogramBase::Sample ToHistogramSample(T t) { class MockDelegate : public DownloadItemImplDelegate { public: - MockDelegate() : DownloadItemImplDelegate() { SetDefaultExpectations(); } + MockDelegate() { SetDefaultExpectations(); } MOCK_METHOD2(DetermineDownloadTarget, void(DownloadItemImpl*, @@ -89,6 +89,7 @@ class MockDelegate : public DownloadItemImplDelegate { MOCK_METHOD1(DownloadOpened, void(DownloadItemImpl*)); MOCK_METHOD1(DownloadRemoved, void(DownloadItemImpl*)); MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItemImpl*)); + MOCK_CONST_METHOD0(IsOffTheRecord, bool()); void VerifyAndClearExpectations() { ::testing::Mock::VerifyAndClearExpectations(this); @@ -101,6 +102,7 @@ class MockDelegate : public DownloadItemImplDelegate { EXPECT_CALL(*this, ShouldOpenFileBasedOnExtension(_)) .WillRepeatedly(Return(false)); EXPECT_CALL(*this, ShouldOpenDownload(_, _)).WillRepeatedly(Return(true)); + EXPECT_CALL(*this, IsOffTheRecord()).WillRepeatedly(Return(false)); } }; @@ -2010,6 +2012,48 @@ TEST_F(DownloadItemTest, StealInterruptedNonContinuableDangerousDownload) { EXPECT_TRUE(returned_path.empty()); } +// Tests that for an incognito download, the target file is annotated with an +// empty source URL. +TEST_F(DownloadItemTest, AnnotationWithEmptyURLInIncognito) { + // Non-incognito case + DownloadItemImpl* item = CreateDownloadItem(); + MockDownloadFile* download_file = + DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS); + // Target file should be annotated with the source URL. + EXPECT_CALL(*download_file, + RenameAndAnnotate(_, _, create_info()->url(), _, _)) + .WillOnce(ScheduleRenameAndAnnotateCallback( + DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath), + base::ThreadTaskRunnerHandle::Get())); + EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _)) + .WillOnce(Return(true)); + EXPECT_CALL(*download_file, FullPath()) + .WillOnce(ReturnRefOfCopy(base::FilePath())); + EXPECT_CALL(*download_file, Detach()); + item->DestinationObserverAsWeakPtr()->DestinationCompleted( + 0, std::unique_ptr<crypto::SecureHash>()); + task_environment_.RunUntilIdle(); + + // Incognito case + item = CreateDownloadItem(); + download_file = + DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS); + // Target file should be annotated with an empty URL. + EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, GURL(), _, _)) + .WillOnce(ScheduleRenameAndAnnotateCallback( + DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath), + base::ThreadTaskRunnerHandle::Get())); + EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _)) + .WillOnce(Return(true)); + EXPECT_CALL(*mock_delegate(), IsOffTheRecord()).WillRepeatedly(Return(true)); + EXPECT_CALL(*download_file, FullPath()) + .WillOnce(ReturnRefOfCopy(base::FilePath())); + EXPECT_CALL(*download_file, Detach()); + item->DestinationObserverAsWeakPtr()->DestinationCompleted( + 0, std::unique_ptr<crypto::SecureHash>()); + task_environment_.RunUntilIdle(); +} + namespace { // The DownloadItemDestinationUpdateRaceTest fixture (defined below) is used to @@ -2191,8 +2235,7 @@ class DownloadItemDestinationUpdateRaceTest public ::testing::WithParamInterface<EventList> { public: DownloadItemDestinationUpdateRaceTest() - : DownloadItemTest(), - item_(CreateDownloadItem()), + : item_(CreateDownloadItem()), file_(new ::testing::StrictMock<MockDownloadFile>()), request_handle_(new ::testing::StrictMock<MockRequestHandle>()) { DCHECK_EQ(GetParam().size(), static_cast<unsigned>(kEventCount)); diff --git a/chromium/components/download/internal/common/download_job_factory.cc b/chromium/components/download/internal/common/download_job_factory.cc index b2fda04191a..c9cffbebc1b 100644 --- a/chromium/components/download/internal/common/download_job_factory.cc +++ b/chromium/components/download/internal/common/download_job_factory.cc @@ -12,7 +12,7 @@ #include "components/download/internal/common/save_package_download_job.h" #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_stats.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" namespace download { @@ -44,10 +44,12 @@ bool IsParallelizableDownload(const DownloadCreateInfo& create_info, net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1; bool http_get_method = create_info.method == "GET" && create_info.url().SchemeIsHTTPOrHTTPS(); - + bool partial_response_success = + download_item->GetReceivedSlices().empty() || create_info.offset != 0; bool is_parallelizable = has_strong_validator && create_info.accept_range && has_content_length && satisfy_min_file_size && - satisfy_connection_type && http_get_method; + satisfy_connection_type && http_get_method && + partial_response_success; if (!IsParallelDownloadEnabled()) return is_parallelizable; @@ -93,7 +95,8 @@ std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob( std::unique_ptr<DownloadRequestHandleInterface> req_handle, const DownloadCreateInfo& create_info, bool is_save_package_download, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, net::URLRequestContextGetter* url_request_context_getter) { if (is_save_package_download) { return std::make_unique<SavePackageDownloadJob>(download_item, @@ -105,7 +108,7 @@ std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob( if (IsParallelDownloadEnabled() && is_parallelizable) { return std::make_unique<ParallelDownloadJob>( download_item, std::move(req_handle), create_info, - std::move(shared_url_loader_factory), url_request_context_getter); + std::move(url_loader_factory_getter), url_request_context_getter); } // An ordinary download job. diff --git a/chromium/components/download/internal/common/download_stats.cc b/chromium/components/download/internal/common/download_stats.cc index 829b99ed9d6..fb06e932988 100644 --- a/chromium/components/download/internal/common/download_stats.cc +++ b/chromium/components/download/internal/common/download_stats.cc @@ -377,8 +377,7 @@ void RecordDownloadInterrupted(DownloadInterruptReason reason, } std::vector<base::HistogramBase::Sample> samples = - base::CustomHistogram::ArrayToCustomRanges( - kAllInterruptReasonCodes, arraysize(kAllInterruptReasonCodes)); + base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes); UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.InterruptedReason", reason, samples); diff --git a/chromium/components/download/internal/common/download_task_runner.cc b/chromium/components/download/internal/common/download_task_runner.cc index 0cc99355e32..55db38f64b6 100644 --- a/chromium/components/download/internal/common/download_task_runner.cc +++ b/chromium/components/download/internal/common/download_task_runner.cc @@ -6,6 +6,7 @@ #include "base/lazy_instance.h" #include "base/no_destructor.h" +#include "base/single_thread_task_runner.h" #include "base/synchronization/lock.h" #include "base/task_scheduler/lazy_task_runner.h" #include "build/build_config.h" diff --git a/chromium/components/download/internal/common/download_utils.cc b/chromium/components/download/internal/common/download_utils.cc index 224894906f4..cc9f500041b 100644 --- a/chromium/components/download/internal/common/download_utils.cc +++ b/chromium/components/download/internal/common/download_utils.cc @@ -5,6 +5,7 @@ #include "components/download/public/common/download_utils.h" #include "base/format_macros.h" +#include "base/rand_util.h" #include "base/strings/stringprintf.h" #include "components/download/public/common/download_create_info.h" #include "components/download/public/common/download_interrupt_reasons_utils.h" @@ -347,4 +348,24 @@ std::unique_ptr<net::HttpRequestHeaders> GetAdditionalRequestHeaders( return headers; } +DownloadEntry CreateDownloadEntryFromItem( + const DownloadItem& item, + const std::string& request_origin, + DownloadSource download_source, + bool fetch_error_body, + const DownloadUrlParameters::RequestHeadersType& request_headers) { + return DownloadEntry(item.GetGuid(), request_origin, download_source, + fetch_error_body, request_headers, + GetUniqueDownloadId()); +} + +uint64_t GetUniqueDownloadId() { + // Get a new UKM download_id that is not 0. + uint64_t download_id = 0; + do { + download_id = base::RandUint64(); + } while (download_id == 0); + return download_id; +} + } // namespace download diff --git a/chromium/components/download/internal/common/download_worker.cc b/chromium/components/download/internal/common/download_worker.cc index c05b1f8a0c2..b6f3aa58879 100644 --- a/chromium/components/download/internal/common/download_worker.cc +++ b/chromium/components/download/internal/common/download_worker.cc @@ -4,13 +4,13 @@ #include "components/download/internal/common/download_worker.h" -#include "base/message_loop/message_loop.h" +#include "components/download/internal/common/resource_downloader.h" #include "components/download/public/common/download_create_info.h" #include "components/download/public/common/download_interrupt_reasons.h" #include "components/download/public/common/download_task_runner.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" #include "components/download/public/common/download_utils.h" #include "components/download/public/common/input_stream.h" -#include "components/download/public/common/resource_downloader.h" #include "components/download/public/common/url_download_handler_factory.h" #include "services/network/public/cpp/features.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -43,10 +43,11 @@ class CompletedInputStream : public InputStream { void CreateUrlDownloadHandler( std::unique_ptr<DownloadUrlParameters> params, base::WeakPtr<UrlDownloadHandler::Delegate> delegate, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { auto downloader = UrlDownloadHandlerFactory::Create( - std::move(params), delegate, std::move(shared_url_loader_factory), + std::move(params), delegate, std::move(url_loader_factory_getter), task_runner); task_runner->PostTask( FROM_HERE, @@ -74,11 +75,12 @@ DownloadWorker::~DownloadWorker() = default; void DownloadWorker::SendRequest( std::unique_ptr<DownloadUrlParameters> params, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) { + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter) { GetIOTaskRunner()->PostTask( FROM_HERE, base::BindOnce(&CreateUrlDownloadHandler, std::move(params), weak_factory_.GetWeakPtr(), - std::move(shared_url_loader_factory), + std::move(url_loader_factory_getter), base::ThreadTaskRunnerHandle::Get())); } @@ -104,7 +106,8 @@ void DownloadWorker::Cancel(bool user_cancel) { void DownloadWorker::OnUrlDownloadStarted( std::unique_ptr<DownloadCreateInfo> create_info, std::unique_ptr<InputStream> input_stream, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const DownloadUrlParameters::OnStartedCallback& callback) { // |callback| is not used in subsequent requests. DCHECK(callback.is_null()); @@ -134,7 +137,8 @@ void DownloadWorker::OnUrlDownloadStarted( Pause(); } - delegate_->OnInputStreamReady(this, std::move(input_stream)); + delegate_->OnInputStreamReady(this, std::move(input_stream), + std::move(create_info)); } void DownloadWorker::OnUrlDownloadStopped(UrlDownloadHandler* downloader) { diff --git a/chromium/components/download/internal/common/download_worker.h b/chromium/components/download/internal/common/download_worker.h index 8996f082d12..8c712607093 100644 --- a/chromium/components/download/internal/common/download_worker.h +++ b/chromium/components/download/internal/common/download_worker.h @@ -14,11 +14,8 @@ #include "components/download/public/common/download_url_parameters.h" #include "components/download/public/common/url_download_handler.h" -namespace network { -class SharedURLLoaderFactory; -} - namespace download { +class DownloadURLLoaderFactoryGetter; // Helper class used to send subsequent range requests to fetch slices of the // file after handling response of the original non-range request. @@ -34,7 +31,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker // destination file. virtual void OnInputStreamReady( DownloadWorker* worker, - std::unique_ptr<InputStream> input_stream) = 0; + std::unique_ptr<InputStream> input_stream, + std::unique_ptr<DownloadCreateInfo> download_create_info) = 0; }; DownloadWorker(DownloadWorker::Delegate* delegate, @@ -46,9 +44,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker int64_t length() const { return length_; } // Send network request to ask for a download. - void SendRequest( - std::unique_ptr<DownloadUrlParameters> params, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory); + void SendRequest(std::unique_ptr<DownloadUrlParameters> params, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter); // Download operations. void Pause(); @@ -60,7 +58,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker void OnUrlDownloadStarted( std::unique_ptr<DownloadCreateInfo> create_info, std::unique_ptr<InputStream> input_stream, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const DownloadUrlParameters::OnStartedCallback& callback) override; void OnUrlDownloadStopped(UrlDownloadHandler* downloader) override; void OnUrlDownloadHandlerCreated( diff --git a/chromium/components/download/internal/common/in_progress_download_manager.cc b/chromium/components/download/internal/common/in_progress_download_manager.cc new file mode 100644 index 00000000000..9ed647a5b05 --- /dev/null +++ b/chromium/components/download/internal/common/in_progress_download_manager.cc @@ -0,0 +1,402 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/public/common/in_progress_download_manager.h" + +#include "base/optional.h" +#include "base/task_scheduler/post_task.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/download/downloader/in_progress/in_progress_cache_impl.h" +#include "components/download/internal/common/resource_downloader.h" +#include "components/download/public/common/download_file.h" +#include "components/download/public/common/download_item_impl.h" +#include "components/download/public/common/download_stats.h" +#include "components/download/public/common/download_task_runner.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" +#include "components/download/public/common/download_url_parameters.h" +#include "components/download/public/common/download_utils.h" +#include "components/download/public/common/input_stream.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/cpp/resource_response.h" + +namespace download { + +namespace { + +void OnUrlDownloadHandlerCreated( + UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader, + base::WeakPtr<InProgressDownloadManager> download_manager, + const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) { + main_task_runner->PostTask( + FROM_HERE, + base::BindOnce(&UrlDownloadHandler::Delegate::OnUrlDownloadHandlerCreated, + download_manager, std::move(downloader))); +} + +void BeginResourceDownload( + std::unique_ptr<DownloadUrlParameters> params, + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + uint32_t download_id, + base::WeakPtr<InProgressDownloadManager> download_manager, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) { + DCHECK(GetIOTaskRunner()->BelongsToCurrentThread()); + UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader( + ResourceDownloader::BeginDownload( + download_manager, std::move(params), std::move(request), + std::move(url_loader_factory_getter), site_url, tab_url, + tab_referrer_url, download_id, false, main_task_runner) + .release(), + base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get())); + + OnUrlDownloadHandlerCreated(std::move(downloader), download_manager, + main_task_runner); +} + +void CreateDownloadHandlerForNavigation( + base::WeakPtr<InProgressDownloadManager> download_manager, + std::unique_ptr<network::ResourceRequest> resource_request, + int render_process_id, + int render_frame_id, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + std::vector<GURL> url_chain, + scoped_refptr<network::ResourceResponse> response, + net::CertStatus cert_status, + network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) { + DCHECK(GetIOTaskRunner()->BelongsToCurrentThread()); + UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader( + ResourceDownloader::InterceptNavigationResponse( + download_manager, std::move(resource_request), render_process_id, + render_frame_id, site_url, tab_url, tab_referrer_url, + std::move(url_chain), std::move(response), std::move(cert_status), + std::move(url_loader_client_endpoints), + std::move(url_loader_factory_getter), main_task_runner) + .release(), + base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get())); + + OnUrlDownloadHandlerCreated(std::move(downloader), download_manager, + main_task_runner); +} + +// Responsible for persisting the in-progress metadata associated with a +// download. +class InProgressDownloadObserver : public DownloadItem::Observer { + public: + explicit InProgressDownloadObserver(InProgressCache* in_progress_cache); + ~InProgressDownloadObserver() override; + + private: + // DownloadItem::Observer + void OnDownloadUpdated(DownloadItem* download) override; + void OnDownloadRemoved(DownloadItem* download) override; + + // The persistent cache to store in-progress metadata. + InProgressCache* in_progress_cache_; + + DISALLOW_COPY_AND_ASSIGN(InProgressDownloadObserver); +}; + +InProgressDownloadObserver::InProgressDownloadObserver( + InProgressCache* in_progress_cache) + : in_progress_cache_(in_progress_cache) {} + +InProgressDownloadObserver::~InProgressDownloadObserver() = default; + +void InProgressDownloadObserver::OnDownloadUpdated(DownloadItem* download) { + // TODO(crbug.com/778425): Properly handle fail/resume/retry for downloads + // that are in the INTERRUPTED state for a long time. + if (!in_progress_cache_) + return; + + switch (download->GetState()) { + case DownloadItem::DownloadState::COMPLETE: + // Intentional fallthrough. + case DownloadItem::DownloadState::CANCELLED: + if (in_progress_cache_) + in_progress_cache_->RemoveEntry(download->GetGuid()); + break; + + case DownloadItem::DownloadState::INTERRUPTED: + // Intentional fallthrough. + case DownloadItem::DownloadState::IN_PROGRESS: { + // Make sure the entry exists in the cache. + base::Optional<DownloadEntry> entry_opt = + in_progress_cache_->RetrieveEntry(download->GetGuid()); + DownloadEntry entry; + if (!entry_opt.has_value()) { + entry = CreateDownloadEntryFromItem( + *download, std::string(), /* request_origin */ + DownloadSource::UNKNOWN, false, /* fetch_error_body */ + DownloadUrlParameters::RequestHeadersType()); + in_progress_cache_->AddOrReplaceEntry(entry); + break; + } + entry = entry_opt.value(); + break; + } + + default: + break; + } +} + +void InProgressDownloadObserver::OnDownloadRemoved(DownloadItem* download) { + if (!in_progress_cache_) + return; + + in_progress_cache_->RemoveEntry(download->GetGuid()); +} + +} // namespace + +InProgressDownloadManager::InProgressDownloadManager( + Delegate* delegate, + const IsOriginSecureCallback& is_origin_secure_cb) + : delegate_(delegate), + file_factory_(new DownloadFileFactory()), + is_origin_secure_cb_(is_origin_secure_cb), + weak_factory_(this) {} + +InProgressDownloadManager::~InProgressDownloadManager() = default; + +void InProgressDownloadManager::OnUrlDownloadStarted( + std::unique_ptr<DownloadCreateInfo> download_create_info, + std::unique_ptr<InputStream> input_stream, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + const DownloadUrlParameters::OnStartedCallback& callback) { + StartDownload(std::move(download_create_info), std::move(input_stream), + std::move(url_loader_factory_getter), callback); +} + +void InProgressDownloadManager::OnUrlDownloadStopped( + UrlDownloadHandler* downloader) { + for (auto ptr = url_download_handlers_.begin(); + ptr != url_download_handlers_.end(); ++ptr) { + if (ptr->get() == downloader) { + url_download_handlers_.erase(ptr); + return; + } + } +} + +void InProgressDownloadManager::OnUrlDownloadHandlerCreated( + UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader) { + if (downloader) + url_download_handlers_.push_back(std::move(downloader)); +} + +void InProgressDownloadManager::BeginDownload( + std::unique_ptr<DownloadUrlParameters> params, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + uint32_t download_id, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url) { + std::unique_ptr<network::ResourceRequest> request = + CreateResourceRequest(params.get()); + GetIOTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&BeginResourceDownload, std::move(params), + std::move(request), std::move(url_loader_factory_getter), + download_id, weak_factory_.GetWeakPtr(), site_url, tab_url, + tab_referrer_url, base::ThreadTaskRunnerHandle::Get())); +} + +void InProgressDownloadManager::InterceptDownloadFromNavigation( + std::unique_ptr<network::ResourceRequest> resource_request, + int render_process_id, + int render_frame_id, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + std::vector<GURL> url_chain, + scoped_refptr<network::ResourceResponse> response, + net::CertStatus cert_status, + network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter) { + GetIOTaskRunner()->PostTask( + FROM_HERE, + base::BindOnce(&CreateDownloadHandlerForNavigation, + weak_factory_.GetWeakPtr(), std::move(resource_request), + render_process_id, render_frame_id, site_url, tab_url, + tab_referrer_url, std::move(url_chain), + std::move(response), std::move(cert_status), + std::move(url_loader_client_endpoints), + std::move(url_loader_factory_getter), + base::ThreadTaskRunnerHandle::Get())); +} + +void InProgressDownloadManager::Initialize( + const base::FilePath& metadata_cache_dir, + base::OnceClosure callback) { + download_metadata_cache_ = std::make_unique<InProgressCacheImpl>( + metadata_cache_dir.empty() ? base::FilePath() : + metadata_cache_dir.Append(kDownloadMetadataStoreFilename), + base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BACKGROUND, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})); + + download_metadata_cache_->Initialize(std::move(callback)); +} + +void InProgressDownloadManager::ShutDown() { + url_download_handlers_.clear(); +} + +void InProgressDownloadManager::ResumeInterruptedDownload( + std::unique_ptr<DownloadUrlParameters> params, + uint32_t id, + const GURL& site_url) {} + +base::Optional<DownloadEntry> InProgressDownloadManager::GetInProgressEntry( + DownloadItemImpl* download) { + if (!download || !download_metadata_cache_) + return base::Optional<DownloadEntry>(); + + return download_metadata_cache_->RetrieveEntry(download->GetGuid()); +} + +void InProgressDownloadManager::ReportBytesWasted(DownloadItemImpl* download) { + if (!download_metadata_cache_) + return; + base::Optional<DownloadEntry> entry_opt = + download_metadata_cache_->RetrieveEntry(download->GetGuid()); + if (entry_opt.has_value()) { + DownloadEntry entry = entry_opt.value(); + entry.bytes_wasted = download->GetBytesWasted(); + download_metadata_cache_->AddOrReplaceEntry(entry); + } +} + +void InProgressDownloadManager::StartDownload( + std::unique_ptr<DownloadCreateInfo> info, + std::unique_ptr<InputStream> stream, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + const DownloadUrlParameters::OnStartedCallback& on_started) { + DCHECK(info); + + uint32_t download_id = info->download_id; + bool new_download = (download_id == DownloadItem::kInvalidId); + if (new_download && info->result == DOWNLOAD_INTERRUPT_REASON_NONE) { + if (delegate_ && delegate_->InterceptDownload(*info)) { + GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release()); + return; + } + } + + // |stream| is only non-null if the download request was successful. + DCHECK( + (info->result == DOWNLOAD_INTERRUPT_REASON_NONE && !stream->IsEmpty()) || + (info->result != DOWNLOAD_INTERRUPT_REASON_NONE && stream->IsEmpty())); + DVLOG(20) << __func__ + << "() result=" << DownloadInterruptReasonToString(info->result); + + GURL url = info->url(); + std::vector<GURL> url_chain = info->url_chain; + std::string mime_type = info->mime_type; + + if (new_download) { + RecordDownloadConnectionSecurity(info->url(), info->url_chain); + RecordDownloadContentTypeSecurity(info->url(), info->url_chain, + info->mime_type, is_origin_secure_cb_); + } + + base::RepeatingCallback<void(uint32_t)> got_id(base::BindRepeating( + &InProgressDownloadManager::StartDownloadWithId, + weak_factory_.GetWeakPtr(), base::Passed(&info), base::Passed(&stream), + std::move(url_loader_factory_getter), on_started, new_download)); + if (new_download) { + // TODO(qinmin): use GUID as the key for downloads history table so we don't + // rely on the delegate to provide the next download ID. + if (delegate_) + delegate_->GetNextId(std::move(got_id)); + } else { + std::move(got_id).Run(download_id); + } +} + +void InProgressDownloadManager::StartDownloadWithId( + std::unique_ptr<DownloadCreateInfo> info, + std::unique_ptr<InputStream> stream, + scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter, + const DownloadUrlParameters::OnStartedCallback& on_started, + bool new_download, + uint32_t id) { + DCHECK_NE(DownloadItem::kInvalidId, id); + DownloadItemImpl* download = + delegate_ ? delegate_->GetDownloadItem(id, new_download, *info) : nullptr; + + if (!download) { + // If the download is no longer known to the DownloadManager, then it was + // removed after it was resumed. Ignore. If the download is cancelled + // while resuming, then also ignore the request. + if (info->request_handle) + info->request_handle->CancelRequest(true); + if (!on_started.is_null()) + on_started.Run(nullptr, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED); + // The ByteStreamReader lives and dies on the download sequence. + if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) + GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release()); + return; + } + + base::FilePath default_download_directory; + if (delegate_) + default_download_directory = delegate_->GetDefaultDownloadDirectory(); + + if (download_metadata_cache_) { + base::Optional<DownloadEntry> entry_opt = + download_metadata_cache_->RetrieveEntry(download->GetGuid()); + if (!entry_opt.has_value()) { + download_metadata_cache_->AddOrReplaceEntry(CreateDownloadEntryFromItem( + *download, info->request_origin, info->download_source, + info->fetch_error_body, info->request_headers)); + } + } + + if (!in_progress_download_observer_) { + in_progress_download_observer_ = + std::make_unique<InProgressDownloadObserver>( + download_metadata_cache_.get()); + } + // May already observe this item, remove observer first. + download->RemoveObserver(in_progress_download_observer_.get()); + download->AddObserver(in_progress_download_observer_.get()); + + std::unique_ptr<DownloadFile> download_file; + if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) { + DCHECK(stream); + download_file.reset(file_factory_->CreateFile( + std::move(info->save_info), default_download_directory, + std::move(stream), id, download->DestinationObserverAsWeakPtr())); + } + // It is important to leave info->save_info intact in the case of an interrupt + // so that the DownloadItem can salvage what it can out of a failed + // resumption attempt. + + download->Start( + std::move(download_file), std::move(info->request_handle), *info, + std::move(url_loader_factory_getter), + delegate_ ? delegate_->GetURLRequestContextGetter(*info) : nullptr); + + // For interrupted downloads, Start() will transition the state to + // IN_PROGRESS and consumers will be notified via OnDownloadUpdated(). + // For new downloads, we notify here, rather than earlier, so that + // the download_file is bound to download and all the usual + // setters (e.g. Cancel) work. + if (new_download && delegate_) + delegate_->OnNewDownloadStarted(download); + + if (!on_started.is_null()) + on_started.Run(download, DOWNLOAD_INTERRUPT_REASON_NONE); +} + +} // namespace download diff --git a/chromium/components/download/internal/common/parallel_download_job.cc b/chromium/components/download/internal/common/parallel_download_job.cc index e139a42c314..e72f9af89c0 100644 --- a/chromium/components/download/internal/common/parallel_download_job.cc +++ b/chromium/components/download/internal/common/parallel_download_job.cc @@ -12,6 +12,7 @@ #include "components/download/internal/common/parallel_download_utils.h" #include "components/download/public/common/download_create_info.h" #include "components/download/public/common/download_stats.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" #include "net/traffic_annotation/network_traffic_annotation.h" namespace download { @@ -23,7 +24,8 @@ ParallelDownloadJob::ParallelDownloadJob( DownloadItem* download_item, std::unique_ptr<DownloadRequestHandleInterface> request_handle, const DownloadCreateInfo& create_info, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, net::URLRequestContextGetter* url_request_context_getter) : DownloadJobImpl(download_item, std::move(request_handle), true), initial_request_offset_(create_info.offset), @@ -31,7 +33,7 @@ ParallelDownloadJob::ParallelDownloadJob( content_length_(create_info.total_bytes), requests_sent_(false), is_canceled_(false), - shared_url_loader_factory_(std::move(shared_url_loader_factory)), + url_loader_factory_getter_(std::move(url_loader_factory_getter)), url_request_context_getter_(url_request_context_getter) {} ParallelDownloadJob::~ParallelDownloadJob() = default; @@ -121,9 +123,14 @@ void ParallelDownloadJob::BuildParallelRequestAfterDelay() { void ParallelDownloadJob::OnInputStreamReady( DownloadWorker* worker, - std::unique_ptr<InputStream> input_stream) { - bool success = DownloadJob::AddInputStream( - std::move(input_stream), worker->offset(), worker->length()); + std::unique_ptr<InputStream> input_stream, + std::unique_ptr<DownloadCreateInfo> download_create_info) { + // If server returns a wrong range, abort the parallel request. + bool success = download_create_info->offset == worker->offset(); + if (success) { + success = DownloadJob::AddInputStream(std::move(input_stream), + worker->offset(), worker->length()); + } RecordParallelDownloadAddStreamSuccess(success); // Destroy the request if the sink is gone. @@ -286,7 +293,7 @@ void ParallelDownloadJob::CreateRequest(int64_t offset, int64_t length) { download_params->set_referrer_policy(net::URLRequest::NEVER_CLEAR_REFERRER); // Send the request. - worker->SendRequest(std::move(download_params), shared_url_loader_factory_); + worker->SendRequest(std::move(download_params), url_loader_factory_getter_); DCHECK(workers_.find(offset) == workers_.end()); workers_[offset] = std::move(worker); } diff --git a/chromium/components/download/internal/common/parallel_download_job.h b/chromium/components/download/internal/common/parallel_download_job.h index c37fb07eb96..a6803e22ee4 100644 --- a/chromium/components/download/internal/common/parallel_download_job.h +++ b/chromium/components/download/internal/common/parallel_download_job.h @@ -35,7 +35,8 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob DownloadItem* download_item, std::unique_ptr<DownloadRequestHandleInterface> request_handle, const DownloadCreateInfo& create_info, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, net::URLRequestContextGetter* url_request_context_getter); ~ParallelDownloadJob() override; @@ -67,8 +68,10 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob friend class ParallelDownloadJobTest; // DownloadWorker::Delegate implementation. - void OnInputStreamReady(DownloadWorker* worker, - std::unique_ptr<InputStream> input_stream) override; + void OnInputStreamReady( + DownloadWorker* worker, + std::unique_ptr<InputStream> input_stream, + std::unique_ptr<DownloadCreateInfo> download_create_info) override; // Build parallel requests after a delay, to effectively measure the single // stream bandwidth. @@ -110,8 +113,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob // If the download progress is canceled. bool is_canceled_; - // SharedURLLoaderFactory to issue network requests with network service - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_; + // URLLoaderFactory getter to issue network requests with network service + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter_; // URLRequestContextGetter for issueing network requests when network service // is disabled. diff --git a/chromium/components/download/internal/common/parallel_download_job_unittest.cc b/chromium/components/download/internal/common/parallel_download_job_unittest.cc index eb09f931707..61761c49fb4 100644 --- a/chromium/components/download/internal/common/parallel_download_job_unittest.cc +++ b/chromium/components/download/internal/common/parallel_download_job_unittest.cc @@ -94,8 +94,10 @@ class ParallelDownloadJobForTest : public ParallelDownloadJob { return min_remaining_time_; } - void OnInputStreamReady(DownloadWorker* worker, - std::unique_ptr<InputStream> input_stream) override { + void OnInputStreamReady( + DownloadWorker* worker, + std::unique_ptr<InputStream> input_stream, + std::unique_ptr<DownloadCreateInfo> download_create_info) override { CountOnInputStreamReady(); } @@ -429,7 +431,7 @@ TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeByteStreamReady) { for (auto& worker : job_->workers()) { std::unique_ptr<MockDownloadRequestHandle> mock_handle = std::make_unique<MockDownloadRequestHandle>(); - EXPECT_CALL(*mock_handle.get(), CancelRequest(_)); + EXPECT_CALL(*mock_handle, CancelRequest(_)); MakeWorkerReady(worker.second.get(), std::move(mock_handle)); } @@ -451,10 +453,10 @@ TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeByteStreamReady) { EXPECT_TRUE(job_->is_paused()); for (auto& worker : job_->workers()) { - EXPECT_CALL(*job_.get(), CountOnInputStreamReady()); + EXPECT_CALL(*job_, CountOnInputStreamReady()); std::unique_ptr<MockDownloadRequestHandle> mock_handle = std::make_unique<MockDownloadRequestHandle>(); - EXPECT_CALL(*mock_handle.get(), PauseRequest()); + EXPECT_CALL(*mock_handle, PauseRequest()); MakeWorkerReady(worker.second.get(), std::move(mock_handle)); } @@ -517,7 +519,7 @@ TEST_F(ParallelDownloadJobTest, InterruptOnStartup) { job_->MakeFileInitialized(callback.Get(), DOWNLOAD_INTERRUPT_REASON_NONE); // Simulate and inject an error from IO thread after file initialized. - EXPECT_CALL(*download_item_.get(), GetState()) + EXPECT_CALL(*download_item_, GetState()) .WillRepeatedly(Return(DownloadItem::DownloadState::INTERRUPTED)); // Because of the error, no parallel requests are built. diff --git a/chromium/components/download/internal/common/resource_downloader.cc b/chromium/components/download/internal/common/resource_downloader.cc index ab961f310e3..988cf5cef88 100644 --- a/chromium/components/download/internal/common/resource_downloader.cc +++ b/chromium/components/download/internal/common/resource_downloader.cc @@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/download/public/common/resource_downloader.h" +#include "components/download/internal/common/resource_downloader.h" #include <memory> -#include "base/strings/utf_string_conversions.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" #include "components/download/public/common/stream_handle_input_stream.h" #include "services/network/public/cpp/shared_url_loader_factory.h" @@ -60,7 +60,8 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload( base::WeakPtr<UrlDownloadHandler::Delegate> delegate, std::unique_ptr<DownloadUrlParameters> params, std::unique_ptr<network::ResourceRequest> request, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const GURL& site_url, const GURL& tab_url, const GURL& tab_referrer_url, @@ -71,7 +72,7 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload( delegate, std::move(request), params->render_process_host_id(), params->render_frame_host_routing_id(), site_url, tab_url, tab_referrer_url, download_id, task_runner, - std::move(shared_url_loader_factory)); + std::move(url_loader_factory_getter)); downloader->Start(std::move(params), is_parallel_request); return downloader; @@ -88,18 +89,18 @@ ResourceDownloader::InterceptNavigationResponse( const GURL& tab_url, const GURL& tab_referrer_url, std::vector<GURL> url_chain, - const base::Optional<std::string>& suggested_filename, const scoped_refptr<network::ResourceResponse>& response, net::CertStatus cert_status, network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { auto downloader = std::make_unique<ResourceDownloader>( delegate, std::move(resource_request), render_process_id, render_frame_id, site_url, tab_url, tab_referrer_url, download::DownloadItem::kInvalidId, - task_runner, std::move(shared_url_loader_factory)); + task_runner, std::move(url_loader_factory_getter)); downloader->InterceptResponse(std::move(response), std::move(url_chain), - suggested_filename, cert_status, + cert_status, std::move(url_loader_client_endpoints)); return downloader; } @@ -114,7 +115,8 @@ ResourceDownloader::ResourceDownloader( const GURL& tab_referrer_url, uint32_t download_id, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter) : delegate_(delegate), resource_request_(std::move(resource_request)), download_id_(download_id), @@ -124,7 +126,7 @@ ResourceDownloader::ResourceDownloader( tab_url_(tab_url), tab_referrer_url_(tab_referrer_url), delegate_task_runner_(task_runner), - shared_url_loader_factory_(std::move(shared_url_loader_factory)), + url_loader_factory_getter_(std::move(url_loader_factory_getter)), weak_ptr_factory_(this) {} ResourceDownloader::~ResourceDownloader() = default; @@ -154,7 +156,7 @@ void ResourceDownloader::Start( // Set up the URLLoader network::mojom::URLLoaderRequest url_loader_request = mojo::MakeRequest(&url_loader_); - shared_url_loader_factory_->CreateLoaderAndStart( + url_loader_factory_getter_->GetURLLoaderFactory()->CreateLoaderAndStart( std::move(url_loader_request), 0, // routing_id 0, // request_id @@ -169,18 +171,14 @@ void ResourceDownloader::Start( void ResourceDownloader::InterceptResponse( const scoped_refptr<network::ResourceResponse>& response, std::vector<GURL> url_chain, - const base::Optional<std::string>& suggested_filename, net::CertStatus cert_status, network::mojom::URLLoaderClientEndpointsPtr endpoints) { // Set the URLLoader. url_loader_.Bind(std::move(endpoints->url_loader)); // Create the new URLLoaderClient that will intercept the navigation. - auto save_info = std::make_unique<DownloadSaveInfo>(); - if (suggested_filename.has_value()) - save_info->suggested_name = base::UTF8ToUTF16(suggested_filename.value()); url_loader_client_ = std::make_unique<DownloadResponseHandler>( - resource_request_.get(), this, std::move(save_info), + resource_request_.get(), this, std::make_unique<DownloadSaveInfo>(), false, /* is_parallel_request */ false, /* is_transient */ false, /* fetch_error_body */ @@ -216,11 +214,11 @@ void ResourceDownloader::OnResponseStarted( &UrlDownloadHandler::Delegate::OnUrlDownloadStarted, delegate_, std::move(download_create_info), std::make_unique<StreamHandleInputStream>(std::move(stream_handle)), - std::move(shared_url_loader_factory_), callback_)); + std::move(url_loader_factory_getter_), callback_)); } void ResourceDownloader::OnReceiveRedirect() { - url_loader_->FollowRedirect(); + url_loader_->FollowRedirect(base::nullopt); } } // namespace download diff --git a/chromium/components/download/internal/common/resource_downloader.h b/chromium/components/download/internal/common/resource_downloader.h new file mode 100644 index 00000000000..ce6eef63834 --- /dev/null +++ b/chromium/components/download/internal/common/resource_downloader.h @@ -0,0 +1,145 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_ + +#include "components/download/public/common/download_export.h" +#include "components/download/public/common/download_response_handler.h" +#include "components/download/public/common/url_download_handler.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "net/cert/cert_status_flags.h" +#include "services/network/public/cpp/resource_request.h" +#include "services/network/public/mojom/url_loader.mojom.h" + +namespace download { +class DownloadURLLoaderFactoryGetter; + +// Class for handing the download of a url. +class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader + : public download::UrlDownloadHandler, + public download::DownloadResponseHandler::Delegate { + public: + // Called to start a download, must be called on IO thread. + static std::unique_ptr<ResourceDownloader> BeginDownload( + base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate, + std::unique_ptr<download::DownloadUrlParameters> download_url_parameters, + std::unique_ptr<network::ResourceRequest> request, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + uint32_t download_id, + bool is_parallel_request, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + + // Create a ResourceDownloader from a navigation that turns to be a download. + // No URLLoader is created, but the URLLoaderClient implementation is + // transferred. + static std::unique_ptr<ResourceDownloader> InterceptNavigationResponse( + base::WeakPtr<UrlDownloadHandler::Delegate> delegate, + std::unique_ptr<network::ResourceRequest> resource_request, + int render_process_id, + int render_frame_id, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + std::vector<GURL> url_chain, + const scoped_refptr<network::ResourceResponse>& response, + net::CertStatus cert_status, + network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); + + ResourceDownloader( + base::WeakPtr<UrlDownloadHandler::Delegate> delegate, + std::unique_ptr<network::ResourceRequest> resource_request, + int render_process_id, + int render_frame_id, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + uint32_t download_id, + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter); + ~ResourceDownloader() override; + + // download::DownloadResponseHandler::Delegate + void OnResponseStarted( + std::unique_ptr<download::DownloadCreateInfo> download_create_info, + download::mojom::DownloadStreamHandlePtr stream_handle) override; + void OnReceiveRedirect() override; + + private: + // Helper method to start the network request. + void Start( + std::unique_ptr<download::DownloadUrlParameters> download_url_parameters, + bool is_parallel_request); + + // Intercepts the navigation response. + void InterceptResponse( + const scoped_refptr<network::ResourceResponse>& response, + std::vector<GURL> url_chain, + net::CertStatus cert_status, + network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints); + + base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate_; + + // The ResourceRequest for this object. + std::unique_ptr<network::ResourceRequest> resource_request_; + + // Object that will handle the response. + std::unique_ptr<network::mojom::URLLoaderClient> url_loader_client_; + + // URLLoaderClient binding. It sends any requests to the |url_loader_client_|. + std::unique_ptr<mojo::Binding<network::mojom::URLLoaderClient>> + url_loader_client_binding_; + + // URLLoader for sending out the request. + network::mojom::URLLoaderPtr url_loader_; + + // ID of the download, or download::DownloadItem::kInvalidId if this is a new + // download. + uint32_t download_id_; + + // GUID of the download, or empty if this is a new download. + std::string guid_; + + // Callback to run after download starts. + download::DownloadUrlParameters::OnStartedCallback callback_; + + // Frame and process id associated with the request. + int render_process_id_; + int render_frame_id_; + + // Site URL for the site instance that initiated the download. + GURL site_url_; + + // The URL of the tab that started us. + GURL tab_url_; + + // The referrer URL of the tab that started us. + GURL tab_referrer_url_; + + // URLLoader status when intercepting the navigation request. + base::Optional<network::URLLoaderCompletionStatus> url_loader_status_; + + // TaskRunner to post callbacks to the |delegate_| + scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_; + + // URLLoaderFactory getter for issueing network requests. + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter_; + + base::WeakPtrFactory<ResourceDownloader> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ResourceDownloader); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_ diff --git a/chromium/components/download/internal/common/url_download_handler_factory.cc b/chromium/components/download/internal/common/url_download_handler_factory.cc index fec5bf41cd0..625f6da4ffd 100644 --- a/chromium/components/download/internal/common/url_download_handler_factory.cc +++ b/chromium/components/download/internal/common/url_download_handler_factory.cc @@ -6,9 +6,10 @@ #include "base/no_destructor.h" #include "base/synchronization/lock.h" +#include "components/download/internal/common/resource_downloader.h" #include "components/download/public/common/download_item.h" +#include "components/download/public/common/download_url_loader_factory_getter.h" #include "components/download/public/common/download_utils.h" -#include "components/download/public/common/resource_downloader.h" #include "services/network/public/cpp/shared_url_loader_factory.h" namespace download { @@ -25,14 +26,15 @@ class DefaultUrlDownloadHandlerFactory : public UrlDownloadHandlerFactory { UrlDownloadHandler::UniqueUrlDownloadHandlerPtr CreateUrlDownloadHandler( std::unique_ptr<download::DownloadUrlParameters> params, base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) override { std::unique_ptr<network::ResourceRequest> request = CreateResourceRequest(params.get()); return UrlDownloadHandler::UniqueUrlDownloadHandlerPtr( download::ResourceDownloader::BeginDownload( delegate, std::move(params), std::move(request), - std::move(shared_url_loader_factory), GURL(), GURL(), GURL(), + std::move(url_loader_factory_getter), GURL(), GURL(), GURL(), download::DownloadItem::kInvalidId, true, task_runner) .release(), base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get())); @@ -57,13 +59,14 @@ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr UrlDownloadHandlerFactory::Create( std::unique_ptr<download::DownloadUrlParameters> params, base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate, - scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory, + scoped_refptr<download::DownloadURLLoaderFactoryGetter> + url_loader_factory_getter, const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { base::AutoLock auto_lock(GetURLDownloadHandlerFactoryLock()); if (!g_url_download_handler_factory) g_url_download_handler_factory = new DefaultUrlDownloadHandlerFactory(); return g_url_download_handler_factory->CreateUrlDownloadHandler( - std::move(params), delegate, std::move(shared_url_loader_factory), + std::move(params), delegate, std::move(url_loader_factory_getter), task_runner); } |