OLD | NEW |
| (Empty) |
1 // Copyright 2014 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 "components/cronet/android/url_request_adapter.h" | |
6 | |
7 #include <stddef.h> | |
8 #include <string.h> | |
9 #include <utility> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/location.h" | |
13 #include "base/logging.h" | |
14 #include "base/single_thread_task_runner.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "components/cronet/android/url_request_context_adapter.h" | |
17 #include "components/cronet/android/wrapped_channel_upload_element_reader.h" | |
18 #include "net/base/elements_upload_data_stream.h" | |
19 #include "net/base/load_flags.h" | |
20 #include "net/base/net_errors.h" | |
21 #include "net/base/upload_bytes_element_reader.h" | |
22 #include "net/http/http_response_headers.h" | |
23 #include "net/http/http_status_code.h" | |
24 | |
25 namespace cronet { | |
26 | |
27 static const size_t kReadBufferSize = 32768; | |
28 | |
29 URLRequestAdapter::URLRequestAdapter(URLRequestContextAdapter* context, | |
30 URLRequestAdapterDelegate* delegate, | |
31 GURL url, | |
32 net::RequestPriority priority) | |
33 : method_("GET"), | |
34 total_bytes_read_(0), | |
35 error_code_(0), | |
36 http_status_code_(0), | |
37 canceled_(false), | |
38 expected_size_(0), | |
39 chunked_upload_(false), | |
40 disable_redirect_(false) { | |
41 context_ = context; | |
42 delegate_ = delegate; | |
43 url_ = url; | |
44 priority_ = priority; | |
45 } | |
46 | |
47 URLRequestAdapter::~URLRequestAdapter() { | |
48 DCHECK(OnNetworkThread()); | |
49 CHECK(url_request_ == NULL); | |
50 } | |
51 | |
52 void URLRequestAdapter::SetMethod(const std::string& method) { | |
53 method_ = method; | |
54 } | |
55 | |
56 void URLRequestAdapter::AddHeader(const std::string& name, | |
57 const std::string& value) { | |
58 headers_.SetHeader(name, value); | |
59 } | |
60 | |
61 void URLRequestAdapter::SetUploadContent(const char* bytes, int bytes_len) { | |
62 std::vector<char> data(bytes, bytes + bytes_len); | |
63 std::unique_ptr<net::UploadElementReader> reader( | |
64 new net::UploadOwnedBytesElementReader(&data)); | |
65 upload_data_stream_ = | |
66 net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0); | |
67 } | |
68 | |
69 void URLRequestAdapter::SetUploadChannel(JNIEnv* env, int64_t content_length) { | |
70 std::unique_ptr<net::UploadElementReader> reader( | |
71 new WrappedChannelElementReader(delegate_, content_length)); | |
72 upload_data_stream_ = | |
73 net::ElementsUploadDataStream::CreateWithReader(std::move(reader), 0); | |
74 } | |
75 | |
76 void URLRequestAdapter::DisableRedirects() { | |
77 disable_redirect_ = true; | |
78 } | |
79 | |
80 void URLRequestAdapter::EnableChunkedUpload() { | |
81 chunked_upload_ = true; | |
82 } | |
83 | |
84 void URLRequestAdapter::AppendChunk(const char* bytes, int bytes_len, | |
85 bool is_last_chunk) { | |
86 VLOG(1) << "AppendChunk, len: " << bytes_len << ", last: " << is_last_chunk; | |
87 std::unique_ptr<char[]> buf(new char[bytes_len]); | |
88 memcpy(buf.get(), bytes, bytes_len); | |
89 context_->PostTaskToNetworkThread( | |
90 FROM_HERE, | |
91 base::Bind(&URLRequestAdapter::OnAppendChunk, base::Unretained(this), | |
92 base::Passed(&buf), bytes_len, is_last_chunk)); | |
93 } | |
94 | |
95 std::string URLRequestAdapter::GetHeader(const std::string& name) const { | |
96 std::string value; | |
97 if (url_request_ != NULL) { | |
98 url_request_->GetResponseHeaderByName(name, &value); | |
99 } | |
100 return value; | |
101 } | |
102 | |
103 net::HttpResponseHeaders* URLRequestAdapter::GetResponseHeaders() const { | |
104 if (url_request_ == NULL) { | |
105 return NULL; | |
106 } | |
107 return url_request_->response_headers(); | |
108 } | |
109 | |
110 std::string URLRequestAdapter::GetNegotiatedProtocol() const { | |
111 if (url_request_ == NULL) | |
112 return std::string(); | |
113 return url_request_->response_info().alpn_negotiated_protocol; | |
114 } | |
115 | |
116 bool URLRequestAdapter::GetWasCached() const { | |
117 if (url_request_ == NULL) | |
118 return false; | |
119 return url_request_->response_info().was_cached; | |
120 } | |
121 | |
122 void URLRequestAdapter::Start() { | |
123 context_->PostTaskToNetworkThread( | |
124 FROM_HERE, | |
125 base::Bind(&URLRequestAdapter::OnInitiateConnection, | |
126 base::Unretained(this))); | |
127 } | |
128 | |
129 void URLRequestAdapter::OnAppendChunk(const std::unique_ptr<char[]> bytes, | |
130 int bytes_len, | |
131 bool is_last_chunk) { | |
132 DCHECK(OnNetworkThread()); | |
133 // If AppendData returns false, the request has been cancelled or completed | |
134 // without uploading the entire request body. Either way, that result will | |
135 // have been sent to the embedder, so there's nothing else to do here. | |
136 chunked_upload_writer_->AppendData(bytes.get(), bytes_len, is_last_chunk); | |
137 } | |
138 | |
139 void URLRequestAdapter::OnInitiateConnection() { | |
140 DCHECK(OnNetworkThread()); | |
141 if (canceled_) { | |
142 return; | |
143 } | |
144 | |
145 VLOG(1) << "Starting chromium request: " | |
146 << url_.possibly_invalid_spec().c_str() | |
147 << " priority: " << RequestPriorityToString(priority_); | |
148 url_request_ = context_->GetURLRequestContext()->CreateRequest( | |
149 url_, net::DEFAULT_PRIORITY, this); | |
150 int flags = net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES; | |
151 if (context_->load_disable_cache()) | |
152 flags |= net::LOAD_DISABLE_CACHE; | |
153 url_request_->SetLoadFlags(flags); | |
154 url_request_->set_method(method_); | |
155 url_request_->SetExtraRequestHeaders(headers_); | |
156 if (!headers_.HasHeader(net::HttpRequestHeaders::kUserAgent)) { | |
157 std::string user_agent; | |
158 user_agent = context_->GetUserAgent(url_); | |
159 url_request_->SetExtraRequestHeaderByName( | |
160 net::HttpRequestHeaders::kUserAgent, user_agent, true /* override */); | |
161 } | |
162 | |
163 if (upload_data_stream_) { | |
164 url_request_->set_upload(std::move(upload_data_stream_)); | |
165 } else if (chunked_upload_) { | |
166 std::unique_ptr<net::ChunkedUploadDataStream> chunked_upload_data_stream( | |
167 new net::ChunkedUploadDataStream(0)); | |
168 // Create a ChunkedUploadDataStream::Writer, which keeps a weak reference to | |
169 // the UploadDataStream, before passing ownership of the stream to the | |
170 // URLRequest. | |
171 chunked_upload_writer_ = chunked_upload_data_stream->CreateWriter(); | |
172 url_request_->set_upload(std::move(chunked_upload_data_stream)); | |
173 } | |
174 | |
175 url_request_->SetPriority(priority_); | |
176 | |
177 url_request_->Start(); | |
178 } | |
179 | |
180 void URLRequestAdapter::Cancel() { | |
181 context_->PostTaskToNetworkThread( | |
182 FROM_HERE, | |
183 base::Bind(&URLRequestAdapter::OnCancelRequest, base::Unretained(this))); | |
184 } | |
185 | |
186 void URLRequestAdapter::OnCancelRequest() { | |
187 DCHECK(OnNetworkThread()); | |
188 DCHECK(!canceled_); | |
189 VLOG(1) << "Canceling chromium request: " << url_.possibly_invalid_spec(); | |
190 canceled_ = true; | |
191 // Check whether request has already completed. | |
192 if (url_request_ == nullptr) | |
193 return; | |
194 | |
195 url_request_->Cancel(); | |
196 OnRequestCompleted(); | |
197 } | |
198 | |
199 void URLRequestAdapter::Destroy() { | |
200 context_->PostTaskToNetworkThread( | |
201 FROM_HERE, base::Bind(&URLRequestAdapter::OnDestroyRequest, this)); | |
202 } | |
203 | |
204 // static | |
205 void URLRequestAdapter::OnDestroyRequest(URLRequestAdapter* self) { | |
206 DCHECK(self->OnNetworkThread()); | |
207 VLOG(1) << "Destroying chromium request: " | |
208 << self->url_.possibly_invalid_spec(); | |
209 delete self; | |
210 } | |
211 | |
212 // static | |
213 void URLRequestAdapter::OnResponseStarted(net::URLRequest* request, | |
214 int net_error) { | |
215 DCHECK_NE(net::ERR_IO_PENDING, net_error); | |
216 DCHECK(OnNetworkThread()); | |
217 | |
218 if (net_error != net::OK) { | |
219 OnRequestFailed(net_error); | |
220 return; | |
221 } | |
222 | |
223 http_status_code_ = request->GetResponseCode(); | |
224 VLOG(1) << "Response started with status: " << http_status_code_; | |
225 | |
226 net::HttpResponseHeaders* headers = request->response_headers(); | |
227 if (headers) | |
228 http_status_text_ = headers->GetStatusText(); | |
229 | |
230 request->GetResponseHeaderByName("Content-Type", &content_type_); | |
231 expected_size_ = request->GetExpectedContentSize(); | |
232 delegate_->OnResponseStarted(this); | |
233 | |
234 Read(); | |
235 } | |
236 | |
237 // Reads all available data or starts an asynchronous read. | |
238 void URLRequestAdapter::Read() { | |
239 DCHECK(OnNetworkThread()); | |
240 if (!read_buffer_.get()) | |
241 read_buffer_ = new net::IOBufferWithSize(kReadBufferSize); | |
242 | |
243 while(true) { | |
244 int result = url_request_->Read(read_buffer_.get(), kReadBufferSize); | |
245 // If IO is pending, wait for the URLRequest to call OnReadCompleted. | |
246 if (result == net::ERR_IO_PENDING) | |
247 return; | |
248 // Stop when request has failed or succeeded. | |
249 if (!HandleReadResult(result)) | |
250 return; | |
251 } | |
252 } | |
253 | |
254 bool URLRequestAdapter::HandleReadResult(int result) { | |
255 DCHECK(OnNetworkThread()); | |
256 if (result < 0) { | |
257 OnRequestFailed(result); | |
258 return false; | |
259 } | |
260 | |
261 if (result == 0) { | |
262 OnRequestSucceeded(); | |
263 return false; | |
264 } | |
265 | |
266 total_bytes_read_ += result; | |
267 delegate_->OnBytesRead(this, result); | |
268 | |
269 return true; | |
270 } | |
271 | |
272 void URLRequestAdapter::OnReadCompleted(net::URLRequest* request, | |
273 int bytes_read) { | |
274 DCHECK_NE(net::ERR_IO_PENDING, bytes_read); | |
275 if (!HandleReadResult(bytes_read)) | |
276 return; | |
277 | |
278 Read(); | |
279 } | |
280 | |
281 void URLRequestAdapter::OnReceivedRedirect(net::URLRequest* request, | |
282 const net::RedirectInfo& info, | |
283 bool* defer_redirect) { | |
284 DCHECK(OnNetworkThread()); | |
285 if (disable_redirect_) { | |
286 http_status_code_ = request->GetResponseCode(); | |
287 request->CancelWithError(net::ERR_TOO_MANY_REDIRECTS); | |
288 error_code_ = net::ERR_TOO_MANY_REDIRECTS; | |
289 canceled_ = true; | |
290 *defer_redirect = false; | |
291 OnRequestCompleted(); | |
292 } | |
293 } | |
294 | |
295 void URLRequestAdapter::OnRequestSucceeded() { | |
296 DCHECK(OnNetworkThread()); | |
297 if (canceled_) { | |
298 return; | |
299 } | |
300 | |
301 VLOG(1) << "Request completed with HTTP status: " << http_status_code_ | |
302 << ". Total bytes read: " << total_bytes_read_; | |
303 | |
304 OnRequestCompleted(); | |
305 } | |
306 | |
307 void URLRequestAdapter::OnRequestFailed(int net_error) { | |
308 DCHECK_LE(net_error, 0); | |
309 DCHECK_NE(net::ERR_IO_PENDING, net_error); | |
310 DCHECK(OnNetworkThread()); | |
311 if (canceled_) { | |
312 return; | |
313 } | |
314 | |
315 error_code_ = net_error; | |
316 VLOG(1) << "Request failed with error: " << net::ErrorToString(error_code_); | |
317 OnRequestCompleted(); | |
318 } | |
319 | |
320 void URLRequestAdapter::OnRequestCompleted() { | |
321 DCHECK(OnNetworkThread()); | |
322 VLOG(1) << "Completed: " << url_.possibly_invalid_spec(); | |
323 | |
324 DCHECK(url_request_ != nullptr); | |
325 | |
326 delegate_->OnRequestFinished(this); | |
327 url_request_.reset(); | |
328 } | |
329 | |
330 unsigned char* URLRequestAdapter::Data() const { | |
331 DCHECK(OnNetworkThread()); | |
332 return reinterpret_cast<unsigned char*>(read_buffer_->data()); | |
333 } | |
334 | |
335 bool URLRequestAdapter::OnNetworkThread() const { | |
336 return context_->GetNetworkTaskRunner()->BelongsToCurrentThread(); | |
337 } | |
338 | |
339 } // namespace cronet | |
OLD | NEW |