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 void URLRequestAdapter::Start() {
118 context_
->PostTaskToNetworkThread(
120 base::Bind(&URLRequestAdapter::OnInitiateConnection
,
121 base::Unretained(this)));
124 void URLRequestAdapter::OnAppendChunk(const scoped_ptr
<char[]> bytes
,
125 int bytes_len
, bool is_last_chunk
) {
126 DCHECK(OnNetworkThread());
127 // Request could have completed and been destroyed on the network thread
128 // while appendChunk was posting the task from an application thread.
130 VLOG(1) << "Cannot append chunk to destroyed request: "
131 << url_
.possibly_invalid_spec().c_str();
134 url_request_
->AppendChunkToUpload(bytes
.get(), bytes_len
, is_last_chunk
);
137 void URLRequestAdapter::OnInitiateConnection() {
138 DCHECK(OnNetworkThread());
143 VLOG(1) << "Starting chromium request: "
144 << url_
.possibly_invalid_spec().c_str()
145 << " priority: " << RequestPriorityToString(priority_
);
146 url_request_
= context_
->GetURLRequestContext()->CreateRequest(
147 url_
, net::DEFAULT_PRIORITY
, this, NULL
);
148 int flags
= net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
;
149 if (context_
->load_disable_cache())
150 flags
|= net::LOAD_DISABLE_CACHE
;
151 url_request_
->SetLoadFlags(flags
);
152 url_request_
->set_method(method_
);
153 url_request_
->SetExtraRequestHeaders(headers_
);
154 if (!headers_
.HasHeader(net::HttpRequestHeaders::kUserAgent
)) {
155 std::string user_agent
;
156 user_agent
= context_
->GetUserAgent(url_
);
157 url_request_
->SetExtraRequestHeaderByName(
158 net::HttpRequestHeaders::kUserAgent
, user_agent
, true /* override */);
161 if (upload_data_stream_
) {
162 url_request_
->set_upload(upload_data_stream_
.Pass());
163 } else if (chunked_upload_
) {
164 url_request_
->EnableChunkedUpload();
167 url_request_
->SetPriority(priority_
);
169 url_request_
->Start();
172 void URLRequestAdapter::Cancel() {
173 context_
->PostTaskToNetworkThread(
175 base::Bind(&URLRequestAdapter::OnCancelRequest
, base::Unretained(this)));
178 void URLRequestAdapter::OnCancelRequest() {
179 DCHECK(OnNetworkThread());
181 VLOG(1) << "Canceling chromium request: " << url_
.possibly_invalid_spec();
183 // Check whether request has already completed.
184 if (url_request_
== nullptr)
187 url_request_
->Cancel();
188 OnRequestCompleted();
191 void URLRequestAdapter::Destroy() {
192 context_
->PostTaskToNetworkThread(
193 FROM_HERE
, base::Bind(&URLRequestAdapter::OnDestroyRequest
, this));
197 void URLRequestAdapter::OnDestroyRequest(URLRequestAdapter
* self
) {
198 DCHECK(self
->OnNetworkThread());
199 VLOG(1) << "Destroying chromium request: "
200 << self
->url_
.possibly_invalid_spec();
205 void URLRequestAdapter::OnResponseStarted(net::URLRequest
* request
) {
206 DCHECK(OnNetworkThread());
207 if (request
->status().status() != net::URLRequestStatus::SUCCESS
) {
212 http_status_code_
= request
->GetResponseCode();
213 VLOG(1) << "Response started with status: " << http_status_code_
;
215 net::HttpResponseHeaders
* headers
= request
->response_headers();
217 http_status_text_
= headers
->GetStatusText();
219 request
->GetResponseHeaderByName("Content-Type", &content_type_
);
220 expected_size_
= request
->GetExpectedContentSize();
221 delegate_
->OnResponseStarted(this);
226 // Reads all available data or starts an asynchronous read.
227 void URLRequestAdapter::Read() {
228 DCHECK(OnNetworkThread());
229 if (!read_buffer_
.get())
230 read_buffer_
= new net::IOBufferWithSize(kReadBufferSize
);
234 url_request_
->Read(read_buffer_
.get(), kReadBufferSize
, &bytes_read
);
235 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
236 if (url_request_
->status().is_io_pending())
238 // Stop when request has failed or succeeded.
239 if (!HandleReadResult(bytes_read
))
244 bool URLRequestAdapter::HandleReadResult(int bytes_read
) {
245 DCHECK(OnNetworkThread());
246 if (!url_request_
->status().is_success()) {
249 } else if (bytes_read
== 0) {
250 OnRequestSucceeded();
254 total_bytes_read_
+= bytes_read
;
255 delegate_
->OnBytesRead(this, bytes_read
);
260 void URLRequestAdapter::OnReadCompleted(net::URLRequest
* request
,
262 if (!HandleReadResult(bytes_read
))
268 void URLRequestAdapter::OnReceivedRedirect(net::URLRequest
* request
,
269 const net::RedirectInfo
& info
,
270 bool* defer_redirect
) {
271 DCHECK(OnNetworkThread());
272 if (disable_redirect_
) {
273 http_status_code_
= request
->GetResponseCode();
274 request
->CancelWithError(net::ERR_TOO_MANY_REDIRECTS
);
275 error_code_
= net::ERR_TOO_MANY_REDIRECTS
;
277 *defer_redirect
= false;
278 OnRequestCompleted();
282 void URLRequestAdapter::OnRequestSucceeded() {
283 DCHECK(OnNetworkThread());
288 VLOG(1) << "Request completed with HTTP status: " << http_status_code_
289 << ". Total bytes read: " << total_bytes_read_
;
291 OnRequestCompleted();
294 void URLRequestAdapter::OnRequestFailed() {
295 DCHECK(OnNetworkThread());
300 error_code_
= url_request_
->status().error();
301 VLOG(1) << "Request failed with status: " << url_request_
->status().status()
302 << " and error: " << net::ErrorToString(error_code_
);
303 OnRequestCompleted();
306 void URLRequestAdapter::OnRequestCompleted() {
307 DCHECK(OnNetworkThread());
308 VLOG(1) << "Completed: " << url_
.possibly_invalid_spec();
310 DCHECK(url_request_
!= nullptr);
312 delegate_
->OnRequestFinished(this);
313 url_request_
.reset();
316 unsigned char* URLRequestAdapter::Data() const {
317 DCHECK(OnNetworkThread());
318 return reinterpret_cast<unsigned char*>(read_buffer_
->data());
321 bool URLRequestAdapter::OnNetworkThread() const {
322 return context_
->GetNetworkTaskRunner()->BelongsToCurrentThread();
325 } // namespace cronet