// Copyright 2013 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "extensions/browser/blob_reader.h" #include #include #include "base/containers/span.h" #include "base/functional/bind.h" #include "base/memory/ptr_util.h" #include "content/public/browser/browser_thread.h" // static void BlobReader::Read(mojo::PendingRemote blob, BlobReadCallback callback, uint64_t offset, uint64_t length) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); CHECK_GE(offset, 0U); CHECK_GT(length, 0U); CHECK_LE(offset, std::numeric_limits::max() - length); Read(std::move(blob), std::move(callback), Range{offset, length}); } // static void BlobReader::Read(mojo::PendingRemote blob, BlobReadCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Read(std::move(blob), std::move(callback), /*range=*/std::nullopt); } BlobReader::~BlobReader() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } // static void BlobReader::Read(mojo::PendingRemote blob, BlobReadCallback callback, std::optional range) { auto reader = base::WrapUnique(new BlobReader(std::move(blob), std::move(range))); // Move the reader to be owned by the callback, so hold onto a temporary // pointer to it so we can still call Start on it. BlobReader* raw_reader = reader.get(); base::OnceClosure wrapped = base::BindOnce( [](BlobReadCallback callback, std::unique_ptr reader) { std::move(callback).Run(std::move(reader->blob_data_), *reader->blob_length_); }, std::move(callback), std::move(reader)); raw_reader->Start(std::move(wrapped)); } BlobReader::BlobReader(mojo::PendingRemote blob, std::optional range) : blob_(std::move(blob)), read_range_(std::move(range)) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); blob_.set_disconnect_handler( base::BindOnce(&BlobReader::Failed, base::Unretained(this))); } void BlobReader::Start(base::OnceClosure callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); callback_ = std::move(callback); mojo::ScopedDataPipeProducerHandle producer_handle; mojo::ScopedDataPipeConsumerHandle consumer_handle; MojoResult result = CreateDataPipe(nullptr, producer_handle, consumer_handle); if (result != MOJO_RESULT_OK) { Failed(); return; } if (read_range_) { blob_->ReadRange(read_range_->offset, read_range_->length, std::move(producer_handle), receiver_.BindNewPipeAndPassRemote()); } else { blob_->ReadAll(std::move(producer_handle), receiver_.BindNewPipeAndPassRemote()); } data_pipe_drainer_ = std::make_unique(this, std::move(consumer_handle)); } void BlobReader::OnCalculatedSize(uint64_t total_size, uint64_t expected_content_size) { blob_length_ = total_size; if (data_complete_) { Succeeded(); } } void BlobReader::OnDataAvailable(base::span data) { blob_data_.append(base::as_string_view(data)); } void BlobReader::OnDataComplete() { data_complete_ = true; if (blob_length_) { Succeeded(); } } void BlobReader::Failed() { blob_length_ = 0; std::move(callback_).Run(); } void BlobReader::Succeeded() { std::move(callback_).Run(); }