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

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

Powered by Google App Engine
This is Rietveld 408576698