OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "mojo/services/network/url_loader_impl.h" | 5 #include "mojo/services/network/url_loader_impl.h" |
6 | 6 |
7 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
8 #include "mojo/common/common_type_converters.h" | 8 #include "mojo/common/common_type_converters.h" |
9 #include "mojo/services/network/network_context.h" | 9 #include "mojo/services/network/network_context.h" |
10 #include "net/base/io_buffer.h" | 10 #include "net/base/io_buffer.h" |
(...skipping 28 matching lines...) Expand all Loading... | |
39 url_request->GetMimeType(&mime_type); | 39 url_request->GetMimeType(&mime_type); |
40 response->mime_type = mime_type; | 40 response->mime_type = mime_type; |
41 | 41 |
42 std::string charset; | 42 std::string charset; |
43 url_request->GetCharset(&charset); | 43 url_request->GetCharset(&charset); |
44 response->charset = charset; | 44 response->charset = charset; |
45 | 45 |
46 return response.Pass(); | 46 return response.Pass(); |
47 } | 47 } |
48 | 48 |
49 NetworkErrorPtr MakeNetworkError(int error_code) { | |
50 NetworkErrorPtr error = NetworkError::New(); | |
51 error->code = error_code; | |
52 error->description = net::ErrorToString(error_code); | |
53 return error.Pass(); | |
54 } | |
55 | |
49 } // namespace | 56 } // namespace |
50 | 57 |
51 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. | 58 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. |
52 class URLLoaderImpl::PendingWriteToDataPipe : | 59 class URLLoaderImpl::PendingWriteToDataPipe : |
53 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { | 60 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { |
54 public: | 61 public: |
55 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) | 62 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) |
56 : handle_(handle.Pass()), | 63 : handle_(handle.Pass()), |
57 buffer_(NULL) { | 64 buffer_(NULL) { |
58 } | 65 } |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 : net::WrappedIOBuffer(pending_write->buffer()), | 103 : net::WrappedIOBuffer(pending_write->buffer()), |
97 pending_write_(pending_write) { | 104 pending_write_(pending_write) { |
98 } | 105 } |
99 private: | 106 private: |
100 virtual ~DependentIOBuffer() {} | 107 virtual ~DependentIOBuffer() {} |
101 scoped_refptr<PendingWriteToDataPipe> pending_write_; | 108 scoped_refptr<PendingWriteToDataPipe> pending_write_; |
102 }; | 109 }; |
103 | 110 |
104 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) | 111 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) |
105 : context_(context), | 112 : context_(context), |
113 response_body_buffer_size_(0), | |
106 auto_follow_redirects_(true), | 114 auto_follow_redirects_(true), |
107 weak_ptr_factory_(this) { | 115 weak_ptr_factory_(this) { |
108 } | 116 } |
109 | 117 |
110 URLLoaderImpl::~URLLoaderImpl() { | 118 URLLoaderImpl::~URLLoaderImpl() { |
111 } | 119 } |
112 | 120 |
113 void URLLoaderImpl::OnConnectionError() { | 121 void URLLoaderImpl::OnConnectionError() { |
114 delete this; | 122 delete this; |
115 } | 123 } |
116 | 124 |
117 void URLLoaderImpl::Start(URLRequestPtr request, | 125 void URLLoaderImpl::Start(URLRequestPtr request, |
118 ScopedDataPipeProducerHandle response_body_stream) { | 126 const Callback<void(URLResponsePtr)>& callback) { |
119 // Do not allow starting another request. | |
120 if (url_request_) { | 127 if (url_request_) { |
121 SendError(net::ERR_UNEXPECTED); | 128 SendError(net::ERR_UNEXPECTED, callback); |
122 url_request_.reset(); | |
123 response_body_stream_.reset(); | |
124 return; | 129 return; |
125 } | 130 } |
126 | 131 |
127 if (!request) { | 132 if (!request) { |
128 SendError(net::ERR_INVALID_ARGUMENT); | 133 SendError(net::ERR_INVALID_ARGUMENT, callback); |
129 return; | 134 return; |
130 } | 135 } |
131 | 136 |
132 response_body_stream_ = response_body_stream.Pass(); | |
133 | |
134 GURL url(request->url); | |
135 url_request_.reset( | 137 url_request_.reset( |
136 new net::URLRequest(url, | 138 new net::URLRequest(GURL(request->url), |
137 net::DEFAULT_PRIORITY, | 139 net::DEFAULT_PRIORITY, |
138 this, | 140 this, |
139 context_->url_request_context())); | 141 context_->url_request_context())); |
140 url_request_->set_method(request->method); | 142 url_request_->set_method(request->method); |
141 if (request->headers) { | 143 if (request->headers) { |
142 net::HttpRequestHeaders headers; | 144 net::HttpRequestHeaders headers; |
143 for (size_t i = 0; i < request->headers.size(); ++i) | 145 for (size_t i = 0; i < request->headers.size(); ++i) |
144 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); | 146 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); |
145 url_request_->SetExtraRequestHeaders(headers); | 147 url_request_->SetExtraRequestHeaders(headers); |
146 } | 148 } |
147 if (request->bypass_cache) | 149 if (request->bypass_cache) |
148 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); | 150 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); |
149 // TODO(darin): Handle request body. | 151 // TODO(darin): Handle request body. |
150 | 152 |
153 callback_ = callback; | |
154 response_body_buffer_size_ = request->response_body_buffer_size; | |
151 auto_follow_redirects_ = request->auto_follow_redirects; | 155 auto_follow_redirects_ = request->auto_follow_redirects; |
152 | 156 |
153 url_request_->Start(); | 157 url_request_->Start(); |
154 } | 158 } |
155 | 159 |
156 void URLLoaderImpl::FollowRedirect() { | 160 void URLLoaderImpl::FollowRedirect( |
161 const Callback<void(URLResponsePtr)>& callback) { | |
162 if (!url_request_) { | |
163 SendError(net::ERR_UNEXPECTED, callback); | |
164 return; | |
165 } | |
166 | |
157 if (auto_follow_redirects_) { | 167 if (auto_follow_redirects_) { |
158 DLOG(ERROR) << "Spurious call to FollowRedirect"; | 168 DLOG(ERROR) << "Spurious call to FollowRedirect"; |
169 SendError(net::ERR_UNEXPECTED, callback); | |
170 return; | |
171 } | |
172 | |
173 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect. | |
174 url_request_->FollowDeferredRedirect(); | |
175 } | |
176 | |
177 void URLLoaderImpl::QueryStatus( | |
178 const Callback<void(URLLoaderStatusPtr)>& callback) { | |
179 URLLoaderStatusPtr status(URLLoaderStatus::New()); | |
180 if (url_request_) { | |
181 status->is_loading = url_request_->is_pending(); | |
182 if (!url_request_->status().is_success()) | |
183 status->error = MakeNetworkError(url_request_->status().error()); | |
159 } else { | 184 } else { |
160 if (url_request_) | 185 status->is_loading = false; |
161 url_request_->FollowDeferredRedirect(); | |
162 } | 186 } |
187 // TODO(darin): Populate more status fields. | |
188 callback.Run(status.Pass()); | |
163 } | 189 } |
164 | 190 |
165 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, | 191 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, |
166 const GURL& new_url, | 192 const GURL& new_url, |
167 bool* defer_redirect) { | 193 bool* defer_redirect) { |
168 DCHECK(url_request == url_request_.get()); | 194 DCHECK(url_request == url_request_.get()); |
169 DCHECK(url_request->status().is_success()); | 195 DCHECK(url_request->status().is_success()); |
170 | 196 |
197 if ((*defer_redirect = !auto_follow_redirects_)) | |
Aaron Boodman
2014/07/10 20:05:00
Do you need the extra parens?
| |
198 return; | |
199 | |
171 URLResponsePtr response = MakeURLResponse(url_request); | 200 URLResponsePtr response = MakeURLResponse(url_request); |
172 std::string redirect_method = | 201 response->redirect_method = |
173 net::URLRequest::ComputeMethodForRedirect(url_request->method(), | 202 net::URLRequest::ComputeMethodForRedirect(url_request->method(), |
174 response->status_code); | 203 response->status_code); |
175 client()->OnReceivedRedirect( | 204 response->redirect_url = new_url.spec(); |
176 response.Pass(), new_url.spec(), redirect_method); | |
177 | 205 |
178 *defer_redirect = !auto_follow_redirects_; | 206 SendResponse(response.Pass()); |
179 } | 207 } |
180 | 208 |
181 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { | 209 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { |
182 DCHECK(url_request == url_request_.get()); | 210 DCHECK(url_request == url_request_.get()); |
183 | 211 |
184 if (!url_request->status().is_success()) { | 212 if (!url_request->status().is_success()) { |
185 SendError(url_request->status().error()); | 213 SendError(url_request->status().error(), callback_); |
214 callback_ = Callback<void(URLResponsePtr)>(); | |
Aaron Boodman
2014/07/10 20:05:00
It looks like if an empty mojo::Callback gets Run(
| |
186 return; | 215 return; |
187 } | 216 } |
188 | 217 |
189 // TODO(darin): Add support for optional MIME sniffing. | 218 // TODO(darin): Add support for optional MIME sniffing. |
190 | 219 |
191 client()->OnReceivedResponse(MakeURLResponse(url_request)); | 220 DataPipe data_pipe; |
221 // TODO(darin): Honor given buffer size. | |
222 | |
223 URLResponsePtr response = MakeURLResponse(url_request); | |
224 response->body = data_pipe.consumer_handle.Pass(); | |
225 response_body_stream_ = data_pipe.producer_handle.Pass(); | |
226 | |
227 SendResponse(response.Pass()); | |
192 | 228 |
193 // Start reading... | 229 // Start reading... |
194 ReadMore(); | 230 ReadMore(); |
195 } | 231 } |
196 | 232 |
197 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, | 233 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, |
198 int bytes_read) { | 234 int bytes_read) { |
235 DCHECK(url_request == url_request_.get()); | |
236 | |
199 if (url_request->status().is_success()) { | 237 if (url_request->status().is_success()) { |
200 DidRead(static_cast<uint32_t>(bytes_read), false); | 238 DidRead(static_cast<uint32_t>(bytes_read), false); |
201 } else { | 239 } else { |
202 pending_write_ = NULL; // This closes the data pipe. | 240 pending_write_ = NULL; // This closes the data pipe. |
203 // TODO(darin): Perhaps we should communicate this error to our client. | |
204 } | 241 } |
205 } | 242 } |
206 | 243 |
207 void URLLoaderImpl::SendError(int error_code) { | 244 void URLLoaderImpl::SendError( |
208 NetworkErrorPtr error(NetworkError::New()); | 245 int error_code, |
209 error->code = error_code; | 246 const Callback<void(URLResponsePtr)>& callback) { |
210 error->description = net::ErrorToString(error_code); | 247 URLResponsePtr response(URLResponse::New()); |
211 client()->OnReceivedError(error.Pass()); | 248 if (url_request_) |
249 response->url = url_request_->url().spec(); | |
250 response->error = MakeNetworkError(error_code); | |
251 callback.Run(response.Pass()); | |
252 } | |
253 | |
254 void URLLoaderImpl::SendResponse(URLResponsePtr response) { | |
255 Callback<void(URLResponsePtr)> callback; | |
256 std::swap(callback_, callback); | |
257 callback.Run(response.Pass()); | |
212 } | 258 } |
213 | 259 |
214 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { | 260 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { |
215 // TODO(darin): Handle a bad |result| value. | 261 // TODO(darin): Handle a bad |result| value. |
216 ReadMore(); | 262 ReadMore(); |
217 } | 263 } |
218 | 264 |
219 void URLLoaderImpl::WaitToReadMore() { | 265 void URLLoaderImpl::WaitToReadMore() { |
220 handle_watcher_.Start(response_body_stream_.get(), | 266 handle_watcher_.Start(response_body_stream_.get(), |
221 MOJO_HANDLE_SIGNAL_WRITABLE, | 267 MOJO_HANDLE_SIGNAL_WRITABLE, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 // Drop our reference to the buffer. | 299 // Drop our reference to the buffer. |
254 buf = NULL; | 300 buf = NULL; |
255 | 301 |
256 if (url_request_->status().is_io_pending()) { | 302 if (url_request_->status().is_io_pending()) { |
257 // Wait for OnReadCompleted. | 303 // Wait for OnReadCompleted. |
258 } else if (url_request_->status().is_success() && bytes_read > 0) { | 304 } else if (url_request_->status().is_success() && bytes_read > 0) { |
259 DidRead(static_cast<uint32_t>(bytes_read), true); | 305 DidRead(static_cast<uint32_t>(bytes_read), true); |
260 } else { | 306 } else { |
261 pending_write_->Complete(0); | 307 pending_write_->Complete(0); |
262 pending_write_ = NULL; // This closes the data pipe. | 308 pending_write_ = NULL; // This closes the data pipe. |
263 if (bytes_read == 0) { | 309 DCHECK(bytes_read == 0 || !url_request_->status().is_success()); |
Aaron Boodman
2014/07/10 20:05:00
Nit: Recommend separate DCHECKs so that you can se
| |
264 client()->OnReceivedEndOfResponseBody(); | |
265 } else { | |
266 DCHECK(!url_request_->status().is_success()); | |
267 SendError(url_request_->status().error()); | |
268 } | |
269 } | 310 } |
270 } | 311 } |
271 | 312 |
272 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { | 313 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { |
273 DCHECK(url_request_->status().is_success()); | 314 DCHECK(url_request_->status().is_success()); |
274 | 315 |
275 response_body_stream_ = pending_write_->Complete(num_bytes); | 316 response_body_stream_ = pending_write_->Complete(num_bytes); |
276 pending_write_ = NULL; | 317 pending_write_ = NULL; |
277 | 318 |
278 if (completed_synchronously) { | 319 if (completed_synchronously) { |
279 base::MessageLoop::current()->PostTask( | 320 base::MessageLoop::current()->PostTask( |
280 FROM_HERE, | 321 FROM_HERE, |
281 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); | 322 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); |
282 } else { | 323 } else { |
283 ReadMore(); | 324 ReadMore(); |
284 } | 325 } |
285 } | 326 } |
286 | 327 |
287 } // namespace mojo | 328 } // namespace mojo |
OLD | NEW |