OLD | NEW |
| (Empty) |
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 } | |
OLD | NEW |