Chromium Code Reviews| 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" |
| 17 #include "base/strings/string_number_conversions.h" | |
| 15 #include "base/task_runner.h" | 18 #include "base/task_runner.h" |
| 16 #include "base/threading/sequenced_worker_pool.h" | 19 #include "base/threading/sequenced_worker_pool.h" |
| 17 #include "base/threading/thread.h" | 20 #include "base/threading/thread.h" |
| 18 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
| 19 #include "net/base/io_buffer.h" | 22 #include "net/base/io_buffer.h" |
| 20 #include "net/base/mime_util.h" | 23 #include "net/base/mime_util.h" |
| 21 #include "net/base/net_errors.h" | 24 #include "net/base/net_errors.h" |
| 22 #include "net/base/net_util.h" | 25 #include "net/base/net_util.h" |
| 26 #include "net/http/http_response_headers.h" | |
| 27 #include "net/http/http_response_info.h" | |
| 23 #include "net/http/http_util.h" | 28 #include "net/http/http_util.h" |
| 24 #include "net/url_request/url_request.h" | 29 #include "net/url_request/url_request.h" |
| 25 #include "net/url_request/url_request_job_manager.h" | 30 #include "net/url_request/url_request_job_manager.h" |
| 26 | 31 |
| 27 using android_webview::InputStream; | 32 using android_webview::InputStream; |
| 28 using android_webview::InputStreamReader; | 33 using android_webview::InputStreamReader; |
| 29 using base::android::AttachCurrentThread; | 34 using base::android::AttachCurrentThread; |
| 30 using base::PostTaskAndReplyWithResult; | 35 using base::PostTaskAndReplyWithResult; |
| 31 using content::BrowserThread; | 36 using content::BrowserThread; |
| 32 | 37 |
| 38 namespace { | |
| 39 | |
| 40 const int kHTTPOk = 200; | |
|
benm (inactive)
2013/03/06 17:05:11
these surely must be defined somewhere in chromium
mkosiba (inactive)
2013/03/07 18:52:01
yeath.. somewhere in uh.. drive_url_request_job. I
| |
| 41 const int kHTTPNotFound = 404; | |
| 42 | |
| 43 const char kHTTPOkText[] = "OK"; | |
| 44 const char kHTTPNotFoundText[] = "Not Found"; | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 33 // The requests posted to the worker thread might outlive the job. Thread-safe | 48 // The requests posted to the worker thread might outlive the job. Thread-safe |
| 34 // ref counting is used to ensure that the InputStream and InputStreamReader | 49 // ref counting is used to ensure that the InputStream and InputStreamReader |
| 35 // members of this class are still there when the closure is run on the worker | 50 // members of this class are still there when the closure is run on the worker |
| 36 // thread. | 51 // thread. |
| 37 class InputStreamReaderWrapper : | 52 class InputStreamReaderWrapper : |
| 38 public base::RefCountedThreadSafe<InputStreamReaderWrapper> { | 53 public base::RefCountedThreadSafe<InputStreamReaderWrapper> { |
| 39 public: | 54 public: |
| 40 InputStreamReaderWrapper( | 55 InputStreamReaderWrapper( |
| 41 scoped_ptr<InputStream> input_stream, | 56 scoped_ptr<InputStream> input_stream, |
| 42 scoped_ptr<InputStreamReader> input_stream_reader) | 57 scoped_ptr<InputStreamReader> input_stream_reader) |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 void AndroidStreamReaderURLRequestJob::StartAsync() { | 121 void AndroidStreamReaderURLRequestJob::StartAsync() { |
| 107 JNIEnv* env = AttachCurrentThread(); | 122 JNIEnv* env = AttachCurrentThread(); |
| 108 DCHECK(env); | 123 DCHECK(env); |
| 109 | 124 |
| 110 // This could be done in the InputStreamReader but would force more | 125 // This could be done in the InputStreamReader but would force more |
| 111 // complex synchronization in the delegate. | 126 // complex synchronization in the delegate. |
| 112 scoped_ptr<android_webview::InputStream> stream( | 127 scoped_ptr<android_webview::InputStream> stream( |
| 113 delegate_->OpenInputStream(env, request())); | 128 delegate_->OpenInputStream(env, request())); |
| 114 | 129 |
| 115 if (!stream) { | 130 if (!stream) { |
| 116 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 131 // Clear the IO_PENDING status set in Start(). |
| 117 net::ERR_FAILED)); | 132 SetStatus(net::URLRequestStatus()); |
| 133 HeadersComplete(kHTTPNotFound, kHTTPNotFoundText); | |
| 118 return; | 134 return; |
| 119 } | 135 } |
| 120 | 136 |
| 121 scoped_ptr<InputStreamReader> input_stream_reader( | 137 scoped_ptr<InputStreamReader> input_stream_reader( |
| 122 CreateStreamReader(stream.get())); | 138 CreateStreamReader(stream.get())); |
| 123 DCHECK(input_stream_reader); | 139 DCHECK(input_stream_reader); |
| 124 | 140 |
| 125 DCHECK(!input_stream_reader_wrapper_); | 141 DCHECK(!input_stream_reader_wrapper_); |
| 126 input_stream_reader_wrapper_ = | 142 input_stream_reader_wrapper_ = |
| 127 new InputStreamReaderWrapper(stream.Pass(), input_stream_reader.Pass()); | 143 new InputStreamReaderWrapper(stream.Pass(), input_stream_reader.Pass()); |
| 128 | 144 |
| 129 PostTaskAndReplyWithResult( | 145 PostTaskAndReplyWithResult( |
| 130 GetWorkerThreadRunner(), | 146 GetWorkerThreadRunner(), |
| 131 FROM_HERE, | 147 FROM_HERE, |
| 132 base::Bind(&InputStreamReaderWrapper::Seek, | 148 base::Bind(&InputStreamReaderWrapper::Seek, |
| 133 input_stream_reader_wrapper_, | 149 input_stream_reader_wrapper_, |
| 134 byte_range_), | 150 byte_range_), |
| 135 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, | 151 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, |
| 136 weak_factory_.GetWeakPtr())); | 152 weak_factory_.GetWeakPtr())); |
| 137 } | 153 } |
| 138 | 154 |
| 139 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { | 155 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { |
| 140 // Clear the IO_PENDING status set in Start(). | 156 // Clear the IO_PENDING status set in Start(). |
| 141 SetStatus(net::URLRequestStatus()); | 157 SetStatus(net::URLRequestStatus()); |
| 142 if (result >= 0) { | 158 if (result >= 0) { |
| 143 set_expected_content_size(result); | 159 set_expected_content_size(result); |
| 144 NotifyHeadersComplete(); | 160 HeadersComplete(kHTTPOk, kHTTPOkText); |
| 145 } else { | 161 } else { |
| 146 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 162 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
| 147 } | 163 } |
| 148 } | 164 } |
| 149 | 165 |
| 150 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { | 166 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { |
| 151 // The URLRequest API contract requires that: | 167 // The URLRequest API contract requires that: |
| 152 // * NotifyDone be called once, to set the status code, indicate the job is | 168 // * NotifyDone be called once, to set the status code, indicate the job is |
| 153 // finished (there will be no further IO), | 169 // finished (there will be no further IO), |
| 154 // * NotifyReadComplete be called if false is returned from ReadRawData to | 170 // * NotifyReadComplete be called if false is returned from ReadRawData to |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 167 NotifyReadComplete(result); | 183 NotifyReadComplete(result); |
| 168 } | 184 } |
| 169 | 185 |
| 170 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { | 186 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { |
| 171 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); | 187 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); |
| 172 } | 188 } |
| 173 | 189 |
| 174 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, | 190 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, |
| 175 int dest_size, | 191 int dest_size, |
| 176 int* bytes_read) { | 192 int* bytes_read) { |
| 177 DCHECK(input_stream_reader_wrapper_); | 193 if (!input_stream_reader_wrapper_) { |
| 194 // This will happen if opening the InputStream fails in which case the | |
| 195 // error is communicated by setting the HTTP response status header rather | |
| 196 // than failing the entire request. | |
| 197 *bytes_read = 0; | |
| 198 return true; | |
| 199 } | |
| 178 | 200 |
| 179 PostTaskAndReplyWithResult( | 201 PostTaskAndReplyWithResult( |
| 180 GetWorkerThreadRunner(), | 202 GetWorkerThreadRunner(), |
| 181 FROM_HERE, | 203 FROM_HERE, |
| 182 base::Bind(&InputStreamReaderWrapper::ReadRawData, | 204 base::Bind(&InputStreamReaderWrapper::ReadRawData, |
| 183 input_stream_reader_wrapper_, | 205 input_stream_reader_wrapper_, |
| 184 make_scoped_refptr(dest), | 206 make_scoped_refptr(dest), |
| 185 dest_size), | 207 dest_size), |
| 186 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, | 208 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, |
| 187 weak_factory_.GetWeakPtr())); | 209 weak_factory_.GetWeakPtr())); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 215 return false; | 237 return false; |
| 216 | 238 |
| 217 // Since it's possible for this call to alter the InputStream a | 239 // Since it's possible for this call to alter the InputStream a |
| 218 // Seek or ReadRawData operation running in the background is not permitted. | 240 // Seek or ReadRawData operation running in the background is not permitted. |
| 219 DCHECK(!request_->status().is_io_pending()); | 241 DCHECK(!request_->status().is_io_pending()); |
| 220 | 242 |
| 221 return delegate_->GetCharset( | 243 return delegate_->GetCharset( |
| 222 env, request(), input_stream_reader_wrapper_->input_stream(), charset); | 244 env, request(), input_stream_reader_wrapper_->input_stream(), charset); |
| 223 } | 245 } |
| 224 | 246 |
| 247 void AndroidStreamReaderURLRequestJob::HeadersComplete( | |
| 248 int status_code, | |
|
mnaganov (inactive)
2013/03/06 13:33:10
nit: please move the first arg in line with the fu
mkosiba (inactive)
2013/03/07 18:52:01
No can do. The chromium style guide says that you
mnaganov (inactive)
2013/03/08 09:15:47
Ah, sorry. The second line visually looks as if it
| |
| 249 const std::string& status_text) { | |
| 250 std::string status("HTTP/1.1 "); | |
|
benm (inactive)
2013/03/06 17:05:11
It feels weird to me we need to do this from scrat
mkosiba (inactive)
2013/03/07 18:52:01
nope, I did spend a while searching. The Chromium
| |
| 251 status.append(base::IntToString(status_code)); | |
| 252 status.append(" "); | |
| 253 status.append(status_text); | |
| 254 // HttpResponseHeaders expects its input string to be terminated by two NULs. | |
| 255 status.append("\0\0", 2); | |
| 256 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status); | |
| 257 | |
| 258 if (status_code == kHTTPOk) { | |
| 259 if (expected_content_size() != -1) { | |
| 260 std::string content_length_header( | |
| 261 net::HttpRequestHeaders::kContentLength); | |
| 262 content_length_header.append(": "); | |
| 263 content_length_header.append( | |
| 264 base::Int64ToString(expected_content_size())); | |
|
mnaganov (inactive)
2013/03/06 13:33:10
nit: is this wrap needed?
mkosiba (inactive)
2013/03/07 18:52:01
yes. If I join the lines they don't fit in the lin
mnaganov (inactive)
2013/03/08 09:15:47
Ah, it's Rietveld fooling me--it displays a lot of
| |
| 265 headers->AddHeader(content_length_header); | |
| 266 } | |
| 267 | |
| 268 std::string mime_type; | |
| 269 if (GetMimeType(&mime_type) && !mime_type.empty()) { | |
| 270 std::string content_type_header(net::HttpRequestHeaders::kContentType); | |
| 271 content_type_header.append(": "); | |
| 272 content_type_header.append(mime_type); | |
| 273 headers->AddHeader(content_type_header); | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 response_info_.reset(new net::HttpResponseInfo()); | |
| 278 response_info_->headers = headers; | |
| 279 | |
| 280 NotifyHeadersComplete(); | |
| 281 } | |
| 282 | |
| 283 int AndroidStreamReaderURLRequestJob::GetResponseCode() const { | |
| 284 if (response_info_) | |
| 285 return response_info_->headers->response_code(); | |
| 286 return URLRequestJob::GetResponseCode(); | |
| 287 } | |
| 288 | |
| 289 void AndroidStreamReaderURLRequestJob::GetResponseInfo( | |
| 290 net::HttpResponseInfo* info) { | |
| 291 if (response_info_) | |
| 292 *info = *response_info_; | |
| 293 } | |
| 294 | |
| 225 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( | 295 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( |
| 226 const net::HttpRequestHeaders& headers) { | 296 const net::HttpRequestHeaders& headers) { |
| 227 std::string range_header; | 297 std::string range_header; |
| 228 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { | 298 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { |
| 229 // We only extract the "Range" header so that we know how many bytes in the | 299 // We only extract the "Range" header so that we know how many bytes in the |
| 230 // stream to skip and how many to read after that. | 300 // stream to skip and how many to read after that. |
| 231 std::vector<net::HttpByteRange> ranges; | 301 std::vector<net::HttpByteRange> ranges; |
| 232 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { | 302 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { |
| 233 if (ranges.size() == 1) { | 303 if (ranges.size() == 1) { |
| 234 byte_range_ = ranges[0]; | 304 byte_range_ = ranges[0]; |
| 235 } else { | 305 } else { |
| 236 // We don't support multiple range requests in one single URL request, | 306 // We don't support multiple range requests in one single URL request, |
| 237 // because we need to do multipart encoding here. | 307 // because we need to do multipart encoding here. |
| 238 NotifyDone(net::URLRequestStatus( | 308 NotifyDone(net::URLRequestStatus( |
| 239 net::URLRequestStatus::FAILED, | 309 net::URLRequestStatus::FAILED, |
| 240 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 310 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
| 241 } | 311 } |
| 242 } | 312 } |
| 243 } | 313 } |
| 244 } | 314 } |
| OLD | NEW |