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