Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / android_webview / browser / net / android_stream_reader_url_request_job.cc
blobc2c478362281a0b74bafa225ffc89c3d5c1d2b65
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
3 // found in the LICENSE file.
5 #include "android_webview/browser/net/android_stream_reader_url_request_job.h"
7 #include <string>
9 #include "android_webview/browser/input_stream.h"
10 #include "android_webview/browser/net/input_stream_reader.h"
11 #include "base/android/jni_android.h"
12 #include "base/android/jni_string.h"
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/lazy_instance.h"
16 #include "base/message_loop.h"
17 #include "base/message_loop_proxy.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/task_runner.h"
20 #include "base/threading/sequenced_worker_pool.h"
21 #include "base/threading/thread.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "net/base/io_buffer.h"
24 #include "net/base/mime_util.h"
25 #include "net/base/net_errors.h"
26 #include "net/base/net_util.h"
27 #include "net/http/http_response_headers.h"
28 #include "net/http/http_response_info.h"
29 #include "net/http/http_util.h"
30 #include "net/url_request/url_request.h"
31 #include "net/url_request/url_request_job_manager.h"
33 using android_webview::InputStream;
34 using android_webview::InputStreamReader;
35 using base::android::AttachCurrentThread;
36 using base::PostTaskAndReplyWithResult;
37 using content::BrowserThread;
39 namespace {
41 const int kHTTPOk = 200;
42 const int kHTTPNotFound = 404;
44 const char kHTTPOkText[] = "OK";
45 const char kHTTPNotFoundText[] = "Not Found";
47 } // namespace
49 // The requests posted to the worker thread might outlive the job. Thread-safe
50 // ref counting is used to ensure that the InputStream and InputStreamReader
51 // members of this class are still there when the closure is run on the worker
52 // thread.
53 class InputStreamReaderWrapper :
54 public base::RefCountedThreadSafe<InputStreamReaderWrapper> {
55 public:
56 InputStreamReaderWrapper(
57 scoped_ptr<InputStream> input_stream,
58 scoped_ptr<InputStreamReader> input_stream_reader)
59 : input_stream_(input_stream.Pass()),
60 input_stream_reader_(input_stream_reader.Pass()) {
61 DCHECK(input_stream_);
62 DCHECK(input_stream_reader_);
65 android_webview::InputStream* input_stream() {
66 return input_stream_.get();
69 int Seek(const net::HttpByteRange& byte_range) {
70 return input_stream_reader_->Seek(byte_range);
73 int ReadRawData(net::IOBuffer* buffer, int buffer_size) {
74 return input_stream_reader_->ReadRawData(buffer, buffer_size);
77 private:
78 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>;
79 ~InputStreamReaderWrapper() {}
81 scoped_ptr<android_webview::InputStream> input_stream_;
82 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_;
84 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper);
87 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob(
88 net::URLRequest* request,
89 net::NetworkDelegate* network_delegate,
90 scoped_ptr<Delegate> delegate)
91 : URLRequestJob(request, network_delegate),
92 delegate_(delegate.Pass()),
93 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
94 DCHECK(delegate_);
97 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() {
100 namespace {
102 typedef base::Callback<
103 void(scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>,
104 scoped_ptr<InputStream>)> OnInputStreamOpenedCallback;
106 // static
107 void OpenInputStreamOnWorkerThread(
108 scoped_refptr<base::MessageLoopProxy> job_thread_proxy,
109 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate> delegate,
110 const GURL& url,
111 OnInputStreamOpenedCallback callback) {
113 JNIEnv* env = AttachCurrentThread();
114 DCHECK(env);
116 scoped_ptr<InputStream> input_stream = delegate->OpenInputStream(env, url);
117 job_thread_proxy->PostTask(FROM_HERE,
118 base::Bind(callback,
119 base::Passed(delegate.Pass()),
120 base::Passed(input_stream.Pass())));
123 } // namespace
125 void AndroidStreamReaderURLRequestJob::Start() {
126 DCHECK(thread_checker_.CalledOnValidThread());
127 // Start reading asynchronously so that all error reporting and data
128 // callbacks happen as they would for network requests.
129 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
130 net::ERR_IO_PENDING));
132 // This could be done in the InputStreamReader but would force more
133 // complex synchronization in the delegate.
134 GetWorkerThreadRunner()->PostTask(
135 FROM_HERE,
136 base::Bind(
137 &OpenInputStreamOnWorkerThread,
138 MessageLoop::current()->message_loop_proxy(),
139 // This is intentional - the job could be deleted while the callback
140 // is executing on the background thread.
141 // The delegate will be "returned" to the job once the InputStream
142 // open attempt is completed.
143 base::Passed(&delegate_),
144 request()->url(),
145 base::Bind(&AndroidStreamReaderURLRequestJob::OnInputStreamOpened,
146 weak_factory_.GetWeakPtr())));
149 void AndroidStreamReaderURLRequestJob::Kill() {
150 DCHECK(thread_checker_.CalledOnValidThread());
151 weak_factory_.InvalidateWeakPtrs();
152 URLRequestJob::Kill();
155 scoped_ptr<InputStreamReader>
156 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) {
157 return make_scoped_ptr(new InputStreamReader(stream));
160 void AndroidStreamReaderURLRequestJob::OnInputStreamOpened(
161 scoped_ptr<Delegate> returned_delegate,
162 scoped_ptr<android_webview::InputStream> input_stream) {
163 DCHECK(thread_checker_.CalledOnValidThread());
164 DCHECK(returned_delegate);
165 delegate_ = returned_delegate.Pass();
167 if (!input_stream) {
168 bool restart_required = false;
169 delegate_->OnInputStreamOpenFailed(request(), &restart_required);
170 if (restart_required) {
171 NotifyRestartRequired();
172 } else {
173 // Clear the IO_PENDING status set in Start().
174 SetStatus(net::URLRequestStatus());
175 HeadersComplete(kHTTPNotFound, kHTTPNotFoundText);
177 return;
180 scoped_ptr<InputStreamReader> input_stream_reader(
181 CreateStreamReader(input_stream.get()));
182 DCHECK(input_stream_reader);
184 DCHECK(!input_stream_reader_wrapper_);
185 input_stream_reader_wrapper_ = new InputStreamReaderWrapper(
186 input_stream.Pass(), input_stream_reader.Pass());
188 PostTaskAndReplyWithResult(
189 GetWorkerThreadRunner(),
190 FROM_HERE,
191 base::Bind(&InputStreamReaderWrapper::Seek,
192 input_stream_reader_wrapper_,
193 byte_range_),
194 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted,
195 weak_factory_.GetWeakPtr()));
198 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) {
199 DCHECK(thread_checker_.CalledOnValidThread());
200 // Clear the IO_PENDING status set in Start().
201 SetStatus(net::URLRequestStatus());
202 if (result >= 0) {
203 set_expected_content_size(result);
204 HeadersComplete(kHTTPOk, kHTTPOkText);
205 } else {
206 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
210 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) {
211 DCHECK(thread_checker_.CalledOnValidThread());
212 // The URLRequest API contract requires that:
213 // * NotifyDone be called once, to set the status code, indicate the job is
214 // finished (there will be no further IO),
215 // * NotifyReadComplete be called if false is returned from ReadRawData to
216 // indicate that the IOBuffer will not be used by the job anymore.
217 // There might be multiple calls to ReadRawData (and thus multiple calls to
218 // NotifyReadComplete), which is why NotifyDone is called only on errors
219 // (result < 0) and end of data (result == 0).
220 if (result == 0) {
221 NotifyDone(net::URLRequestStatus());
222 } else if (result < 0) {
223 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
224 } else {
225 // Clear the IO_PENDING status.
226 SetStatus(net::URLRequestStatus());
228 NotifyReadComplete(result);
231 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() {
232 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool());
235 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
236 int dest_size,
237 int* bytes_read) {
238 DCHECK(thread_checker_.CalledOnValidThread());
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;
247 PostTaskAndReplyWithResult(
248 GetWorkerThreadRunner(),
249 FROM_HERE,
250 base::Bind(&InputStreamReaderWrapper::ReadRawData,
251 input_stream_reader_wrapper_,
252 make_scoped_refptr(dest),
253 dest_size),
254 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted,
255 weak_factory_.GetWeakPtr()));
257 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
258 net::ERR_IO_PENDING));
259 return false;
262 bool AndroidStreamReaderURLRequestJob::GetMimeType(
263 std::string* mime_type) const {
264 DCHECK(thread_checker_.CalledOnValidThread());
265 JNIEnv* env = AttachCurrentThread();
266 DCHECK(env);
268 if (!input_stream_reader_wrapper_)
269 return false;
271 // Since it's possible for this call to alter the InputStream a
272 // Seek or ReadRawData operation running in the background is not permitted.
273 DCHECK(!request_->status().is_io_pending());
275 return delegate_->GetMimeType(
276 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type);
279 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) {
280 DCHECK(thread_checker_.CalledOnValidThread());
281 JNIEnv* env = AttachCurrentThread();
282 DCHECK(env);
284 if (!input_stream_reader_wrapper_)
285 return false;
287 // Since it's possible for this call to alter the InputStream a
288 // Seek or ReadRawData operation running in the background is not permitted.
289 DCHECK(!request_->status().is_io_pending());
291 return delegate_->GetCharset(
292 env, request(), input_stream_reader_wrapper_->input_stream(), charset);
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);
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);
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);
325 response_info_.reset(new net::HttpResponseInfo());
326 response_info_->headers = headers;
328 NotifyHeadersComplete();
331 int AndroidStreamReaderURLRequestJob::GetResponseCode() const {
332 if (response_info_)
333 return response_info_->headers->response_code();
334 return URLRequestJob::GetResponseCode();
337 void AndroidStreamReaderURLRequestJob::GetResponseInfo(
338 net::HttpResponseInfo* info) {
339 if (response_info_)
340 *info = *response_info_;
343 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
344 const net::HttpRequestHeaders& headers) {
345 std::string range_header;
346 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
347 // We only extract the "Range" header so that we know how many bytes in the
348 // stream to skip and how many to read after that.
349 std::vector<net::HttpByteRange> ranges;
350 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
351 if (ranges.size() == 1) {
352 byte_range_ = ranges[0];
353 } else {
354 // We don't support multiple range requests in one single URL request,
355 // because we need to do multipart encoding here.
356 NotifyDone(net::URLRequestStatus(
357 net::URLRequestStatus::FAILED,
358 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));