Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(826)

Side by Side Diff: android_webview/browser/net/android_stream_reader_url_request_job.cc

Issue 12531002: [android_webview] Make intercepted URLRequests have status codes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698