Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / net / cronet / android / url_request_peer.cc
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 "url_request_peer.h"
6
7 #include "base/strings/string_number_conversions.h"
8 #include "net/base/load_flags.h"
9 #include "net/http/http_status_code.h"
10
11 static const size_t kBufferSizeIncrement = 8192;
12
13 // Fragment automatically inserted in the User-Agent header to indicate
14 // that the request is coming from this network stack.
15 static const char kUserAgentFragment[] = "; ChromiumJNI/";
16
17 URLRequestPeer::URLRequestPeer(URLRequestContextPeer* context,
18                                URLRequestPeerDelegate* delegate,
19                                GURL url,
20                                net::RequestPriority priority)
21     : method_("GET"),
22       url_request_(NULL),
23       read_buffer_(new net::GrowableIOBuffer()),
24       bytes_read_(0),
25       total_bytes_read_(0),
26       error_code_(0),
27       http_status_code_(0),
28       canceled_(false),
29       expected_size_(0),
30       streaming_upload_(false) {
31   context_ = context;
32   delegate_ = delegate;
33   url_ = url;
34   priority_ = priority;
35 }
36
37 URLRequestPeer::~URLRequestPeer() { CHECK(url_request_ == NULL); }
38
39 void URLRequestPeer::SetMethod(const std::string& method) { method_ = method; }
40
41 void URLRequestPeer::AddHeader(const std::string& name,
42                                const std::string& value) {
43   headers_.SetHeader(name, value);
44 }
45
46 void URLRequestPeer::SetPostContent(const char* bytes, int bytes_len) {
47   if (!upload_data_stream_) {
48     upload_data_stream_.reset(
49         new net::UploadDataStream(net::UploadDataStream::CHUNKED, 0));
50   }
51   upload_data_stream_->AppendChunk(bytes, bytes_len, true /* is_last_chunk */);
52 }
53
54 void URLRequestPeer::EnableStreamingUpload() { streaming_upload_ = true; }
55
56 void URLRequestPeer::AppendChunk(const char* bytes,
57                                  int bytes_len,
58                                  bool is_last_chunk) {
59   VLOG(context_->logging_level()) << "AppendChunk, len: " << bytes_len
60                                   << ", last: " << is_last_chunk;
61
62   context_->GetNetworkTaskRunner()->PostTask(
63       FROM_HERE,
64       base::Bind(&URLRequestPeer::OnAppendChunkWrapper,
65                  this,
66                  bytes,
67                  bytes_len,
68                  is_last_chunk));
69 }
70
71 void URLRequestPeer::Start() {
72   context_->GetNetworkTaskRunner()->PostTask(
73       FROM_HERE,
74       base::Bind(&URLRequestPeer::OnInitiateConnectionWrapper, this));
75 }
76
77 // static
78 void URLRequestPeer::OnAppendChunkWrapper(URLRequestPeer* self,
79                                           const char* bytes,
80                                           int bytes_len,
81                                           bool is_last_chunk) {
82   self->OnAppendChunk(bytes, bytes_len, is_last_chunk);
83 }
84
85 void URLRequestPeer::OnAppendChunk(const char* bytes,
86                                    int bytes_len,
87                                    bool is_last_chunk) {
88   if (url_request_ != NULL) {
89     url_request_->AppendChunkToUpload(bytes, bytes_len, is_last_chunk);
90     delegate_->OnAppendChunkCompleted(this);
91   }
92 }
93
94 // static
95 void URLRequestPeer::OnInitiateConnectionWrapper(URLRequestPeer* self) {
96   self->OnInitiateConnection();
97 }
98
99 void URLRequestPeer::OnInitiateConnection() {
100   if (canceled_) {
101     return;
102   }
103
104   VLOG(context_->logging_level())
105       << "Starting chromium request: " << url_.possibly_invalid_spec().c_str()
106       << " priority: " << RequestPriorityToString(priority_);
107   url_request_ = new net::URLRequest(
108       url_, net::DEFAULT_PRIORITY, this, context_->GetURLRequestContext());
109   url_request_->SetLoadFlags(net::LOAD_DISABLE_CACHE |
110                              net::LOAD_DO_NOT_SAVE_COOKIES |
111                              net::LOAD_DO_NOT_SEND_COOKIES);
112   url_request_->set_method(method_);
113   url_request_->SetExtraRequestHeaders(headers_);
114   std::string user_agent;
115   if (headers_.HasHeader(net::HttpRequestHeaders::kUserAgent)) {
116     headers_.GetHeader(net::HttpRequestHeaders::kUserAgent, &user_agent);
117   } else {
118     user_agent = context_->GetUserAgent(url_);
119   }
120   size_t pos = user_agent.find(')');
121   if (pos != std::string::npos) {
122     user_agent.insert(pos, context_->version());
123     user_agent.insert(pos, kUserAgentFragment);
124   }
125   url_request_->SetExtraRequestHeaderByName(
126       net::HttpRequestHeaders::kUserAgent, user_agent, true /* override */);
127
128   VLOG(context_->logging_level()) << "User agent: " << user_agent;
129
130   if (upload_data_stream_) {
131     url_request_->set_upload(make_scoped_ptr(upload_data_stream_.release()));
132   } else if (streaming_upload_) {
133     url_request_->EnableChunkedUpload();
134   }
135
136   url_request_->SetPriority(priority_);
137
138   url_request_->Start();
139 }
140
141 void URLRequestPeer::Cancel() {
142   if (canceled_) {
143     return;
144   }
145
146   canceled_ = true;
147
148   context_->GetNetworkTaskRunner()->PostTask(
149       FROM_HERE, base::Bind(&URLRequestPeer::OnCancelRequestWrapper, this));
150 }
151
152 // static
153 void URLRequestPeer::OnCancelRequestWrapper(URLRequestPeer* self) {
154   self->OnCancelRequest();
155 }
156
157 void URLRequestPeer::OnCancelRequest() {
158   VLOG(context_->logging_level())
159       << "Canceling chromium request: " << url_.possibly_invalid_spec();
160
161   if (url_request_ != NULL) {
162     url_request_->Cancel();
163   }
164
165   OnRequestCanceled();
166 }
167
168 void URLRequestPeer::Destroy() {
169   context_->GetNetworkTaskRunner()->PostTask(
170       FROM_HERE, base::Bind(&URLRequestPeer::OnDestroyRequest, this));
171 }
172
173 // static
174 void URLRequestPeer::OnDestroyRequest(URLRequestPeer* self) {
175   VLOG(self->context_->logging_level())
176       << "Destroying chromium request: " << self->url_.possibly_invalid_spec();
177   delete self;
178 }
179
180 void URLRequestPeer::OnResponseStarted(net::URLRequest* request) {
181   if (request->status().status() != net::URLRequestStatus::SUCCESS) {
182     OnRequestFailed();
183     return;
184   }
185
186   http_status_code_ = request->GetResponseCode();
187   VLOG(context_->logging_level())
188       << "Response started with status: " << http_status_code_;
189
190   request->GetResponseHeaderByName("Content-Type", &content_type_);
191   expected_size_ = request->GetExpectedContentSize();
192   delegate_->OnResponseStarted(this);
193
194   Read();
195 }
196
197 // Reads all available data or starts an asynchronous read.
198 void URLRequestPeer::Read() {
199   while (true) {
200     if (read_buffer_->RemainingCapacity() == 0) {
201       int new_capacity = read_buffer_->capacity() + kBufferSizeIncrement;
202       read_buffer_->SetCapacity(new_capacity);
203     }
204
205     int bytes_read;
206     if (url_request_->Read(
207             read_buffer_, read_buffer_->RemainingCapacity(), &bytes_read)) {
208       if (bytes_read == 0) {
209         OnRequestSucceeded();
210         break;
211       }
212
213       VLOG(context_->logging_level()) << "Synchronously read: " << bytes_read
214                                       << " bytes";
215       OnBytesRead(bytes_read);
216     } else if (url_request_->status().status() ==
217                net::URLRequestStatus::IO_PENDING) {
218       if (bytes_read_ != 0) {
219         VLOG(context_->logging_level()) << "Flushing buffer: " << bytes_read_
220                                         << " bytes";
221
222         delegate_->OnBytesRead(this);
223         read_buffer_->set_offset(0);
224         bytes_read_ = 0;
225       }
226       VLOG(context_->logging_level()) << "Started async read";
227       break;
228     } else {
229       OnRequestFailed();
230       break;
231     }
232   }
233 }
234
235 void URLRequestPeer::OnReadCompleted(net::URLRequest* request, int bytes_read) {
236   VLOG(context_->logging_level()) << "Asynchronously read: " << bytes_read
237                                   << " bytes";
238   if (bytes_read < 0) {
239     OnRequestFailed();
240     return;
241   } else if (bytes_read == 0) {
242     OnRequestSucceeded();
243     return;
244   }
245
246   OnBytesRead(bytes_read);
247   Read();
248 }
249
250 void URLRequestPeer::OnBytesRead(int bytes_read) {
251   read_buffer_->set_offset(read_buffer_->offset() + bytes_read);
252   bytes_read_ += bytes_read;
253   total_bytes_read_ += bytes_read;
254 }
255
256 void URLRequestPeer::OnRequestSucceeded() {
257   if (canceled_) {
258     return;
259   }
260
261   VLOG(context_->logging_level())
262       << "Request completed with HTTP status: " << http_status_code_
263       << ". Total bytes read: " << total_bytes_read_;
264
265   OnRequestCompleted();
266 }
267
268 void URLRequestPeer::OnRequestFailed() {
269   if (canceled_) {
270     return;
271   }
272
273   error_code_ = url_request_->status().error();
274   VLOG(context_->logging_level())
275       << "Request failed with status: " << url_request_->status().status()
276       << " and error: " << net::ErrorToString(error_code_);
277   OnRequestCompleted();
278 }
279
280 void URLRequestPeer::OnRequestCanceled() { OnRequestCompleted(); }
281
282 void URLRequestPeer::OnRequestCompleted() {
283   VLOG(context_->logging_level())
284       << "Completed: " << url_.possibly_invalid_spec();
285   if (url_request_ != NULL) {
286     delete url_request_;
287     url_request_ = NULL;
288   }
289
290   delegate_->OnBytesRead(this);
291   delegate_->OnRequestFinished(this);
292 }
293
294 unsigned char* URLRequestPeer::Data() const {
295   return reinterpret_cast<unsigned char*>(read_buffer_->StartOfBuffer());
296 }