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