Download driver for components/download.
This CL introduces the glue layer between //components/download and
//content. The DownloadDriver interface will be the only place to access
content functionalities from download service.
Also provides a test support class for //components/download code. The
test support version of DownloadManager is not done in this CL.
The response/request headers pumping is not done in this CL, which
requires tweak on download network code.
BUG=717180
Review-Url: https://codereview.chromium.org/2880933002
Cr-Commit-Position: refs/heads/master@{#474191}
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index ec81704..fb47fa8 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -315,6 +315,7 @@
++history_size_;
}
notifier_.GetManager()->CheckForHistoryFilesRemoval();
+ notifier_.GetManager()->PostInitialization();
initial_history_query_complete_ = true;
for (Observer& observer : observers_)
diff --git a/chrome/browser/download/download_ui_controller_unittest.cc b/chrome/browser/download/download_ui_controller_unittest.cc
index 47308a7..87af5bd 100644
--- a/chrome/browser/download/download_ui_controller_unittest.cc
+++ b/chrome/browser/download/download_ui_controller_unittest.cc
@@ -329,6 +329,7 @@
EXPECT_CALL(*item, GetOriginalMimeType());
EXPECT_CALL(*manager(), CheckForHistoryFilesRemoval());
+ EXPECT_CALL(*manager(), PostInitialization());
{
testing::InSequence s;
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 0e5a648..0c176a8e 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -190,6 +190,7 @@
"//components/discardable_memory/service:unit_tests",
"//components/dom_distiller/content/browser:unit_tests",
"//components/domain_reliability:unit_tests",
+ "//components/download/content:unit_tests",
"//components/error_page/renderer:unit_tests",
"//components/favicon/content:unit_tests",
"//components/gcm_driver/instance_id:unit_tests",
diff --git a/components/download/content/BUILD.gn b/components/download/content/BUILD.gn
new file mode 100644
index 0000000..7ca79f6
--- /dev/null
+++ b/components/download/content/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+source_set("content") {
+ sources = [
+ "download_driver_impl.cc",
+ "download_driver_impl.h",
+ ]
+
+ public_deps = [
+ "//components/download/internal",
+ "//components/download/public",
+ ]
+
+ deps = [
+ "//base",
+ "//content/public/browser",
+ "//net",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "download_driver_impl_unittest.cc",
+ ]
+
+ deps = [
+ ":content",
+ "//content/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/components/download/content/DEPS b/components/download/content/DEPS
new file mode 100644
index 0000000..ea159c83
--- /dev/null
+++ b/components/download/content/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+content/public/browser",
+ "+content/public/test",
+ "+base",
+ "+net",
+]
diff --git a/components/download/content/download_driver_impl.cc b/components/download/content/download_driver_impl.cc
new file mode 100644
index 0000000..0d1d281
--- /dev/null
+++ b/components/download/content/download_driver_impl.cc
@@ -0,0 +1,188 @@
+// 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.
+
+#include "components/download/content/download_driver_impl.h"
+
+#include "components/download/internal/driver_entry.h"
+#include "content/public/browser/download_interrupt_reasons.h"
+#include "content/public/browser/download_url_parameters.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/http/http_response_headers.h"
+
+namespace download {
+
+namespace {
+
+// Converts a content::DownloadItem::DownloadState to DriverEntry::State.
+DriverEntry::State ToDriverEntryState(
+ content::DownloadItem::DownloadState state) {
+ switch (state) {
+ case content::DownloadItem::IN_PROGRESS:
+ return DriverEntry::State::IN_PROGRESS;
+ case content::DownloadItem::COMPLETE:
+ return DriverEntry::State::COMPLETE;
+ case content::DownloadItem::CANCELLED:
+ return DriverEntry::State::CANCELLED;
+ case content::DownloadItem::INTERRUPTED:
+ return DriverEntry::State::INTERRUPTED;
+ case content::DownloadItem::MAX_DOWNLOAD_STATE:
+ return DriverEntry::State::UNKNOWN;
+ default:
+ NOTREACHED();
+ return DriverEntry::State::UNKNOWN;
+ }
+}
+
+} // namespace
+
+// static
+DriverEntry DownloadDriverImpl::CreateDriverEntry(
+ const content::DownloadItem* item) {
+ DCHECK(item);
+ DriverEntry entry;
+ entry.guid = item->GetGuid();
+ entry.state = ToDriverEntryState(item->GetState());
+ entry.paused = item->IsPaused();
+ entry.bytes_downloaded = item->GetReceivedBytes();
+ entry.expected_total_size = item->GetTotalBytes();
+ entry.response_headers = item->GetResponseHeaders();
+ return entry;
+}
+
+DownloadDriverImpl::DownloadDriverImpl(content::DownloadManager* manager,
+ const base::FilePath& dir)
+ : download_manager_(manager), file_dir_(dir), client_(nullptr) {
+ DCHECK(download_manager_);
+}
+
+DownloadDriverImpl::~DownloadDriverImpl() {
+ if (download_manager_)
+ download_manager_->RemoveObserver(this);
+}
+
+void DownloadDriverImpl::Initialize(DownloadDriver::Client* client) {
+ DCHECK(!client_);
+ client_ = client;
+ DCHECK(client_);
+
+ // |download_manager_| may be shut down. Informs the client.
+ if (!download_manager_) {
+ client_->OnDriverReady(false);
+ return;
+ }
+
+ download_manager_->AddObserver(this);
+ if (download_manager_->IsManagerInitialized())
+ client_->OnDriverReady(true);
+}
+
+bool DownloadDriverImpl::IsReady() const {
+ return client_ && download_manager_;
+}
+
+void DownloadDriverImpl::Start(const DownloadParams& params) {
+ DCHECK(!params.request_params.url.is_empty());
+ DCHECK(!params.guid.empty());
+ if (!download_manager_)
+ return;
+
+ content::StoragePartition* storage_partition =
+ content::BrowserContext::GetStoragePartitionForSite(
+ download_manager_->GetBrowserContext(), params.request_params.url);
+ DCHECK(storage_partition);
+
+ std::unique_ptr<content::DownloadUrlParameters> download_url_params(
+ new content::DownloadUrlParameters(
+ params.request_params.url,
+ storage_partition->GetURLRequestContext()));
+
+ // TODO(xingliu): Handle the request headers from |params|, need to tweak
+ // download network stack.
+ // Make content::DownloadManager handle potential guid collision and return
+ // an error to fail the download cleanly.
+ download_url_params->set_guid(params.guid);
+ download_url_params->set_transient(true);
+ download_url_params->set_method(params.request_params.method);
+ download_url_params->set_file_path(file_dir_.AppendASCII(params.guid));
+
+ download_manager_->DownloadUrl(std::move(download_url_params));
+}
+
+void DownloadDriverImpl::Cancel(const std::string& guid) {
+ if (!download_manager_)
+ return;
+ content::DownloadItem* item = download_manager_->GetDownloadByGuid(guid);
+ // Cancels the download and removes the persisted records in content layer.
+ if (item) {
+ item->RemoveObserver(this);
+ item->Remove();
+ }
+}
+
+void DownloadDriverImpl::Pause(const std::string& guid) {
+ if (!download_manager_)
+ return;
+ content::DownloadItem* item = download_manager_->GetDownloadByGuid(guid);
+ if (item)
+ item->Pause();
+}
+
+void DownloadDriverImpl::Resume(const std::string& guid) {
+ if (!download_manager_)
+ return;
+ content::DownloadItem* item = download_manager_->GetDownloadByGuid(guid);
+ if (item)
+ item->Resume();
+}
+
+base::Optional<DriverEntry> DownloadDriverImpl::Find(const std::string& guid) {
+ if (!download_manager_)
+ return base::nullopt;
+ content::DownloadItem* item = download_manager_->GetDownloadByGuid(guid);
+ if (item)
+ return CreateDriverEntry(item);
+ return base::nullopt;
+}
+
+void DownloadDriverImpl::OnDownloadUpdated(content::DownloadItem* item) {
+ DCHECK(client_);
+
+ using DownloadState = content::DownloadItem::DownloadState;
+ DownloadState state = item->GetState();
+ content::DownloadInterruptReason reason = item->GetLastReason();
+ DriverEntry entry = CreateDriverEntry(item);
+
+ if (state == DownloadState::COMPLETE) {
+ client_->OnDownloadSucceeded(entry, item->GetTargetFilePath());
+ item->RemoveObserver(this);
+ } else if (state == DownloadState::IN_PROGRESS) {
+ client_->OnDownloadUpdated(entry);
+ } else if (reason !=
+ content::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE) {
+ client_->OnDownloadFailed(entry, static_cast<int>(reason));
+ item->RemoveObserver(this);
+ }
+}
+
+void DownloadDriverImpl::OnDownloadCreated(content::DownloadManager* manager,
+ content::DownloadItem* item) {
+ // Listens to all downloads.
+ item->AddObserver(this);
+ DCHECK(client_);
+ DriverEntry entry = CreateDriverEntry(item);
+ client_->OnDownloadCreated(entry);
+}
+
+void DownloadDriverImpl::OnManagerInitialized() {
+ DCHECK(client_);
+ DCHECK(download_manager_);
+ client_->OnDriverReady(true);
+}
+
+void DownloadDriverImpl::ManagerGoingDown(content::DownloadManager* manager) {
+ DCHECK_EQ(download_manager_, manager);
+ download_manager_ = nullptr;
+}
+
+} // namespace download
diff --git a/components/download/content/download_driver_impl.h b/components/download/content/download_driver_impl.h
new file mode 100644
index 0000000..c7c5b1c
--- /dev/null
+++ b/components/download/content/download_driver_impl.h
@@ -0,0 +1,67 @@
+// 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_CONTENT_DOWNLOAD_DRIVER_IMPL_H_
+#define COMPONENTS_DOWNLOAD_CONTENT_DOWNLOAD_DRIVER_IMPL_H_
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "components/download/internal/download_driver.h"
+#include "components/download/public/download_params.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/download_manager.h"
+
+namespace download {
+
+struct DriverEntry;
+
+// Aggregates and handles all interaction between download service and content
+// download logic.
+class DownloadDriverImpl : public DownloadDriver,
+ public content::DownloadManager::Observer,
+ public content::DownloadItem::Observer {
+ public:
+ // Creates a driver entry based on a download item.
+ static DriverEntry CreateDriverEntry(const content::DownloadItem* item);
+
+ // Create the driver. All files downloaded will be saved to |dir|.
+ DownloadDriverImpl(content::DownloadManager* manager,
+ const base::FilePath& dir);
+ ~DownloadDriverImpl() override;
+
+ // DownloadDriver implementation.
+ void Initialize(DownloadDriver::Client* client) override;
+ bool IsReady() const override;
+ void Start(const DownloadParams& params) override;
+ void Cancel(const std::string& guid) override;
+ void Pause(const std::string& guid) override;
+ void Resume(const std::string& guid) override;
+ base::Optional<DriverEntry> Find(const std::string& guid) override;
+
+ private:
+ // content::DownloadItem::Observer implementation.
+ void OnDownloadUpdated(content::DownloadItem* item) override;
+
+ // content::DownloadManager::Observer implementation.
+ void OnDownloadCreated(content::DownloadManager* manager,
+ content::DownloadItem* item) override;
+ void OnManagerInitialized() override;
+ void ManagerGoingDown(content::DownloadManager* manager) override;
+
+ // Low level download handle.
+ content::DownloadManager* download_manager_;
+
+ // Target directory of download files.
+ base::FilePath file_dir_;
+
+ // The client that receives updates from low level download logic.
+ DownloadDriver::Client* client_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadDriverImpl);
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_CONTENT_DOWNLOAD_DRIVER_IMPL_H_
diff --git a/components/download/content/download_driver_impl_unittest.cc b/components/download/content/download_driver_impl_unittest.cc
new file mode 100644
index 0000000..c53b490f
--- /dev/null
+++ b/components/download/content/download_driver_impl_unittest.cc
@@ -0,0 +1,129 @@
+// 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.
+
+#include "components/download/content/download_driver_impl.h"
+
+#include <memory>
+#include <string>
+
+#include "base/memory/ptr_util.h"
+#include "content/public/test/fake_download_item.h"
+#include "content/public/test/mock_download_manager.h"
+#include "net/http/http_response_headers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::NiceMock;
+using testing::Return;
+
+namespace download {
+
+namespace {
+
+const char kFakeGuid[] = "fake_guid";
+
+// Matcher to compare driver entries. Not all the memeber fields are compared.
+// Currently no comparison in non test code, so no operator== override for
+// driver entry.
+MATCHER_P(DriverEntryEuqual, entry, "") {
+ return entry.guid == arg.guid && entry.state == arg.state &&
+ entry.bytes_downloaded == arg.bytes_downloaded;
+}
+
+} // namespace
+
+class MockDriverClient : public DownloadDriver::Client {
+ public:
+ MOCK_METHOD1(OnDriverReady, void(bool));
+ MOCK_METHOD1(OnDownloadCreated, void(const DriverEntry&));
+ MOCK_METHOD2(OnDownloadFailed, void(const DriverEntry&, int));
+ MOCK_METHOD2(OnDownloadSucceeded,
+ void(const DriverEntry&, const base::FilePath&));
+ MOCK_METHOD1(OnDownloadUpdated, void(const DriverEntry&));
+};
+
+class DownloadDriverImplTest : public testing::Test {
+ public:
+ DownloadDriverImplTest() = default;
+ ~DownloadDriverImplTest() override = default;
+
+ void SetUp() override {
+ driver_ =
+ base::MakeUnique<DownloadDriverImpl>(&mock_manager_, base::FilePath());
+ }
+
+ // TODO(xingliu): implements test download manager for embedders to test.
+ NiceMock<content::MockDownloadManager> mock_manager_;
+ MockDriverClient mock_client_;
+ std::unique_ptr<DownloadDriverImpl> driver_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DownloadDriverImplTest);
+};
+
+// Ensure the download manager can be initialized after the download driver.
+TEST_F(DownloadDriverImplTest, ManagerLateInitialization) {
+ EXPECT_CALL(mock_manager_, IsManagerInitialized())
+ .Times(1)
+ .WillOnce(Return(false));
+ driver_->Initialize(&mock_client_);
+
+ EXPECT_CALL(mock_client_, OnDriverReady(true));
+ static_cast<content::DownloadManager::Observer*>(driver_.get())
+ ->OnManagerInitialized();
+}
+
+// Ensures download updates from download items are propagated correctly.
+TEST_F(DownloadDriverImplTest, DownloadItemUpdateEvents) {
+ using DownloadState = content::DownloadItem::DownloadState;
+ using DownloadInterruptReason = content::DownloadInterruptReason;
+
+ EXPECT_CALL(mock_manager_, IsManagerInitialized())
+ .Times(1)
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_client_, OnDriverReady(true)).Times(1);
+ driver_->Initialize(&mock_client_);
+
+ content::FakeDownloadItem fake_item;
+ fake_item.SetState(DownloadState::IN_PROGRESS);
+ fake_item.SetGuid(kFakeGuid);
+ fake_item.SetReceivedBytes(0);
+ fake_item.SetTotalBytes(1024);
+ DriverEntry entry = DownloadDriverImpl::CreateDriverEntry(&fake_item);
+
+ EXPECT_CALL(mock_client_, OnDownloadUpdated(DriverEntryEuqual(entry)))
+ .Times(1)
+ .RetiresOnSaturation();
+ static_cast<content::DownloadItem::Observer*>(driver_.get())
+ ->OnDownloadUpdated(&fake_item);
+
+ // Nothing happens for cancelled state.
+ fake_item.SetState(DownloadState::CANCELLED);
+ static_cast<content::DownloadItem::Observer*>(driver_.get())
+ ->OnDownloadUpdated(&fake_item);
+
+ fake_item.SetReceivedBytes(1024);
+ fake_item.SetState(DownloadState::COMPLETE);
+ entry = DownloadDriverImpl::CreateDriverEntry(&fake_item);
+ EXPECT_CALL(mock_client_, OnDownloadSucceeded(DriverEntryEuqual(entry), _))
+ .Times(1)
+ .RetiresOnSaturation();
+ static_cast<content::DownloadItem::Observer*>(driver_.get())
+ ->OnDownloadUpdated(&fake_item);
+
+ fake_item.SetState(DownloadState::INTERRUPTED);
+ fake_item.SetLastReason(
+ DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT);
+ entry = DownloadDriverImpl::CreateDriverEntry(&fake_item);
+ int reason = static_cast<int>(
+ DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT);
+ EXPECT_CALL(mock_client_, OnDownloadFailed(DriverEntryEuqual(entry), reason))
+ .Times(1)
+ .RetiresOnSaturation();
+ static_cast<content::DownloadItem::Observer*>(driver_.get())
+ ->OnDownloadUpdated(&fake_item);
+}
+
+} // namespace download
diff --git a/components/download/internal/BUILD.gn b/components/download/internal/BUILD.gn
index 7e35171..d1e1e43 100644
--- a/components/download/internal/BUILD.gn
+++ b/components/download/internal/BUILD.gn
@@ -11,14 +11,18 @@
visibility = [
":*",
"//components/download",
+ "//components/download/content",
"//components/download/internal/test:test_support",
]
sources = [
"config.cc",
"config.h",
+ "download_driver.h",
"download_service_impl.cc",
"download_service_impl.h",
+ "driver_entry.cc",
+ "driver_entry.h",
"entry.cc",
"entry.h",
"model.h",
diff --git a/components/download/internal/DEPS b/components/download/internal/DEPS
index a348cdf..4ca86d9b 100644
--- a/components/download/internal/DEPS
+++ b/components/download/internal/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "-components/download/content",
"-content",
"+base",
"+net",
diff --git a/components/download/internal/download_driver.h b/components/download/internal/download_driver.h
new file mode 100644
index 0000000..88247d1
--- /dev/null
+++ b/components/download/internal/download_driver.h
@@ -0,0 +1,76 @@
+// 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_DOWNLOAD_DRIVER_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_DRIVER_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "components/download/internal/driver_entry.h"
+
+namespace base {
+class FilePath;
+} // namespace base
+
+namespace download {
+
+struct DownloadParams;
+
+// The interface that includes all the operations to interact with low level
+// download library functionalities.
+class DownloadDriver {
+ public:
+ // The client to receive updates from content download library.
+ // The update events for all downloads will pass through, so it's the
+ // client's responsibility to filter the events it needs to handle.
+ class Client {
+ public:
+ // Called when the low level download library is ready. |success| is true
+ // when the low level download library is ready.
+ virtual void OnDriverReady(bool success) = 0;
+
+ // Called when any download is created.
+ virtual void OnDownloadCreated(const DriverEntry& download) = 0;
+
+ // Called when any download is failed. |reason| is propagated from low level
+ // download library.
+ virtual void OnDownloadFailed(const DriverEntry& download, int reason) = 0;
+
+ // Called when any download is successfully completed.
+ virtual void OnDownloadSucceeded(const DriverEntry& download,
+ const base::FilePath& path) = 0;
+
+ // Called when any download is updated.
+ virtual void OnDownloadUpdated(const DriverEntry& download) = 0;
+ };
+
+ // Initialize the driver to receive download updates.
+ virtual void Initialize(Client* client) = 0;
+
+ // Returns if the driver is ready. Returns false when the driver is not
+ // initialized by the client, or low level download library has been shut
+ // down.
+ virtual bool IsReady() const = 0;
+
+ // Starts a new download.
+ virtual void Start(const DownloadParams& params) = 0;
+
+ // Cancels an existing download, all data associated with this download should
+ // be removed.
+ virtual void Cancel(const std::string& guid) = 0;
+
+ // Pauses the download.
+ virtual void Pause(const std::string& guid) = 0;
+
+ // Resumes the download
+ virtual void Resume(const std::string& guid) = 0;
+
+ // Find a download record from low level download library.
+ virtual base::Optional<DriverEntry> Find(const std::string& guid) = 0;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_INTERNAL_DOWNLOAD_DRIVER_H_
diff --git a/components/download/internal/driver_entry.cc b/components/download/internal/driver_entry.cc
new file mode 100644
index 0000000..88ab03df2
--- /dev/null
+++ b/components/download/internal/driver_entry.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "components/download/internal/driver_entry.h"
+
+#include "net/http/http_response_headers.h"
+
+namespace download {
+
+DriverEntry::DriverEntry()
+ : state(State::UNKNOWN),
+ paused(false),
+ bytes_downloaded(0u),
+ expected_total_size(0u) {}
+
+DriverEntry::DriverEntry(const DriverEntry& other) = default;
+
+DriverEntry::~DriverEntry() = default;
+
+} // namespace download
diff --git a/components/download/internal/driver_entry.h b/components/download/internal/driver_entry.h
new file mode 100644
index 0000000..a21a431
--- /dev/null
+++ b/components/download/internal/driver_entry.h
@@ -0,0 +1,61 @@
+// 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_DRIVER_ENTRY_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_DRIVER_ENTRY_H_
+
+#include <string>
+
+#include "base/memory/ref_counted.h"
+
+namespace net {
+class HttpResponseHeaders;
+} // namespace net
+
+namespace content {
+class DownloadItem;
+} // namespace content
+
+namespace download {
+
+// A snapshot of the states of a download. It's preferred to use the data on the
+// fly and query new ones from download driver, instead of caching the states.
+struct DriverEntry {
+ // States of the download. Mostly maps to
+ // content::DownloadItem::DownloadState.
+ enum class State {
+ IN_PROGRESS = 0,
+ COMPLETE = 1,
+ CANCELLED = 2,
+ INTERRUPTED = 3,
+ UNKNOWN = 4, /* Not created from a download item object. */
+ };
+
+ DriverEntry();
+ DriverEntry(const DriverEntry& other);
+ ~DriverEntry();
+
+ // The unique identifier of the download.
+ std::string guid;
+
+ // The current state of the download.
+ State state;
+
+ // If the download is paused.
+ bool paused;
+
+ // The number of bytes downloaded.
+ uint64_t bytes_downloaded;
+
+ // The expected total size of the download, set to 0 if the Content-Length
+ // http header is not presented.
+ uint64_t expected_total_size;
+
+ // The response headers for the most recent download request.
+ scoped_refptr<const net::HttpResponseHeaders> response_headers;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_INTERNAL_DRIVER_ENTRY_H_
diff --git a/components/download/internal/test/BUILD.gn b/components/download/internal/test/BUILD.gn
index cabd4ee..87032dc 100644
--- a/components/download/internal/test/BUILD.gn
+++ b/components/download/internal/test/BUILD.gn
@@ -12,6 +12,8 @@
"entry_utils.h",
"mock_model_client.cc",
"mock_model_client.h",
+ "test_download_driver.cc",
+ "test_download_driver.h",
"test_store.cc",
"test_store.h",
]
@@ -19,6 +21,7 @@
public_deps = [
"//base",
"//components/download/internal",
+ "//components/download/public",
"//testing/gmock",
]
}
diff --git a/components/download/internal/test/test_download_driver.cc b/components/download/internal/test/test_download_driver.cc
new file mode 100644
index 0000000..78de8d77
--- /dev/null
+++ b/components/download/internal/test/test_download_driver.cc
@@ -0,0 +1,84 @@
+// 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.
+
+#include "components/download/internal/test/test_download_driver.h"
+
+#include "base/files/file_path.h"
+#include "components/download/public/download_params.h"
+#include "net/http/http_response_headers.h"
+
+namespace download {
+
+TestDownloadDriver::TestDownloadDriver() : is_ready_(false), client_(nullptr) {}
+
+TestDownloadDriver::~TestDownloadDriver() = default;
+
+void TestDownloadDriver::MakeReady() {
+ is_ready_ = true;
+ DCHECK(client_);
+ if (client_)
+ client_->OnDriverReady(is_ready_);
+}
+
+void TestDownloadDriver::NotifyDownloadUpdate(const DriverEntry& entry) {
+ if (client_) {
+ entries_[entry.guid] = entry;
+ client_->OnDownloadUpdated(entry);
+ }
+}
+
+void TestDownloadDriver::NotifyDownloadFailed(const DriverEntry& entry,
+ int reason) {
+ if (client_) {
+ entries_[entry.guid] = entry;
+ client_->OnDownloadFailed(entry, reason);
+ }
+}
+
+void TestDownloadDriver::NotifyDownloadSucceeded(const DriverEntry& entry,
+ const base::FilePath& path) {
+ if (client_) {
+ entries_[entry.guid] = entry;
+ client_->OnDownloadSucceeded(entry, path);
+ }
+}
+
+void TestDownloadDriver::Initialize(DownloadDriver::Client* client) {
+ DCHECK(!client_);
+ client_ = client;
+}
+
+bool TestDownloadDriver::IsReady() const {
+ return is_ready_;
+}
+
+void TestDownloadDriver::Start(const DownloadParams& params) {
+ DriverEntry entry;
+ entry.guid = params.guid;
+ entry.state = DriverEntry::State::IN_PROGRESS;
+ entry.paused = false;
+ entry.bytes_downloaded = 0;
+ entry.expected_total_size = 0;
+ entry.response_headers =
+ base::MakeRefCounted<net::HttpResponseHeaders>("HTTP/1.1 200");
+ entries_[params.guid] = entry;
+
+ if (client_)
+ client_->OnDownloadCreated(entry);
+}
+
+void TestDownloadDriver::Cancel(const std::string& guid) {}
+
+void TestDownloadDriver::Pause(const std::string& guid) {}
+
+void TestDownloadDriver::Resume(const std::string& guid) {}
+
+base::Optional<DriverEntry> TestDownloadDriver::Find(const std::string& guid) {
+ auto it = entries_.find(guid);
+ if (it == entries_.end())
+ return base::nullopt;
+ return it->second;
+}
+
+} // namespace downloads
diff --git a/components/download/internal/test/test_download_driver.h b/components/download/internal/test/test_download_driver.h
new file mode 100644
index 0000000..0ee9f3d
--- /dev/null
+++ b/components/download/internal/test/test_download_driver.h
@@ -0,0 +1,53 @@
+// 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_TEST_TEST_DOWNLOAD_DRIVER_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_TEST_TEST_DOWNLOAD_DRIVER_H_
+
+#include <map>
+#include <memory>
+
+#include "base/macros.h"
+#include "components/download/internal/download_driver.h"
+
+namespace download {
+
+// Download driver that simulates content layer download logic.
+class TestDownloadDriver : public DownloadDriver {
+ public:
+ TestDownloadDriver();
+ ~TestDownloadDriver();
+
+ // Marks download driver as ready, used to test logic that depends on
+ // data initialization.
+ void MakeReady();
+
+ // Simulates download events from content layer.
+ void NotifyDownloadUpdate(const DriverEntry& entry);
+ void NotifyDownloadFailed(const DriverEntry& entry, int reason);
+ void NotifyDownloadSucceeded(const DriverEntry& entry,
+ const base::FilePath& path);
+
+ // DownloadDriver implementation.
+ void Initialize(DownloadDriver::Client* client) override;
+ bool IsReady() const override;
+ void Start(const DownloadParams& params) override;
+ void Cancel(const std::string& guid) override;
+ void Pause(const std::string& guid) override;
+ void Resume(const std::string& guid) override;
+ base::Optional<DriverEntry> Find(const std::string& guid) override;
+
+ private:
+ bool is_ready_;
+ DownloadDriver::Client* client_;
+
+ // Map of guid --> DriverEntry.
+ std::map<std::string, DriverEntry> entries_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDownloadDriver);
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_CONTENT_TEST_TEST_DOWNLOAD_DRIVER_H_
diff --git a/content/browser/download/download_create_info.h b/content/browser/download/download_create_info.h
index 1f6c773..3ebcaf2 100644
--- a/content/browser/download/download_create_info.h
+++ b/content/browser/download/download_create_info.h
@@ -44,9 +44,12 @@
// redirection by the server for |url_chain|.
const GURL& url() const;
- // The ID of the download.
+ // The ID of the download. (Deprecated)
uint32_t download_id;
+ // The unique identifier for the download.
+ std::string guid;
+
// The chain of redirects that leading up to and including the final URL.
std::vector<GURL> url_chain;
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index 1132560..dccaf11c 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -203,7 +203,8 @@
uint32_t download_id,
const DownloadCreateInfo& info,
const net::NetLogWithSource& net_log)
- : guid_(base::ToUpperASCII(base::GenerateGUID())),
+ : guid_(info.guid.empty() ? base::ToUpperASCII(base::GenerateGUID())
+ : info.guid),
download_id_(download_id),
target_disposition_((info.save_info->prompt_for_save_location)
? TARGET_DISPOSITION_PROMPT
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 44ac7f5..ecd6d88 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -181,6 +181,7 @@
: item_factory_(new DownloadItemFactoryImpl()),
file_factory_(new DownloadFileFactory()),
shutdown_needed_(true),
+ initialized_(false),
browser_context_(browser_context),
delegate_(nullptr),
net_log_(net_log),
@@ -674,6 +675,17 @@
return item;
}
+void DownloadManagerImpl::PostInitialization() {
+ DCHECK(!initialized_);
+ initialized_ = true;
+ for (auto& observer : observers_)
+ observer.OnManagerInitialized();
+}
+
+bool DownloadManagerImpl::IsManagerInitialized() const {
+ return initialized_;
+}
+
int DownloadManagerImpl::InProgressCount() const {
int count = 0;
for (const auto& it : downloads_) {
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index 0128c28..e9b13f6 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -108,6 +108,8 @@
base::Time last_access_time,
bool transient,
const std::vector<DownloadItem::ReceivedSlice>& received_slices) override;
+ void PostInitialization() override;
+ bool IsManagerInitialized() const override;
int InProgressCount() const override;
int NonMaliciousInProgressCount() const override;
BrowserContext* GetBrowserContext() const override;
@@ -227,6 +229,9 @@
// True if the download manager has been initialized and requires a shutdown.
bool shutdown_needed_;
+ // True if the download manager has been initialized and loaded all the data.
+ bool initialized_;
+
// Observers that want to be notified of changes to the set of downloads.
base::ObserverList<Observer> observers_;
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index 7c55b93..6dd961b0 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -65,6 +65,7 @@
return std::move(save_info_);
}
uint32_t download_id() const { return download_id_; }
+ std::string guid() const { return guid_; }
bool is_transient() const { return transient_; }
const DownloadUrlParameters::OnStartedCallback& callback() const {
return on_started_callback_;
@@ -75,6 +76,7 @@
std::unique_ptr<DownloadSaveInfo> save_info_;
uint32_t download_id_ = DownloadItem::kInvalidId;
+ std::string guid_;
bool transient_ = false;
DownloadUrlParameters::OnStartedCallback on_started_callback_;
};
@@ -90,6 +92,7 @@
request_data->save_info_.reset(
new DownloadSaveInfo(parameters->GetSaveInfo()));
request_data->download_id_ = download_id;
+ request_data->guid_ = parameters->guid();
request_data->transient_ = parameters->is_transient();
request_data->on_started_callback_ = parameters->callback();
request->SetUserData(&kKey, std::move(request_data));
@@ -221,6 +224,7 @@
if (request_data) {
save_info_ = request_data->TakeSaveInfo();
download_id_ = request_data->download_id();
+ guid_ = request_data->guid();
transient_ = request_data->is_transient();
on_started_callback_ = request_data->callback();
DownloadRequestData::Detach(request_);
@@ -251,6 +255,7 @@
create_info->referrer_url = GURL(request()->referrer());
create_info->result = result;
create_info->download_id = download_id_;
+ create_info->guid = guid_;
create_info->transient = transient_;
create_info->response_headers = request()->response_headers();
create_info->offset = create_info->save_info->offset;
diff --git a/content/browser/download/download_request_core.h b/content/browser/download/download_request_core.h
index dae93986..fc2ccd2 100644
--- a/content/browser/download/download_request_core.h
+++ b/content/browser/download/download_request_core.h
@@ -135,6 +135,7 @@
// populate the DownloadCreateInfo when the time comes.
std::unique_ptr<DownloadSaveInfo> save_info_;
uint32_t download_id_;
+ std::string guid_;
bool transient_;
DownloadUrlParameters::OnStartedCallback on_started_callback_;
diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h
index 9e38db2..f6080fe5 100644
--- a/content/public/browser/download_manager.h
+++ b/content/public/browser/download_manager.h
@@ -84,6 +84,9 @@
virtual void OnSavePackageSuccessfullyFinished(
DownloadManager* manager, DownloadItem* item) {}
+ // Called when the download manager has finished loading the data.
+ virtual void OnManagerInitialized() {}
+
// Called when the DownloadManager is being destroyed to prevent Observers
// from calling back to a stale pointer.
virtual void ManagerGoingDown(DownloadManager* manager) {}
@@ -155,6 +158,12 @@
bool transient,
const std::vector<DownloadItem::ReceivedSlice>& received_slices) = 0;
+ // Called when download manager has loaded all the data.
+ virtual void PostInitialization() = 0;
+
+ // Returns if the manager has been initialized and loaded all the data.
+ virtual bool IsManagerInitialized() const = 0;
+
// The number of in progress (including paused) downloads.
// Performance note: this loops over all items. If profiling finds that this
// is too slow, use an AllDownloadItemNotifier to count in-progress items.
diff --git a/content/public/browser/download_url_parameters.h b/content/public/browser/download_url_parameters.h
index b1a8bce..a88be116 100644
--- a/content/public/browser/download_url_parameters.h
+++ b/content/public/browser/download_url_parameters.h
@@ -209,6 +209,11 @@
// download is short-lived and is not shown in the UI.
void set_transient(bool transient) { transient_ = transient; }
+ // Sets the optional guid for the download, the guid serves as the unique
+ // identitfier for the download item. If no guid is provided, download
+ // system will automatically generate one.
+ void set_guid(const std::string& guid) { guid_ = guid; }
+
// For downloads of blob URLs, the caller can store a BlobDataHandle in the
// DownloadUrlParameters object so that the blob will remain valid until
// the download starts. The BlobDataHandle will be attached to the associated
@@ -262,6 +267,7 @@
const GURL& url() const { return url_; }
bool do_not_prompt_for_login() const { return do_not_prompt_for_login_; }
bool is_transient() const { return transient_; }
+ std::string guid() const { return guid_; }
// STATE_CHANGING: Return the BlobDataHandle.
std::unique_ptr<storage::BlobDataHandle> GetBlobDataHandle() {
@@ -294,6 +300,7 @@
GURL url_;
bool do_not_prompt_for_login_;
bool transient_;
+ std::string guid_;
std::unique_ptr<storage::BlobDataHandle> blob_data_handle_;
DISALLOW_COPY_AND_ASSIGN(DownloadUrlParameters);
diff --git a/content/public/test/fake_download_item.cc b/content/public/test/fake_download_item.cc
index ccc2188..4ae0a1b 100644
--- a/content/public/test/fake_download_item.cc
+++ b/content/public/test/fake_download_item.cc
@@ -157,6 +157,10 @@
received_bytes_ = received_bytes;
}
+void FakeDownloadItem::SetTotalBytes(int64_t total_bytes) {
+ total_bytes_ = total_bytes;
+}
+
int64_t FakeDownloadItem::GetReceivedBytes() const {
return received_bytes_;
}
@@ -206,7 +210,6 @@
}
bool FakeDownloadItem::IsPaused() const {
- NOTREACHED();
return false;
}
@@ -351,8 +354,7 @@
}
int64_t FakeDownloadItem::GetTotalBytes() const {
- NOTREACHED();
- return 1;
+ return total_bytes_;
}
const std::vector<DownloadItem::ReceivedSlice>&
diff --git a/content/public/test/fake_download_item.h b/content/public/test/fake_download_item.h
index f2e23057..504477c 100644
--- a/content/public/test/fake_download_item.h
+++ b/content/public/test/fake_download_item.h
@@ -80,6 +80,9 @@
void SetReceivedBytes(int64_t received_bytes);
int64_t GetReceivedBytes() const override;
+ void SetTotalBytes(int64_t total_bytes);
+ int64_t GetTotalBytes() const override;
+
void SetLastAccessTime(base::Time time) override;
base::Time GetLastAccessTime() const override;
@@ -122,7 +125,6 @@
int64_t CurrentSpeed() const override;
int PercentComplete() const override;
bool AllDataSaved() const override;
- int64_t GetTotalBytes() const override;
const std::vector<DownloadItem::ReceivedSlice>& GetReceivedSlices()
const override;
bool CanShowInFolder() override;
@@ -160,6 +162,7 @@
DownloadInterruptReason last_reason_ =
DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_NONE;
int64_t received_bytes_ = 0;
+ int64_t total_bytes_ = 0;
// The members below are to be returned by methods, which return by reference.
std::string dummy_string;
diff --git a/content/public/test/mock_download_manager.h b/content/public/test/mock_download_manager.h
index 41ca921..f462fa1 100644
--- a/content/public/test/mock_download_manager.h
+++ b/content/public/test/mock_download_manager.h
@@ -148,7 +148,8 @@
MOCK_METHOD1(MockCreateDownloadItem,
DownloadItem*(CreateDownloadItemAdapter adapter));
-
+ MOCK_METHOD0(PostInitialization, void());
+ MOCK_CONST_METHOD0(IsManagerInitialized, bool());
MOCK_CONST_METHOD0(InProgressCount, int());
MOCK_CONST_METHOD0(NonMaliciousInProgressCount, int());
MOCK_CONST_METHOD0(GetBrowserContext, BrowserContext*());