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

Side by Side Diff: net/http/disk_based_cert_cache.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/http/disk_based_cert_cache.h ('k') | net/http/disk_based_cert_cache_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
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/http/disk_based_cert_cache.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/metrics/histogram.h"
13 #include "base/profiler/scoped_tracker.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/disk_cache/disk_cache.h"
19
20 namespace net {
21
22 namespace {
23
24 // TODO(brandonsalmon): change this number to improve performance.
25 const size_t kMemoryCacheMaxSize = 30;
26
27 // Used to obtain a unique cache key for a certificate in the form of
28 // "cert:<hash>".
29 std::string GetCacheKeyForCert(
30 const X509Certificate::OSCertHandle cert_handle) {
31 SHA1HashValue fingerprint =
32 X509Certificate::CalculateFingerprint(cert_handle);
33
34 return "cert:" +
35 base::HexEncode(fingerprint.data, arraysize(fingerprint.data));
36 }
37
38 enum CacheResult {
39 MEMORY_CACHE_HIT = 0,
40 DISK_CACHE_HIT,
41 DISK_CACHE_ENTRY_CORRUPT,
42 DISK_CACHE_ERROR,
43 CACHE_RESULT_MAX
44 };
45
46 void RecordCacheResult(CacheResult result) {
47 UMA_HISTOGRAM_ENUMERATION(
48 "DiskBasedCertCache.CertIoCacheResult", result, CACHE_RESULT_MAX);
49 }
50
51 } // namespace
52
53 // WriteWorkers represent pending SetCertificate jobs in the DiskBasedCertCache.
54 // Each certificate requested to be stored is assigned a WriteWorker.
55 // The same certificate should not have multiple WriteWorkers at the same
56 // time; instead, add a user callback to the existing WriteWorker.
57 class DiskBasedCertCache::WriteWorker {
58 public:
59 // |backend| is the backend to store |certificate| in, using
60 // |key| as the key for the disk_cache::Entry.
61 // |cleanup_callback| is called to clean up this ReadWorker,
62 // regardless of success or failure.
63 WriteWorker(disk_cache::Backend* backend,
64 const std::string& key,
65 X509Certificate::OSCertHandle cert_handle,
66 const base::Closure& cleanup_callback);
67
68 ~WriteWorker();
69
70 // Writes the given certificate to the cache. On completion, will invoke all
71 // user callbacks.
72 void Start();
73
74 // Adds a callback to the set of callbacks to be run when this
75 // WriteWorker finishes processing.
76 void AddCallback(const SetCallback& user_callback);
77
78 // Signals the WriteWorker to abort early. The WriteWorker will be destroyed
79 // upon the completion of any pending callbacks. User callbacks will be
80 // invoked with an empty string.
81 void Cancel();
82
83 private:
84 enum State {
85 STATE_OPEN,
86 STATE_OPEN_COMPLETE,
87 STATE_CREATE,
88 STATE_CREATE_COMPLETE,
89 STATE_WRITE,
90 STATE_WRITE_COMPLETE,
91 STATE_NONE
92 };
93
94 void OnIOComplete(int rv);
95 int DoLoop(int rv);
96
97 int DoOpen();
98 int DoOpenComplete(int rv);
99 int DoCreate();
100 int DoCreateComplete(int rv);
101 int DoWrite();
102 int DoWriteComplete(int rv);
103
104 void Finish(int rv);
105
106 // Invokes all of the |user_callbacks_|
107 void RunCallbacks(int rv);
108
109 disk_cache::Backend* backend_;
110 const X509Certificate::OSCertHandle cert_handle_;
111 std::string key_;
112 bool canceled_;
113
114 disk_cache::Entry* entry_;
115 State next_state_;
116 scoped_refptr<IOBuffer> buffer_;
117 int io_buf_len_;
118
119 base::Closure cleanup_callback_;
120 std::vector<SetCallback> user_callbacks_;
121 CompletionCallback io_callback_;
122 };
123
124 DiskBasedCertCache::WriteWorker::WriteWorker(
125 disk_cache::Backend* backend,
126 const std::string& key,
127 X509Certificate::OSCertHandle cert_handle,
128 const base::Closure& cleanup_callback)
129 : backend_(backend),
130 cert_handle_(X509Certificate::DupOSCertHandle(cert_handle)),
131 key_(key),
132 canceled_(false),
133 entry_(NULL),
134 next_state_(STATE_NONE),
135 io_buf_len_(0),
136 cleanup_callback_(cleanup_callback),
137 io_callback_(
138 base::Bind(&WriteWorker::OnIOComplete, base::Unretained(this))) {
139 }
140
141 DiskBasedCertCache::WriteWorker::~WriteWorker() {
142 if (cert_handle_)
143 X509Certificate::FreeOSCertHandle(cert_handle_);
144 if (entry_)
145 entry_->Close();
146 }
147
148 void DiskBasedCertCache::WriteWorker::Start() {
149 DCHECK_EQ(STATE_NONE, next_state_);
150
151 next_state_ = STATE_OPEN;
152 int rv = DoLoop(OK);
153
154 if (rv == ERR_IO_PENDING)
155 return;
156
157 Finish(rv);
158 }
159
160 void DiskBasedCertCache::WriteWorker::AddCallback(
161 const SetCallback& user_callback) {
162 user_callbacks_.push_back(user_callback);
163 }
164
165 void DiskBasedCertCache::WriteWorker::Cancel() {
166 canceled_ = true;
167 }
168
169 void DiskBasedCertCache::WriteWorker::OnIOComplete(int rv) {
170 if (canceled_) {
171 Finish(ERR_FAILED);
172 return;
173 }
174
175 rv = DoLoop(rv);
176
177 if (rv == ERR_IO_PENDING)
178 return;
179
180 Finish(rv);
181 }
182
183 int DiskBasedCertCache::WriteWorker::DoLoop(int rv) {
184 do {
185 State state = next_state_;
186 next_state_ = STATE_NONE;
187 switch (state) {
188 case STATE_OPEN:
189 rv = DoOpen();
190 break;
191 case STATE_OPEN_COMPLETE:
192 rv = DoOpenComplete(rv);
193 break;
194 case STATE_CREATE:
195 rv = DoCreate();
196 break;
197 case STATE_CREATE_COMPLETE:
198 rv = DoCreateComplete(rv);
199 break;
200 case STATE_WRITE:
201 rv = DoWrite();
202 break;
203 case STATE_WRITE_COMPLETE:
204 rv = DoWriteComplete(rv);
205 break;
206 case STATE_NONE:
207 NOTREACHED();
208 break;
209 }
210 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
211
212 return rv;
213 }
214
215 int DiskBasedCertCache::WriteWorker::DoOpen() {
216 next_state_ = STATE_OPEN_COMPLETE;
217 return backend_->OpenEntry(key_, &entry_, io_callback_);
218 }
219
220 int DiskBasedCertCache::WriteWorker::DoOpenComplete(int rv) {
221 // The entry doesn't exist yet, so we should create it.
222 if (rv < 0) {
223 next_state_ = STATE_CREATE;
224 return OK;
225 }
226
227 next_state_ = STATE_WRITE;
228 return OK;
229 }
230
231 int DiskBasedCertCache::WriteWorker::DoCreate() {
232 next_state_ = STATE_CREATE_COMPLETE;
233 return backend_->CreateEntry(key_, &entry_, io_callback_);
234 }
235
236 int DiskBasedCertCache::WriteWorker::DoCreateComplete(int rv) {
237 if (rv < 0)
238 return rv;
239
240 next_state_ = STATE_WRITE;
241 return OK;
242 }
243
244 int DiskBasedCertCache::WriteWorker::DoWrite() {
245 std::string write_data;
246 bool encoded = X509Certificate::GetDEREncoded(cert_handle_, &write_data);
247
248 if (!encoded)
249 return ERR_FAILED;
250
251 buffer_ = new IOBuffer(write_data.size());
252 io_buf_len_ = write_data.size();
253 memcpy(buffer_->data(), write_data.data(), io_buf_len_);
254
255 next_state_ = STATE_WRITE_COMPLETE;
256
257 return entry_->WriteData(0 /* index */,
258 0 /* offset */,
259 buffer_.get(),
260 write_data.size(),
261 io_callback_,
262 true /* truncate */);
263 }
264
265 int DiskBasedCertCache::WriteWorker::DoWriteComplete(int rv) {
266 if (rv < io_buf_len_)
267 return ERR_FAILED;
268
269 return OK;
270 }
271
272 void DiskBasedCertCache::WriteWorker::Finish(int rv) {
273 cleanup_callback_.Run();
274 cleanup_callback_.Reset();
275 RunCallbacks(rv);
276 delete this;
277 }
278
279 void DiskBasedCertCache::WriteWorker::RunCallbacks(int rv) {
280 std::string key;
281 if (rv >= 0)
282 key = key_;
283
284 for (std::vector<SetCallback>::const_iterator it = user_callbacks_.begin();
285 it != user_callbacks_.end();
286 ++it) {
287 it->Run(key);
288 }
289 user_callbacks_.clear();
290 }
291
292 // ReadWorkers represent pending GetCertificate jobs in the DiskBasedCertCache.
293 // Each certificate requested to be retrieved from the cache is assigned a
294 // ReadWorker. The same |key| should not have multiple ReadWorkers at the
295 // same time; instead, call AddCallback to add a user callback to the
296 // existing ReadWorker.
297 class DiskBasedCertCache::ReadWorker {
298 public:
299 // |backend| is the backend to read |certificate| from, using
300 // |key| as the key for the disk_cache::Entry.
301 // |cleanup_callback| is called to clean up this ReadWorker,
302 // regardless of success or failure.
303 ReadWorker(disk_cache::Backend* backend,
304 const std::string& key,
305 const GetCallback& cleanup_callback);
306
307 ~ReadWorker();
308
309 // Reads the given certificate from the cache. On completion, will invoke all
310 // user callbacks.
311 void Start();
312
313 // Adds a callback to the set of callbacks to be run when this
314 // ReadWorker finishes processing.
315 void AddCallback(const GetCallback& user_callback);
316
317 // Signals the ReadWorker to abort early. The ReadWorker will be destroyed
318 // upon the completion of any pending callbacks. User callbacks will be
319 // invoked with a NULL cert handle.
320 void Cancel();
321
322 private:
323 enum State {
324 STATE_OPEN,
325 STATE_OPEN_COMPLETE,
326 STATE_READ,
327 STATE_READ_COMPLETE,
328 STATE_NONE
329 };
330
331 void OnIOComplete(int rv);
332 int DoLoop(int rv);
333 int DoOpen();
334 int DoOpenComplete(int rv);
335 int DoRead();
336 int DoReadComplete(int rv);
337 void Finish(int rv);
338
339 // Invokes all of |user_callbacks_|
340 void RunCallbacks();
341
342 disk_cache::Backend* backend_;
343 X509Certificate::OSCertHandle cert_handle_;
344 std::string key_;
345 bool canceled_;
346
347 disk_cache::Entry* entry_;
348
349 State next_state_;
350 scoped_refptr<IOBuffer> buffer_;
351 int io_buf_len_;
352
353 GetCallback cleanup_callback_;
354 std::vector<GetCallback> user_callbacks_;
355 CompletionCallback io_callback_;
356 };
357
358 DiskBasedCertCache::ReadWorker::ReadWorker(disk_cache::Backend* backend,
359 const std::string& key,
360 const GetCallback& cleanup_callback)
361 : backend_(backend),
362 cert_handle_(NULL),
363 key_(key),
364 canceled_(false),
365 entry_(NULL),
366 next_state_(STATE_NONE),
367 io_buf_len_(0),
368 cleanup_callback_(cleanup_callback),
369 io_callback_(
370 base::Bind(&ReadWorker::OnIOComplete, base::Unretained(this))) {
371 }
372
373 DiskBasedCertCache::ReadWorker::~ReadWorker() {
374 if (entry_)
375 entry_->Close();
376 if (cert_handle_)
377 X509Certificate::FreeOSCertHandle(cert_handle_);
378 }
379
380 void DiskBasedCertCache::ReadWorker::Start() {
381 DCHECK_EQ(STATE_NONE, next_state_);
382 next_state_ = STATE_OPEN;
383 int rv = DoLoop(OK);
384
385 if (rv == ERR_IO_PENDING)
386 return;
387
388 Finish(rv);
389 }
390
391 void DiskBasedCertCache::ReadWorker::AddCallback(
392 const GetCallback& user_callback) {
393 user_callbacks_.push_back(user_callback);
394 }
395
396 void DiskBasedCertCache::ReadWorker::Cancel() {
397 canceled_ = true;
398 }
399
400 void DiskBasedCertCache::ReadWorker::OnIOComplete(int rv) {
401 // TODO(vadimt): Remove ScopedTracker below once crbug.com/422516 is fixed.
402 tracked_objects::ScopedTracker tracking_profile(
403 FROM_HERE_WITH_EXPLICIT_FUNCTION(
404 "422516 DiskBasedCertCache::ReadWorker::OnIOComplete"));
405
406 if (canceled_) {
407 Finish(ERR_FAILED);
408 return;
409 }
410
411 rv = DoLoop(rv);
412
413 if (rv == ERR_IO_PENDING)
414 return;
415
416 Finish(rv);
417 }
418
419 int DiskBasedCertCache::ReadWorker::DoLoop(int rv) {
420 do {
421 State state = next_state_;
422 next_state_ = STATE_NONE;
423 switch (state) {
424 case STATE_OPEN:
425 rv = DoOpen();
426 break;
427 case STATE_OPEN_COMPLETE:
428 rv = DoOpenComplete(rv);
429 break;
430 case STATE_READ:
431 rv = DoRead();
432 break;
433 case STATE_READ_COMPLETE:
434 rv = DoReadComplete(rv);
435 break;
436 case STATE_NONE:
437 NOTREACHED();
438 break;
439 }
440 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
441
442 return rv;
443 }
444
445 int DiskBasedCertCache::ReadWorker::DoOpen() {
446 next_state_ = STATE_OPEN_COMPLETE;
447 return backend_->OpenEntry(key_, &entry_, io_callback_);
448 }
449
450 int DiskBasedCertCache::ReadWorker::DoOpenComplete(int rv) {
451 if (rv < 0) {
452 RecordCacheResult(DISK_CACHE_ERROR);
453 return rv;
454 }
455
456 next_state_ = STATE_READ;
457 return OK;
458 }
459
460 int DiskBasedCertCache::ReadWorker::DoRead() {
461 next_state_ = STATE_READ_COMPLETE;
462 io_buf_len_ = entry_->GetDataSize(0 /* index */);
463 buffer_ = new IOBuffer(io_buf_len_);
464 return entry_->ReadData(
465 0 /* index */, 0 /* offset */, buffer_.get(), io_buf_len_, io_callback_);
466 }
467
468 int DiskBasedCertCache::ReadWorker::DoReadComplete(int rv) {
469 // The cache should return the entire buffer length. If it does not,
470 // it is probably indicative of an issue other than corruption.
471 if (rv < io_buf_len_) {
472 RecordCacheResult(DISK_CACHE_ERROR);
473 return ERR_FAILED;
474 }
475 cert_handle_ = X509Certificate::CreateOSCertHandleFromBytes(buffer_->data(),
476 io_buf_len_);
477 if (!cert_handle_) {
478 RecordCacheResult(DISK_CACHE_ENTRY_CORRUPT);
479 return ERR_FAILED;
480 }
481
482 RecordCacheResult(DISK_CACHE_HIT);
483 return OK;
484 }
485
486 void DiskBasedCertCache::ReadWorker::Finish(int rv) {
487 cleanup_callback_.Run(cert_handle_);
488 cleanup_callback_.Reset();
489 RunCallbacks();
490 delete this;
491 }
492
493 void DiskBasedCertCache::ReadWorker::RunCallbacks() {
494 for (std::vector<GetCallback>::const_iterator it = user_callbacks_.begin();
495 it != user_callbacks_.end();
496 ++it) {
497 it->Run(cert_handle_);
498 }
499 user_callbacks_.clear();
500 }
501
502 void DiskBasedCertCache::CertFree::operator()(
503 X509Certificate::OSCertHandle cert_handle) {
504 X509Certificate::FreeOSCertHandle(cert_handle);
505 }
506
507 DiskBasedCertCache::DiskBasedCertCache(disk_cache::Backend* backend)
508 : backend_(backend),
509 mru_cert_cache_(kMemoryCacheMaxSize),
510 mem_cache_hits_(0),
511 mem_cache_misses_(0),
512 weak_factory_(this) {
513 DCHECK(backend_);
514 }
515
516 DiskBasedCertCache::~DiskBasedCertCache() {
517 for (WriteWorkerMap::iterator it = write_worker_map_.begin();
518 it != write_worker_map_.end();
519 ++it) {
520 it->second->Cancel();
521 }
522 for (ReadWorkerMap::iterator it = read_worker_map_.begin();
523 it != read_worker_map_.end();
524 ++it) {
525 it->second->Cancel();
526 }
527 }
528
529 void DiskBasedCertCache::GetCertificate(const std::string& key,
530 const GetCallback& cb) {
531 DCHECK(!key.empty());
532
533 // If the handle is already in the MRU cache, just return that (via callback).
534 // Note, this will also bring the cert_handle to the front of the recency
535 // list in the MRU cache.
536 MRUCertCache::iterator mru_it = mru_cert_cache_.Get(key);
537 if (mru_it != mru_cert_cache_.end()) {
538 RecordCacheResult(MEMORY_CACHE_HIT);
539 ++mem_cache_hits_;
540 cb.Run(mru_it->second);
541 return;
542 }
543 ++mem_cache_misses_;
544
545 ReadWorkerMap::iterator it = read_worker_map_.find(key);
546
547 if (it == read_worker_map_.end()) {
548 ReadWorker* worker =
549 new ReadWorker(backend_,
550 key,
551 base::Bind(&DiskBasedCertCache::FinishedReadOperation,
552 weak_factory_.GetWeakPtr(),
553 key));
554 read_worker_map_[key] = worker;
555 worker->AddCallback(cb);
556 worker->Start();
557 } else {
558 it->second->AddCallback(cb);
559 }
560 }
561
562 void DiskBasedCertCache::SetCertificate(
563 const X509Certificate::OSCertHandle cert_handle,
564 const SetCallback& cb) {
565 DCHECK(!cb.is_null());
566 DCHECK(cert_handle);
567 std::string key = GetCacheKeyForCert(cert_handle);
568
569 WriteWorkerMap::iterator it = write_worker_map_.find(key);
570
571 if (it == write_worker_map_.end()) {
572 WriteWorker* worker =
573 new WriteWorker(backend_,
574 key,
575 cert_handle,
576 base::Bind(&DiskBasedCertCache::FinishedWriteOperation,
577 weak_factory_.GetWeakPtr(),
578 key,
579 cert_handle));
580 write_worker_map_[key] = worker;
581 worker->AddCallback(cb);
582 worker->Start();
583 } else {
584 it->second->AddCallback(cb);
585 }
586 }
587
588 void DiskBasedCertCache::FinishedReadOperation(
589 const std::string& key,
590 X509Certificate::OSCertHandle cert_handle) {
591 if (cert_handle)
592 mru_cert_cache_.Put(key, X509Certificate::DupOSCertHandle(cert_handle));
593 read_worker_map_.erase(key);
594 }
595
596 void DiskBasedCertCache::FinishedWriteOperation(
597 const std::string& key,
598 X509Certificate::OSCertHandle cert_handle) {
599 write_worker_map_.erase(key);
600 if (!key.empty())
601 mru_cert_cache_.Put(key, X509Certificate::DupOSCertHandle(cert_handle));
602 }
603
604 } // namespace net
OLDNEW
« no previous file with comments | « net/http/disk_based_cert_cache.h ('k') | net/http/disk_based_cert_cache_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698