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