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

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

Issue 11363123: [android_webview] Don't block the IO thread when reading from an InputStream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix double-free Created 8 years, 1 month 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
(Empty)
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.
4
5 #include "android_webview/browser/net/android_stream_reader_url_request_job.h"
6
7 #include "android_webview/browser/input_stream.h"
8 #include "android_webview/browser/net/input_stream_reader.h"
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/lazy_instance.h"
14 #include "base/message_loop.h"
15 #include "base/task_runner.h"
16 #include "base/threading/sequenced_worker_pool.h"
17 #include "base/threading/thread.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "net/base/io_buffer.h"
20 #include "net/base/mime_util.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/net_util.h"
23 #include "net/http/http_util.h"
24 #include "net/url_request/url_request.h"
25 #include "net/url_request/url_request_job_manager.h"
26
27 using android_webview::InputStream;
28 using android_webview::InputStreamReader;
29 using base::android::AttachCurrentThread;
30 using base::PostTaskAndReplyWithResult;
31 using content::BrowserThread;
32
33 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob(
34 net::URLRequest* request,
35 net::NetworkDelegate* network_delegate,
36 scoped_ptr<Delegate> delegate)
37 : URLRequestJob(request, network_delegate),
38 delegate_(delegate.Pass()),
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
40 DCHECK(delegate_.get());
41 }
42
43 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() {
44 }
45
46 void AndroidStreamReaderURLRequestJob::Start() {
47 // Start reading asynchronously so that all error reporting and data
48 // callbacks happen as they would for network requests.
49 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
50 MessageLoop::current()->PostTask(
51 FROM_HERE,
52 base::Bind(
53 &AndroidStreamReaderURLRequestJob::StartAsync,
54 weak_factory_.GetWeakPtr()));
55 }
56
57 void AndroidStreamReaderURLRequestJob::Kill() {
58 weak_factory_.InvalidateWeakPtrs();
59 URLRequestJob::Kill();
60 }
61
62 InputStreamReader* AndroidStreamReaderURLRequestJob::CreateStreamReader(
63 InputStream* stream) {
64 return new InputStreamReader(stream);
65 }
66
67 void AndroidStreamReaderURLRequestJob::StartAsync() {
68 JNIEnv* env = AttachCurrentThread();
69 DCHECK(env);
70
71 // This could be done in the InputStreamReader but would force more
72 // complex synchronization in the delegate.
73 stream_ = delegate_->OpenInputStream(env, request());
74 if (!stream_) {
75 NotifyDone(
76 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
77 return;
78 }
79
80 DCHECK(!input_stream_reader_);
81 input_stream_reader_ = CreateStreamReader(stream_.get());
82 CHECK(input_stream_reader_);
83
84 PostTaskAndReplyWithResult(
85 GetWorkerThreadRunner(),
86 FROM_HERE,
87 base::Bind(&InputStreamReader::Seek, input_stream_reader_, byte_range_),
88 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted,
89 weak_factory_.GetWeakPtr()));
90 }
91
92 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(
93 int result) {
94 // Clear the IO_PENDING status set in Start().
95 SetStatus(net::URLRequestStatus());
96 if (result >= 0) {
97 set_expected_content_size(result);
98 NotifyHeadersComplete();
99 } else {
100 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
101 }
102 }
103
104 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(
105 int result) {
106 // The URLRequest API contract requires that:
107 // * NotifyDone be called once, to set the status code, indicate the job is
108 // finished (there will be no further IO),
109 // * NotifyReadComplete be called if false is returned from ReadRawData to
110 // indicate that the IOBuffer will not be used by the job anymore.
111 // There might be multiple calls to ReadRawData (and thus multiple calls to
112 // NotifyReadComplete), which is why NotifyDone is called only on errors
113 // (result < 0) and end of data (result == 0).
114 if (result == 0) {
115 NotifyDone(net::URLRequestStatus());
116 } else if (result < 0) {
117 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
118 } else {
119 // Clear the IO_PENDING status.
120 SetStatus(net::URLRequestStatus());
121 }
122 NotifyReadComplete(result);
123 }
124
125 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() {
126 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool());
127 }
128
129 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest,
130 int dest_size,
131 int *bytes_read) {
joth 2012/11/20 20:46:35 ubernit: put '*' next to the type
mkosiba (inactive) 2012/11/21 15:19:47 Done.
132 DCHECK(input_stream_reader_);
133
134 PostTaskAndReplyWithResult(
135 GetWorkerThreadRunner(),
136 FROM_HERE,
137 base::Bind(&InputStreamReader::ReadRawData,
138 input_stream_reader_,
139 base::Unretained(dest),
140 dest_size),
141 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted,
142 weak_factory_.GetWeakPtr()));
143
144 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
145 return false;
146 }
147
148 bool AndroidStreamReaderURLRequestJob::GetMimeType(
149 std::string* mime_type) const {
150 JNIEnv* env = AttachCurrentThread();
151 DCHECK(env);
152
153 if (!stream_)
154 return false;
155
156 return delegate_->GetMimeType(env, request(), *stream_, mime_type);
157 }
158
159 bool AndroidStreamReaderURLRequestJob::GetCharset(
160 std::string* charset) {
161 JNIEnv* env = AttachCurrentThread();
162 DCHECK(env);
163
164 if (!stream_)
165 return false;
166
167 return delegate_->GetCharset(env, request(), *stream_, charset);
168 }
169
170 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders(
171 const net::HttpRequestHeaders& headers) {
172 std::string range_header;
173 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
174 // We only care about "Range" header here.
joth 2012/11/20 20:46:35 nit: maybe expand the comment a little about what
mkosiba (inactive) 2012/11/21 15:19:47 Done.
175 std::vector<net::HttpByteRange> ranges;
176 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
177 if (ranges.size() == 1) {
178 byte_range_ = ranges[0];
179 } else {
180 // We don't support multiple range requests in one single URL request,
181 // because we need to do multipart encoding here.
182 NotifyDone(net::URLRequestStatus(
183 net::URLRequestStatus::FAILED,
184 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
185 }
186 }
187 }
188 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698