diff options
author | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-28 17:30:37 +0000 |
---|---|---|
committer | willchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-06-28 17:30:37 +0000 |
commit | bdbda4656e353e11016a2946d3e5a6eb824bb8ac (patch) | |
tree | e416d641cdabac98d3bc5fa055811158f785dc6b | |
parent | 4457384fc143316ce58d65b6b356329ff1b3f16e (diff) | |
download | chromium_src-bdbda4656e353e11016a2946d3e5a6eb824bb8ac.zip chromium_src-bdbda4656e353e11016a2946d3e5a6eb824bb8ac.tar.gz chromium_src-bdbda4656e353e11016a2946d3e5a6eb824bb8ac.tar.bz2 |
SPDY: Make sure we don't try to send https/wss over an unauthenticated, but encrypted SSL socket.
BUG=46924
Review URL: http://codereview.chromium.org/2805039
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50997 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | net/http/http_network_transaction.cc | 39 | ||||
-rw-r--r-- | net/http/http_network_transaction.h | 3 | ||||
-rw-r--r-- | net/spdy/spdy_http_stream_unittest.cc | 6 | ||||
-rw-r--r-- | net/spdy/spdy_network_transaction.cc | 16 | ||||
-rw-r--r-- | net/spdy/spdy_session.cc | 55 | ||||
-rw-r--r-- | net/spdy/spdy_session.h | 20 | ||||
-rw-r--r-- | net/spdy/spdy_session_pool.cc | 10 | ||||
-rw-r--r-- | net/spdy/spdy_session_pool.h | 5 |
8 files changed, 109 insertions, 45 deletions
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc index 2b14d02..9524704 100644 --- a/net/http/http_network_transaction.cc +++ b/net/http/http_network_transaction.cc @@ -288,6 +288,7 @@ HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session) logged_response_time_(false), using_ssl_(false), using_spdy_(false), + spdy_certificate_error_(OK), alternate_protocol_mode_( g_use_alternate_protocols ? kUnspecified : kDoNotUseAlternateProtocol), @@ -1142,12 +1143,18 @@ int HttpNetworkTransaction::DoSSLConnectComplete(int result) { } if (IsCertificateError(result)) { - result = HandleCertificateError(result); - if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { - connection_->socket()->Disconnect(); - connection_->Reset(); - next_state_ = STATE_INIT_CONNECTION; - return result; + if (using_spdy_ && request_->url.SchemeIs("http")) { + // We ignore certificate errors for http over spdy. + spdy_certificate_error_ = result; + result = OK; + } else { + result = HandleCertificateError(result); + if (result == OK && !connection_->socket()->IsConnectedAndIdle()) { + connection_->socket()->Disconnect(); + connection_->Reset(); + next_state_ = STATE_INIT_CONNECTION; + return result; + } } } @@ -1494,7 +1501,8 @@ int HttpNetworkTransaction::DoSpdySendRequest() { DCHECK(using_ssl_); CHECK(connection_->socket()); int error = spdy_pool->GetSpdySessionFromSSLSocket( - endpoint_, session_, connection_.release(), net_log_, spdy_session); + endpoint_, session_, connection_.release(), net_log_, + spdy_certificate_error_, &spdy_session); if (error != OK) return error; } @@ -1510,17 +1518,24 @@ int HttpNetworkTransaction::DoSpdySendRequest() { } headers_valid_ = false; scoped_refptr<SpdyStream> spdy_stream; - if (request_->method == "GET") - spdy_stream = spdy_session->GetPushStream(request_->url, net_log_); + if (request_->method == "GET") { + int error = + spdy_session->GetPushStream(request_->url, &spdy_stream, net_log_); + if (error != OK) + return error; + } if (spdy_stream.get()) { DCHECK(spdy_stream->pushed()); CHECK(spdy_stream->GetDelegate() == NULL); spdy_http_stream_.reset(new SpdyHttpStream(spdy_stream)); spdy_http_stream_->InitializeRequest(*request_, base::Time::Now(), NULL); } else { - spdy_stream = spdy_session->CreateStream(request_->url, - request_->priority, - net_log_); + int error = spdy_session->CreateStream(request_->url, + request_->priority, + &spdy_stream, + net_log_); + if (error != OK) + return error; DCHECK(!spdy_stream->pushed()); CHECK(spdy_stream->GetDelegate() == NULL); spdy_http_stream_.reset(new SpdyHttpStream(spdy_stream)); diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h index a59f908..bc1d06b 100644 --- a/net/http/http_network_transaction.h +++ b/net/http/http_network_transaction.h @@ -295,6 +295,9 @@ class HttpNetworkTransaction : public HttpTransaction { // True if this network transaction is using SPDY instead of HTTP. bool using_spdy_; + // The certificate error while using SPDY over SSL for insecure URLs. + int spdy_certificate_error_; + AlternateProtocolMode alternate_protocol_mode_; // Only valid if |alternate_protocol_mode_| == kUsingAlternateProtocol. diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc index d1d3546..a2fdf58 100644 --- a/net/spdy/spdy_http_stream_unittest.cc +++ b/net/spdy/spdy_http_stream_unittest.cc @@ -116,8 +116,10 @@ TEST_F(SpdyHttpStreamTest, SendRequest) { TestCompletionCallback callback; HttpResponseInfo response; - scoped_refptr<SpdyStream> stream( - session->CreateStream(request.url, HIGHEST, BoundNetLog())); + scoped_refptr<SpdyStream> stream; + ASSERT_EQ( + OK, + session->CreateStream(request.url, HIGHEST, &stream, BoundNetLog())); scoped_ptr<SpdyHttpStream> http_stream(new SpdyHttpStream(stream.get())); http_stream->InitializeRequest(request, base::Time::Now(), NULL); diff --git a/net/spdy/spdy_network_transaction.cc b/net/spdy/spdy_network_transaction.cc index 5872a38..ce52518 100644 --- a/net/spdy/spdy_network_transaction.cc +++ b/net/spdy/spdy_network_transaction.cc @@ -257,8 +257,11 @@ int SpdyNetworkTransaction::DoSendRequest() { return error_code; } scoped_refptr<SpdyStream> spdy_stream; - if (request_->method == "GET") - spdy_stream = spdy_->GetPushStream(request_->url, net_log_); + if (request_->method == "GET") { + int error = spdy_->GetPushStream(request_->url, &spdy_stream, net_log_); + if (error != OK) + return error; + } if (spdy_stream.get()) { DCHECK(spdy_stream->pushed()); CHECK(spdy_stream->GetDelegate() == NULL); @@ -266,9 +269,12 @@ int SpdyNetworkTransaction::DoSendRequest() { stream_->InitializeRequest(*request_, base::Time::Now(), NULL); // "vary" field? } else { - spdy_stream = spdy_->CreateStream(request_->url, - request_->priority, - net_log_); + int error = spdy_->CreateStream(request_->url, + request_->priority, + &spdy_stream, + net_log_); + if (error != OK) + return error; DCHECK(!spdy_stream->pushed()); CHECK(spdy_stream->GetDelegate() == NULL); stream_.reset(new SpdyHttpStream(spdy_stream)); diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index 4910646..bc9be5e 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc @@ -153,6 +153,7 @@ SpdySession::SpdySession(const HostPortPair& host_port_pair, write_pending_(false), delayed_write_pending_(false), is_secure_(false), + certificate_error_code_(OK), error_(OK), state_(IDLE), streams_initiated_count_(0), @@ -191,7 +192,8 @@ SpdySession::~SpdySession() { } net::Error SpdySession::InitializeWithSSLSocket( - ClientSocketHandle* connection) { + ClientSocketHandle* connection, + int certificate_error_code) { static StatsCounter spdy_sessions("spdy.sessions"); spdy_sessions.Increment(); @@ -200,6 +202,7 @@ net::Error SpdySession::InitializeWithSSLSocket( state_ = CONNECTED; connection_.reset(connection); is_secure_ = true; // |connection| contains an SSLClientSocket. + certificate_error_code_ = certificate_error_code; // This is a newly initialized session that no client should have a handle to // yet, so there's no need to start writing data as in OnTCPConnect(), but we @@ -237,17 +240,30 @@ net::Error SpdySession::Connect(const std::string& group_name, return static_cast<net::Error>(rv); } -scoped_refptr<SpdyStream> SpdySession::GetPushStream( +int SpdySession::GetPushStream( const GURL& url, + scoped_refptr<SpdyStream>* stream, const BoundNetLog& stream_net_log) { CHECK_NE(state_, CLOSED); + + *stream = NULL; + + // Don't allow access to secure push streams over an unauthenticated, but + // encrypted SSL socket. + if (is_secure_ && certificate_error_code_ != OK && + (url.SchemeIs("https") || url.SchemeIs("wss"))) { + LOG(DFATAL) << "Tried to get pushed spdy stream for secure content over an " + << "unauthenticated session."; + return certificate_error_code_; + } + const std::string& path = url.PathForRequest(); - scoped_refptr<SpdyStream> stream = GetActivePushStream(path); - if (stream) { + *stream = GetActivePushStream(path); + if (stream->get()) { DCHECK(streams_pushed_and_claimed_count_ < streams_pushed_count_); streams_pushed_and_claimed_count_++; - return stream; + return OK; } // Check if we have a pending push stream for this url. @@ -260,24 +276,35 @@ scoped_refptr<SpdyStream> SpdySession::GetPushStream( // Server will assign a stream id when the push stream arrives. Use 0 for // now. net_log_.AddEvent(NetLog::TYPE_SPDY_STREAM_ADOPTED_PUSH_STREAM, NULL); - stream = new SpdyStream(this, 0, true); - stream->set_path(path); - stream->set_net_log(stream_net_log); - it->second = stream; - return stream; + *stream = new SpdyStream(this, 0, true); + (*stream)->set_path(path); + (*stream)->set_net_log(stream_net_log); + it->second = *stream; + return OK; } - return NULL; + return OK; } -const scoped_refptr<SpdyStream>& SpdySession::CreateStream( +int SpdySession::CreateStream( const GURL& url, RequestPriority priority, + scoped_refptr<SpdyStream>* spdy_stream, const BoundNetLog& stream_net_log) { + // Make sure that we don't try to send https/wss over an unauthenticated, but + // encrypted SSL socket. + if (is_secure_ && certificate_error_code_ != OK && + (url.SchemeIs("https") || url.SchemeIs("wss"))) { + LOG(DFATAL) << "Tried to create spdy stream for secure content over an " + << "unauthenticated session."; + return certificate_error_code_; + } + const std::string& path = url.PathForRequest(); const spdy::SpdyStreamId stream_id = GetNewStreamId(); - scoped_refptr<SpdyStream> stream(new SpdyStream(this, stream_id, false)); + *spdy_stream = new SpdyStream(this, stream_id, false); + const scoped_refptr<SpdyStream>& stream = *spdy_stream; stream->set_priority(priority); stream->set_path(path); @@ -293,7 +320,7 @@ const scoped_refptr<SpdyStream>& SpdySession::CreateStream( priority <= SPDY_PRIORITY_LOWEST); DCHECK_EQ(active_streams_[stream_id].get(), stream.get()); - return active_streams_[stream_id]; + return OK; } int SpdySession::WriteSynStream( diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index a46dad4..8a23168 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h @@ -59,22 +59,25 @@ class SpdySession : public base::RefCounted<SpdySession>, // Get a pushed stream for a given |url|. // If the server initiates a stream, it might already exist for a given path. // The server might also not have initiated the stream yet, but indicated it - // will via X-Associated-Content. - // Returns existing stream or NULL. - scoped_refptr<SpdyStream> GetPushStream( + // will via X-Associated-Content. Writes the stream out to |spdy_stream|. + // Returns a net error code. + int GetPushStream( const GURL& url, + scoped_refptr<SpdyStream>* spdy_stream, const BoundNetLog& stream_net_log); - // Create a new stream for a given |url|. - // Returns the new stream. Never returns NULL. - const scoped_refptr<SpdyStream>& CreateStream( + // Create a new stream for a given |url|. Writes it out to |spdy_stream|. + // Returns a net error code. + int CreateStream( const GURL& url, RequestPriority priority, + scoped_refptr<SpdyStream>* spdy_stream, const BoundNetLog& stream_net_log); // Used by SpdySessionPool to initialize with a pre-existing SSL socket. // Returns OK on success, or an error on failure. - net::Error InitializeWithSSLSocket(ClientSocketHandle* connection); + net::Error InitializeWithSSLSocket(ClientSocketHandle* connection, + int certificate_error_code); // Send the SYN frame for |stream_id|. int WriteSynStream( @@ -251,6 +254,9 @@ class SpdySession : public base::RefCounted<SpdySession>, // Flag if we're using an SSL connection for this SpdySession. bool is_secure_; + // Certificate error code when using a secure connection. + int certificate_error_code_; + // Spdy Frame state. spdy::SpdyFramer spdy_framer_; diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index 3374a2e..21fa0ac 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc @@ -53,17 +53,19 @@ net::Error SpdySessionPool::GetSpdySessionFromSSLSocket( HttpNetworkSession* session, ClientSocketHandle* connection, const BoundNetLog& net_log, - scoped_refptr<SpdySession>& spdy_session) { + int certificate_error_code, + scoped_refptr<SpdySession>* spdy_session) { // Create the SPDY session and add it to the pool. - spdy_session = (new SpdySession(host_port_pair, session, net_log.net_log())); + *spdy_session = new SpdySession(host_port_pair, session, net_log.net_log()); SpdySessionList* list = GetSessionList(host_port_pair); if (!list) list = AddSessionList(host_port_pair); DCHECK(list->empty()); - list->push_back(spdy_session); + list->push_back(*spdy_session); // Now we can initialize the session with the SSL socket. - return spdy_session->InitializeWithSSLSocket(connection); + return (*spdy_session)->InitializeWithSSLSocket(connection, + certificate_error_code); } bool SpdySessionPool::HasSession(const HostPortPair& host_port_pair) const { diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index 3ea97f3..321f55c 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -47,6 +47,8 @@ class SpdySessionPool // calling Get() first to use an existing SpdySession so we don't get // multiple SpdySessions per domain. Note that ownership of |connection| is // transferred from the caller to the SpdySession. + // |certificate_error_code| is used to indicate the certificate error + // encountered when connecting the SSL socket. OK means there was no error. // Returns OK on success, and the |spdy_session| will be provided. // Returns an error on failure, and |spdy_session| will be NULL. net::Error GetSpdySessionFromSSLSocket( @@ -54,7 +56,8 @@ class SpdySessionPool HttpNetworkSession* session, ClientSocketHandle* connection, const BoundNetLog& net_log, - scoped_refptr<SpdySession>& spdy_session); + int certificate_error_code, + scoped_refptr<SpdySession>* spdy_session); // TODO(willchan): Consider renaming to HasReusableSession, since perhaps we // should be creating a new session. |