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

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

Issue 2453093004: Remove dependence on a message loop for net::PathBuilder. (Closed)
Patch Set: remove unnecessary forward decl Created 4 years 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 //
5 // Overview
6 //
7 // The main entry point is CertNetFetcherImpl. This is an implementation of
8 // CertNetFetcher that provides a service for fetching network requests.
9 //
10 // The interface for CertNetFetcher is synchronous, however allows
11 // overlapping requests. When starting a request CertNetFetcherImpl
12 // returns a CertNetFetcher::Request (CertNetFetcherImpl) that the
13 // caller can use to cancel the fetch, or wait for it to complete
14 // (blocking).
15 //
16 // The classes are mainly organized based on their thread affinity:
17 //
18 // ---------------
19 // Lives on caller thread
20 // ---------------
21 //
22 // CertNetFetcherImpl (implements CertNetFetcher)
23 // * Main entry point
24 // * Provides a service to start/cancel/wait for URL fetches
25 // * Returns callers a CertNetFetcher::Request as a handle
26 // * Requests can run in parallel, however will block the current thread when
27 // reading results.
28 // * Posts tasks to network thread to coordinate actual work
29 //
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
45 // * Reference-counted bridge between CertNetFetcherRequestImpl and the
46 // dependencies on the network thread
47 // * Holds the result of the request, a WaitableEvent for signaling
48 // completion, and pointers for canceling work on network thread.
49 //
50 // ---------------
51 // Lives on network thread
52 // ---------------
53 //
54 // AsyncCertNetFetcherImpl
55 // * Asyncronous manager for outstanding requests. Handles de-duplication,
56 // timeouts, and actual integration with network stack. This is where the
57 // majority of the logic lives.
58 // * Signals completion of requests through RequestCore's WaitableEvent.
59 // * Attaches requests to Jobs for the purpose of de-duplication
4 60
5 #include "net/cert_net/cert_net_fetcher_impl.h" 61 #include "net/cert_net/cert_net_fetcher_impl.h"
6 62
7 #include <tuple> 63 #include <tuple>
8 #include <utility> 64 #include <utility>
9 65
10 #include "base/callback_helpers.h" 66 #include "base/callback_helpers.h"
11 #include "base/containers/linked_list.h"
12 #include "base/logging.h" 67 #include "base/logging.h"
13 #include "base/macros.h" 68 #include "base/macros.h"
14 #include "base/memory/ptr_util.h" 69 #include "base/memory/ptr_util.h"
15 #include "base/numerics/safe_math.h" 70 #include "base/numerics/safe_math.h"
71 #include "base/synchronization/waitable_event.h"
16 #include "base/timer/timer.h" 72 #include "base/timer/timer.h"
17 #include "net/base/load_flags.h" 73 #include "net/base/load_flags.h"
74 #include "net/cert/cert_net_fetcher.h"
18 #include "net/url_request/redirect_info.h" 75 #include "net/url_request/redirect_info.h"
19 #include "net/url_request/url_request_context.h" 76 #include "net/url_request/url_request_context.h"
77 #include "net/url_request/url_request_context_getter.h"
20 78
21 // TODO(eroman): Add support for POST parameters. 79 // TODO(eroman): Add support for POST parameters.
22 // TODO(eroman): Add controls for bypassing the cache. 80 // TODO(eroman): Add controls for bypassing the cache.
23 // TODO(eroman): Add a maximum number of in-flight jobs/requests. 81 // TODO(eroman): Add a maximum number of in-flight jobs/requests.
24 // TODO(eroman): Add NetLog integration. 82 // TODO(eroman): Add NetLog integration.
25 83
26 namespace net { 84 namespace net {
27 85
28 namespace { 86 namespace {
29 87
30 // The size of the buffer used for reading the response body of the URLRequest. 88 // The size of the buffer used for reading the response body of the URLRequest.
31 const int kReadBufferSizeInBytes = 4096; 89 const int kReadBufferSizeInBytes = 4096;
32 90
33 // The maximum size in bytes for the response body when fetching a CRL. 91 // The maximum size in bytes for the response body when fetching a CRL.
34 const int kMaxResponseSizeInBytesForCrl = 5 * 1024 * 1024; 92 const int kMaxResponseSizeInBytesForCrl = 5 * 1024 * 1024;
35 93
36 // The maximum size in bytes for the response body when fetching an AIA URL 94 // The maximum size in bytes for the response body when fetching an AIA URL
37 // (caIssuers/OCSP). 95 // (caIssuers/OCSP).
38 const int kMaxResponseSizeInBytesForAia = 64 * 1024; 96 const int kMaxResponseSizeInBytesForAia = 64 * 1024;
39 97
40 // The default timeout in seconds for fetch requests. 98 // The default timeout in seconds for fetch requests.
41 const int kTimeoutSeconds = 15; 99 const int kTimeoutSeconds = 15;
42 100
101 class RequestCore;
102 struct RequestParams;
103 class Job;
104
105 struct JobToRequestParamsComparator;
106
107 struct JobComparator {
108 bool operator()(const Job* job1, const Job* job2) const;
109 };
110
111 // Would be a set<unique_ptr> but extraction of owned objects from a set of
112 // owned types doesn't come until C++17.
113 using JobSet = std::map<Job*, std::unique_ptr<Job>, JobComparator>;
114
115 // AsyncCertNetFetcherImpl manages URLRequests in an async fashion on the
116 // URLRequestContexts's task runner thread.
117 //
118 // * Schedules
119 // * De-duplicates requests
120 // * Handles timeouts
121 class AsyncCertNetFetcherImpl {
122 public:
123 // Initializes AsyncCertNetFetcherImpl using the specified URLRequestContext
124 // for issuing requests. |context| must remain valid for the entire
125 // lifetime of the AsyncCertNetFetcherImpl.
126 explicit AsyncCertNetFetcherImpl(URLRequestContext* context);
127
128 // Deletion implicitly cancels any outstanding requests.
129 ~AsyncCertNetFetcherImpl();
130
131 // Starts an asynchronous request to fetch the given URL. On completion
132 // |callback| 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,
138 RequestCore* request);
139
140 private:
141 friend class Job;
142
143 // Finds a job with a matching RequestPararms or returns nullptr if there was
144 // no match.
145 Job* FindJob(const RequestParams& params);
146
147 // Removes |job| from the in progress jobs and transfers ownership to the
148 // caller.
149 std::unique_ptr<Job> RemoveJob(Job* job);
150
151 // The in-progress jobs. This set does not contain the job which is actively
152 // invoking callbacks (OnJobCompleted).
153 JobSet jobs_;
154
155 // Not owned. |context_| must outlive the AsyncCertNetFetcherImpl.
156 URLRequestContext* context_ = nullptr;
157
158 base::ThreadChecker thread_checker_;
159
160 DISALLOW_COPY_AND_ASSIGN(AsyncCertNetFetcherImpl);
161 };
162
43 // Policy for which URLs are allowed to be fetched. This is called both for the 163 // Policy for which URLs are allowed to be fetched. This is called both for the
44 // initial URL and for each redirect. Returns OK on success or a net error 164 // initial URL and for each redirect. Returns OK on success or a net error
45 // code on failure. 165 // code on failure.
46 Error CanFetchUrl(const GURL& url) { 166 Error CanFetchUrl(const GURL& url) {
47 if (!url.SchemeIs("http")) 167 if (!url.SchemeIs("http"))
48 return ERR_DISALLOWED_URL_SCHEME; 168 return ERR_DISALLOWED_URL_SCHEME;
49 return OK; 169 return OK;
50 } 170 }
51 171
52 base::TimeDelta GetTimeout(int timeout_milliseconds) { 172 base::TimeDelta GetTimeout(int timeout_milliseconds) {
(...skipping 14 matching lines...) Expand all
67 DCHECK(check.IsValid()); 187 DCHECK(check.IsValid());
68 188
69 return max_response_bytes; 189 return max_response_bytes;
70 } 190 }
71 191
72 enum HttpMethod { 192 enum HttpMethod {
73 HTTP_METHOD_GET, 193 HTTP_METHOD_GET,
74 HTTP_METHOD_POST, 194 HTTP_METHOD_POST,
75 }; 195 };
76 196
77 } // namespace 197 // RequestCore tracks an outstanding call to Fetch(). It is
198 // reference-counted for ease of sharing between threads.
199 class RequestCore : public base::RefCountedThreadSafe<RequestCore> {
200 public:
201 explicit RequestCore(scoped_refptr<base::SingleThreadTaskRunner> task_runner)
202 : completion_event_(base::WaitableEvent::ResetPolicy::MANUAL,
203 base::WaitableEvent::InitialState::NOT_SIGNALED),
204 task_runner_(std::move(task_runner)) {}
78 205
79 // CertNetFetcherImpl::RequestImpl tracks an outstanding call to Fetch(). 206 void AttachedToJob(Job* job) {
80 class CertNetFetcherImpl::RequestImpl : public CertNetFetcher::Request, 207 DCHECK(task_runner_->RunsTasksOnCurrentThread());
81 public base::LinkNode<RequestImpl> { 208 DCHECK(!job_);
82 public: 209 job_ = job;
83 RequestImpl(Job* job, const FetchCallback& callback)
84 : callback_(callback), job_(job) {
85 DCHECK(!callback.is_null());
86 }
87
88 // Deletion cancels the outstanding request.
89 ~RequestImpl() override;
90
91 void OnJobCancelled(Job* job) {
92 DCHECK_EQ(job_, job);
93 job_ = nullptr;
94 callback_.Reset();
95 } 210 }
96 211
97 void OnJobCompleted(Job* job, 212 void OnJobCompleted(Job* job,
98 Error error, 213 Error error,
99 const std::vector<uint8_t>& response_body) { 214 const std::vector<uint8_t>& response_body) {
215 DCHECK(task_runner_->RunsTasksOnCurrentThread());
216
100 DCHECK_EQ(job_, job); 217 DCHECK_EQ(job_, job);
101 job_ = nullptr; 218 job_ = nullptr;
102 base::ResetAndReturn(&callback_).Run(error, response_body); 219
220 error_ = error;
221 bytes_ = response_body;
222 completion_event_.Signal();
223 }
224
225 // Can be called from any thread.
226 void Cancel();
227
228 // Should only be called once.
229 void WaitForResult(Error* error, std::vector<uint8_t>* bytes) {
230 DCHECK(!task_runner_->RunsTasksOnCurrentThread());
231
232 completion_event_.Wait();
233 *bytes = std::move(bytes_);
234 *error = error_;
235
236 error_ = ERR_UNEXPECTED;
103 } 237 }
104 238
105 private: 239 private:
106 // The callback to invoke when the request has completed. 240 friend class base::RefCountedThreadSafe<RequestCore>;
107 FetchCallback callback_; 241
242 ~RequestCore() {
243 // Requests should have been cancelled prior to destruction.
244 DCHECK(!job_);
245 }
108 246
109 // A non-owned pointer to the job that is executing the request. 247 // A non-owned pointer to the job that is executing the request.
110 Job* job_; 248 Job* job_ = nullptr;
111 249
112 private: 250 // May be written to from network thread.
113 DISALLOW_COPY_AND_ASSIGN(RequestImpl); 251 Error error_;
252 std::vector<uint8_t> bytes_;
253
254 // Indicates when |error_| and |bytes_| have been written to.
255 base::WaitableEvent completion_event_;
256
257 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
258
259 DISALLOW_COPY_AND_ASSIGN(RequestCore);
114 }; 260 };
115 261
116 struct CertNetFetcherImpl::RequestParams { 262 struct RequestParams {
117 RequestParams(); 263 RequestParams();
118 264
119 bool operator<(const RequestParams& other) const; 265 bool operator<(const RequestParams& other) const;
120 266
121 GURL url; 267 GURL url;
122 HttpMethod http_method; 268 HttpMethod http_method;
123 size_t max_response_bytes; 269 size_t max_response_bytes;
124 270
125 // If set to a value <= 0 then means "no timeout". 271 // If set to a value <= 0 then means "no timeout".
126 base::TimeDelta timeout; 272 base::TimeDelta timeout;
127 273
128 // IMPORTANT: When adding fields to this structure, update operator<(). 274 // IMPORTANT: When adding fields to this structure, update operator<().
129 275
130 private: 276 private:
131 DISALLOW_COPY_AND_ASSIGN(RequestParams); 277 DISALLOW_COPY_AND_ASSIGN(RequestParams);
132 }; 278 };
133 279
134 CertNetFetcherImpl::RequestParams::RequestParams() 280 RequestParams::RequestParams()
135 : http_method(HTTP_METHOD_GET), max_response_bytes(0) { 281 : http_method(HTTP_METHOD_GET), max_response_bytes(0) {}
136 }
137 282
138 bool CertNetFetcherImpl::RequestParams::operator<( 283 bool RequestParams::operator<(const RequestParams& other) const {
139 const RequestParams& other) const {
140 return std::tie(url, http_method, max_response_bytes, timeout) < 284 return std::tie(url, http_method, max_response_bytes, timeout) <
141 std::tie(other.url, other.http_method, other.max_response_bytes, 285 std::tie(other.url, other.http_method, other.max_response_bytes,
142 other.timeout); 286 other.timeout);
143 } 287 }
144 288
145 // CertNetFetcherImpl::Job tracks an outstanding URLRequest as well as all of 289 // Job tracks an outstanding URLRequest as well as all of the pending requests
146 // the pending requests for it. 290 // for it.
147 class CertNetFetcherImpl::Job : public URLRequest::Delegate { 291 class Job : public URLRequest::Delegate {
148 public: 292 public:
149 Job(std::unique_ptr<RequestParams> request_params, 293 Job(std::unique_ptr<RequestParams> request_params,
150 CertNetFetcherImpl* parent); 294 AsyncCertNetFetcherImpl* parent);
151 ~Job() override; 295 ~Job() override;
152 296
153 // Cancels the job and all requests attached to it. No callbacks will be
154 // invoked following cancellation.
155 void Cancel();
156
157 const RequestParams& request_params() const { return *request_params_; } 297 const RequestParams& request_params() const { return *request_params_; }
158 298
159 // Create a request and attaches it to the job. When the job completes it will 299 // Create a request and attaches it to the job. When the job completes it will
160 // notify the request of completion through OnJobCompleted. Note that the Job 300 // notify the request of completion through OnJobCompleted. Note that the Job
161 // does NOT own the request. 301 // does NOT own the request.
162 std::unique_ptr<Request> CreateRequest(const FetchCallback& callback); 302 void AttachRequest(RequestCore* request);
163 303
164 // Removes |request| from the job. 304 // Removes |request| from the job.
165 void DetachRequest(RequestImpl* request); 305 void DetachRequest(RequestCore* request);
166 306
167 // Creates and starts a URLRequest for the job. After the request has 307 // Creates and starts a URLRequest for the job. After the URLRequest has
168 // completed, OnJobCompleted() will be invoked and all the registered requests 308 // completed, OnJobCompleted() will be invoked and all the registered requests
169 // notified of completion. 309 // notified of completion.
170 void StartURLRequest(URLRequestContext* context); 310 void StartURLRequest(URLRequestContext* context);
171 311
172 private: 312 private:
173 // The pointers in RequestList are not owned by the Job.
174 using RequestList = base::LinkedList<RequestImpl>;
175
176 // Implementation of URLRequest::Delegate 313 // Implementation of URLRequest::Delegate
177 void OnReceivedRedirect(URLRequest* request, 314 void OnReceivedRedirect(URLRequest* request,
178 const RedirectInfo& redirect_info, 315 const RedirectInfo& redirect_info,
179 bool* defer_redirect) override; 316 bool* defer_redirect) override;
180 void OnResponseStarted(URLRequest* request, int net_error) override; 317 void OnResponseStarted(URLRequest* request, int net_error) override;
181 void OnReadCompleted(URLRequest* request, int bytes_read) override; 318 void OnReadCompleted(URLRequest* request, int bytes_read) override;
182 319
183 // Clears the URLRequest and timer. Helper for doing work common to 320 // Clears the URLRequest and timer. Helper for doing work common to
184 // cancellation and job completion. 321 // cancellation and job completion.
185 void Stop(); 322 void Stop();
(...skipping 10 matching lines...) Expand all
196 333
197 // Called when the Job has completed. The job may finish in response to a 334 // Called when the Job has completed. The job may finish in response to a
198 // timeout, an invalid URL, or the URLRequest completing. By the time this 335 // timeout, an invalid URL, or the URLRequest completing. By the time this
199 // method is called, the |response_body_| variable have been assigned. 336 // method is called, the |response_body_| variable have been assigned.
200 void OnJobCompleted(Error error); 337 void OnJobCompleted(Error error);
201 338
202 // Cancels a request with a specified error code and calls 339 // Cancels a request with a specified error code and calls
203 // OnUrlRequestCompleted(). 340 // OnUrlRequestCompleted().
204 void FailRequest(Error error); 341 void FailRequest(Error error);
205 342
206 // The requests attached to this job. 343 // The requests attached to this job (non-owned).
207 RequestList requests_; 344 std::vector<RequestCore*> requests_;
208 345
209 // The input parameters for starting a URLRequest. 346 // The input parameters for starting a URLRequest.
210 std::unique_ptr<RequestParams> request_params_; 347 std::unique_ptr<RequestParams> request_params_;
211 348
212 // The URLRequest response information. 349 // The URLRequest response information.
213 std::vector<uint8_t> response_body_; 350 std::vector<uint8_t> response_body_;
214 351
215 std::unique_ptr<URLRequest> url_request_; 352 std::unique_ptr<URLRequest> url_request_;
216 scoped_refptr<IOBuffer> read_buffer_; 353 scoped_refptr<IOBuffer> read_buffer_;
217 354
218 // Used to timeout the job when the URLRequest takes too long. This timer is 355 // Used to timeout the job when the URLRequest takes too long. This timer is
219 // also used for notifying a failure to start the URLRequest. 356 // also used for notifying a failure to start the URLRequest.
220 base::OneShotTimer timer_; 357 base::OneShotTimer timer_;
221 358
222 // Non-owned pointer to the CertNetFetcherImpl that created this job. 359 // Non-owned pointer to the AsyncCertNetFetcherImpl that created this job.
223 CertNetFetcherImpl* parent_; 360 AsyncCertNetFetcherImpl* parent_;
224 361
225 DISALLOW_COPY_AND_ASSIGN(Job); 362 DISALLOW_COPY_AND_ASSIGN(Job);
226 }; 363 };
227 364
228 CertNetFetcherImpl::RequestImpl::~RequestImpl() { 365 void RequestCore::Cancel() {
229 if (job_) 366 if (!task_runner_->RunsTasksOnCurrentThread()) {
230 job_->DetachRequest(this); 367 task_runner_->PostTask(FROM_HERE, base::Bind(&RequestCore::Cancel, this));
368 return;
369 }
370
371 if (job_) {
372 auto* job = job_;
373 job_ = nullptr;
374 job->DetachRequest(this);
375 }
376
377 bytes_.clear();
378 error_ = ERR_UNEXPECTED;
231 } 379 }
232 380
233 CertNetFetcherImpl::Job::Job(std::unique_ptr<RequestParams> request_params, 381 Job::Job(std::unique_ptr<RequestParams> request_params,
234 CertNetFetcherImpl* parent) 382 AsyncCertNetFetcherImpl* parent)
235 : request_params_(std::move(request_params)), 383 : request_params_(std::move(request_params)), parent_(parent) {}
236 parent_(parent) {}
237 384
238 CertNetFetcherImpl::Job::~Job() { 385 Job::~Job() {
239 Cancel();
240 }
241
242 void CertNetFetcherImpl::Job::Cancel() {
243 parent_ = nullptr;
244
245 // Notify each request of cancellation and remove it from the list.
246 for (base::LinkNode<RequestImpl>* current = requests_.head();
247 current != requests_.end();) {
248 base::LinkNode<RequestImpl>* next = current->next();
249 current->value()->OnJobCancelled(this);
250 current->RemoveFromList();
251 current = next;
252 }
253
254 DCHECK(requests_.empty()); 386 DCHECK(requests_.empty());
255
256 Stop(); 387 Stop();
257 } 388 }
258 389
259 std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::Job::CreateRequest( 390 void Job::AttachRequest(RequestCore* request) {
260 const FetchCallback& callback) { 391 requests_.push_back(request);
261 std::unique_ptr<RequestImpl> request(new RequestImpl(this, callback)); 392 request->AttachedToJob(this);
262 requests_.Append(request.get());
263 return std::move(request);
264 } 393 }
265 394
266 void CertNetFetcherImpl::Job::DetachRequest(RequestImpl* request) { 395 void Job::DetachRequest(RequestCore* request) {
267 std::unique_ptr<Job> delete_this; 396 std::unique_ptr<Job> delete_this;
268 397
269 request->RemoveFromList(); 398 auto it = std::find(requests_.begin(), requests_.end(), request);
399 DCHECK(it != requests_.end());
400 requests_.erase(it);
270 401
271 // If there are no longer any requests attached to the job then 402 // If there are no longer any requests attached to the job then
272 // cancel and delete it. 403 // cancel and delete it.
273 if (requests_.empty() && !parent_->IsCurrentlyCompletingJob(this)) 404 if (requests_.empty())
274 delete_this = parent_->RemoveJob(this); 405 delete_this = parent_->RemoveJob(this);
275 } 406 }
276 407
277 void CertNetFetcherImpl::Job::StartURLRequest(URLRequestContext* context) { 408 void Job::StartURLRequest(URLRequestContext* context) {
278 Error error = CanFetchUrl(request_params_->url); 409 Error error = CanFetchUrl(request_params_->url);
279 if (error != OK) { 410 if (error != OK) {
280 // The CertNetFetcher's API contract is that requests always complete 411 // TODO(eroman): Don't post a task for this case.
281 // asynchronously. Use the timer class so the task is easily cancelled.
282 timer_.Start( 412 timer_.Start(
283 FROM_HERE, base::TimeDelta(), 413 FROM_HERE, base::TimeDelta(),
284 base::Bind(&Job::OnJobCompleted, base::Unretained(this), error)); 414 base::Bind(&Job::OnJobCompleted, base::Unretained(this), error));
285 return; 415 return;
286 } 416 }
287 417
288 // Start the URLRequest. 418 // Start the URLRequest.
289 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes); 419 read_buffer_ = new IOBuffer(kReadBufferSizeInBytes);
290 url_request_ = 420 url_request_ =
291 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this); 421 context->CreateRequest(request_params_->url, DEFAULT_PRIORITY, this);
292 if (request_params_->http_method == HTTP_METHOD_POST) 422 if (request_params_->http_method == HTTP_METHOD_POST)
293 url_request_->set_method("POST"); 423 url_request_->set_method("POST");
294 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES | 424 url_request_->SetLoadFlags(LOAD_DO_NOT_SAVE_COOKIES |
295 LOAD_DO_NOT_SEND_COOKIES); 425 LOAD_DO_NOT_SEND_COOKIES);
296 url_request_->Start(); 426 url_request_->Start();
297 427
298 // Start a timer to limit how long the job runs for. 428 // Start a timer to limit how long the job runs for.
299 if (request_params_->timeout > base::TimeDelta()) 429 if (request_params_->timeout > base::TimeDelta())
300 timer_.Start( 430 timer_.Start(
301 FROM_HERE, request_params_->timeout, 431 FROM_HERE, request_params_->timeout,
302 base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT)); 432 base::Bind(&Job::FailRequest, base::Unretained(this), ERR_TIMED_OUT));
303 } 433 }
304 434
305 void CertNetFetcherImpl::Job::OnReceivedRedirect( 435 void Job::OnReceivedRedirect(URLRequest* request,
306 URLRequest* request, 436 const RedirectInfo& redirect_info,
307 const RedirectInfo& redirect_info, 437 bool* defer_redirect) {
308 bool* defer_redirect) {
309 DCHECK_EQ(url_request_.get(), request); 438 DCHECK_EQ(url_request_.get(), request);
310 439
311 // Ensure that the new URL matches the policy. 440 // Ensure that the new URL matches the policy.
312 Error error = CanFetchUrl(redirect_info.new_url); 441 Error error = CanFetchUrl(redirect_info.new_url);
313 if (error != OK) { 442 if (error != OK) {
314 FailRequest(error); 443 FailRequest(error);
315 return; 444 return;
316 } 445 }
317 } 446 }
318 447
319 void CertNetFetcherImpl::Job::OnResponseStarted(URLRequest* request, 448 void Job::OnResponseStarted(URLRequest* request, int net_error) {
320 int net_error) {
321 DCHECK_EQ(url_request_.get(), request); 449 DCHECK_EQ(url_request_.get(), request);
322 DCHECK_NE(ERR_IO_PENDING, net_error); 450 DCHECK_NE(ERR_IO_PENDING, net_error);
323 451
324 if (net_error != OK) { 452 if (net_error != OK) {
325 OnUrlRequestCompleted(net_error); 453 OnUrlRequestCompleted(net_error);
326 return; 454 return;
327 } 455 }
328 456
329 if (request->GetResponseCode() != 200) { 457 if (request->GetResponseCode() != 200) {
330 // TODO(eroman): Use a more specific error code. 458 // TODO(eroman): Use a more specific error code.
331 FailRequest(ERR_FAILED); 459 FailRequest(ERR_FAILED);
332 return; 460 return;
333 } 461 }
334 462
335 ReadBody(request); 463 ReadBody(request);
336 } 464 }
337 465
338 void CertNetFetcherImpl::Job::OnReadCompleted(URLRequest* request, 466 void Job::OnReadCompleted(URLRequest* request, int bytes_read) {
339 int bytes_read) {
340 DCHECK_EQ(url_request_.get(), request); 467 DCHECK_EQ(url_request_.get(), request);
341 DCHECK_NE(ERR_IO_PENDING, bytes_read); 468 DCHECK_NE(ERR_IO_PENDING, bytes_read);
342 469
343 // Keep reading the response body. 470 // Keep reading the response body.
344 if (ConsumeBytesRead(request, bytes_read)) 471 if (ConsumeBytesRead(request, bytes_read))
345 ReadBody(request); 472 ReadBody(request);
346 } 473 }
347 474
348 void CertNetFetcherImpl::Job::Stop() { 475 void Job::Stop() {
349 timer_.Stop(); 476 timer_.Stop();
350 url_request_.reset(); 477 url_request_.reset();
351 } 478 }
352 479
353 void CertNetFetcherImpl::Job::ReadBody(URLRequest* request) { 480 void Job::ReadBody(URLRequest* request) {
354 // Read as many bytes as are available synchronously. 481 // Read as many bytes as are available synchronously.
355 int num_bytes = 0; 482 int num_bytes = 0;
356 while (num_bytes >= 0) { 483 while (num_bytes >= 0) {
357 num_bytes = request->Read(read_buffer_.get(), kReadBufferSizeInBytes); 484 num_bytes = request->Read(read_buffer_.get(), kReadBufferSizeInBytes);
358 if (num_bytes == ERR_IO_PENDING) 485 if (num_bytes == ERR_IO_PENDING)
359 return; 486 return;
360 if (!ConsumeBytesRead(request, num_bytes)) 487 if (!ConsumeBytesRead(request, num_bytes))
361 return; 488 return;
362 } 489 }
363 490
364 OnUrlRequestCompleted(num_bytes); 491 OnUrlRequestCompleted(num_bytes);
365 } 492 }
366 493
367 bool CertNetFetcherImpl::Job::ConsumeBytesRead(URLRequest* request, 494 bool Job::ConsumeBytesRead(URLRequest* request, int num_bytes) {
368 int num_bytes) {
369 DCHECK_NE(ERR_IO_PENDING, num_bytes); 495 DCHECK_NE(ERR_IO_PENDING, num_bytes);
370 if (num_bytes <= 0) { 496 if (num_bytes <= 0) {
371 // Error while reading, or EOF. 497 // Error while reading, or EOF.
372 OnUrlRequestCompleted(num_bytes); 498 OnUrlRequestCompleted(num_bytes);
373 return false; 499 return false;
374 } 500 }
375 501
376 // Enforce maximum size bound. 502 // Enforce maximum size bound.
377 if (num_bytes + response_body_.size() > request_params_->max_response_bytes) { 503 if (num_bytes + response_body_.size() > request_params_->max_response_bytes) {
378 FailRequest(ERR_FILE_TOO_BIG); 504 FailRequest(ERR_FILE_TOO_BIG);
379 return false; 505 return false;
380 } 506 }
381 507
382 // Append the data to |response_body_|. 508 // Append the data to |response_body_|.
383 response_body_.reserve(num_bytes); 509 response_body_.reserve(num_bytes);
384 response_body_.insert(response_body_.end(), read_buffer_->data(), 510 response_body_.insert(response_body_.end(), read_buffer_->data(),
385 read_buffer_->data() + num_bytes); 511 read_buffer_->data() + num_bytes);
386 return true; 512 return true;
387 } 513 }
388 514
389 void CertNetFetcherImpl::Job::OnUrlRequestCompleted(int net_error) { 515 void Job::OnUrlRequestCompleted(int net_error) {
390 DCHECK_NE(ERR_IO_PENDING, net_error); 516 DCHECK_NE(ERR_IO_PENDING, net_error);
391 Error result = static_cast<Error>(net_error); 517 Error result = static_cast<Error>(net_error);
392 OnJobCompleted(result); 518 OnJobCompleted(result);
393 } 519 }
394 520
395 void CertNetFetcherImpl::Job::OnJobCompleted(Error error) { 521 void Job::OnJobCompleted(Error error) {
396 DCHECK_NE(ERR_IO_PENDING, error); 522 DCHECK_NE(ERR_IO_PENDING, error);
397 // Stop the timer and clear the URLRequest. 523 // Stop the timer and clear the URLRequest.
398 Stop(); 524 Stop();
399 525
400 // Invoking the callbacks is subtle as state may be mutated while iterating 526 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this);
401 // through the callbacks:
402 //
403 // * The parent CertNetFetcherImpl may be deleted
404 // * Requests in this job may be cancelled
405 527
406 std::unique_ptr<Job> delete_this = parent_->RemoveJob(this); 528 for (auto* request : requests_) {
407 parent_->SetCurrentlyCompletingJob(this); 529 request->OnJobCompleted(this, error, response_body_);
408
409 while (!requests_.empty()) {
410 base::LinkNode<RequestImpl>* request = requests_.head();
411 request->RemoveFromList();
412 request->value()->OnJobCompleted(this, error, response_body_);
413 } 530 }
414 531
415 if (parent_) 532 requests_.clear();
416 parent_->ClearCurrentlyCompletingJob(this);
417 } 533 }
418 534
419 void CertNetFetcherImpl::Job::FailRequest(Error error) { 535 void Job::FailRequest(Error error) {
420 DCHECK_NE(ERR_IO_PENDING, error); 536 DCHECK_NE(ERR_IO_PENDING, error);
421 int result = url_request_->CancelWithError(error); 537 int result = url_request_->CancelWithError(error);
422 OnUrlRequestCompleted(result); 538 OnUrlRequestCompleted(result);
423 } 539 }
424 540
425 CertNetFetcherImpl::CertNetFetcherImpl(URLRequestContext* context) 541 AsyncCertNetFetcherImpl::AsyncCertNetFetcherImpl(URLRequestContext* context)
426 : currently_completing_job_(nullptr), context_(context) { 542 : context_(context) {
543 // Allow creation to happen from another thread.
544 thread_checker_.DetachFromThread();
427 } 545 }
428 546
429 CertNetFetcherImpl::~CertNetFetcherImpl() { 547 AsyncCertNetFetcherImpl::~AsyncCertNetFetcherImpl() {
548 DCHECK(thread_checker_.CalledOnValidThread());
430 jobs_.clear(); 549 jobs_.clear();
431
432 // The CertNetFetcherImpl was destroyed in a FetchCallback. Detach all
433 // remaining requests from the job so no further callbacks are called.
434 if (currently_completing_job_)
435 currently_completing_job_->Cancel();
436 } 550 }
437 551
438 std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchCaIssuers( 552 bool JobComparator::operator()(const Job* job1, const Job* job2) const {
439 const GURL& url,
440 int timeout_milliseconds,
441 int max_response_bytes,
442 const FetchCallback& callback) {
443 std::unique_ptr<RequestParams> request_params(new RequestParams);
444
445 request_params->url = url;
446 request_params->http_method = HTTP_METHOD_GET;
447 request_params->timeout = GetTimeout(timeout_milliseconds);
448 request_params->max_response_bytes =
449 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
450
451 return Fetch(std::move(request_params), callback);
452 }
453
454 std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchCrl(
455 const GURL& url,
456 int timeout_milliseconds,
457 int max_response_bytes,
458 const FetchCallback& callback) {
459 std::unique_ptr<RequestParams> request_params(new RequestParams);
460
461 request_params->url = url;
462 request_params->http_method = HTTP_METHOD_GET;
463 request_params->timeout = GetTimeout(timeout_milliseconds);
464 request_params->max_response_bytes =
465 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForCrl);
466
467 return Fetch(std::move(request_params), callback);
468 }
469
470 std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::FetchOcsp(
471 const GURL& url,
472 int timeout_milliseconds,
473 int max_response_bytes,
474 const FetchCallback& callback) {
475 std::unique_ptr<RequestParams> request_params(new RequestParams);
476
477 request_params->url = url;
478 request_params->http_method = HTTP_METHOD_GET;
479 request_params->timeout = GetTimeout(timeout_milliseconds);
480 request_params->max_response_bytes =
481 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
482
483 return Fetch(std::move(request_params), callback);
484 }
485
486 bool CertNetFetcherImpl::JobComparator::operator()(const Job* job1,
487 const Job* job2) const {
488 return job1->request_params() < job2->request_params(); 553 return job1->request_params() < job2->request_params();
489 } 554 }
490 555
491 std::unique_ptr<CertNetFetcher::Request> CertNetFetcherImpl::Fetch( 556 void AsyncCertNetFetcherImpl::Fetch(
492 std::unique_ptr<RequestParams> request_params, 557 std::unique_ptr<RequestParams> request_params,
493 const FetchCallback& callback) { 558 RequestCore* request) {
494 DCHECK(thread_checker_.CalledOnValidThread()); 559 DCHECK(thread_checker_.CalledOnValidThread());
495 560
496 // If there is an in-progress job that matches the request parameters use it. 561 // If there is an in-progress job that matches the request parameters use it.
497 // Otherwise start a new job. 562 // Otherwise start a new job.
498 Job* job = FindJob(*request_params); 563 Job* job = FindJob(*request_params);
499 564
500 if (!job) { 565 if (!job) {
501 job = new Job(std::move(request_params), this); 566 job = new Job(std::move(request_params), this);
502 jobs_[job] = base::WrapUnique(job); 567 jobs_[job] = base::WrapUnique(job);
503 job->StartURLRequest(context_); 568 job->StartURLRequest(context_);
504 } 569 }
505 570
506 return job->CreateRequest(callback); 571 return job->AttachRequest(request);
507 } 572 }
508 573
509 struct CertNetFetcherImpl::JobToRequestParamsComparator { 574 struct JobToRequestParamsComparator {
510 bool operator()(const CertNetFetcherImpl::JobSet::value_type& job, 575 bool operator()(const JobSet::value_type& job,
511 const CertNetFetcherImpl::RequestParams& value) const { 576 const RequestParams& value) const {
512 return job.first->request_params() < value; 577 return job.first->request_params() < value;
513 } 578 }
514 }; 579 };
515 580
516 CertNetFetcherImpl::Job* CertNetFetcherImpl::FindJob( 581 Job* AsyncCertNetFetcherImpl::FindJob(const RequestParams& params) {
517 const RequestParams& params) {
518 DCHECK(thread_checker_.CalledOnValidThread()); 582 DCHECK(thread_checker_.CalledOnValidThread());
519 583
520 // The JobSet is kept in sorted order so items can be found using binary 584 // The JobSet is kept in sorted order so items can be found using binary
521 // search. 585 // search.
522 JobSet::iterator it = std::lower_bound(jobs_.begin(), jobs_.end(), params, 586 JobSet::iterator it = std::lower_bound(jobs_.begin(), jobs_.end(), params,
523 JobToRequestParamsComparator()); 587 JobToRequestParamsComparator());
524 if (it != jobs_.end() && !(params < (*it).first->request_params())) 588 if (it != jobs_.end() && !(params < (*it).first->request_params()))
525 return (*it).first; 589 return (*it).first;
526 return nullptr; 590 return nullptr;
527 } 591 }
528 592
529 std::unique_ptr<CertNetFetcherImpl::Job> CertNetFetcherImpl::RemoveJob( 593 std::unique_ptr<Job> AsyncCertNetFetcherImpl::RemoveJob(Job* job) {
530 Job* job) {
531 DCHECK(thread_checker_.CalledOnValidThread()); 594 DCHECK(thread_checker_.CalledOnValidThread());
532 auto it = jobs_.find(job); 595 auto it = jobs_.find(job);
533 CHECK(it != jobs_.end()); 596 CHECK(it != jobs_.end());
534 std::unique_ptr<Job> owned_job = std::move(it->second); 597 std::unique_ptr<Job> owned_job = std::move(it->second);
535 jobs_.erase(it); 598 jobs_.erase(it);
536 return owned_job; 599 return owned_job;
537 } 600 }
538 601
539 void CertNetFetcherImpl::SetCurrentlyCompletingJob(Job* job) { 602 class CertNetFetcherRequestImpl : public CertNetFetcher::Request {
540 DCHECK(!currently_completing_job_); 603 public:
541 DCHECK(job); 604 explicit CertNetFetcherRequestImpl(scoped_refptr<RequestCore> core)
542 currently_completing_job_ = job; 605 : core_(std::move(core)) {
543 } 606 DCHECK(core_);
607 }
544 608
545 void CertNetFetcherImpl::ClearCurrentlyCompletingJob(Job* job) { 609 void WaitForResult(Error* error, std::vector<uint8_t>* bytes) override {
546 DCHECK_EQ(currently_completing_job_, job); 610 // Should only be called a single time.
547 currently_completing_job_ = nullptr; 611 DCHECK(core_);
548 } 612 core_->WaitForResult(error, bytes);
613 core_ = nullptr;
614 }
549 615
550 bool CertNetFetcherImpl::IsCurrentlyCompletingJob(Job* job) { 616 ~CertNetFetcherRequestImpl() override {
551 return job == currently_completing_job_; 617 if (core_)
618 core_->Cancel();
619 }
620
621 private:
622 scoped_refptr<RequestCore> core_;
623 };
624
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 {
673 public:
674 explicit CertNetFetcherImpl(URLRequestContextGetter* context_getter)
675 : core_(new CertNetFetcherCore(context_getter)) {}
676
677 ~CertNetFetcherImpl() override { core_->Abandon(); }
678
679 std::unique_ptr<Request> FetchCaIssuers(const GURL& url,
680 int timeout_milliseconds,
681 int max_response_bytes) override {
682 std::unique_ptr<RequestParams> request_params(new RequestParams);
683
684 request_params->url = url;
685 request_params->http_method = HTTP_METHOD_GET;
686 request_params->timeout = GetTimeout(timeout_milliseconds);
687 request_params->max_response_bytes =
688 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
689
690 return DoFetch(std::move(request_params));
691 }
692
693 std::unique_ptr<Request> FetchCrl(const GURL& url,
694 int timeout_milliseconds,
695 int max_response_bytes) override {
696 std::unique_ptr<RequestParams> request_params(new RequestParams);
697
698 request_params->url = url;
699 request_params->http_method = HTTP_METHOD_GET;
700 request_params->timeout = GetTimeout(timeout_milliseconds);
701 request_params->max_response_bytes =
702 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForCrl);
703
704 return DoFetch(std::move(request_params));
705 }
706
707 WARN_UNUSED_RESULT std::unique_ptr<Request> FetchOcsp(
708 const GURL& url,
709 int timeout_milliseconds,
710 int max_response_bytes) override {
711 std::unique_ptr<RequestParams> request_params(new RequestParams);
712
713 request_params->url = url;
714 request_params->http_method = HTTP_METHOD_GET;
715 request_params->timeout = GetTimeout(timeout_milliseconds);
716 request_params->max_response_bytes =
717 GetMaxResponseBytes(max_response_bytes, kMaxResponseSizeInBytesForAia);
718
719 return DoFetch(std::move(request_params));
720 }
721
722 private:
723 std::unique_ptr<Request> DoFetch(
724 std::unique_ptr<RequestParams> request_params) {
725 auto task_runner = core_->GetNetworkTaskRunner();
726 scoped_refptr<RequestCore> request_core = new RequestCore(task_runner);
727
728 task_runner->PostTask(
729 FROM_HERE,
730 base::Bind(&CertNetFetcherCore::DoFetchOnNetworkThread, core_,
731 base::Passed(&request_params), request_core));
732
733 return base::MakeUnique<CertNetFetcherRequestImpl>(std::move(request_core));
734 }
735
736 private:
737 scoped_refptr<CertNetFetcherCore> core_;
738 };
739
740 } // namespace
741
742 std::unique_ptr<CertNetFetcher> CreateCertNetFetcher(
743 URLRequestContextGetter* context_getter) {
744 return base::MakeUnique<CertNetFetcherImpl>(context_getter);
552 } 745 }
553 746
554 } // namespace net 747 } // 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