OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert_net/cert_net_fetcher_impl.h" | 5 #include "net/cert_net/cert_net_fetcher_impl.h" |
6 | 6 |
7 #include <tuple> | 7 #include <tuple> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 void StartURLRequest(URLRequestContext* context); | 171 void StartURLRequest(URLRequestContext* context); |
172 | 172 |
173 private: | 173 private: |
174 // The pointers in RequestList are not owned by the Job. | 174 // The pointers in RequestList are not owned by the Job. |
175 using RequestList = base::LinkedList<RequestImpl>; | 175 using RequestList = base::LinkedList<RequestImpl>; |
176 | 176 |
177 // Implementation of URLRequest::Delegate | 177 // Implementation of URLRequest::Delegate |
178 void OnReceivedRedirect(URLRequest* request, | 178 void OnReceivedRedirect(URLRequest* request, |
179 const RedirectInfo& redirect_info, | 179 const RedirectInfo& redirect_info, |
180 bool* defer_redirect) override; | 180 bool* defer_redirect) override; |
181 void OnResponseStarted(URLRequest* request, int net_error) override; | 181 void OnResponseStarted(URLRequest* request) override; |
182 void OnReadCompleted(URLRequest* request, int bytes_read) override; | 182 void OnReadCompleted(URLRequest* request, int bytes_read) override; |
183 | 183 |
184 // Clears the URLRequest and timer. Helper for doing work common to | 184 // Clears the URLRequest and timer. Helper for doing work common to |
185 // cancellation and job completion. | 185 // cancellation and job completion. |
186 void Stop(); | 186 void Stop(); |
187 | 187 |
188 // Reads as much data as available from |request|. | 188 // Reads as much data as available from |request|. |
189 void ReadBody(URLRequest* request); | 189 void ReadBody(URLRequest* request); |
190 | 190 |
191 // Helper to copy the partial bytes read from the read IOBuffer to an | 191 // Helper to copy the partial bytes read from the read IOBuffer to an |
192 // aggregated buffer. | 192 // aggregated buffer. |
193 bool ConsumeBytesRead(URLRequest* request, int num_bytes); | 193 bool ConsumeBytesRead(URLRequest* request, int num_bytes); |
194 | 194 |
| 195 // Called once the job has exceeded its deadline. |
| 196 void OnTimeout(); |
| 197 |
195 // Called when the URLRequest has completed (either success or failure). | 198 // Called when the URLRequest has completed (either success or failure). |
196 void OnUrlRequestCompleted(int net_error); | 199 void OnUrlRequestCompleted(URLRequest* request); |
197 | 200 |
198 // Called when the Job has completed. The job may finish in response to a | 201 // Called when the Job has completed. The job may finish in response to a |
199 // timeout, an invalid URL, or the URLRequest completing. By the time this | 202 // timeout, an invalid URL, or the URLRequest completing. By the time this |
200 // method is called, the |response_body_| variable have been assigned. | 203 // method is called, the response variables have been assigned |
201 void OnJobCompleted(Error error); | 204 // (result_net_error_ and response_body_). |
202 | 205 void OnJobCompleted(); |
203 // Cancels a request with a specified error code and calls | |
204 // OnUrlRequestCompleted(). | |
205 void FailRequest(Error error); | |
206 | 206 |
207 // The requests attached to this job. | 207 // The requests attached to this job. |
208 RequestList requests_; | 208 RequestList requests_; |
209 | 209 |
210 // The input parameters for starting a URLRequest. | 210 // The input parameters for starting a URLRequest. |
211 std::unique_ptr<RequestParams> request_params_; | 211 std::unique_ptr<RequestParams> request_params_; |
212 | 212 |
213 // The URLRequest response information. | 213 // The URLRequest response information. |
214 std::vector<uint8_t> response_body_; | 214 std::vector<uint8_t> response_body_; |
| 215 Error result_net_error_; |
215 | 216 |
216 std::unique_ptr<URLRequest> url_request_; | 217 std::unique_ptr<URLRequest> url_request_; |
217 scoped_refptr<IOBuffer> read_buffer_; | 218 scoped_refptr<IOBuffer> read_buffer_; |
218 | 219 |
219 // Used to timeout the job when the URLRequest takes too long. This timer is | 220 // Used to timeout the job when the URLRequest takes too long. This timer is |
220 // also used for notifying a failure to start the URLRequest. | 221 // also used for notifying a failure to start the URLRequest. |
221 base::OneShotTimer timer_; | 222 base::OneShotTimer timer_; |
222 | 223 |
223 // Non-owned pointer to the CertNetFetcherImpl that created this job. | 224 // Non-owned pointer to the CertNetFetcherImpl that created this job. |
224 CertNetFetcherImpl* parent_; | 225 CertNetFetcherImpl* parent_; |
225 | 226 |
226 DISALLOW_COPY_AND_ASSIGN(Job); | 227 DISALLOW_COPY_AND_ASSIGN(Job); |
227 }; | 228 }; |
228 | 229 |
229 CertNetFetcherImpl::RequestImpl::~RequestImpl() { | 230 CertNetFetcherImpl::RequestImpl::~RequestImpl() { |
230 if (job_) | 231 if (job_) |
231 job_->DetachRequest(this); | 232 job_->DetachRequest(this); |
232 } | 233 } |
233 | 234 |
234 CertNetFetcherImpl::Job::Job(std::unique_ptr<RequestParams> request_params, | 235 CertNetFetcherImpl::Job::Job(std::unique_ptr<RequestParams> request_params, |
235 CertNetFetcherImpl* parent) | 236 CertNetFetcherImpl* parent) |
236 : request_params_(std::move(request_params)), | 237 : request_params_(std::move(request_params)), |
| 238 result_net_error_(ERR_IO_PENDING), |
237 parent_(parent) {} | 239 parent_(parent) {} |
238 | 240 |
239 CertNetFetcherImpl::Job::~Job() { | 241 CertNetFetcherImpl::Job::~Job() { |
240 Cancel(); | 242 Cancel(); |
241 } | 243 } |
242 | 244 |
243 void CertNetFetcherImpl::Job::Cancel() { | 245 void CertNetFetcherImpl::Job::Cancel() { |
244 parent_ = nullptr; | 246 parent_ = nullptr; |
245 | 247 |
246 // Notify each request of cancellation and remove it from the list. | 248 // Notify each request of cancellation and remove it from the list. |
(...skipping 24 matching lines...) Expand all Loading... |
271 | 273 |
272 // If there are no longer any requests attached to the job then | 274 // If there are no longer any requests attached to the job then |
273 // cancel and delete it. | 275 // cancel and delete it. |
274 if (requests_.empty() && !parent_->IsCurrentlyCompletingJob(this)) | 276 if (requests_.empty() && !parent_->IsCurrentlyCompletingJob(this)) |
275 delete_this = parent_->RemoveJob(this); | 277 delete_this = parent_->RemoveJob(this); |
276 } | 278 } |
277 | 279 |
278 void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) { | 280 void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) { |
279 Error error = CanFetchUrl(request_params_->url); | 281 Error error = CanFetchUrl(request_params_->url); |
280 if (error != OK) { | 282 if (error != OK) { |
| 283 result_net_error_ = error; |
281 // The CertNetFetcher's API contract is that requests always complete | 284 // The CertNetFetcher's API contract is that requests always complete |
282 // asynchronously. Use the timer class so the task is easily cancelled. | 285 // asynchronously. Use the timer class so the task is easily cancelled. |
283 timer_.Start( | 286 timer_.Start(FROM_HERE, base::TimeDelta(), this, &Job::OnJobCompleted); |
284 FROM_HERE, base::TimeDelta(), | |
285 base::Bind(&Job::OnJobCompleted, base::Unretained(this), error)); | |
286 return; | 287 return; |
287 } | 288 } |
288 | 289 |
289 // Start the URLRequest. | 290 // Start the URLRequest. |
290 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes); | 291 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes); |
291 url_request_ = | 292 url_request_ = |
292 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this); | 293 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this); |
293 if (request_params_->http_method == HTTP_METHOD_POST) | 294 if (request_params_->http_method == HTTP_METHOD_POST) |
294 url_request_->set_method("POST"); | 295 url_request_->set_method("POST"); |
295 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES | | 296 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES | |
296 LOAD_DO_NOT_SEND_COOKIES); | 297 LOAD_DO_NOT_SEND_COOKIES); |
297 url_request_->Start(); | 298 url_request_->Start(); |
298 | 299 |
299 // Start a timer to limit how long the job runs for. | 300 // Start a timer to limit how long the job runs for. |
300 if (request_params_->timeout > base::TimeDelta()) | 301 if (request_params_->timeout > base::TimeDelta()) |
301 timer_.Start( | 302 timer_.Start(FROM_HERE, request_params_->timeout, this, &Job::OnTimeout); |
302 FROM_HERE, request_params_->timeout, | |
303 base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT)); | |
304 } | 303 } |
305 | 304 |
306 void CertNetFetcherImpl::Job::OnReceivedRedirect( | 305 void CertNetFetcherImpl::Job::OnReceivedRedirect( |
307 URLRequest* request, | 306 URLRequest* request, |
308 const RedirectInfo& redirect_info, | 307 const RedirectInfo& redirect_info, |
309 bool* defer_redirect) { | 308 bool* defer_redirect) { |
310 DCHECK_EQ(url_request_.get(), request); | 309 DCHECK_EQ(url_request_.get(), request); |
311 | 310 |
312 // Ensure that the new URL matches the policy. | 311 // Ensure that the new URL matches the policy. |
313 Error error = CanFetchUrl(redirect_info.new_url); | 312 Error error = CanFetchUrl(redirect_info.new_url); |
314 if (error != OK) { | 313 if (error != OK) { |
315 FailRequest(error); | 314 request->CancelWithError(error); |
| 315 OnUrlRequestCompleted(request); |
316 return; | 316 return; |
317 } | 317 } |
318 } | 318 } |
319 | 319 |
320 void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request, | 320 void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request) { |
321 int net_error) { | |
322 DCHECK_EQ(url_request_.get(), request); | 321 DCHECK_EQ(url_request_.get(), request); |
323 DCHECK_NE(ERR_IO_PENDING, net_error); | |
324 | 322 |
325 if (net_error != OK) { | 323 if (!request->status().is_success()) { |
326 OnUrlRequestCompleted(net_error); | 324 OnUrlRequestCompleted(request); |
327 return; | 325 return; |
328 } | 326 } |
329 | 327 |
330 if (request->GetResponseCode() != 200) { | 328 if (request->GetResponseCode() != 200) { |
331 // TODO(eroman): Use a more specific error code. | 329 // TODO(eroman): Use a more specific error code. |
332 FailRequest(ERR_FAILED); | 330 request->CancelWithError(ERR_FAILED); |
| 331 OnUrlRequestCompleted(request); |
333 return; | 332 return; |
334 } | 333 } |
335 | 334 |
336 ReadBody(request); | 335 ReadBody(request); |
337 } | 336 } |
338 | 337 |
339 void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request, | 338 void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request, |
340 int bytes_read) { | 339 int bytes_read) { |
341 DCHECK_EQ(url_request_.get(), request); | 340 DCHECK_EQ(url_request_.get(), request); |
342 DCHECK_NE(ERR_IO_PENDING, bytes_read); | |
343 | 341 |
344 // Keep reading the response body. | 342 // Keep reading the response body. |
345 if (ConsumeBytesRead(request, bytes_read)) | 343 if (ConsumeBytesRead(request, bytes_read)) |
346 ReadBody(request); | 344 ReadBody(request); |
347 } | 345 } |
348 | 346 |
349 void CertNetFetcherImpl::Job::Stop() { | 347 void CertNetFetcherImpl::Job::Stop() { |
350 timer_.Stop(); | 348 timer_.Stop(); |
351 url_request_.reset(); | 349 url_request_.reset(); |
352 } | 350 } |
353 | 351 |
354 void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) { | 352 void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) { |
355 // Read as many bytes as are available synchronously. | 353 // Read as many bytes as are available synchronously. |
356 int num_bytes = 0; | 354 int num_bytes; |
357 while (num_bytes >= 0) { | 355 while ( |
358 num_bytes = request->Read(read_buffer_.get(), kReadBufferSizeInBytes); | 356 request->Read(read_buffer_.get(), kReadBufferSizeInBytes, &num_bytes)) { |
359 if (!ConsumeBytesRead(request, num_bytes)) | 357 if (!ConsumeBytesRead(request, num_bytes)) |
360 return; | 358 return; |
361 } | 359 } |
362 | 360 |
363 // Check whether the read failed synchronously. | 361 // Check whether the read failed synchronously. |
364 if (num_bytes != ERR_IO_PENDING) | 362 if (!request->status().is_io_pending()) |
365 OnUrlRequestCompleted(num_bytes); | 363 OnUrlRequestCompleted(request); |
366 return; | 364 return; |
367 } | 365 } |
368 | 366 |
369 bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request, | 367 bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request, |
370 int num_bytes) { | 368 int num_bytes) { |
371 if (num_bytes <= 0) { | 369 if (num_bytes <= 0) { |
372 // Error while reading, or EOF. | 370 // Error while reading, or EOF. |
373 OnUrlRequestCompleted(num_bytes); | 371 OnUrlRequestCompleted(request); |
374 return false; | 372 return false; |
375 } | 373 } |
376 | 374 |
377 // Enforce maximum size bound. | 375 // Enforce maximum size bound. |
378 if (num_bytes + response_body_.size() > request_params_->max_response_bytes) { | 376 if (num_bytes + response_body_.size() > request_params_->max_response_bytes) { |
379 FailRequest(ERR_FILE_TOO_BIG); | 377 request->CancelWithError(ERR_FILE_TOO_BIG); |
| 378 OnUrlRequestCompleted(request); |
380 return false; | 379 return false; |
381 } | 380 } |
382 | 381 |
383 // Append the data to |response_body_|. | 382 // Append the data to |response_body_|. |
384 response_body_.reserve(num_bytes); | 383 response_body_.reserve(num_bytes); |
385 response_body_.insert(response_body_.end(), read_buffer_->data(), | 384 response_body_.insert(response_body_.end(), read_buffer_->data(), |
386 read_buffer_->data() + num_bytes); | 385 read_buffer_->data() + num_bytes); |
387 return true; | 386 return true; |
388 } | 387 } |
389 | 388 |
390 void CertNetFetcherImpl::Job::OnUrlRequestCompleted(int net_error) { | 389 void CertNetFetcherImpl::Job::OnTimeout() { |
391 Error result = static_cast<Error>(net_error); | 390 result_net_error_ = ERR_TIMED_OUT; |
392 OnJobCompleted(result); | 391 url_request_->CancelWithError(result_net_error_); |
| 392 OnJobCompleted(); |
393 } | 393 } |
394 | 394 |
395 void CertNetFetcherImpl::Job::OnJobCompleted(Error error) { | 395 void CertNetFetcherImpl::Job::OnUrlRequestCompleted(URLRequest* request) { |
| 396 DCHECK_EQ(request, url_request_.get()); |
| 397 |
| 398 if (request->status().is_success()) |
| 399 result_net_error_ = OK; |
| 400 else |
| 401 result_net_error_ = static_cast<Error>(request->status().error()); |
| 402 |
| 403 OnJobCompleted(); |
| 404 } |
| 405 |
| 406 void CertNetFetcherImpl::Job::OnJobCompleted() { |
396 // Stop the timer and clear the URLRequest. | 407 // Stop the timer and clear the URLRequest. |
397 Stop(); | 408 Stop(); |
398 | 409 |
399 // Invoking the callbacks is subtle as state may be mutated while iterating | 410 // Invoking the callbacks is subtle as state may be mutated while iterating |
400 // through the callbacks: | 411 // through the callbacks: |
401 // | 412 // |
402 // * The parent CertNetFetcherImpl may be deleted | 413 // * The parent CertNetFetcherImpl may be deleted |
403 // * Requests in this job may be cancelled | 414 // * Requests in this job may be cancelled |
404 | 415 |
405 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this); | 416 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this); |
406 parent_->SetCurrentlyCompletingJob(this); | 417 parent_->SetCurrentlyCompletingJob(this); |
407 | 418 |
408 while (!requests_.empty()) { | 419 while (!requests_.empty()) { |
409 base::LinkNode<RequestImpl>* request = requests_.head(); | 420 base::LinkNode<RequestImpl>* request = requests_.head(); |
410 request->RemoveFromList(); | 421 request->RemoveFromList(); |
411 request->value()->OnJobCompleted(this, error, response_body_); | 422 request->value()->OnJobCompleted(this, result_net_error_, response_body_); |
412 } | 423 } |
413 | 424 |
414 if (parent_) | 425 if (parent_) |
415 parent_->ClearCurrentlyCompletingJob(this); | 426 parent_->ClearCurrentlyCompletingJob(this); |
416 } | 427 } |
417 | 428 |
418 void CertNetFetcherImpl::Job::FailRequest(Error error) { | |
419 int result = url_request_->CancelWithError(error); | |
420 OnUrlRequestCompleted(result); | |
421 } | |
422 | |
423 CertNetFetcherImpl::CertNetFetcherImpl(URLRequestContext* context) | 429 CertNetFetcherImpl::CertNetFetcherImpl(URLRequestContext* context) |
424 : currently_completing_job_(nullptr), context_(context) { | 430 : currently_completing_job_(nullptr), context_(context) { |
425 } | 431 } |
426 | 432 |
427 CertNetFetcherImpl::~CertNetFetcherImpl() { | 433 CertNetFetcherImpl::~CertNetFetcherImpl() { |
428 base::STLDeleteElements(&jobs_); | 434 base::STLDeleteElements(&jobs_); |
429 | 435 |
430 // The CertNetFetcherImpl was destroyed in a FetchCallback. Detach all | 436 // The CertNetFetcherImpl was destroyed in a FetchCallback. Detach all |
431 // remaining requests from the job so no further callbacks are called. | 437 // remaining requests from the job so no further callbacks are called. |
432 if (currently_completing_job_) | 438 if (currently_completing_job_) |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 void CertNetFetcherImpl::ClearCurrentlyCompletingJob(Job* job) { | 547 void CertNetFetcherImpl::ClearCurrentlyCompletingJob(Job* job) { |
542 DCHECK_EQ(currently_completing_job_, job); | 548 DCHECK_EQ(currently_completing_job_, job); |
543 currently_completing_job_ = nullptr; | 549 currently_completing_job_ = nullptr; |
544 } | 550 } |
545 | 551 |
546 bool CertNetFetcherImpl::IsCurrentlyCompletingJob(Job* job) { | 552 bool CertNetFetcherImpl::IsCurrentlyCompletingJob(Job* job) { |
547 return job == currently_completing_job_; | 553 return job == currently_completing_job_; |
548 } | 554 } |
549 | 555 |
550 } // namespace net | 556 } // namespace net |
OLD | NEW |