| // 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/internal/background_service/in_memory_download_driver.h" |
| |
| #include "components/download/internal/background_service/in_memory_download.h" |
| #include "services/network/public/cpp/resource_request_body.h" |
| |
| namespace download { |
| |
| namespace { |
| |
| DriverEntry::State ToDriverEntryState(InMemoryDownload::State state) { |
| switch (state) { |
| case InMemoryDownload::State::INITIAL: |
| return DriverEntry::State::IN_PROGRESS; |
| case InMemoryDownload::State::IN_PROGRESS: |
| return DriverEntry::State::IN_PROGRESS; |
| case InMemoryDownload::State::FAILED: |
| return DriverEntry::State::INTERRUPTED; |
| case InMemoryDownload::State::COMPLETE: |
| return DriverEntry::State::COMPLETE; |
| } |
| NOTREACHED(); |
| return DriverEntry::State::UNKNOWN; |
| } |
| |
| // Helper function to create download driver entry based on in memory download. |
| DriverEntry CreateDriverEntry(const InMemoryDownload& download) { |
| DriverEntry entry; |
| entry.guid = download.guid(); |
| entry.state = ToDriverEntryState(download.state()); |
| entry.paused = download.paused(); |
| entry.done = entry.state == DriverEntry::State::COMPLETE || |
| entry.state == DriverEntry::State::CANCELLED; |
| entry.bytes_downloaded = download.bytes_downloaded(); |
| entry.url_chain = download.url_chain(); |
| entry.response_headers = download.response_headers(); |
| if (entry.response_headers) { |
| entry.expected_total_size = entry.response_headers->GetContentLength(); |
| } |
| // Currently incognito mode network backend can't resume in the middle. |
| entry.can_resume = false; |
| |
| if (download.state() == InMemoryDownload::State::COMPLETE) { |
| auto blob_handle = download.ResultAsBlob(); |
| if (blob_handle) |
| entry.blob_handle = base::Optional<storage::BlobDataHandle>(*blob_handle); |
| } |
| return entry; |
| } |
| |
| } // namespace |
| |
| InMemoryDownloadFactory::InMemoryDownloadFactory( |
| network::mojom::URLLoaderFactory* url_loader_factory, |
| BlobTaskProxy::BlobContextGetter blob_context_getter, |
| scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) |
| : url_loader_factory_(url_loader_factory), |
| blob_context_getter_(blob_context_getter), |
| io_task_runner_(io_task_runner) {} |
| |
| InMemoryDownloadFactory::~InMemoryDownloadFactory() = default; |
| |
| std::unique_ptr<InMemoryDownload> InMemoryDownloadFactory::Create( |
| const std::string& guid, |
| const RequestParams& request_params, |
| scoped_refptr<network::ResourceRequestBody> request_body, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation, |
| InMemoryDownload::Delegate* delegate) { |
| DCHECK(url_loader_factory_); |
| return std::make_unique<InMemoryDownloadImpl>( |
| guid, request_params, std::move(request_body), traffic_annotation, |
| delegate, url_loader_factory_, blob_context_getter_, io_task_runner_); |
| } |
| |
| InMemoryDownloadDriver::InMemoryDownloadDriver( |
| std::unique_ptr<InMemoryDownload::Factory> download_factory) |
| : client_(nullptr), download_factory_(std::move(download_factory)) {} |
| |
| InMemoryDownloadDriver::~InMemoryDownloadDriver() = default; |
| |
| void InMemoryDownloadDriver::Initialize(DownloadDriver::Client* client) { |
| DCHECK(!client_) << "Initialize can be called only once."; |
| client_ = client; |
| DCHECK(client_); |
| client_->OnDriverReady(true); |
| } |
| |
| void InMemoryDownloadDriver::HardRecover() { |
| client_->OnDriverHardRecoverComplete(true); |
| } |
| |
| bool InMemoryDownloadDriver::IsReady() const { |
| return true; |
| } |
| |
| void InMemoryDownloadDriver::Start( |
| const RequestParams& request_params, |
| const std::string& guid, |
| const base::FilePath& file_path, |
| scoped_refptr<network::ResourceRequestBody> request_body, |
| const net::NetworkTrafficAnnotationTag& traffic_annotation) { |
| std::unique_ptr<InMemoryDownload> download = download_factory_->Create( |
| guid, request_params, std::move(request_body), traffic_annotation, this); |
| InMemoryDownload* download_ptr = download.get(); |
| DCHECK(downloads_.find(guid) == downloads_.end()) << "Existing GUID found."; |
| downloads_.emplace(guid, std::move(download)); |
| |
| download_ptr->Start(); |
| } |
| |
| void InMemoryDownloadDriver::Remove(const std::string& guid, bool remove_file) { |
| downloads_.erase(guid); |
| } |
| |
| void InMemoryDownloadDriver::Pause(const std::string& guid) { |
| auto it = downloads_.find(guid); |
| if (it != downloads_.end()) |
| it->second->Pause(); |
| } |
| |
| void InMemoryDownloadDriver::Resume(const std::string& guid) { |
| auto it = downloads_.find(guid); |
| if (it != downloads_.end()) |
| it->second->Resume(); |
| } |
| |
| base::Optional<DriverEntry> InMemoryDownloadDriver::Find( |
| const std::string& guid) { |
| base::Optional<DriverEntry> entry; |
| auto it = downloads_.find(guid); |
| if (it != downloads_.end()) |
| entry = CreateDriverEntry(*it->second); |
| return entry; |
| } |
| |
| std::set<std::string> InMemoryDownloadDriver::GetActiveDownloads() { |
| std::set<std::string> downloads; |
| for (const auto& it : downloads_) { |
| if (it.second->state() == InMemoryDownload::State::INITIAL || |
| it.second->state() == InMemoryDownload::State::IN_PROGRESS) { |
| downloads.emplace(it.first); |
| } |
| } |
| return downloads; |
| } |
| |
| size_t InMemoryDownloadDriver::EstimateMemoryUsage() const { |
| size_t memory_usage = 0u; |
| for (const auto& it : downloads_) { |
| memory_usage += it.second->EstimateMemoryUsage(); |
| } |
| return memory_usage; |
| } |
| |
| void InMemoryDownloadDriver::OnDownloadStarted(InMemoryDownload* download) { |
| DCHECK(client_); |
| client_->OnDownloadCreated(CreateDriverEntry(*download)); |
| } |
| |
| void InMemoryDownloadDriver::OnDownloadProgress(InMemoryDownload* download) { |
| DCHECK(client_); |
| client_->OnDownloadUpdated(CreateDriverEntry(*download)); |
| } |
| |
| void InMemoryDownloadDriver::OnDownloadComplete(InMemoryDownload* download) { |
| DCHECK(download); |
| DCHECK(client_); |
| DriverEntry entry = CreateDriverEntry(*download); |
| switch (download->state()) { |
| case InMemoryDownload::State::FAILED: |
| // URLFetcher retries for network failures. |
| client_->OnDownloadFailed(entry, FailureType::NOT_RECOVERABLE); |
| // Should immediately return in case |client_| removes |download| in |
| // OnDownloadFailed. |
| return; |
| case InMemoryDownload::State::COMPLETE: |
| client_->OnDownloadSucceeded(entry); |
| // Should immediately return in case |client_| removes |download| in |
| // OnDownloadSucceeded. |
| return; |
| case InMemoryDownload::State::INITIAL: |
| case InMemoryDownload::State::IN_PROGRESS: |
| NOTREACHED(); |
| return; |
| } |
| } |
| |
| void InMemoryDownloadDriver::OnUploadProgress(InMemoryDownload* download) { |
| DCHECK(download); |
| DCHECK(client_); |
| client_->OnUploadProgress(download->guid(), download->bytes_uploaded()); |
| } |
| |
| } // namespace download |