Commit e6112f4e authored by Steven Valdez's avatar Steven Valdez Committed by Commit Bot

Enforce single-use tickets and remove session counting histogram.

Bug: 631988
Change-Id: I16e2aaa227e36c3d025c6663b10f6a15e4a32428
Reviewed-on: https://chromium-review.googlesource.com/692946Reviewed-by: default avatarDavid Benjamin <davidben@chromium.org>
Reviewed-by: default avatarAlexei Svitkine <asvitkine@chromium.org>
Commit-Queue: Steven Valdez <svaldez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#506882}
parent 2f280c65
......@@ -446,7 +446,6 @@ SSLClientSocketImpl::SSLClientSocketImpl(
host_and_port_(host_and_port),
ssl_config_(ssl_config),
ssl_session_cache_shard_(context.ssl_session_cache_shard),
ssl_session_cache_lookup_count_(0),
next_handshake_state_(STATE_NONE),
disconnected_(false),
negotiated_protocol_(kProtoUnknown),
......@@ -864,8 +863,8 @@ int SSLClientSocketImpl::Init() {
}
if (!ssl_session_cache_shard_.empty()) {
bssl::UniquePtr<SSL_SESSION> session = context->session_cache()->Lookup(
GetSessionCacheKey(), &ssl_session_cache_lookup_count_);
bssl::UniquePtr<SSL_SESSION> session =
context->session_cache()->Lookup(GetSessionCacheKey());
if (session)
SSL_set_session(ssl_.get(), session.get());
}
......@@ -1124,17 +1123,6 @@ int SSLClientSocketImpl::DoHandshakeComplete(int result) {
negotiated_protocol_ = NextProtoFromString(proto);
}
// If we got a session from the session cache, log how many concurrent
// handshakes that session was used in before we finished our handshake. This
// is only recorded if the session from the cache was actually used, and only
// if the ALPN protocol is h2 (under the assumption that TLS 1.3 servers will
// be speaking h2). See https://crbug.com/631988.
if (ssl_session_cache_lookup_count_ && negotiated_protocol_ == kProtoHTTP2 &&
SSL_session_reused(ssl_.get())) {
UMA_HISTOGRAM_EXACT_LINEAR("Net.SSLSessionConcurrentLookupCount",
ssl_session_cache_lookup_count_, 20);
}
RecordNegotiatedProtocol();
RecordChannelIDSupport();
......
......@@ -305,7 +305,6 @@ class SSLClientSocketImpl : public SSLClientSocket,
// session cache. i.e. sessions created with one value will not attempt to
// resume on the socket with a different value.
const std::string ssl_session_cache_shard_;
int ssl_session_cache_lookup_count_;
enum State {
STATE_NONE,
......
......@@ -36,8 +36,7 @@ size_t SSLClientSessionCache::size() const {
}
bssl::UniquePtr<SSL_SESSION> SSLClientSessionCache::Lookup(
const std::string& cache_key,
int* count) {
const std::string& cache_key) {
base::AutoLock lock(lock_);
// Expire stale sessions.
......@@ -47,27 +46,18 @@ bssl::UniquePtr<SSL_SESSION> SSLClientSessionCache::Lookup(
FlushExpiredSessions();
}
// Set count to 0 if there's no session in the cache.
if (count != nullptr)
*count = 0;
auto iter = cache_.Get(cache_key);
if (iter == cache_.end())
return nullptr;
SSL_SESSION* session = iter->second.session.get();
if (IsExpired(session, clock_->Now().ToTimeT())) {
time_t now = clock_->Now().ToTimeT();
bssl::UniquePtr<SSL_SESSION> session = iter->second.Pop();
if (iter->second.ExpireSessions(now))
cache_.Erase(iter);
return nullptr;
}
iter->second.lookups++;
if (count != nullptr) {
*count = iter->second.lookups;
}
SSL_SESSION_up_ref(session);
return bssl::UniquePtr<SSL_SESSION>(session);
if (IsExpired(session.get(), now))
session = nullptr;
return session;
}
void SSLClientSessionCache::ResetLookupCount(const std::string& cache_key) {
......@@ -78,8 +68,6 @@ void SSLClientSessionCache::ResetLookupCount(const std::string& cache_key) {
auto iter = cache_.Get(cache_key);
if (iter == cache_.end())
return;
iter->second.lookups = 0;
}
void SSLClientSessionCache::Insert(const std::string& cache_key,
......@@ -87,9 +75,10 @@ void SSLClientSessionCache::Insert(const std::string& cache_key,
base::AutoLock lock(lock_);
SSL_SESSION_up_ref(session);
Entry entry;
entry.session = bssl::UniquePtr<SSL_SESSION>(session);
cache_.Put(cache_key, std::move(entry));
auto iter = cache_.Get(cache_key);
if (iter == cache_.end())
iter = cache_.Put(cache_key, Entry());
iter->second.Push(bssl::UniquePtr<SSL_SESSION>(session));
}
void SSLClientSessionCache::Flush() {
......@@ -129,23 +118,27 @@ void SSLClientSessionCache::DumpMemoryStats(
size_t undeduped_cert_size = 0;
size_t undeduped_cert_count = 0;
for (const auto& pair : cache_) {
undeduped_cert_count +=
sk_CRYPTO_BUFFER_num(pair.second.session.get()->certs);
for (const auto& session : pair.second.sessions) {
if (!session)
continue;
undeduped_cert_count += sk_CRYPTO_BUFFER_num(session->certs);
}
}
// Use a flat_set here to avoid malloc upon insertion.
base::flat_set<const CRYPTO_BUFFER*> crypto_buffer_set;
crypto_buffer_set.reserve(undeduped_cert_count);
for (const auto& pair : cache_) {
const SSL_SESSION* session = pair.second.session.get();
size_t pair_cert_count = sk_CRYPTO_BUFFER_num(session->certs);
for (size_t i = 0; i < pair_cert_count; ++i) {
const CRYPTO_BUFFER* cert = sk_CRYPTO_BUFFER_value(session->certs, i);
undeduped_cert_size += CRYPTO_BUFFER_len(cert);
auto result = crypto_buffer_set.insert(cert);
if (!result.second)
for (const auto& session : pair.second.sessions) {
if (!session)
continue;
cert_size += CRYPTO_BUFFER_len(cert);
cert_count++;
for (const CRYPTO_BUFFER* cert : session->certs) {
undeduped_cert_size += CRYPTO_BUFFER_len(cert);
auto result = crypto_buffer_set.insert(cert);
if (!result.second)
continue;
cert_size += CRYPTO_BUFFER_len(cert);
cert_count++;
}
}
}
cache_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
......@@ -165,15 +158,51 @@ void SSLClientSessionCache::DumpMemoryStats(
undeduped_cert_count);
}
SSLClientSessionCache::Entry::Entry() : lookups(0) {}
SSLClientSessionCache::Entry::Entry() {}
SSLClientSessionCache::Entry::Entry(Entry&&) = default;
SSLClientSessionCache::Entry::~Entry() = default;
void SSLClientSessionCache::Entry::Push(bssl::UniquePtr<SSL_SESSION> session) {
if (sessions[0] != nullptr &&
SSL_SESSION_should_be_single_use(sessions[0].get())) {
sessions[1] = std::move(sessions[0]);
}
sessions[0] = std::move(session);
}
bssl::UniquePtr<SSL_SESSION> SSLClientSessionCache::Entry::Pop() {
if (sessions[0] == nullptr)
return nullptr;
SSL_SESSION* session = sessions[0].get();
SSL_SESSION_up_ref(session);
if (SSL_SESSION_should_be_single_use(session)) {
sessions[0] = std::move(sessions[1]);
sessions[1] = nullptr;
}
return bssl::UniquePtr<SSL_SESSION>(session);
}
bool SSLClientSessionCache::Entry::ExpireSessions(time_t now) {
if (sessions[0] == nullptr)
return true;
if (SSLClientSessionCache::IsExpired(sessions[0].get(), now)) {
return true;
}
if (sessions[1] != nullptr &&
SSLClientSessionCache::IsExpired(sessions[1].get(), now)) {
sessions[1] = nullptr;
}
return false;
}
void SSLClientSessionCache::FlushExpiredSessions() {
time_t now = clock_->Now().ToTimeT();
auto iter = cache_.begin();
while (iter != cache_.end()) {
if (IsExpired(iter->second.session.get(), now)) {
if (iter->second.ExpireSessions(now)) {
iter = cache_.Erase(iter);
} else {
++iter;
......
......@@ -43,13 +43,14 @@ class NET_EXPORT SSLClientSessionCache : public base::MemoryCoordinatorClient {
explicit SSLClientSessionCache(const Config& config);
~SSLClientSessionCache() override;
// Returns true if |entry| is expired as of |now|.
static bool IsExpired(SSL_SESSION* session, time_t now);
size_t size() const;
// Returns the session associated with |cache_key| and moves it to the front
// of the MRU list. Returns nullptr if there is none. If |count| is non-null,
// |*count| will contain the number of times this session has been looked up
// (including this call).
bssl::UniquePtr<SSL_SESSION> Lookup(const std::string& cache_key, int* count);
// of the MRU list. Returns nullptr if there is none.
bssl::UniquePtr<SSL_SESSION> Lookup(const std::string& cache_key);
// Resets the count returned by Lookup to 0 for the session associated with
// |cache_key|.
......@@ -75,16 +76,24 @@ class NET_EXPORT SSLClientSessionCache : public base::MemoryCoordinatorClient {
Entry(Entry&&);
~Entry();
int lookups;
bssl::UniquePtr<SSL_SESSION> session;
// Adds a new session onto this entry, dropping the oldest one if two are
// already stored.
void Push(bssl::UniquePtr<SSL_SESSION> session);
// Retrieves the latest session from the entry, removing it if its
// single-use.
bssl::UniquePtr<SSL_SESSION> Pop();
// Removes any expired sessions, returning true if this entry can be
// deleted.
bool ExpireSessions(time_t now);
bssl::UniquePtr<SSL_SESSION> sessions[2] = {nullptr};
};
// base::MemoryCoordinatorClient implementation:
void OnPurgeMemory() override;
// Returns true if |entry| is expired as of |now|.
bool IsExpired(SSL_SESSION* session, time_t now);
// Removes all expired sessions from the cache.
void FlushExpiredSessions();
......
......@@ -33,8 +33,12 @@ class SSLClientSessionCacheTest : public testing::Test {
SSLClientSessionCacheTest() : ssl_ctx_(SSL_CTX_new(TLS_method())) {}
protected:
bssl::UniquePtr<SSL_SESSION> NewSSLSession() {
return bssl::UniquePtr<SSL_SESSION>(SSL_SESSION_new(ssl_ctx_.get()));
bssl::UniquePtr<SSL_SESSION> NewSSLSession(
uint16_t version = TLS1_2_VERSION) {
SSL_SESSION* session = SSL_SESSION_new(ssl_ctx_.get());
if (!SSL_SESSION_set_protocol_version(session, version))
return nullptr;
return bssl::UniquePtr<SSL_SESSION>(session);
}
bssl::UniquePtr<SSL_SESSION> MakeTestSession(base::Time now,
......@@ -63,26 +67,26 @@ TEST_F(SSLClientSessionCacheTest, Basic) {
EXPECT_EQ(1u, session2->references);
EXPECT_EQ(1u, session3->references);
EXPECT_EQ(nullptr, cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key1", session1.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(1u, cache.size());
cache.Insert("key2", session2.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(2u, cache.size());
EXPECT_EQ(2u, session1->references);
EXPECT_EQ(2u, session2->references);
cache.Insert("key1", session3.get());
EXPECT_EQ(session3.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session3.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(2u, cache.size());
EXPECT_EQ(1u, session1->references);
......@@ -90,9 +94,9 @@ TEST_F(SSLClientSessionCacheTest, Basic) {
EXPECT_EQ(2u, session3->references);
cache.Flush();
EXPECT_EQ(nullptr, cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key3", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(nullptr, cache.Lookup("key3").get());
EXPECT_EQ(0u, cache.size());
EXPECT_EQ(1u, session1->references);
......@@ -100,43 +104,125 @@ TEST_F(SSLClientSessionCacheTest, Basic) {
EXPECT_EQ(1u, session3->references);
}
// Test that pairs of calls to Lookup/ResetLookupCount appropriately log to
// UMA.
TEST_F(SSLClientSessionCacheTest, LookupCountUMA) {
// Test basic insertion and lookup operations with single-use sessions.
TEST_F(SSLClientSessionCacheTest, BasicSingleUse) {
SSLClientSessionCache::Config config;
SSLClientSessionCache cache(config);
bssl::UniquePtr<SSL_SESSION> session1 = NewSSLSession();
bssl::UniquePtr<SSL_SESSION> session2 = NewSSLSession();
bssl::UniquePtr<SSL_SESSION> session1 = NewSSLSession(TLS1_3_VERSION);
bssl::UniquePtr<SSL_SESSION> session2 = NewSSLSession(TLS1_3_VERSION);
bssl::UniquePtr<SSL_SESSION> session3 = NewSSLSession(TLS1_3_VERSION);
EXPECT_EQ(1u, session1->references);
EXPECT_EQ(1u, session2->references);
EXPECT_EQ(1u, session3->references);
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key1", session1.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
cache.Insert("key1", session1.get());
cache.Insert("key1", session1.get());
cache.Insert("key2", session2.get());
// Test that the count returned increments when multiple lookups of the same
// key/session occur before the count is reset.
int count;
EXPECT_EQ(session1.get(), cache.Lookup("key1", &count).get());
EXPECT_EQ(1, count);
EXPECT_EQ(session1.get(), cache.Lookup("key1", &count).get());
EXPECT_EQ(2, count);
cache.ResetLookupCount("key1");
EXPECT_EQ(session1.get(), cache.Lookup("key1", &count).get());
cache.ResetLookupCount("key1");
EXPECT_EQ(1, count);
// Test that independent keys are logged separately.
EXPECT_EQ(session1.get(), cache.Lookup("key1", &count).get());
EXPECT_EQ(1, count);
EXPECT_EQ(session2.get(), cache.Lookup("key2", &count).get());
EXPECT_EQ(1, count);
// Test that the count is 0 if there is a cache miss.
EXPECT_EQ(nullptr, cache.Lookup("not present", &count).get());
EXPECT_EQ(0, count);
// Check that ResetLookupCount doesn't explode if there's a cache miss.
cache.ResetLookupCount("not present");
EXPECT_EQ(3u, session1->references);
EXPECT_EQ(2u, session2->references);
EXPECT_EQ(2u, cache.size());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(1u, cache.size());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(1u, session1->references);
EXPECT_EQ(1u, session2->references);
cache.Insert("key1", session1.get());
cache.Insert("key1", session3.get());
cache.Insert("key2", session2.get());
EXPECT_EQ(session3.get(), cache.Lookup("key1").get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
EXPECT_EQ(1u, session1->references);
EXPECT_EQ(1u, session2->references);
EXPECT_EQ(1u, session3->references);
cache.Flush();
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(nullptr, cache.Lookup("key3").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key1", session1.get());
cache.Insert("key1", session2.get());
cache.Insert("key1", session3.get());
EXPECT_EQ(1u, session1->references);
EXPECT_EQ(2u, session2->references);
EXPECT_EQ(2u, session3->references);
EXPECT_EQ(session3.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(1u, session1->references);
EXPECT_EQ(1u, session2->references);
EXPECT_EQ(1u, session3->references);
}
// Test insertion and lookup operations with both single-use and reusable
// sessions.
TEST_F(SSLClientSessionCacheTest, MixedUse) {
SSLClientSessionCache::Config config;
SSLClientSessionCache cache(config);
bssl::UniquePtr<SSL_SESSION> session_single = NewSSLSession(TLS1_3_VERSION);
bssl::UniquePtr<SSL_SESSION> session_reuse = NewSSLSession(TLS1_2_VERSION);
EXPECT_EQ(1u, session_single->references);
EXPECT_EQ(1u, session_reuse->references);
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key1", session_reuse.get());
EXPECT_EQ(session_reuse.get(), cache.Lookup("key1").get());
EXPECT_EQ(1u, cache.size());
cache.Insert("key1", session_single.get());
EXPECT_EQ(session_single.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(0u, cache.size());
EXPECT_EQ(1u, session_single->references);
EXPECT_EQ(1u, session_reuse->references);
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key2", session_single.get());
cache.Insert("key2", session_single.get());
EXPECT_EQ(1u, cache.size());
EXPECT_EQ(session_single.get(), cache.Lookup("key2").get());
EXPECT_EQ(session_single.get(), cache.Lookup("key2").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key2", session_single.get());
cache.Insert("key2", session_reuse.get());
EXPECT_EQ(session_reuse.get(), cache.Lookup("key2").get());
EXPECT_EQ(session_reuse.get(), cache.Lookup("key2").get());
EXPECT_EQ(1u, cache.size());
EXPECT_EQ(2u, session_single->references);
EXPECT_EQ(2u, session_reuse->references);
}
// Test that a session may be inserted at two different keys. This should never
......@@ -148,27 +234,27 @@ TEST_F(SSLClientSessionCacheTest, DoubleInsert) {
bssl::UniquePtr<SSL_SESSION> session = NewSSLSession();
EXPECT_EQ(1u, session->references);
EXPECT_EQ(nullptr, cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
cache.Insert("key1", session.get());
EXPECT_EQ(session.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(1u, cache.size());
EXPECT_EQ(2u, session->references);
cache.Insert("key2", session.get());
EXPECT_EQ(session.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key1").get());
EXPECT_EQ(session.get(), cache.Lookup("key2").get());
EXPECT_EQ(2u, cache.size());
EXPECT_EQ(3u, session->references);
cache.Flush();
EXPECT_EQ(nullptr, cache.Lookup("key1", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key2", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(nullptr, cache.Lookup("key2").get());
EXPECT_EQ(0u, cache.size());
EXPECT_EQ(1u, session->references);
......@@ -189,26 +275,26 @@ TEST_F(SSLClientSessionCacheTest, MaxEntries) {
cache.Insert("key1", session1.get());
cache.Insert("key2", session2.get());
cache.Insert("key3", session3.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session3.get(), cache.Lookup("key3", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(session3.get(), cache.Lookup("key3").get());
EXPECT_EQ(3u, cache.size());
// On insertion of a fourth, the first is removed.
cache.Insert("key4", session4.get());
EXPECT_EQ(nullptr, cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session4.get(), cache.Lookup("key4", nullptr).get());
EXPECT_EQ(session3.get(), cache.Lookup("key3", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key1").get());
EXPECT_EQ(session4.get(), cache.Lookup("key4").get());
EXPECT_EQ(session3.get(), cache.Lookup("key3").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(3u, cache.size());
// Despite being newest, the next to be removed is session4 as it was accessed
// least. recently.
cache.Insert("key1", session1.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session3.get(), cache.Lookup("key3", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key4", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(session3.get(), cache.Lookup("key3").get());
EXPECT_EQ(nullptr, cache.Lookup("key4").get());
EXPECT_EQ(3u, cache.size());
}
......@@ -244,18 +330,18 @@ TEST_F(SSLClientSessionCacheTest, Expiration) {
// Perform one fewer lookup than needed to trigger the expiration check. This
// shall not expire any session.
for (size_t i = 0; i < kExpirationCheckCount - 1; i++)
cache.Lookup("key", nullptr);
cache.Lookup("key");
// All entries are still in the cache.
EXPECT_EQ(kNumEntries, cache.size());
// Perform one more lookup. This will expire all sessions but the last one.
cache.Lookup("key", nullptr);
cache.Lookup("key");
EXPECT_EQ(1u, cache.size());
EXPECT_EQ(session.get(), cache.Lookup("key", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key").get());
for (size_t i = 0; i < kNumEntries - 1; i++) {
SCOPED_TRACE(i);
EXPECT_EQ(nullptr, cache.Lookup(base::SizeTToString(i), nullptr));
EXPECT_EQ(nullptr, cache.Lookup(base::SizeTToString(i)));
}
}
......@@ -277,7 +363,7 @@ TEST_F(SSLClientSessionCacheTest, LookupExpirationCheck) {
bssl::UniquePtr<SSL_SESSION> session =
MakeTestSession(clock->Now(), kTimeout);
cache.Insert("key", session.get());
EXPECT_EQ(session.get(), cache.Lookup("key", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key").get());
EXPECT_EQ(1u, cache.size());
// Expire the session.
......@@ -287,24 +373,24 @@ TEST_F(SSLClientSessionCacheTest, LookupExpirationCheck) {
EXPECT_EQ(1u, cache.size());
// But it will not be returned on lookup and gets pruned at that point.
EXPECT_EQ(nullptr, cache.Lookup("key", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key").get());
EXPECT_EQ(0u, cache.size());
// Re-inserting a session does not refresh the lifetime. The expiration
// information in the session is used.
cache.Insert("key", session.get());
EXPECT_EQ(nullptr, cache.Lookup("key", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key").get());
EXPECT_EQ(0u, cache.size());
// Re-insert a fresh copy of the session.
session = MakeTestSession(clock->Now(), kTimeout);
cache.Insert("key", session.get());
EXPECT_EQ(session.get(), cache.Lookup("key", nullptr).get());
EXPECT_EQ(session.get(), cache.Lookup("key").get());
EXPECT_EQ(1u, cache.size());
// Sessions also are treated as expired if the clock rewinds.
clock->Advance(base::TimeDelta::FromSeconds(-1));
EXPECT_EQ(nullptr, cache.Lookup("key", nullptr).get());
EXPECT_EQ(nullptr, cache.Lookup("key").get());
EXPECT_EQ(0u, cache.size());
}
......@@ -325,7 +411,7 @@ TEST_F(SSLClientSessionCacheTest, TestFlushOnMemoryNotifications) {
bssl::UniquePtr<SSL_SESSION> session1 =
MakeTestSession(clock->Now(), kTimeout);
cache.Insert("key1", session1.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(1u, cache.size());
// Expire the session.
......@@ -343,8 +429,8 @@ TEST_F(SSLClientSessionCacheTest, TestFlushOnMemoryNotifications) {
// Expired session's cache should be flushed.
// Lookup returns nullptr, when cache entry not found.
EXPECT_FALSE(cache.Lookup("key1", nullptr));
EXPECT_TRUE(cache.Lookup("key2", nullptr));
EXPECT_FALSE(cache.Lookup("key1"));
EXPECT_TRUE(cache.Lookup("key2"));
EXPECT_EQ(1u, cache.size());
// Fire notification that will flush everything.
......@@ -378,9 +464,9 @@ TEST_P(SSLClientSessionCacheMemoryDumpTest, TestDumpMemoryStats) {
cache.Insert("key1", session1.get());
cache.Insert("key2", session2.get());
cache.Insert("key3", session3.get());
EXPECT_EQ(session1.get(), cache.Lookup("key1", nullptr).get());
EXPECT_EQ(session2.get(), cache.Lookup("key2", nullptr).get());
EXPECT_EQ(session3.get(), cache.Lookup("key3", nullptr).get());
EXPECT_EQ(session1.get(), cache.Lookup("key1").get());
EXPECT_EQ(session2.get(), cache.Lookup("key2").get());
EXPECT_EQ(session3.get(), cache.Lookup("key3").get());
EXPECT_EQ(3u, cache.size());
base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
......
......@@ -44793,6 +44793,9 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</histogram>
<histogram name="Net.SSLSessionConcurrentLookupCount">
<obsolete>
Removed on 2017-10-02.
</obsolete>
<owner>nharper@chromium.org</owner>
<summary>
For each SSL connection where we resume a session and negotiate HTTP/2, the
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment