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 |