OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/cert_net/cert_net_fetcher_impl.h" | 5 #include "net/cert_net/cert_net_fetcher_impl.h" |
6 | 6 |
7 #include <tuple> | 7 #include <tuple> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |