Chromium Code Reviews| Index: net/socket/ssl_session_cache_openssl.cc |
| diff --git a/net/socket/ssl_session_cache_openssl.cc b/net/socket/ssl_session_cache_openssl.cc |
| index d16bb8d6325ec6b105da7219d4e9ea9e5f6f4828..c5cf07e4801fcd1bf888ba4fc91f6055ae347a23 100644 |
| --- a/net/socket/ssl_session_cache_openssl.cc |
| +++ b/net/socket/ssl_session_cache_openssl.cc |
| @@ -10,6 +10,7 @@ |
| #include <openssl/rand.h> |
| #include <openssl/ssl.h> |
| +#include "base/callback.h" |
| #include "base/containers/hash_tables.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| @@ -236,14 +237,55 @@ class SSLSessionCacheOpenSSLImpl { |
| return SSL_set_session(ssl, session) == 1; |
| } |
| + // Return true iff a cached session was associated with the given |cache_key|. |
| + bool SSLSessionIsInCache(const std::string& cache_key) const { |
| + base::AutoLock locked(lock_); |
| + KeyIndex::const_iterator it = key_index_.find(cache_key); |
| + if (it == key_index_.end()) |
| + return false; |
| + |
| + SSL_SESSION* session = *it->second; |
| + DCHECK(session); |
| + |
| + void* session_is_good = |
| + SSL_SESSION_get_ex_data(session, GetSSLSessionExIndex()); |
| + |
| + return session_is_good; |
| + } |
| + |
| + void SetSessionAddedCallback(SSL* ssl, const base::Closure& callback) { |
| + // Add |ssl| to the SSLToCallbackMap. |
| + ssl_to_callback_map_.insert(SSLToCallbackMap::value_type( |
| + ssl, CallbackAndCompletionCount(callback, 0))); |
| + } |
| + |
| + // Determines if the session for |ssl| is in the cache, and calls the |
| + // appropriate callback if that is the case. |
| + void CheckIfSessionFinished(SSL* ssl) { |
| + // The session must be both MarkedAsGood and Added in order to be |
| + // considered finished. These two events can occur in either order. |
|
wtc
2014/07/30 21:56:58
I think Ryan wanted you to move this comment befor
mshelley
2014/07/31 00:51:21
Done.
|
| + SSLToCallbackMap::iterator it = ssl_to_callback_map_.find(ssl); |
| + if (it == ssl_to_callback_map_.end()) |
| + return; |
| + // Increment the session's completion count. |
| + if (++it->second.count == 2) { |
| + base::Closure callback = it->second.callback; |
| + ssl_to_callback_map_.erase(it); |
| + callback.Run(); |
| + } |
| + } |
| + |
| + void RemoveSessionAddedCallback(SSL* ssl) { ssl_to_callback_map_.erase(ssl); } |
| + |
| void MarkSSLSessionAsGood(SSL* ssl) { |
| SSL_SESSION* session = SSL_get_session(ssl); |
| - if (!session) |
| - return; |
| + CHECK(session); |
| // Mark the session as good, allowing it to be used for future connections. |
| SSL_SESSION_set_ex_data( |
| session, GetSSLSessionExIndex(), reinterpret_cast<void*>(1)); |
| + |
| + CheckIfSessionFinished(ssl); |
| } |
| // Flush all entries from the cache. |
| @@ -259,12 +301,30 @@ class SSLSessionCacheOpenSSLImpl { |
| } |
| private: |
| + // CallbackAndCompletionCounts are used to group a callback that should be |
| + // run when a certain sesssion is added to the session cache with an integer |
| + // indicating the status of that session. |
| + struct CallbackAndCompletionCount { |
| + CallbackAndCompletionCount(const base::Closure& completion_callback, |
| + int completion_count) |
| + : callback(completion_callback), count(completion_count) {} |
| + |
| + const base::Closure callback; |
| + // |count| < 2 means that the ssl session associated with this object |
| + // has not been added to the session cache or has not been marked as good. |
| + // |count| is incremented when a session is added to the cache or marked as |
| + // good, thus |count| == 2 means that the session is ready for use. |
| + int count; |
| + }; |
| + |
| // Type for list of SSL_SESSION handles, ordered in MRU order. |
| typedef std::list<SSL_SESSION*> MRUSessionList; |
| // Type for a dictionary from unique cache keys to session list nodes. |
| typedef base::hash_map<std::string, MRUSessionList::iterator> KeyIndex; |
| // Type for a dictionary from SessionId values to key index nodes. |
| typedef base::hash_map<SessionId, KeyIndex::iterator> SessionIdIndex; |
| + // Type for a map from SSL* to associated callbacks |
| + typedef std::map<SSL*, CallbackAndCompletionCount> SSLToCallbackMap; |
| // Return the key associated with a given session, or the empty string if |
| // none exist. This shall only be used for debugging. |
| @@ -342,7 +402,9 @@ class SSLSessionCacheOpenSSLImpl { |
| // to indicate that it took ownership of the session, i.e. that the caller |
| // should not decrement its reference count after completion. |
| static int NewSessionCallbackStatic(SSL* ssl, SSL_SESSION* session) { |
| - GetCache(ssl->ctx)->OnSessionAdded(ssl, session); |
| + SSLSessionCacheOpenSSLImpl* cache = GetCache(ssl->ctx); |
| + cache->OnSessionAdded(ssl, session); |
| + cache->CheckIfSessionFinished(ssl); |
| return 1; |
| } |
| @@ -466,10 +528,11 @@ class SSLSessionCacheOpenSSLImpl { |
| SSL_CTX* ctx_; |
| SSLSessionCacheOpenSSL::Config config_; |
| + SSLToCallbackMap ssl_to_callback_map_; |
| // method to get the index which can later be used with SSL_CTX_get_ex_data() |
| // or SSL_CTX_set_ex_data(). |
| - base::Lock lock_; // Protects access to containers below. |
| + mutable base::Lock lock_; // Protects access to containers below. |
| MRUSessionList ordering_; |
| KeyIndex key_index_; |
| @@ -499,6 +562,20 @@ bool SSLSessionCacheOpenSSL::SetSSLSessionWithKey( |
| return impl_->SetSSLSessionWithKey(ssl, cache_key); |
| } |
| +bool SSLSessionCacheOpenSSL::SSLSessionIsInCache( |
| + const std::string& cache_key) const { |
| + return impl_->SSLSessionIsInCache(cache_key); |
| +} |
| + |
| +void SSLSessionCacheOpenSSL::RemoveSessionAddedCallback(SSL* ssl) { |
| + impl_->RemoveSessionAddedCallback(ssl); |
| +} |
| + |
| +void SSLSessionCacheOpenSSL::SetSessionAddedCallback(SSL* ssl, |
| + const base::Closure& cb) { |
| + impl_->SetSessionAddedCallback(ssl, cb); |
| +} |
| + |
| void SSLSessionCacheOpenSSL::MarkSSLSessionAsGood(SSL* ssl) { |
| return impl_->MarkSSLSessionAsGood(ssl); |
| } |