summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/automation/automation_profile_impl.cc2
-rw-r--r--chrome/browser/net/chrome_url_request_context.cc8
-rw-r--r--chrome/browser/net/chrome_url_request_context.h8
-rw-r--r--chrome/browser/profile.cc38
-rw-r--r--chrome/browser/profile.h22
-rw-r--r--chrome/browser/transport_security_persister.cc (renamed from chrome/browser/strict_transport_security_persister.cc)38
-rw-r--r--chrome/browser/transport_security_persister.h (renamed from chrome/browser/strict_transport_security_persister.h)46
-rwxr-xr-xchrome/chrome_browser.gypi4
-rw-r--r--chrome/test/testing_profile.h2
-rw-r--r--net/base/https_prober.cc80
-rw-r--r--net/base/https_prober.h73
-rw-r--r--net/base/strict_transport_security_state.h95
-rw-r--r--net/base/strict_transport_security_state_unittest.cc206
-rw-r--r--net/base/transport_security_state.cc (renamed from net/base/strict_transport_security_state.cc)89
-rw-r--r--net/base/transport_security_state.h111
-rw-r--r--net/base/transport_security_state_unittest.cc247
-rw-r--r--net/net.gyp8
-rw-r--r--net/url_request/url_request_context.h11
-rw-r--r--net/url_request/url_request_http_job.cc160
19 files changed, 794 insertions, 454 deletions
diff --git a/chrome/browser/automation/automation_profile_impl.cc b/chrome/browser/automation/automation_profile_impl.cc
index ce0949e..0acd37d 100644
--- a/chrome/browser/automation/automation_profile_impl.cc
+++ b/chrome/browser/automation/automation_profile_impl.cc
@@ -38,7 +38,7 @@ class AutomationURLRequestContext : public ChromeURLRequestContext {
http_transaction_factory_ = NULL;
ftp_transaction_factory_ = NULL;
cookie_store_ = NULL;
- strict_transport_security_state_ = NULL;
+ transport_security_state_ = NULL;
}
scoped_refptr<ChromeURLRequestContext> original_context_;
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc
index 51b5517..97fba69 100644
--- a/chrome/browser/net/chrome_url_request_context.cc
+++ b/chrome/browser/net/chrome_url_request_context.cc
@@ -750,7 +750,7 @@ ChromeURLRequestContext::ChromeURLRequestContext(
ftp_transaction_factory_ = other->ftp_transaction_factory_;
cookie_store_ = other->cookie_store_;
cookie_policy_.set_type(other->cookie_policy_.type());
- strict_transport_security_state_ = other->strict_transport_security_state_;
+ transport_security_state_ = other->transport_security_state_;
accept_language_ = other->accept_language_;
accept_charset_ = other->accept_charset_;
referrer_charset_ = other->referrer_charset_;
@@ -835,7 +835,7 @@ ChromeURLRequestContextFactory::ChromeURLRequestContextFactory(Profile* profile)
blacklist_manager_ = profile->GetBlacklistManager();
// TODO(eroman): this doesn't look safe; sharing between IO and UI threads!
- strict_transport_security_state_ = profile->GetStrictTransportSecurityState();
+ transport_security_state_ = profile->GetTransportSecurityState();
if (profile->GetExtensionsService()) {
const ExtensionList* extensions =
@@ -872,8 +872,8 @@ void ChromeURLRequestContextFactory::ApplyProfileParametersToContext(
context->set_user_script_dir_path(user_script_dir_path_);
context->set_host_zoom_map(host_zoom_map_);
context->set_blacklist_manager(blacklist_manager_.get());
- context->set_strict_transport_security_state(
- strict_transport_security_state_);
+ context->set_transport_security_state(
+ transport_security_state_);
context->set_ssl_config_service(ssl_config_service_);
}
diff --git a/chrome/browser/net/chrome_url_request_context.h b/chrome/browser/net/chrome_url_request_context.h
index 55c497a..912f484 100644
--- a/chrome/browser/net/chrome_url_request_context.h
+++ b/chrome/browser/net/chrome_url_request_context.h
@@ -212,9 +212,9 @@ class ChromeURLRequestContext : public URLRequestContext {
void set_cookie_policy_type(net::CookiePolicy::Type type) {
cookie_policy_.set_type(type);
}
- void set_strict_transport_security_state(
- net::StrictTransportSecurityState* state) {
- strict_transport_security_state_ = state;
+ void set_transport_security_state(
+ net::TransportSecurityState* state) {
+ transport_security_state_ = state;
}
void set_ssl_config_service(net::SSLConfigService* service) {
ssl_config_service_ = service;
@@ -317,7 +317,7 @@ class ChromeURLRequestContextFactory {
FilePath user_script_dir_path_;
scoped_refptr<HostZoomMap> host_zoom_map_;
scoped_refptr<BlacklistManager> blacklist_manager_;
- net::StrictTransportSecurityState* strict_transport_security_state_;
+ net::TransportSecurityState* transport_security_state_;
scoped_refptr<net::SSLConfigService> ssl_config_service_;
FilePath profile_dir_path_;
diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc
index fa245e0..3f5deee 100644
--- a/chrome/browser/profile.cc
+++ b/chrome/browser/profile.cc
@@ -27,7 +27,7 @@
#include "chrome/browser/extensions/user_script_master.h"
#include "chrome/browser/favicon_service.h"
#include "chrome/browser/spellcheck_host.h"
-#include "chrome/browser/strict_transport_security_persister.h"
+#include "chrome/browser/transport_security_persister.h"
#include "chrome/browser/history/history.h"
#include "chrome/browser/host_zoom_map.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
@@ -59,7 +59,7 @@
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "grit/locale_settings.h"
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/transport_security_state.h"
#include "webkit/database/database_tracker.h"
#if defined(OS_LINUX)
@@ -273,13 +273,13 @@ class OffTheRecordProfileImpl : public Profile,
return ssl_host_state_.get();
}
- virtual net::StrictTransportSecurityState* GetStrictTransportSecurityState() {
- if (!strict_transport_security_state_.get()) {
- strict_transport_security_state_ =
- new net::StrictTransportSecurityState();
+ virtual net::TransportSecurityState* GetTransportSecurityState() {
+ if (!transport_security_state_.get()) {
+ transport_security_state_ =
+ new net::TransportSecurityState();
}
- return strict_transport_security_state_.get();
+ return transport_security_state_.get();
}
virtual HistoryService* GetHistoryService(ServiceAccessType sat) {
@@ -551,9 +551,9 @@ class OffTheRecordProfileImpl : public Profile,
// the user visited while OTR.
scoped_ptr<SSLHostState> ssl_host_state_;
- // The StrictTransportSecurityState that only stores enabled sites in memory.
- scoped_refptr<net::StrictTransportSecurityState>
- strict_transport_security_state_;
+ // The TransportSecurityState that only stores enabled sites in memory.
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
// Time we were started.
Time start_time_;
@@ -855,17 +855,17 @@ SSLHostState* ProfileImpl::GetSSLHostState() {
return ssl_host_state_.get();
}
-net::StrictTransportSecurityState*
- ProfileImpl::GetStrictTransportSecurityState() {
- if (!strict_transport_security_state_.get()) {
- strict_transport_security_state_ = new net::StrictTransportSecurityState();
- strict_transport_security_persister_ =
- new StrictTransportSecurityPersister();
- strict_transport_security_persister_->Initialize(
- strict_transport_security_state_.get(), path_);
+net::TransportSecurityState*
+ ProfileImpl::GetTransportSecurityState() {
+ if (!transport_security_state_.get()) {
+ transport_security_state_ = new net::TransportSecurityState();
+ transport_security_persister_ =
+ new TransportSecurityPersister();
+ transport_security_persister_->Initialize(
+ transport_security_state_.get(), path_);
}
- return strict_transport_security_state_.get();
+ return transport_security_state_.get();
}
PrefService* ProfileImpl::GetPrefs() {
diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h
index 2a1c065..815dc22 100644
--- a/chrome/browser/profile.h
+++ b/chrome/browser/profile.h
@@ -22,7 +22,7 @@
#endif
namespace net {
-class StrictTransportSecurityState;
+class TransportSecurityState;
class SSLConfigService;
}
@@ -55,7 +55,7 @@ class SessionService;
class SpellCheckHost;
class SSLConfigServiceManager;
class SSLHostState;
-class StrictTransportSecurityPersister;
+class TransportSecurityPersister;
class SQLitePersistentCookieStore;
class TabRestoreService;
class TemplateURLFetcher;
@@ -174,11 +174,11 @@ class Profile {
// called.
virtual SSLHostState* GetSSLHostState() = 0;
- // Retrieves a pointer to the StrictTransportSecurityState associated with
- // this profile. The StrictTransportSecurityState is lazily created the
+ // Retrieves a pointer to the TransportSecurityState associated with
+ // this profile. The TransportSecurityState is lazily created the
// first time that this method is called.
- virtual net::StrictTransportSecurityState*
- GetStrictTransportSecurityState() = 0;
+ virtual net::TransportSecurityState*
+ GetTransportSecurityState() = 0;
// Retrieves a pointer to the FaviconService associated with this
// profile. The FaviconService is lazily created the first time
@@ -408,7 +408,7 @@ class ProfileImpl : public Profile,
virtual VisitedLinkMaster* GetVisitedLinkMaster();
virtual UserScriptMaster* GetUserScriptMaster();
virtual SSLHostState* GetSSLHostState();
- virtual net::StrictTransportSecurityState* GetStrictTransportSecurityState();
+ virtual net::TransportSecurityState* GetTransportSecurityState();
virtual ExtensionsService* GetExtensionsService();
virtual ExtensionDevToolsManager* GetExtensionDevToolsManager();
virtual ExtensionProcessManager* GetExtensionProcessManager();
@@ -499,10 +499,10 @@ class ProfileImpl : public Profile,
scoped_ptr<ExtensionProcessManager> extension_process_manager_;
scoped_refptr<ExtensionMessageService> extension_message_service_;
scoped_ptr<SSLHostState> ssl_host_state_;
- scoped_refptr<net::StrictTransportSecurityState>
- strict_transport_security_state_;
- scoped_refptr<StrictTransportSecurityPersister>
- strict_transport_security_persister_;
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
+ scoped_refptr<TransportSecurityPersister>
+ transport_security_persister_;
scoped_ptr<PrefService> prefs_;
scoped_refptr<ThumbnailStore> thumbnail_store_;
scoped_ptr<TemplateURLFetcher> template_url_fetcher_;
diff --git a/chrome/browser/strict_transport_security_persister.cc b/chrome/browser/transport_security_persister.cc
index ce6078a..ffc1ab3 100644
--- a/chrome/browser/strict_transport_security_persister.cc
+++ b/chrome/browser/transport_security_persister.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/strict_transport_security_persister.h"
+#include "chrome/browser/transport_security_persister.h"
#include "base/file_path.h"
#include "base/file_util.h"
@@ -10,29 +10,29 @@
#include "base/path_service.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/common/chrome_paths.h"
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/transport_security_state.h"
-StrictTransportSecurityPersister::StrictTransportSecurityPersister()
+TransportSecurityPersister::TransportSecurityPersister()
: state_is_dirty_(false) {
}
-StrictTransportSecurityPersister::~StrictTransportSecurityPersister() {
- strict_transport_security_state_->SetDelegate(NULL);
+TransportSecurityPersister::~TransportSecurityPersister() {
+ transport_security_state_->SetDelegate(NULL);
}
-void StrictTransportSecurityPersister::Initialize(
- net::StrictTransportSecurityState* state, const FilePath& profile_path) {
- strict_transport_security_state_ = state;
+void TransportSecurityPersister::Initialize(
+ net::TransportSecurityState* state, const FilePath& profile_path) {
+ transport_security_state_ = state;
state_file_ =
- profile_path.Append(FILE_PATH_LITERAL("StrictTransportSecurity"));
+ profile_path.Append(FILE_PATH_LITERAL("TransportSecurity"));
state->SetDelegate(this);
Task* task = NewRunnableMethod(this,
- &StrictTransportSecurityPersister::LoadState);
+ &TransportSecurityPersister::LoadState);
ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE, task, 1000);
}
-void StrictTransportSecurityPersister::LoadState() {
+void TransportSecurityPersister::LoadState() {
AutoLock locked_(lock_);
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
@@ -40,26 +40,26 @@ void StrictTransportSecurityPersister::LoadState() {
if (!file_util::ReadFileToString(state_file_, &state))
return;
- strict_transport_security_state_->Deserialise(state);
+ transport_security_state_->Deserialise(state);
}
-void StrictTransportSecurityPersister::StateIsDirty(
- net::StrictTransportSecurityState* state) {
+void TransportSecurityPersister::StateIsDirty(
+ net::TransportSecurityState* state) {
// Runs on arbitary thread, may not block nor reenter
- // |strict_transport_security_state_|.
+ // |transport_security_state_|.
AutoLock locked_(lock_);
- DCHECK(state == strict_transport_security_state_);
+ DCHECK(state == transport_security_state_);
if (state_is_dirty_)
return; // we already have a serialisation scheduled
Task* task = NewRunnableMethod(this,
- &StrictTransportSecurityPersister::SerialiseState);
+ &TransportSecurityPersister::SerialiseState);
ChromeThread::PostDelayedTask(ChromeThread::FILE, FROM_HERE, task, 1000);
state_is_dirty_ = true;
}
-void StrictTransportSecurityPersister::SerialiseState() {
+void TransportSecurityPersister::SerialiseState() {
AutoLock locked_(lock_);
DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
@@ -67,7 +67,7 @@ void StrictTransportSecurityPersister::SerialiseState() {
state_is_dirty_ = false;
std::string state;
- if (!strict_transport_security_state_->Serialise(&state))
+ if (!transport_security_state_->Serialise(&state))
return;
file_util::WriteFile(state_file_, state.data(), state.size());
diff --git a/chrome/browser/strict_transport_security_persister.h b/chrome/browser/transport_security_persister.h
index 8a24660..660faa7 100644
--- a/chrome/browser/strict_transport_security_persister.h
+++ b/chrome/browser/transport_security_persister.h
@@ -2,32 +2,32 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// StrictTransportSecurityState maintains an in memory database containing the
-// list of hosts that currently have strict transport security enabled. This
+// TransportSecurityState maintains an in memory database containing the
+// list of hosts that currently have transport security enabled. This
// singleton object deals with writing that data out to disk as needed and
// loading it at startup.
-// At startup we need to load the strict transport security state from the
+// At startup we need to load the transport security state from the
// disk. For the moment, we don't want to delay startup for this load, so we
-// let the StrictTransportSecurityState run for a while without being loaded.
+// let the TransportSecurityState run for a while without being loaded.
// This means that it's possible for pages opened very quickly not to get the
-// correct strict transport security information.
+// correct transport security information.
//
// To load the state, we schedule a Task on the file thread which loads,
-// deserialises and configures the StrictTransportSecurityState.
+// deserialises and configures the TransportSecurityState.
//
-// The StrictTransportSecurityState object supports running a callback function
+// The TransportSecurityState object supports running a callback function
// when it changes. This object registers the callback, pointing at itself.
//
-// StrictTransportSecurityState calls...
-// StrictTransportSecurityPersister::StateIsDirty
+// TransportSecurityState calls...
+// TransportSecurityPersister::StateIsDirty
// since the callback isn't allowed to block or reenter, we schedule a Task
// on the file thread after some small amount of time
//
// ...
//
-// StrictTransportSecurityPersister::SerialiseState
-// copies the current state of the StrictTransportSecurityState, serialises
+// TransportSecurityPersister::SerialiseState
+// copies the current state of the TransportSecurityState, serialises
// and writes to disk.
#ifndef CHROME_BROWSER_STRICT_TRANSPORT_SECURITY_PERSISTER_H_
@@ -36,23 +36,23 @@
#include "base/file_path.h"
#include "base/lock.h"
#include "base/ref_counted.h"
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/transport_security_state.h"
-class StrictTransportSecurityPersister
- : public base::RefCountedThreadSafe<StrictTransportSecurityPersister>,
- public net::StrictTransportSecurityState::Delegate {
+class TransportSecurityPersister
+ : public base::RefCountedThreadSafe<TransportSecurityPersister>,
+ public net::TransportSecurityState::Delegate {
public:
- StrictTransportSecurityPersister();
- void Initialize(net::StrictTransportSecurityState* state,
+ TransportSecurityPersister();
+ void Initialize(net::TransportSecurityState* state,
const FilePath& profile_path);
- // Called by the StrictTransportSecurityState when it changes its state.
- virtual void StateIsDirty(net::StrictTransportSecurityState*);
+ // Called by the TransportSecurityState when it changes its state.
+ virtual void StateIsDirty(net::TransportSecurityState*);
private:
- friend class base::RefCountedThreadSafe<StrictTransportSecurityPersister>;
+ friend class base::RefCountedThreadSafe<TransportSecurityPersister>;
- ~StrictTransportSecurityPersister();
+ ~TransportSecurityPersister();
// a Task callback for when the state needs to be written out.
void SerialiseState();
@@ -66,8 +66,8 @@ class StrictTransportSecurityPersister
// serialised the state yet.
bool state_is_dirty_;
- scoped_refptr<net::StrictTransportSecurityState>
- strict_transport_security_state_;
+ scoped_refptr<net::TransportSecurityState>
+ transport_security_state_;
// The path to the file in which we store the serialised state.
FilePath state_file_;
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 11d042f..5ac8be1 100755
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -1436,8 +1436,8 @@
'browser/ssl/ssl_policy_backend.h',
'browser/ssl/ssl_request_info.h',
'browser/status_bubble.h',
- 'browser/strict_transport_security_persister.cc',
- 'browser/strict_transport_security_persister.h',
+ 'browser/transport_security_persister.cc',
+ 'browser/transport_security_persister.h',
'browser/sync/engine/syncapi.h',
'browser/sync/glue/bookmark_model_worker.cc',
'browser/sync/glue/bookmark_model_worker.h',
diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h
index 7d6451c..0e6f16d 100644
--- a/chrome/test/testing_profile.h
+++ b/chrome/test/testing_profile.h
@@ -85,7 +85,7 @@ class TestingProfile : public Profile {
virtual ExtensionProcessManager* GetExtensionProcessManager() { return NULL; }
virtual ExtensionMessageService* GetExtensionMessageService() { return NULL; }
virtual SSLHostState* GetSSLHostState() { return NULL; }
- virtual net::StrictTransportSecurityState* GetStrictTransportSecurityState() {
+ virtual net::TransportSecurityState* GetTransportSecurityState() {
return NULL;
}
virtual FaviconService* GetFaviconService(ServiceAccessType access) {
diff --git a/net/base/https_prober.cc b/net/base/https_prober.cc
new file mode 100644
index 0000000..c37f17d
--- /dev/null
+++ b/net/base/https_prober.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/https_prober.h"
+
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+
+namespace net {
+
+bool HTTPSProber::HaveProbed(const std::string& host) const {
+ return probed_.find(host) != probed_.end();
+}
+
+bool HTTPSProber::InFlight(const std::string& host) const {
+ return inflight_probes_.find(host) != inflight_probes_.end();
+}
+
+bool HTTPSProber::ProbeHost(const std::string& host, URLRequestContext* ctx,
+ HTTPSProberDelegate* delegate) {
+ if (HaveProbed(host) || InFlight(host)) {
+ return false;
+ }
+
+ inflight_probes_[host] = delegate;
+
+ GURL url("https://" + host);
+ DCHECK_EQ(url.host(), host);
+
+ URLRequest* req = new URLRequest(url, this);
+ req->set_context(ctx);
+ req->Start();
+ return true;
+}
+
+void HTTPSProber::Success(URLRequest* request) {
+ DoCallback(request, true);
+}
+
+void HTTPSProber::Failure(URLRequest* request) {
+ DoCallback(request, false);
+}
+
+void HTTPSProber::DoCallback(URLRequest* request, bool result) {
+ std::map<std::string, HTTPSProberDelegate*>::iterator i =
+ inflight_probes_.find(request->original_url().host());
+ DCHECK(i != inflight_probes_.end());
+
+ HTTPSProberDelegate* delegate = i->second;
+ inflight_probes_.erase(i);
+ probed_.insert(request->original_url().host());
+ delete request;
+ delegate->ProbeComplete(result);
+}
+
+void HTTPSProber::OnAuthRequired(URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
+ Success(request);
+}
+
+void HTTPSProber::OnSSLCertificateError(URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert) {
+ request->ContinueDespiteLastError();
+}
+
+void HTTPSProber::OnResponseStarted(URLRequest* request) {
+ if (request->status().status() == URLRequestStatus::SUCCESS) {
+ Success(request);
+ } else {
+ Failure(request);
+ }
+}
+
+void HTTPSProber::OnReadCompleted(URLRequest* request, int bytes_read) {
+ NOTREACHED();
+}
+
+} // namespace net
diff --git a/net/base/https_prober.h b/net/base/https_prober.h
new file mode 100644
index 0000000..327fc16
--- /dev/null
+++ b/net/base/https_prober.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_HTTPS_PROBER_H_
+#define NET_BASE_HTTPS_PROBER_H_
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "base/singleton.h"
+#include "base/task.h"
+#include "net/url_request/url_request.h"
+
+class URLRequestContext;
+
+namespace net {
+
+// This should be scoped inside HTTPSProber, but VC cannot compile
+// HTTPProber::Delegate when HTTPSProber also inherits from
+// URLRequest::Delegate.
+class HTTPSProberDelegate {
+ public:
+ virtual void ProbeComplete(bool result) = 0;
+};
+
+// HTTPSProber is a singleton object that manages HTTPS probes. A HTTPS probe
+// determines if we can connect to a given host over HTTPS. It's used when
+// transparently upgrading from HTTP to HTTPS (for example, for SPDY).
+class HTTPSProber : public URLRequest::Delegate {
+ public:
+ HTTPSProber() { }
+
+ // HaveProbed returns true if the given host is known to have been probed
+ // since the browser was last started.
+ bool HaveProbed(const std::string& host) const;
+
+ // InFlight returns true iff a probe for the given host is currently active.
+ bool InFlight(const std::string& host) const;
+
+ // ProbeHost starts a new probe for the given host. If the host is known to
+ // have been probed since the browser was started, false is returned and no
+ // other action is taken. If a probe to the given host in currently inflight,
+ // false will be returned, and no other action is taken. Otherwise, a new
+ // probe is started, true is returned and the Delegate will be called with the
+ // results (true means a successful handshake).
+ bool ProbeHost(const std::string& host, URLRequestContext* ctx,
+ HTTPSProberDelegate* delegate);
+
+ // Implementation of URLRequest::Delegate
+ void OnAuthRequired(URLRequest* request,
+ net::AuthChallengeInfo* auth_info);
+ void OnSSLCertificateError(URLRequest* request,
+ int cert_error,
+ net::X509Certificate* cert);
+ void OnResponseStarted(URLRequest* request);
+ void OnReadCompleted(URLRequest* request, int bytes_read);
+
+ private:
+ void Success(URLRequest* request);
+ void Failure(URLRequest* request);
+ void DoCallback(URLRequest* request, bool result);
+
+ std::map<std::string, HTTPSProberDelegate*> inflight_probes_;
+ std::set<std::string> probed_;
+
+ friend struct DefaultSingletonTraits<HTTPSProber>;
+ DISALLOW_EVIL_CONSTRUCTORS(HTTPSProber);
+};
+
+} // namespace net
+#endif
diff --git a/net/base/strict_transport_security_state.h b/net/base/strict_transport_security_state.h
deleted file mode 100644
index de7d2b1..0000000
--- a/net/base/strict_transport_security_state.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_BASE_STRICT_TRANSPORT_SECURITY_STATE_H_
-#define NET_BASE_STRICT_TRANSPORT_SECURITY_STATE_H_
-
-#include <map>
-#include <string>
-
-#include "base/basictypes.h"
-#include "base/lock.h"
-#include "base/ref_counted.h"
-#include "base/time.h"
-
-class GURL;
-
-namespace net {
-
-// StrictTransportSecurityState
-//
-// Tracks which hosts have enabled StrictTransportSecurityState. After a host
-// enables StrictTransportSecurityState, then we refuse to talk to the host
-// over HTTP, treat all certificate errors as fatal, and refuse to load any
-// mixed content.
-//
-class StrictTransportSecurityState :
- public base::RefCountedThreadSafe<StrictTransportSecurityState> {
- public:
- StrictTransportSecurityState();
-
- // Called when we see an X-Force-TLS header that we should process. Modifies
- // our state as instructed by the header.
- void DidReceiveHeader(const GURL& url, const std::string& value);
-
- // Enable StrictTransportSecurity for |host|.
- void EnableHost(const std::string& host, base::Time expiry,
- bool include_subdomains);
-
- // Returns whether |host| has had StrictTransportSecurity enabled.
- bool IsEnabledForHost(const std::string& host);
-
- // Returns |true| if |value| parses as a valid X-Force-TLS header value.
- // The values of max-age and and includeSubDomains are returned in |max_age|
- // and |include_subdomains|, respectively. The out parameters are not
- // modified if the function returns |false|.
- static bool ParseHeader(const std::string& value,
- int* max_age,
- bool* include_subdomains);
-
- struct State {
- base::Time expiry; // the absolute time (UTC) when this record expires
- bool include_subdomains; // subdomains included?
- };
-
- class Delegate {
- public:
- // This function may not block and may be called with internal locks held.
- // Thus it must not reenter the StrictTransportSecurityState object.
- virtual void StateIsDirty(StrictTransportSecurityState* state) = 0;
- };
-
- void SetDelegate(Delegate*);
-
- bool Serialise(std::string* output);
- bool Deserialise(const std::string& state);
-
- private:
- friend class base::RefCountedThreadSafe<StrictTransportSecurityState>;
-
- ~StrictTransportSecurityState() {}
-
- // If we have a callback configured, call it to let our serialiser know that
- // our state is dirty.
- void DirtyNotify();
-
- // The set of hosts that have enabled StrictTransportSecurity. The keys here
- // are SHA256(DNSForm(domain)) where DNSForm converts from dotted form
- // ('www.google.com') to the form used in DNS: "\x03www\x06google\x03com"
- std::map<std::string, State> enabled_hosts_;
-
- // Protect access to our data members with this lock.
- Lock lock_;
-
- // Our delegate who gets notified when we are dirtied, or NULL.
- Delegate* delegate_;
-
- static std::string CanonicaliseHost(const std::string& host);
-
- DISALLOW_COPY_AND_ASSIGN(StrictTransportSecurityState);
-};
-
-} // namespace net
-
-#endif // NET_BASE_STRICT_TRANSPORT_SECURITY_STATE_H_
diff --git a/net/base/strict_transport_security_state_unittest.cc b/net/base/strict_transport_security_state_unittest.cc
deleted file mode 100644
index 5ebd358..0000000
--- a/net/base/strict_transport_security_state_unittest.cc
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/base/strict_transport_security_state.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-class StrictTransportSecurityStateTest : public testing::Test {
-};
-
-TEST_F(StrictTransportSecurityStateTest, BogusHeaders) {
- int max_age = 42;
- bool include_subdomains = false;
-
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "abc", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " abc", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " abc ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age=", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age =", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age= ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age = ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age = xy", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- " max-age = 3488a923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488a923 ", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-ag=3488923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-aged=3488923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age==3488923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "amax-age=3488923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=-3488923", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923;", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 e", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomain", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923includesubdomains", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923=includesubdomains", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomainx", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomain=", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomain=true", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomainsx", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=3488923 includesubdomains x", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=34889.23 includesubdomains", &max_age, &include_subdomains));
- EXPECT_FALSE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=34889 includesubdomains", &max_age, &include_subdomains));
-
- EXPECT_EQ(max_age, 42);
- EXPECT_FALSE(include_subdomains);
-}
-
-TEST_F(StrictTransportSecurityStateTest, ValidHeaders) {
- int max_age = 42;
- bool include_subdomains = true;
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=243", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 243);
- EXPECT_FALSE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- " Max-agE = 567", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 567);
- EXPECT_FALSE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- " mAx-aGe = 890 ", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 890);
- EXPECT_FALSE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=123;incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 123);
- EXPECT_TRUE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=394082; incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 394082);
- EXPECT_TRUE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=39408299 ;incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 39408299);
- EXPECT_TRUE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- "max-age=394082038 ; incLudesUbdOmains", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 394082038);
- EXPECT_TRUE(include_subdomains);
-
- EXPECT_TRUE(net::StrictTransportSecurityState::ParseHeader(
- " max-age=0 ; incLudesUbdOmains ", &max_age, &include_subdomains));
- EXPECT_EQ(max_age, 0);
- EXPECT_TRUE(include_subdomains);
-}
-
-TEST_F(StrictTransportSecurityStateTest, SimpleMatches) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
- const base::Time current_time(base::Time::Now());
- const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
-
- EXPECT_FALSE(state->IsEnabledForHost("google.com"));
- state->EnableHost("google.com", expiry, false);
- EXPECT_TRUE(state->IsEnabledForHost("google.com"));
-}
-
-TEST_F(StrictTransportSecurityStateTest, MatchesCase1) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
- const base::Time current_time(base::Time::Now());
- const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
-
- EXPECT_FALSE(state->IsEnabledForHost("google.com"));
- state->EnableHost("GOOgle.coM", expiry, false);
- EXPECT_TRUE(state->IsEnabledForHost("google.com"));
-}
-
-TEST_F(StrictTransportSecurityStateTest, MatchesCase2) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
- const base::Time current_time(base::Time::Now());
- const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
-
- EXPECT_FALSE(state->IsEnabledForHost("GOOgle.coM"));
- state->EnableHost("google.com", expiry, false);
- EXPECT_TRUE(state->IsEnabledForHost("GOOgle.coM"));
-}
-
-TEST_F(StrictTransportSecurityStateTest, SubdomainMatches) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
- const base::Time current_time(base::Time::Now());
- const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
-
- EXPECT_FALSE(state->IsEnabledForHost("google.com"));
- state->EnableHost("google.com", expiry, true);
- EXPECT_TRUE(state->IsEnabledForHost("google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.bar.google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.bar.baz.google.com"));
- EXPECT_FALSE(state->IsEnabledForHost("com"));
-}
-
-TEST_F(StrictTransportSecurityStateTest, Serialise1) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
- std::string output;
- state->Serialise(&output);
- EXPECT_TRUE(state->Deserialise(output));
-}
-
-TEST_F(StrictTransportSecurityStateTest, Serialise2) {
- scoped_refptr<net::StrictTransportSecurityState> state(
- new net::StrictTransportSecurityState);
-
- const base::Time current_time(base::Time::Now());
- const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
-
- EXPECT_FALSE(state->IsEnabledForHost("google.com"));
- state->EnableHost("google.com", expiry, true);
-
- std::string output;
- state->Serialise(&output);
- EXPECT_TRUE(state->Deserialise(output));
-
- EXPECT_TRUE(state->IsEnabledForHost("google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.bar.google.com"));
- EXPECT_TRUE(state->IsEnabledForHost("foo.bar.baz.google.com"));
- EXPECT_FALSE(state->IsEnabledForHost("com"));
-}
diff --git a/net/base/strict_transport_security_state.cc b/net/base/transport_security_state.cc
index 29f892f..35b930c 100644
--- a/net/base/strict_transport_security_state.cc
+++ b/net/base/transport_security_state.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/transport_security_state.h"
#include "base/base64.h"
#include "base/json/json_reader.h"
@@ -18,28 +18,12 @@
namespace net {
-StrictTransportSecurityState::StrictTransportSecurityState()
+TransportSecurityState::TransportSecurityState()
: delegate_(NULL) {
}
-void StrictTransportSecurityState::DidReceiveHeader(const GURL& url,
- const std::string& value) {
- int max_age;
- bool include_subdomains;
-
- if (!ParseHeader(value, &max_age, &include_subdomains))
- return;
-
- base::Time current_time(base::Time::Now());
- base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
- base::Time expiry = current_time + max_age_delta;
-
- EnableHost(url.host(), expiry, include_subdomains);
-}
-
-void StrictTransportSecurityState::EnableHost(const std::string& host,
- base::Time expiry,
- bool include_subdomains) {
+void TransportSecurityState::EnableHost(const std::string& host,
+ const DomainState& state) {
const std::string canonicalised_host = CanonicaliseHost(host);
if (canonicalised_host.empty())
return;
@@ -48,12 +32,12 @@ void StrictTransportSecurityState::EnableHost(const std::string& host,
AutoLock lock(lock_);
- State state = {expiry, include_subdomains};
enabled_hosts_[std::string(hashed, sizeof(hashed))] = state;
DirtyNotify();
}
-bool StrictTransportSecurityState::IsEnabledForHost(const std::string& host) {
+bool TransportSecurityState::IsEnabledForHost(DomainState* result,
+ const std::string& host) {
const std::string canonicalised_host = CanonicaliseHost(host);
if (canonicalised_host.empty())
return false;
@@ -66,7 +50,7 @@ bool StrictTransportSecurityState::IsEnabledForHost(const std::string& host) {
base::SHA256HashString(&canonicalised_host[i], &hashed_domain,
sizeof(hashed_domain));
- std::map<std::string, State>::iterator j =
+ std::map<std::string, DomainState>::iterator j =
enabled_hosts_.find(std::string(hashed_domain, sizeof(hashed_domain)));
if (j == enabled_hosts_.end())
continue;
@@ -77,6 +61,8 @@ bool StrictTransportSecurityState::IsEnabledForHost(const std::string& host) {
continue;
}
+ *result = j->second;
+
// If we matched the domain exactly, it doesn't matter what the value of
// include_subdomains is.
if (i == 0)
@@ -90,9 +76,9 @@ bool StrictTransportSecurityState::IsEnabledForHost(const std::string& host) {
// "Strict-Transport-Security" ":"
// "max-age" "=" delta-seconds [ ";" "includeSubDomains" ]
-bool StrictTransportSecurityState::ParseHeader(const std::string& value,
- int* max_age,
- bool* include_subdomains) {
+bool TransportSecurityState::ParseHeader(const std::string& value,
+ int* max_age,
+ bool* include_subdomains) {
DCHECK(max_age);
DCHECK(include_subdomains);
@@ -187,8 +173,8 @@ bool StrictTransportSecurityState::ParseHeader(const std::string& value,
}
}
-void StrictTransportSecurityState::SetDelegate(
- StrictTransportSecurityState::Delegate* delegate) {
+void TransportSecurityState::SetDelegate(
+ TransportSecurityState::Delegate* delegate) {
AutoLock lock(lock_);
delegate_ = delegate;
@@ -215,16 +201,32 @@ static std::string ExternalStringToHashedDomain(const std::wstring& external) {
return out;
}
-bool StrictTransportSecurityState::Serialise(std::string* output) {
+bool TransportSecurityState::Serialise(std::string* output) {
AutoLock lock(lock_);
DictionaryValue toplevel;
- for (std::map<std::string, State>::const_iterator
+ for (std::map<std::string, DomainState>::const_iterator
i = enabled_hosts_.begin(); i != enabled_hosts_.end(); ++i) {
DictionaryValue* state = new DictionaryValue;
state->SetBoolean(L"include_subdomains", i->second.include_subdomains);
state->SetReal(L"expiry", i->second.expiry.ToDoubleT());
+ switch (i->second.mode) {
+ case DomainState::MODE_STRICT:
+ state->SetString(L"mode", "strict");
+ break;
+ case DomainState::MODE_OPPORTUNISTIC:
+ state->SetString(L"mode", "opportunistic");
+ break;
+ case DomainState::MODE_SPDY_ONLY:
+ state->SetString(L"mode", "spdy-only");
+ break;
+ default:
+ NOTREACHED() << "DomainState with unknown mode";
+ delete state;
+ continue;
+ }
+
toplevel.Set(HashedDomainToExternalString(i->first), state);
}
@@ -232,7 +234,7 @@ bool StrictTransportSecurityState::Serialise(std::string* output) {
return true;
}
-bool StrictTransportSecurityState::Deserialise(const std::string& input) {
+bool TransportSecurityState::Deserialise(const std::string& input) {
AutoLock lock(lock_);
enabled_hosts_.clear();
@@ -252,13 +254,28 @@ bool StrictTransportSecurityState::Deserialise(const std::string& input) {
continue;
bool include_subdomains;
+ std::string mode_string;
double expiry;
if (!state->GetBoolean(L"include_subdomains", &include_subdomains) ||
+ !state->GetString(L"mode", &mode_string) ||
!state->GetReal(L"expiry", &expiry)) {
continue;
}
+ DomainState::Mode mode;
+ if (mode_string == "strict") {
+ mode = DomainState::MODE_STRICT;
+ } else if (mode_string == "opportunistic") {
+ mode = DomainState::MODE_OPPORTUNISTIC;
+ } else if (mode_string == "spdy-only") {
+ mode = DomainState::MODE_SPDY_ONLY;
+ } else {
+ LOG(WARNING) << "Unknown TransportSecurityState mode string found: "
+ << mode_string;
+ continue;
+ }
+
base::Time expiry_time = base::Time::FromDoubleT(expiry);
if (expiry_time <= current_time)
continue;
@@ -267,21 +284,23 @@ bool StrictTransportSecurityState::Deserialise(const std::string& input) {
if (hashed.empty())
continue;
- State new_state = { expiry_time, include_subdomains };
+ DomainState new_state;
+ new_state.mode = mode;
+ new_state.expiry = expiry_time;
+ new_state.include_subdomains = include_subdomains;
enabled_hosts_[hashed] = new_state;
}
return true;
}
-void StrictTransportSecurityState::DirtyNotify() {
+void TransportSecurityState::DirtyNotify() {
if (delegate_)
delegate_->StateIsDirty(this);
}
// static
-std::string StrictTransportSecurityState::CanonicaliseHost(
- const std::string& host) {
+std::string TransportSecurityState::CanonicaliseHost(const std::string& host) {
// We cannot perform the operations as detailed in the spec here as |host|
// has already undergone IDN processing before it reached us. Thus, we check
// that there are no invalid characters in the host and lowercase the result.
diff --git a/net/base/transport_security_state.h b/net/base/transport_security_state.h
new file mode 100644
index 0000000..360eb0b
--- /dev/null
+++ b/net/base/transport_security_state.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_BASE_TRANSPORT_SECURITY_STATE_H_
+#define NET_BASE_TRANSPORT_SECURITY_STATE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+#include "base/ref_counted.h"
+#include "base/time.h"
+
+class GURL;
+
+namespace net {
+
+// TransportSecurityState
+//
+// Tracks which hosts have enabled *-Transport-Security. This object manages
+// the in-memory store. A separate object must register itself with this object
+// in order to persist the state to disk.
+class TransportSecurityState :
+ public base::RefCountedThreadSafe<TransportSecurityState> {
+ public:
+ TransportSecurityState();
+
+ // A DomainState is the information that we persist about a given domain.
+ struct DomainState {
+ enum Mode {
+ // Strict mode implies:
+ // * We generate internal redirects from HTTP -> HTTPS.
+ // * Certificate issues are fatal.
+ MODE_STRICT = 0,
+ // Opportunistic mode implies:
+ // * We'll request HTTP URLs over HTTPS
+ // * Certificate issues are ignored.
+ MODE_OPPORTUNISTIC = 1,
+ // SPDY_ONLY (aka X-Bodge-Transport-Security) is a hopefully temporary
+ // measure. It implies:
+ // * We'll request HTTP URLs over HTTPS iff we have SPDY support.
+ // * Certificate issues are fatal.
+ MODE_SPDY_ONLY = 2,
+ };
+ Mode mode;
+
+ DomainState()
+ : mode(MODE_STRICT),
+ include_subdomains(false) { }
+
+ base::Time expiry; // the absolute time (UTC) when this record expires
+ bool include_subdomains; // subdomains included?
+ };
+
+ // Enable TransportSecurity for |host|.
+ void EnableHost(const std::string& host, const DomainState& state);
+
+ // Returns true if |host| has TransportSecurity enabled. If that case,
+ // *result is filled out.
+ bool IsEnabledForHost(DomainState* result, const std::string& host);
+
+ // Returns |true| if |value| parses as a valid *-Transport-Security
+ // header value. The values of max-age and and includeSubDomains are
+ // returned in |max_age| and |include_subdomains|, respectively. The out
+ // parameters are not modified if the function returns |false|.
+ static bool ParseHeader(const std::string& value,
+ int* max_age,
+ bool* include_subdomains);
+
+ class Delegate {
+ public:
+ // This function may not block and may be called with internal locks held.
+ // Thus it must not reenter the TransportSecurityState object.
+ virtual void StateIsDirty(TransportSecurityState* state) = 0;
+ };
+
+ void SetDelegate(Delegate*);
+
+ bool Serialise(std::string* output);
+ bool Deserialise(const std::string& state);
+
+ private:
+ friend class base::RefCountedThreadSafe<TransportSecurityState>;
+
+ ~TransportSecurityState() {}
+
+ // If we have a callback configured, call it to let our serialiser know that
+ // our state is dirty.
+ void DirtyNotify();
+
+ // The set of hosts that have enabled TransportSecurity. The keys here
+ // are SHA256(DNSForm(domain)) where DNSForm converts from dotted form
+ // ('www.google.com') to the form used in DNS: "\x03www\x06google\x03com"
+ std::map<std::string, DomainState> enabled_hosts_;
+
+ // Protect access to our data members with this lock.
+ Lock lock_;
+
+ // Our delegate who gets notified when we are dirtied, or NULL.
+ Delegate* delegate_;
+
+ static std::string CanonicaliseHost(const std::string& host);
+
+ DISALLOW_COPY_AND_ASSIGN(TransportSecurityState);
+};
+
+} // namespace net
+
+#endif // NET_BASE_TRANSPORT_SECURITY_STATE_H_
diff --git a/net/base/transport_security_state_unittest.cc b/net/base/transport_security_state_unittest.cc
new file mode 100644
index 0000000..f52912c
--- /dev/null
+++ b/net/base/transport_security_state_unittest.cc
@@ -0,0 +1,247 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/base/transport_security_state.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TransportSecurityStateTest : public testing::Test {
+};
+
+TEST_F(TransportSecurityStateTest, BogusHeaders) {
+ int max_age = 42;
+ bool include_subdomains = false;
+
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "abc", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " abc", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " abc ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age=", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age =", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age= ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age = ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age = xy", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ " max-age = 3488a923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488a923 ", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-ag=3488923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-aged=3488923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age==3488923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "amax-age=3488923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=-3488923", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923;", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 e", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomain", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923includesubdomains", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923=includesubdomains", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomainx", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomain=", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomain=true", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomainsx", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=3488923 includesubdomains x", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=34889.23 includesubdomains", &max_age, &include_subdomains));
+ EXPECT_FALSE(net::TransportSecurityState::ParseHeader(
+ "max-age=34889 includesubdomains", &max_age, &include_subdomains));
+
+ EXPECT_EQ(max_age, 42);
+ EXPECT_FALSE(include_subdomains);
+}
+
+TEST_F(TransportSecurityStateTest, ValidHeaders) {
+ int max_age = 42;
+ bool include_subdomains = true;
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ "max-age=243", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 243);
+ EXPECT_FALSE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ " Max-agE = 567", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 567);
+ EXPECT_FALSE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ " mAx-aGe = 890 ", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 890);
+ EXPECT_FALSE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ "max-age=123;incLudesUbdOmains", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 123);
+ EXPECT_TRUE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ "max-age=394082; incLudesUbdOmains", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 394082);
+ EXPECT_TRUE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ "max-age=39408299 ;incLudesUbdOmains", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 39408299);
+ EXPECT_TRUE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ "max-age=394082038 ; incLudesUbdOmains", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 394082038);
+ EXPECT_TRUE(include_subdomains);
+
+ EXPECT_TRUE(net::TransportSecurityState::ParseHeader(
+ " max-age=0 ; incLudesUbdOmains ", &max_age, &include_subdomains));
+ EXPECT_EQ(max_age, 0);
+ EXPECT_TRUE(include_subdomains);
+}
+
+TEST_F(TransportSecurityStateTest, SimpleMatches) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+ domain_state.expiry = expiry;
+ state->EnableHost("google.com", domain_state);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+}
+
+TEST_F(TransportSecurityStateTest, MatchesCase1) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+ domain_state.expiry = expiry;
+ state->EnableHost("GOOgle.coM", domain_state);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+}
+
+TEST_F(TransportSecurityStateTest, MatchesCase2) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "GOOgle.coM"));
+ domain_state.expiry = expiry;
+ state->EnableHost("google.com", domain_state);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "GOOgle.coM"));
+}
+
+TEST_F(TransportSecurityStateTest, SubdomainMatches) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+ domain_state.expiry = expiry;
+ domain_state.include_subdomains = true;
+ state->EnableHost("google.com", domain_state);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.google.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.bar.google.com"));
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state,
+ "foo.bar.baz.google.com"));
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "com"));
+}
+
+TEST_F(TransportSecurityStateTest, Serialise1) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+ std::string output;
+ state->Serialise(&output);
+ EXPECT_TRUE(state->Deserialise(output));
+}
+
+TEST_F(TransportSecurityStateTest, Serialise2) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+ domain_state.mode = net::TransportSecurityState::DomainState::MODE_STRICT;
+ domain_state.expiry = expiry;
+ domain_state.include_subdomains = true;
+ state->EnableHost("google.com", domain_state);
+
+ std::string output;
+ state->Serialise(&output);
+ EXPECT_TRUE(state->Deserialise(output));
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+ EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.google.com"));
+ EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "foo.bar.google.com"));
+ EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state,
+ "foo.bar.baz.google.com"));
+ EXPECT_EQ(domain_state.mode, net::TransportSecurityState::DomainState::MODE_STRICT);
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "com"));
+}
+
+TEST_F(TransportSecurityStateTest, Serialise3) {
+ scoped_refptr<net::TransportSecurityState> state(
+ new net::TransportSecurityState);
+
+ net::TransportSecurityState::DomainState domain_state;
+ const base::Time current_time(base::Time::Now());
+ const base::Time expiry = current_time + base::TimeDelta::FromSeconds(1000);
+
+ EXPECT_FALSE(state->IsEnabledForHost(&domain_state, "google.com"));
+ domain_state.mode = net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
+ domain_state.expiry = expiry;
+ state->EnableHost("google.com", domain_state);
+
+ std::string output;
+ state->Serialise(&output);
+ EXPECT_TRUE(state->Deserialise(output));
+
+ EXPECT_TRUE(state->IsEnabledForHost(&domain_state, "google.com"));
+ EXPECT_EQ(domain_state.mode,
+ net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC);
+}
diff --git a/net/net.gyp b/net/net.gyp
index 5118981..7f0d88e 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -75,6 +75,8 @@
'base/host_resolver_impl.h',
'base/host_resolver_proc.cc',
'base/host_resolver_proc.h',
+ 'base/https_prober.h',
+ 'base/https_prober.cc',
'base/io_buffer.cc',
'base/io_buffer.h',
'base/keygen_handler.h',
@@ -131,8 +133,8 @@
'base/ssl_config_service_win.cc',
'base/ssl_config_service_win.h',
'base/ssl_info.h',
- 'base/strict_transport_security_state.cc',
- 'base/strict_transport_security_state.h',
+ 'base/transport_security_state.cc',
+ 'base/transport_security_state.h',
'base/telnet_server.cc',
'base/telnet_server.h',
'base/test_completion_callback.h',
@@ -597,7 +599,7 @@
'base/ssl_client_auth_cache_unittest.cc',
'base/ssl_config_service_mac_unittest.cc',
'base/ssl_config_service_win_unittest.cc',
- 'base/strict_transport_security_state_unittest.cc',
+ 'base/transport_security_state_unittest.cc',
'base/telnet_server_unittest.cc',
'base/test_certificate_data.h',
'base/test_completion_callback_unittest.cc',
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index f02bc43..5eac06e 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -16,7 +16,7 @@
#include "net/base/cookie_store.h"
#include "net/base/host_resolver.h"
#include "net/base/ssl_config_service.h"
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/transport_security_state.h"
#include "net/ftp/ftp_auth_cache.h"
#include "net/proxy/proxy_service.h"
#include "net/url_request/request_tracker.h"
@@ -36,7 +36,7 @@ class URLRequestContext :
: http_transaction_factory_(NULL),
ftp_transaction_factory_(NULL),
cookie_store_(NULL),
- strict_transport_security_state_(NULL) {
+ transport_security_state_(NULL) {
}
net::HostResolver* host_resolver() const {
@@ -69,8 +69,8 @@ class URLRequestContext :
// Gets the cookie policy for this context.
net::CookiePolicy* cookie_policy() { return &cookie_policy_; }
- net::StrictTransportSecurityState* strict_transport_security_state() {
- return strict_transport_security_state_; }
+ net::TransportSecurityState* transport_security_state() {
+ return transport_security_state_; }
// Gets the FTP authentication cache for this context.
net::FtpAuthCache* ftp_auth_cache() { return &ftp_auth_cache_; }
@@ -132,8 +132,7 @@ class URLRequestContext :
net::FtpTransactionFactory* ftp_transaction_factory_;
scoped_refptr<net::CookieStore> cookie_store_;
net::CookiePolicy cookie_policy_;
- scoped_refptr<net::StrictTransportSecurityState>
- strict_transport_security_state_;
+ scoped_refptr<net::TransportSecurityState> transport_security_state_;
net::FtpAuthCache ftp_auth_cache_;
std::string accept_language_;
std::string accept_charset_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 84d5709..755bfa7 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -14,7 +14,8 @@
#include "base/string_util.h"
#include "net/base/cert_status_flags.h"
#include "net/base/filter.h"
-#include "net/base/strict_transport_security_state.h"
+#include "net/base/https_prober.h"
+#include "net/base/transport_security_state.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
@@ -46,17 +47,24 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
return new URLRequestErrorJob(request, net::ERR_INVALID_ARGUMENT);
}
+ net::TransportSecurityState::DomainState domain_state;
if (scheme == "http" &&
- request->context()->strict_transport_security_state() &&
- request->context()->strict_transport_security_state()->IsEnabledForHost(
- request->url().host())) {
- DCHECK_EQ(request->url().scheme(), "http");
- url_canon::Replacements<char> replacements;
- static const char kNewScheme[] = "https";
- replacements.SetScheme(kNewScheme,
- url_parse::Component(0, strlen(kNewScheme)));
- GURL new_location = request->url().ReplaceComponents(replacements);
- return new URLRequestRedirectJob(request, new_location);
+ (request->url().port().empty() || port == 80) &&
+ request->context()->transport_security_state() &&
+ request->context()->transport_security_state()->IsEnabledForHost(
+ &domain_state, request->url().host())) {
+ if (domain_state.mode ==
+ net::TransportSecurityState::DomainState::MODE_STRICT) {
+ DCHECK_EQ(request->url().scheme(), "http");
+ url_canon::Replacements<char> replacements;
+ static const char kNewScheme[] = "https";
+ replacements.SetScheme(kNewScheme,
+ url_parse::Component(0, strlen(kNewScheme)));
+ GURL new_location = request->url().ReplaceComponents(replacements);
+ return new URLRequestRedirectJob(request, new_location);
+ } else {
+ // TODO(agl): implement opportunistic HTTPS upgrade.
+ }
}
return new URLRequestHttpJob(request);
@@ -483,11 +491,16 @@ bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) {
return false;
// Check whether our context is using Strict-Transport-Security.
- if (!context_->strict_transport_security_state())
+ if (!context_->transport_security_state())
return true;
- return !context_->strict_transport_security_state()->IsEnabledForHost(
- request_info_.url.host());
+ net::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());
+
+ return !r || domain_state.mode ==
+ net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
}
void URLRequestHttpJob::NotifyHeadersComplete() {
@@ -686,28 +699,125 @@ void URLRequestHttpJob::FetchResponseCookies() {
response_cookies_.push_back(value);
}
+class HTTPSProberDelegate : public net::HTTPSProberDelegate {
+ public:
+ HTTPSProberDelegate(const std::string& host, int max_age,
+ bool include_subdomains,
+ net::TransportSecurityState* sts)
+ : host_(host),
+ max_age_(max_age),
+ include_subdomains_(include_subdomains),
+ sts_(sts) { }
+
+ virtual void ProbeComplete(bool result) {
+ if (result) {
+ base::Time current_time(base::Time::Now());
+ base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age_);
+
+ net::TransportSecurityState::DomainState domain_state;
+ domain_state.expiry = current_time + max_age_delta;
+ domain_state.mode =
+ net::TransportSecurityState::DomainState::MODE_OPPORTUNISTIC;
+ domain_state.include_subdomains = include_subdomains_;
+
+ sts_->EnableHost(host_, domain_state);
+ }
-void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
- DCHECK(response_info_);
+ delete this;
+ }
- // Only process Strict-Transport-Security from HTTPS responses.
- if (request_info_.url.scheme() != "https")
- return;
+ private:
+ const std::string host_;
+ const int max_age_;
+ const bool include_subdomains_;
+ scoped_refptr<net::TransportSecurityState> sts_;
+};
- // Only process Strict-Transport-Security from responses with valid certificates.
- if (response_info_->ssl_info.cert_status & net::CERT_STATUS_ALL_ERRORS)
- return;
+void URLRequestHttpJob::ProcessStrictTransportSecurityHeader() {
+ DCHECK(response_info_);
URLRequestContext* ctx = request_->context();
- if (!ctx || !ctx->strict_transport_security_state())
+ if (!ctx || !ctx->transport_security_state())
return;
+ const bool https = response_info_->ssl_info.is_valid();
+ const bool valid_https =
+ https &&
+ !(response_info_->ssl_info.cert_status & net::CERT_STATUS_ALL_ERRORS);
+
std::string name = "Strict-Transport-Security";
std::string value;
+ int max_age;
+ bool include_subdomains;
+
void* iter = NULL;
while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
- ctx->strict_transport_security_state()->DidReceiveHeader(
- request_info_.url, value);
+ const bool ok = net::TransportSecurityState::ParseHeader(
+ value, &max_age, &include_subdomains);
+ if (!ok)
+ continue;
+ // We will only accept strict mode if we saw the header from an HTTPS
+ // connection with no certificate problems.
+ if (!valid_https)
+ continue;
+ base::Time current_time(base::Time::Now());
+ base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
+
+ net::TransportSecurityState::DomainState domain_state;
+ domain_state.expiry = current_time + max_age_delta;
+ domain_state.mode = net::TransportSecurityState::DomainState::MODE_STRICT;
+ domain_state.include_subdomains = include_subdomains;
+
+ ctx->transport_security_state()->EnableHost(request_info_.url.host(),
+ domain_state);
+ }
+
+ // TODO(agl): change this over when we have fixed things at the server end.
+ // The string should be "Opportunistic-Transport-Security";
+ name = "X-Bodge-Transport-Security";
+
+ while (response_info_->headers->EnumerateHeader(&iter, name, &value)) {
+ const bool ok = net::TransportSecurityState::ParseHeader(
+ value, &max_age, &include_subdomains);
+ if (!ok)
+ continue;
+ // If we saw an opportunistic request over HTTPS, then clearly we can make
+ // HTTPS connections to the host so we should remember this.
+ if (https) {
+ base::Time current_time(base::Time::Now());
+ base::TimeDelta max_age_delta = base::TimeDelta::FromSeconds(max_age);
+
+ net::TransportSecurityState::DomainState domain_state;
+ domain_state.expiry = current_time + max_age_delta;
+ domain_state.mode =
+ net::TransportSecurityState::DomainState::MODE_SPDY_ONLY;
+ domain_state.include_subdomains = include_subdomains;
+
+ ctx->transport_security_state()->EnableHost(request_info_.url.host(),
+ domain_state);
+ continue;
+ }
+
+ if (!request())
+ break;
+
+ // At this point, we have a request for opportunistic encryption over HTTP.
+ // In this case we need to probe to check that we can make HTTPS
+ // connections to that host.
+ net::HTTPSProber* const prober = Singleton<net::HTTPSProber>::get();
+ if (prober->HaveProbed(request_info_.url.host()) ||
+ prober->InFlight(request_info_.url.host())) {
+ continue;
+ }
+
+ net::HTTPSProberDelegate* delegate =
+ new HTTPSProberDelegate(request_info_.url.host(), max_age,
+ include_subdomains,
+ ctx->transport_security_state());
+ if (!prober->ProbeHost(request_info_.url.host(), request()->context(),
+ delegate)) {
+ delete delegate;
+ }
}
}