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/common/url_type_converters.h"
11 #include "mojo/services/network/net_adapters.h"
12 #include "mojo/services/network/network_context.h"
13 #include "net/base/elements_upload_data_stream.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
17 #include "net/base/upload_bytes_element_reader.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/url_request/redirect_info.h"
20 #include "net/url_request/url_request_context.h"
25 GURL
GetSiteForURL(const GURL
& url
) {
26 // If the url has a host, then determine the site.
28 // Only keep the scheme and registered domain as given by GetOrigin. This
29 // may also include a port, which we need to drop.
30 GURL site
= url
.GetOrigin();
32 // Remove port, if any.
33 if (site
.has_port()) {
34 GURL::Replacements rep
;
36 site
= site
.ReplaceComponents(rep
);
39 // If this URL has a registered domain, we only want to remember that part.
40 std::string domain
= net::registry_controlled_domains::GetDomainAndRegistry(
41 url
, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES
);
42 if (!domain
.empty()) {
43 GURL::Replacements rep
;
44 rep
.SetHostStr(domain
);
45 site
= site
.ReplaceComponents(rep
);
50 // If there is no host but there is a scheme, return the scheme.
51 // This is useful for cases like file URLs.
53 return GURL(url
.scheme() + ":");
55 // Otherwise the URL should be invalid; return an empty site.
56 DCHECK(!url
.is_valid());
60 // Generates an URLResponsePtr from the response state of a net::URLRequest.
61 URLResponsePtr
MakeURLResponse(const net::URLRequest
* url_request
) {
62 URLResponsePtr
response(URLResponse::New());
63 response
->url
= String::From(url_request
->url());
64 response
->site
= GetSiteForURL(url_request
->url()).spec();
66 const net::HttpResponseHeaders
* headers
= url_request
->response_headers();
68 response
->status_code
= headers
->response_code();
69 response
->status_line
= headers
->GetStatusLine();
71 response
->headers
= Array
<HttpHeaderPtr
>::New(0);
72 std::vector
<String
> header_lines
;
74 std::string name
, value
;
75 while (headers
->EnumerateHeaderLines(&iter
, &name
, &value
)) {
76 HttpHeaderPtr header
= HttpHeader::New();
78 header
->value
= value
;
79 response
->headers
.push_back(header
.Pass());
83 std::string mime_type
;
84 url_request
->GetMimeType(&mime_type
);
85 response
->mime_type
= mime_type
;
88 url_request
->GetCharset(&charset
);
89 response
->charset
= charset
;
91 return response
.Pass();
94 // Reads the request body upload data from a DataPipe.
95 class UploadDataPipeElementReader
: public net::UploadElementReader
{
97 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe
)
98 : pipe_(pipe
.Pass()), num_bytes_(0) {}
99 ~UploadDataPipeElementReader() override
{}
101 // UploadElementReader overrides:
102 int Init(const net::CompletionCallback
& callback
) override
{
104 ReadDataRaw(pipe_
.get(), nullptr, &num_bytes_
, MOJO_READ_DATA_FLAG_QUERY
);
107 uint64
GetContentLength() const override
{ return num_bytes_
; }
108 uint64
BytesRemaining() const override
{ return num_bytes_
- offset_
; }
109 bool IsInMemory() const override
{ return false; }
110 int Read(net::IOBuffer
* buf
,
112 const net::CompletionCallback
& callback
) override
{
113 uint32_t bytes_read
=
114 std::min(static_cast<uint32_t>(BytesRemaining()),
115 static_cast<uint32_t>(buf_length
));
116 if (bytes_read
> 0) {
117 ReadDataRaw(pipe_
.get(), buf
->data(), &bytes_read
,
118 MOJO_READ_DATA_FLAG_NONE
);
121 offset_
+= bytes_read
;
126 ScopedDataPipeConsumerHandle pipe_
;
130 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader
);
135 URLLoaderImpl::URLLoaderImpl(NetworkContext
* context
,
136 InterfaceRequest
<URLLoader
> request
,
137 scoped_ptr
<mojo::AppRefCount
> app_refcount
)
139 response_body_buffer_size_(0),
140 auto_follow_redirects_(true),
142 binding_(this, request
.Pass()),
143 app_refcount_(app_refcount
.Pass()),
144 weak_ptr_factory_(this) {
145 binding_
.set_connection_error_handler([this]() { OnConnectionError(); });
146 context_
->RegisterURLLoader(this);
149 URLLoaderImpl::~URLLoaderImpl() {
150 context_
->DeregisterURLLoader(this);
153 void URLLoaderImpl::Cleanup() {
154 // The associated network context is going away and we have to destroy
155 // net::URLRequest hold by this loader.
159 void URLLoaderImpl::Start(URLRequestPtr request
,
160 const Callback
<void(URLResponsePtr
)>& callback
) {
162 SendError(net::ERR_UNEXPECTED
, callback
);
167 SendError(net::ERR_INVALID_ARGUMENT
, callback
);
171 url_request_
= context_
->url_request_context()->CreateRequest(
172 GURL(request
->url
), net::DEFAULT_PRIORITY
, this);
173 url_request_
->set_method(request
->method
);
174 // TODO(jam): need to specify this policy.
175 url_request_
->set_referrer_policy(
176 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
);
177 if (request
->headers
) {
178 net::HttpRequestHeaders headers
;
179 for (size_t i
= 0; i
< request
->headers
.size(); ++i
) {
180 base::StringPiece header
=
181 request
->headers
[i
]->name
.To
<base::StringPiece
>();
182 base::StringPiece value
=
183 request
->headers
[i
]->value
.To
<base::StringPiece
>();
184 if (header
== net::HttpRequestHeaders::kReferer
) {
185 url_request_
->SetReferrer(value
.as_string());
187 headers
.SetHeader(header
, value
);
190 url_request_
->SetExtraRequestHeaders(headers
);
193 ScopedVector
<net::UploadElementReader
> element_readers
;
194 for (size_t i
= 0; i
< request
->body
.size(); ++i
) {
195 element_readers
.push_back(
196 new UploadDataPipeElementReader(request
->body
[i
].Pass()));
198 url_request_
->set_upload(make_scoped_ptr
<net::UploadDataStream
>(
199 new net::ElementsUploadDataStream(element_readers
.Pass(), 0)));
201 if (request
->bypass_cache
)
202 url_request_
->SetLoadFlags(net::LOAD_BYPASS_CACHE
);
204 callback_
= callback
;
205 response_body_buffer_size_
= request
->response_body_buffer_size
;
206 auto_follow_redirects_
= request
->auto_follow_redirects
;
208 url_request_
->Start();
211 void URLLoaderImpl::FollowRedirect(
212 const Callback
<void(URLResponsePtr
)>& callback
) {
214 SendError(net::ERR_UNEXPECTED
, callback
);
218 if (auto_follow_redirects_
) {
219 DLOG(ERROR
) << "Spurious call to FollowRedirect";
220 SendError(net::ERR_UNEXPECTED
, callback
);
224 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
225 url_request_
->FollowDeferredRedirect();
226 callback_
= callback
;
229 void URLLoaderImpl::QueryStatus(
230 const Callback
<void(URLLoaderStatusPtr
)>& callback
) {
231 URLLoaderStatusPtr
status(URLLoaderStatus::New());
233 status
->is_loading
= url_request_
->is_pending();
234 if (!url_request_
->status().is_success())
235 status
->error
= MakeNetworkError(url_request_
->status().error());
237 status
->is_loading
= false;
239 // TODO(darin): Populate more status fields.
240 callback
.Run(status
.Pass());
243 void URLLoaderImpl::OnConnectionError() {
248 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest
* url_request
,
249 const net::RedirectInfo
& redirect_info
,
250 bool* defer_redirect
) {
251 DCHECK(url_request
== url_request_
.get());
252 DCHECK(url_request
->status().is_success());
254 if (auto_follow_redirects_
)
257 // Send the redirect response to the client, allowing them to inspect it and
258 // optionally follow the redirect.
259 *defer_redirect
= true;
261 URLResponsePtr response
= MakeURLResponse(url_request
);
262 response
->redirect_method
= redirect_info
.new_method
;
263 response
->redirect_url
= String::From(redirect_info
.new_url
);
264 response
->redirect_referrer
= redirect_info
.new_referrer
;
266 SendResponse(response
.Pass());
271 void URLLoaderImpl::OnResponseStarted(net::URLRequest
* url_request
) {
272 DCHECK(url_request
== url_request_
.get());
274 if (!url_request
->status().is_success()) {
275 SendError(url_request
->status().error(), callback_
);
276 callback_
= Callback
<void(URLResponsePtr
)>();
281 // TODO(darin): Add support for optional MIME sniffing.
284 // TODO(darin): Honor given buffer size.
286 URLResponsePtr response
= MakeURLResponse(url_request
);
287 response
->body
= data_pipe
.consumer_handle
.Pass();
288 response_body_stream_
= data_pipe
.producer_handle
.Pass();
289 ListenForPeerClosed();
291 SendResponse(response
.Pass());
297 void URLLoaderImpl::OnReadCompleted(net::URLRequest
* url_request
,
299 DCHECK(url_request
== url_request_
.get());
301 if (url_request
->status().is_success()) {
302 DidRead(static_cast<uint32_t>(bytes_read
), false);
304 handle_watcher_
.Stop();
305 pending_write_
= nullptr; // This closes the data pipe.
311 void URLLoaderImpl::SendError(
313 const Callback
<void(URLResponsePtr
)>& callback
) {
314 URLResponsePtr
response(URLResponse::New());
316 response
->url
= String::From(url_request_
->url());
317 response
->error
= MakeNetworkError(error_code
);
318 callback
.Run(response
.Pass());
321 void URLLoaderImpl::SendResponse(URLResponsePtr response
) {
322 Callback
<void(URLResponsePtr
)> callback
;
323 std::swap(callback_
, callback
);
324 callback
.Run(response
.Pass());
327 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result
) {
328 // TODO(darin): Handle a bad |result| value.
330 // Continue watching the handle in case the peer is closed.
331 ListenForPeerClosed();
335 void URLLoaderImpl::OnResponseBodyStreamClosed(MojoResult result
) {
336 url_request_
.reset();
337 response_body_stream_
.reset();
338 pending_write_
= nullptr;
342 void URLLoaderImpl::ReadMore() {
343 DCHECK(!pending_write_
.get());
346 MojoResult result
= NetToMojoPendingBuffer::BeginWrite(
347 &response_body_stream_
, &pending_write_
, &num_bytes
);
349 if (result
== MOJO_RESULT_SHOULD_WAIT
) {
350 // The pipe is full. We need to wait for it to have more space.
351 handle_watcher_
.Start(response_body_stream_
.get(),
352 MOJO_HANDLE_SIGNAL_WRITABLE
, MOJO_DEADLINE_INDEFINITE
,
353 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady
,
354 base::Unretained(this)));
356 } else if (result
!= MOJO_RESULT_OK
) {
357 // The response body stream is in a bad state. Bail.
358 // TODO(darin): How should this be communicated to our client?
359 handle_watcher_
.Stop();
360 response_body_stream_
.reset();
364 CHECK_GT(static_cast<uint32_t>(std::numeric_limits
<int>::max()), num_bytes
);
366 scoped_refptr
<net::IOBuffer
> buf(new NetToMojoIOBuffer(pending_write_
.get()));
369 url_request_
->Read(buf
.get(), static_cast<int>(num_bytes
), &bytes_read
);
370 if (url_request_
->status().is_io_pending()) {
371 // Wait for OnReadCompleted.
372 } else if (url_request_
->status().is_success() && bytes_read
> 0) {
373 DidRead(static_cast<uint32_t>(bytes_read
), true);
375 handle_watcher_
.Stop();
376 pending_write_
->Complete(0);
377 pending_write_
= nullptr; // This closes the data pipe.
383 void URLLoaderImpl::DidRead(uint32_t num_bytes
, bool completed_synchronously
) {
384 DCHECK(url_request_
->status().is_success());
386 response_body_stream_
= pending_write_
->Complete(num_bytes
);
387 pending_write_
= nullptr;
389 if (completed_synchronously
) {
390 base::MessageLoop::current()->PostTask(
392 base::Bind(&URLLoaderImpl::ReadMore
, weak_ptr_factory_
.GetWeakPtr()));
398 void URLLoaderImpl::DeleteIfNeeded() {
399 bool has_data_pipe
= pending_write_
.get() || response_body_stream_
.is_valid();
400 if (!connected_
&& !has_data_pipe
)
404 void URLLoaderImpl::ListenForPeerClosed() {
405 handle_watcher_
.Start(response_body_stream_
.get(),
406 MOJO_HANDLE_SIGNAL_PEER_CLOSED
,
407 MOJO_DEADLINE_INDEFINITE
,
408 base::Bind(&URLLoaderImpl::OnResponseBodyStreamClosed
,
409 base::Unretained(this)));