Commit 99ae2517 authored by Min Qin's avatar Min Qin Committed by Commit Bot

Read from Remote<blob> directly instead of converting it to a BlobDataHandle

This CL addresses some comments left in:
https://chromium-review.googlesource.com/c/chromium/src/+/1832723.
It now reads the remote blob interface directly rather than
converting it to a BlobDataHandle first.

BUG=947395

Change-Id: Ie9ecdaab3fa392f0c99f51eb73d5b0f8590cfbef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1869751
Commit-Queue: Min Qin <qinmin@chromium.org>
Reviewed-by: default avatarMarijn Kruisselbrink <mek@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710153}
parent e105a881
...@@ -4,112 +4,73 @@ ...@@ -4,112 +4,73 @@
#include "content/browser/download/data_url_blob_reader.h" #include "content/browser/download/data_url_blob_reader.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "content/public/browser/browser_thread.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "storage/browser/blob/blob_data_handle.h"
#include "storage/browser/blob/blob_reader.h"
namespace { namespace content {
// Class for reading data from a BlobReader. Once blob reading completes,
// it constructs a data URL from the data and calls the callback
// given by the caller. All the operations are on the IO thread.
class BlobReadJob : public base::RefCounted<BlobReadJob> {
public:
BlobReadJob(content::DataURLBlobReader::ReadCompletionCallback
read_completion_callback,
std::unique_ptr<storage::BlobReader> blob_reader);
// Called to start the job.
void Start();
private:
friend class base::RefCounted<BlobReadJob>;
~BlobReadJob();
// Called when blob size is calculated.
void OnSizeCalculated(int result_code);
// Called when all the data is read.
void OnReadComplete(int size);
content::DataURLBlobReader::ReadCompletionCallback read_completion_callback_;
std::unique_ptr<storage::BlobReader> blob_reader_;
scoped_refptr<net::IOBufferWithSize> io_buffer_;
DISALLOW_COPY_AND_ASSIGN(BlobReadJob); // static
}; void DataURLBlobReader::ReadDataURLFromBlob(
mojo::PendingRemote<blink::mojom::Blob> data_url_blob,
DataURLBlobReader::ReadCompletionCallback read_completion_callback) {
DataURLBlobReader* reader = new DataURLBlobReader(std::move(data_url_blob));
auto data_url_blob_reader = base::WrapUnique(reader);
// Move the reader to be owned by the callback.
base::OnceClosure closure = base::BindOnce(
[](ReadCompletionCallback callback,
std::unique_ptr<DataURLBlobReader> blob_reader) {
GURL url = base::StartsWith(blob_reader->url_data_,
"data:", base::CompareCase::SENSITIVE)
? GURL(blob_reader->url_data_)
: GURL();
std::move(callback).Run(std::move(url));
},
std::move(read_completion_callback), std::move(data_url_blob_reader));
reader->Start(std::move(closure));
}
BlobReadJob::BlobReadJob( DataURLBlobReader::DataURLBlobReader(
content::DataURLBlobReader::ReadCompletionCallback read_completion_callback, mojo::PendingRemote<blink::mojom::Blob> data_url_blob)
std::unique_ptr<storage::BlobReader> blob_reader) : data_url_blob_(std::move(data_url_blob)) {
: read_completion_callback_(std::move(read_completion_callback)), data_url_blob_.set_disconnect_handler(
blob_reader_(std::move(blob_reader)) {} base::BindOnce(&DataURLBlobReader::OnFailed, base::Unretained(this)));
DETACH_FROM_SEQUENCE(sequence_checker_);
}
BlobReadJob::~BlobReadJob() = default; DataURLBlobReader::~DataURLBlobReader() = default;
void BlobReadJob::Start() { void DataURLBlobReader::Start(base::OnceClosure callback) {
const storage::BlobReader::Status size_status = blob_reader_->CalculateSize( DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
base::BindOnce(&BlobReadJob::OnSizeCalculated, this)); mojo::ScopedDataPipeProducerHandle producer_handle;
switch (size_status) { mojo::ScopedDataPipeConsumerHandle consumer_handle;
case storage::BlobReader::Status::NET_ERROR: MojoResult result =
std::move(read_completion_callback_).Run(GURL()); CreateDataPipe(nullptr, &producer_handle, &consumer_handle);
return; if (result != MOJO_RESULT_OK) {
case storage::BlobReader::Status::IO_PENDING: std::move(callback).Run();
return;
case storage::BlobReader::Status::DONE:
OnSizeCalculated(net::OK);
return; return;
} }
}
void BlobReadJob::OnSizeCalculated(int result_code) { callback_ = std::move(callback);
if (result_code != net::OK) {
std::move(read_completion_callback_).Run(GURL());
return;
}
io_buffer_ = base::MakeRefCounted<net::IOBufferWithSize>(
static_cast<size_t>(blob_reader_->total_size()));
int bytes_read;
storage::BlobReader::Status read_status = blob_reader_->Read(
io_buffer_.get(), blob_reader_->total_size(), &bytes_read,
base::BindOnce(&BlobReadJob::OnReadComplete, this));
switch (read_status) {
case storage::BlobReader::Status::NET_ERROR:
std::move(read_completion_callback_).Run(GURL());
return;
case storage::BlobReader::Status::IO_PENDING:
return;
case storage::BlobReader::Status::DONE:
OnReadComplete(bytes_read);
return;
}
}
void BlobReadJob::OnReadComplete(int size) { data_url_blob_->ReadAll(std::move(producer_handle), mojo::NullRemote());
base::StringPiece url_data = base::StringPiece(io_buffer_->data(), size); data_pipe_drainer_ =
GURL url = base::StartsWith(url_data, "data:", base::CompareCase::SENSITIVE) std::make_unique<mojo::DataPipeDrainer>(this, std::move(consumer_handle));
? GURL(url_data)
: GURL();
std::move(read_completion_callback_).Run(std::move(url));
} }
} // namespace void DataURLBlobReader::OnDataAvailable(const void* data, size_t num_bytes) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
namespace content { url_data_.append(static_cast<const char*>(data), num_bytes);
}
// static void DataURLBlobReader::OnDataComplete() {
void DataURLBlobReader::ReadDataURLFromBlob( DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::unique_ptr<storage::BlobDataHandle> blob_data_handle, std::move(callback_).Run();
DataURLBlobReader::ReadCompletionCallback read_completion_callback) { }
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<BlobReadJob> blob_read_job = base::MakeRefCounted<BlobReadJob>( void DataURLBlobReader::OnFailed() {
std::move(read_completion_callback), blob_data_handle->CreateReader()); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
blob_read_job->Start(); url_data_.clear();
std::move(callback_).Run();
} }
} // namespace content } // namespace content
...@@ -5,10 +5,16 @@ ...@@ -5,10 +5,16 @@
#ifndef CONTENT_BROWSER_DOWNLOAD_DATA_URL_BLOB_READER_H_ #ifndef CONTENT_BROWSER_DOWNLOAD_DATA_URL_BLOB_READER_H_
#define CONTENT_BROWSER_DOWNLOAD_DATA_URL_BLOB_READER_H_ #define CONTENT_BROWSER_DOWNLOAD_DATA_URL_BLOB_READER_H_
#include <memory> #include <string>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/sequence_checker.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/system/data_pipe_drainer.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace storage { namespace storage {
...@@ -17,18 +23,48 @@ class BlobDataHandle; ...@@ -17,18 +23,48 @@ class BlobDataHandle;
namespace content { namespace content {
// Helper class to read a data url from a BlobDataHandle on IO thread. // Helper class to read a data url from a BlobDataHandle.
class CONTENT_EXPORT DataURLBlobReader { class CONTENT_EXPORT DataURLBlobReader : public mojo::DataPipeDrainer::Client {
public: public:
using ReadCompletionCallback = base::OnceCallback<void(GURL)>; using ReadCompletionCallback = base::OnceCallback<void(GURL)>;
// Read the data URL from |blob_data_handle|, and call // Read the data URL from |blob_data_handle|, and call
// |read_completion_callback| once it completes. If the data URL cannot be // |read_completion_callback| once it completes. If the data URL cannot be
// retrieved, |read_completion_callback| will be called with an empty URL. // retrieved, |read_completion_callback| will be called with an empty URL.
// This method must be called on the IO thread. // This method must be called on the UI thread.
static void ReadDataURLFromBlob( static void ReadDataURLFromBlob(
std::unique_ptr<storage::BlobDataHandle> blob_data_handle, mojo::PendingRemote<blink::mojom::Blob> data_url_blob,
ReadCompletionCallback read_completion_callback); ReadCompletionCallback read_completion_callback);
~DataURLBlobReader() override;
private:
DataURLBlobReader(mojo::PendingRemote<blink::mojom::Blob> data_url_blob);
// Starts reading from the |data_url_blob_| and calls |callback| once
// completes.
void Start(base::OnceClosure callback);
// mojo::DataPipeDrainer:
void OnDataAvailable(const void* data, size_t num_bytes) override;
void OnDataComplete() override;
// Called when failed to read from blob.
void OnFailed();
std::unique_ptr<mojo::DataPipeDrainer> data_pipe_drainer_;
mojo::Remote<blink::mojom::Blob> data_url_blob_;
// Data URL retrieved from the blob.
std::string url_data_;
// Callback to run once blob data is read.
base::OnceClosure callback_;
SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(DataURLBlobReader);
}; };
} // namespace content } // namespace content
......
...@@ -529,7 +529,7 @@ void GetRestrictedCookieManager( ...@@ -529,7 +529,7 @@ void GetRestrictedCookieManager(
} }
// Helper method to download a URL on UI thread. // Helper method to download a URL on UI thread.
void DownloadUrlOnUIThread( void StartDownload(
std::unique_ptr<download::DownloadUrlParameters> parameters, std::unique_ptr<download::DownloadUrlParameters> parameters,
mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) { mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
...@@ -555,37 +555,16 @@ void DownloadUrlOnUIThread( ...@@ -555,37 +555,16 @@ void DownloadUrlOnUIThread(
std::move(blob_url_loader_factory)); std::move(blob_url_loader_factory));
} }
// Called on the IO thread when the data URL in the BlobDataHandle // Called on the UI thread when the data URL in the BlobDataHandle
// is read. // is read.
void OnDataURLRetrieved( void OnDataURLRetrieved(
std::unique_ptr<download::DownloadUrlParameters> parameters, std::unique_ptr<download::DownloadUrlParameters> parameters,
GURL data_url) { GURL data_url) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!data_url.is_valid())
return;
parameters->set_url(std::move(data_url)); parameters->set_url(std::move(data_url));
base::PostTask(FROM_HERE, {BrowserThread::UI}, StartDownload(std::move(parameters), mojo::NullRemote());
base::BindOnce(&DownloadUrlOnUIThread, std::move(parameters),
mojo::NullRemote()));
}
// Called on the IO thread when the BlobDataHandle for the data URL
// is retrieved.
void OnDataURLBlobRetrieved(
std::unique_ptr<download::DownloadUrlParameters> parameters,
std::unique_ptr<storage::BlobDataHandle> blob_data_handle) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DataURLBlobReader::ReadDataURLFromBlob(
std::move(blob_data_handle),
base::BindOnce(&OnDataURLRetrieved, std::move(parameters)));
}
// Called to retrieve the data URL on the IO thread.
void RetrieveDataURLOnIOThread(
std::unique_ptr<download::DownloadUrlParameters> parameters,
mojo::PendingRemote<blink::mojom::Blob> data_url_blob,
scoped_refptr<ChromeBlobStorageContext> blob_context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
blob_context->context()->GetBlobDataFromBlobRemote(
std::move(data_url_blob),
base::BindOnce(&OnDataURLBlobRetrieved, std::move(parameters)));
} }
// TODO(crbug.com/977040): Remove when no longer needed. // TODO(crbug.com/977040): Remove when no longer needed.
...@@ -4163,18 +4142,14 @@ void RenderFrameHostImpl::DownloadUrl( ...@@ -4163,18 +4142,14 @@ void RenderFrameHostImpl::DownloadUrl(
parameters->set_initiator(initiator); parameters->set_initiator(initiator);
parameters->set_download_source(download::DownloadSource::FROM_RENDERER); parameters->set_download_source(download::DownloadSource::FROM_RENDERER);
BrowserContext* browser_context = GetSiteInstance()->GetBrowserContext();
if (data_url_blob) { if (data_url_blob) {
scoped_refptr<ChromeBlobStorageContext> blob_context = DataURLBlobReader::ReadDataURLFromBlob(
ChromeBlobStorageContext::GetFor(browser_context); std::move(data_url_blob),
base::PostTask( base::BindOnce(&OnDataURLRetrieved, std::move(parameters)));
FROM_HERE, {BrowserThread::IO},
base::BindOnce(&RetrieveDataURLOnIOThread, std::move(parameters),
std::move(data_url_blob), blob_context));
return; return;
} }
DownloadUrlOnUIThread(std::move(parameters), std::move(blob_url_token)); StartDownload(std::move(parameters), std::move(blob_url_token));
} }
#if BUILDFLAG(USE_EXTERNAL_POPUP_MENU) #if BUILDFLAG(USE_EXTERNAL_POPUP_MENU)
......
...@@ -16,8 +16,8 @@ class WebString; ...@@ -16,8 +16,8 @@ class WebString;
BLINK_PLATFORM_EXPORT GURL WebStringToGURL(const WebString&); BLINK_PLATFORM_EXPORT GURL WebStringToGURL(const WebString&);
// Convert a data url to to message pipe handle so that it can be passed across // Convert a data url to a message pipe handle that corresponds to a remote
// processes. // blob, so that it can be passed across processes.
BLINK_PLATFORM_EXPORT mojo::ScopedMessagePipeHandle DataURLToMessagePipeHandle( BLINK_PLATFORM_EXPORT mojo::ScopedMessagePipeHandle DataURLToMessagePipeHandle(
const WebString&); const WebString&);
......
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