Commit 6d7c9ec2 authored by Min Qin's avatar Min Qin Committed by Commit Bot

Pass renderer initiated flag for navigations triggered by cross-origin download

If a navigation is triggered by a cross-origin download initiated by
renderer, the navigation should carry the renderer initiated flag.

BUG=979443

Change-Id: I0716193768a5473f70e909b7efbb5fc74933d89e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1768825Reviewed-by: default avatarXing Liu <xingliu@chromium.org>
Commit-Queue: Min Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690869}
parent 054e0817
......@@ -31,7 +31,8 @@ DownloadCreateInfo::DownloadCreateInfo(
accept_range(RangeRequestSupportType::kNoSupport),
connection_info(net::HttpResponseInfo::CONNECTION_INFO_UNKNOWN),
method("GET"),
ukm_source_id(ukm::kInvalidSourceId) {}
ukm_source_id(ukm::kInvalidSourceId),
is_content_initiated(false) {}
DownloadCreateInfo::DownloadCreateInfo()
: DownloadCreateInfo(base::Time(), base::WrapUnique(new DownloadSaveInfo)) {
......
......@@ -138,7 +138,8 @@ ResourceDownloader::ResourceDownloader(
tab_referrer_url_(tab_referrer_url),
delegate_task_runner_(task_runner),
url_loader_factory_getter_(std::move(url_loader_factory_getter)),
url_security_policy_(url_security_policy) {
url_security_policy_(url_security_policy),
is_content_initiated_(false) {
RequestWakeLock(connector.get());
}
......@@ -151,6 +152,7 @@ void ResourceDownloader::Start(
callback_ = download_url_parameters->callback();
upload_callback_ = download_url_parameters->upload_callback();
guid_ = download_url_parameters->guid();
is_content_initiated_ = download_url_parameters->content_initiated();
// Set up the URLLoaderClient.
url_loader_client_ = std::make_unique<DownloadResponseHandler>(
......@@ -231,6 +233,7 @@ void ResourceDownloader::OnResponseStarted(
download_create_info->render_process_id = render_process_id_;
download_create_info->render_frame_id = render_frame_id_;
download_create_info->has_user_gesture = resource_request_->has_user_gesture;
download_create_info->is_content_initiated = is_content_initiated_;
delegate_task_runner_->PostTask(
FROM_HERE,
......
......@@ -169,6 +169,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
// Used to check if the URL is safe to request.
URLSecurityPolicy url_security_policy_;
// Whether download is initated by the content on the page.
bool is_content_initiated_;
// Used to keep the system from sleeping while a download is ongoing. If the
// system enters power saving mode while a download is alive, it can cause
// download to be interrupted.
......
......@@ -173,6 +173,9 @@ struct COMPONENTS_DOWNLOAD_EXPORT DownloadCreateInfo {
// Source of the download, used in metrics.
DownloadSource download_source = DownloadSource::UNKNOWN;
// Whether download is initated by the content on the page.
bool is_content_initiated;
private:
DISALLOW_COPY_AND_ASSIGN(DownloadCreateInfo);
};
......
......@@ -622,6 +622,38 @@ class ErrorStreamCountingObserver : download::DownloadItem::Observer {
base::Closure completion_closure_;
};
// Class to wait for a WebContents to kick off a specified number of
// navigations.
class NavigationStartObserver : public WebContentsObserver {
public:
explicit NavigationStartObserver(WebContents* web_contents)
: WebContentsObserver(web_contents) {}
~NavigationStartObserver() override {}
void WaitForFinished(int navigation_count) {
if (start_count_ >= navigation_count)
return;
navigation_count_ = navigation_count;
base::RunLoop run_loop;
completion_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
private:
// WebContentsObserver implementations.
void DidStartNavigation(NavigationHandle* navigation_handle) override {
start_count_++;
if (start_count_ >= navigation_count_ && !completion_closure_.is_null()) {
std::move(completion_closure_).Run();
}
}
int navigation_count_ = 0;
int start_count_ = 0;
base::Closure completion_closure_;
DISALLOW_COPY_AND_ASSIGN(NavigationStartObserver);
};
bool IsDownloadInState(download::DownloadItem::DownloadState state,
download::DownloadItem* item) {
return item->GetState() == state;
......@@ -3298,8 +3330,54 @@ IN_PROC_BROWSER_TEST_F(DownloadContentTest,
std::vector<download::DownloadItem*> downloads;
DownloadManagerForShell(shell())->GetAllDownloads(&downloads);
ASSERT_EQ(0u, downloads.size());
ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
}
// Tests that if a renderer initiated download triggers cross origin in the
// redirect chain, the visible URL of the current tab shouldn't change.
IN_PROC_BROWSER_TEST_F(DownloadContentTest,
DownloadAttributeSameOriginRedirectNavigationTimeOut) {
net::EmbeddedTestServer origin_one;
net::EmbeddedTestServer origin_two;
ASSERT_TRUE(origin_one.InitializeAndListen());
ASSERT_TRUE(origin_two.InitializeAndListen());
// The download-attribute.html page contains an anchor element whose href is
// set to the value of the query parameter (specified as |target| in the URL
// below). The suggested filename for the anchor is 'suggested-filename'. When
// the page is loaded, a script simulates a click on the anchor, triggering a
// download of the target URL.
//
// We construct two test servers; origin_one and origin_two. Once started, the
// server URLs will differ by the port number. Therefore they will be in
// different origins.
GURL download_url = origin_one.GetURL("/ping");
GURL referrer_url = origin_one.GetURL(
std::string("/download-attribute.html?target=") + download_url.spec());
origin_one.ServeFilesFromDirectory(GetTestFilePath("download", ""));
// <origin_one>/download-attribute.html initiates a download of
// <origin_one>/ping, which redirects to <origin_two>/download. The latter
// will time out.
origin_one.RegisterRequestHandler(
CreateRedirectHandler("/ping", origin_two.GetURL("/download")));
origin_one.StartAcceptingConnections();
NavigationStartObserver obs(shell()->web_contents());
NavigationController::LoadURLParams params(referrer_url);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
shell()->web_contents()->GetController().LoadURLWithParams(params);
shell()->web_contents()->Focus();
// Waiting for 2 navigation to happen, one for the original request, one for
// the redirect.
obs.WaitForFinished(2);
EXPECT_EQ(referrer_url, shell()->web_contents()->GetVisibleURL());
ASSERT_TRUE(origin_one.ShutdownAndWaitUntilComplete());
origin_two.StartAcceptingConnections();
ASSERT_TRUE(origin_two.ShutdownAndWaitUntilComplete());
}
......
......@@ -497,6 +497,7 @@ bool DownloadManagerImpl::InterceptDownload(
info.render_process_id, info.render_frame_id);
params.from_download_cross_origin_redirect = true;
params.initiator_origin = info.request_initiator;
params.is_renderer_initiated = info.is_content_initiated;
web_contents->GetController().LoadURLWithParams(params);
}
return true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment