// Copyright 2019 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/data_url_loader_factory.h" #include "base/memory/ref_counted.h" #include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/system/data_pipe_producer.h" #include "mojo/public/cpp/system/string_data_source.h" #include "net/base/data_url.h" #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" #include "services/network/public/mojom/url_loader.mojom.h" #include "services/network/public/mojom/url_response_head.mojom.h" namespace content { namespace { struct WriteData { mojo::Remote client; std::string data; std::unique_ptr producer; }; void OnWrite(std::unique_ptr write_data, MojoResult result) { if (result != MOJO_RESULT_OK) { write_data->client->OnComplete( network::URLLoaderCompletionStatus(net::ERR_FAILED)); return; } network::URLLoaderCompletionStatus status(net::OK); status.encoded_data_length = write_data->data.size(); status.encoded_body_length = write_data->data.size(); status.decoded_body_length = write_data->data.size(); write_data->client->OnComplete(status); } } // namespace DataURLLoaderFactory::DataURLLoaderFactory( const GURL& url, mojo::PendingReceiver factory_receiver) : NonNetworkURLLoaderFactoryBase(std::move(factory_receiver)), url_(url) {} DataURLLoaderFactory::~DataURLLoaderFactory() = default; void DataURLLoaderFactory::CreateLoaderAndStart( mojo::PendingReceiver loader, int32_t routing_id, int32_t request_id, uint32_t options, const network::ResourceRequest& request, mojo::PendingRemote client, const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) { const GURL* url = nullptr; if (!url_.is_empty() && request.url.is_empty()) { url = &url_; } else { url = &request.url; } std::string data; scoped_refptr headers; auto response = network::mojom::URLResponseHead::New(); net::Error result = net::DataURL::BuildResponse( *url, request.method, &response->mime_type, &response->charset, &data, &response->headers); // Users of CreateAndBindForOneSpecificUrl should only submit one load // request - we won't need the URL anymore. url_ = GURL(); mojo::Remote client_remote( std::move(client)); if (result != net::OK) { client_remote->OnComplete(network::URLLoaderCompletionStatus(result)); return; } client_remote->OnReceiveResponse(std::move(response)); mojo::ScopedDataPipeProducerHandle producer; mojo::ScopedDataPipeConsumerHandle consumer; if (CreateDataPipe(nullptr, &producer, &consumer) != MOJO_RESULT_OK) { client_remote->OnComplete( network::URLLoaderCompletionStatus(net::ERR_INSUFFICIENT_RESOURCES)); return; } client_remote->OnStartLoadingResponseBody(std::move(consumer)); auto write_data = new WriteData(); write_data->client = std::move(client_remote); write_data->data = std::move(data); write_data->producer = std::make_unique(std::move(producer)); mojo::DataPipeProducer* producer_ptr = write_data->producer.get(); base::StringPiece string_piece(write_data->data); producer_ptr->Write( std::make_unique( string_piece, mojo::StringDataSource::AsyncWritingMode:: STRING_STAYS_VALID_UNTIL_COMPLETION), base::BindOnce(OnWrite, std::unique_ptr(write_data))); } // static mojo::PendingRemote DataURLLoaderFactory::Create() { return CreateForOneSpecificUrl(GURL()); } // static mojo::PendingRemote DataURLLoaderFactory::CreateForOneSpecificUrl(const GURL& url) { mojo::PendingRemote pending_remote; // The DataURLLoaderFactory will delete itself when there are no more // receivers - see the NonNetworkURLLoaderFactoryBase::OnDisconnect method. new DataURLLoaderFactory(url, pending_remote.InitWithNewPipeAndPassReceiver()); return pending_remote; } } // namespace content