1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "mojo/services/network/url_loader_impl.h"
7 #include "base/memory/scoped_vector.h"
8 #include "base/message_loop/message_loop.h"
9 #include "mojo/common/common_type_converters.h"
10 #include "mojo/services/network/net_adapters.h"
11 #include "mojo/services/network/network_context.h"
12 #include "net/base/elements_upload_data_stream.h"
13 #include "net/base/io_buffer.h"
14 #include "net/base/load_flags.h"
15 #include "net/base/upload_bytes_element_reader.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/redirect_info.h"
18 #include "net/url_request/url_request_context.h"
23 // Generates an URLResponsePtr from the response state of a net::URLRequest.
24 URLResponsePtr
MakeURLResponse(const net::URLRequest
* url_request
) {
25 URLResponsePtr
response(URLResponse::New());
26 response
->url
= String::From(url_request
->url());
28 const net::HttpResponseHeaders
* headers
= url_request
->response_headers();
30 response
->status_code
= headers
->response_code();
31 response
->status_line
= headers
->GetStatusLine();
33 std::vector
<String
> header_lines
;
35 std::string name
, value
;
36 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
))
37 header_lines
.push_back(name
+ ": " + value
);
38 if (!header_lines
.empty())
39 response
->headers
.Swap(&header_lines
);
42 std::string mime_type
;
43 url_request
->GetMimeType(&mime_type
);
44 response
->mime_type
= mime_type
;
47 url_request
->GetCharset(&charset
);
48 response
->charset
= charset
;
50 return response
.Pass();
53 // Reads the request body upload data from a DataPipe.
54 class UploadDataPipeElementReader
: public net::UploadElementReader
{
56 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe
)
57 : pipe_(pipe
.Pass()), num_bytes_(0) {}
58 ~UploadDataPipeElementReader() override
{}
60 // UploadElementReader overrides:
61 int Init(const net::CompletionCallback
& callback
) override
{
63 ReadDataRaw(pipe_
.get(), nullptr, &num_bytes_
, MOJO_READ_DATA_FLAG_QUERY
);
66 uint64
GetContentLength() const override
{ return num_bytes_
; }
67 uint64
BytesRemaining() const override
{ return num_bytes_
- offset_
; }
68 bool IsInMemory() const override
{ return false; }
69 int Read(net::IOBuffer
* buf
,
71 const net::CompletionCallback
& callback
) override
{
73 std::min(static_cast<uint32_t>(BytesRemaining()),
74 static_cast<uint32_t>(buf_length
));
76 ReadDataRaw(pipe_
.get(), buf
->data(), &bytes_read
,
77 MOJO_READ_DATA_FLAG_NONE
);
80 offset_
+= bytes_read
;
85 ScopedDataPipeConsumerHandle pipe_
;
89 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader
);
94 URLLoaderImpl::URLLoaderImpl(NetworkContext
* context
,
95 InterfaceRequest
<URLLoader
> request
)
97 response_body_buffer_size_(0),
98 auto_follow_redirects_(true),
100 binding_(this, request
.Pass()),
101 weak_ptr_factory_(this) {
102 binding_
.set_error_handler(this);
105 URLLoaderImpl::~URLLoaderImpl() {
108 void URLLoaderImpl::Start(URLRequestPtr request
,
109 const Callback
<void(URLResponsePtr
)>& callback
) {
111 SendError(net::ERR_UNEXPECTED
, callback
);
116 SendError(net::ERR_INVALID_ARGUMENT
, callback
);
120 url_request_
= context_
->url_request_context()->CreateRequest(
121 GURL(request
->url
), net::DEFAULT_PRIORITY
, this, nullptr);
122 url_request_
->set_method(request
->method
);
123 if (request
->headers
) {
124 net::HttpRequestHeaders headers
;
125 for (size_t i
= 0; i
< request
->headers
.size(); ++i
)
126 headers
.AddHeaderFromString(request
->headers
[i
].To
<base::StringPiece
>());
127 url_request_
->SetExtraRequestHeaders(headers
);
130 ScopedVector
<net::UploadElementReader
> element_readers
;
131 for (size_t i
= 0; i
< request
->body
.size(); ++i
) {
132 element_readers
.push_back(
133 new UploadDataPipeElementReader(request
->body
[i
].Pass()));
135 url_request_
->set_upload(make_scoped_ptr
<net::UploadDataStream
>(
136 new net::ElementsUploadDataStream(element_readers
.Pass(), 0)));
138 if (request
->bypass_cache
)
139 url_request_
->SetLoadFlags(net::LOAD_BYPASS_CACHE
);
141 callback_
= callback
;
142 response_body_buffer_size_
= request
->response_body_buffer_size
;
143 auto_follow_redirects_
= request
->auto_follow_redirects
;
145 url_request_
->Start();
148 void URLLoaderImpl::FollowRedirect(
149 const Callback
<void(URLResponsePtr
)>& callback
) {
151 SendError(net::ERR_UNEXPECTED
, callback
);
155 if (auto_follow_redirects_
) {
156 DLOG(ERROR
) << "Spurious call to FollowRedirect";
157 SendError(net::ERR_UNEXPECTED
, callback
);
161 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
162 url_request_
->FollowDeferredRedirect();
165 void URLLoaderImpl::QueryStatus(
166 const Callback
<void(URLLoaderStatusPtr
)>& callback
) {
167 URLLoaderStatusPtr
status(URLLoaderStatus::New());
169 status
->is_loading
= url_request_
->is_pending();
170 if (!url_request_
->status().is_success())
171 status
->error
= MakeNetworkError(url_request_
->status().error());
173 status
->is_loading
= false;
175 // TODO(darin): Populate more status fields.
176 callback
.Run(status
.Pass());
179 void URLLoaderImpl::OnConnectionError() {
184 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest
* url_request
,
185 const net::RedirectInfo
& redirect_info
,
186 bool* defer_redirect
) {
187 DCHECK(url_request
== url_request_
.get());
188 DCHECK(url_request
->status().is_success());
190 if (auto_follow_redirects_
)
193 // Send the redirect response to the client, allowing them to inspect it and
194 // optionally follow the redirect.
195 *defer_redirect
= true;
197 URLResponsePtr response
= MakeURLResponse(url_request
);
198 response
->redirect_method
= redirect_info
.new_method
;
199 response
->redirect_url
= String::From(redirect_info
.new_url
);
201 SendResponse(response
.Pass());
206 void URLLoaderImpl::OnResponseStarted(net::URLRequest
* url_request
) {
207 DCHECK(url_request
== url_request_
.get());
209 if (!url_request
->status().is_success()) {
210 SendError(url_request
->status().error(), callback_
);
211 callback_
= Callback
<void(URLResponsePtr
)>();
216 // TODO(darin): Add support for optional MIME sniffing.
219 // TODO(darin): Honor given buffer size.
221 URLResponsePtr response
= MakeURLResponse(url_request
);
222 response
->body
= data_pipe
.consumer_handle
.Pass();
223 response_body_stream_
= data_pipe
.producer_handle
.Pass();
224 ListenForPeerClosed();
226 SendResponse(response
.Pass());
232 void URLLoaderImpl::OnReadCompleted(net::URLRequest
* url_request
,
234 DCHECK(url_request
== url_request_
.get());
236 if (url_request
->status().is_success()) {
237 DidRead(static_cast<uint32_t>(bytes_read
), false);
239 handle_watcher_
.Stop();
240 pending_write_
= nullptr; // This closes the data pipe.
246 void URLLoaderImpl::SendError(
248 const Callback
<void(URLResponsePtr
)>& callback
) {
249 URLResponsePtr
response(URLResponse::New());
251 response
->url
= String::From(url_request_
->url());
252 response
->error
= MakeNetworkError(error_code
);
253 callback
.Run(response
.Pass());
256 void URLLoaderImpl::SendResponse(URLResponsePtr response
) {
257 Callback
<void(URLResponsePtr
)> callback
;
258 std::swap(callback_
, callback
);
259 callback
.Run(response
.Pass());
262 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result
) {
263 // TODO(darin): Handle a bad |result| value.
265 // Continue watching the handle in case the peer is closed.
266 ListenForPeerClosed();
270 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result
) {
271 response_body_stream_
.reset();
272 pending_write_
= nullptr;
276 void URLLoaderImpl::ReadMore() {
277 DCHECK(!pending_write_
.get());
280 MojoResult result
= NetToMojoPendingBuffer::BeginWrite(
281 &response_body_stream_
, &pending_write_
, &num_bytes
);
283 if (result
== MOJO_RESULT_SHOULD_WAIT
) {
284 // The pipe is full. We need to wait for it to have more space.
285 handle_watcher_
.Start(response_body_stream_
.get(),
286 MOJO_HANDLE_SIGNAL_WRITABLE
, MOJO_DEADLINE_INDEFINITE
,
287 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady
,
288 base::Unretained(this)));
290 } else if (result
!= MOJO_RESULT_OK
) {
291 // The response body stream is in a bad state. Bail.
292 // TODO(darin): How should this be communicated to our client?
293 handle_watcher_
.Stop();
294 response_body_stream_
.reset();
298 CHECK_GT(static_cast<uint32_t>(std::numeric_limits
<int>::max()), num_bytes
);
300 scoped_refptr
<net::IOBuffer
> buf(new NetToMojoIOBuffer(pending_write_
.get()));
303 url_request_
->Read(buf
.get(), static_cast<int>(num_bytes
), &bytes_read
);
304 if (url_request_
->status().is_io_pending()) {
305 // Wait for OnReadCompleted.
306 } else if (url_request_
->status().is_success() && bytes_read
> 0) {
307 DidRead(static_cast<uint32_t>(bytes_read
), true);
309 handle_watcher_
.Stop();
310 pending_write_
->Complete(0);
311 pending_write_
= nullptr; // This closes the data pipe.
317 void URLLoaderImpl::DidRead(uint32_t num_bytes
, bool completed_synchronously
) {
318 DCHECK(url_request_
->status().is_success());
320 response_body_stream_
= pending_write_
->Complete(num_bytes
);
321 pending_write_
= nullptr;
323 if (completed_synchronously
) {
324 base::MessageLoop::current()->PostTask(
326 base::Bind(&URLLoaderImpl::ReadMore
, weak_ptr_factory_
.GetWeakPtr()));
332 void URLLoaderImpl::DeleteIfNeeded() {
333 bool has_data_pipe
= pending_write_
.get() || response_body_stream_
.is_valid();
334 if (!connected_
&& !has_data_pipe
)
338 void URLLoaderImpl::ListenForPeerClosed() {
339 handle_watcher_
.Start(response_body_stream_
.get(),
340 MOJO_HANDLE_SIGNAL_PEER_CLOSED
,
341 MOJO_DEADLINE_INDEFINITE
,
342 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed
,
343 base::Unretained(this)));