OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "android_webview/browser/net/android_stream_reader_url_request_job.h" | 5 #include "android_webview/browser/net/android_stream_reader_url_request_job.h" |
6 | 6 |
| 7 #include <string> |
| 8 |
7 #include "android_webview/browser/input_stream.h" | 9 #include "android_webview/browser/input_stream.h" |
8 #include "android_webview/browser/net/input_stream_reader.h" | 10 #include "android_webview/browser/net/input_stream_reader.h" |
9 #include "base/android/jni_android.h" | 11 #include "base/android/jni_android.h" |
10 #include "base/android/jni_string.h" | 12 #include "base/android/jni_string.h" |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
13 #include "base/lazy_instance.h" | 15 #include "base/lazy_instance.h" |
14 #include "base/message_loop.h" | 16 #include "base/message_loop.h" |
15 #include "base/message_loop_proxy.h" | 17 #include "base/message_loop_proxy.h" |
| 18 #include "base/strings/string_number_conversions.h" |
16 #include "base/task_runner.h" | 19 #include "base/task_runner.h" |
17 #include "base/threading/sequenced_worker_pool.h" | 20 #include "base/threading/sequenced_worker_pool.h" |
18 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
19 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
20 #include "net/base/io_buffer.h" | 23 #include "net/base/io_buffer.h" |
21 #include "net/base/mime_util.h" | 24 #include "net/base/mime_util.h" |
22 #include "net/base/net_errors.h" | 25 #include "net/base/net_errors.h" |
23 #include "net/base/net_util.h" | 26 #include "net/base/net_util.h" |
| 27 #include "net/http/http_response_headers.h" |
| 28 #include "net/http/http_response_info.h" |
24 #include "net/http/http_util.h" | 29 #include "net/http/http_util.h" |
25 #include "net/url_request/url_request.h" | 30 #include "net/url_request/url_request.h" |
26 #include "net/url_request/url_request_job_manager.h" | 31 #include "net/url_request/url_request_job_manager.h" |
27 | 32 |
28 using android_webview::InputStream; | 33 using android_webview::InputStream; |
29 using android_webview::InputStreamReader; | 34 using android_webview::InputStreamReader; |
30 using base::android::AttachCurrentThread; | 35 using base::android::AttachCurrentThread; |
31 using base::PostTaskAndReplyWithResult; | 36 using base::PostTaskAndReplyWithResult; |
32 using content::BrowserThread; | 37 using content::BrowserThread; |
33 | 38 |
| 39 namespace { |
| 40 |
| 41 const int kHTTPOk = 200; |
| 42 const int kHTTPNotFound = 404; |
| 43 |
| 44 const char kHTTPOkText[] = "OK"; |
| 45 const char kHTTPNotFoundText[] = "Not Found"; |
| 46 |
| 47 } // namespace |
| 48 |
34 // The requests posted to the worker thread might outlive the job. Thread-safe | 49 // The requests posted to the worker thread might outlive the job. Thread-safe |
35 // ref counting is used to ensure that the InputStream and InputStreamReader | 50 // ref counting is used to ensure that the InputStream and InputStreamReader |
36 // members of this class are still there when the closure is run on the worker | 51 // members of this class are still there when the closure is run on the worker |
37 // thread. | 52 // thread. |
38 class InputStreamReaderWrapper : | 53 class InputStreamReaderWrapper : |
39 public base::RefCountedThreadSafe<InputStreamReaderWrapper> { | 54 public base::RefCountedThreadSafe<InputStreamReaderWrapper> { |
40 public: | 55 public: |
41 InputStreamReaderWrapper( | 56 InputStreamReaderWrapper( |
42 scoped_ptr<InputStream> input_stream, | 57 scoped_ptr<InputStream> input_stream, |
43 scoped_ptr<InputStreamReader> input_stream_reader) | 58 scoped_ptr<InputStreamReader> input_stream_reader) |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 DCHECK(thread_checker_.CalledOnValidThread()); | 163 DCHECK(thread_checker_.CalledOnValidThread()); |
149 DCHECK(returned_delegate); | 164 DCHECK(returned_delegate); |
150 delegate_ = returned_delegate.Pass(); | 165 delegate_ = returned_delegate.Pass(); |
151 | 166 |
152 if (!input_stream) { | 167 if (!input_stream) { |
153 bool restart_required = false; | 168 bool restart_required = false; |
154 delegate_->OnInputStreamOpenFailed(request(), &restart_required); | 169 delegate_->OnInputStreamOpenFailed(request(), &restart_required); |
155 if (restart_required) { | 170 if (restart_required) { |
156 NotifyRestartRequired(); | 171 NotifyRestartRequired(); |
157 } else { | 172 } else { |
158 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 173 // Clear the IO_PENDING status set in Start(). |
159 net::ERR_FAILED)); | 174 SetStatus(net::URLRequestStatus()); |
| 175 HeadersComplete(kHTTPNotFound, kHTTPNotFoundText); |
160 } | 176 } |
161 return; | 177 return; |
162 } | 178 } |
163 | 179 |
164 scoped_ptr<InputStreamReader> input_stream_reader( | 180 scoped_ptr<InputStreamReader> input_stream_reader( |
165 CreateStreamReader(input_stream.get())); | 181 CreateStreamReader(input_stream.get())); |
166 DCHECK(input_stream_reader); | 182 DCHECK(input_stream_reader); |
167 | 183 |
168 DCHECK(!input_stream_reader_wrapper_); | 184 DCHECK(!input_stream_reader_wrapper_); |
169 input_stream_reader_wrapper_ = new InputStreamReaderWrapper( | 185 input_stream_reader_wrapper_ = new InputStreamReaderWrapper( |
170 input_stream.Pass(), input_stream_reader.Pass()); | 186 input_stream.Pass(), input_stream_reader.Pass()); |
171 | 187 |
172 PostTaskAndReplyWithResult( | 188 PostTaskAndReplyWithResult( |
173 GetWorkerThreadRunner(), | 189 GetWorkerThreadRunner(), |
174 FROM_HERE, | 190 FROM_HERE, |
175 base::Bind(&InputStreamReaderWrapper::Seek, | 191 base::Bind(&InputStreamReaderWrapper::Seek, |
176 input_stream_reader_wrapper_, | 192 input_stream_reader_wrapper_, |
177 byte_range_), | 193 byte_range_), |
178 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, | 194 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, |
179 weak_factory_.GetWeakPtr())); | 195 weak_factory_.GetWeakPtr())); |
180 } | 196 } |
181 | 197 |
182 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { | 198 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { |
183 DCHECK(thread_checker_.CalledOnValidThread()); | 199 DCHECK(thread_checker_.CalledOnValidThread()); |
184 // Clear the IO_PENDING status set in Start(). | 200 // Clear the IO_PENDING status set in Start(). |
185 SetStatus(net::URLRequestStatus()); | 201 SetStatus(net::URLRequestStatus()); |
186 if (result >= 0) { | 202 if (result >= 0) { |
187 set_expected_content_size(result); | 203 set_expected_content_size(result); |
188 NotifyHeadersComplete(); | 204 HeadersComplete(kHTTPOk, kHTTPOkText); |
189 } else { | 205 } else { |
190 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 206 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
191 } | 207 } |
192 } | 208 } |
193 | 209 |
194 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { | 210 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { |
195 DCHECK(thread_checker_.CalledOnValidThread()); | 211 DCHECK(thread_checker_.CalledOnValidThread()); |
196 // The URLRequest API contract requires that: | 212 // The URLRequest API contract requires that: |
197 // * NotifyDone be called once, to set the status code, indicate the job is | 213 // * NotifyDone be called once, to set the status code, indicate the job is |
198 // finished (there will be no further IO), | 214 // finished (there will be no further IO), |
(...skipping 14 matching lines...) Expand all Loading... |
213 } | 229 } |
214 | 230 |
215 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { | 231 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { |
216 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); | 232 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); |
217 } | 233 } |
218 | 234 |
219 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, | 235 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, |
220 int dest_size, | 236 int dest_size, |
221 int* bytes_read) { | 237 int* bytes_read) { |
222 DCHECK(thread_checker_.CalledOnValidThread()); | 238 DCHECK(thread_checker_.CalledOnValidThread()); |
223 DCHECK(input_stream_reader_wrapper_); | 239 if (!input_stream_reader_wrapper_) { |
| 240 // This will happen if opening the InputStream fails in which case the |
| 241 // error is communicated by setting the HTTP response status header rather |
| 242 // than failing the request during the header fetch phase. |
| 243 *bytes_read = 0; |
| 244 return true; |
| 245 } |
224 | 246 |
225 PostTaskAndReplyWithResult( | 247 PostTaskAndReplyWithResult( |
226 GetWorkerThreadRunner(), | 248 GetWorkerThreadRunner(), |
227 FROM_HERE, | 249 FROM_HERE, |
228 base::Bind(&InputStreamReaderWrapper::ReadRawData, | 250 base::Bind(&InputStreamReaderWrapper::ReadRawData, |
229 input_stream_reader_wrapper_, | 251 input_stream_reader_wrapper_, |
230 make_scoped_refptr(dest), | 252 make_scoped_refptr(dest), |
231 dest_size), | 253 dest_size), |
232 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, | 254 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, |
233 weak_factory_.GetWeakPtr())); | 255 weak_factory_.GetWeakPtr())); |
(...skipping 29 matching lines...) Expand all Loading... |
263 return false; | 285 return false; |
264 | 286 |
265 // Since it's possible for this call to alter the InputStream a | 287 // Since it's possible for this call to alter the InputStream a |
266 // Seek or ReadRawData operation running in the background is not permitted. | 288 // Seek or ReadRawData operation running in the background is not permitted. |
267 DCHECK(!request_->status().is_io_pending()); | 289 DCHECK(!request_->status().is_io_pending()); |
268 | 290 |
269 return delegate_->GetCharset( | 291 return delegate_->GetCharset( |
270 env, request(), input_stream_reader_wrapper_->input_stream(), charset); | 292 env, request(), input_stream_reader_wrapper_->input_stream(), charset); |
271 } | 293 } |
272 | 294 |
| 295 void AndroidStreamReaderURLRequestJob::HeadersComplete( |
| 296 int status_code, |
| 297 const std::string& status_text) { |
| 298 std::string status("HTTP/1.1 "); |
| 299 status.append(base::IntToString(status_code)); |
| 300 status.append(" "); |
| 301 status.append(status_text); |
| 302 // HttpResponseHeaders expects its input string to be terminated by two NULs. |
| 303 status.append("\0\0", 2); |
| 304 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status); |
| 305 |
| 306 if (status_code == kHTTPOk) { |
| 307 if (expected_content_size() != -1) { |
| 308 std::string content_length_header( |
| 309 net::HttpRequestHeaders::kContentLength); |
| 310 content_length_header.append(": "); |
| 311 content_length_header.append( |
| 312 base::Int64ToString(expected_content_size())); |
| 313 headers->AddHeader(content_length_header); |
| 314 } |
| 315 |
| 316 std::string mime_type; |
| 317 if (GetMimeType(&mime_type) && !mime_type.empty()) { |
| 318 std::string content_type_header(net::HttpRequestHeaders::kContentType); |
| 319 content_type_header.append(": "); |
| 320 content_type_header.append(mime_type); |
| 321 headers->AddHeader(content_type_header); |
| 322 } |
| 323 } |
| 324 |
| 325 response_info_.reset(new net::HttpResponseInfo()); |
| 326 response_info_->headers = headers; |
| 327 |
| 328 NotifyHeadersComplete(); |
| 329 } |
| 330 |
| 331 int AndroidStreamReaderURLRequestJob::GetResponseCode() const { |
| 332 if (response_info_) |
| 333 return response_info_->headers->response_code(); |
| 334 return URLRequestJob::GetResponseCode(); |
| 335 } |
| 336 |
| 337 void AndroidStreamReaderURLRequestJob::GetResponseInfo( |
| 338 net::HttpResponseInfo* info) { |
| 339 if (response_info_) |
| 340 *info = *response_info_; |
| 341 } |
| 342 |
273 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( | 343 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( |
274 const net::HttpRequestHeaders& headers) { | 344 const net::HttpRequestHeaders& headers) { |
275 std::string range_header; | 345 std::string range_header; |
276 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { | 346 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { |
277 // We only extract the "Range" header so that we know how many bytes in the | 347 // We only extract the "Range" header so that we know how many bytes in the |
278 // stream to skip and how many to read after that. | 348 // stream to skip and how many to read after that. |
279 std::vector<net::HttpByteRange> ranges; | 349 std::vector<net::HttpByteRange> ranges; |
280 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { | 350 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { |
281 if (ranges.size() == 1) { | 351 if (ranges.size() == 1) { |
282 byte_range_ = ranges[0]; | 352 byte_range_ = ranges[0]; |
283 } else { | 353 } else { |
284 // We don't support multiple range requests in one single URL request, | 354 // We don't support multiple range requests in one single URL request, |
285 // because we need to do multipart encoding here. | 355 // because we need to do multipart encoding here. |
286 NotifyDone(net::URLRequestStatus( | 356 NotifyDone(net::URLRequestStatus( |
287 net::URLRequestStatus::FAILED, | 357 net::URLRequestStatus::FAILED, |
288 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 358 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
289 } | 359 } |
290 } | 360 } |
291 } | 361 } |
292 } | 362 } |
OLD | NEW |