base: Change DCHECK_IS_ON to a macro DCHECK_IS_ON().
[chromium-blink-merge.git] / mojo / services / network / url_loader_impl.cc
blob3f263780407b907f7d25da682dcc69719f91e0f0
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"
20 namespace mojo {
21 namespace {
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();
29 if (headers) {
30 response->status_code = headers->response_code();
31 response->status_line = headers->GetStatusLine();
33 std::vector<String> header_lines;
34 void* iter = NULL;
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;
46 std::string charset;
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 {
55 public:
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 {
62 offset_ = 0;
63 ReadDataRaw(pipe_.get(), NULL, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY);
64 return net::OK;
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,
70 int buf_length,
71 const net::CompletionCallback& callback) override {
72 uint32_t bytes_read =
73 std::min(static_cast<uint32_t>(BytesRemaining()),
74 static_cast<uint32_t>(buf_length));
75 if (bytes_read > 0) {
76 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read,
77 MOJO_READ_DATA_FLAG_NONE);
80 offset_ += bytes_read;
81 return bytes_read;
84 private:
85 ScopedDataPipeConsumerHandle pipe_;
86 uint32_t num_bytes_;
87 uint32_t offset_;
89 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader);
92 } // namespace
94 URLLoaderImpl::URLLoaderImpl(NetworkContext* context)
95 : context_(context),
96 response_body_buffer_size_(0),
97 auto_follow_redirects_(true),
98 weak_ptr_factory_(this) {
101 URLLoaderImpl::~URLLoaderImpl() {
104 void URLLoaderImpl::Start(URLRequestPtr request,
105 const Callback<void(URLResponsePtr)>& callback) {
106 if (url_request_) {
107 SendError(net::ERR_UNEXPECTED, callback);
108 return;
111 if (!request) {
112 SendError(net::ERR_INVALID_ARGUMENT, callback);
113 return;
116 url_request_ = context_->url_request_context()->CreateRequest(
117 GURL(request->url),
118 net::DEFAULT_PRIORITY,
119 this,
120 NULL);
121 url_request_->set_method(request->method);
122 if (request->headers) {
123 net::HttpRequestHeaders headers;
124 for (size_t i = 0; i < request->headers.size(); ++i)
125 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>());
126 url_request_->SetExtraRequestHeaders(headers);
128 if (request->body) {
129 ScopedVector<net::UploadElementReader> element_readers;
130 for (size_t i = 0; i < request->body.size(); ++i) {
131 element_readers.push_back(
132 new UploadDataPipeElementReader(request->body[i].Pass()));
134 url_request_->set_upload(make_scoped_ptr<net::UploadDataStream>(
135 new net::ElementsUploadDataStream(element_readers.Pass(), 0)));
137 if (request->bypass_cache)
138 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE);
140 callback_ = callback;
141 response_body_buffer_size_ = request->response_body_buffer_size;
142 auto_follow_redirects_ = request->auto_follow_redirects;
144 url_request_->Start();
147 void URLLoaderImpl::FollowRedirect(
148 const Callback<void(URLResponsePtr)>& callback) {
149 if (!url_request_) {
150 SendError(net::ERR_UNEXPECTED, callback);
151 return;
154 if (auto_follow_redirects_) {
155 DLOG(ERROR) << "Spurious call to FollowRedirect";
156 SendError(net::ERR_UNEXPECTED, callback);
157 return;
160 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect.
161 url_request_->FollowDeferredRedirect();
164 void URLLoaderImpl::QueryStatus(
165 const Callback<void(URLLoaderStatusPtr)>& callback) {
166 URLLoaderStatusPtr status(URLLoaderStatus::New());
167 if (url_request_) {
168 status->is_loading = url_request_->is_pending();
169 if (!url_request_->status().is_success())
170 status->error = MakeNetworkError(url_request_->status().error());
171 } else {
172 status->is_loading = false;
174 // TODO(darin): Populate more status fields.
175 callback.Run(status.Pass());
178 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request,
179 const net::RedirectInfo& redirect_info,
180 bool* defer_redirect) {
181 DCHECK(url_request == url_request_.get());
182 DCHECK(url_request->status().is_success());
184 if (auto_follow_redirects_)
185 return;
187 // Send the redirect response to the client, allowing them to inspect it and
188 // optionally follow the redirect.
189 *defer_redirect = true;
191 URLResponsePtr response = MakeURLResponse(url_request);
192 response->redirect_method = redirect_info.new_method;
193 response->redirect_url = String::From(redirect_info.new_url);
195 SendResponse(response.Pass());
198 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) {
199 DCHECK(url_request == url_request_.get());
201 if (!url_request->status().is_success()) {
202 SendError(url_request->status().error(), callback_);
203 callback_ = Callback<void(URLResponsePtr)>();
204 return;
207 // TODO(darin): Add support for optional MIME sniffing.
209 DataPipe data_pipe;
210 // TODO(darin): Honor given buffer size.
212 URLResponsePtr response = MakeURLResponse(url_request);
213 response->body = data_pipe.consumer_handle.Pass();
214 response_body_stream_ = data_pipe.producer_handle.Pass();
216 SendResponse(response.Pass());
218 // Start reading...
219 ReadMore();
222 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request,
223 int bytes_read) {
224 DCHECK(url_request == url_request_.get());
226 if (url_request->status().is_success()) {
227 DidRead(static_cast<uint32_t>(bytes_read), false);
228 } else {
229 pending_write_ = NULL; // This closes the data pipe.
233 void URLLoaderImpl::SendError(
234 int error_code,
235 const Callback<void(URLResponsePtr)>& callback) {
236 URLResponsePtr response(URLResponse::New());
237 if (url_request_)
238 response->url = String::From(url_request_->url());
239 response->error = MakeNetworkError(error_code);
240 callback.Run(response.Pass());
243 void URLLoaderImpl::SendResponse(URLResponsePtr response) {
244 Callback<void(URLResponsePtr)> callback;
245 std::swap(callback_, callback);
246 callback.Run(response.Pass());
249 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) {
250 // TODO(darin): Handle a bad |result| value.
251 ReadMore();
254 void URLLoaderImpl::ReadMore() {
255 DCHECK(!pending_write_.get());
257 uint32_t num_bytes;
258 MojoResult result = NetToMojoPendingBuffer::BeginWrite(
259 &response_body_stream_, &pending_write_, &num_bytes);
261 if (result == MOJO_RESULT_SHOULD_WAIT) {
262 // The pipe is full. We need to wait for it to have more space.
263 handle_watcher_.Start(response_body_stream_.get(),
264 MOJO_HANDLE_SIGNAL_WRITABLE,
265 MOJO_DEADLINE_INDEFINITE,
266 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady,
267 weak_ptr_factory_.GetWeakPtr()));
268 return;
269 } else if (result != MOJO_RESULT_OK) {
270 // The response body stream is in a bad state. Bail.
271 // TODO(darin): How should this be communicated to our client?
272 return;
274 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes);
276 scoped_refptr<net::IOBuffer> buf(new NetToMojoIOBuffer(pending_write_.get()));
278 int bytes_read;
279 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read);
280 if (url_request_->status().is_io_pending()) {
281 // Wait for OnReadCompleted.
282 } else if (url_request_->status().is_success() && bytes_read > 0) {
283 DidRead(static_cast<uint32_t>(bytes_read), true);
284 } else {
285 pending_write_->Complete(0);
286 pending_write_ = NULL; // This closes the data pipe.
290 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) {
291 DCHECK(url_request_->status().is_success());
293 response_body_stream_ = pending_write_->Complete(num_bytes);
294 pending_write_ = NULL;
296 if (completed_synchronously) {
297 base::MessageLoop::current()->PostTask(
298 FROM_HERE,
299 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr()));
300 } else {
301 ReadMore();
305 } // namespace mojo