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. 4 5 #include "mojo/services/network/url_loader_impl.h" 6 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/network_context.h" 11 #include "net/base/io_buffer.h" 12 #include "net/base/load_flags.h" 13 #include "net/base/upload_bytes_element_reader.h" 14 #include "net/base/upload_data_stream.h" 15 #include "net/http/http_response_headers.h" 16 #include "net/url_request/redirect_info.h" 17 #include "net/url_request/url_request_context.h" 18 19 namespace mojo { 20 namespace { 21 22 const uint32_t kMaxReadSize = 64 * 1024; 23 24 // Generates an URLResponsePtr from the response state of a net::URLRequest. 25 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) { 26 URLResponsePtr response(URLResponse::New()); 27 response->url = String::From(url_request->url()); 28 29 const net::HttpResponseHeaders* headers = url_request->response_headers(); 30 if (headers) { 31 response->status_code = headers->response_code(); 32 response->status_line = headers->GetStatusLine(); 33 34 std::vector<String> header_lines; 35 void* iter = NULL; 36 std::string name, value; 37 while (headers->EnumerateHeaderLines(&iter, &name, &value)) 38 header_lines.push_back(name + ": " + value); 39 if (!header_lines.empty()) 40 response->headers.Swap(&header_lines); 41 } 42 43 std::string mime_type; 44 url_request->GetMimeType(&mime_type); 45 response->mime_type = mime_type; 46 47 std::string charset; 48 url_request->GetCharset(&charset); 49 response->charset = charset; 50 51 return response.Pass(); 52 } 53 54 NetworkErrorPtr MakeNetworkError(int error_code) { 55 NetworkErrorPtr error = NetworkError::New(); 56 error->code = error_code; 57 error->description = net::ErrorToString(error_code); 58 return error.Pass(); 59 } 60 61 // Reads the request body upload data from a DataPipe. 62 class UploadDataPipeElementReader : public net::UploadElementReader { 63 public: 64 UploadDataPipeElementReader(ScopedDataPipeConsumerHandle pipe) 65 : pipe_(pipe.Pass()), num_bytes_(0) {} 66 virtual ~UploadDataPipeElementReader() {} 67 68 // UploadElementReader overrides: 69 virtual int Init(const net::CompletionCallback& callback) OVERRIDE { 70 offset_ = 0; 71 ReadDataRaw(pipe_.get(), NULL, &num_bytes_, MOJO_READ_DATA_FLAG_QUERY); 72 return net::OK; 73 } 74 virtual uint64 GetContentLength() const OVERRIDE { 75 return num_bytes_; 76 } 77 virtual uint64 BytesRemaining() const OVERRIDE { 78 return num_bytes_ - offset_; 79 } 80 virtual bool IsInMemory() const OVERRIDE { 81 return false; 82 } 83 virtual int Read(net::IOBuffer* buf, 84 int buf_length, 85 const net::CompletionCallback& callback) OVERRIDE { 86 uint32_t bytes_read = 87 std::min(static_cast<uint32_t>(BytesRemaining()), 88 static_cast<uint32_t>(buf_length)); 89 if (bytes_read > 0) { 90 ReadDataRaw(pipe_.get(), buf->data(), &bytes_read, 91 MOJO_READ_DATA_FLAG_NONE); 92 } 93 94 offset_ += bytes_read; 95 return bytes_read; 96 } 97 98 private: 99 ScopedDataPipeConsumerHandle pipe_; 100 uint32_t num_bytes_; 101 uint32_t offset_; 102 103 DISALLOW_COPY_AND_ASSIGN(UploadDataPipeElementReader); 104 }; 105 106 } // namespace 107 108 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. 109 class URLLoaderImpl::PendingWriteToDataPipe : 110 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { 111 public: 112 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) 113 : handle_(handle.Pass()), 114 buffer_(NULL) { 115 } 116 117 MojoResult BeginWrite(uint32_t* num_bytes) { 118 MojoResult result = BeginWriteDataRaw(handle_.get(), &buffer_, num_bytes, 119 MOJO_WRITE_DATA_FLAG_NONE); 120 if (*num_bytes > kMaxReadSize) 121 *num_bytes = kMaxReadSize; 122 123 return result; 124 } 125 126 ScopedDataPipeProducerHandle Complete(uint32_t num_bytes) { 127 EndWriteDataRaw(handle_.get(), num_bytes); 128 buffer_ = NULL; 129 return handle_.Pass(); 130 } 131 132 char* buffer() { return static_cast<char*>(buffer_); } 133 134 private: 135 friend class base::RefCountedThreadSafe<PendingWriteToDataPipe>; 136 137 ~PendingWriteToDataPipe() { 138 if (handle_.is_valid()) 139 EndWriteDataRaw(handle_.get(), 0); 140 } 141 142 ScopedDataPipeProducerHandle handle_; 143 void* buffer_; 144 145 DISALLOW_COPY_AND_ASSIGN(PendingWriteToDataPipe); 146 }; 147 148 // Takes ownership of a pending two-phase write on a DataPipeProducerHandle, 149 // and makes its buffer available as a net::IOBuffer. 150 class URLLoaderImpl::DependentIOBuffer : public net::WrappedIOBuffer { 151 public: 152 DependentIOBuffer(PendingWriteToDataPipe* pending_write) 153 : net::WrappedIOBuffer(pending_write->buffer()), 154 pending_write_(pending_write) { 155 } 156 private: 157 virtual ~DependentIOBuffer() {} 158 scoped_refptr<PendingWriteToDataPipe> pending_write_; 159 }; 160 161 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) 162 : context_(context), 163 response_body_buffer_size_(0), 164 auto_follow_redirects_(true), 165 weak_ptr_factory_(this) { 166 } 167 168 URLLoaderImpl::~URLLoaderImpl() { 169 } 170 171 void URLLoaderImpl::Start(URLRequestPtr request, 172 const Callback<void(URLResponsePtr)>& callback) { 173 if (url_request_) { 174 SendError(net::ERR_UNEXPECTED, callback); 175 return; 176 } 177 178 if (!request) { 179 SendError(net::ERR_INVALID_ARGUMENT, callback); 180 return; 181 } 182 183 url_request_ = context_->url_request_context()->CreateRequest( 184 GURL(request->url), 185 net::DEFAULT_PRIORITY, 186 this, 187 NULL); 188 url_request_->set_method(request->method); 189 if (request->headers) { 190 net::HttpRequestHeaders headers; 191 for (size_t i = 0; i < request->headers.size(); ++i) 192 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); 193 url_request_->SetExtraRequestHeaders(headers); 194 } 195 if (request->body) { 196 ScopedVector<net::UploadElementReader> element_readers; 197 for (size_t i = 0; i < request->body.size(); ++i) { 198 element_readers.push_back( 199 new UploadDataPipeElementReader(request->body[i].Pass())); 200 } 201 url_request_->set_upload(make_scoped_ptr( 202 new net::UploadDataStream(element_readers.Pass(), 0))); 203 } 204 if (request->bypass_cache) 205 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); 206 207 callback_ = callback; 208 response_body_buffer_size_ = request->response_body_buffer_size; 209 auto_follow_redirects_ = request->auto_follow_redirects; 210 211 url_request_->Start(); 212 } 213 214 void URLLoaderImpl::FollowRedirect( 215 const Callback<void(URLResponsePtr)>& callback) { 216 if (!url_request_) { 217 SendError(net::ERR_UNEXPECTED, callback); 218 return; 219 } 220 221 if (auto_follow_redirects_) { 222 DLOG(ERROR) << "Spurious call to FollowRedirect"; 223 SendError(net::ERR_UNEXPECTED, callback); 224 return; 225 } 226 227 // TODO(darin): Verify that it makes sense to call FollowDeferredRedirect. 228 url_request_->FollowDeferredRedirect(); 229 } 230 231 void URLLoaderImpl::QueryStatus( 232 const Callback<void(URLLoaderStatusPtr)>& callback) { 233 URLLoaderStatusPtr status(URLLoaderStatus::New()); 234 if (url_request_) { 235 status->is_loading = url_request_->is_pending(); 236 if (!url_request_->status().is_success()) 237 status->error = MakeNetworkError(url_request_->status().error()); 238 } else { 239 status->is_loading = false; 240 } 241 // TODO(darin): Populate more status fields. 242 callback.Run(status.Pass()); 243 } 244 245 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, 246 const net::RedirectInfo& redirect_info, 247 bool* defer_redirect) { 248 DCHECK(url_request == url_request_.get()); 249 DCHECK(url_request->status().is_success()); 250 251 if (auto_follow_redirects_) 252 return; 253 254 // Send the redirect response to the client, allowing them to inspect it and 255 // optionally follow the redirect. 256 *defer_redirect = true; 257 258 URLResponsePtr response = MakeURLResponse(url_request); 259 response->redirect_method = redirect_info.new_method; 260 response->redirect_url = String::From(redirect_info.new_url); 261 262 SendResponse(response.Pass()); 263 } 264 265 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { 266 DCHECK(url_request == url_request_.get()); 267 268 if (!url_request->status().is_success()) { 269 SendError(url_request->status().error(), callback_); 270 callback_ = Callback<void(URLResponsePtr)>(); 271 return; 272 } 273 274 // TODO(darin): Add support for optional MIME sniffing. 275 276 DataPipe data_pipe; 277 // TODO(darin): Honor given buffer size. 278 279 URLResponsePtr response = MakeURLResponse(url_request); 280 response->body = data_pipe.consumer_handle.Pass(); 281 response_body_stream_ = data_pipe.producer_handle.Pass(); 282 283 SendResponse(response.Pass()); 284 285 // Start reading... 286 ReadMore(); 287 } 288 289 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, 290 int bytes_read) { 291 DCHECK(url_request == url_request_.get()); 292 293 if (url_request->status().is_success()) { 294 DidRead(static_cast<uint32_t>(bytes_read), false); 295 } else { 296 pending_write_ = NULL; // This closes the data pipe. 297 } 298 } 299 300 void URLLoaderImpl::SendError( 301 int error_code, 302 const Callback<void(URLResponsePtr)>& callback) { 303 URLResponsePtr response(URLResponse::New()); 304 if (url_request_) 305 response->url = String::From(url_request_->url()); 306 response->error = MakeNetworkError(error_code); 307 callback.Run(response.Pass()); 308 } 309 310 void URLLoaderImpl::SendResponse(URLResponsePtr response) { 311 Callback<void(URLResponsePtr)> callback; 312 std::swap(callback_, callback); 313 callback.Run(response.Pass()); 314 } 315 316 void URLLoaderImpl::OnResponseBodyStreamReady(MojoResult result) { 317 // TODO(darin): Handle a bad |result| value. 318 ReadMore(); 319 } 320 321 void URLLoaderImpl::WaitToReadMore() { 322 handle_watcher_.Start(response_body_stream_.get(), 323 MOJO_HANDLE_SIGNAL_WRITABLE, 324 MOJO_DEADLINE_INDEFINITE, 325 base::Bind(&URLLoaderImpl::OnResponseBodyStreamReady, 326 weak_ptr_factory_.GetWeakPtr())); 327 } 328 329 void URLLoaderImpl::ReadMore() { 330 DCHECK(!pending_write_.get()); 331 332 pending_write_ = new PendingWriteToDataPipe(response_body_stream_.Pass()); 333 334 uint32_t num_bytes; 335 MojoResult result = pending_write_->BeginWrite(&num_bytes); 336 if (result == MOJO_RESULT_SHOULD_WAIT) { 337 // The pipe is full. We need to wait for it to have more space. 338 response_body_stream_ = pending_write_->Complete(num_bytes); 339 pending_write_ = NULL; 340 WaitToReadMore(); 341 return; 342 } 343 if (result != MOJO_RESULT_OK) { 344 // The response body stream is in a bad state. Bail. 345 // TODO(darin): How should this be communicated to our client? 346 return; 347 } 348 CHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()), num_bytes); 349 350 scoped_refptr<net::IOBuffer> buf = 351 new DependentIOBuffer(pending_write_.get()); 352 353 int bytes_read; 354 url_request_->Read(buf.get(), static_cast<int>(num_bytes), &bytes_read); 355 356 // Drop our reference to the buffer. 357 buf = NULL; 358 359 if (url_request_->status().is_io_pending()) { 360 // Wait for OnReadCompleted. 361 } else if (url_request_->status().is_success() && bytes_read > 0) { 362 DidRead(static_cast<uint32_t>(bytes_read), true); 363 } else { 364 pending_write_->Complete(0); 365 pending_write_ = NULL; // This closes the data pipe. 366 } 367 } 368 369 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { 370 DCHECK(url_request_->status().is_success()); 371 372 response_body_stream_ = pending_write_->Complete(num_bytes); 373 pending_write_ = NULL; 374 375 if (completed_synchronously) { 376 base::MessageLoop::current()->PostTask( 377 FROM_HERE, 378 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); 379 } else { 380 ReadMore(); 381 } 382 } 383 384 } // namespace mojo 385