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_peer.h"
7 #include "base/strings/string_number_conversions.h"
8 #include "net/base/load_flags.h"
9 #include "net/http/http_status_code.h"
13 static const size_t kBufferSizeIncrement
= 8192;
15 // Fragment automatically inserted in the User-Agent header to indicate
16 // that the request is coming from this network stack.
17 static const char kUserAgentFragment
[] = "; ChromiumJNI/";
19 URLRequestPeer::URLRequestPeer(URLRequestContextPeer
* context
,
20 URLRequestPeerDelegate
* delegate
,
22 net::RequestPriority priority
)
25 read_buffer_(new net::GrowableIOBuffer()),
32 streaming_upload_(false) {
39 URLRequestPeer::~URLRequestPeer() { CHECK(url_request_
== NULL
); }
41 void URLRequestPeer::SetMethod(const std::string
& method
) { method_
= method
; }
43 void URLRequestPeer::AddHeader(const std::string
& name
,
44 const std::string
& value
) {
45 headers_
.SetHeader(name
, value
);
48 void URLRequestPeer::SetPostContent(const char* bytes
, int bytes_len
) {
49 if (!upload_data_stream_
) {
50 upload_data_stream_
.reset(
51 new net::UploadDataStream(net::UploadDataStream::CHUNKED
, 0));
53 upload_data_stream_
->AppendChunk(bytes
, bytes_len
, true /* is_last_chunk */);
56 void URLRequestPeer::EnableStreamingUpload() { streaming_upload_
= true; }
58 void URLRequestPeer::AppendChunk(const char* bytes
,
61 VLOG(context_
->logging_level()) << "AppendChunk, len: " << bytes_len
62 << ", last: " << is_last_chunk
;
64 context_
->GetNetworkTaskRunner()->PostTask(
66 base::Bind(&URLRequestPeer::OnAppendChunk
,
67 base::Unretained(this),
73 void URLRequestPeer::Start() {
74 context_
->GetNetworkTaskRunner()->PostTask(
76 base::Bind(&URLRequestPeer::OnInitiateConnection
,
77 base::Unretained(this)));
80 void URLRequestPeer::OnAppendChunk(const char* bytes
,
83 if (url_request_
!= NULL
) {
84 url_request_
->AppendChunkToUpload(bytes
, bytes_len
, is_last_chunk
);
85 delegate_
->OnAppendChunkCompleted(this);
89 void URLRequestPeer::OnInitiateConnection() {
94 VLOG(context_
->logging_level())
95 << "Starting chromium request: " << url_
.possibly_invalid_spec().c_str()
96 << " priority: " << RequestPriorityToString(priority_
);
97 url_request_
= new net::URLRequest(
98 url_
, net::DEFAULT_PRIORITY
, this, context_
->GetURLRequestContext());
99 url_request_
->SetLoadFlags(net::LOAD_DISABLE_CACHE
|
100 net::LOAD_DO_NOT_SAVE_COOKIES
|
101 net::LOAD_DO_NOT_SEND_COOKIES
);
102 url_request_
->set_method(method_
);
103 url_request_
->SetExtraRequestHeaders(headers_
);
104 std::string user_agent
;
105 if (headers_
.HasHeader(net::HttpRequestHeaders::kUserAgent
)) {
106 headers_
.GetHeader(net::HttpRequestHeaders::kUserAgent
, &user_agent
);
108 user_agent
= context_
->GetUserAgent(url_
);
110 size_t pos
= user_agent
.find(')');
111 if (pos
!= std::string::npos
) {
112 user_agent
.insert(pos
, context_
->version());
113 user_agent
.insert(pos
, kUserAgentFragment
);
115 url_request_
->SetExtraRequestHeaderByName(
116 net::HttpRequestHeaders::kUserAgent
, user_agent
, true /* override */);
118 VLOG(context_
->logging_level()) << "User agent: " << user_agent
;
120 if (upload_data_stream_
) {
121 url_request_
->set_upload(make_scoped_ptr(upload_data_stream_
.release()));
122 } else if (streaming_upload_
) {
123 url_request_
->EnableChunkedUpload();
126 url_request_
->SetPriority(priority_
);
128 url_request_
->Start();
131 void URLRequestPeer::Cancel() {
138 context_
->GetNetworkTaskRunner()->PostTask(
140 base::Bind(&URLRequestPeer::OnCancelRequest
, base::Unretained(this)));
143 void URLRequestPeer::OnCancelRequest() {
144 VLOG(context_
->logging_level())
145 << "Canceling chromium request: " << url_
.possibly_invalid_spec();
147 if (url_request_
!= NULL
) {
148 url_request_
->Cancel();
154 void URLRequestPeer::Destroy() {
155 context_
->GetNetworkTaskRunner()->PostTask(
156 FROM_HERE
, base::Bind(&URLRequestPeer::OnDestroyRequest
, this));
160 void URLRequestPeer::OnDestroyRequest(URLRequestPeer
* self
) {
161 VLOG(self
->context_
->logging_level())
162 << "Destroying chromium request: " << self
->url_
.possibly_invalid_spec();
166 void URLRequestPeer::OnResponseStarted(net::URLRequest
* request
) {
167 if (request
->status().status() != net::URLRequestStatus::SUCCESS
) {
172 http_status_code_
= request
->GetResponseCode();
173 VLOG(context_
->logging_level())
174 << "Response started with status: " << http_status_code_
;
176 request
->GetResponseHeaderByName("Content-Type", &content_type_
);
177 expected_size_
= request
->GetExpectedContentSize();
178 delegate_
->OnResponseStarted(this);
183 // Reads all available data or starts an asynchronous read.
184 void URLRequestPeer::Read() {
186 if (read_buffer_
->RemainingCapacity() == 0) {
187 int new_capacity
= read_buffer_
->capacity() + kBufferSizeIncrement
;
188 read_buffer_
->SetCapacity(new_capacity
);
192 if (url_request_
->Read(
193 read_buffer_
, read_buffer_
->RemainingCapacity(), &bytes_read
)) {
194 if (bytes_read
== 0) {
195 OnRequestSucceeded();
199 VLOG(context_
->logging_level()) << "Synchronously read: " << bytes_read
201 OnBytesRead(bytes_read
);
202 } else if (url_request_
->status().status() ==
203 net::URLRequestStatus::IO_PENDING
) {
204 if (bytes_read_
!= 0) {
205 VLOG(context_
->logging_level()) << "Flushing buffer: " << bytes_read_
208 delegate_
->OnBytesRead(this);
209 read_buffer_
->set_offset(0);
212 VLOG(context_
->logging_level()) << "Started async read";
221 void URLRequestPeer::OnReadCompleted(net::URLRequest
* request
, int bytes_read
) {
222 VLOG(context_
->logging_level()) << "Asynchronously read: " << bytes_read
224 if (bytes_read
< 0) {
227 } else if (bytes_read
== 0) {
228 OnRequestSucceeded();
232 OnBytesRead(bytes_read
);
236 void URLRequestPeer::OnBytesRead(int bytes_read
) {
237 read_buffer_
->set_offset(read_buffer_
->offset() + bytes_read
);
238 bytes_read_
+= bytes_read
;
239 total_bytes_read_
+= bytes_read
;
242 void URLRequestPeer::OnRequestSucceeded() {
247 VLOG(context_
->logging_level())
248 << "Request completed with HTTP status: " << http_status_code_
249 << ". Total bytes read: " << total_bytes_read_
;
251 OnRequestCompleted();
254 void URLRequestPeer::OnRequestFailed() {
259 error_code_
= url_request_
->status().error();
260 VLOG(context_
->logging_level())
261 << "Request failed with status: " << url_request_
->status().status()
262 << " and error: " << net::ErrorToString(error_code_
);
263 OnRequestCompleted();
266 void URLRequestPeer::OnRequestCanceled() { OnRequestCompleted(); }
268 void URLRequestPeer::OnRequestCompleted() {
269 VLOG(context_
->logging_level())
270 << "Completed: " << url_
.possibly_invalid_spec();
271 if (url_request_
!= NULL
) {
276 delegate_
->OnBytesRead(this);
277 delegate_
->OnRequestFinished(this);
280 unsigned char* URLRequestPeer::Data() const {
281 return reinterpret_cast<unsigned char*>(read_buffer_
->StartOfBuffer());
284 } // namespace cronet