// Copyright 2013 The Chromium Authors. All rights reserved. // 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/bind.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" // static void BlobReader::Read(content::BrowserContext* browser_context, const std::string& blob_uuid, BlobReader::BlobReadCallback callback, int64_t offset, int64_t length) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); CHECK_GE(offset, 0); CHECK_GT(length, 0); CHECK_LE(offset, std::numeric_limits::max() - length); base::Optional range = Range{offset, length}; Read(browser_context, blob_uuid, std::move(callback), std::move(range)); } // static void BlobReader::Read(content::BrowserContext* browser_context, const std::string& blob_uuid, BlobReader::BlobReadCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); Read(browser_context, blob_uuid, std::move(callback), base::nullopt); } BlobReader::~BlobReader() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } // static void BlobReader::Read(content::BrowserContext* browser_context, const std::string& blob_uuid, BlobReader::BlobReadCallback callback, base::Optional range) { std::unique_ptr reader(new BlobReader( content::BrowserContext::GetBlobRemote(browser_context, blob_uuid), 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, base::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(const void* data, size_t num_bytes) { if (!blob_data_) blob_data_ = std::make_unique(); blob_data_->append(static_cast(data), num_bytes); } void BlobReader::OnDataComplete() { data_complete_ = true; if (!blob_data_) blob_data_ = std::make_unique(); if (blob_length_) Succeeded(); } void BlobReader::Failed() { blob_length_ = 0; blob_data_ = std::make_unique(); std::move(callback_).Run(); } void BlobReader::Succeeded() { std::move(callback_).Run(); }