summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-28 17:30:37 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-06-28 17:30:37 +0000
commitbdbda4656e353e11016a2946d3e5a6eb824bb8ac (patch)
treee416d641cdabac98d3bc5fa055811158f785dc6b
parent4457384fc143316ce58d65b6b356329ff1b3f16e (diff)
downloadchromium_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.cc39
-rw-r--r--net/http/http_network_transaction.h3
-rw-r--r--net/spdy/spdy_http_stream_unittest.cc6
-rw-r--r--net/spdy/spdy_network_transaction.cc16
-rw-r--r--net/spdy/spdy_session.cc55
-rw-r--r--net/spdy/spdy_session.h20
-rw-r--r--net/spdy/spdy_session_pool.cc10
-rw-r--r--net/spdy/spdy_session_pool.h5
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.