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.
5 #include "url_request_adapter.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "components/cronet/android/url_request_context_adapter.h"
15 #include "components/cronet/android/wrapped_channel_upload_element_reader.h"
16 #include "net/base/elements_upload_data_stream.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/http/http_response_headers.h"
21 #include "net/http/http_status_code.h"
25 static const size_t kReadBufferSize
= 32768;
27 URLRequestAdapter::URLRequestAdapter(URLRequestContextAdapter
* context
,
28 URLRequestAdapterDelegate
* delegate
,
30 net::RequestPriority priority
)
37 chunked_upload_(false),
38 disable_redirect_(false) {
45 URLRequestAdapter::~URLRequestAdapter() {
46 DCHECK(OnNetworkThread());
47 CHECK(url_request_
== NULL
);
50 void URLRequestAdapter::SetMethod(const std::string
& method
) {
54 void URLRequestAdapter::AddHeader(const std::string
& name
,
55 const std::string
& value
) {
56 headers_
.SetHeader(name
, value
);
59 void URLRequestAdapter::SetUploadContent(const char* bytes
, int bytes_len
) {
60 std::vector
<char> data(bytes
, bytes
+ bytes_len
);
61 scoped_ptr
<net::UploadElementReader
> reader(
62 new net::UploadOwnedBytesElementReader(&data
));
64 net::ElementsUploadDataStream::CreateWithReader(reader
.Pass(), 0);
67 void URLRequestAdapter::SetUploadChannel(JNIEnv
* env
, int64 content_length
) {
68 scoped_ptr
<net::UploadElementReader
> reader(
69 new WrappedChannelElementReader(delegate_
, content_length
));
71 net::ElementsUploadDataStream::CreateWithReader(reader
.Pass(), 0);
74 void URLRequestAdapter::DisableRedirects() {
75 disable_redirect_
= true;
78 void URLRequestAdapter::EnableChunkedUpload() {
79 chunked_upload_
= true;
82 void URLRequestAdapter::AppendChunk(const char* bytes
, int bytes_len
,
84 VLOG(1) << "AppendChunk, len: " << bytes_len
<< ", last: " << is_last_chunk
;
85 scoped_ptr
<char[]> buf(new char[bytes_len
]);
86 memcpy(buf
.get(), bytes
, bytes_len
);
87 context_
->PostTaskToNetworkThread(
89 base::Bind(&URLRequestAdapter::OnAppendChunk
,
90 base::Unretained(this),
96 std::string
URLRequestAdapter::GetHeader(const std::string
& name
) const {
98 if (url_request_
!= NULL
) {
99 url_request_
->GetResponseHeaderByName(name
, &value
);
104 net::HttpResponseHeaders
* URLRequestAdapter::GetResponseHeaders() const {
105 if (url_request_
== NULL
) {
108 return url_request_
->response_headers();
111 std::string
URLRequestAdapter::GetNegotiatedProtocol() const {
112 if (url_request_
== NULL
)
113 return std::string();
114 return url_request_
->response_info().npn_negotiated_protocol
;
117 bool URLRequestAdapter::GetWasCached() const {
118 if (url_request_
== NULL
)
120 return url_request_
->response_info().was_cached
;
123 void URLRequestAdapter::Start() {
124 context_
->PostTaskToNetworkThread(
126 base::Bind(&URLRequestAdapter::OnInitiateConnection
,
127 base::Unretained(this)));
130 void URLRequestAdapter::OnAppendChunk(const scoped_ptr
<char[]> bytes
,
131 int bytes_len
, bool is_last_chunk
) {
132 DCHECK(OnNetworkThread());
133 // Request could have completed and been destroyed on the network thread
134 // while appendChunk was posting the task from an application thread.
136 VLOG(1) << "Cannot append chunk to destroyed request: "
137 << url_
.possibly_invalid_spec().c_str();
140 url_request_
->AppendChunkToUpload(bytes
.get(), bytes_len
, is_last_chunk
);
143 void URLRequestAdapter::OnInitiateConnection() {
144 DCHECK(OnNetworkThread());
149 VLOG(1) << "Starting chromium request: "
150 << url_
.possibly_invalid_spec().c_str()
151 << " priority: " << RequestPriorityToString(priority_
);
152 url_request_
= context_
->GetURLRequestContext()->CreateRequest(
153 url_
, net::DEFAULT_PRIORITY
, this);
154 int flags
= net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
;
155 if (context_
->load_disable_cache())
156 flags
|= net::LOAD_DISABLE_CACHE
;
157 url_request_
->SetLoadFlags(flags
);
158 url_request_
->set_method(method_
);
159 url_request_
->SetExtraRequestHeaders(headers_
);
160 if (!headers_
.HasHeader(net::HttpRequestHeaders::kUserAgent
)) {
161 std::string user_agent
;
162 user_agent
= context_
->GetUserAgent(url_
);
163 url_request_
->SetExtraRequestHeaderByName(
164 net::HttpRequestHeaders::kUserAgent
, user_agent
, true /* override */);
167 if (upload_data_stream_
) {
168 url_request_
->set_upload(upload_data_stream_
.Pass());
169 } else if (chunked_upload_
) {
170 url_request_
->EnableChunkedUpload();
173 url_request_
->SetPriority(priority_
);
175 url_request_
->Start();
178 void URLRequestAdapter::Cancel() {
179 context_
->PostTaskToNetworkThread(
181 base::Bind(&URLRequestAdapter::OnCancelRequest
, base::Unretained(this)));
184 void URLRequestAdapter::OnCancelRequest() {
185 DCHECK(OnNetworkThread());
187 VLOG(1) << "Canceling chromium request: " << url_
.possibly_invalid_spec();
189 // Check whether request has already completed.
190 if (url_request_
== nullptr)
193 url_request_
->Cancel();
194 OnRequestCompleted();
197 void URLRequestAdapter::Destroy() {
198 context_
->PostTaskToNetworkThread(
199 FROM_HERE
, base::Bind(&URLRequestAdapter::OnDestroyRequest
, this));
203 void URLRequestAdapter::OnDestroyRequest(URLRequestAdapter
* self
) {
204 DCHECK(self
->OnNetworkThread());
205 VLOG(1) << "Destroying chromium request: "
206 << self
->url_
.possibly_invalid_spec();
211 void URLRequestAdapter::OnResponseStarted(net::URLRequest
* request
) {
212 DCHECK(OnNetworkThread());
213 if (request
->status().status() != net::URLRequestStatus::SUCCESS
) {
218 http_status_code_
= request
->GetResponseCode();
219 VLOG(1) << "Response started with status: " << http_status_code_
;
221 net::HttpResponseHeaders
* headers
= request
->response_headers();
223 http_status_text_
= headers
->GetStatusText();
225 request
->GetResponseHeaderByName("Content-Type", &content_type_
);
226 expected_size_
= request
->GetExpectedContentSize();
227 delegate_
->OnResponseStarted(this);
232 // Reads all available data or starts an asynchronous read.
233 void URLRequestAdapter::Read() {
234 DCHECK(OnNetworkThread());
235 if (!read_buffer_
.get())
236 read_buffer_
= new net::IOBufferWithSize(kReadBufferSize
);
240 url_request_
->Read(read_buffer_
.get(), kReadBufferSize
, &bytes_read
);
241 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
242 if (url_request_
->status().is_io_pending())
244 // Stop when request has failed or succeeded.
245 if (!HandleReadResult(bytes_read
))
250 bool URLRequestAdapter::HandleReadResult(int bytes_read
) {
251 DCHECK(OnNetworkThread());
252 if (!url_request_
->status().is_success()) {
255 } else if (bytes_read
== 0) {
256 OnRequestSucceeded();
260 total_bytes_read_
+= bytes_read
;
261 delegate_
->OnBytesRead(this, bytes_read
);
266 void URLRequestAdapter::OnReadCompleted(net::URLRequest
* request
,
268 if (!HandleReadResult(bytes_read
))
274 void URLRequestAdapter::OnReceivedRedirect(net::URLRequest
* request
,
275 const net::RedirectInfo
& info
,
276 bool* defer_redirect
) {
277 DCHECK(OnNetworkThread());
278 if (disable_redirect_
) {
279 http_status_code_
= request
->GetResponseCode();
280 request
->CancelWithError(net::ERR_TOO_MANY_REDIRECTS
);
281 error_code_
= net::ERR_TOO_MANY_REDIRECTS
;
283 *defer_redirect
= false;
284 OnRequestCompleted();
288 void URLRequestAdapter::OnRequestSucceeded() {
289 DCHECK(OnNetworkThread());
294 VLOG(1) << "Request completed with HTTP status: " << http_status_code_
295 << ". Total bytes read: " << total_bytes_read_
;
297 OnRequestCompleted();
300 void URLRequestAdapter::OnRequestFailed() {
301 DCHECK(OnNetworkThread());
306 error_code_
= url_request_
->status().error();
307 VLOG(1) << "Request failed with status: " << url_request_
->status().status()
308 << " and error: " << net::ErrorToString(error_code_
);
309 OnRequestCompleted();
312 void URLRequestAdapter::OnRequestCompleted() {
313 DCHECK(OnNetworkThread());
314 VLOG(1) << "Completed: " << url_
.possibly_invalid_spec();
316 DCHECK(url_request_
!= nullptr);
318 delegate_
->OnRequestFinished(this);
319 url_request_
.reset();
322 unsigned char* URLRequestAdapter::Data() const {
323 DCHECK(OnNetworkThread());
324 return reinterpret_cast<unsigned char*>(read_buffer_
->data());
327 bool URLRequestAdapter::OnNetworkThread() const {
328 return context_
->GetNetworkTaskRunner()->BelongsToCurrentThread();
331 } // namespace cronet