Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: net/cert_net/cert_net_fetcher_impl.cc

Issue 2595723002: Allow CertNetFetcher to be shutdown from the network thread (Closed)
Patch Set: fix verify tool #if Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/cert_net/cert_net_fetcher_impl.h ('k') | net/cert_net/cert_net_fetcher_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Overview 5 // Overview
6 // 6 //
7 // The main entry point is CertNetFetcherImpl. This is an implementation of 7 // The main entry point is CertNetFetcherImpl. This is an implementation of
8 // CertNetFetcher that provides a service for fetching network requests. 8 // CertNetFetcher that provides a service for fetching network requests.
9 // 9 //
10 // The interface for CertNetFetcher is synchronous, however allows 10 // The interface for CertNetFetcher is synchronous, however allows
11 // overlapping requests. When starting a request CertNetFetcherImpl 11 // overlapping requests. When starting a request CertNetFetcherImpl
12 // returns a CertNetFetcher::Request (CertNetFetcherImpl) that the 12 // returns a CertNetFetcher::Request (CertNetFetcherImpl) that the
13 // caller can use to cancel the fetch, or wait for it to complete 13 // caller can use to cancel the fetch, or wait for it to complete
14 // (blocking). 14 // (blocking).
15 // 15 //
16 // The CertNetFetcherImpl is shared between a network thread and a
17 // caller thread that waits for fetches to happen on the network thread.
18 //
16 // The classes are mainly organized based on their thread affinity: 19 // The classes are mainly organized based on their thread affinity:
17 // 20 //
18 // --------------- 21 // ---------------
19 // Lives on caller thread 22 // Straddles caller thread and network thread
20 // --------------- 23 // ---------------
21 // 24 //
22 // CertNetFetcherImpl (implements CertNetFetcher) 25 // CertNetFetcherImpl (implements CertNetFetcher)
23 // * Main entry point 26 // * Main entry point. Must be created and shutdown from the network thread.
24 // * Provides a service to start/cancel/wait for URL fetches 27 // * Provides a service to start/cancel/wait for URL fetches, to be
28 // used on the caller thread.
25 // * Returns callers a CertNetFetcher::Request as a handle 29 // * Returns callers a CertNetFetcher::Request as a handle
26 // * Requests can run in parallel, however will block the current thread when 30 // * Requests can run in parallel, however will block the current thread when
27 // reading results. 31 // reading results.
28 // * Posts tasks to network thread to coordinate actual work 32 // * Posts tasks to network thread to coordinate actual work
29 // 33 //
30 // CertNetFetcherRequestImpl (implements CertNetFetcher::Request)
31 // * Wrapper for cancelling events, or waiting for a request to complete
32 // * Waits on a WaitableEvent to complete requests.
33 //
34 // ---------------
35 // Straddles caller thread and network thread
36 // ---------------
37 //
38 // CertNetFetcherCore
39 // * Reference-counted bridge between CertNetFetcherImpl and the dependencies
40 // on network thread.
41 // * Small wrapper to holds the state that is conceptually owned by
42 // CertNetFetcherImpl, but belongs on the network thread.
43 //
44 // RequestCore 34 // RequestCore
45 // * Reference-counted bridge between CertNetFetcherRequestImpl and the 35 // * Reference-counted bridge between CertNetFetcherRequestImpl and the
46 // dependencies on the network thread 36 // dependencies on the network thread
47 // * Holds the result of the request, a WaitableEvent for signaling 37 // * Holds the result of the request, a WaitableEvent for signaling
48 // completion, and pointers for canceling work on network thread. 38 // completion, and pointers for canceling work on network thread.
49 // 39 //
50 // --------------- 40 // ---------------
41 // Lives on caller thread
42 // ---------------
43 //
44 // CertNetFetcherRequestImpl (implements CertNetFetcher::Request)
45 // * Wrapper for cancelling events, or waiting for a request to complete
46 // * Waits on a WaitableEvent to complete requests.
47 //
48 // ---------------
51 // Lives on network thread 49 // Lives on network thread
52 // --------------- 50 // ---------------
53 // 51 //
54 // AsyncCertNetFetcherImpl 52 // AsyncCertNetFetcherImpl
55 // * Asyncronous manager for outstanding requests. Handles de-duplication, 53 // * Asyncronous manager for outstanding requests. Handles de-duplication,
56 // timeouts, and actual integration with network stack. This is where the 54 // timeouts, and actual integration with network stack. This is where the
57 // majority of the logic lives. 55 // majority of the logic lives.
58 // * Signals completion of requests through RequestCore's WaitableEvent. 56 // * Signals completion of requests through RequestCore's WaitableEvent.
59 // * Attaches requests to Jobs for the purpose of de-duplication 57 // * Attaches requests to Jobs for the purpose of de-duplication
60 58
61 #include "net/cert_net/cert_net_fetcher_impl.h" 59 #include "net/cert_net/cert_net_fetcher_impl.h"
62 60
63 #include <tuple> 61 #include <tuple>
64 #include <utility> 62 #include <utility>
65 63
66 #include "base/callback_helpers.h" 64 #include "base/callback_helpers.h"
67 #include "base/logging.h" 65 #include "base/logging.h"
68 #include "base/macros.h" 66 #include "base/macros.h"
69 #include "base/memory/ptr_util.h" 67 #include "base/memory/ptr_util.h"
70 #include "base/numerics/safe_math.h" 68 #include "base/numerics/safe_math.h"
71 #include "base/synchronization/waitable_event.h" 69 #include "base/synchronization/waitable_event.h"
70 #include "base/threading/thread_task_runner_handle.h"
72 #include "base/timer/timer.h" 71 #include "base/timer/timer.h"
73 #include "net/base/load_flags.h" 72 #include "net/base/load_flags.h"
74 #include "net/cert/cert_net_fetcher.h" 73 #include "net/cert/cert_net_fetcher.h"
75 #include "net/url_request/redirect_info.h" 74 #include "net/url_request/redirect_info.h"
76 #include "net/url_request/url_request_context.h" 75 #include "net/url_request/url_request_context.h"
77 #include "net/url_request/url_request_context_getter.h"
78 76
79 // TODO(eroman): Add support for POST parameters. 77 // TODO(eroman): Add support for POST parameters.
80 // TODO(eroman): Add controls for bypassing the cache. 78 // TODO(eroman): Add controls for bypassing the cache.
81 // TODO(eroman): Add a maximum number of in-flight jobs/requests. 79 // TODO(eroman): Add a maximum number of in-flight jobs/requests.
82 // TODO(eroman): Add NetLog integration. 80 // TODO(eroman): Add NetLog integration.
83 81
84 namespace net { 82 namespace net {
85 83
86 namespace { 84 namespace {
87 85
(...skipping 26 matching lines...) Expand all
114 112
115 // AsyncCertNetFetcherImpl manages URLRequests in an async fashion on the 113 // AsyncCertNetFetcherImpl manages URLRequests in an async fashion on the
116 // URLRequestContexts's task runner thread. 114 // URLRequestContexts's task runner thread.
117 // 115 //
118 // * Schedules 116 // * Schedules
119 // * De-duplicates requests 117 // * De-duplicates requests
120 // * Handles timeouts 118 // * Handles timeouts
121 class AsyncCertNetFetcherImpl { 119 class AsyncCertNetFetcherImpl {
122 public: 120 public:
123 // Initializes AsyncCertNetFetcherImpl using the specified URLRequestContext 121 // Initializes AsyncCertNetFetcherImpl using the specified URLRequestContext
124 // for issuing requests. |context| must remain valid for the entire 122 // for issuing requests. |context| must remain valid until Shutdown() is
125 // lifetime of the AsyncCertNetFetcherImpl. 123 // called or the AsyncCertNetFetcherImpl is destroyed.
126 explicit AsyncCertNetFetcherImpl(URLRequestContext* context); 124 explicit AsyncCertNetFetcherImpl(URLRequestContext* context);
127 125
128 // Deletion implicitly cancels any outstanding requests. 126 // The AsyncCertNetFetcherImpl is expected to be kept alive until all
127 // requests have completed or Shutdown() is called.
129 ~AsyncCertNetFetcherImpl(); 128 ~AsyncCertNetFetcherImpl();
130 129
131 // Starts an asynchronous request to fetch the given URL. On completion 130 // Starts an asynchronous request to fetch the given URL. On completion
132 // |callback| will be invoked. 131 // request->OnJobCompleted() will be invoked.
133 //
134 // Completion of the request will never occur synchronously. In other words it
135 // is guaranteed that |callback| will only be invoked once the Fetch*() method
136 // has returned.
137 void Fetch(std::unique_ptr<RequestParams> request_params, 132 void Fetch(std::unique_ptr<RequestParams> request_params,
138 RequestCore* request); 133 scoped_refptr<RequestCore> request);
134
135 // Cancels outstanding jobs, which stops network requests and signals the
136 // corresponding RequestCores that the requests have completed.
137 void Shutdown();
139 138
140 private: 139 private:
141 friend class Job; 140 friend class Job;
142 141
143 // Finds a job with a matching RequestPararms or returns nullptr if there was 142 // Finds a job with a matching RequestPararms or returns nullptr if there was
144 // no match. 143 // no match.
145 Job* FindJob(const RequestParams& params); 144 Job* FindJob(const RequestParams& params);
146 145
147 // Removes |job| from the in progress jobs and transfers ownership to the 146 // Removes |job| from the in progress jobs and transfers ownership to the
148 // caller. 147 // caller.
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 class RequestCore : public base::RefCountedThreadSafe<RequestCore> { 198 class RequestCore : public base::RefCountedThreadSafe<RequestCore> {
200 public: 199 public:
201 explicit RequestCore(scoped_refptr<base::SingleThreadTaskRunner> task_runner) 200 explicit RequestCore(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
202 : completion_event_(base::WaitableEvent::ResetPolicy::MANUAL, 201 : completion_event_(base::WaitableEvent::ResetPolicy::MANUAL,
203 base::WaitableEvent::InitialState::NOT_SIGNALED), 202 base::WaitableEvent::InitialState::NOT_SIGNALED),
204 task_runner_(std::move(task_runner)) {} 203 task_runner_(std::move(task_runner)) {}
205 204
206 void AttachedToJob(Job* job) { 205 void AttachedToJob(Job* job) {
207 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 206 DCHECK(task_runner_->RunsTasksOnCurrentThread());
208 DCHECK(!job_); 207 DCHECK(!job_);
208 // Requests should not be attached to jobs after they have been signalled
209 // with a cancellation error (which happens via either Cancel() or
210 // SignalImmediateError()).
211 DCHECK_NE(error_, ERR_ABORTED);
209 job_ = job; 212 job_ = job;
210 } 213 }
211 214
212 void OnJobCompleted(Job* job, 215 void OnJobCompleted(Job* job,
213 Error error, 216 Error error,
214 const std::vector<uint8_t>& response_body) { 217 const std::vector<uint8_t>& response_body) {
215 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 218 DCHECK(task_runner_->RunsTasksOnCurrentThread());
216 219
217 DCHECK_EQ(job_, job); 220 DCHECK_EQ(job_, job);
218 job_ = nullptr; 221 job_ = nullptr;
219 222
220 error_ = error; 223 error_ = error;
221 bytes_ = response_body; 224 bytes_ = response_body;
222 completion_event_.Signal(); 225 completion_event_.Signal();
223 } 226 }
224 227
225 // Can be called from any thread. 228 // Can be called from any thread. Detaches this request from its job (if it is
229 // attached to any), but does not signal completion.
226 void Cancel(); 230 void Cancel();
227 231
232 // Can be used to signal that an error was encountered before the request was
233 // attached to a job. Can be called from any thread.
234 void SignalImmediateError();
235
228 // Should only be called once. 236 // Should only be called once.
229 void WaitForResult(Error* error, std::vector<uint8_t>* bytes) { 237 void WaitForResult(Error* error, std::vector<uint8_t>* bytes) {
230 DCHECK(!task_runner_->RunsTasksOnCurrentThread()); 238 DCHECK(!task_runner_->RunsTasksOnCurrentThread());
231 239
232 completion_event_.Wait(); 240 completion_event_.Wait();
233 *bytes = std::move(bytes_); 241 *bytes = std::move(bytes_);
234 *error = error_; 242 *error = error_;
235 243
236 error_ = ERR_UNEXPECTED; 244 error_ = ERR_UNEXPECTED;
237 } 245 }
238 246
239 private: 247 private:
240 friend class base::RefCountedThreadSafe<RequestCore>; 248 friend class base::RefCountedThreadSafe<RequestCore>;
241 249
242 ~RequestCore() { 250 ~RequestCore() {
243 // Requests should have been cancelled prior to destruction. 251 // Requests should have been cancelled prior to destruction.
244 DCHECK(!job_); 252 DCHECK(!job_);
245 } 253 }
246 254
247 // A non-owned pointer to the job that is executing the request. 255 // A non-owned pointer to the job that is executing the request.
248 Job* job_ = nullptr; 256 Job* job_ = nullptr;
249 257
250 // May be written to from network thread. 258 // May be written to from network thread, or from the caller thread only when
259 // there is no work that will be done on the network thread (e.g. when the
260 // network thread has been shutdown before the request begins). See comment in
261 // SignalImmediateError.
251 Error error_; 262 Error error_;
252 std::vector<uint8_t> bytes_; 263 std::vector<uint8_t> bytes_;
253 264
254 // Indicates when |error_| and |bytes_| have been written to. 265 // Indicates when |error_| and |bytes_| have been written to.
255 base::WaitableEvent completion_event_; 266 base::WaitableEvent completion_event_;
256 267
257 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 268 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
258 269
259 DISALLOW_COPY_AND_ASSIGN(RequestCore); 270 DISALLOW_COPY_AND_ASSIGN(RequestCore);
260 }; 271 };
(...skipping 28 matching lines...) Expand all
289 // Job tracks an outstanding URLRequest as well as all of the pending requests 300 // Job tracks an outstanding URLRequest as well as all of the pending requests
290 // for it. 301 // for it.
291 class Job : public URLRequest::Delegate { 302 class Job : public URLRequest::Delegate {
292 public: 303 public:
293 Job(std::unique_ptr<RequestParams> request_params, 304 Job(std::unique_ptr<RequestParams> request_params,
294 AsyncCertNetFetcherImpl* parent); 305 AsyncCertNetFetcherImpl* parent);
295 ~Job() override; 306 ~Job() override;
296 307
297 const RequestParams& request_params() const { return *request_params_; } 308 const RequestParams& request_params() const { return *request_params_; }
298 309
299 // Create a request and attaches it to the job. When the job completes it will 310 // Creates a request and attaches it to the job. When the job completes it
300 // notify the request of completion through OnJobCompleted. Note that the Job 311 // will notify the request of completion through OnJobCompleted.
301 // does NOT own the request. 312 void AttachRequest(scoped_refptr<RequestCore> request);
302 void AttachRequest(RequestCore* request);
303 313
304 // Removes |request| from the job. 314 // Removes |request| from the job.
305 void DetachRequest(RequestCore* request); 315 void DetachRequest(RequestCore* request);
306 316
307 // Creates and starts a URLRequest for the job. After the URLRequest has 317 // Creates and starts a URLRequest for the job. After the URLRequest has
308 // completed, OnJobCompleted() will be invoked and all the registered requests 318 // completed, OnJobCompleted() will be invoked and all the registered requests
309 // notified of completion. 319 // notified of completion.
310 void StartURLRequest(URLRequestContext* context); 320 void StartURLRequest(URLRequestContext* context);
311 321
322 // Cancels the request with an ERR_ABORTED error and invokes
323 // RequestCore::OnJobCompleted() to notify the registered requests of the
324 // cancellation. The job is *not* removed from the AsyncCertNetFetcherImpl.
325 void Cancel();
326
312 private: 327 private:
313 // Implementation of URLRequest::Delegate 328 // Implementation of URLRequest::Delegate
314 void OnReceivedRedirect(URLRequest* request, 329 void OnReceivedRedirect(URLRequest* request,
315 const RedirectInfo& redirect_info, 330 const RedirectInfo& redirect_info,
316 bool* defer_redirect) override; 331 bool* defer_redirect) override;
317 void OnResponseStarted(URLRequest* request, int net_error) override; 332 void OnResponseStarted(URLRequest* request, int net_error) override;
318 void OnReadCompleted(URLRequest* request, int bytes_read) override; 333 void OnReadCompleted(URLRequest* request, int bytes_read) override;
319 334
320 // Clears the URLRequest and timer. Helper for doing work common to 335 // Clears the URLRequest and timer. Helper for doing work common to
321 // cancellation and job completion. 336 // cancellation and job completion.
322 void Stop(); 337 void Stop();
323 338
324 // Reads as much data as available from |request|. 339 // Reads as much data as available from |request|.
325 void ReadBody(URLRequest* request); 340 void ReadBody(URLRequest* request);
326 341
327 // Helper to copy the partial bytes read from the read IOBuffer to an 342 // Helper to copy the partial bytes read from the read IOBuffer to an
328 // aggregated buffer. 343 // aggregated buffer.
329 bool ConsumeBytesRead(URLRequest* request, int num_bytes); 344 bool ConsumeBytesRead(URLRequest* request, int num_bytes);
330 345
331 // Called when the URLRequest has completed (either success or failure). 346 // Called when the URLRequest has completed (either success or failure).
332 void OnUrlRequestCompleted(int net_error); 347 void OnUrlRequestCompleted(int net_error);
333 348
334 // Called when the Job has completed. The job may finish in response to a 349 // Called when the Job has completed. The job may finish in response to a
335 // timeout, an invalid URL, or the URLRequest completing. By the time this 350 // timeout, an invalid URL, or the URLRequest completing. By the time this
336 // method is called, the |response_body_| variable have been assigned. 351 // method is called, the |response_body_| variable have been assigned.
337 void OnJobCompleted(Error error); 352 void OnJobCompleted(Error error);
338 353
354 // Calls r->OnJobCompleted() for each RequestCore |r| currently attached
355 // to this job, and then clears |requests_|.
356 void CompleteAndClearRequests(Error error);
357
339 // Cancels a request with a specified error code and calls 358 // Cancels a request with a specified error code and calls
340 // OnUrlRequestCompleted(). 359 // OnUrlRequestCompleted().
341 void FailRequest(Error error); 360 void FailRequest(Error error);
342 361
343 // The requests attached to this job (non-owned). 362 // The requests attached to this job.
344 std::vector<RequestCore*> requests_; 363 std::vector<scoped_refptr<RequestCore>> requests_;
345 364
346 // The input parameters for starting a URLRequest. 365 // The input parameters for starting a URLRequest.
347 std::unique_ptr<RequestParams> request_params_; 366 std::unique_ptr<RequestParams> request_params_;
348 367
349 // The URLRequest response information. 368 // The URLRequest response information.
350 std::vector<uint8_t> response_body_; 369 std::vector<uint8_t> response_body_;
351 370
352 std::unique_ptr<URLRequest> url_request_; 371 std::unique_ptr<URLRequest> url_request_;
353 scoped_refptr<IOBuffer> read_buffer_; 372 scoped_refptr<IOBuffer> read_buffer_;
354 373
355 // Used to timeout the job when the URLRequest takes too long. This timer is 374 // Used to timeout the job when the URLRequest takes too long. This timer is
356 // also used for notifying a failure to start the URLRequest. 375 // also used for notifying a failure to start the URLRequest.
357 base::OneShotTimer timer_; 376 base::OneShotTimer timer_;
358 377
359 // Non-owned pointer to the AsyncCertNetFetcherImpl that created this job. 378 // Non-owned pointer to the AsyncCertNetFetcherImpl that created this job.
360 AsyncCertNetFetcherImpl* parent_; 379 AsyncCertNetFetcherImpl* parent_;
361 380
362 DISALLOW_COPY_AND_ASSIGN(Job); 381 DISALLOW_COPY_AND_ASSIGN(Job);
363 }; 382 };
364 383
365 void RequestCore::Cancel() { 384 void RequestCore::Cancel() {
eroman 2017/01/13 01:13:52 Optional: May consider renaming this "CancelJob" t
estark 2017/01/13 02:42:56 Done.
366 if (!task_runner_->RunsTasksOnCurrentThread()) { 385 if (!task_runner_->RunsTasksOnCurrentThread()) {
367 task_runner_->PostTask(FROM_HERE, base::Bind(&RequestCore::Cancel, this)); 386 task_runner_->PostTask(FROM_HERE, base::Bind(&RequestCore::Cancel, this));
368 return; 387 return;
369 } 388 }
370 389
371 if (job_) { 390 if (job_) {
372 auto* job = job_; 391 auto* job = job_;
373 job_ = nullptr; 392 job_ = nullptr;
374 job->DetachRequest(this); 393 job->DetachRequest(this);
375 } 394 }
376 395
377 bytes_.clear(); 396 bytes_.clear();
eroman 2017/01/13 01:13:52 optional: Could replace these last two lines with
estark 2017/01/13 02:42:56 Done.
378 error_ = ERR_UNEXPECTED; 397 error_ = ERR_ABORTED;
398 }
399
400 void RequestCore::SignalImmediateError() {
401 // Writing to |error_| is safe here from either thread, because
402 // SignalImmediateError is only to be called before this request is attached
403 // to a job. In particular, if called from the caller thread, no work will be
404 // done on the network thread for this request, so |error_| will only be
405 // written and read on the caller thread. If called from the network thread,
406 // |error_| will only be written to on the network thread and will not be read
407 // on the caller thread until |completion_event_| is signalled (after which it
408 // will be not be written on the network thread again).
409 error_ = ERR_ABORTED;
eroman 2017/01/13 01:13:52 [optional] Could also assert that job_ is null. Te
estark 2017/01/13 02:42:56 Done.
410 completion_event_.Signal();
eroman 2017/01/13 01:13:53 optional: May want to clear bytes_ just in case.
estark 2017/01/13 02:42:56 Done.
379 } 411 }
380 412
381 Job::Job(std::unique_ptr<RequestParams> request_params, 413 Job::Job(std::unique_ptr<RequestParams> request_params,
382 AsyncCertNetFetcherImpl* parent) 414 AsyncCertNetFetcherImpl* parent)
383 : request_params_(std::move(request_params)), parent_(parent) {} 415 : request_params_(std::move(request_params)), parent_(parent) {}
384 416
385 Job::~Job() { 417 Job::~Job() {
386 DCHECK(requests_.empty()); 418 DCHECK(requests_.empty());
387 Stop(); 419 Stop();
388 } 420 }
389 421
390 void Job::AttachRequest(RequestCore* request) { 422 void Job::AttachRequest(scoped_refptr<RequestCore> request) {
391 requests_.push_back(request);
392 request->AttachedToJob(this); 423 request->AttachedToJob(this);
424 requests_.push_back(std::move(request));
393 } 425 }
394 426
395 void Job::DetachRequest(RequestCore* request) { 427 void Job::DetachRequest(RequestCore* request) {
396 std::unique_ptr<Job> delete_this; 428 std::unique_ptr<Job> delete_this;
397 429
398 auto it = std::find(requests_.begin(), requests_.end(), request); 430 auto it = std::find(requests_.begin(), requests_.end(), request);
399 DCHECK(it != requests_.end()); 431 DCHECK(it != requests_.end());
400 requests_.erase(it); 432 requests_.erase(it);
401 433
402 // If there are no longer any requests attached to the job then 434 // If there are no longer any requests attached to the job then
403 // cancel and delete it. 435 // cancel and delete it.
404 if (requests_.empty()) 436 if (requests_.empty())
405 delete_this = parent_->RemoveJob(this); 437 delete_this = parent_->RemoveJob(this);
406 } 438 }
407 439
408 void Job::StartURLRequest(URLRequestContext* context) { 440 void Job::StartURLRequest(URLRequestContext* context) {
409 Error error = CanFetchUrl(request_params_->url); 441 Error error = CanFetchUrl(request_params_->url);
410 if (error != OK) { 442 if (error != OK) {
411 // TODO(eroman): Don't post a task for this case. 443 OnJobCompleted(error);
eroman 2017/01/13 01:13:52 Thanks!
412 timer_.Start(
413 FROM_HERE, base::TimeDelta(),
414 base::Bind(&Job::OnJobCompleted, base::Unretained(this), error));
415 return; 444 return;
416 } 445 }
417 446
418 // Start the URLRequest. 447 // Start the URLRequest.
419 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes); 448 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes);
420 url_request_ = 449 url_request_ =
421 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this); 450 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this);
422 if (request_params_->http_method == HTTP_METHOD_POST) 451 if (request_params_->http_method == HTTP_METHOD_POST)
423 url_request_->set_method("POST"); 452 url_request_->set_method("POST");
424 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES | 453 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES |
425 LOAD_DO_NOT_SEND_COOKIES); 454 LOAD_DO_NOT_SEND_COOKIES);
426 url_request_->Start(); 455 url_request_->Start();
427 456
428 // Start a timer to limit how long the job runs for. 457 // Start a timer to limit how long the job runs for.
429 if (request_params_->timeout > base::TimeDelta()) 458 if (request_params_->timeout > base::TimeDelta())
430 timer_.Start( 459 timer_.Start(
431 FROM_HERE, request_params_->timeout, 460 FROM_HERE, request_params_->timeout,
432 base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT)); 461 base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT));
433 } 462 }
434 463
464 void Job::Cancel() {
465 // Stop the timer and clear the URLRequest.
466 Stop();
467 // Signal attached requests that they've been completed.
468 CompleteAndClearRequests(static_cast<Error>(ERR_ABORTED));
469 }
470
435 void Job::OnReceivedRedirect(URLRequest* request, 471 void Job::OnReceivedRedirect(URLRequest* request,
436 const RedirectInfo& redirect_info, 472 const RedirectInfo& redirect_info,
437 bool* defer_redirect) { 473 bool* defer_redirect) {
438 DCHECK_EQ(url_request_.get(), request); 474 DCHECK_EQ(url_request_.get(), request);
439 475
440 // Ensure that the new URL matches the policy. 476 // Ensure that the new URL matches the policy.
441 Error error = CanFetchUrl(redirect_info.new_url); 477 Error error = CanFetchUrl(redirect_info.new_url);
442 if (error != OK) { 478 if (error != OK) {
443 FailRequest(error); 479 FailRequest(error);
444 return; 480 return;
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
517 Error result = static_cast<Error>(net_error); 553 Error result = static_cast<Error>(net_error);
518 OnJobCompleted(result); 554 OnJobCompleted(result);
519 } 555 }
520 556
521 void Job::OnJobCompleted(Error error) { 557 void Job::OnJobCompleted(Error error) {
522 DCHECK_NE(ERR_IO_PENDING, error); 558 DCHECK_NE(ERR_IO_PENDING, error);
523 // Stop the timer and clear the URLRequest. 559 // Stop the timer and clear the URLRequest.
524 Stop(); 560 Stop();
525 561
526 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this); 562 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this);
563 CompleteAndClearRequests(error);
564 }
527 565
528 for (auto* request : requests_) { 566 void Job::CompleteAndClearRequests(Error error) {
567 for (const auto& request : requests_) {
529 request->OnJobCompleted(this, error, response_body_); 568 request->OnJobCompleted(this, error, response_body_);
530 } 569 }
531 570
532 requests_.clear(); 571 requests_.clear();
533 } 572 }
534 573
535 void Job::FailRequest(Error error) { 574 void Job::FailRequest(Error error) {
536 DCHECK_NE(ERR_IO_PENDING, error); 575 DCHECK_NE(ERR_IO_PENDING, error);
537 int result = url_request_->CancelWithError(error); 576 int result = url_request_->CancelWithError(error);
538 OnUrlRequestCompleted(result); 577 OnUrlRequestCompleted(result);
539 } 578 }
540 579
541 AsyncCertNetFetcherImpl::AsyncCertNetFetcherImpl(URLRequestContext* context) 580 AsyncCertNetFetcherImpl::AsyncCertNetFetcherImpl(URLRequestContext* context)
542 : context_(context) { 581 : context_(context) {
543 // Allow creation to happen from another thread. 582 // Allow creation to happen from another thread.
544 thread_checker_.DetachFromThread(); 583 thread_checker_.DetachFromThread();
545 } 584 }
546 585
547 AsyncCertNetFetcherImpl::~AsyncCertNetFetcherImpl() { 586 AsyncCertNetFetcherImpl::~AsyncCertNetFetcherImpl() {
548 DCHECK(thread_checker_.CalledOnValidThread()); 587 DCHECK(thread_checker_.CalledOnValidThread());
549 jobs_.clear(); 588 jobs_.clear();
550 } 589 }
551 590
552 bool JobComparator::operator()(const Job* job1, const Job* job2) const { 591 bool JobComparator::operator()(const Job* job1, const Job* job2) const {
553 return job1->request_params() < job2->request_params(); 592 return job1->request_params() < job2->request_params();
554 } 593 }
555 594
556 void AsyncCertNetFetcherImpl::Fetch( 595 void AsyncCertNetFetcherImpl::Fetch(
557 std::unique_ptr<RequestParams> request_params, 596 std::unique_ptr<RequestParams> request_params,
558 RequestCore* request) { 597 scoped_refptr<RequestCore> request) {
559 DCHECK(thread_checker_.CalledOnValidThread()); 598 DCHECK(thread_checker_.CalledOnValidThread());
560 599
561 // If there is an in-progress job that matches the request parameters use it. 600 // If there is an in-progress job that matches the request parameters use it.
562 // Otherwise start a new job. 601 // Otherwise start a new job.
563 Job* job = FindJob(*request_params); 602 Job* job = FindJob(*request_params);
564 603 if (job) {
565 if (!job) { 604 job->AttachRequest(request);
eroman 2017/01/13 01:13:53 std::move()
estark 2017/01/13 02:42:56 Done.
566 job = new Job(std::move(request_params), this); 605 return;
567 jobs_[job] = base::WrapUnique(job);
568 job->StartURLRequest(context_);
569 } 606 }
570 607
571 return job->AttachRequest(request); 608 job = new Job(std::move(request_params), this);
609 jobs_[job] = base::WrapUnique(job);
610 // Attach the request before calling StartURLRequest; this ensures that the
611 // request will get signalled if StartURLRequest completes the job
612 // synchronously.
613 job->AttachRequest(request);
eroman 2017/01/13 01:13:52 std::move
estark 2017/01/13 02:42:56 Done.
614 job->StartURLRequest(context_);
615 }
616
617 void AsyncCertNetFetcherImpl::Shutdown() {
618 DCHECK(thread_checker_.CalledOnValidThread());
619 for (const auto& job : jobs_) {
eroman 2017/01/13 01:13:52 optional: Could also maybe make deletion == cancel
estark 2017/01/13 02:42:56 Acknowledged; I find the explicit cancellation a l
620 job.first->Cancel();
621 }
622 jobs_.clear();
572 } 623 }
573 624
574 struct JobToRequestParamsComparator { 625 struct JobToRequestParamsComparator {
575 bool operator()(const JobSet::value_type& job, 626 bool operator()(const JobSet::value_type& job,
576 const RequestParams& value) const { 627 const RequestParams& value) const {
577 return job.first->request_params() < value; 628 return job.first->request_params() < value;
578 } 629 }
579 }; 630 };
580 631
581 Job* AsyncCertNetFetcherImpl::FindJob(const RequestParams& params) { 632 Job* AsyncCertNetFetcherImpl::FindJob(const RequestParams& params) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 666
616 ~CertNetFetcherRequestImpl() override { 667 ~CertNetFetcherRequestImpl() override {
617 if (core_) 668 if (core_)
618 core_->Cancel(); 669 core_->Cancel();
619 } 670 }
620 671
621 private: 672 private:
622 scoped_refptr<RequestCore> core_; 673 scoped_refptr<RequestCore> core_;
623 }; 674 };
624 675
625 class CertNetFetcherCore
626 : public base::RefCountedThreadSafe<CertNetFetcherCore> {
627 public:
628 explicit CertNetFetcherCore(URLRequestContextGetter* context_getter)
629 : context_getter_(context_getter) {}
630
631 void Abandon() {
632 GetNetworkTaskRunner()->PostTask(
633 FROM_HERE,
634 base::Bind(&CertNetFetcherCore::DoAbandonOnNetworkThread, this));
635 }
636
637 scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() {
638 return context_getter_->GetNetworkTaskRunner();
639 }
640
641 void DoFetchOnNetworkThread(std::unique_ptr<RequestParams> request_params,
642 scoped_refptr<RequestCore> request) {
643 DCHECK(GetNetworkTaskRunner()->RunsTasksOnCurrentThread());
644
645 if (!impl_) {
646 impl_.reset(
647 new AsyncCertNetFetcherImpl(context_getter_->GetURLRequestContext()));
648 }
649
650 // Don't need to retain a reference to |request| because consume is
651 // expected to keep it alive.
652 impl_->Fetch(std::move(request_params), request.get());
653 }
654
655 private:
656 friend class base::RefCountedThreadSafe<CertNetFetcherCore>;
657
658 void DoAbandonOnNetworkThread() {
659 DCHECK(GetNetworkTaskRunner()->RunsTasksOnCurrentThread());
660 impl_.reset();
661 }
662
663 ~CertNetFetcherCore() { DCHECK(!impl_); }
664
665 scoped_refptr<URLRequestContextGetter> context_getter_;
666
667 std::unique_ptr<AsyncCertNetFetcherImpl> impl_;
668
669 DISALLOW_COPY_AND_ASSIGN(CertNetFetcherCore);
670 };
671
672 class CertNetFetcherImpl : public CertNetFetcher { 676 class CertNetFetcherImpl : public CertNetFetcher {
673 public: 677 public:
674 explicit CertNetFetcherImpl(URLRequestContextGetter* context_getter) 678 explicit CertNetFetcherImpl(URLRequestContext* context)
675 : core_(new CertNetFetcherCore(context_getter)) {} 679 : task_runner_(base::ThreadTaskRunnerHandle::Get()), context_(context) {}
676 680
677 ~CertNetFetcherImpl() override { core_->Abandon(); } 681 void Shutdown() override {
682 DCHECK(task_runner_->RunsTasksOnCurrentThread());
683 if (impl_) {
684 impl_->Shutdown();
eroman 2017/01/13 01:13:52 optional: Per comment above, could combine shutdow
estark 2017/01/13 02:42:56 Acknowledged.
685 impl_.reset();
686 }
687 context_ = nullptr;
688 }
678 689
679 std::unique_ptr<Request> FetchCaIssuers(const GURL& url, 690 std::unique_ptr<Request> FetchCaIssuers(const GURL& url,
680 int timeout_milliseconds, 691 int timeout_milliseconds,
681 int max_response_bytes) override { 692 int max_response_bytes) override {
682 std::unique_ptr<RequestParams> request_params(new RequestParams); 693 std::unique_ptr<RequestParams> request_params(new RequestParams);
683 694
684 request_params->url = url; 695 request_params->url = url;
685 request_params->http_method = HTTP_METHOD_GET; 696 request_params->http_method = HTTP_METHOD_GET;
686 request_params->timeout = GetTimeout(timeout_milliseconds); 697 request_params->timeout = GetTimeout(timeout_milliseconds);
687 request_params->max_response_bytes = 698 request_params->max_response_bytes =
(...skipping 25 matching lines...) Expand all
713 request_params->url = url; 724 request_params->url = url;
714 request_params->http_method = HTTP_METHOD_GET; 725 request_params->http_method = HTTP_METHOD_GET;
715 request_params->timeout = GetTimeout(timeout_milliseconds); 726 request_params->timeout = GetTimeout(timeout_milliseconds);
716 request_params->max_response_bytes = 727 request_params->max_response_bytes =
717 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia); 728 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
718 729
719 return DoFetch(std::move(request_params)); 730 return DoFetch(std::move(request_params));
720 } 731 }
721 732
722 private: 733 private:
734 ~CertNetFetcherImpl() override {
735 // The fetcher must be shutdown (at which point |context_| will be set to
736 // null) before destruction.
737 DCHECK(!context_);
738 }
739
740 void DoFetchOnNetworkThread(std::unique_ptr<RequestParams> request_params,
741 scoped_refptr<RequestCore> request) {
742 DCHECK(task_runner_->RunsTasksOnCurrentThread());
743
744 if (!context_) {
745 // The fetcher might have been shutdown between when this task was posted
746 // and when it is running. In this case, signal the request and do not
747 // start a network request.
748 request->SignalImmediateError();
749 return;
750 }
751
752 if (!impl_) {
753 impl_.reset(new AsyncCertNetFetcherImpl(context_));
754 }
755
756 impl_->Fetch(std::move(request_params), request);
757 }
758
723 std::unique_ptr<Request> DoFetch( 759 std::unique_ptr<Request> DoFetch(
724 std::unique_ptr<RequestParams> request_params) { 760 std::unique_ptr<RequestParams> request_params) {
725 auto task_runner = core_->GetNetworkTaskRunner(); 761 scoped_refptr<RequestCore> request_core = new RequestCore(task_runner_);
726 scoped_refptr<RequestCore> request_core = new RequestCore(task_runner);
727 762
728 task_runner->PostTask( 763 // If the fetcher has already been shutdown, DoFetchOnNetworkThread will
729 FROM_HERE, 764 // signal the request with an error. However, if the fetcher shuts down
730 base::Bind(&CertNetFetcherCore::DoFetchOnNetworkThread, core_, 765 // before DoFetchOnNetworkThread runs and PostTask still returns true, then
731 base::Passed(&request_params), request_core)); 766 // the request will hang (that is, WaitForResult will not return).
767 if (!task_runner_->PostTask(
768 FROM_HERE,
769 base::Bind(&CertNetFetcherImpl::DoFetchOnNetworkThread, this,
770 base::Passed(&request_params), request_core))) {
771 request_core->SignalImmediateError();
772 }
732 773
733 return base::MakeUnique<CertNetFetcherRequestImpl>(std::move(request_core)); 774 return base::MakeUnique<CertNetFetcherRequestImpl>(std::move(request_core));
734 } 775 }
735 776
736 private: 777 private:
737 scoped_refptr<CertNetFetcherCore> core_; 778 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
779 // Not owned. |context_| must stay valid until Shutdown() is called.
780 URLRequestContext* context_ = nullptr;
781 std::unique_ptr<AsyncCertNetFetcherImpl> impl_;
738 }; 782 };
739 783
740 } // namespace 784 } // namespace
741 785
742 std::unique_ptr<CertNetFetcher> CreateCertNetFetcher( 786 scoped_refptr<CertNetFetcher> CreateCertNetFetcher(URLRequestContext* context) {
743 URLRequestContextGetter* context_getter) { 787 return make_scoped_refptr(new CertNetFetcherImpl(context));
744 return base::MakeUnique<CertNetFetcherImpl>(context_getter);
745 } 788 }
746 789
747 } // namespace net 790 } // namespace net
OLDNEW
« no previous file with comments | « net/cert_net/cert_net_fetcher_impl.h ('k') | net/cert_net/cert_net_fetcher_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698