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 "mojo/common/common_type_converters.h" 8 #include "mojo/services/network/network_context.h" 9 #include "net/base/io_buffer.h" 10 #include "net/base/load_flags.h" 11 #include "net/http/http_response_headers.h" 12 13 namespace mojo { 14 namespace { 15 16 const uint32_t kMaxReadSize = 64 * 1024; 17 18 // Generates an URLResponsePtr from the response state of a net::URLRequest. 19 URLResponsePtr MakeURLResponse(const net::URLRequest* url_request) { 20 URLResponsePtr response(URLResponse::New()); 21 response->url = url_request->url().spec(); 22 23 const net::HttpResponseHeaders* headers = url_request->response_headers(); 24 if (headers) { 25 response->status_code = headers->response_code(); 26 response->status_line = headers->GetStatusLine(); 27 28 std::vector<String> header_lines; 29 void* iter = NULL; 30 std::string name, value; 31 while (headers->EnumerateHeaderLines(&iter, &name, &value)) 32 header_lines.push_back(name + ": " + value); 33 if (!header_lines.empty()) 34 response->headers.Swap(&header_lines); 35 } 36 37 return response.Pass(); 38 } 39 40 } // namespace 41 42 // Keeps track of a pending two-phase write on a DataPipeProducerHandle. 43 class URLLoaderImpl::PendingWriteToDataPipe : 44 public base::RefCountedThreadSafe<PendingWriteToDataPipe> { 45 public: 46 explicit PendingWriteToDataPipe(ScopedDataPipeProducerHandle handle) 47 : handle_(handle.Pass()), 48 buffer_(NULL) { 49 } 50 51 bool BeginWrite(uint32_t* num_bytes) { 52 MojoResult result = BeginWriteDataRaw(handle_.get(), &buffer_, num_bytes, 53 MOJO_WRITE_DATA_FLAG_NONE); 54 if (*num_bytes > kMaxReadSize) 55 *num_bytes = kMaxReadSize; 56 57 return result == MOJO_RESULT_OK; 58 } 59 60 ScopedDataPipeProducerHandle Complete(uint32_t num_bytes) { 61 EndWriteDataRaw(handle_.get(), num_bytes); 62 buffer_ = NULL; 63 return handle_.Pass(); 64 } 65 66 char* buffer() { return static_cast<char*>(buffer_); } 67 68 private: 69 friend class base::RefCountedThreadSafe<PendingWriteToDataPipe>; 70 71 ~PendingWriteToDataPipe() { 72 if (handle_.is_valid()) 73 EndWriteDataRaw(handle_.get(), 0); 74 } 75 76 ScopedDataPipeProducerHandle handle_; 77 void* buffer_; 78 79 DISALLOW_COPY_AND_ASSIGN(PendingWriteToDataPipe); 80 }; 81 82 // Takes ownership of a pending two-phase write on a DataPipeProducerHandle, 83 // and makes its buffer available as a net::IOBuffer. 84 class URLLoaderImpl::DependentIOBuffer : public net::WrappedIOBuffer { 85 public: 86 DependentIOBuffer(PendingWriteToDataPipe* pending_write) 87 : net::WrappedIOBuffer(pending_write->buffer()), 88 pending_write_(pending_write) { 89 } 90 private: 91 virtual ~DependentIOBuffer() {} 92 scoped_refptr<PendingWriteToDataPipe> pending_write_; 93 }; 94 95 URLLoaderImpl::URLLoaderImpl(NetworkContext* context) 96 : context_(context), 97 auto_follow_redirects_(true), 98 weak_ptr_factory_(this) { 99 } 100 101 URLLoaderImpl::~URLLoaderImpl() { 102 } 103 104 void URLLoaderImpl::OnConnectionError() { 105 delete this; 106 } 107 108 void URLLoaderImpl::Start(URLRequestPtr request, 109 ScopedDataPipeProducerHandle response_body_stream) { 110 // Do not allow starting another request. 111 if (url_request_) { 112 SendError(net::ERR_UNEXPECTED); 113 url_request_.reset(); 114 response_body_stream_.reset(); 115 return; 116 } 117 118 if (!request) { 119 SendError(net::ERR_INVALID_ARGUMENT); 120 return; 121 } 122 123 response_body_stream_ = response_body_stream.Pass(); 124 125 GURL url(request->url); 126 url_request_.reset( 127 new net::URLRequest(url, 128 net::DEFAULT_PRIORITY, 129 this, 130 context_->url_request_context())); 131 url_request_->set_method(request->method); 132 if (request->headers) { 133 net::HttpRequestHeaders headers; 134 for (size_t i = 0; i < request->headers.size(); ++i) 135 headers.AddHeaderFromString(request->headers[i].To<base::StringPiece>()); 136 url_request_->SetExtraRequestHeaders(headers); 137 } 138 if (request->bypass_cache) 139 url_request_->SetLoadFlags(net::LOAD_BYPASS_CACHE); 140 // TODO(darin): Handle request body. 141 142 auto_follow_redirects_ = request->auto_follow_redirects; 143 144 url_request_->Start(); 145 } 146 147 void URLLoaderImpl::FollowRedirect() { 148 if (auto_follow_redirects_) { 149 DLOG(ERROR) << "Spurious call to FollowRedirect"; 150 } else { 151 if (url_request_) 152 url_request_->FollowDeferredRedirect(); 153 } 154 } 155 156 void URLLoaderImpl::OnReceivedRedirect(net::URLRequest* url_request, 157 const GURL& new_url, 158 bool* defer_redirect) { 159 DCHECK(url_request == url_request_.get()); 160 DCHECK(url_request->status().is_success()); 161 162 URLResponsePtr response = MakeURLResponse(url_request); 163 std::string redirect_method = 164 net::URLRequest::ComputeMethodForRedirect(url_request->method(), 165 response->status_code); 166 client()->OnReceivedRedirect( 167 response.Pass(), new_url.spec(), redirect_method); 168 169 *defer_redirect = !auto_follow_redirects_; 170 } 171 172 void URLLoaderImpl::OnResponseStarted(net::URLRequest* url_request) { 173 DCHECK(url_request == url_request_.get()); 174 175 if (!url_request->status().is_success()) { 176 SendError(url_request->status().error()); 177 return; 178 } 179 180 client()->OnReceivedResponse(MakeURLResponse(url_request)); 181 182 // Start reading... 183 ReadMore(); 184 } 185 186 void URLLoaderImpl::OnReadCompleted(net::URLRequest* url_request, 187 int bytes_read) { 188 if (url_request->status().is_success()) { 189 DidRead(static_cast<uint32_t>(bytes_read), false); 190 } else { 191 pending_write_ = NULL; // This closes the data pipe. 192 // TODO(darin): Perhaps we should communicate this error to our client. 193 } 194 } 195 196 void URLLoaderImpl::SendError(int error_code) { 197 NetworkErrorPtr error(NetworkError::New()); 198 error->code = error_code; 199 error->description = net::ErrorToString(error_code); 200 client()->OnReceivedError(error.Pass()); 201 } 202 203 void URLLoaderImpl::ReadMore() { 204 DCHECK(!pending_write_); 205 206 pending_write_ = new PendingWriteToDataPipe(response_body_stream_.Pass()); 207 208 uint32_t num_bytes; 209 if (!pending_write_->BeginWrite(&num_bytes)) 210 CHECK(false); // Oops! TODO(darin): crbug/386877: The pipe might be full! 211 if (num_bytes > static_cast<uint32_t>(std::numeric_limits<int>::max())) 212 CHECK(false); // Oops! 213 214 scoped_refptr<net::IOBuffer> buf = new DependentIOBuffer(pending_write_); 215 216 int bytes_read; 217 url_request_->Read(buf, static_cast<int>(num_bytes), &bytes_read); 218 219 // Drop our reference to the buffer. 220 buf = NULL; 221 222 if (url_request_->status().is_io_pending()) { 223 // Wait for OnReadCompleted. 224 } else if (url_request_->status().is_success() && bytes_read > 0) { 225 DidRead(static_cast<uint32_t>(bytes_read), true); 226 } else { 227 pending_write_->Complete(0); 228 pending_write_ = NULL; // This closes the data pipe. 229 if (bytes_read == 0) { 230 client()->OnReceivedEndOfResponseBody(); 231 } else { 232 DCHECK(!url_request_->status().is_success()); 233 SendError(url_request_->status().error()); 234 } 235 } 236 } 237 238 void URLLoaderImpl::DidRead(uint32_t num_bytes, bool completed_synchronously) { 239 DCHECK(url_request_->status().is_success()); 240 241 response_body_stream_ = pending_write_->Complete(num_bytes); 242 pending_write_ = NULL; 243 244 if (completed_synchronously) { 245 base::MessageLoop::current()->PostTask( 246 FROM_HERE, 247 base::Bind(&URLLoaderImpl::ReadMore, weak_ptr_factory_.GetWeakPtr())); 248 } else { 249 ReadMore(); 250 } 251 } 252 253 } // namespace mojo 254