| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <string> |
| |
| #include "quic/core/crypto/quic_compressed_certs_cache.h" |
| |
| namespace quic { |
| |
| namespace { |
| |
| // Inline helper function for extending a 64-bit |seed| in-place with a 64-bit |
| // |value|. Based on Boost's hash_combine function. |
| inline void hash_combine(uint64_t* seed, const uint64_t& val) { |
| (*seed) ^= val + 0x9e3779b9 + ((*seed) << 6) + ((*seed) >> 2); |
| } |
| |
| } // namespace |
| |
| const size_t QuicCompressedCertsCache::kQuicCompressedCertsCacheSize = 225; |
| |
| QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts() |
| : chain(nullptr), |
| client_common_set_hashes(nullptr), |
| client_cached_cert_hashes(nullptr) {} |
| |
| QuicCompressedCertsCache::UncompressedCerts::UncompressedCerts( |
| const QuicReferenceCountedPointer<ProofSource::Chain>& chain, |
| const std::string* client_common_set_hashes, |
| const std::string* client_cached_cert_hashes) |
| : chain(chain), |
| client_common_set_hashes(client_common_set_hashes), |
| client_cached_cert_hashes(client_cached_cert_hashes) {} |
| |
| QuicCompressedCertsCache::UncompressedCerts::~UncompressedCerts() {} |
| |
| QuicCompressedCertsCache::CachedCerts::CachedCerts() {} |
| |
| QuicCompressedCertsCache::CachedCerts::CachedCerts( |
| const UncompressedCerts& uncompressed_certs, |
| const std::string& compressed_cert) |
| : chain_(uncompressed_certs.chain), |
| client_common_set_hashes_(*uncompressed_certs.client_common_set_hashes), |
| client_cached_cert_hashes_(*uncompressed_certs.client_cached_cert_hashes), |
| compressed_cert_(compressed_cert) {} |
| |
| QuicCompressedCertsCache::CachedCerts::CachedCerts(const CachedCerts& other) = |
| default; |
| |
| QuicCompressedCertsCache::CachedCerts::~CachedCerts() {} |
| |
| bool QuicCompressedCertsCache::CachedCerts::MatchesUncompressedCerts( |
| const UncompressedCerts& uncompressed_certs) const { |
| return (client_common_set_hashes_ == |
| *uncompressed_certs.client_common_set_hashes && |
| client_cached_cert_hashes_ == |
| *uncompressed_certs.client_cached_cert_hashes && |
| chain_ == uncompressed_certs.chain); |
| } |
| |
| const std::string* QuicCompressedCertsCache::CachedCerts::compressed_cert() |
| const { |
| return &compressed_cert_; |
| } |
| |
| QuicCompressedCertsCache::QuicCompressedCertsCache(int64_t max_num_certs) |
| : certs_cache_(max_num_certs) {} |
| |
| QuicCompressedCertsCache::~QuicCompressedCertsCache() { |
| // Underlying cache must be cleared before destruction. |
| certs_cache_.Clear(); |
| } |
| |
| const std::string* QuicCompressedCertsCache::GetCompressedCert( |
| const QuicReferenceCountedPointer<ProofSource::Chain>& chain, |
| const std::string& client_common_set_hashes, |
| const std::string& client_cached_cert_hashes) { |
| UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes, |
| &client_cached_cert_hashes); |
| |
| uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs); |
| |
| CachedCerts* cached_value = nullptr; |
| auto iter = certs_cache_.Lookup(key); |
| if (iter != certs_cache_.end()) { |
| cached_value = iter->second.get(); |
| } |
| if (cached_value != nullptr && |
| cached_value->MatchesUncompressedCerts(uncompressed_certs)) { |
| return cached_value->compressed_cert(); |
| } |
| return nullptr; |
| } |
| |
| void QuicCompressedCertsCache::Insert( |
| const QuicReferenceCountedPointer<ProofSource::Chain>& chain, |
| const std::string& client_common_set_hashes, |
| const std::string& client_cached_cert_hashes, |
| const std::string& compressed_cert) { |
| UncompressedCerts uncompressed_certs(chain, &client_common_set_hashes, |
| &client_cached_cert_hashes); |
| |
| uint64_t key = ComputeUncompressedCertsHash(uncompressed_certs); |
| |
| // Insert one unit to the cache. |
| std::unique_ptr<CachedCerts> cached_certs( |
| new CachedCerts(uncompressed_certs, compressed_cert)); |
| certs_cache_.Insert(key, std::move(cached_certs)); |
| } |
| |
| size_t QuicCompressedCertsCache::MaxSize() { |
| return certs_cache_.MaxSize(); |
| } |
| |
| size_t QuicCompressedCertsCache::Size() { |
| return certs_cache_.Size(); |
| } |
| |
| uint64_t QuicCompressedCertsCache::ComputeUncompressedCertsHash( |
| const UncompressedCerts& uncompressed_certs) { |
| uint64_t hash = |
| std::hash<std::string>()(*uncompressed_certs.client_common_set_hashes); |
| uint64_t h = |
| std::hash<std::string>()(*uncompressed_certs.client_cached_cert_hashes); |
| hash_combine(&hash, h); |
| |
| hash_combine(&hash, |
| reinterpret_cast<uint64_t>(uncompressed_certs.chain.get())); |
| return hash; |
| } |
| |
| } // namespace quic |