summaryrefslogtreecommitdiff
path: root/chromium/content/browser/download
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-13 15:05:36 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-02-14 10:33:47 +0000
commite684a3455bcc29a6e3e66a004e352dea4e1141e7 (patch)
treed55b4003bde34d7d05f558f02cfd82b2a66a7aac /chromium/content/browser/download
parent2b94bfe47ccb6c08047959d1c26e392919550e86 (diff)
downloadqtwebengine-chromium-e684a3455bcc29a6e3e66a004e352dea4e1141e7.tar.gz
BASELINE: Update Chromium to 72.0.3626.110 and Ninja to 1.9.0
Change-Id: Ic57220b00ecc929a893c91f5cc552f5d3e99e922 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/content/browser/download')
-rw-r--r--chromium/content/browser/download/download_browsertest.cc70
-rw-r--r--chromium/content/browser/download/download_manager_impl.cc219
-rw-r--r--chromium/content/browser/download/download_manager_impl.h37
-rw-r--r--chromium/content/browser/download/download_manager_impl_unittest.cc119
-rw-r--r--chromium/content/browser/download/download_request_utils.cc13
-rw-r--r--chromium/content/browser/download/download_resource_handler.cc1
-rw-r--r--chromium/content/browser/download/download_utils.cc2
-rw-r--r--chromium/content/browser/download/file_download_url_loader_factory_getter.cc16
-rw-r--r--chromium/content/browser/download/file_download_url_loader_factory_getter.h11
-rw-r--r--chromium/content/browser/download/url_downloader.cc40
-rw-r--r--chromium/content/browser/download/url_downloader.h3
-rw-r--r--chromium/content/browser/download/url_downloader_factory.cc1
-rw-r--r--chromium/content/browser/download/url_downloader_factory.h2
13 files changed, 437 insertions, 97 deletions
diff --git a/chromium/content/browser/download/download_browsertest.cc b/chromium/content/browser/download/download_browsertest.cc
index 97421cd8745..4fcfe051d6c 100644
--- a/chromium/content/browser/download/download_browsertest.cc
+++ b/chromium/content/browser/download/download_browsertest.cc
@@ -1686,6 +1686,72 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, RedirectWhileResume) {
EXPECT_GT(parameters.size, requests[2]->transferred_byte_count);
}
+// Verify that DownloadUrl can support URL redirect.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RedirectDownload) {
+ // Setup a redirect chain with two URL.
+ GURL first_url = embedded_test_server()->GetURL("example.com", "/first-url");
+ GURL download_url =
+ embedded_test_server()->GetURL("example.com", "/download");
+ TestDownloadHttpResponse::StartServingStaticResponse(
+ base::StringPrintf("HTTP/1.1 302 Redirect\r\n"
+ "Location: %s\r\n\r\n",
+ download_url.spec().c_str()),
+ first_url);
+ TestDownloadHttpResponse::StartServing(TestDownloadHttpResponse::Parameters(),
+ download_url);
+
+ // Start a download and explicitly specify to support redirect.
+ std::unique_ptr<DownloadTestObserver> observer(CreateWaiter(shell(), 1));
+ auto download_parameters = std::make_unique<download::DownloadUrlParameters>(
+ first_url, TRAFFIC_ANNOTATION_FOR_TESTS);
+ download_parameters->set_follow_cross_origin_redirects(true);
+ DownloadManagerForShell(shell())->DownloadUrl(std::move(download_parameters));
+ observer->WaitForFinished();
+
+ // Verify download is done.
+ std::vector<download::DownloadItem*> downloads;
+ DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+ EXPECT_EQ(1u, downloads.size());
+ EXPECT_EQ(download::DownloadItem::COMPLETE, downloads[0]->GetState());
+}
+
+// Verify that DownloadUrl() to URL with unsafe scheme should fail.
+IN_PROC_BROWSER_TEST_F(DownloadContentTest, RedirectUnsafeDownload) {
+ // Setup a redirect chain with two URL.
+ GURL first_url = embedded_test_server()->GetURL("example.com", "/first-url");
+ GURL unsafe_url = GURL("unsafe:///etc/passwd");
+ TestDownloadHttpResponse::StartServingStaticResponse(
+ base::StringPrintf("HTTP/1.1 302 Redirect\r\n"
+ "Location: %s\r\n\r\n",
+ unsafe_url.spec().c_str()),
+ first_url);
+ TestDownloadHttpResponse::StartServing(TestDownloadHttpResponse::Parameters(),
+ unsafe_url);
+
+ // Start a download and explicitly specify to support redirect.
+ DownloadManager* download_manager = DownloadManagerForShell(shell());
+ std::unique_ptr<DownloadTestObserverInterrupted> observer =
+ std::make_unique<DownloadTestObserverInterrupted>(
+ download_manager, 1,
+ DownloadTestObserver::ON_DANGEROUS_DOWNLOAD_FAIL);
+ auto download_parameters = std::make_unique<download::DownloadUrlParameters>(
+ first_url, TRAFFIC_ANNOTATION_FOR_TESTS);
+ download_parameters->set_follow_cross_origin_redirects(true);
+ download_manager->DownloadUrl(std::move(download_parameters));
+ observer->WaitForFinished();
+
+ // Verify download failed.
+ std::vector<download::DownloadItem*> downloads;
+ DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
+ EXPECT_EQ(1u, downloads.size());
+ EXPECT_EQ(download::DownloadItem::INTERRUPTED, downloads[0]->GetState());
+
+ // The interrupt reason must match, notice the embedded test server used in
+ // tests may also fail even if the download passed the security check.
+ EXPECT_EQ(download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
+ downloads[0]->GetLastReason());
+}
+
// If the server response for the resumption request specifies a bad range (i.e.
// not the range that was requested or an invalid or missing Content-Range
// header), then the download should be marked as interrupted again without
@@ -3237,8 +3303,8 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeNetworkError) {
IN_PROC_BROWSER_TEST_F(DownloadContentTest, DownloadAttributeInvalidURL) {
GURL url = embedded_test_server()->GetURL(
"/download/download-attribute.html?target=about:version");
- auto observer = std::make_unique<content::TestNavigationObserver>(
- GURL(url::kAboutBlankURL));
+ auto observer =
+ std::make_unique<content::TestNavigationObserver>(GURL(kBlockedURL));
observer->WatchExistingWebContents();
observer->StartWatchingNewWebContents();
NavigateToURL(shell(), url);
diff --git a/chromium/content/browser/download/download_manager_impl.cc b/chromium/content/browser/download/download_manager_impl.cc
index a0220133cd2..74940229a0d 100644
--- a/chromium/content/browser/download/download_manager_impl.cc
+++ b/chromium/content/browser/download/download_manager_impl.cc
@@ -23,7 +23,6 @@
#include "base/task/post_task.h"
#include "build/build_config.h"
#include "components/download/database/in_progress/download_entry.h"
-#include "components/download/database/in_progress/in_progress_cache_impl.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_features.h"
#include "components/download/public/common/download_file.h"
@@ -40,7 +39,7 @@
#include "components/download/public/common/url_download_handler_factory.h"
#include "content/browser/byte_stream.h"
#include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/devtools/render_frame_devtools_agent_host.h"
+#include "content/browser/devtools/devtools_instrumentation.h"
#include "content/browser/download/byte_stream_input_stream.h"
#include "content/browser/download/download_resource_handler.h"
#include "content/browser/download/download_utils.h"
@@ -61,13 +60,13 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/download_item_utils.h"
#include "content/public/browser/download_manager_delegate.h"
+#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/web_contents_delegate.h"
-#include "content/public/common/browser_side_navigation_policy.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/previews_state.h"
#include "content/public/common/referrer.h"
@@ -89,6 +88,17 @@
namespace content {
namespace {
+#if defined(OS_ANDROID)
+void DeleteDownloadedFileOnUIThread(const base::FilePath& file_path) {
+ if (!file_path.empty()) {
+ download::GetDownloadTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(base::IgnoreResult(&download::DeleteDownloadedFile),
+ file_path));
+ }
+}
+#endif
+
StoragePartitionImpl* GetStoragePartition(BrowserContext* context,
int render_process_id,
int render_frame_id) {
@@ -105,18 +115,6 @@ StoragePartitionImpl* GetStoragePartition(BrowserContext* context,
BrowserContext::GetStoragePartition(context, site_instance));
}
-bool CanRequestURLFromRenderer(int render_process_id, GURL url) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // Check if the renderer is permitted to request the requested URL.
- if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL(
- render_process_id, url)) {
- DVLOG(1) << "Denied unauthorized download request for "
- << url.possibly_invalid_spec();
- return false;
- }
- return true;
-}
-
void OnDownloadStarted(
download::DownloadItemImpl* download,
const download::DownloadUrlParameters::OnStartedCallback& on_started) {
@@ -279,7 +277,7 @@ CreateDownloadURLLoaderFactoryGetter(StoragePartitionImpl* storage_partition,
network::mojom::URLLoaderFactoryPtrInfo devtools_factory_ptr_info;
network::mojom::URLLoaderFactoryRequest devtools_factory_request =
MakeRequest(&devtools_factory_ptr_info);
- if (RenderFrameDevToolsAgentHost::WillCreateURLLoaderFactory(
+ if (devtools_instrumentation::WillCreateURLLoaderFactory(
static_cast<RenderFrameHostImpl*>(rfh), true, is_download,
&devtools_factory_request)) {
proxy_factory_ptr_info = std::move(devtools_factory_ptr_info);
@@ -305,6 +303,9 @@ DownloadManagerImpl::DownloadManagerImpl(BrowserContext* browser_context)
browser_context_->RetriveInProgressDownloadManager()),
next_download_id_(download::DownloadItem::kInvalidId),
is_history_download_id_retrieved_(false),
+ should_persist_new_download_(false),
+ cancelled_download_cleared_from_history_(0),
+ interrupted_download_cleared_from_history_(0),
weak_factory_(this) {
DCHECK(browser_context);
download::SetIOTaskRunner(
@@ -317,7 +318,8 @@ DownloadManagerImpl::DownloadManagerImpl(BrowserContext* browser_context)
std::make_unique<download::InProgressDownloadManager>(
this,
IsOffTheRecord() ? base::FilePath() : browser_context_->GetPath(),
- base::BindRepeating(&IsOriginSecure));
+ base::BindRepeating(&IsOriginSecure),
+ base::BindRepeating(&DownloadRequestUtils::IsURLSafe));
} else {
in_progress_manager_->set_delegate(this);
in_progress_manager_->set_download_start_observer(nullptr);
@@ -367,7 +369,7 @@ void DownloadManagerImpl::GetNextId(GetNextIdCallback callback) {
base::BindRepeating(&DownloadManagerImpl::OnHistoryNextIdRetrived,
weak_factory_.GetWeakPtr()));
} else {
- OnHistoryNextIdRetrived(download::DownloadItem::kInvalidId + 1);
+ OnHistoryNextIdRetrived(download::DownloadItem::kInvalidId);
}
}
}
@@ -386,6 +388,10 @@ void DownloadManagerImpl::SetNextId(uint32_t next_id) {
void DownloadManagerImpl::OnHistoryNextIdRetrived(uint32_t next_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
is_history_download_id_retrieved_ = true;
+ if (next_id == download::DownloadItem::kInvalidId)
+ next_id++;
+ else
+ should_persist_new_download_ = true;
SetNextId(next_id);
}
@@ -544,19 +550,23 @@ void DownloadManagerImpl::OnInProgressDownloadManagerInitialized() {
in_progress_downloads = in_progress_manager_->TakeInProgressDownloads();
uint32_t max_id = download::DownloadItem::kInvalidId;
for (auto& download : in_progress_downloads) {
- DCHECK(!base::ContainsKey(downloads_by_guid_, download->GetGuid()));
- DCHECK(!base::ContainsKey(downloads_, download->GetId()));
- DownloadItemUtils::AttachInfo(download.get(), GetBrowserContext(), nullptr);
- download::DownloadItemImpl* item = download.get();
- item->SetDelegate(this);
- downloads_by_guid_[download->GetGuid()] = item;
uint32_t id = download->GetId();
- downloads_[id] = std::move(download);
+ if (base::ContainsKey(in_progress_downloads_, id)) {
+ in_progress_manager_->RemoveInProgressDownload(download->GetGuid());
+ continue;
+ }
if (id > max_id)
max_id = id;
- for (auto& observer : observers_)
- observer.OnDownloadCreated(this, item);
- DVLOG(20) << __func__ << "() download = " << item->DebugString(true);
+#if defined(OS_ANDROID)
+ // On android, clean up cancelled and non resumable interrupted downloads.
+ if (ShouldClearDownloadFromDB(download->GetURL(), download->GetState(),
+ download->GetLastReason())) {
+ cleared_download_guids_on_startup_.insert(download->GetGuid());
+ DeleteDownloadedFileOnUIThread(download->GetFullPath());
+ continue;
+ }
+#endif // defined(OS_ANDROID)
+ in_progress_downloads_[id] = std::move(download);
}
PostInitialization(DOWNLOAD_INITIALIZATION_DEPENDENCY_IN_PROGRESS_CACHE);
SetNextId(max_id + 1);
@@ -572,7 +582,8 @@ void DownloadManagerImpl::StartDownloadItem(
download::DownloadItemImpl* download = downloads_by_guid_[info->guid];
if (!download || download->GetState() == download::DownloadItem::CANCELLED)
download = nullptr;
- std::move(callback).Run(std::move(info), download);
+ std::move(callback).Run(std::move(info), download,
+ should_persist_new_download_);
OnDownloadStarted(download, on_started);
} else {
GetNextId(base::BindOnce(&DownloadManagerImpl::CreateNewDownloadItemToStart,
@@ -589,7 +600,8 @@ void DownloadManagerImpl::CreateNewDownloadItemToStart(
DCHECK_CURRENTLY_ON(BrowserThread::UI);
download::DownloadItemImpl* download = CreateActiveItem(id, *info);
- std::move(callback).Run(std::move(info), download);
+ std::move(callback).Run(std::move(info), download,
+ should_persist_new_download_);
// 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.
@@ -703,11 +715,7 @@ void DownloadManagerImpl::CreateSavePackageDownloadItemWithId(
DownloadItemUtils::AttachInfo(download_item, GetBrowserContext(),
WebContentsImpl::FromRenderFrameHostID(
render_process_id, render_frame_id));
- downloads_[download_item->GetId()] = base::WrapUnique(download_item);
- DCHECK(!base::ContainsKey(downloads_by_guid_, download_item->GetGuid()));
- downloads_by_guid_[download_item->GetGuid()] = download_item;
- for (auto& observer : observers_)
- observer.OnDownloadCreated(this, download_item);
+ OnDownloadCreated(base::WrapUnique(download_item));
if (!item_created.is_null())
item_created.Run(download_item);
}
@@ -943,29 +951,55 @@ download::DownloadItem* DownloadManagerImpl::CreateDownloadItem(
base::Time last_access_time,
bool transient,
const std::vector<download::DownloadItem::ReceivedSlice>& received_slices) {
- if (base::ContainsKey(downloads_, id)) {
- // If a completed or cancelled download item is already in the history db,
- // remove it from the in-progress db.
- if (state == download::DownloadItem::COMPLETE ||
- state == download::DownloadItem::CANCELLED) {
- in_progress_manager_->RemoveInProgressDownload(guid);
- } else {
- return downloads_[id].get();
- }
+ // Retrive the in-progress download if it exists. Notice that this also
+ // removes it from |in_progress_downloads_|.
+ auto in_progress_download = RetrieveInProgressDownload(id);
+#if defined(OS_ANDROID)
+ // On Android, there is no way to interact with cancelled or non-resumable
+ // download. Simply returning null and don't store them in this class to
+ // reduce memory usage.
+ if (cleared_download_guids_on_startup_.find(guid) !=
+ cleared_download_guids_on_startup_.end()) {
+ return nullptr;
+ }
+ if (url_chain.empty() ||
+ ShouldClearDownloadFromDB(url_chain.back(), state, interrupt_reason)) {
+ DeleteDownloadedFileOnUIThread(current_path);
+ return nullptr;
}
- download::DownloadItemImpl* item = item_factory_->CreatePersistedItem(
+#endif
+ auto item = base::WrapUnique(item_factory_->CreatePersistedItem(
this, guid, id, current_path, target_path, url_chain, referrer_url,
site_url, tab_url, tab_refererr_url, mime_type, original_mime_type,
start_time, end_time, etag, last_modified, received_bytes, total_bytes,
hash, state, danger_type, interrupt_reason, opened, last_access_time,
- transient, received_slices);
- DownloadItemUtils::AttachInfo(item, GetBrowserContext(), nullptr);
- downloads_[id] = base::WrapUnique(item);
- downloads_by_guid_[guid] = item;
+ transient, received_slices));
+ if (in_progress_download) {
+ // If the download item from history db is already in terminal state,
+ // remove it from the in-progress db. Otherwise, use the in-progress db one.
+ if (item->IsDone()) {
+ in_progress_manager_->RemoveInProgressDownload(guid);
+ } else {
+ item = std::move(in_progress_download);
+ item->SetDelegate(this);
+ }
+ }
+ download::DownloadItemImpl* download = item.get();
+ DownloadItemUtils::AttachInfo(download, GetBrowserContext(), nullptr);
+ OnDownloadCreated(std::move(item));
+ return download;
+}
+
+void DownloadManagerImpl::OnDownloadCreated(
+ std::unique_ptr<download::DownloadItemImpl> download) {
+ DCHECK(!base::ContainsKey(downloads_, download->GetId()));
+ DCHECK(!base::ContainsKey(downloads_by_guid_, download->GetGuid()));
+ download::DownloadItemImpl* item = download.get();
+ downloads_[item->GetId()] = std::move(download);
+ downloads_by_guid_[item->GetGuid()] = item;
for (auto& observer : observers_)
observer.OnDownloadCreated(this, item);
DVLOG(20) << __func__ << "() download = " << item->DebugString(true);
- return item;
}
void DownloadManagerImpl::PostInitialization(
@@ -980,8 +1014,11 @@ void DownloadManagerImpl::PostInitialization(
break;
case DOWNLOAD_INITIALIZATION_DEPENDENCY_IN_PROGRESS_CACHE:
in_progress_cache_initialized_ = true;
- if (load_history_downloads_cb_)
- std::move(load_history_downloads_cb_).Run();
+ // Post a task to load downloads from history db.
+ if (load_history_downloads_cb_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(load_history_downloads_cb_));
+ }
break;
case DOWNLOAD_INITIALIZATION_DEPENDENCY_NONE:
default:
@@ -993,10 +1030,38 @@ void DownloadManagerImpl::PostInitialization(
// cache are initialized.
initialized_ = history_db_initialized_ && in_progress_cache_initialized_;
- if (initialized_) {
+ if (!initialized_)
+ return;
+
+#if defined(OS_ANDROID)
+ for (const auto& guid : cleared_download_guids_on_startup_)
+ in_progress_manager_->RemoveInProgressDownload(guid);
+ if (cancelled_download_cleared_from_history_ > 0) {
+ UMA_HISTOGRAM_COUNTS_1000(
+ "MobileDownload.CancelledDownloadRemovedFromHistory",
+ cancelled_download_cleared_from_history_);
+ }
+
+ if (interrupted_download_cleared_from_history_ > 0) {
+ UMA_HISTOGRAM_COUNTS_1000(
+ "MobileDownload.InterruptedDownloadsRemovedFromHistory",
+ interrupted_download_cleared_from_history_);
+ }
+#endif
+
+ // If there are still downloads in |in_progress_downloads_|, import them
+ // now.
+ for (auto& download : in_progress_downloads_) {
+ auto item = std::move(download.second);
+ item->SetDelegate(this);
+ DownloadItemUtils::AttachInfo(item.get(), GetBrowserContext(), nullptr);
+ OnDownloadCreated(std::move(item));
+ }
+ in_progress_downloads_.clear();
+
+ in_progress_manager_->OnAllInprogressDownloadsLoaded();
for (auto& observer : observers_)
observer.OnManagerInitialized();
- }
}
bool DownloadManagerImpl::IsManagerInitialized() const {
@@ -1175,7 +1240,8 @@ void DownloadManagerImpl::BeginResourceDownloadOnChecksComplete(
} else if (params->url().SchemeIsFile()) {
url_loader_factory_getter =
base::MakeRefCounted<FileDownloadURLLoaderFactoryGetter>(
- params->url(), browser_context_->GetPath());
+ params->url(), browser_context_->GetPath(),
+ BrowserContext::GetSharedCorsOriginAccessList(browser_context_));
} else if (params->url().SchemeIs(content::kChromeUIScheme)) {
url_loader_factory_getter =
base::MakeRefCounted<WebUIDownloadURLLoaderFactoryGetter>(
@@ -1220,8 +1286,8 @@ void DownloadManagerImpl::BeginDownloadInternal(
const GURL& site_url) {
// Check if the renderer is permitted to request the requested URL.
if (params->render_process_host_id() >= 0 &&
- !CanRequestURLFromRenderer(params->render_process_host_id(),
- params->url())) {
+ !DownloadRequestUtils::IsURLSafe(params->render_process_host_id(),
+ params->url())) {
CreateInterruptedDownload(
std::move(params),
download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST,
@@ -1230,6 +1296,15 @@ void DownloadManagerImpl::BeginDownloadInternal(
}
if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ // Ideally everywhere a blob: URL is downloaded a URLLoaderFactory for that
+ // blob URL is also passed, but since that isn't always the case, create
+ // a new factory if we don't have one already.
+ if (!blob_url_loader_factory && params->url().SchemeIsBlob()) {
+ blob_url_loader_factory =
+ ChromeBlobStorageContext::URLLoaderFactoryForUrl(browser_context_,
+ params->url());
+ }
+
auto* rfh = RenderFrameHost::FromID(params->render_process_host_id(),
params->render_frame_host_routing_id());
bool content_initiated = params->content_initiated();
@@ -1274,4 +1349,34 @@ bool DownloadManagerImpl::IsNextIdInitialized() const {
return is_history_download_id_retrieved_ && in_progress_cache_initialized_;
}
+#if defined(OS_ANDROID)
+bool DownloadManagerImpl::ShouldClearDownloadFromDB(
+ const GURL& url,
+ download::DownloadItem::DownloadState state,
+ download::DownloadInterruptReason reason) {
+ if (state == download::DownloadItem::CANCELLED) {
+ ++cancelled_download_cleared_from_history_;
+ return true;
+ }
+ if (reason != download::DOWNLOAD_INTERRUPT_REASON_NONE &&
+ download::GetDownloadResumeMode(url, reason, false /* restart_required */,
+ false /* user_action_required */) ==
+ download::ResumeMode::INVALID) {
+ ++interrupted_download_cleared_from_history_;
+ return true;
+ }
+ return false;
+}
+#endif // defined(OS_ANDROID)
+
+std::unique_ptr<download::DownloadItemImpl>
+DownloadManagerImpl::RetrieveInProgressDownload(uint32_t id) {
+ if (base::ContainsKey(in_progress_downloads_, id)) {
+ auto download = std::move(in_progress_downloads_[id]);
+ in_progress_downloads_.erase(id);
+ return download;
+ }
+ return nullptr;
+}
+
} // namespace content
diff --git a/chromium/content/browser/download/download_manager_impl.h b/chromium/content/browser/download/download_manager_impl.h
index 5f53beb1236..b94e85cf289 100644
--- a/chromium/content/browser/download/download_manager_impl.h
+++ b/chromium/content/browser/download/download_manager_impl.h
@@ -20,6 +20,7 @@
#include "base/observer_list.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
#include "components/download/public/common/download_item_impl_delegate.h"
#include "components/download/public/common/download_url_parameters.h"
#include "components/download/public/common/in_progress_download_manager.h"
@@ -132,6 +133,7 @@ class CONTENT_EXPORT DownloadManagerImpl
base::OnceClosure load_history_downloads_cb) override;
download::DownloadItem* GetDownload(uint32_t id) override;
download::DownloadItem* GetDownloadByGuid(const std::string& guid) override;
+ void GetNextId(GetNextIdCallback callback) override;
// UrlDownloadHandler::Delegate implementation.
void OnUrlDownloadStarted(
@@ -214,11 +216,6 @@ class CONTENT_EXPORT DownloadManagerImpl
download::InProgressDownloadManager::StartDownloadItemCallback callback,
uint32_t id);
- using GetNextIdCallback = base::OnceCallback<void(uint32_t)>;
- // Called to get an ID for a new download. |callback| may be called
- // synchronously.
- void GetNextId(GetNextIdCallback callback);
-
// Sets the |next_download_id_| if the |next_id| is larger. Runs all the
// |id_callbacks_| if both the ID from both history db and in-progress db
// are retrieved.
@@ -291,6 +288,22 @@ class CONTENT_EXPORT DownloadManagerImpl
// Whether |next_download_id_| is initialized.
bool IsNextIdInitialized() const;
+ // Called when a new download is created.
+ void OnDownloadCreated(std::unique_ptr<download::DownloadItemImpl> download);
+
+ // Retrieves a download from |in_progress_downloads_|.
+ std::unique_ptr<download::DownloadItemImpl> RetrieveInProgressDownload(
+ uint32_t id);
+
+#if defined(OS_ANDROID)
+ // Check whether a download should be cleared from history. On Android,
+ // cancelled and non-resumable interrupted download will be cleaned up to
+ // save memory.
+ bool ShouldClearDownloadFromDB(const GURL& url,
+ download::DownloadItem::DownloadState state,
+ download::DownloadInterruptReason reason);
+#endif // defined(OS_ANDROID)
+
// Factory for creation of downloads items.
std::unique_ptr<download::DownloadItemFactory> item_factory_;
@@ -349,6 +362,20 @@ class CONTENT_EXPORT DownloadManagerImpl
// Whether next download ID from history DB is being retrieved.
bool is_history_download_id_retrieved_;
+ // Whether new download should be persisted to the in progress download
+ // database.
+ bool should_persist_new_download_;
+
+ // The download GUIDs that are cleared up on startup.
+ std::set<std::string> cleared_download_guids_on_startup_;
+ int cancelled_download_cleared_from_history_;
+ int interrupted_download_cleared_from_history_;
+
+ // In progress downloads returned by |in_progress_manager_| that are not yet
+ // added to |downloads_|.
+ std::unordered_map<uint32_t, std::unique_ptr<download::DownloadItemImpl>>
+ in_progress_downloads_;
+
// Callbacks to run once download ID is determined.
using IdCallbackVector = std::vector<std::unique_ptr<GetNextIdCallback>>;
IdCallbackVector id_callbacks_;
diff --git a/chromium/content/browser/download/download_manager_impl_unittest.cc b/chromium/content/browser/download/download_manager_impl_unittest.cc
index fa6bd708f10..9fd5ebe21be 100644
--- a/chromium/content/browser/download/download_manager_impl_unittest.cc
+++ b/chromium/content/browser/download/download_manager_impl_unittest.cc
@@ -69,6 +69,10 @@ class ByteStreamReader;
namespace {
+bool URLAlwaysSafe(int render_process_id, const GURL& url) {
+ return true;
+}
+
class MockDownloadManagerDelegate : public DownloadManagerDelegate {
public:
MockDownloadManagerDelegate();
@@ -161,20 +165,20 @@ class MockDownloadItemFactory
std::unique_ptr<download::DownloadRequestHandleInterface> request_handle)
override;
- void set_is_download_started(bool is_download_started) {
- is_download_started_ = is_download_started;
+ void set_is_download_persistent(bool is_download_persistent) {
+ is_download_persistent_ = is_download_persistent;
}
private:
std::map<uint32_t, download::MockDownloadItemImpl*> items_;
download::DownloadItemImplDelegate item_delegate_;
- bool is_download_started_;
+ bool is_download_persistent_;
DISALLOW_COPY_AND_ASSIGN(MockDownloadItemFactory);
};
MockDownloadItemFactory::MockDownloadItemFactory()
- : is_download_started_(false) {}
+ : is_download_persistent_(false) {}
MockDownloadItemFactory::~MockDownloadItemFactory() {}
@@ -248,7 +252,45 @@ download::DownloadItemImpl* MockDownloadItemFactory::CreateActiveItem(
.WillRepeatedly(Return(download_id));
EXPECT_CALL(*result, GetGuid())
.WillRepeatedly(ReturnRefOfCopy(base::GenerateGUID()));
- if (is_download_started_) {
+ EXPECT_CALL(*result, GetUrlChain())
+ .WillRepeatedly(ReturnRefOfCopy(std::vector<GURL>()));
+ EXPECT_CALL(*result, GetReferrerUrl())
+ .WillRepeatedly(ReturnRefOfCopy(GURL()));
+ EXPECT_CALL(*result, GetTabUrl()).WillRepeatedly(ReturnRefOfCopy(GURL()));
+ EXPECT_CALL(*result, GetTabReferrerUrl())
+ .WillRepeatedly(ReturnRefOfCopy(GURL()));
+ EXPECT_CALL(*result, GetETag())
+ .WillRepeatedly(ReturnRefOfCopy(std::string()));
+ EXPECT_CALL(*result, GetLastModifiedTime())
+ .WillRepeatedly(ReturnRefOfCopy(std::string()));
+ EXPECT_CALL(*result, GetMimeType()).WillRepeatedly(Return(std::string()));
+ EXPECT_CALL(*result, GetOriginalMimeType())
+ .WillRepeatedly(Return(std::string()));
+ EXPECT_CALL(*result, GetTotalBytes()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*result, GetFullPath())
+ .WillRepeatedly(
+ ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("foo"))));
+ EXPECT_CALL(*result, GetTargetFilePath())
+ .WillRepeatedly(
+ ReturnRefOfCopy(base::FilePath(FILE_PATH_LITERAL("foo"))));
+ EXPECT_CALL(*result, GetReceivedBytes()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*result, GetStartTime()).WillRepeatedly(Return(base::Time()));
+ EXPECT_CALL(*result, GetEndTime()).WillRepeatedly(Return(base::Time()));
+ EXPECT_CALL(*result, GetReceivedSlices())
+ .WillRepeatedly(ReturnRefOfCopy(
+ std::vector<download::DownloadItem::ReceivedSlice>()));
+ EXPECT_CALL(*result, GetHash())
+ .WillRepeatedly(ReturnRefOfCopy(std::string()));
+ EXPECT_CALL(*result, GetState())
+ .WillRepeatedly(Return(download::DownloadItem::IN_PROGRESS));
+ EXPECT_CALL(*result, GetDangerType())
+ .WillRepeatedly(Return(download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS));
+ EXPECT_CALL(*result, GetLastReason())
+ .WillRepeatedly(Return(download::DOWNLOAD_INTERRUPT_REASON_NONE));
+ EXPECT_CALL(*result, IsPaused()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*result, IsTemporary()).WillRepeatedly(Return(false));
+
+ if (is_download_persistent_) {
EXPECT_CALL(*result, RemoveObserver(_));
EXPECT_CALL(*result, AddObserver(_));
}
@@ -337,7 +379,8 @@ TestInProgressManager::TestInProgressManager()
: download::InProgressDownloadManager(
nullptr,
base::FilePath(),
- download::InProgressDownloadManager::IsOriginSecureCallback()) {}
+ download::InProgressDownloadManager::IsOriginSecureCallback(),
+ base::BindRepeating(&URLAlwaysSafe)) {}
void TestInProgressManager::AddDownloadItem(
std::unique_ptr<download::DownloadItemImpl> item) {
@@ -483,6 +526,11 @@ class DownloadManagerTest : public testing::Test {
download_manager_->OnInProgressDownloadManagerInitialized();
}
+ void OnHistoryDBInitialized() {
+ download_manager_->PostInitialization(
+ DownloadManager::DOWNLOAD_INITIALIZATION_DEPENDENCY_HISTORY_DB);
+ }
+
void SetInProgressDownloadManager(
std::unique_ptr<download::InProgressDownloadManager> manager) {
download_manager_->in_progress_manager_ = std::move(manager);
@@ -519,7 +567,9 @@ TEST_F(DownloadManagerTest, StartDownload) {
std::unique_ptr<download::DownloadCreateInfo> info(
new download::DownloadCreateInfo);
std::unique_ptr<ByteStreamReader> stream(new MockByteStreamReader);
- uint32_t local_id(5); // Random value
+ // Random value, a non 0 value means history db is properly loaded, and new
+ // downloads should be persisted to the in-progress db.
+ uint32_t local_id(5);
base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
OnInProgressDownloadManagerInitialized();
@@ -544,13 +594,49 @@ TEST_F(DownloadManagerTest, StartDownload) {
MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
.WillOnce(Return(mock_file));
- mock_download_item_factory_->set_is_download_started(true);
+ mock_download_item_factory_->set_is_download_persistent(true);
download_manager_->StartDownload(
std::move(info), std::move(input_stream), nullptr,
download::DownloadUrlParameters::OnStartedCallback());
EXPECT_TRUE(download_manager_->GetDownload(local_id));
}
+// Test the case that a new download is started when history db failed to
+// initialize.
+TEST_F(DownloadManagerTest, StartDownloadWithoutHistoryDB) {
+ std::unique_ptr<download::DownloadCreateInfo> info(
+ new download::DownloadCreateInfo);
+ std::unique_ptr<ByteStreamReader> stream(new MockByteStreamReader);
+ base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
+ OnInProgressDownloadManagerInitialized();
+ EXPECT_FALSE(download_manager_->GetDownload(1));
+
+ EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _))
+ .WillOnce(Return());
+ // Returning kInvalidId to indicate that the history db failed.
+ EXPECT_CALL(GetMockDownloadManagerDelegate(), GetNextId(_))
+ .WillOnce(RunCallback<0>(download::DownloadItem::kInvalidId));
+
+#if !defined(USE_X11)
+ // Doing nothing will set the default download directory to null.
+ EXPECT_CALL(GetMockDownloadManagerDelegate(), GetSaveDir(_, _, _, _));
+#endif
+ EXPECT_CALL(GetMockDownloadManagerDelegate(),
+ ApplicationClientIdForFileScanning())
+ .WillRepeatedly(Return("client-id"));
+ download::MockDownloadFile* mock_file = new download::MockDownloadFile;
+ auto input_stream =
+ std::make_unique<ByteStreamInputStream>(std::move(stream));
+ EXPECT_CALL(*mock_download_file_factory_.get(),
+ MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
+ .WillOnce(Return(mock_file));
+
+ download_manager_->StartDownload(
+ std::move(info), std::move(input_stream), nullptr,
+ download::DownloadUrlParameters::OnStartedCallback());
+ EXPECT_TRUE(download_manager_->GetDownload(1));
+}
+
// Confirm that calling DetermineDownloadTarget behaves properly if the delegate
// blocks starting.
TEST_F(DownloadManagerTest, DetermineDownloadTarget_True) {
@@ -602,9 +688,11 @@ TEST_F(DownloadManagerTest, GetDownloadByGuid) {
ASSERT_FALSE(download_manager_->GetDownloadByGuid(""));
const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
+ std::vector<GURL> url_chain;
+ url_chain.emplace_back("http://example.com/1.zip");
download::DownloadItem* persisted_item =
download_manager_->CreateDownloadItem(
- kGuid, 10, base::FilePath(), base::FilePath(), std::vector<GURL>(),
+ kGuid, 10, base::FilePath(), base::FilePath(), url_chain,
GURL("http://example.com/a"), GURL("http://example.com/a"),
GURL("http://example.com/a"), GURL("http://example.com/a"),
"application/octet-stream", "application/octet-stream",
@@ -653,13 +741,14 @@ TEST_F(DownloadManagerTest, RemoveDownloadsByURL) {
TEST_F(DownloadManagerTest, OnInProgressDownloadsLoaded) {
auto in_progress_manager = std::make_unique<TestInProgressManager>();
const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
+ std::vector<GURL> url_chain;
+ url_chain.emplace_back("http://example.com/1.zip");
auto in_progress_item = std::make_unique<download::DownloadItemImpl>(
in_progress_manager.get(), kGuid, 10, base::FilePath(), base::FilePath(),
- std::vector<GURL>(), GURL("http://example.com/a"),
+ url_chain, GURL("http://example.com/a"), GURL("http://example.com/a"),
GURL("http://example.com/a"), GURL("http://example.com/a"),
- GURL("http://example.com/a"), "application/octet-stream",
- "application/octet-stream", base::Time::Now(), base::Time::Now(),
- std::string(), std::string(), 10, 10, std::string(),
+ "application/octet-stream", "application/octet-stream", base::Time::Now(),
+ base::Time::Now(), std::string(), std::string(), 10, 10, std::string(),
download::DownloadItem::INTERRUPTED,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, false,
@@ -670,8 +759,10 @@ TEST_F(DownloadManagerTest, OnInProgressDownloadsLoaded) {
EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _))
.WillOnce(Return());
OnInProgressDownloadManagerInitialized();
- ASSERT_TRUE(download_manager_->GetDownloadByGuid(kGuid));
+ ASSERT_FALSE(download_manager_->GetDownloadByGuid(kGuid));
+ OnHistoryDBInitialized();
+ ASSERT_TRUE(download_manager_->GetDownloadByGuid(kGuid));
download::DownloadItem* download =
download_manager_->GetDownloadByGuid(kGuid);
download->Remove();
diff --git a/chromium/content/browser/download/download_request_utils.cc b/chromium/content/browser/download/download_request_utils.cc
index 86de66d1a75..2704f4d19b8 100644
--- a/chromium/content/browser/download/download_request_utils.cc
+++ b/chromium/content/browser/download/download_request_utils.cc
@@ -5,6 +5,7 @@
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/browser_context.h"
+#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
@@ -26,4 +27,16 @@ DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
render_frame_host->GetRoutingID(), traffic_annotation));
}
+// static
+bool DownloadRequestUtils::IsURLSafe(int render_process_id, const GURL& url) {
+ // Check if the renderer is permitted to request the requested URL.
+ if (!ChildProcessSecurityPolicy::GetInstance()->CanRequestURL(
+ render_process_id, url)) {
+ DVLOG(1) << "Denied unauthorized download request for "
+ << url.possibly_invalid_spec();
+ return false;
+ }
+ return true;
+}
+
} // namespace content
diff --git a/chromium/content/browser/download/download_resource_handler.cc b/chromium/content/browser/download/download_resource_handler.cc
index d022b897f75..e595dd5abba 100644
--- a/chromium/content/browser/download/download_resource_handler.cc
+++ b/chromium/content/browser/download/download_resource_handler.cc
@@ -31,7 +31,6 @@
#include "content/public/browser/download_request_utils.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_frame_host.h"
-#include "content/public/common/browser_side_navigation_policy.h"
#include "services/network/public/cpp/resource_response.h"
namespace content {
diff --git a/chromium/content/browser/download/download_utils.cc b/chromium/content/browser/download/download_utils.cc
index 89d3af0f95a..d4f2f562f42 100644
--- a/chromium/content/browser/download/download_utils.cc
+++ b/chromium/content/browser/download/download_utils.cc
@@ -10,7 +10,6 @@
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h"
#include "components/download/database/in_progress/download_entry.h"
-#include "components/download/database/in_progress/in_progress_cache.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_interrupt_reasons_utils.h"
#include "components/download/public/common/download_save_info.h"
@@ -21,6 +20,7 @@
#include "content/browser/resource_context_impl.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/download_manager_delegate.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
diff --git a/chromium/content/browser/download/file_download_url_loader_factory_getter.cc b/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
index 86dfd9a6aee..52582d0caf3 100644
--- a/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
+++ b/chromium/content/browser/download/file_download_url_loader_factory_getter.cc
@@ -17,8 +17,13 @@ namespace content {
FileDownloadURLLoaderFactoryGetter::FileDownloadURLLoaderFactoryGetter(
const GURL& url,
- const base::FilePath& profile_path)
- : url_(url), profile_path_(profile_path) {
+ const base::FilePath& profile_path,
+ scoped_refptr<const SharedCorsOriginAccessList>
+ shared_cors_origin_access_list)
+ : url_(url),
+ profile_path_(profile_path),
+ shared_cors_origin_access_list_(
+ std::move(shared_cors_origin_access_list)) {
DCHECK(url.SchemeIs(url::kFileScheme));
}
@@ -32,9 +37,10 @@ FileDownloadURLLoaderFactoryGetter::GetURLLoaderFactory() {
network::mojom::URLLoaderFactoryPtrInfo url_loader_factory_ptr_info;
mojo::MakeStrongBinding(
std::make_unique<FileURLLoaderFactory>(
- profile_path_, base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
+ profile_path_, shared_cors_origin_access_list_,
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})),
MakeRequest(&url_loader_factory_ptr_info));
return base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
diff --git a/chromium/content/browser/download/file_download_url_loader_factory_getter.h b/chromium/content/browser/download/file_download_url_loader_factory_getter.h
index 9c3e79c7a13..6629f4c810a 100644
--- a/chromium/content/browser/download/file_download_url_loader_factory_getter.h
+++ b/chromium/content/browser/download/file_download_url_loader_factory_getter.h
@@ -6,7 +6,9 @@
#define CONTENT_BROWSER_DOWNLOAD_FILE_DOWNLOAD_URL_LOADER_FACTORY_GETTER_H_
#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
#include "components/download/public/common/download_url_loader_factory_getter.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
#include "url/gurl.h"
namespace content {
@@ -15,8 +17,11 @@ namespace content {
class FileDownloadURLLoaderFactoryGetter
: public download::DownloadURLLoaderFactoryGetter {
public:
- FileDownloadURLLoaderFactoryGetter(const GURL& url,
- const base::FilePath& profile_path);
+ FileDownloadURLLoaderFactoryGetter(
+ const GURL& url,
+ const base::FilePath& profile_path,
+ scoped_refptr<const SharedCorsOriginAccessList>
+ shared_cors_origin_access_list);
// download::DownloadURLLoaderFactoryGetter implementation.
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
@@ -27,6 +32,8 @@ class FileDownloadURLLoaderFactoryGetter
private:
GURL url_;
base::FilePath profile_path_;
+ const scoped_refptr<const SharedCorsOriginAccessList>
+ shared_cors_origin_access_list_;
DISALLOW_COPY_AND_ASSIGN(FileDownloadURLLoaderFactoryGetter);
};
diff --git a/chromium/content/browser/download/url_downloader.cc b/chromium/content/browser/download/url_downloader.cc
index 15b46abdb33..62939781aa7 100644
--- a/chromium/content/browser/download/url_downloader.cc
+++ b/chromium/content/browser/download/url_downloader.cc
@@ -19,6 +19,8 @@
#include "content/browser/download/byte_stream_input_stream.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_request_utils.h"
+#include "content/public/common/child_process_host.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
@@ -41,14 +43,16 @@ std::unique_ptr<UrlDownloader> UrlDownloader::BeginDownload(
Referrer::SanitizeForRequest(request->url(), referrer);
Referrer::SetReferrerForRequest(request.get(), sanitized_referrer);
+ // TODO(xingliu): Figure out if we can support blob scheme.
if (request->url().SchemeIs(url::kBlobScheme))
return nullptr;
// From this point forward, the |UrlDownloader| is responsible for
// |started_callback|.
- std::unique_ptr<UrlDownloader> downloader(
- new UrlDownloader(std::move(request), delegate, is_parallel_request,
- params->request_origin(), params->download_source()));
+ std::unique_ptr<UrlDownloader> downloader(new UrlDownloader(
+ std::move(request), delegate, is_parallel_request,
+ params->request_origin(), params->follow_cross_origin_redirects(),
+ params->download_source()));
downloader->Start();
return downloader;
@@ -59,6 +63,7 @@ UrlDownloader::UrlDownloader(
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
bool is_parallel_request,
const std::string& request_origin,
+ bool follow_cross_origin_redirects,
download::DownloadSource download_source)
: request_(std::move(request)),
delegate_(delegate),
@@ -67,6 +72,7 @@ UrlDownloader::UrlDownloader(
is_parallel_request,
request_origin,
download_source),
+ follow_cross_origin_redirects_(follow_cross_origin_redirects),
weak_ptr_factory_(this) {}
UrlDownloader::~UrlDownloader() {
@@ -82,13 +88,19 @@ void UrlDownloader::Start() {
void UrlDownloader::OnReceivedRedirect(net::URLRequest* request,
const net::RedirectInfo& redirect_info,
bool* defer_redirect) {
- DVLOG(1) << "OnReceivedRedirect: " << request_->url().spec();
- // We are going to block redirects even if DownloadRequestCore allows it. No
- // redirects are expected for download requests that are made without a
- // renderer, which are currently exclusively resumption requests. Since there
- // is no security policy being applied here, it's safer to block redirects and
- // revisit if some previously unknown legitimate use case arises for redirects
- // while resuming.
+ DVLOG(1) << __func__ << " , request url: " << request_->url().spec()
+ << " ,redirect url:" << redirect_info.new_url;
+ if (follow_cross_origin_redirects_) {
+ if (!DownloadRequestUtils::IsURLSafe(ChildProcessHost::kInvalidUniqueID,
+ redirect_info.new_url)) {
+ core_.OnWillAbort(
+ download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
+ request_->CancelWithError(net::ERR_UNSAFE_REDIRECT);
+ }
+ return;
+ }
+
+ // Block redirects since there is no security policy being applied here.
core_.OnWillAbort(download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE);
request_->CancelWithError(net::ERR_UNSAFE_REDIRECT);
}
@@ -103,6 +115,14 @@ void UrlDownloader::OnResponseStarted(net::URLRequest* request, int net_error) {
return;
}
+ if (!DownloadRequestUtils::IsURLSafe(ChildProcessHost::kInvalidUniqueID,
+ request_->url())) {
+ core_.OnWillAbort(
+ download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST);
+ request_->CancelWithError(net::ERR_DISALLOWED_URL_SCHEME);
+ return;
+ }
+
if (core_.OnResponseStarted(std::string()))
StartReading(false); // Read the first chunk.
else
diff --git a/chromium/content/browser/download/url_downloader.h b/chromium/content/browser/download/url_downloader.h
index e5b7289ea15..6552a4032ba 100644
--- a/chromium/content/browser/download/url_downloader.h
+++ b/chromium/content/browser/download/url_downloader.h
@@ -32,6 +32,7 @@ class UrlDownloader : public net::URLRequest::Delegate,
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
bool is_parallel_request,
const std::string& request_origin,
+ bool follow_cross_origin_redirects,
download::DownloadSource download_source);
~UrlDownloader() override;
@@ -78,6 +79,8 @@ class UrlDownloader : public net::URLRequest::Delegate,
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate_;
DownloadRequestCore core_;
+ const bool follow_cross_origin_redirects_;
+
base::WeakPtrFactory<UrlDownloader> weak_ptr_factory_;
};
diff --git a/chromium/content/browser/download/url_downloader_factory.cc b/chromium/content/browser/download/url_downloader_factory.cc
index c6a915457d2..9d2c16550a8 100644
--- a/chromium/content/browser/download/url_downloader_factory.cc
+++ b/chromium/content/browser/download/url_downloader_factory.cc
@@ -22,6 +22,7 @@ UrlDownloaderFactory::CreateUrlDownloadHandler(
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
scoped_refptr<download::DownloadURLLoaderFactoryGetter>
url_loader_factory_getter,
+ const download::URLSecurityPolicy& url_security_policy,
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
std::unique_ptr<net::URLRequest> url_request =
diff --git a/chromium/content/browser/download/url_downloader_factory.h b/chromium/content/browser/download/url_downloader_factory.h
index bda99732608..23b287feb37 100644
--- a/chromium/content/browser/download/url_downloader_factory.h
+++ b/chromium/content/browser/download/url_downloader_factory.h
@@ -6,6 +6,7 @@
#define CONTENT_BROWSER_DOWNLOAD_URL_DOWNLOADER_FACTORY_H_
#include "base/memory/ref_counted.h"
+#include "components/download/public/common/download_utils.h"
#include "components/download/public/common/url_download_handler_factory.h"
namespace download {
@@ -32,6 +33,7 @@ class UrlDownloaderFactory : public download::UrlDownloadHandlerFactory {
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
scoped_refptr<download::DownloadURLLoaderFactoryGetter>
shared_url_loader_factory,
+ const download::URLSecurityPolicy& url_security_policy,
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) override;
};