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 12 matching lines...) Expand all Loading... |
23 #include "net/http/http_util.h" | 23 #include "net/http/http_util.h" |
24 #include "net/url_request/url_request.h" | 24 #include "net/url_request/url_request.h" |
25 #include "net/url_request/url_request_job_manager.h" | 25 #include "net/url_request/url_request_job_manager.h" |
26 | 26 |
27 using android_webview::InputStream; | 27 using android_webview::InputStream; |
28 using android_webview::InputStreamReader; | 28 using android_webview::InputStreamReader; |
29 using base::android::AttachCurrentThread; | 29 using base::android::AttachCurrentThread; |
30 using base::PostTaskAndReplyWithResult; | 30 using base::PostTaskAndReplyWithResult; |
31 using content::BrowserThread; | 31 using content::BrowserThread; |
32 | 32 |
| 33 // 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 |
| 35 // members of this class are still there when the closure is run on the worker |
| 36 // thread. |
| 37 class InputStreamReaderWrapper : |
| 38 public base::RefCountedThreadSafe<InputStreamReaderWrapper> { |
| 39 public: |
| 40 InputStreamReaderWrapper( |
| 41 scoped_ptr<InputStream> input_stream, |
| 42 scoped_ptr<InputStreamReader> input_stream_reader) |
| 43 : input_stream_(input_stream.Pass()), |
| 44 input_stream_reader_(input_stream_reader.Pass()) { |
| 45 DCHECK(input_stream_); |
| 46 DCHECK(input_stream_reader_); |
| 47 } |
| 48 |
| 49 android_webview::InputStream* input_stream() { |
| 50 return input_stream_.get(); |
| 51 } |
| 52 |
| 53 int Seek(const net::HttpByteRange& byte_range) { |
| 54 return input_stream_reader_->Seek(byte_range); |
| 55 } |
| 56 |
| 57 int ReadRawData(net::IOBuffer* buffer, int buffer_size) { |
| 58 return input_stream_reader_->ReadRawData(buffer, buffer_size); |
| 59 } |
| 60 |
| 61 private: |
| 62 friend class base::RefCountedThreadSafe<InputStreamReaderWrapper>; |
| 63 ~InputStreamReaderWrapper() {} |
| 64 |
| 65 scoped_ptr<android_webview::InputStream> input_stream_; |
| 66 scoped_ptr<android_webview::InputStreamReader> input_stream_reader_; |
| 67 |
| 68 DISALLOW_COPY_AND_ASSIGN(InputStreamReaderWrapper); |
| 69 }; |
| 70 |
33 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( | 71 AndroidStreamReaderURLRequestJob::AndroidStreamReaderURLRequestJob( |
34 net::URLRequest* request, | 72 net::URLRequest* request, |
35 net::NetworkDelegate* network_delegate, | 73 net::NetworkDelegate* network_delegate, |
36 scoped_ptr<Delegate> delegate) | 74 scoped_ptr<Delegate> delegate) |
37 : URLRequestJob(request, network_delegate), | 75 : URLRequestJob(request, network_delegate), |
38 delegate_(delegate.Pass()), | 76 delegate_(delegate.Pass()), |
39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 77 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
40 DCHECK(delegate_.get()); | 78 DCHECK(delegate_); |
41 } | 79 } |
42 | 80 |
43 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { | 81 AndroidStreamReaderURLRequestJob::~AndroidStreamReaderURLRequestJob() { |
44 } | 82 } |
45 | 83 |
46 void AndroidStreamReaderURLRequestJob::Start() { | 84 void AndroidStreamReaderURLRequestJob::Start() { |
47 // Start reading asynchronously so that all error reporting and data | 85 // Start reading asynchronously so that all error reporting and data |
48 // callbacks happen as they would for network requests. | 86 // callbacks happen as they would for network requests. |
49 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | 87 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, |
| 88 net::ERR_IO_PENDING)); |
50 MessageLoop::current()->PostTask( | 89 MessageLoop::current()->PostTask( |
51 FROM_HERE, | 90 FROM_HERE, |
52 base::Bind( | 91 base::Bind( |
53 &AndroidStreamReaderURLRequestJob::StartAsync, | 92 &AndroidStreamReaderURLRequestJob::StartAsync, |
54 weak_factory_.GetWeakPtr())); | 93 weak_factory_.GetWeakPtr())); |
55 } | 94 } |
56 | 95 |
57 void AndroidStreamReaderURLRequestJob::Kill() { | 96 void AndroidStreamReaderURLRequestJob::Kill() { |
58 weak_factory_.InvalidateWeakPtrs(); | 97 weak_factory_.InvalidateWeakPtrs(); |
59 URLRequestJob::Kill(); | 98 URLRequestJob::Kill(); |
60 } | 99 } |
61 | 100 |
62 scoped_refptr<InputStreamReader> | 101 scoped_ptr<InputStreamReader> |
63 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) { | 102 AndroidStreamReaderURLRequestJob::CreateStreamReader(InputStream* stream) { |
64 return make_scoped_refptr(new InputStreamReader(stream)); | 103 return make_scoped_ptr(new InputStreamReader(stream)); |
65 } | 104 } |
66 | 105 |
67 void AndroidStreamReaderURLRequestJob::StartAsync() { | 106 void AndroidStreamReaderURLRequestJob::StartAsync() { |
68 JNIEnv* env = AttachCurrentThread(); | 107 JNIEnv* env = AttachCurrentThread(); |
69 DCHECK(env); | 108 DCHECK(env); |
70 | 109 |
71 // This could be done in the InputStreamReader but would force more | 110 // This could be done in the InputStreamReader but would force more |
72 // complex synchronization in the delegate. | 111 // complex synchronization in the delegate. |
73 stream_ = delegate_->OpenInputStream(env, request()); | 112 scoped_ptr<android_webview::InputStream> stream( |
74 if (!stream_) { | 113 delegate_->OpenInputStream(env, request())); |
75 NotifyDone( | 114 |
76 net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED)); | 115 if (!stream) { |
| 116 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, |
| 117 net::ERR_FAILED)); |
77 return; | 118 return; |
78 } | 119 } |
79 | 120 |
80 DCHECK(!input_stream_reader_); | 121 scoped_ptr<InputStreamReader> input_stream_reader( |
81 input_stream_reader_ = CreateStreamReader(stream_.get()); | 122 CreateStreamReader(stream.get())); |
82 CHECK(input_stream_reader_); | 123 DCHECK(input_stream_reader); |
| 124 |
| 125 DCHECK(!input_stream_reader_wrapper_); |
| 126 input_stream_reader_wrapper_ = |
| 127 new InputStreamReaderWrapper(stream.Pass(), input_stream_reader.Pass()); |
83 | 128 |
84 PostTaskAndReplyWithResult( | 129 PostTaskAndReplyWithResult( |
85 GetWorkerThreadRunner(), | 130 GetWorkerThreadRunner(), |
86 FROM_HERE, | 131 FROM_HERE, |
87 base::Bind(&InputStreamReader::Seek, input_stream_reader_, byte_range_), | 132 base::Bind(&InputStreamReaderWrapper::Seek, |
| 133 input_stream_reader_wrapper_, |
| 134 byte_range_), |
88 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, | 135 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted, |
89 weak_factory_.GetWeakPtr())); | 136 weak_factory_.GetWeakPtr())); |
90 } | 137 } |
91 | 138 |
92 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted( | 139 void AndroidStreamReaderURLRequestJob::OnReaderSeekCompleted(int result) { |
93 int result) { | |
94 // Clear the IO_PENDING status set in Start(). | 140 // Clear the IO_PENDING status set in Start(). |
95 SetStatus(net::URLRequestStatus()); | 141 SetStatus(net::URLRequestStatus()); |
96 if (result >= 0) { | 142 if (result >= 0) { |
97 set_expected_content_size(result); | 143 set_expected_content_size(result); |
98 NotifyHeadersComplete(); | 144 NotifyHeadersComplete(); |
99 } else { | 145 } else { |
100 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 146 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
101 } | 147 } |
102 } | 148 } |
103 | 149 |
104 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted( | 150 void AndroidStreamReaderURLRequestJob::OnReaderReadCompleted(int result) { |
105 int result) { | |
106 // The URLRequest API contract requires that: | 151 // The URLRequest API contract requires that: |
107 // * NotifyDone be called once, to set the status code, indicate the job is | 152 // * NotifyDone be called once, to set the status code, indicate the job is |
108 // finished (there will be no further IO), | 153 // finished (there will be no further IO), |
109 // * NotifyReadComplete be called if false is returned from ReadRawData to | 154 // * NotifyReadComplete be called if false is returned from ReadRawData to |
110 // indicate that the IOBuffer will not be used by the job anymore. | 155 // 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 | 156 // There might be multiple calls to ReadRawData (and thus multiple calls to |
112 // NotifyReadComplete), which is why NotifyDone is called only on errors | 157 // NotifyReadComplete), which is why NotifyDone is called only on errors |
113 // (result < 0) and end of data (result == 0). | 158 // (result < 0) and end of data (result == 0). |
114 if (result == 0) { | 159 if (result == 0) { |
115 NotifyDone(net::URLRequestStatus()); | 160 NotifyDone(net::URLRequestStatus()); |
116 } else if (result < 0) { | 161 } else if (result < 0) { |
117 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); | 162 NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result)); |
118 } else { | 163 } else { |
119 // Clear the IO_PENDING status. | 164 // Clear the IO_PENDING status. |
120 SetStatus(net::URLRequestStatus()); | 165 SetStatus(net::URLRequestStatus()); |
121 } | 166 } |
122 NotifyReadComplete(result); | 167 NotifyReadComplete(result); |
123 } | 168 } |
124 | 169 |
125 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { | 170 base::TaskRunner* AndroidStreamReaderURLRequestJob::GetWorkerThreadRunner() { |
126 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); | 171 return static_cast<base::TaskRunner*>(BrowserThread::GetBlockingPool()); |
127 } | 172 } |
128 | 173 |
129 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, | 174 bool AndroidStreamReaderURLRequestJob::ReadRawData(net::IOBuffer* dest, |
130 int dest_size, | 175 int dest_size, |
131 int* bytes_read) { | 176 int* bytes_read) { |
132 DCHECK(input_stream_reader_); | 177 DCHECK(input_stream_reader_wrapper_); |
133 | 178 |
134 PostTaskAndReplyWithResult( | 179 PostTaskAndReplyWithResult( |
135 GetWorkerThreadRunner(), | 180 GetWorkerThreadRunner(), |
136 FROM_HERE, | 181 FROM_HERE, |
137 base::Bind(&InputStreamReader::ReadRawData, | 182 base::Bind(&InputStreamReaderWrapper::ReadRawData, |
138 input_stream_reader_, | 183 input_stream_reader_wrapper_, |
139 base::Unretained(dest), | 184 make_scoped_refptr(dest), |
140 dest_size), | 185 dest_size), |
141 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, | 186 base::Bind(&AndroidStreamReaderURLRequestJob::OnReaderReadCompleted, |
142 weak_factory_.GetWeakPtr())); | 187 weak_factory_.GetWeakPtr())); |
143 | 188 |
144 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0)); | 189 SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, |
| 190 net::ERR_IO_PENDING)); |
145 return false; | 191 return false; |
146 } | 192 } |
147 | 193 |
148 bool AndroidStreamReaderURLRequestJob::GetMimeType( | 194 bool AndroidStreamReaderURLRequestJob::GetMimeType( |
149 std::string* mime_type) const { | 195 std::string* mime_type) const { |
150 JNIEnv* env = AttachCurrentThread(); | 196 JNIEnv* env = AttachCurrentThread(); |
151 DCHECK(env); | 197 DCHECK(env); |
152 | 198 |
153 if (!stream_) | 199 if (!input_stream_reader_wrapper_) |
154 return false; | 200 return false; |
155 | 201 |
156 return delegate_->GetMimeType(env, request(), *stream_, mime_type); | 202 // Since it's possible for this call to alter the InputStream a |
| 203 // Seek or ReadRawData operation running in the background is not permitted. |
| 204 DCHECK(!request_->status().is_io_pending()); |
| 205 |
| 206 return delegate_->GetMimeType( |
| 207 env, request(), input_stream_reader_wrapper_->input_stream(), mime_type); |
157 } | 208 } |
158 | 209 |
159 bool AndroidStreamReaderURLRequestJob::GetCharset( | 210 bool AndroidStreamReaderURLRequestJob::GetCharset(std::string* charset) { |
160 std::string* charset) { | |
161 JNIEnv* env = AttachCurrentThread(); | 211 JNIEnv* env = AttachCurrentThread(); |
162 DCHECK(env); | 212 DCHECK(env); |
163 | 213 |
164 if (!stream_) | 214 if (!input_stream_reader_wrapper_) |
165 return false; | 215 return false; |
166 | 216 |
167 return delegate_->GetCharset(env, request(), *stream_, charset); | 217 // Since it's possible for this call to alter the InputStream a |
| 218 // Seek or ReadRawData operation running in the background is not permitted. |
| 219 DCHECK(!request_->status().is_io_pending()); |
| 220 |
| 221 return delegate_->GetCharset( |
| 222 env, request(), input_stream_reader_wrapper_->input_stream(), charset); |
168 } | 223 } |
169 | 224 |
170 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( | 225 void AndroidStreamReaderURLRequestJob::SetExtraRequestHeaders( |
171 const net::HttpRequestHeaders& headers) { | 226 const net::HttpRequestHeaders& headers) { |
172 std::string range_header; | 227 std::string range_header; |
173 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { | 228 if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) { |
174 // We only extract the "Range" header so that we know how many bytes in the | 229 // We only extract the "Range" header so that we know how many bytes in the |
175 // stream to skip and how many to read after that. | 230 // stream to skip and how many to read after that. |
176 std::vector<net::HttpByteRange> ranges; | 231 std::vector<net::HttpByteRange> ranges; |
177 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { | 232 if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) { |
178 if (ranges.size() == 1) { | 233 if (ranges.size() == 1) { |
179 byte_range_ = ranges[0]; | 234 byte_range_ = ranges[0]; |
180 } else { | 235 } else { |
181 // We don't support multiple range requests in one single URL request, | 236 // We don't support multiple range requests in one single URL request, |
182 // because we need to do multipart encoding here. | 237 // because we need to do multipart encoding here. |
183 NotifyDone(net::URLRequestStatus( | 238 NotifyDone(net::URLRequestStatus( |
184 net::URLRequestStatus::FAILED, | 239 net::URLRequestStatus::FAILED, |
185 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); | 240 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE)); |
186 } | 241 } |
187 } | 242 } |
188 } | 243 } |
189 } | 244 } |
OLD | NEW |