Chromium Code Reviews| Index: net/socket/ssl_client_socket_openssl.cc |
| diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc |
| index 12373488f909af5960292cfc2973a70e07a2679d..b3fb823653febe43ff1c37949b3178fe2f712c38 100644 |
| --- a/net/socket/ssl_client_socket_openssl.cc |
| +++ b/net/socket/ssl_client_socket_openssl.cc |
| @@ -205,23 +205,27 @@ class SSLSessionCache { |
| public: |
| SSLSessionCache() {} |
| - void OnSessionAdded(const HostPortPair& host_and_port, SSL_SESSION* session) { |
| + void OnSessionAdded(const HostPortPair& host_and_port, |
| + const std::string& shard, |
| + SSL_SESSION* session) { |
| // Declare the session cleaner-upper before the lock, so any call into |
| // OpenSSL to free the session will happen after the lock is released. |
| crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free> session_to_free; |
| base::AutoLock lock(lock_); |
| DCHECK_EQ(0U, session_map_.count(session)); |
| + const std::string cache_key = GetCacheKey(host_and_port, shard); |
| + |
| std::pair<HostPortMap::iterator, bool> res = |
| - host_port_map_.insert(std::make_pair(host_and_port, session)); |
| + host_port_map_.insert(std::make_pair(cache_key, session)); |
| if (!res.second) { // Already exists: replace old entry. |
| session_to_free.reset(res.first->second); |
| session_map_.erase(session_to_free.get()); |
| res.first->second = session; |
| } |
| DVLOG(2) << "Adding session " << session << " => " |
| - << host_and_port.ToString() << ", new entry = " << res.second; |
| - DCHECK(host_port_map_[host_and_port] == session); |
| + << cache_key << ", new entry = " << res.second; |
| + DCHECK(host_port_map_[cache_key] == session); |
| session_map_[session] = res.first; |
| DCHECK_EQ(host_port_map_.size(), session_map_.size()); |
| DCHECK_LE(host_port_map_.size(), kSessionCacheMaxEntires); |
| @@ -237,7 +241,7 @@ class SSLSessionCache { |
| if (it == session_map_.end()) |
| return; |
| DVLOG(2) << "Remove session " << session << " => " |
| - << it->second->first.ToString(); |
| + << it->second->first; |
|
joth
2011/12/09 23:28:37
nit: no need to line break
agl
2011/12/12 22:18:20
Done.
|
| DCHECK(it->second->second == session); |
| host_port_map_.erase(it->second); |
| session_map_.erase(it); |
| @@ -247,13 +251,15 @@ class SSLSessionCache { |
| // Looks up the host:port in the cache, and if a session is found it is added |
| // to |ssl|, returning true on success. |
| - bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port) { |
| + bool SetSSLSession(SSL* ssl, const HostPortPair& host_and_port, |
| + const std::string& shard) { |
| base::AutoLock lock(lock_); |
| - HostPortMap::iterator it = host_port_map_.find(host_and_port); |
| + const std::string cache_key = GetCacheKey(host_and_port, shard); |
| + HostPortMap::iterator it = host_port_map_.find(cache_key); |
| if (it == host_port_map_.end()) |
| return false; |
| DVLOG(2) << "Lookup session: " << it->second << " => " |
| - << host_and_port.ToString(); |
| + << cache_key; |
|
joth
2011/12/09 23:28:37
nit: no need for line break
agl
2011/12/12 22:18:20
Done.
|
| SSL_SESSION* session = it->second; |
| DCHECK(session); |
| DCHECK(session_map_[session] == it); |
| @@ -265,12 +271,26 @@ class SSLSessionCache { |
| return SSL_set_session(ssl, session) == 1; |
| } |
| + // Flush removes all entries from the cache. This is called when a client |
| + // certificate is added. |
| + void Flush() { |
| + for (HostPortMap::iterator i = host_port_map_.begin(); |
| + i != host_port_map_.end(); i++) { |
| + SSL_SESSION_free(i->second); |
| + } |
| + host_port_map_.clear(); |
| + session_map_.clear(); |
| + } |
| + |
| private: |
| + static std::string GetCacheKey(const HostPortPair& host_and_port, |
| + const std::string& shard) { |
| + return host_and_port.ToString() + "/" + shard; |
| + } |
| + |
| // A pair of maps to allow bi-directional lookups between host:port and an |
| // associated session. |
| - // TODO(joth): When client certificates are implemented we should key the |
| - // cache on the client certificate used in addition to the host-port pair. |
|
joth
2011/12/09 23:28:37
thanks for handling this one too. if I've followed
agl
2011/12/12 22:18:20
Right. And when we add a new client-cert, we flush
|
| - typedef std::map<HostPortPair, SSL_SESSION*> HostPortMap; |
| + typedef std::map<std::string, SSL_SESSION*> HostPortMap; |
| typedef std::map<SSL_SESSION*, HostPortMap::iterator> SessionMap; |
| HostPortMap host_port_map_; |
| SessionMap session_map_; |
| @@ -329,7 +349,9 @@ class SSLContext { |
| int NewSessionCallback(SSL* ssl, SSL_SESSION* session) { |
| SSLClientSocketOpenSSL* socket = GetClientSocketFromSSL(ssl); |
| - session_cache_.OnSessionAdded(socket->host_and_port(), session); |
| + session_cache_.OnSessionAdded(socket->host_and_port(), |
| + socket->session_cache_shard(), |
| + session); |
| return 1; // 1 => We took ownership of |session|. |
| } |
| @@ -360,8 +382,11 @@ class SSLContext { |
| // SSLClientSocketOpenSSL object from an SSL instance. |
| int ssl_socket_data_index_; |
| - crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; |
| + // session_cache_ must appear before |ssl_ctx_| because the destruction of |
| + // |ssl_ctx_| may trigger callbacks into |session_cache_|. Therefore, |
| + // |session_cache_| must be destructed after |ssl_ctx_|. |
| SSLSessionCache session_cache_; |
| + crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free> ssl_ctx_; |
| }; |
| // Utility to construct the appropriate set & clear masks for use the OpenSSL |
| @@ -379,6 +404,12 @@ struct SslSetClearMask { |
| } // namespace |
| +// static |
| +void SSLClientSocket::ClearSessionCache() { |
| + SSLContext* context = SSLContext::GetInstance(); |
| + context->session_cache()->Flush(); |
| +} |
| + |
| SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( |
| ClientSocketHandle* transport_socket, |
| const HostPortPair& host_and_port, |
| @@ -401,6 +432,7 @@ SSLClientSocketOpenSSL::SSLClientSocketOpenSSL( |
| transport_(transport_socket), |
| host_and_port_(host_and_port), |
| ssl_config_(ssl_config), |
| + session_cache_shard_(context.session_cache_shard), |
| trying_cached_session_(false), |
| npn_status_(kNextProtoUnsupported), |
| net_log_(transport_socket->socket()->NetLog()) { |
| @@ -425,7 +457,8 @@ bool SSLClientSocketOpenSSL::Init() { |
| return false; |
| trying_cached_session_ = |
| - context->session_cache()->SetSSLSession(ssl_, host_and_port_); |
| + context->session_cache()->SetSSLSession(ssl_, host_and_port_, |
| + session_cache_shard_); |
| BIO* ssl_bio = NULL; |
| // 0 => use default buffer sizes. |
| @@ -690,6 +723,9 @@ int SSLClientSocketOpenSSL::Connect(const CompletionCallback& callback) { |
| void SSLClientSocketOpenSSL::Disconnect() { |
| if (ssl_) { |
| + // Calling SSL_shutdown prevents the session from being marked as |
| + // unresumable. |
| + SSL_shutdown(ssl_); |
| SSL_free(ssl_); |
| ssl_ = NULL; |
| } |