Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / android_webview / browser / net / android_stream_reader_url_request_job.cc
blobfd2691208efda361fb4508106fc69a66d26c37bb
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/single_thread_task_runner.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/task_runner.h"
19 #include "base/threading/sequenced_worker_pool.h"
20 #include "base/threading/thread.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/mime_util.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_util.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/http/http_response_info.h"
28 #include "net/http/http_util.h"
29 #include "net/url_request/url_request.h"
30 #include "net/url_request/url_request_job_manager.h"
32 using android_webview::InputStream;
33 using android_webview::InputStreamReader;
34 using base::android::AttachCurrentThread;
35 using base::PostTaskAndReplyWithResult;
36 using content::BrowserThread;
38 namespace {
40 const int kHTTPOk = 200;
41 const int kHTTPNotFound = 404;
43 const char kResponseHeaderViaShouldInterceptRequest[] =
44 "Client-Via: shouldInterceptRequest";
45 const char kHTTPOkText[] = "OK";
46 const char kHTTPNotFoundText[] = "Not Found";
48 } // namespace
50 // The requests posted to the worker thread might outlive the job. Thread-safe
51 // ref counting is used to ensure that the InputStream and InputStreamReader
52 // members of this class are still there when the closure is run on the worker
53 // thread.
54 class InputStreamReaderWrapper :
55 public base::RefCountedThreadSafe<InputStreamReaderWrapper> {
56 public:
57 InputStreamReaderWrapper(
58 scoped_ptr<InputStream> input_stream,
59 scoped_ptr<InputStreamReader> input_stream_reader)
60 : input_stream_(input_stream.Pass()),
61 input_stream_reader_(input_stream_reader.Pass()) {
62 DCHECK(input_stream_);
63 DCHECK(input_stream_reader_);
66 android_webview::InputStream* input_stream() {
67 return input_stream_.get();
70 int Seek(const net::HttpByteRange& byte_range) {
71 return input_stream_reader_->Seek(byte_range);
74 int ReadRawData(net::IOBuffer* buffer, int buffer_size) {
75 return input_stream_reader_->ReadRawData(buffer, buffer_size);
78 private:
79 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>;
80 ~InputStreamReaderWrapper() {}
82 scoped_ptr<android_webview::InputStream> input_stream_;
83 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_;
85 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper);
88 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob(
89 net::URLRequest* request,
90 net::NetworkDelegate* network_delegate,
91 scoped_ptr<Delegate> delegate)
92 : URLRequestJob(request, network_delegate),
93 delegate_(delegate.Pass()),
94 weak_factory_(this) {
95 DCHECK(delegate_);
98 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() {
101 namespace {
103 typedef base::Callback<
104 void(scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate>,
105 scoped_ptr<InputStream>)> OnInputStreamOpenedCallback;
107 // static
108 void OpenInputStreamOnWorkerThread(
109 scoped_refptr<base::SingleThreadTaskRunner> job_thread_task_runner,
110 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate> delegate,
111 const GURL& url,
112 OnInputStreamOpenedCallback callback) {
113 JNIEnv* env = AttachCurrentThread();
114 DCHECK(env);
116 scoped_ptr<InputStream> input_stream = delegate->OpenInputStream(env, url);
117 job_thread_task_runner->PostTask(
118 FROM_HERE, base::Bind(callback, base::Passed(delegate.Pass()),
119 base::Passed(input_stream.Pass())));
122 } // namespace
124 void AndroidStreamReaderURLRequestJob::Start() {
125 DCHECK(thread_checker_.CalledOnValidThread());
126 // Start reading asynchronously so that all error reporting and data
127 // callbacks happen as they would for network requests.
128 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
129 net::ERR_IO_PENDING));
131 // This could be done in the InputStreamReader but would force more
132 // complex synchronization in the delegate.
133 GetWorkerThreadRunner()->PostTask(
134 FROM_HERE,
135 base::Bind(
136 &OpenInputStreamOnWorkerThread,
137 base::MessageLoop::current()->task_runner(),
138 // This is intentional - the job could be deleted while the callback
139 // is executing on the background thread.
140 // The delegate will be "returned" to the job once the InputStream
141 // open attempt is completed.
142 base::Passed(&delegate_), request()->url(),
143 base::Bind(&AndroidStreamReaderURLRequestJob::OnInputStreamOpened,
144 weak_factory_.GetWeakPtr())));
147 void AndroidStreamReaderURLRequestJob::Kill() {
148 DCHECK(thread_checker_.CalledOnValidThread());
149 weak_factory_.InvalidateWeakPtrs();
150 URLRequestJob::Kill();
153 scoped_ptr<InputStreamReader>
154 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) {
155 return make_scoped_ptr(new InputStreamReader(stream));
158 void AndroidStreamReaderURLRequestJob::OnInputStreamOpened(
159 scoped_ptr<Delegate> returned_delegate,
160 scoped_ptr<android_webview::InputStream> input_stream) {
161 DCHECK(thread_checker_.CalledOnValidThread());
162 DCHECK(returned_delegate);
163 delegate_ = returned_delegate.Pass();
165 if (!input_stream) {
166 bool restart_required = false;
167 delegate_->OnInputStreamOpenFailed(request(), &restart_required);
168 if (restart_required) {
169 NotifyRestartRequired();
170 } else {
171 // Clear the IO_PENDING status set in Start().
172 SetStatus(net::URLRequestStatus());
173 HeadersComplete(kHTTPNotFound, kHTTPNotFoundText);
175 return;
178 scoped_ptr<InputStreamReader> input_stream_reader(
179 CreateStreamReader(input_stream.get()));
180 DCHECK(input_stream_reader);
182 DCHECK(!input_stream_reader_wrapper_.get());
183 input_stream_reader_wrapper_ = new InputStreamReaderWrapper(
184 input_stream.Pass(), input_stream_reader.Pass());
186 PostTaskAndReplyWithResult(
187 GetWorkerThreadRunner(),
188 FROM_HERE,
189 base::Bind(&InputStreamReaderWrapper::Seek,
190 input_stream_reader_wrapper_,
191 byte_range_),
192 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted,
193 weak_factory_.GetWeakPtr()));
196 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) {
197 DCHECK(thread_checker_.CalledOnValidThread());
198 // Clear the IO_PENDING status set in Start().
199 SetStatus(net::URLRequestStatus());
200 if (result >= 0) {
201 set_expected_content_size(result);
202 HeadersComplete(kHTTPOk, kHTTPOkText);
203 } else {
204 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
208 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) {
209 DCHECK(thread_checker_.CalledOnValidThread());
210 // The URLRequest API contract requires that:
211 // * NotifyDone be called once, to set the status code, indicate the job is
212 // finished (there will be no further IO),
213 // * NotifyReadComplete be called if false is returned from ReadRawData to
214 // indicate that the IOBuffer will not be used by the job anymore.
215 // There might be multiple calls to ReadRawData (and thus multiple calls to
216 // NotifyReadComplete), which is why NotifyDone is called only on errors
217 // (result < 0) and end of data (result == 0).
218 if (result == 0) {
219 NotifyDone(net::URLRequestStatus());
220 } else if (result < 0) {
221 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
222 } else {
223 // Clear the IO_PENDING status.
224 SetStatus(net::URLRequestStatus());
226 NotifyReadComplete(result);
229 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() {
230 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool());
233 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
234 int dest_size,
235 int* bytes_read) {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 if (!input_stream_reader_wrapper_.get()) {
238 // This will happen if opening the InputStream fails in which case the
239 // error is communicated by setting the HTTP response status header rather
240 // than failing the request during the header fetch phase.
241 *bytes_read = 0;
242 return true;
245 PostTaskAndReplyWithResult(
246 GetWorkerThreadRunner(),
247 FROM_HERE,
248 base::Bind(&InputStreamReaderWrapper::ReadRawData,
249 input_stream_reader_wrapper_,
250 make_scoped_refptr(dest),
251 dest_size),
252 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted,
253 weak_factory_.GetWeakPtr()));
255 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING,
256 net::ERR_IO_PENDING));
257 return false;
260 bool AndroidStreamReaderURLRequestJob::GetMimeType(
261 std::string* mime_type) const {
262 DCHECK(thread_checker_.CalledOnValidThread());
263 JNIEnv* env = AttachCurrentThread();
264 DCHECK(env);
266 if (!input_stream_reader_wrapper_.get())
267 return false;
269 // Since it's possible for this call to alter the InputStream a
270 // Seek or ReadRawData operation running in the background is not permitted.
271 DCHECK(!request_->status().is_io_pending());
273 return delegate_->GetMimeType(
274 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type);
277 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) {
278 DCHECK(thread_checker_.CalledOnValidThread());
279 JNIEnv* env = AttachCurrentThread();
280 DCHECK(env);
282 if (!input_stream_reader_wrapper_.get())
283 return false;
285 // Since it's possible for this call to alter the InputStream a
286 // Seek or ReadRawData operation running in the background is not permitted.
287 DCHECK(!request_->status().is_io_pending());
289 return delegate_->GetCharset(
290 env, request(), input_stream_reader_wrapper_->input_stream(), charset);
293 void AndroidStreamReaderURLRequestJob::HeadersComplete(
294 int status_code,
295 const std::string& status_text) {
296 std::string status("HTTP/1.1 ");
297 status.append(base::IntToString(status_code));
298 status.append(" ");
299 status.append(status_text);
300 // HttpResponseHeaders expects its input string to be terminated by two NULs.
301 status.append("\0\0", 2);
302 net::HttpResponseHeaders* headers = new net::HttpResponseHeaders(status);
304 if (status_code == kHTTPOk) {
305 if (expected_content_size() != -1) {
306 std::string content_length_header(
307 net::HttpRequestHeaders::kContentLength);
308 content_length_header.append(": ");
309 content_length_header.append(
310 base::Int64ToString(expected_content_size()));
311 headers->AddHeader(content_length_header);
314 std::string mime_type;
315 if (GetMimeType(&mime_type) && !mime_type.empty()) {
316 std::string content_type_header(net::HttpRequestHeaders::kContentType);
317 content_type_header.append(": ");
318 content_type_header.append(mime_type);
319 headers->AddHeader(content_type_header);
323 JNIEnv* env = AttachCurrentThread();
324 DCHECK(env);
325 delegate_->AppendResponseHeaders(env, headers);
327 // Indicate that the response had been obtained via shouldInterceptRequest.
328 headers->AddHeader(kResponseHeaderViaShouldInterceptRequest);
330 response_info_.reset(new net::HttpResponseInfo());
331 response_info_->headers = headers;
333 NotifyHeadersComplete();
336 int AndroidStreamReaderURLRequestJob::GetResponseCode() const {
337 if (response_info_)
338 return response_info_->headers->response_code();
339 return URLRequestJob::GetResponseCode();
342 void AndroidStreamReaderURLRequestJob::GetResponseInfo(
343 net::HttpResponseInfo* info) {
344 if (response_info_)
345 *info = *response_info_;
348 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
349 const net::HttpRequestHeaders& headers) {
350 std::string range_header;
351 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
352 // We only extract the "Range" header so that we know how many bytes in the
353 // stream to skip and how many to read after that.
354 std::vector<net::HttpByteRange> ranges;
355 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
356 if (ranges.size() == 1) {
357 byte_range_ = ranges[0];
358 } else {
359 // We don't support multiple range requests in one single URL request,
360 // because we need to do multipart encoding here.
361 NotifyDone(net::URLRequestStatus(
362 net::URLRequestStatus::FAILED,
363 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));