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 "android_webview/browser/input_stream.h" | 7 #include "android_webview/browser/input_stream.h" |
8 #include "android_webview/browser/net/input_stream_reader.h" | 8 #include "android_webview/browser/net/input_stream_reader.h" |
9 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 private: | 61 private: |
62 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>; | 62 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>; |
63 ~InputStreamReaderWrapper() {} | 63 ~InputStreamReaderWrapper() {} |
64 | 64 |
65 scoped_ptr<android_webview::InputStream> input_stream_; | 65 scoped_ptr<android_webview::InputStream> input_stream_; |
66 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_; | 66 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_; |
67 | 67 |
68 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper); | 68 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper); |
69 }; | 69 }; |
70 | 70 |
71 // In unittests the Job isn't created on the IO thread making it slightly | |
72 // harder to post back to the job's thread. We use a helper data structure to | |
73 // be able to use PostTaskAndReplyWithResult with OpenInputStreamOnWorkerThread | |
74 // which will take care of posting back to the Job's thread. | |
75 struct AndroidStreamReaderURLRequestJob::OpenInputStreamResult { | |
mnaganov (inactive)
2013/03/06 09:26:47
Is this about C++ or Java unittests? If C++, perha
mkosiba (inactive)
2013/03/06 19:05:27
C++ unittests. So it looks all of the remaining jo
| |
76 scoped_ptr<InputStream> input_stream; | |
77 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate> delegate; | |
78 }; | |
79 | |
71 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( | 80 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( |
72 net::URLRequest* request, | 81 net::URLRequest* request, |
73 net::NetworkDelegate* network_delegate, | 82 net::NetworkDelegate* network_delegate, |
74 scoped_ptr<Delegate> delegate) | 83 scoped_ptr<Delegate> delegate) |
75 : URLRequestJob(request, network_delegate), | 84 : URLRequestJob(request, network_delegate), |
76 delegate_(delegate.Pass()), | 85 delegate_(delegate.Pass()), |
77 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 86 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
78 DCHECK(delegate_); | 87 DCHECK(delegate_); |
79 } | 88 } |
80 | 89 |
81 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { | 90 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { |
82 } | 91 } |
83 | 92 |
93 // static | |
94 scoped_ptr<AndroidStreamReaderURLRequestJob::OpenInputStreamResult> | |
95 AndroidStreamReaderURLRequestJob::OpenInputStreamOnWorkerThread( | |
96 scoped_ptr<AndroidStreamReaderURLRequestJob::Delegate> delegate, | |
97 const GURL& url) { | |
98 JNIEnv* env = AttachCurrentThread(); | |
99 DCHECK(env); | |
100 | |
101 scoped_ptr<AndroidStreamReaderURLRequestJob::OpenInputStreamResult> result( | |
102 new AndroidStreamReaderURLRequestJob::OpenInputStreamResult()); | |
103 result->input_stream = delegate->OpenInputStream(env, url); | |
104 result->delegate = delegate.Pass(); | |
105 return result.Pass(); | |
106 } | |
107 | |
84 void AndroidStreamReaderURLRequestJob::Start() { | 108 void AndroidStreamReaderURLRequestJob::Start() { |
109 DCHECK(thread_checker_.CalledOnValidThread()); | |
85 // Start reading asynchronously so that all error reporting and data | 110 // Start reading asynchronously so that all error reporting and data |
86 // callbacks happen as they would for network requests. | 111 // callbacks happen as they would for network requests. |
87 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, | 112 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, |
88 net::ERR_IO_PENDING)); | 113 net::ERR_IO_PENDING)); |
89 MessageLoop::current()->PostTask( | 114 |
115 // This could be done in the InputStreamReader but would force more | |
116 // complex synchronization in the delegate. | |
117 PostTaskAndReplyWithResult( | |
118 GetWorkerThreadRunner(), | |
90 FROM_HERE, | 119 FROM_HERE, |
91 base::Bind( | 120 base::Bind( |
92 &AndroidStreamReaderURLRequestJob::StartAsync, | 121 &OpenInputStreamOnWorkerThread, |
93 weak_factory_.GetWeakPtr())); | 122 // This is intentional - the job could be deleted while the callback |
123 // is executing on the background thread. | |
124 // The delegate will be "returned" to the job once the InputStream | |
125 // open attempt is completed. | |
126 base::Passed(&delegate_), | |
boliu
2013/03/06 02:30:18
How bad is it to make delegate RefCountedThreadSaf
mkosiba (inactive)
2013/03/06 19:05:27
but the delegate _isn't_ thread safe. I actually l
| |
127 request()->url()), | |
128 base::Bind(&AndroidStreamReaderURLRequestJob::OnInputStreamOpened, | |
129 weak_factory_.GetWeakPtr())); | |
94 } | 130 } |
95 | 131 |
96 void AndroidStreamReaderURLRequestJob::Kill() { | 132 void AndroidStreamReaderURLRequestJob::Kill() { |
133 DCHECK(thread_checker_.CalledOnValidThread()); | |
97 weak_factory_.InvalidateWeakPtrs(); | 134 weak_factory_.InvalidateWeakPtrs(); |
98 URLRequestJob::Kill(); | 135 URLRequestJob::Kill(); |
99 } | 136 } |
100 | 137 |
101 scoped_ptr<InputStreamReader> | 138 scoped_ptr<InputStreamReader> |
102 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) { | 139 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) { |
103 return make_scoped_ptr(new InputStreamReader(stream)); | 140 return make_scoped_ptr(new InputStreamReader(stream)); |
104 } | 141 } |
105 | 142 |
106 void AndroidStreamReaderURLRequestJob::StartAsync() { | 143 void AndroidStreamReaderURLRequestJob::OnInputStreamOpened( |
107 JNIEnv* env = AttachCurrentThread(); | 144 scoped_ptr<OpenInputStreamResult> result) { |
108 DCHECK(env); | 145 DCHECK(thread_checker_.CalledOnValidThread()); |
146 DCHECK(result->delegate); | |
147 delegate_ = result->delegate.Pass(); | |
148 scoped_ptr<InputStream> input_stream = result->input_stream.Pass(); | |
109 | 149 |
110 // This could be done in the InputStreamReader but would force more | 150 if (!input_stream) { |
111 // complex synchronization in the delegate. | 151 bool restart_required = false; |
112 scoped_ptr<android_webview::InputStream> stream( | 152 delegate_->OnInputStreamOpenFailed(request(), &restart_required); |
113 delegate_->OpenInputStream(env, request())); | 153 if (restart_required) { |
114 | 154 NotifyRestartRequired(); |
115 if (!stream) { | 155 } else { |
116 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, | 156 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
117 net::ERR_FAILED)); | 157 net::ERR_FAILED)); |
158 } | |
118 return; | 159 return; |
119 } | 160 } |
120 | 161 |
121 scoped_ptr<InputStreamReader> input_stream_reader( | 162 scoped_ptr<InputStreamReader> input_stream_reader( |
122 CreateStreamReader(stream.get())); | 163 CreateStreamReader(input_stream.get())); |
123 DCHECK(input_stream_reader); | 164 DCHECK(input_stream_reader); |
124 | 165 |
125 DCHECK(!input_stream_reader_wrapper_); | 166 DCHECK(!input_stream_reader_wrapper_); |
126 input_stream_reader_wrapper_ = | 167 input_stream_reader_wrapper_ = new InputStreamReaderWrapper( |
127 new InputStreamReaderWrapper(stream.Pass(), input_stream_reader.Pass()); | 168 input_stream.Pass(), input_stream_reader.Pass()); |
128 | 169 |
129 PostTaskAndReplyWithResult( | 170 PostTaskAndReplyWithResult( |
130 GetWorkerThreadRunner(), | 171 GetWorkerThreadRunner(), |
131 FROM_HERE, | 172 FROM_HERE, |
132 base::Bind(&InputStreamReaderWrapper::Seek, | 173 base::Bind(&InputStreamReaderWrapper::Seek, |
133 input_stream_reader_wrapper_, | 174 input_stream_reader_wrapper_, |
134 byte_range_), | 175 byte_range_), |
135 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, | 176 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, |
136 weak_factory_.GetWeakPtr())); | 177 weak_factory_.GetWeakPtr())); |
137 } | 178 } |
138 | 179 |
139 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { | 180 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { |
181 DCHECK(thread_checker_.CalledOnValidThread()); | |
140 // Clear the IO_PENDING status set in Start(). | 182 // Clear the IO_PENDING status set in Start(). |
141 SetStatus(net::URLRequestStatus()); | 183 SetStatus(net::URLRequestStatus()); |
142 if (result >= 0) { | 184 if (result >= 0) { |
143 set_expected_content_size(result); | 185 set_expected_content_size(result); |
144 NotifyHeadersComplete(); | 186 NotifyHeadersComplete(); |
145 } else { | 187 } else { |
146 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 188 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
147 } | 189 } |
148 } | 190 } |
149 | 191 |
150 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { | 192 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { |
193 DCHECK(thread_checker_.CalledOnValidThread()); | |
151 // The URLRequest API contract requires that: | 194 // The URLRequest API contract requires that: |
152 // * NotifyDone be called once, to set the status code, indicate the job is | 195 // * NotifyDone be called once, to set the status code, indicate the job is |
153 // finished (there will be no further IO), | 196 // finished (there will be no further IO), |
154 // * NotifyReadComplete be called if false is returned from ReadRawData to | 197 // * NotifyReadComplete be called if false is returned from ReadRawData to |
155 // indicate that the IOBuffer will not be used by the job anymore. | 198 // indicate that the IOBuffer will not be used by the job anymore. |
156 // There might be multiple calls to ReadRawData (and thus multiple calls to | 199 // There might be multiple calls to ReadRawData (and thus multiple calls to |
157 // NotifyReadComplete), which is why NotifyDone is called only on errors | 200 // NotifyReadComplete), which is why NotifyDone is called only on errors |
158 // (result < 0) and end of data (result == 0). | 201 // (result < 0) and end of data (result == 0). |
159 if (result == 0) { | 202 if (result == 0) { |
160 NotifyDone(net::URLRequestStatus()); | 203 NotifyDone(net::URLRequestStatus()); |
161 } else if (result < 0) { | 204 } else if (result < 0) { |
162 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 205 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
163 } else { | 206 } else { |
164 // Clear the IO_PENDING status. | 207 // Clear the IO_PENDING status. |
165 SetStatus(net::URLRequestStatus()); | 208 SetStatus(net::URLRequestStatus()); |
166 } | 209 } |
167 NotifyReadComplete(result); | 210 NotifyReadComplete(result); |
168 } | 211 } |
169 | 212 |
170 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { | 213 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { |
171 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); | 214 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); |
172 } | 215 } |
173 | 216 |
174 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, | 217 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, |
175 int dest_size, | 218 int dest_size, |
176 int* bytes_read) { | 219 int* bytes_read) { |
220 DCHECK(thread_checker_.CalledOnValidThread()); | |
177 DCHECK(input_stream_reader_wrapper_); | 221 DCHECK(input_stream_reader_wrapper_); |
178 | 222 |
179 PostTaskAndReplyWithResult( | 223 PostTaskAndReplyWithResult( |
180 GetWorkerThreadRunner(), | 224 GetWorkerThreadRunner(), |
181 FROM_HERE, | 225 FROM_HERE, |
182 base::Bind(&InputStreamReaderWrapper::ReadRawData, | 226 base::Bind(&InputStreamReaderWrapper::ReadRawData, |
183 input_stream_reader_wrapper_, | 227 input_stream_reader_wrapper_, |
184 make_scoped_refptr(dest), | 228 make_scoped_refptr(dest), |
185 dest_size), | 229 dest_size), |
186 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, | 230 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, |
187 weak_factory_.GetWeakPtr())); | 231 weak_factory_.GetWeakPtr())); |
188 | 232 |
189 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, | 233 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, |
190 net::ERR_IO_PENDING)); | 234 net::ERR_IO_PENDING)); |
191 return false; | 235 return false; |
192 } | 236 } |
193 | 237 |
194 bool AndroidStreamReaderURLRequestJob::GetMimeType( | 238 bool AndroidStreamReaderURLRequestJob::GetMimeType( |
195 std::string* mime_type) const { | 239 std::string* mime_type) const { |
240 DCHECK(thread_checker_.CalledOnValidThread()); | |
196 JNIEnv* env = AttachCurrentThread(); | 241 JNIEnv* env = AttachCurrentThread(); |
197 DCHECK(env); | 242 DCHECK(env); |
198 | 243 |
199 if (!input_stream_reader_wrapper_) | 244 if (!input_stream_reader_wrapper_) |
200 return false; | 245 return false; |
201 | 246 |
202 // Since it's possible for this call to alter the InputStream a | 247 // Since it's possible for this call to alter the InputStream a |
203 // Seek or ReadRawData operation running in the background is not permitted. | 248 // Seek or ReadRawData operation running in the background is not permitted. |
204 DCHECK(!request_->status().is_io_pending()); | 249 DCHECK(!request_->status().is_io_pending()); |
205 | 250 |
206 return delegate_->GetMimeType( | 251 return delegate_->GetMimeType( |
207 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type); | 252 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type); |
208 } | 253 } |
209 | 254 |
210 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) { | 255 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) { |
256 DCHECK(thread_checker_.CalledOnValidThread()); | |
211 JNIEnv* env = AttachCurrentThread(); | 257 JNIEnv* env = AttachCurrentThread(); |
212 DCHECK(env); | 258 DCHECK(env); |
213 | 259 |
214 if (!input_stream_reader_wrapper_) | 260 if (!input_stream_reader_wrapper_) |
215 return false; | 261 return false; |
216 | 262 |
217 // Since it's possible for this call to alter the InputStream a | 263 // Since it's possible for this call to alter the InputStream a |
218 // Seek or ReadRawData operation running in the background is not permitted. | 264 // Seek or ReadRawData operation running in the background is not permitted. |
219 DCHECK(!request_->status().is_io_pending()); | 265 DCHECK(!request_->status().is_io_pending()); |
220 | 266 |
(...skipping 14 matching lines...) Expand all Loading... | |
235 } else { | 281 } else { |
236 // We don't support multiple range requests in one single URL request, | 282 // We don't support multiple range requests in one single URL request, |
237 // because we need to do multipart encoding here. | 283 // because we need to do multipart encoding here. |
238 NotifyDone(net::URLRequestStatus( | 284 NotifyDone(net::URLRequestStatus( |
239 net::URLRequestStatus::FAILED, | 285 net::URLRequestStatus::FAILED, |
240 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 286 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
241 } | 287 } |
242 } | 288 } |
243 } | 289 } |
244 } | 290 } |
OLD | NEW |