diff --git a/DEPS b/DEPS index 8f5c4ba5..6480161 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '4833950b754d076e725d592e53bfd2ed22d6d669', + 'skia_revision': 'b5d9e85c028f937991efac755a6da02ec1977f80', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other.
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc index d2141c9..94dd9d1 100644 --- a/components/exo/buffer.cc +++ b/components/exo/buffer.cc
@@ -144,6 +144,7 @@ void ScheduleWaitForRelease(base::TimeDelta delay); void WaitForRelease(); + gfx::GpuMemoryBuffer* const gpu_memory_buffer_; ui::ContextFactory* context_factory_; scoped_refptr<cc::ContextProvider> context_provider_; const unsigned texture_target_; @@ -163,7 +164,8 @@ Buffer::Texture::Texture(ui::ContextFactory* context_factory, cc::ContextProvider* context_provider) - : context_factory_(context_factory), + : gpu_memory_buffer_(nullptr), + context_factory_(context_factory), context_provider_(context_provider), texture_target_(GL_TEXTURE_2D), query_type_(GL_COMMANDS_COMPLETED_CHROMIUM), @@ -182,7 +184,8 @@ gfx::GpuMemoryBuffer* gpu_memory_buffer, unsigned texture_target, unsigned query_type) - : context_factory_(context_factory), + : gpu_memory_buffer_(gpu_memory_buffer), + context_factory_(context_factory), context_provider_(context_provider), texture_target_(texture_target), query_type_(query_type), @@ -250,6 +253,8 @@ uint64_t fence_sync = gles2->InsertFenceSyncCHROMIUM(); gles2->OrderingBarrierCHROMIUM(); gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); + TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_, + "bound"); } return sync_token; } @@ -327,6 +332,8 @@ base::TimeDelta::FromMilliseconds(kWaitForReleaseDelayMs); wait_for_release_time_ = base::TimeTicks::Now() + wait_for_release_delay; ScheduleWaitForRelease(wait_for_release_delay); + TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_, + "pending_query"); context_provider_->ContextSupport()->SignalQuery( query_id_, base::Bind(&Buffer::Texture::Released, weak_ptr_factory_.GetWeakPtr())); @@ -406,6 +413,8 @@ bool secure_output_only, bool client_usage, cc::TransferableResource* resource) { + TRACE_EVENT0("exo", "Buffer::ProduceTransferableResource"); + DCHECK(attach_count_); DLOG_IF(WARNING, !release_contents_callback_.IsCancelled() && client_usage) << "Producing a texture mailbox for a buffer that has not been released"; @@ -443,6 +452,9 @@ } Texture* contents_texture = contents_texture_.get(); + if (release_contents_callback_.IsCancelled()) + TRACE_EVENT_ASYNC_BEGIN0("exo", "BufferInUse", gpu_memory_buffer_.get()); + // Cancel pending contents release callback. release_contents_callback_.Reset( base::Bind(&Buffer::ReleaseContents, base::Unretained(this))); @@ -535,6 +547,8 @@ // Buffer, private: void Buffer::Release() { + TRACE_EVENT_ASYNC_END0("exo", "BufferInUse", gpu_memory_buffer_.get()); + // Run release callback to notify the client that buffer has been released. if (!release_callback_.is_null()) release_callback_.Run(); @@ -556,9 +570,13 @@ // Cancel callback to indicate that buffer has been released. release_contents_callback_.Cancel(); - // Release buffer if not attached to surface. - if (!attach_count_) + if (attach_count_) { + TRACE_EVENT_ASYNC_STEP_INTO0("exo", "BufferInUse", gpu_memory_buffer_.get(), + "attached"); + } else { + // Release buffer if not attached to surface. Release(); + } } } // namespace exo
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 6c88e40..fd5bcf6 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -391,6 +391,8 @@ "blob_storage/blob_dispatcher_host.h", "blob_storage/blob_internals_url_loader.cc", "blob_storage/blob_internals_url_loader.h", + "blob_storage/blob_url_loader_factory.cc", + "blob_storage/blob_url_loader_factory.h", "blob_storage/chrome_blob_storage_context.cc", "blob_storage/chrome_blob_storage_context.h", "bluetooth/bluetooth_allowed_devices.cc",
diff --git a/content/browser/blob_storage/blob_url_loader_factory.cc b/content/browser/blob_storage/blob_url_loader_factory.cc new file mode 100644 index 0000000..8267654e --- /dev/null +++ b/content/browser/blob_storage/blob_url_loader_factory.cc
@@ -0,0 +1,405 @@ +// Copyright 2017 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 "content/browser/blob_storage/blob_url_loader_factory.h" + +#include <stddef.h> +#include "base/bind.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "base/threading/thread_task_runner_handle.h" +#include "content/browser/blob_storage/chrome_blob_storage_context.h" +#include "content/browser/storage_partition_impl.h" +#include "content/common/net_adapters.h" +#include "content/common/url_loader.mojom.h" +#include "content/public/browser/browser_thread.h" +#include "mojo/public/cpp/system/simple_watcher.h" +#include "net/base/io_buffer.h" +#include "net/http/http_byte_range.h" +#include "net/http/http_request_headers.h" +#include "net/http/http_response_headers.h" +#include "net/http/http_status_code.h" +#include "net/http/http_util.h" +#include "storage/browser/blob/blob_data_handle.h" +#include "storage/browser/blob/blob_reader.h" +#include "storage/browser/blob/blob_storage_context.h" +#include "storage/browser/blob/blob_url_request_job.h" +#include "storage/browser/fileapi/file_system_context.h" + +namespace content { + +namespace { +constexpr size_t kDefaultAllocationSize = 512 * 1024; + +// This class handles a request for a blob:// url. It self-destructs (see +// DeleteIfNeeded) when it has finished responding. +// Note: some of this code is duplicated from storage::BlobURLRequestJob. +class BlobURLLoader : public mojom::URLLoader { + public: + BlobURLLoader(mojom::URLLoaderAssociatedRequest url_loader_request, + const ResourceRequest& request, + mojom::URLLoaderClientPtr client, + storage::BlobStorageContext* blob_storage_context, + scoped_refptr<storage::FileSystemContext> file_system_context) + : binding_(this, std::move(url_loader_request)), + request_(request), + client_(std::move(client)), + writable_handle_watcher_(FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::MANUAL), + peer_closed_handle_watcher_(FROM_HERE, + mojo::SimpleWatcher::ArmingPolicy::MANUAL), + weak_factory_(this) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + if (blob_storage_context) { + blob_handle_ = + blob_storage_context->GetBlobDataFromPublicURL(request.url); + } + + // PostTask since it might destruct. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::Bind(&BlobURLLoader::Start, weak_factory_.GetWeakPtr(), + request, file_system_context)); + } + + void Start(const ResourceRequest& request, + scoped_refptr<storage::FileSystemContext> file_system_context) { + if (!blob_handle_) { + NotifyCompleted(net::ERR_FILE_NOT_FOUND); + return; + } + + base::SequencedTaskRunner* file_task_runner = + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE).get(); + blob_reader_ = + blob_handle_->CreateReader(file_system_context.get(), file_task_runner); + + // We only support GET request per the spec. + if (request.method != "GET") { + NotifyCompleted(net::ERR_METHOD_NOT_SUPPORTED); + return; + } + + if (blob_reader_->net_error()) { + NotifyCompleted(blob_reader_->net_error()); + return; + } + + net::HttpRequestHeaders request_headers; + request_headers.AddHeadersFromString(request.headers); + std::string range_header; + if (request_headers.GetHeader(net::HttpRequestHeaders::kRange, + &range_header)) { + // We only care about "Range" header here. + std::vector<net::HttpByteRange> ranges; + if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { + if (ranges.size() == 1) { + byte_range_set_ = true; + byte_range_ = ranges[0]; + } else { + // We don't support multiple range requests in one single URL request, + // because we need to do multipart encoding here. + // TODO(jianli): Support multipart byte range requests. + NotifyCompleted(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); + } + } + } + + storage::BlobReader::Status size_status = + blob_reader_->CalculateSize(base::Bind(&BlobURLLoader::DidCalculateSize, + weak_factory_.GetWeakPtr())); + switch (size_status) { + case storage::BlobReader::Status::NET_ERROR: + NotifyCompleted(blob_reader_->net_error()); + return; + case storage::BlobReader::Status::IO_PENDING: + return; + case storage::BlobReader::Status::DONE: + DidCalculateSize(net::OK); + return; + } + + NOTREACHED(); + } + + ~BlobURLLoader() override {} + + private: + // mojom::URLLoader implementation: + void FollowRedirect() override { NOTREACHED(); } + + void SetPriority(net::RequestPriority priority, + int32_t intra_priority_value) override {} + + // Notifies the client that the request completed. Takes care of deleting this + // object now if possible (i.e. no outstanding data pipe), otherwise this + // object will be deleted when the data pipe is closed. + void NotifyCompleted(int error_code) { + if (error_code != net::OK && !sent_headers_) { + net::HttpStatusCode status_code = + storage::BlobURLRequestJob::NetErrorToHttpStatusCode(error_code); + ResourceResponseHead response; + response.headers = storage::BlobURLRequestJob::GenerateHeaders( + status_code, nullptr, nullptr, nullptr, nullptr); + client_->OnReceiveResponse(response, base::nullopt, nullptr); + } + ResourceRequestCompletionStatus request_complete_data; + client_->OnComplete(request_complete_data); + + DeleteIfNeeded(); + } + + void DidCalculateSize(int result) { + if (result != net::OK) { + NotifyCompleted(result); + return; + } + + // Apply the range requirement. + if (!byte_range_.ComputeBounds(blob_reader_->total_size())) { + NotifyCompleted(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE); + return; + } + + DCHECK_LE(byte_range_.first_byte_position(), + byte_range_.last_byte_position() + 1); + uint64_t length = + base::checked_cast<uint64_t>(byte_range_.last_byte_position() - + byte_range_.first_byte_position() + 1); + + if (byte_range_set_) + blob_reader_->SetReadRange(byte_range_.first_byte_position(), length); + + net::HttpStatusCode status_code = net::HTTP_OK; + if (byte_range_set_ && byte_range_.IsValid()) { + status_code = net::HTTP_PARTIAL_CONTENT; + } else { + // TODO(horo): When the requester doesn't need the side data + // (ex:FileReader) we should skip reading the side data. + if (blob_reader_->has_side_data() && + blob_reader_->ReadSideData(base::Bind(&BlobURLLoader::DidReadMetadata, + weak_factory_.GetWeakPtr())) == + storage::BlobReader::Status::IO_PENDING) { + return; + } + } + + HeadersCompleted(status_code); + } + + void DidReadMetadata(storage::BlobReader::Status result) { + if (result != storage::BlobReader::Status::DONE) { + NotifyCompleted(blob_reader_->net_error()); + return; + } + HeadersCompleted(net::HTTP_OK); + } + + void HeadersCompleted(net::HttpStatusCode status_code) { + ResourceResponseHead response; + response.content_length = 0; + response.headers = storage::BlobURLRequestJob::GenerateHeaders( + status_code, blob_handle_.get(), blob_reader_.get(), &byte_range_, + &response.content_length); + + std::string mime_type; + response.headers->GetMimeType(&mime_type); + // Match logic in StreamURLRequestJob::HeadersCompleted. + if (mime_type.empty()) + mime_type = "text/plain"; + response.mime_type = mime_type; + + // TODO(jam): some of this code can be shared with + // content/network/url_loader_impl.h + client_->OnReceiveResponse(response, base::nullopt, nullptr); + sent_headers_ = true; + + net::IOBufferWithSize* metadata = blob_reader_->side_data(); + if (metadata) { + const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data()); + client_->OnReceiveCachedMetadata( + std::vector<uint8_t>(data, data + metadata->size())); + } + + mojo::DataPipe data_pipe(kDefaultAllocationSize); + response_body_stream_ = std::move(data_pipe.producer_handle); + response_body_consumer_handle_ = std::move(data_pipe.consumer_handle); + peer_closed_handle_watcher_.Watch( + response_body_stream_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED, + base::Bind(&BlobURLLoader::OnResponseBodyStreamClosed, + base::Unretained(this))); + peer_closed_handle_watcher_.ArmOrNotify(); + + writable_handle_watcher_.Watch( + response_body_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE, + base::Bind(&BlobURLLoader::OnResponseBodyStreamReady, + base::Unretained(this))); + + // Start reading... + ReadMore(); + } + + void ReadMore() { + DCHECK(!pending_write_.get()); + + uint32_t num_bytes; + // TODO: we should use the abstractions in MojoAsyncResourceHandler. + MojoResult result = NetToMojoPendingBuffer::BeginWrite( + &response_body_stream_, &pending_write_, &num_bytes); + if (result == MOJO_RESULT_SHOULD_WAIT) { + // The pipe is full. We need to wait for it to have more space. + writable_handle_watcher_.ArmOrNotify(); + return; + } else if (result != MOJO_RESULT_OK) { + // The response body stream is in a bad state. Bail. + writable_handle_watcher_.Cancel(); + response_body_stream_.reset(); + NotifyCompleted(net::ERR_UNEXPECTED); + return; + } + + CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); + scoped_refptr<net::IOBuffer> buf( + new NetToMojoIOBuffer(pending_write_.get())); + int bytes_read; + storage::BlobReader::Status read_status = blob_reader_->Read( + buf.get(), static_cast<int>(num_bytes), &bytes_read, + base::Bind(&BlobURLLoader::DidRead, weak_factory_.GetWeakPtr(), false)); + switch (read_status) { + case storage::BlobReader::Status::NET_ERROR: + NotifyCompleted(blob_reader_->net_error()); + return; + case storage::BlobReader::Status::IO_PENDING: + // Wait for DidRead. + return; + case storage::BlobReader::Status::DONE: + if (bytes_read > 0) { + DidRead(true, bytes_read); + } else { + writable_handle_watcher_.Cancel(); + pending_write_->Complete(0); + pending_write_ = nullptr; // This closes the data pipe. + NotifyCompleted(net::OK); + return; + } + } + } + + void DidRead(bool completed_synchronously, int num_bytes) { + if (response_body_consumer_handle_.is_valid()) { + // Send the data pipe on the first OnReadCompleted call. + client_->OnStartLoadingResponseBody( + std::move(response_body_consumer_handle_)); + } + response_body_stream_ = pending_write_->Complete(num_bytes); + pending_write_ = nullptr; + if (completed_synchronously) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&BlobURLLoader::ReadMore, weak_factory_.GetWeakPtr())); + } else { + ReadMore(); + } + } + + void OnResponseBodyStreamClosed(MojoResult result) { + response_body_stream_.reset(); + pending_write_ = nullptr; + DeleteIfNeeded(); + } + + void OnResponseBodyStreamReady(MojoResult result) { + // TODO: Handle a bad |result| value. + DCHECK_EQ(result, MOJO_RESULT_OK); + ReadMore(); + } + + void DeleteIfNeeded() { + bool has_data_pipe = + pending_write_.get() || response_body_stream_.is_valid(); + if (!has_data_pipe) + delete this; + } + + mojo::AssociatedBinding<mojom::URLLoader> binding_; + ResourceRequest request_; + mojom::URLLoaderClientPtr client_; + + bool byte_range_set_ = false; + net::HttpByteRange byte_range_; + + bool sent_headers_ = false; + + std::unique_ptr<storage::BlobDataHandle> blob_handle_; + std::unique_ptr<storage::BlobReader> blob_reader_; + + // TODO(jam): share with URLLoaderImpl + mojo::ScopedDataPipeProducerHandle response_body_stream_; + mojo::ScopedDataPipeConsumerHandle response_body_consumer_handle_; + scoped_refptr<NetToMojoPendingBuffer> pending_write_; + mojo::SimpleWatcher writable_handle_watcher_; + mojo::SimpleWatcher peer_closed_handle_watcher_; + + base::WeakPtrFactory<BlobURLLoader> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(BlobURLLoader); +}; + +} // namespace + +BlobURLLoaderFactory::BlobURLLoaderFactory( + BlobContextGetter blob_storage_context_getter, + scoped_refptr<storage::FileSystemContext> file_system_context) + : file_system_context_(file_system_context) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::BindOnce(&BlobURLLoaderFactory::InitializeOnIO, this, + std::move(blob_storage_context_getter))); +} + +mojom::URLLoaderFactoryPtr BlobURLLoaderFactory::CreateFactory() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + mojom::URLLoaderFactoryPtr factory; + mojom::URLLoaderFactoryRequest request = mojo::MakeRequest(&factory); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::BindOnce(&BlobURLLoaderFactory::BindOnIO, this, + std::move(request))); + + return factory; +} + +BlobURLLoaderFactory::~BlobURLLoaderFactory() {} + +void BlobURLLoaderFactory::InitializeOnIO( + BlobContextGetter blob_storage_context_getter) { + blob_storage_context_ = std::move(blob_storage_context_getter).Run(); +} + +void BlobURLLoaderFactory::BindOnIO(mojom::URLLoaderFactoryRequest request) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + + loader_factory_bindings_.AddBinding(this, std::move(request)); +} + +void BlobURLLoaderFactory::CreateLoaderAndStart( + mojom::URLLoaderAssociatedRequest loader, + int32_t routing_id, + int32_t request_id, + uint32_t options, + const ResourceRequest& request, + mojom::URLLoaderClientPtr client) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + new BlobURLLoader(std::move(loader), request, std::move(client), + blob_storage_context_.get(), file_system_context_); +} + +void BlobURLLoaderFactory::SyncLoad(int32_t routing_id, + int32_t request_id, + const ResourceRequest& request, + SyncLoadCallback callback) { + NOTREACHED(); +} + +} // namespace content
diff --git a/content/browser/blob_storage/blob_url_loader_factory.h b/content/browser/blob_storage/blob_url_loader_factory.h new file mode 100644 index 0000000..cea4f06 --- /dev/null +++ b/content/browser/blob_storage/blob_url_loader_factory.h
@@ -0,0 +1,72 @@ +// Copyright 2017 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. + +#ifndef CONTENT_BROWSER_BLOB_STORAGE_BLOB_URL_LOADER_FACTORY_H_ +#define CONTENT_BROWSER_BLOB_STORAGE_BLOB_URL_LOADER_FACTORY_H_ + +#include "base/callback.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "content/common/content_export.h" +#include "content/common/url_loader_factory.mojom.h" +#include "content/public/browser/browser_thread.h" +#include "mojo/public/cpp/bindings/binding_set.h" + +namespace storage { +class BlobStorageContext; +class FileSystemContext; +} + +namespace content { + +// A class for creating URLLoaderFactory for blob scheme. +// There should be one owned per StoragePartition. +class BlobURLLoaderFactory + : public base::RefCountedThreadSafe<BlobURLLoaderFactory, + BrowserThread::DeleteOnIOThread>, + public mojom::URLLoaderFactory { + public: + using BlobContextGetter = + base::OnceCallback<base::WeakPtr<storage::BlobStorageContext>()>; + CONTENT_EXPORT BlobURLLoaderFactory( + BlobContextGetter blob_storage_context_getter, + scoped_refptr<storage::FileSystemContext> file_system_context); + + // Creates a URLLoaderFactory interface pointer for serving blob requests. + // Called on the UI thread. + mojom::URLLoaderFactoryPtr CreateFactory(); + + // mojom::URLLoaderFactory implementation: + void CreateLoaderAndStart(mojom::URLLoaderAssociatedRequest loader, + int32_t routing_id, + int32_t request_id, + uint32_t options, + const ResourceRequest& request, + mojom::URLLoaderClientPtr client) override; + void SyncLoad(int32_t routing_id, + int32_t request_id, + const ResourceRequest& request, + SyncLoadCallback callback) override; + + private: + friend class base::DeleteHelper<BlobURLLoaderFactory>; + friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>; + + ~BlobURLLoaderFactory() override; + + void InitializeOnIO(BlobContextGetter blob_storage_context_getter); + void BindOnIO(mojom::URLLoaderFactoryRequest request); + + base::WeakPtr<storage::BlobStorageContext> blob_storage_context_; + scoped_refptr<storage::FileSystemContext> file_system_context_; + + // Used on the IO thread. + mojo::BindingSet<mojom::URLLoaderFactory> loader_factory_bindings_; + + DISALLOW_COPY_AND_ASSIGN(BlobURLLoaderFactory); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_BLOB_STORAGE_BLOB_URL_LOADER_FACTORY_H_
diff --git a/storage/browser/blob/blob_url_request_job_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc similarity index 82% rename from storage/browser/blob/blob_url_request_job_unittest.cc rename to content/browser/blob_storage/blob_url_unittest.cc index 353eaf08..fef6738 100644 --- a/storage/browser/blob/blob_url_request_job_unittest.cc +++ b/content/browser/blob_storage/blob_url_unittest.cc
@@ -8,6 +8,7 @@ #include <memory> #include "base/bind.h" +#include "base/command_line.h" #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" @@ -19,6 +20,12 @@ #include "base/run_loop.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "content/browser/blob_storage/blob_url_loader_factory.h" +#include "content/browser/loader/test_url_loader_client.h" +#include "content/browser/url_loader_factory_getter.h" +#include "content/public/common/content_switches.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "mojo/common/data_pipe_utils.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" #include "net/base/test_completion_callback.h" @@ -148,7 +155,10 @@ }; BlobURLRequestJobTest() - : blob_data_(new BlobDataBuilder("uuid")), expected_status_code_(0) {} + : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP), + blob_data_(new BlobDataBuilder("uuid")), + response_error_code_(net::OK), + expected_status_code_(0) {} void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); @@ -180,7 +190,6 @@ void TearDown() override { blob_handle_.reset(); - request_.reset(); // Clean up for ASAN base::RunLoop run_loop; run_loop.RunUntilIdle(); @@ -250,34 +259,76 @@ expected_status_code_ = 200; expected_response_ = expected_response; TestRequest("GET", net::HttpRequestHeaders()); - EXPECT_EQ(expected_content_length, - request_->response_headers()->GetContentLength()); + EXPECT_EQ(expected_content_length, response_headers_->GetContentLength()); } void TestErrorRequest(int expected_status_code) { expected_status_code_ = expected_status_code; expected_response_ = ""; TestRequest("GET", net::HttpRequestHeaders()); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_TRUE(response_metadata_.empty()); } void TestRequest(const std::string& method, const net::HttpRequestHeaders& extra_headers) { - request_ = url_request_context_.CreateRequest( - GURL("blob:blah"), net::DEFAULT_PRIORITY, &url_request_delegate_, - TRAFFIC_ANNOTATION_FOR_TESTS); - request_->set_method(method); - if (!extra_headers.IsEmpty()) - request_->SetExtraRequestHeaders(extra_headers); - request_->Start(); + GURL url("blob:blah"); - base::RunLoop().Run(); + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableNetworkService)) { + GetHandleFromBuilder(); // To add to StorageContext. + const_cast<storage::BlobStorageRegistry&>(blob_context_.registry()) + .CreateUrlMapping(url, blob_data_->uuid()); + ResourceRequest request; + request.url = url; + request.method = method; + if (!extra_headers.IsEmpty()) + request.headers = extra_headers.ToString(); + + mojom::URLLoaderAssociatedPtr url_loader; + TestURLLoaderClient url_loader_client; + scoped_refptr<BlobURLLoaderFactory> factory = new BlobURLLoaderFactory( + base::Bind(&BlobURLRequestJobTest::GetStorageContext, + base::Unretained(this)), + file_system_context_); + base::RunLoop().RunUntilIdle(); + factory->CreateLoaderAndStart(mojo::MakeRequest(&url_loader), 0, 0, + mojom::kURLLoadOptionNone, request, + url_loader_client.CreateInterfacePtr()); + url_loader_client.RunUntilComplete(); + + if (url_loader_client.response_body().is_valid()) { + EXPECT_TRUE(mojo::common::BlockingCopyToString( + url_loader_client.response_body_release(), &response_)); + } + response_headers_ = url_loader_client.response_head().headers; + response_metadata_ = url_loader_client.cached_metadata(); + response_error_code_ = url_loader_client.completion_status().error_code; + } else { + std::unique_ptr<net::URLRequest> request = + url_request_context_.CreateRequest(url, net::DEFAULT_PRIORITY, + &url_request_delegate_, + TRAFFIC_ANNOTATION_FOR_TESTS); + request->set_method(method); + if (!extra_headers.IsEmpty()) + request->SetExtraRequestHeaders(extra_headers); + request->Start(); + + base::RunLoop().Run(); + response_ = url_request_delegate_.data_received(); + response_headers_ = request->response_headers(); + if (request->response_info().metadata) { + response_metadata_ = + std::string(request->response_info().metadata->data(), + request->response_info().metadata->size()); + } + + response_error_code_ = url_request_delegate_.request_status(); + } // Verify response. - EXPECT_EQ(net::OK, url_request_delegate_.request_status()); - EXPECT_EQ(expected_status_code_, - request_->response_headers()->response_code()); - EXPECT_EQ(expected_response_, url_request_delegate_.data_received()); + EXPECT_EQ(net::OK, response_error_code_); + EXPECT_EQ(expected_status_code_, response_headers_->response_code()); + EXPECT_EQ(expected_response_, response_); } void BuildComplicatedData(std::string* expected_result) { @@ -330,6 +381,10 @@ } protected: + base::WeakPtr<storage::BlobStorageContext> GetStorageContext() { + return blob_context_.AsWeakPtr(); + } + base::ScopedTempDir temp_dir_; base::FilePath temp_file1_; base::FilePath temp_file2_; @@ -344,7 +399,7 @@ std::unique_ptr<disk_cache::Backend> disk_cache_backend_; disk_cache::ScopedEntryPtr disk_cache_entry_; - base::MessageLoopForIO message_loop_; + TestBrowserThreadBundle thread_bundle_; scoped_refptr<storage::FileSystemContext> file_system_context_; storage::BlobStorageContext blob_context_; @@ -354,7 +409,10 @@ net::URLRequestJobFactoryImpl url_request_job_factory_; net::URLRequestContext url_request_context_; net::TestDelegate url_request_delegate_; - std::unique_ptr<net::URLRequest> request_; + std::string response_; + int response_error_code_; + scoped_refptr<net::HttpResponseHeaders> response_headers_; + std::string response_metadata_; int expected_status_code_; std::string expected_response_; @@ -490,12 +548,11 @@ expected_response_ = result.substr(5, 10 - 5 + 1); TestRequest("GET", extra_headers); - EXPECT_EQ(6, request_->response_headers()->GetContentLength()); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_EQ(6, response_headers_->GetContentLength()); + EXPECT_TRUE(response_metadata_.empty()); int64_t first = 0, last = 0, length = 0; - EXPECT_TRUE(request_->response_headers()->GetContentRangeFor206(&first, &last, - &length)); + EXPECT_TRUE(response_headers_->GetContentRangeFor206(&first, &last, &length)); EXPECT_EQ(5, first); EXPECT_EQ(10, last); EXPECT_EQ(GetTotalBlobLength(), length); @@ -512,13 +569,12 @@ expected_response_ = result.substr(result.length() - 10); TestRequest("GET", extra_headers); - EXPECT_EQ(10, request_->response_headers()->GetContentLength()); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_EQ(10, response_headers_->GetContentLength()); + EXPECT_TRUE(response_metadata_.empty()); int64_t total = GetTotalBlobLength(); int64_t first = 0, last = 0, length = 0; - EXPECT_TRUE(request_->response_headers()->GetContentRangeFor206(&first, &last, - &length)); + EXPECT_TRUE(response_headers_->GetContentRangeFor206(&first, &last, &length)); EXPECT_EQ(total - 10, first); EXPECT_EQ(total - 1, last); EXPECT_EQ(total, length); @@ -535,12 +591,11 @@ expected_response_ = result.substr(0, 3); TestRequest("GET", extra_headers); - EXPECT_EQ(3, request_->response_headers()->GetContentLength()); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_EQ(3, response_headers_->GetContentLength()); + EXPECT_TRUE(response_metadata_.empty()); int64_t first = 0, last = 0, length = 0; - EXPECT_TRUE(request_->response_headers()->GetContentRangeFor206(&first, &last, - &length)); + EXPECT_TRUE(response_headers_->GetContentRangeFor206(&first, &last, &length)); EXPECT_EQ(0, first); EXPECT_EQ(2, last); EXPECT_EQ(GetTotalBlobLength(), length); @@ -555,13 +610,13 @@ TestRequest("GET", net::HttpRequestHeaders()); std::string content_type; - EXPECT_TRUE(request_->response_headers()->GetMimeType(&content_type)); + EXPECT_TRUE(response_headers_->GetMimeType(&content_type)); EXPECT_EQ(kTestContentType, content_type); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_TRUE(response_metadata_.empty()); size_t iter = 0; std::string content_disposition; - EXPECT_TRUE(request_->response_headers()->EnumerateHeader( - &iter, "Content-Disposition", &content_disposition)); + EXPECT_TRUE(response_headers_->EnumerateHeader(&iter, "Content-Disposition", + &content_disposition)); EXPECT_EQ(kTestContentDisposition, content_disposition); } @@ -577,12 +632,9 @@ expected_response_ = kTestDiskCacheData2; TestRequest("GET", net::HttpRequestHeaders()); EXPECT_EQ(static_cast<int>(arraysize(kTestDiskCacheData2) - 1), - request_->response_headers()->GetContentLength()); + response_headers_->GetContentLength()); - ASSERT_TRUE(request_->response_info().metadata); - std::string metadata(request_->response_info().metadata->data(), - request_->response_info().metadata->size()); - EXPECT_EQ(std::string(kTestDiskCacheSideData), metadata); + EXPECT_EQ(std::string(kTestDiskCacheSideData), response_metadata_); } TEST_F(BlobURLRequestJobTest, TestZeroSizeSideData) { @@ -597,9 +649,9 @@ expected_response_ = kTestDiskCacheData2; TestRequest("GET", net::HttpRequestHeaders()); EXPECT_EQ(static_cast<int>(arraysize(kTestDiskCacheData2) - 1), - request_->response_headers()->GetContentLength()); + response_headers_->GetContentLength()); - EXPECT_FALSE(request_->response_info().metadata); + EXPECT_TRUE(response_metadata_.empty()); } TEST_F(BlobURLRequestJobTest, BrokenBlob) {
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index b4b4cc1..0bd003f 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3151,7 +3151,7 @@ const auto& schemes = URLDataManagerBackend::GetWebUISchemes(); if (std::find(schemes.begin(), schemes.end(), common_params.url.scheme()) != schemes.end()) { - commit_data.url_loader_factory = GetWebUIURLLoader(frame_tree_node_) + commit_data.url_loader_factory = CreateWebUIURLLoader(frame_tree_node_) .PassInterface() .PassHandle() .release();
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc index 49b37ab1..4136c41c 100644 --- a/content/browser/loader/navigation_url_loader_network_service.cc +++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -66,11 +66,13 @@ // redirects happen. class NavigationURLLoaderNetworkService::URLLoaderRequestController { public: - URLLoaderRequestController(std::unique_ptr<ResourceRequest> resource_request, - ResourceContext* resource_context) + URLLoaderRequestController( + std::unique_ptr<ResourceRequest> resource_request, + ResourceContext* resource_context, + scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter) : resource_request_(std::move(resource_request)), resource_context_(resource_context), - network_factory_(nullptr) {} + url_loader_factory_getter_(url_loader_factory_getter) {} virtual ~URLLoaderRequestController() { DCHECK_CURRENTLY_ON(BrowserThread::IO); @@ -81,7 +83,6 @@ AppCacheNavigationHandleCore* appcache_handle_core, std::unique_ptr<NavigationRequestInfo> request_info, mojom::URLLoaderFactoryPtrInfo factory_for_webui, - scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter, const base::Callback<WebContents*(void)>& web_contents_getter, mojom::URLLoaderAssociatedRequest url_loader_request, mojom::URLLoaderClientPtr url_loader_client_ptr, @@ -132,9 +133,6 @@ // TODO: add appcache code here. } - DCHECK(!network_factory_); - network_factory_ = url_loader_factory_getter->GetNetworkFactory()->get(); - Restart(std::move(url_loader_request), std::move(url_loader_client_ptr)); } @@ -167,8 +165,12 @@ } DCHECK_EQ(handlers_.size(), handler_index_); - DCHECK(network_factory_ != nullptr); - MaybeStartLoader(network_factory_); + if (resource_request_->url.SchemeIs(url::kBlobScheme)) { + factory = url_loader_factory_getter_->GetBlobFactory()->get(); + } else { + factory = url_loader_factory_getter_->GetNetworkFactory()->get(); + } + MaybeStartLoader(factory); } private: @@ -178,9 +180,7 @@ std::unique_ptr<ResourceRequest> resource_request_; ResourceContext* resource_context_; - // The factory for doing a vanilla network request, called when - // any of other request handlers handle the given request. - mojom::URLLoaderFactory* network_factory_; + scoped_refptr<URLLoaderFactoryGetter> url_loader_factory_getter_; // Kept around until we create a loader. mojom::URLLoaderAssociatedRequest url_loader_request_; @@ -249,14 +249,16 @@ schemes.end()) { FrameTreeNode* frame_tree_node = FrameTreeNode::GloballyFindByID(frame_tree_node_id); - factory_for_webui = GetWebUIURLLoader(frame_tree_node).PassInterface(); + factory_for_webui = CreateWebUIURLLoader(frame_tree_node).PassInterface(); } g_next_request_id--; DCHECK(!request_controller_); request_controller_ = base::MakeUnique<URLLoaderRequestController>( - std::move(new_request), resource_context); + std::move(new_request), resource_context, + static_cast<StoragePartitionImpl*>(storage_partition) + ->url_loader_factory_getter()); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind( @@ -268,8 +270,6 @@ appcache_handle ? appcache_handle->core() : nullptr, base::Passed(std::move(request_info)), base::Passed(std::move(factory_for_webui)), - static_cast<StoragePartitionImpl*>(storage_partition) - ->url_loader_factory_getter(), base::Bind(&GetWebContentsFromFrameTreeNodeID, frame_tree_node_id), base::Passed(std::move(loader_associated_request)), base::Passed(std::move(url_loader_client_ptr_to_pass)),
diff --git a/content/browser/loader/test_url_loader_client.h b/content/browser/loader/test_url_loader_client.h index ba50bc7..3bec4de 100644 --- a/content/browser/loader/test_url_loader_client.h +++ b/content/browser/loader/test_url_loader_client.h
@@ -61,6 +61,9 @@ return cached_metadata_; } mojo::DataPipeConsumerHandle response_body() { return response_body_.get(); } + mojo::ScopedDataPipeConsumerHandle response_body_release() { + return std::move(response_body_); + } const ResourceRequestCompletionStatus& completion_status() const { return completion_status_; }
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index 01dc7068..dbea308 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -15,6 +15,7 @@ #include "base/sequenced_task_runner.h" #include "base/single_thread_task_runner.h" #include "base/strings/utf_string_conversions.h" +#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/browser_main_loop.h" #include "content/browser/browsing_data/storage_partition_http_cache_data_remover.h" #include "content/browser/fileapi/browser_file_system_helper.h" @@ -40,6 +41,7 @@ #include "net/url_request/url_request_context_getter.h" #include "ppapi/features/features.h" #include "services/service_manager/public/cpp/connector.h" +#include "storage/browser/blob/blob_storage_context.h" #include "storage/browser/database/database_tracker.h" #include "storage/browser/quota/quota_manager.h" @@ -230,6 +232,12 @@ callback)); } +base::WeakPtr<storage::BlobStorageContext> BlobStorageContextGetter( + scoped_refptr<ChromeBlobStorageContext> blob_context) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + return blob_context->context()->AsWeakPtr(); +} + } // namespace // Static. @@ -529,6 +537,13 @@ network_service->CreateNetworkContext( MakeRequest(&partition->network_context_), std::move(context_params)); + scoped_refptr<ChromeBlobStorageContext> blob_context = + ChromeBlobStorageContext::GetFor(context); + BlobURLLoaderFactory::BlobContextGetter blob_getter = + base::BindOnce(&BlobStorageContextGetter, blob_context); + partition->blob_url_loader_factory_ = new BlobURLLoaderFactory( + std::move(blob_getter), partition->filesystem_context_); + partition->url_loader_factory_getter_ = new URLLoaderFactoryGetter(); partition->url_loader_factory_getter_->Initialize(partition.get()); } @@ -623,6 +638,10 @@ return bluetooth_allowed_devices_map_.get(); } +BlobURLLoaderFactory* StoragePartitionImpl::GetBlobURLLoaderFactory() { + return blob_url_loader_factory_.get(); +} + void StoragePartitionImpl::OpenLocalStorage( const url::Origin& origin, mojo::InterfaceRequest<mojom::LevelDBWrapper> request) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h index 58a6de1..cf6d28c 100644 --- a/content/browser/storage_partition_impl.h +++ b/content/browser/storage_partition_impl.h
@@ -18,6 +18,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/background_fetch/background_fetch_context.h" #include "content/browser/background_sync/background_sync_context.h" +#include "content/browser/blob_storage/blob_url_loader_factory.h" #include "content/browser/bluetooth/bluetooth_allowed_devices_map.h" #include "content/browser/broadcast_channel/broadcast_channel_provider.h" #include "content/browser/cache_storage/cache_storage_context_impl.h" @@ -41,6 +42,7 @@ #endif namespace content { +class BlobURLLoaderFactory; class CONTENT_EXPORT StoragePartitionImpl : public StoragePartition, @@ -116,6 +118,7 @@ PaymentAppContextImpl* GetPaymentAppContext(); BroadcastChannelProvider* GetBroadcastChannelProvider(); BluetoothAllowedDevicesMap* GetBluetoothAllowedDevicesMap(); + BlobURLLoaderFactory* GetBlobURLLoaderFactory(); // mojom::StoragePartitionService interface. void OpenLocalStorage( @@ -247,6 +250,7 @@ scoped_refptr<PaymentAppContextImpl> payment_app_context_; scoped_refptr<BroadcastChannelProvider> broadcast_channel_provider_; scoped_refptr<BluetoothAllowedDevicesMap> bluetooth_allowed_devices_map_; + scoped_refptr<BlobURLLoaderFactory> blob_url_loader_factory_; mojo::BindingSet<mojom::StoragePartitionService> bindings_; mojom::NetworkContextPtr network_context_;
diff --git a/content/browser/url_loader_factory_getter.cc b/content/browser/url_loader_factory_getter.cc index 611cef7..9f16c054 100644 --- a/content/browser/url_loader_factory_getter.cc +++ b/content/browser/url_loader_factory_getter.cc
@@ -18,10 +18,14 @@ partition->network_context()->CreateURLLoaderFactory( MakeRequest(&network_factory), 0); + mojom::URLLoaderFactoryPtr blob_factory = + partition->GetBlobURLLoaderFactory()->CreateFactory(); + BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::BindOnce(&URLLoaderFactoryGetter::InitializeOnIOThread, this, network_factory.PassInterface(), + blob_factory.PassInterface(), scoped_refptr<ChromeAppCacheService>( partition->GetAppCacheService()))); } @@ -31,6 +35,11 @@ return test_factory_.is_bound() ? &test_factory_ : &network_factory_; } +mojom::URLLoaderFactoryPtr* URLLoaderFactoryGetter::GetBlobFactory() { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + return &blob_factory_; +} + void URLLoaderFactoryGetter::SetNetworkFactoryForTesting( mojom::URLLoaderFactoryPtr test_factory) { // Since the URLLoaderFactory pointers are bound on the IO thread, and this @@ -51,8 +60,10 @@ void URLLoaderFactoryGetter::InitializeOnIOThread( mojom::URLLoaderFactoryPtrInfo network_factory, + mojom::URLLoaderFactoryPtrInfo blob_factory, scoped_refptr<ChromeAppCacheService> appcache_service) { network_factory_.Bind(std::move(network_factory)); + blob_factory_.Bind(std::move(blob_factory)); AppCacheURLLoaderFactory::CreateURLLoaderFactory( mojo::MakeRequest(&appcache_factory_), appcache_service.get(), this);
diff --git a/content/browser/url_loader_factory_getter.h b/content/browser/url_loader_factory_getter.h index 1b1fb72a..0af16fd 100644 --- a/content/browser/url_loader_factory_getter.h +++ b/content/browser/url_loader_factory_getter.h
@@ -33,6 +33,10 @@ // The pointer shouldn't be cached. mojom::URLLoaderFactoryPtr* GetNetworkFactory(); + // Called on the IO thread to get the URLLoaderFactory to the blob service. + // The pointer shouldn't be cached. + CONTENT_EXPORT mojom::URLLoaderFactoryPtr* GetBlobFactory(); + // Overrides the network URLLoaderFactory for subsequent requests. Passing a // null pointer will restore the default behavior. // This is called on the UI thread. @@ -50,14 +54,16 @@ CONTENT_EXPORT ~URLLoaderFactoryGetter(); void InitializeOnIOThread( mojom::URLLoaderFactoryPtrInfo network_factory, + mojom::URLLoaderFactoryPtrInfo blob_factory, scoped_refptr<ChromeAppCacheService> appcache_service); void SetTestNetworkFactoryOnIOThread( mojom::URLLoaderFactoryPtrInfo test_factory); // Only accessed on IO thread. mojom::URLLoaderFactoryPtr network_factory_; - mojom::URLLoaderFactoryPtr test_factory_; mojom::URLLoaderFactoryPtr appcache_factory_; + mojom::URLLoaderFactoryPtr blob_factory_; + mojom::URLLoaderFactoryPtr test_factory_; DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryGetter); };
diff --git a/content/browser/webui/web_ui_url_loader_factory.cc b/content/browser/webui/web_ui_url_loader_factory.cc index e85627c..a730bba 100644 --- a/content/browser/webui/web_ui_url_loader_factory.cc +++ b/content/browser/webui/web_ui_url_loader_factory.cc
@@ -286,7 +286,7 @@ } // namespace -mojom::URLLoaderFactoryPtr GetWebUIURLLoader(FrameTreeNode* node) { +mojom::URLLoaderFactoryPtr CreateWebUIURLLoader(FrameTreeNode* node) { int ftn_id = node->frame_tree_node_id(); if (g_factories.Get()[ftn_id].get() == nullptr) g_factories.Get()[ftn_id] = base::MakeUnique<WebUIURLLoaderFactory>(node);
diff --git a/content/browser/webui/web_ui_url_loader_factory.h b/content/browser/webui/web_ui_url_loader_factory.h index cf085f51..b52d653 100644 --- a/content/browser/webui/web_ui_url_loader_factory.h +++ b/content/browser/webui/web_ui_url_loader_factory.h
@@ -10,8 +10,8 @@ namespace content { class FrameTreeNode; -// Returns a URLLoaderFactory interface pointer for serving WebUI requests. -mojom::URLLoaderFactoryPtr GetWebUIURLLoader(FrameTreeNode* node); +// Creates a URLLoaderFactory interface pointer for serving WebUI requests. +mojom::URLLoaderFactoryPtr CreateWebUIURLLoader(FrameTreeNode* node); } // namespace content
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index f1bcce28..d5a4acb 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn
@@ -240,6 +240,8 @@ "net/url_request_service_worker_data.h", "net/url_request_user_data.cc", "net/url_request_user_data.h", + "net_adapters.cc", + "net_adapters.h", "origin_trials/trial_token.cc", "origin_trials/trial_token.h", "origin_trials/trial_token_validator.cc",
diff --git a/content/network/net_adapters.cc b/content/common/net_adapters.cc similarity index 96% rename from content/network/net_adapters.cc rename to content/common/net_adapters.cc index ee0bc33..462659a8 100644 --- a/content/network/net_adapters.cc +++ b/content/common/net_adapters.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/network/net_adapters.h" +#include "content/common/net_adapters.h" #include "net/base/net_errors.h"
diff --git a/content/network/net_adapters.h b/content/common/net_adapters.h similarity index 95% rename from content/network/net_adapters.h rename to content/common/net_adapters.h index ab6a496..9da1b21 100644 --- a/content/network/net_adapters.h +++ b/content/common/net_adapters.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_NETWORK_NET_ADAPTERS_ -#define CONTENT_NETWORK_NET_ADAPTERS_ +#ifndef CONTENT_COMMON_NET_ADAPTERS_ +#define CONTENT_COMMON_NET_ADAPTERS_ #include <stdint.h> @@ -68,4 +68,4 @@ } // namespace content -#endif // CONTENT_NETWORK_NET_ADAPTERS_ +#endif // CONTENT_COMMON_NET_ADAPTERS_
diff --git a/content/network/BUILD.gn b/content/network/BUILD.gn index 4031986..8f87a56 100644 --- a/content/network/BUILD.gn +++ b/content/network/BUILD.gn
@@ -30,8 +30,6 @@ sources = [ "cache_url_loader.cc", "cache_url_loader.h", - "net_adapters.cc", - "net_adapters.h", "network_context.cc", "network_context.h", "network_service.cc",
diff --git a/content/network/DEPS b/content/network/DEPS index 1960e889..bbad7c3 100644 --- a/content/network/DEPS +++ b/content/network/DEPS
@@ -3,6 +3,7 @@ "-content", "+content/common/content_export.h", "+content/common/resource_request.h", + "+content/common/net_adapters.h", "+content/common/network_service.mojom.h", "+content/common/url_loader.mojom.h", "+content/common/url_loader_factory.mojom.h",
diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc index 8d2143e..7d015c0 100644 --- a/content/network/url_loader_impl.cc +++ b/content/network/url_loader_impl.cc
@@ -7,8 +7,8 @@ #include "base/task_scheduler/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" +#include "content/common/net_adapters.h" #include "content/common/url_loader_factory.mojom.h" -#include "content/network/net_adapters.h" #include "content/network/network_context.h" #include "content/public/common/referrer.h" #include "content/public/common/resource_response.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index ea57ae5..f756353 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -1073,6 +1073,7 @@ "../browser/background_sync/background_sync_service_impl_unittest.cc", "../browser/blob_storage/blob_dispatcher_host_unittest.cc", "../browser/blob_storage/blob_transport_host_unittest.cc", + "../browser/blob_storage/blob_url_unittest.cc", "../browser/bluetooth/bluetooth_allowed_devices_unittest.cc", "../browser/bluetooth/bluetooth_blocklist_unittest.cc", "../browser/bluetooth/bluetooth_device_chooser_controller_unittest.cc",
diff --git a/storage/browser/BUILD.gn b/storage/browser/BUILD.gn index c02bbea..d0160bf 100644 --- a/storage/browser/BUILD.gn +++ b/storage/browser/BUILD.gn
@@ -236,7 +236,6 @@ "blob/blob_storage_context_unittest.cc", "blob/blob_storage_registry_unittest.cc", "blob/blob_transport_request_builder_unittest.cc", - "blob/blob_url_request_job_unittest.cc", "database/database_quota_client_unittest.cc", "database/database_tracker_unittest.cc", "database/database_util_unittest.cc",
diff --git a/storage/browser/blob/blob_url_request_job.cc b/storage/browser/blob/blob_url_request_job.cc index 8d7aaea..35cc474 100644 --- a/storage/browser/blob/blob_url_request_job.cc +++ b/storage/browser/blob/blob_url_request_job.cc
@@ -143,6 +143,85 @@ } } +scoped_refptr<net::HttpResponseHeaders> BlobURLRequestJob::GenerateHeaders( + net::HttpStatusCode status_code, + BlobDataHandle* blob_handle, + BlobReader* blob_reader, + net::HttpByteRange* byte_range, + int64_t* content_size) { + std::string status("HTTP/1.1 "); + status.append(base::IntToString(status_code)); + status.append(" "); + status.append(net::GetHttpReasonPhrase(status_code)); + status.append("\0\0", 2); + scoped_refptr<net::HttpResponseHeaders> headers = + new net::HttpResponseHeaders(status); + + if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) { + *content_size = blob_reader->remaining_bytes(); + std::string content_length_header(net::HttpRequestHeaders::kContentLength); + content_length_header.append(": "); + content_length_header.append(base::Int64ToString(*content_size)); + headers->AddHeader(content_length_header); + if (status_code == net::HTTP_PARTIAL_CONTENT) { + DCHECK(byte_range->IsValid()); + std::string content_range_header(net::HttpResponseHeaders::kContentRange); + content_range_header.append(": bytes "); + content_range_header.append(base::StringPrintf( + "%" PRId64 "-%" PRId64, byte_range->first_byte_position(), + byte_range->last_byte_position())); + content_range_header.append("/"); + content_range_header.append( + base::StringPrintf("%" PRId64, blob_reader->total_size())); + headers->AddHeader(content_range_header); + } + if (!blob_handle->content_type().empty()) { + std::string content_type_header(net::HttpRequestHeaders::kContentType); + content_type_header.append(": "); + content_type_header.append(blob_handle->content_type()); + headers->AddHeader(content_type_header); + } + if (!blob_handle->content_disposition().empty()) { + std::string content_disposition_header("Content-Disposition: "); + content_disposition_header.append(blob_handle->content_disposition()); + headers->AddHeader(content_disposition_header); + } + } + + return headers; +} + +net::HttpStatusCode BlobURLRequestJob::NetErrorToHttpStatusCode( + int error_code) { + net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; + switch (error_code) { + case net::ERR_ACCESS_DENIED: + status_code = net::HTTP_FORBIDDEN; + break; + case net::ERR_FILE_NOT_FOUND: + status_code = net::HTTP_NOT_FOUND; + break; + case net::ERR_METHOD_NOT_SUPPORTED: + status_code = net::HTTP_METHOD_NOT_ALLOWED; + break; + case net::ERR_REQUEST_RANGE_NOT_SATISFIABLE: + status_code = net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE; + break; + case net::ERR_INVALID_ARGUMENT: + status_code = net::HTTP_BAD_REQUEST; + break; + case net::ERR_CACHE_READ_FAILURE: + case net::ERR_CACHE_CHECKSUM_READ_FAILURE: + case net::ERR_UNEXPECTED: + case net::ERR_FAILED: + break; + default: + DCHECK(false) << "Error code not supported: " << error_code; + break; + } + return status_code; +} + BlobURLRequestJob::~BlobURLRequestJob() { TRACE_EVENT_ASYNC_END1("Blob", "BlobRequest", this, "uuid", blob_handle_ ? blob_handle_->uuid() : "NotFound"); @@ -244,80 +323,16 @@ // now. Instead, we just error out. DCHECK(!response_info_) << "Cannot NotifyFailure after headers."; - net::HttpStatusCode status_code = net::HTTP_INTERNAL_SERVER_ERROR; - switch (error_code) { - case net::ERR_ACCESS_DENIED: - status_code = net::HTTP_FORBIDDEN; - break; - case net::ERR_FILE_NOT_FOUND: - status_code = net::HTTP_NOT_FOUND; - break; - case net::ERR_METHOD_NOT_SUPPORTED: - status_code = net::HTTP_METHOD_NOT_ALLOWED; - break; - case net::ERR_REQUEST_RANGE_NOT_SATISFIABLE: - status_code = net::HTTP_REQUESTED_RANGE_NOT_SATISFIABLE; - break; - case net::ERR_INVALID_ARGUMENT: - status_code = net::HTTP_BAD_REQUEST; - break; - case net::ERR_CACHE_READ_FAILURE: - case net::ERR_CACHE_CHECKSUM_READ_FAILURE: - case net::ERR_UNEXPECTED: - case net::ERR_FAILED: - break; - default: - DCHECK(false) << "Error code not supported: " << error_code; - break; - } - HeadersCompleted(status_code); + HeadersCompleted(NetErrorToHttpStatusCode(error_code)); } void BlobURLRequestJob::HeadersCompleted(net::HttpStatusCode status_code) { - std::string status("HTTP/1.1 "); - status.append(base::IntToString(status_code)); - status.append(" "); - status.append(net::GetHttpReasonPhrase(status_code)); - status.append("\0\0", 2); - net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status); - - set_expected_content_size(0); - - if (status_code == net::HTTP_OK || status_code == net::HTTP_PARTIAL_CONTENT) { - set_expected_content_size(blob_reader_->remaining_bytes()); - std::string content_length_header(net::HttpRequestHeaders::kContentLength); - content_length_header.append(": "); - content_length_header.append( - base::Int64ToString(blob_reader_->remaining_bytes())); - headers->AddHeader(content_length_header); - if (status_code == net::HTTP_PARTIAL_CONTENT) { - DCHECK(byte_range_set_); - DCHECK(byte_range_.IsValid()); - std::string content_range_header(net::HttpResponseHeaders::kContentRange); - content_range_header.append(": bytes "); - content_range_header.append(base::StringPrintf( - "%" PRId64 "-%" PRId64, byte_range_.first_byte_position(), - byte_range_.last_byte_position())); - content_range_header.append("/"); - content_range_header.append( - base::StringPrintf("%" PRId64, blob_reader_->total_size())); - headers->AddHeader(content_range_header); - } - if (!blob_handle_->content_type().empty()) { - std::string content_type_header(net::HttpRequestHeaders::kContentType); - content_type_header.append(": "); - content_type_header.append(blob_handle_->content_type()); - headers->AddHeader(content_type_header); - } - if (!blob_handle_->content_disposition().empty()) { - std::string content_disposition_header("Content-Disposition: "); - content_disposition_header.append(blob_handle_->content_disposition()); - headers->AddHeader(content_disposition_header); - } - } - + int64_t content_size = 0; response_info_.reset(new net::HttpResponseInfo()); - response_info_->headers = headers; + response_info_->headers = + GenerateHeaders(status_code, blob_handle_.get(), blob_reader_.get(), + &byte_range_, &content_size); + set_expected_content_size(content_size); if (blob_reader_) response_info_->metadata = blob_reader_->side_data();
diff --git a/storage/browser/blob/blob_url_request_job.h b/storage/browser/blob/blob_url_request_job.h index 4d83d60..3eb264c 100644 --- a/storage/browser/blob/blob_url_request_job.h +++ b/storage/browser/blob/blob_url_request_job.h
@@ -24,6 +24,7 @@ } namespace net { +class HttpResponseHeaders; class IOBuffer; } @@ -51,6 +52,19 @@ void GetResponseInfo(net::HttpResponseInfo* info) override; void SetExtraRequestHeaders(const net::HttpRequestHeaders& headers) override; + // Helper method to create the HTTP headers for the response. + // |blob_handles|, |blob_reader|, |byte_range| and |content_size| are only + // used if status_code isn't an error. + static scoped_refptr<net::HttpResponseHeaders> GenerateHeaders( + net::HttpStatusCode status_code, + BlobDataHandle* blob_handle, + BlobReader* blob_reader, + net::HttpByteRange* byte_range, + int64_t* content_size); + + // Helper method to map from a net error to an http status code. + static net::HttpStatusCode NetErrorToHttpStatusCode(int error_code); + protected: ~BlobURLRequestJob() override;
diff --git a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter index 25c1dd8..20ca034 100644 --- a/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter +++ b/testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter
@@ -3,7 +3,8 @@ -ServiceWorker* # http://crbug.com/715677 --Blob* +# Needs blob fetching for subresources +-BlobStorageBrowserTest.BlobCombinations # http://crbug.com/715630 -DownloadContentTest.*