0

Populate initiator origin in DragDownloadFileUI::InitiateDownload.

This CL propagates the initiator origin via
`content::DragDownloadFile::DragDownloadFileUI::InitiateDownload`
into `download::DownloadUrlParameters::set_initiator`.

Note that the initiator origin comes from trustworthy, browser-side data:

- `RenderFrameHostImpl::StartDragging` passes `GetLastCommittedOrigin()`
  into `RenderViewHostDelegateView::StartDragging`
- `WebContentsViewAura::StartDragging` stores the origin into into
  `ui::OSExchangeDataProviderFactory` using a call to
  `ui::OSExchangeDataProviderFactory::MarkRendererTaintedFromOrigin`.
  On Windows this CL takes the origin from
  `OSExchangeDataProviderFactory` and passes it directly into
  `DragDownloadFile`'s constructor.
- `WebContentsViewMac::StartDragging` ends up storing the origin in
  `WebDragSource` from `web_drag_source_mac.mm`.  On Mac this CL takes
  this origin and also passes it (indirectly, via mojo) into
  `DragDownloadFile`'s constructor.

@lukasza has manually tested this CL on Windows using the repro steps
from https://crbug.com/40060358 (@dcheng has kindly tried the repro
steps on Mac).  Note that `DragDownloadFile` is used on Windows and Mac,
but not on Linux (i.e. the repro wouldn't have worked on Linux).

Fixed: 40060358
Change-Id: I24b180473e140cbb8a56640444f2f4a306aa42fc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5692867
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Commit-Queue: Łukasz Anforowicz <lukasza@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1327773}
This commit is contained in:
Lukasz Anforowicz
2024-07-15 20:53:31 +00:00
committed by Chromium LUCI CQ
parent afd93e5622
commit fe310d6b61
9 changed files with 68 additions and 17 deletions

@ -280,7 +280,8 @@
base::FilePath filePath =
base::apple::NSURLToFilePath([NSURL URLWithString:dropDestination]);
filePath = filePath.Append(_downloadFileName);
_host->DragPromisedFileTo(filePath, _dropData, _downloadURL, &filePath);
_host->DragPromisedFileTo(filePath, _dropData, _downloadURL, _sourceOrigin,
&filePath);
// The process of writing the file may have altered the value of
// `filePath` if, say, an existing file at the drop site already had that

@ -313,6 +313,7 @@ class WebContentsNSViewHostStub
bool DragPromisedFileTo(const ::base::FilePath& file_path,
const ::content::DropData& drop_data,
const ::GURL& download_url,
const ::url::Origin& source_origin,
::base::FilePath* out_file_path) override {
return false;
}
@ -320,6 +321,7 @@ class WebContentsNSViewHostStub
void DragPromisedFileTo(const ::base::FilePath& file_path,
const ::content::DropData& drop_data,
const ::GURL& download_url,
const ::url::Origin& source_origin,
DragPromisedFileToCallback callback) override {}
void EndDrag(uint32_t drag_operation,

@ -38,6 +38,7 @@ class DragDownloadFile::DragDownloadFileUI
DragDownloadFileUI(const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
std::optional<url::Origin> initiator_origin,
int render_process_id,
int render_frame_id,
OnCompleted on_completed)
@ -45,6 +46,7 @@ class DragDownloadFile::DragDownloadFileUI
url_(url),
referrer_(referrer),
referrer_encoding_(referrer_encoding),
initiator_origin_(initiator_origin),
render_process_id_(render_process_id),
render_frame_id_(render_frame_id) {
DCHECK(on_completed_);
@ -95,6 +97,7 @@ class DragDownloadFile::DragDownloadFileUI
params->set_referrer_policy(
Referrer::ReferrerPolicyForUrlRequest(referrer_.policy));
params->set_referrer_encoding(referrer_encoding_);
params->set_initiator(initiator_origin_);
params->set_callback(base::BindOnce(&DragDownloadFileUI::OnDownloadStarted,
weak_ptr_factory_.GetWeakPtr()));
params->set_file_path(file_path);
@ -174,6 +177,7 @@ class DragDownloadFile::DragDownloadFileUI
GURL url_;
Referrer referrer_;
std::string referrer_encoding_;
std::optional<url::Origin> initiator_origin_;
int render_process_id_;
int render_frame_id_;
raw_ptr<download::DownloadItem> download_item_ = nullptr;
@ -187,13 +191,14 @@ DragDownloadFile::DragDownloadFile(const base::FilePath& file_path,
const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
std::optional<url::Origin> initiator_origin,
WebContents* web_contents)
: file_path_(file_path), file_(std::move(file)) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RenderFrameHost* host = web_contents->GetPrimaryMainFrame();
drag_ui_ = new DragDownloadFileUI(
url, referrer, referrer_encoding, host->GetProcess()->GetID(),
host->GetRoutingID(),
url, referrer, referrer_encoding, initiator_origin,
host->GetProcess()->GetID(), host->GetRoutingID(),
base::BindOnce(&DragDownloadFile::DownloadCompleted,
weak_ptr_factory_.GetWeakPtr()));
DCHECK(!file_path_.empty());

@ -40,6 +40,7 @@ class CONTENT_EXPORT DragDownloadFile : public ui::DownloadFileProvider {
const GURL& url,
const Referrer& referrer,
const std::string& referrer_encoding,
std::optional<url::Origin> initiator_origin,
WebContents* web_contents);
DragDownloadFile(const DragDownloadFile&) = delete;

@ -2,14 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/download/drag_download_file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/download/download_manager_impl.h"
#include "content/browser/download/drag_download_file.h"
#include "content/browser/download/drag_download_util.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_task_traits.h"
@ -100,9 +103,9 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_NetError) {
ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
Referrer referrer;
std::string referrer_encoding;
auto file = std::make_unique<DragDownloadFile>(name, base::File(), url,
referrer, referrer_encoding,
shell()->web_contents());
auto file = std::make_unique<DragDownloadFile>(
name, base::File(), url, referrer, referrer_encoding, std::nullopt,
shell()->web_contents());
scoped_refptr<MockDownloadFileObserver> observer(
new MockDownloadFileObserver());
EXPECT_CALL(*observer.get(), OnDownloadAborted())
@ -119,9 +122,9 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Complete) {
GURL url = embedded_test_server()->GetURL("/download/download-test.lib");
Referrer referrer;
std::string referrer_encoding;
auto file = std::make_unique<DragDownloadFile>(name, base::File(), url,
referrer, referrer_encoding,
shell()->web_contents());
auto file = std::make_unique<DragDownloadFile>(
name, base::File(), url, referrer, referrer_encoding, std::nullopt,
shell()->web_contents());
scoped_refptr<MockDownloadFileObserver> observer(
new MockDownloadFileObserver());
EXPECT_CALL(*observer.get(), OnDownloadCompleted(_))
@ -132,15 +135,48 @@ IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Complete) {
RunUntilSucceed();
}
IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_Initiator) {
base::FilePath name(
downloads_directory().AppendASCII("DragDownloadFileTest_Initiator.txt"));
GURL url = embedded_test_server()->GetURL("/echoheader?sec-fetch-site");
url::Origin initiator =
url::Origin::Create(GURL("https://initiator.example.com"));
Referrer referrer;
std::string referrer_encoding;
auto file = std::make_unique<DragDownloadFile>(
name, base::File(), url, referrer, referrer_encoding, initiator,
shell()->web_contents());
base::FilePath downloaded_path;
scoped_refptr<MockDownloadFileObserver> observer(
new MockDownloadFileObserver());
EXPECT_CALL(*observer.get(), OnDownloadCompleted(_))
.WillOnce([&](const base::FilePath& file_path) {
downloaded_path = file_path;
this->Succeed();
});
ON_CALL(*observer.get(), OnDownloadAborted())
.WillByDefault(InvokeWithoutArgs(this, &DragDownloadFileTest::FailFast));
file->Start(observer.get());
RunUntilSucceed();
std::string actual_sec_fetch_site_value;
{
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(
base::ReadFileToString(downloaded_path, &actual_sec_fetch_site_value));
}
EXPECT_EQ("cross-site", actual_sec_fetch_site_value);
}
IN_PROC_BROWSER_TEST_F(DragDownloadFileTest, DragDownloadFileTest_ClosePage) {
base::FilePath name(
downloads_directory().AppendASCII("DragDownloadFileTest_Complete.txt"));
GURL url = embedded_test_server()->GetURL("/download/download-test.lib");
Referrer referrer;
std::string referrer_encoding;
auto file = std::make_unique<DragDownloadFile>(name, base::File(), url,
referrer, referrer_encoding,
shell()->web_contents());
auto file = std::make_unique<DragDownloadFile>(
name, base::File(), url, referrer, referrer_encoding, std::nullopt,
shell()->web_contents());
scoped_refptr<MockDownloadFileObserver> observer(
new MockDownloadFileObserver());
ON_CALL(*observer.get(), OnDownloadAborted())

@ -232,7 +232,7 @@ void PrepareDragForDownload(const DropData& drop_data,
auto download_file = std::make_unique<DragDownloadFile>(
download_path, base::File(), download_url,
Referrer(page_url, drop_data.referrer_policy), page_encoding,
web_contents);
provider->GetRendererTaintedOrigin(), web_contents);
ui::DownloadFileInfo file_download(base::FilePath(),
std::move(download_file));
provider->SetDownloadFileInfo(&file_download);

@ -169,6 +169,7 @@ class WebContentsViewMac : public WebContentsView,
bool DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
const url::Origin& source_origin,
base::FilePath* out_file_path) override;
void EndDrag(uint32_t drag_opeation,
const gfx::PointF& local_point,
@ -184,6 +185,7 @@ class WebContentsViewMac : public WebContentsView,
void DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
const url::Origin& source_origin,
DragPromisedFileToCallback callback) override;
// Return the list of child RenderWidgetHostViewMacs. This will remove any

@ -521,6 +521,7 @@ bool WebContentsViewMac::PerformDragOperation(DraggingInfoPtr dragging_info,
bool WebContentsViewMac::DragPromisedFileTo(const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
const url::Origin& source_origin,
base::FilePath* out_file_path) {
*out_file_path = file_path;
// This is called by -namesOfPromisedFilesDroppedAtDestination, which is
@ -539,7 +540,7 @@ bool WebContentsViewMac::DragPromisedFileTo(const base::FilePath& file_path,
*out_file_path, std::move(file), download_url,
content::Referrer(web_contents_->GetLastCommittedURL(),
drop_data.referrer_policy),
web_contents_->GetEncoding(), web_contents_);
web_contents_->GetEncoding(), source_origin, web_contents_);
DragDownloadFile* downloader = drag_file_downloader.get();
// The finalizer will take care of closing and deletion.
@ -616,9 +617,11 @@ void WebContentsViewMac::DragPromisedFileTo(
const base::FilePath& file_path,
const DropData& drop_data,
const GURL& download_url,
const url::Origin& source_origin,
DragPromisedFileToCallback callback) {
base::FilePath actual_file_path;
DragPromisedFileTo(file_path, drop_data, download_url, &actual_file_path);
DragPromisedFileTo(file_path, drop_data, download_url, source_origin,
&actual_file_path);
std::move(callback).Run(actual_file_path);
}

@ -145,7 +145,8 @@ interface WebContentsNSViewHost {
[Sync]
DragPromisedFileTo(mojo_base.mojom.FilePath file_path,
content.mojom.DropData drop_data,
url.mojom.Url download_url) =>
url.mojom.Url download_url,
url.mojom.Origin source_origin) =>
(mojo_base.mojom.FilePath file_path);
// Called in to the -draggedImage: method being called on the NSView.