| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/http/disk_based_cert_cache.h" | 5 #include "net/http/disk_based_cert_cache.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| 11 #include "base/memory/ref_counted.h" | 11 #include "base/memory/ref_counted.h" |
| 12 #include "base/metrics/histogram.h" |
| 12 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 13 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
| 14 #include "net/base/io_buffer.h" | 15 #include "net/base/io_buffer.h" |
| 15 #include "net/base/net_errors.h" | 16 #include "net/base/net_errors.h" |
| 16 #include "net/disk_cache/disk_cache.h" | 17 #include "net/disk_cache/disk_cache.h" |
| 17 | 18 |
| 18 namespace net { | 19 namespace net { |
| 19 | 20 |
| 20 namespace { | 21 namespace { |
| 21 | 22 |
| 22 // TODO(brandonsalmon): change this number to improve performance. | 23 // TODO(brandonsalmon): change this number to improve performance. |
| 23 const size_t kMemoryCacheMaxSize = 30; | 24 const size_t kMemoryCacheMaxSize = 30; |
| 24 | 25 |
| 25 // Used to obtain a unique cache key for a certificate in the form of | 26 // Used to obtain a unique cache key for a certificate in the form of |
| 26 // "cert:<hash>". | 27 // "cert:<hash>". |
| 27 std::string GetCacheKeyToCert(const X509Certificate::OSCertHandle cert_handle) { | 28 std::string GetCacheKeyForCert( |
| 29 const X509Certificate::OSCertHandle cert_handle) { |
| 28 SHA1HashValue fingerprint = | 30 SHA1HashValue fingerprint = |
| 29 X509Certificate::CalculateFingerprint(cert_handle); | 31 X509Certificate::CalculateFingerprint(cert_handle); |
| 30 | 32 |
| 31 return "cert:" + | 33 return "cert:" + |
| 32 base::HexEncode(fingerprint.data, arraysize(fingerprint.data)); | 34 base::HexEncode(fingerprint.data, arraysize(fingerprint.data)); |
| 33 } | 35 } |
| 34 | 36 |
| 37 enum CacheResult { |
| 38 MEMORY_CACHE_HIT = 0, |
| 39 DISK_CACHE_HIT, |
| 40 DISK_CACHE_ENTRY_CORRUPT, |
| 41 DISK_CACHE_ERROR, |
| 42 CACHE_MISS, |
| 43 CACHE_RESULT_MAX |
| 44 }; |
| 45 |
| 46 void RecordCacheResult(CacheResult result) { |
| 47 UMA_HISTOGRAM_ENUMERATION( |
| 48 "DiskBasedCertCache.CertIoCacheResult", result, CACHE_RESULT_MAX); |
| 49 } |
| 50 |
| 35 } // namespace | 51 } // namespace |
| 36 | 52 |
| 37 // WriteWorkers represent pending Set jobs in the DiskBasedCertCache. Each | 53 // WriteWorkers represent pending Set jobs in the DiskBasedCertCache. Each |
| 38 // certificate requested to be cached is assigned a Writeworker on a one-to-one | 54 // certificate requested to be cached is assigned a Writeworker on a one-to-one |
| 39 // basis. The same certificate should not have multiple WriteWorkers at the same | 55 // basis. The same certificate should not have multiple WriteWorkers at the same |
| 40 // time; instead, add a user callback to the existing WriteWorker. | 56 // time; instead, add a user callback to the existing WriteWorker. |
| 41 class DiskBasedCertCache::WriteWorker { | 57 class DiskBasedCertCache::WriteWorker { |
| 42 public: | 58 public: |
| 43 // |backend| is the backend to store |certificate| in, using | 59 // |backend| is the backend to store |certificate| in, using |
| 44 // |key| as the key for the disk_cache::Entry. | 60 // |key| as the key for the disk_cache::Entry. |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 canceled_(false), | 132 canceled_(false), |
| 117 entry_(NULL), | 133 entry_(NULL), |
| 118 state_(STATE_NONE), | 134 state_(STATE_NONE), |
| 119 io_buf_len_(0), | 135 io_buf_len_(0), |
| 120 cleanup_callback_(cleanup_callback), | 136 cleanup_callback_(cleanup_callback), |
| 121 io_callback_( | 137 io_callback_( |
| 122 base::Bind(&WriteWorker::OnIOComplete, base::Unretained(this))) { | 138 base::Bind(&WriteWorker::OnIOComplete, base::Unretained(this))) { |
| 123 } | 139 } |
| 124 | 140 |
| 125 DiskBasedCertCache::WriteWorker::~WriteWorker() { | 141 DiskBasedCertCache::WriteWorker::~WriteWorker() { |
| 126 X509Certificate::FreeOSCertHandle(cert_handle_); | 142 if (cert_handle_) |
| 143 X509Certificate::FreeOSCertHandle(cert_handle_); |
| 127 if (entry_) | 144 if (entry_) |
| 128 entry_->Close(); | 145 entry_->Close(); |
| 129 } | 146 } |
| 130 | 147 |
| 131 void DiskBasedCertCache::WriteWorker::Start() { | 148 void DiskBasedCertCache::WriteWorker::Start() { |
| 132 DCHECK_EQ(STATE_NONE, state_); | 149 DCHECK_EQ(STATE_NONE, state_); |
| 133 state_ = STATE_CREATE; | 150 state_ = STATE_CREATE; |
| 134 int rv = DoLoop(OK); | 151 int rv = DoLoop(OK); |
| 135 | 152 |
| 136 if (rv == ERR_IO_PENDING) | 153 if (rv == ERR_IO_PENDING) |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 | 438 |
| 422 return rv; | 439 return rv; |
| 423 } | 440 } |
| 424 | 441 |
| 425 int DiskBasedCertCache::ReadWorker::DoOpen() { | 442 int DiskBasedCertCache::ReadWorker::DoOpen() { |
| 426 state_ = STATE_OPEN_COMPLETE; | 443 state_ = STATE_OPEN_COMPLETE; |
| 427 return backend_->OpenEntry(key_, &entry_, io_callback_); | 444 return backend_->OpenEntry(key_, &entry_, io_callback_); |
| 428 } | 445 } |
| 429 | 446 |
| 430 int DiskBasedCertCache::ReadWorker::DoOpenComplete(int rv) { | 447 int DiskBasedCertCache::ReadWorker::DoOpenComplete(int rv) { |
| 431 if (rv < 0) | 448 if (rv < 0) { |
| 449 // Errors other than ERR_CACHE_MISS are not recorded as either a hit |
| 450 // or a miss. |
| 451 RecordCacheResult(rv == ERR_CACHE_MISS ? CACHE_MISS : DISK_CACHE_ERROR); |
| 432 return rv; | 452 return rv; |
| 453 } |
| 433 | 454 |
| 434 state_ = STATE_READ; | 455 state_ = STATE_READ; |
| 435 return OK; | 456 return OK; |
| 436 } | 457 } |
| 437 | 458 |
| 438 int DiskBasedCertCache::ReadWorker::DoRead() { | 459 int DiskBasedCertCache::ReadWorker::DoRead() { |
| 439 state_ = STATE_READ_COMPLETE; | 460 state_ = STATE_READ_COMPLETE; |
| 440 io_buf_len_ = entry_->GetDataSize(0 /* index */); | 461 io_buf_len_ = entry_->GetDataSize(0 /* index */); |
| 441 buffer_ = new IOBuffer(io_buf_len_); | 462 buffer_ = new IOBuffer(io_buf_len_); |
| 442 return entry_->ReadData( | 463 return entry_->ReadData( |
| 443 0 /* index */, 0 /* offset */, buffer_, io_buf_len_, io_callback_); | 464 0 /* index */, 0 /* offset */, buffer_, io_buf_len_, io_callback_); |
| 444 } | 465 } |
| 445 | 466 |
| 446 int DiskBasedCertCache::ReadWorker::DoReadComplete(int rv) { | 467 int DiskBasedCertCache::ReadWorker::DoReadComplete(int rv) { |
| 447 if (rv < io_buf_len_) | 468 // The cache should return the entire buffer length. If it does not, |
| 469 // it is probably indicative of an issue other than corruption. |
| 470 if (rv < io_buf_len_) { |
| 471 RecordCacheResult(DISK_CACHE_ERROR); |
| 448 return ERR_FAILED; | 472 return ERR_FAILED; |
| 449 | 473 } |
| 450 cert_handle_ = X509Certificate::CreateOSCertHandleFromBytes(buffer_->data(), | 474 cert_handle_ = X509Certificate::CreateOSCertHandleFromBytes(buffer_->data(), |
| 451 io_buf_len_); | 475 io_buf_len_); |
| 452 if (!cert_handle_) | 476 if (!cert_handle_) { |
| 477 RecordCacheResult(DISK_CACHE_ENTRY_CORRUPT); |
| 453 return ERR_FAILED; | 478 return ERR_FAILED; |
| 479 } |
| 454 | 480 |
| 481 RecordCacheResult(DISK_CACHE_HIT); |
| 455 return OK; | 482 return OK; |
| 456 } | 483 } |
| 457 | 484 |
| 458 void DiskBasedCertCache::ReadWorker::Finish(int rv) { | 485 void DiskBasedCertCache::ReadWorker::Finish(int rv) { |
| 459 cleanup_callback_.Run(cert_handle_); | 486 cleanup_callback_.Run(cert_handle_); |
| 460 cleanup_callback_.Reset(); | 487 cleanup_callback_.Reset(); |
| 461 RunCallbacks(); | 488 RunCallbacks(); |
| 462 delete this; | 489 delete this; |
| 463 } | 490 } |
| 464 | 491 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 499 } | 526 } |
| 500 | 527 |
| 501 void DiskBasedCertCache::Get(const std::string& key, const GetCallback& cb) { | 528 void DiskBasedCertCache::Get(const std::string& key, const GetCallback& cb) { |
| 502 DCHECK(!key.empty()); | 529 DCHECK(!key.empty()); |
| 503 | 530 |
| 504 // If the handle is already in the MRU cache, just return that (via callback). | 531 // If the handle is already in the MRU cache, just return that (via callback). |
| 505 // Note, this will also bring the cert_handle to the front of the recency | 532 // Note, this will also bring the cert_handle to the front of the recency |
| 506 // list in the MRU cache. | 533 // list in the MRU cache. |
| 507 MRUCertCache::iterator mru_it = mru_cert_cache_.Get(key); | 534 MRUCertCache::iterator mru_it = mru_cert_cache_.Get(key); |
| 508 if (mru_it != mru_cert_cache_.end()) { | 535 if (mru_it != mru_cert_cache_.end()) { |
| 536 RecordCacheResult(MEMORY_CACHE_HIT); |
| 509 ++mem_cache_hits_; | 537 ++mem_cache_hits_; |
| 510 cb.Run(mru_it->second); | 538 cb.Run(mru_it->second); |
| 511 return; | 539 return; |
| 512 } | 540 } |
| 513 ++mem_cache_misses_; | 541 ++mem_cache_misses_; |
| 514 | 542 |
| 515 ReadWorkerMap::iterator it = read_worker_map_.find(key); | 543 ReadWorkerMap::iterator it = read_worker_map_.find(key); |
| 516 | 544 |
| 517 if (it == read_worker_map_.end()) { | 545 if (it == read_worker_map_.end()) { |
| 518 ReadWorker* worker = | 546 ReadWorker* worker = |
| 519 new ReadWorker(backend_, | 547 new ReadWorker(backend_, |
| 520 key, | 548 key, |
| 521 base::Bind(&DiskBasedCertCache::FinishedReadOperation, | 549 base::Bind(&DiskBasedCertCache::FinishedReadOperation, |
| 522 weak_factory_.GetWeakPtr(), | 550 weak_factory_.GetWeakPtr(), |
| 523 key)); | 551 key)); |
| 524 read_worker_map_[key] = worker; | 552 read_worker_map_[key] = worker; |
| 525 worker->AddCallback(cb); | 553 worker->AddCallback(cb); |
| 526 worker->Start(); | 554 worker->Start(); |
| 527 } else { | 555 } else { |
| 528 it->second->AddCallback(cb); | 556 it->second->AddCallback(cb); |
| 529 } | 557 } |
| 530 } | 558 } |
| 531 | 559 |
| 532 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle, | 560 void DiskBasedCertCache::Set(const X509Certificate::OSCertHandle cert_handle, |
| 533 const SetCallback& cb) { | 561 const SetCallback& cb) { |
| 534 DCHECK(!cb.is_null()); | 562 DCHECK(!cb.is_null()); |
| 535 DCHECK(cert_handle); | 563 DCHECK(cert_handle); |
| 536 std::string key = GetCacheKeyToCert(cert_handle); | 564 std::string key = GetCacheKeyForCert(cert_handle); |
| 537 | 565 |
| 538 WriteWorkerMap::iterator it = write_worker_map_.find(key); | 566 WriteWorkerMap::iterator it = write_worker_map_.find(key); |
| 539 | 567 |
| 540 if (it == write_worker_map_.end()) { | 568 if (it == write_worker_map_.end()) { |
| 541 WriteWorker* worker = | 569 WriteWorker* worker = |
| 542 new WriteWorker(backend_, | 570 new WriteWorker(backend_, |
| 543 key, | 571 key, |
| 544 cert_handle, | 572 cert_handle, |
| 545 base::Bind(&DiskBasedCertCache::FinishedWriteOperation, | 573 base::Bind(&DiskBasedCertCache::FinishedWriteOperation, |
| 546 weak_factory_.GetWeakPtr(), | 574 weak_factory_.GetWeakPtr(), |
| (...skipping 17 matching lines...) Expand all Loading... |
| 564 | 592 |
| 565 void DiskBasedCertCache::FinishedWriteOperation( | 593 void DiskBasedCertCache::FinishedWriteOperation( |
| 566 const std::string& key, | 594 const std::string& key, |
| 567 X509Certificate::OSCertHandle cert_handle) { | 595 X509Certificate::OSCertHandle cert_handle) { |
| 568 write_worker_map_.erase(key); | 596 write_worker_map_.erase(key); |
| 569 if (!key.empty()) | 597 if (!key.empty()) |
| 570 mru_cert_cache_.Put(key, X509Certificate::DupOSCertHandle(cert_handle)); | 598 mru_cert_cache_.Put(key, X509Certificate::DupOSCertHandle(cert_handle)); |
| 571 } | 599 } |
| 572 | 600 |
| 573 } // namespace net | 601 } // namespace net |
| OLD | NEW |