diff options
-rw-r--r-- | content/browser/renderer_host/socket_stream_host.cc | 3 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job.cc | 21 | ||||
-rw-r--r-- | net/socket_stream/socket_stream_job.h | 5 | ||||
-rw-r--r-- | net/url_request/url_request_context.cc | 9 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 3 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 16 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.h | 2 | ||||
-rw-r--r-- | net/websockets/websocket_job_unittest.cc | 26 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_socket_stream_bridge.cc | 3 |
9 files changed, 68 insertions, 20 deletions
diff --git a/content/browser/renderer_host/socket_stream_host.cc b/content/browser/renderer_host/socket_stream_host.cc index c2f1a79..67350fd 100644 --- a/content/browser/renderer_host/socket_stream_host.cc +++ b/content/browser/renderer_host/socket_stream_host.cc @@ -47,7 +47,8 @@ SocketStreamHost::~SocketStreamHost() { void SocketStreamHost::Connect(const GURL& url, net::URLRequestContext* request_context) { VLOG(1) << "SocketStreamHost::Connect url=" << url; - socket_ = net::SocketStreamJob::CreateSocketStreamJob(url, delegate_); + socket_ = net::SocketStreamJob::CreateSocketStreamJob( + url, delegate_, *request_context); socket_->set_context(request_context); socket_->SetUserData(kSocketIdKey, new SocketStreamId(socket_id_)); socket_->Connect(); diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc index b52945a..0349de8 100644 --- a/net/socket_stream/socket_stream_job.cc +++ b/net/socket_stream/socket_stream_job.cc @@ -5,7 +5,9 @@ #include "net/socket_stream/socket_stream_job.h" #include "base/memory/singleton.h" +#include "net/base/transport_security_state.h" #include "net/socket_stream/socket_stream_job_manager.h" +#include "net/url_request/url_request_context.h" namespace net { @@ -18,8 +20,23 @@ SocketStreamJob::ProtocolFactory* SocketStreamJob::RegisterProtocolFactory( // static SocketStreamJob* SocketStreamJob::CreateSocketStreamJob( - const GURL& url, SocketStream::Delegate* delegate) { - return SocketStreamJobManager::GetInstance()->CreateJob(url, delegate); + const GURL& url, + SocketStream::Delegate* delegate, + const URLRequestContext& context) { + GURL socket_url(url); + TransportSecurityState::DomainState domain_state; + if (url.scheme() == "ws" && + context.transport_security_state() && + context.transport_security_state()->IsEnabledForHost( + &domain_state, url.host(), context.IsSNIAvailable()) && + domain_state.mode == TransportSecurityState::DomainState::MODE_STRICT) { + url_canon::Replacements<char> replacements; + static const char kNewScheme[] = "wss"; + replacements.SetScheme(kNewScheme, + url_parse::Component(0, strlen(kNewScheme))); + socket_url = url.ReplaceComponents(replacements); + } + return SocketStreamJobManager::GetInstance()->CreateJob(socket_url, delegate); } SocketStreamJob::SocketStreamJob() {} diff --git a/net/socket_stream/socket_stream_job.h b/net/socket_stream/socket_stream_job.h index 9a4577e..24eaa19 100644 --- a/net/socket_stream/socket_stream_job.h +++ b/net/socket_stream/socket_stream_job.h @@ -32,7 +32,9 @@ class SocketStreamJob : public base::RefCountedThreadSafe<SocketStreamJob> { ProtocolFactory* factory); static SocketStreamJob* CreateSocketStreamJob( - const GURL& url, SocketStream::Delegate* delegate); + const GURL& url, + SocketStream::Delegate* delegate, + const URLRequestContext& context); SocketStreamJob(); void InitSocketStream(SocketStream* socket) { @@ -61,6 +63,7 @@ class SocketStreamJob : public base::RefCountedThreadSafe<SocketStreamJob> { virtual void DetachDelegate(); protected: + friend class WebSocketJobTest; friend class base::RefCountedThreadSafe<SocketStreamJob>; virtual ~SocketStreamJob(); diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc index 7e02641..09ac381 100644 --- a/net/url_request/url_request_context.cc +++ b/net/url_request/url_request_context.cc @@ -58,6 +58,15 @@ const std::string& URLRequestContext::GetUserAgent(const GURL& url) const { return EmptyString(); } +bool URLRequestContext::IsSNIAvailable() const { + if (!ssl_config_service_) + return false; + + SSLConfig ssl_config; + ssl_config_service_->GetSSLConfig(&ssl_config); + return ssl_config.tls1_enabled; +} + URLRequestContext::~URLRequestContext() { } diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index ea80143..2c99059 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -180,6 +180,9 @@ class URLRequestContext bool is_main() const { return is_main_; } void set_is_main(bool is_main) { is_main_ = is_main; } + // Is SNI available in this request context? + bool IsSNIAvailable() const; + protected: friend class base::RefCountedThreadSafe<URLRequestContext>; diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 7166e5f..19b86a8 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -183,7 +183,7 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request, request->context()->transport_security_state()->IsEnabledForHost( &domain_state, request->url().host(), - IsSNIAvailable(request->context()))) { + request->context()->IsSNIAvailable())) { if (domain_state.mode == TransportSecurityState::DomainState::MODE_STRICT) { DCHECK_EQ(request->url().scheme(), "http"); @@ -665,7 +665,7 @@ void URLRequestHttpJob::OnStartCompleted(int result) { if (context_->transport_security_state()->IsEnabledForHost( &domain_state, request_->url().host(), - IsSNIAvailable(context_)) && + context_->IsSNIAvailable()) && ssl_info.is_issued_by_known_root && !domain_state.IsChainOfPublicKeysPermitted(ssl_info.public_key_hashes)){ result = ERR_CERT_INVALID; @@ -720,7 +720,7 @@ bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) { TransportSecurityState::DomainState domain_state; // TODO(agl): don't ignore opportunistic mode. const bool r = context_->transport_security_state()->IsEnabledForHost( - &domain_state, request_info_.url.host(), IsSNIAvailable(context_)); + &domain_state, request_info_.url.host(), context_->IsSNIAvailable()); return !r || domain_state.mode == TransportSecurityState::DomainState::MODE_OPPORTUNISTIC; @@ -1370,14 +1370,4 @@ bool URLRequestHttpJob::IsCompressibleContent() const { IsSupportedNonImageMimeType(mime_type.c_str())); } -// static -bool URLRequestHttpJob::IsSNIAvailable(URLRequestContext* context) { - if (!context->ssl_config_service()) - return false; - - SSLConfig ssl_config; - context->ssl_config_service()->GetSSLConfig(&ssl_config); - return ssl_config.tls1_enabled; -} - } // namespace net diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index 5173ae1..7ac5c97 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -147,8 +147,6 @@ class URLRequestHttpJob : public URLRequestJob { void RecordCompressionHistograms(); bool IsCompressibleContent() const; - static bool IsSNIAvailable(URLRequestContext* context); - base::Time request_creation_time_; // Data used for statistics gathering. This data is only used for histograms diff --git a/net/websockets/websocket_job_unittest.cc b/net/websockets/websocket_job_unittest.cc index a0ae1d4..f027a4a 100644 --- a/net/websockets/websocket_job_unittest.cc +++ b/net/websockets/websocket_job_unittest.cc @@ -13,6 +13,7 @@ #include "net/base/cookie_store.h" #include "net/base/net_errors.h" #include "net/base/sys_addrinfo.h" +#include "net/base/transport_security_state.h" #include "net/socket_stream/socket_stream.h" #include "net/url_request/url_request_context.h" #include "net/websockets/websocket_job.h" @@ -156,11 +157,18 @@ class MockURLRequestContext : public URLRequestContext { CookiePolicy* cookie_policy) { set_cookie_store(cookie_store); set_cookie_policy(cookie_policy); + transport_security_state_ = new TransportSecurityState(); + set_transport_security_state(transport_security_state_.get()); + TransportSecurityState::DomainState state; + state.expiry = base::Time::Now() + base::TimeDelta::FromSeconds(1000); + transport_security_state_->EnableHost("upgrademe.com", state); } private: friend class base::RefCountedThreadSafe<MockURLRequestContext>; virtual ~MockURLRequestContext() {} + + scoped_refptr<TransportSecurityState> transport_security_state_; }; class WebSocketJobTest : public PlatformTest { @@ -209,6 +217,9 @@ class WebSocketJobTest : public PlatformTest { websocket_->delegate_ = NULL; websocket_->socket_ = NULL; } + SocketStream* GetSocket(SocketStreamJob* job) { + return job->socket_.get(); + } scoped_refptr<MockCookieStore> cookie_store_; scoped_ptr<MockCookiePolicy> cookie_policy_; @@ -494,4 +505,19 @@ TEST_F(WebSocketJobTest, HandshakeWithCookieButNotAllowed) { CloseWebSocketJob(); } +TEST_F(WebSocketJobTest, HSTSUpgrade) { + GURL url("ws://upgrademe.com/"); + MockSocketStreamDelegate delegate; + scoped_refptr<SocketStreamJob> job = SocketStreamJob::CreateSocketStreamJob( + url, &delegate, *context_.get()); + EXPECT_TRUE(GetSocket(job.get())->is_secure()); + job->DetachDelegate(); + + url = GURL("ws://donotupgrademe.com/"); + job = SocketStreamJob::CreateSocketStreamJob( + url, &delegate, *context_.get()); + EXPECT_FALSE(GetSocket(job.get())->is_secure()); + job->DetachDelegate(); +} + } // namespace net diff --git a/webkit/tools/test_shell/simple_socket_stream_bridge.cc b/webkit/tools/test_shell/simple_socket_stream_bridge.cc index 4420b26..a555b48 100644 --- a/webkit/tools/test_shell/simple_socket_stream_bridge.cc +++ b/webkit/tools/test_shell/simple_socket_stream_bridge.cc @@ -156,7 +156,8 @@ void WebSocketStreamHandleBridgeImpl::OnClose(net::SocketStream* socket) { void WebSocketStreamHandleBridgeImpl::DoConnect(const GURL& url) { DCHECK(MessageLoop::current() == g_io_thread); - socket_ = net::SocketStreamJob::CreateSocketStreamJob(url, this); + socket_ = net::SocketStreamJob::CreateSocketStreamJob( + url, this, *g_request_context); socket_->set_context(g_request_context); socket_->Connect(); } |