diff options
-rw-r--r-- | chrome/browser/net/chrome_url_request_context.cc | 2 | ||||
-rw-r--r-- | chrome/browser/profile.cc | 18 | ||||
-rw-r--r-- | chrome/browser/profile.h | 10 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy.cc | 14 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy_backend.cc | 8 | ||||
-rw-r--r-- | chrome/browser/ssl/ssl_policy_backend.h | 10 | ||||
-rw-r--r-- | chrome/test/testing_profile.h | 3 | ||||
-rw-r--r-- | net/base/force_tls_state.cc | 34 | ||||
-rw-r--r-- | net/base/force_tls_state.h | 50 | ||||
-rw-r--r-- | net/net.gyp | 2 | ||||
-rw-r--r-- | net/url_request/url_request_context.h | 7 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 57 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.h | 5 |
13 files changed, 210 insertions, 10 deletions
diff --git a/chrome/browser/net/chrome_url_request_context.cc b/chrome/browser/net/chrome_url_request_context.cc index 06b3739..3ea9cc1 100644 --- a/chrome/browser/net/chrome_url_request_context.cc +++ b/chrome/browser/net/chrome_url_request_context.cc @@ -292,6 +292,8 @@ ChromeURLRequestContext::ChromeURLRequestContext(Profile* profile) cookie_policy_.SetType(net::CookiePolicy::FromInt( prefs_->GetInteger(prefs::kCookieBehavior))); + force_tls_state_ = profile->GetForceTLSState(); + if (profile->GetExtensionsService()) { const ExtensionList* extensions = profile->GetExtensionsService()->extensions(); diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 1c76c49..cdb7c00 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -39,6 +39,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" #include "grit/locale_settings.h" +#include "net/base/force_tls_state.h" using base::Time; using base::TimeDelta; @@ -171,6 +172,13 @@ class OffTheRecordProfileImpl : public Profile, return ssl_host_state_.get(); } + virtual net::ForceTLSState* GetForceTLSState() { + if (!force_tls_state_.get()) + force_tls_state_.reset(new net::ForceTLSState()); + + return force_tls_state_.get(); + } + virtual HistoryService* GetHistoryService(ServiceAccessType sat) { if (sat == EXPLICIT_ACCESS) { return profile_->GetHistoryService(sat); @@ -389,6 +397,9 @@ class OffTheRecordProfileImpl : public Profile, // the user visited while OTR. scoped_ptr<SSLHostState> ssl_host_state_; + // The ForceTLSState that only stores enabled sites in memory. + scoped_ptr<net::ForceTLSState> force_tls_state_; + // Extensions run in a different context in incognito mode. scoped_ptr<ExtensionProcessManager> extension_process_manager_; @@ -627,6 +638,13 @@ SSLHostState* ProfileImpl::GetSSLHostState() { return ssl_host_state_.get(); } +net::ForceTLSState* ProfileImpl::GetForceTLSState() { + if (!force_tls_state_.get()) + force_tls_state_.reset(new net::ForceTLSState()); + + return force_tls_state_.get(); +} + PrefService* ProfileImpl::GetPrefs() { if (!prefs_.get()) { prefs_.reset(new PrefService(GetPrefFilePath(), diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 6ec129c..be775c2 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -20,6 +20,9 @@ #endif #include "chrome/common/notification_observer.h" +namespace net { +class ForceTLSState; +} class BookmarkModel; class ChromeURLRequestContext; class DownloadManager; @@ -128,6 +131,11 @@ class Profile { // called. virtual SSLHostState* GetSSLHostState() = 0; + // Retrieves a pointer to the ForceTLStSate associated with this profile. + // The ForceTLSState is lazily created the first time that this method is + // called. + virtual net::ForceTLSState* GetForceTLSState() = 0; + // Retrieves a pointer to the HistoryService associated with this // profile. The HistoryService is lazily created the first time // that this method is called. @@ -301,6 +309,7 @@ class ProfileImpl : public Profile, virtual VisitedLinkMaster* GetVisitedLinkMaster(); virtual UserScriptMaster* GetUserScriptMaster(); virtual SSLHostState* GetSSLHostState(); + virtual net::ForceTLSState* GetForceTLSState(); virtual ExtensionsService* GetExtensionsService(); virtual ExtensionProcessManager* GetExtensionProcessManager(); virtual HistoryService* GetHistoryService(ServiceAccessType sat); @@ -371,6 +380,7 @@ class ProfileImpl : public Profile, scoped_refptr<UserScriptMaster> user_script_master_; scoped_ptr<ExtensionProcessManager> extension_process_manager_; scoped_ptr<SSLHostState> ssl_host_state_; + scoped_ptr<net::ForceTLSState> force_tls_state_; scoped_ptr<PrefService> prefs_; scoped_ptr<TemplateURLFetcher> template_url_fetcher_; scoped_ptr<TemplateURLModel> template_url_model_; diff --git a/chrome/browser/ssl/ssl_policy.cc b/chrome/browser/ssl/ssl_policy.cc index 7004da7..3bf64e5 100644 --- a/chrome/browser/ssl/ssl_policy.cc +++ b/chrome/browser/ssl/ssl_policy.cc @@ -6,6 +6,8 @@ #include "app/l10n_util.h" #include "app/resource_bundle.h" +#include "base/base_switches.h" +#include "base/command_line.h" #include "base/singleton.h" #include "base/string_piece.h" #include "base/string_util.h" @@ -117,11 +119,15 @@ void SSLPolicy::OnMixedContent(SSLMixedContentHandler* handler) { // If the user has added an exception, doctor the |filter_policy|. std::string host = GURL(handler->main_frame_origin()).host(); - if (backend_->DidAllowMixedContentForHost(host) || - backend_->DidMarkHostAsBroken(host, handler->pid())) + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS) && + backend_->IsForceTLSEnabledForHost(host)) { + // We're supposed to block all mixed content for this host. + filter_policy = FilterPolicy::FILTER_ALL; + } else if (backend_->DidAllowMixedContentForHost(host) || + backend_->DidMarkHostAsBroken(host, handler->pid())) { + // Let the mixed content through. filter_policy = FilterPolicy::DONT_FILTER; - - if (filter_policy != FilterPolicy::DONT_FILTER) { + } else if (filter_policy != FilterPolicy::DONT_FILTER) { backend_->ShowMessageWithLink( l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT), l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT), diff --git a/chrome/browser/ssl/ssl_policy_backend.cc b/chrome/browser/ssl/ssl_policy_backend.cc index 9b1eed8..8852190 100644 --- a/chrome/browser/ssl/ssl_policy_backend.cc +++ b/chrome/browser/ssl/ssl_policy_backend.cc @@ -13,6 +13,7 @@ #include "chrome/common/notification_service.h" #include "grit/generated_resources.h" #include "grit/theme_resources.h" +#include "net/base/force_tls_state.h" using WebKit::WebConsoleMessage; @@ -67,7 +68,8 @@ class SSLInfoBarDelegate : public ConfirmInfoBarDelegate { SSLPolicyBackend::SSLPolicyBackend(NavigationController* controller) : controller_(controller), - ssl_host_state_(controller->profile()->GetSSLHostState()) { + ssl_host_state_(controller->profile()->GetSSLHostState()), + force_tls_state_(controller->profile()->GetForceTLSState()) { DCHECK(controller_); } @@ -159,6 +161,10 @@ bool SSLPolicyBackend::DidAllowMixedContentForHost( return ssl_host_state_->DidAllowMixedContentForHost(host); } +bool SSLPolicyBackend::IsForceTLSEnabledForHost(const std::string& host) const { + return force_tls_state_->IsEnabledForHost(host); +} + void SSLPolicyBackend::Reload() { controller_->Reload(true); } diff --git a/chrome/browser/ssl/ssl_policy_backend.h b/chrome/browser/ssl/ssl_policy_backend.h index f8a829c..2d84232 100644 --- a/chrome/browser/ssl/ssl_policy_backend.h +++ b/chrome/browser/ssl/ssl_policy_backend.h @@ -13,6 +13,9 @@ #include "net/base/x509_certificate.h" #include "webkit/api/public/WebConsoleMessage.h" +namespace net { +class ForceTLSState; +} class NavigationController; class SSLHostState; class Task; @@ -68,6 +71,9 @@ class SSLPolicyBackend { // Returns whether the specified host is allowed to show mixed content. bool DidAllowMixedContentForHost(const std::string& host) const; + // Returns whether ForceTLS is enabled for |host|. + bool IsForceTLSEnabledForHost(const std::string& host) const; + // Reloads the tab. void Reload(); @@ -112,6 +118,10 @@ class SSLPolicyBackend { // SSL state specific for each host. SSLHostState* ssl_host_state_; + // ForceTLS state. + // TODO(abarth): Consider combining with SSLHostState? + net::ForceTLSState* force_tls_state_; + // The list of messages that should be displayed (in info bars) when the page // currently loading had loaded. std::vector<SSLMessageInfo> pending_messages_; diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index f83e5e4..974d31d 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -90,6 +90,9 @@ class TestingProfile : public Profile { virtual SSLHostState* GetSSLHostState() { return NULL; } + virtual net::ForceTLSState* GetForceTLSState() { + return NULL; + } virtual HistoryService* GetHistoryService(ServiceAccessType access) { return history_service_.get(); } diff --git a/net/base/force_tls_state.cc b/net/base/force_tls_state.cc new file mode 100644 index 0000000..4be33f5 --- /dev/null +++ b/net/base/force_tls_state.cc @@ -0,0 +1,34 @@ +// 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/force_tls_state.h" + +#include "base/logging.h" +#include "googleurl/src/gurl.h" +#include "net/base/registry_controlled_domain.h" + +namespace net { + +ForceTLSState::ForceTLSState() { +} + +void ForceTLSState::DidReceiveHeader(const GURL& url, + const std::string& value) { + // TODO(abarth): Actually parse |value| once the spec settles down. + EnableHost(url.host()); +} + +void ForceTLSState::EnableHost(const std::string& host) { + // TODO(abarth): Canonicalize host. + AutoLock lock(lock_); + enabled_hosts_.insert(host); +} + +bool ForceTLSState::IsEnabledForHost(const std::string& host) { + // TODO(abarth): Canonicalize host. + AutoLock lock(lock_); + return enabled_hosts_.find(host) != enabled_hosts_.end(); +} + +} // namespace diff --git a/net/base/force_tls_state.h b/net/base/force_tls_state.h new file mode 100644 index 0000000..988e9c07 --- /dev/null +++ b/net/base/force_tls_state.h @@ -0,0 +1,50 @@ +// 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_FORCE_TLS_STATE_H_ +#define NET_BASE_FORCE_TLS_STATE_H_ + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "base/lock.h" + +class GURL; + +namespace net { + +// ForceTLSState +// +// Tracks which hosts have enabled ForceTLS. After a host enables ForceTLS, +// then we refuse to talk to the host over HTTP, treat all certificate errors as +// fatal, and refuses to load any mixed content. +// +class ForceTLSState { + public: + ForceTLSState(); + + // 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 ForceTLS for |host|. + void EnableHost(const std::string& host); + + // Returns whether |host| has had ForceTLS enabled. + bool IsEnabledForHost(const std::string& host); + + private: + // The set of hosts that have enabled ForceTLS. + std::set<std::string> enabled_hosts_; + + // Protect access to our data members with this lock. + Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(ForceTLSState); +}; + +} // namespace net + +#endif // NET_BASE_FORCE_TLS_STATE_H_ diff --git a/net/net.gyp b/net/net.gyp index 8c11266..778f2da 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -75,6 +75,8 @@ 'base/file_stream_win.cc', 'base/filter.cc', 'base/filter.h', + 'base/force_tls_state.cc', + 'base/force_tls_state.h', 'base/gzip_filter.cc', 'base/gzip_filter.h', 'base/gzip_header.cc', diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 29735ac..8e32c97 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h @@ -17,6 +17,7 @@ namespace net { class CookieMonster; +class ForceTLSState; class FtpTransactionFactory; class HttpTransactionFactory; class ProxyService; @@ -30,7 +31,8 @@ class URLRequestContext : : proxy_service_(NULL), http_transaction_factory_(NULL), ftp_transaction_factory_(NULL), - cookie_store_(NULL) { + cookie_store_(NULL), + force_tls_state_(NULL) { } // Get the proxy service for this context. @@ -54,6 +56,8 @@ class URLRequestContext : // Gets the cookie policy for this context. net::CookiePolicy* cookie_policy() { return &cookie_policy_; } + net::ForceTLSState* force_tls_state() { return force_tls_state_; } + // Gets the FTP authentication cache for this context. net::FtpAuthCache* ftp_auth_cache() { return &ftp_auth_cache_; } @@ -89,6 +93,7 @@ class URLRequestContext : net::FtpTransactionFactory* ftp_transaction_factory_; net::CookieMonster* cookie_store_; net::CookiePolicy cookie_policy_; + net::ForceTLSState* force_tls_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 a86edbd..eff2344 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -12,8 +12,10 @@ #include "base/message_loop.h" #include "base/rand_util.h" #include "base/string_util.h" +#include "net/base/cert_status_flags.h" #include "net/base/cookie_monster.h" #include "net/base/filter.h" +#include "net/base/force_tls_state.h" #include "net/base/load_flags.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -47,7 +49,10 @@ URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request, // network request. static const bool kForceHTTPS = CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS); - if (kForceHTTPS && scheme != "https") + if (kForceHTTPS && scheme == "http" && + request->context()->force_tls_state() && + request->context()->force_tls_state()->IsEnabledForHost( + request->url().host())) return new URLRequestErrorJob(request, net::ERR_DISALLOWED_URL_SCHEME); return new URLRequestHttpJob(request); @@ -441,9 +446,7 @@ void URLRequestHttpJob::OnStartCompleted(int result) { if (result == net::OK) { NotifyHeadersComplete(); - } else if (net::IsCertificateError(result) && - !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kForceHTTPS)) { + } else if (ShouldTreatAsCertificateError(result)) { // We encountered an SSL certificate error. Ask our delegate to decide // what we should do. // TODO(wtc): also pass ssl_info.cert_status, or just pass the whole @@ -470,6 +473,22 @@ void URLRequestHttpJob::OnReadCompleted(int result) { NotifyReadComplete(result); } +bool URLRequestHttpJob::ShouldTreatAsCertificateError(int result) { + if (!net::IsCertificateError(result)) + return false; + + // Hide the fancy processing behind a command line switch. + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS)) + return true; + + // Check whether our context is using ForceTLS. + if (!context_->force_tls_state()) + return true; + + return !context_->force_tls_state()->IsEnabledForHost( + request_info_.url.host()); +} + void URLRequestHttpJob::NotifyHeadersComplete() { DCHECK(!response_info_); @@ -494,6 +513,8 @@ void URLRequestHttpJob::NotifyHeadersComplete() { } } + ProcessForceTLSHeader(); + if (SdchManager::Global() && SdchManager::Global()->IsInSupportedDomain(request_->url())) { static const std::string name = "Get-Dictionary"; @@ -657,3 +678,31 @@ void URLRequestHttpJob::FetchResponseCookies() { while (response_info_->headers->EnumerateHeader(&iter, name, &value)) response_cookies_.push_back(value); } + + +void URLRequestHttpJob::ProcessForceTLSHeader() { + DCHECK(response_info_); + + // Hide processing behind a command line flag. + if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS)) + return; + + // Only process X-Force-TLS from HTTPS responses. + if (request_info_.url.scheme() != "https") + return; + + // Only process X-Force-TLS from responses with valid certificates. + if (response_info_->ssl_info.cert_status & net::CERT_STATUS_ALL_ERRORS) + return; + + URLRequestContext* ctx = request_->context(); + if (!ctx || !ctx->force_tls_state()) + return; + + std::string name = "X-Force-TLS"; + std::string value; + + void* iter = NULL; + while (response_info_->headers->EnumerateHeader(&iter, name, &value)) + ctx->force_tls_state()->DidReceiveHeader(request_info_.url, value); +} diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index a946f62..7853f83 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -67,9 +67,14 @@ class URLRequestHttpJob : public URLRequestJob { std::string AssembleRequestCookies(); void FetchResponseCookies(); + // Process the X-Force-TLS header, if one exists. + void ProcessForceTLSHeader(); + void OnStartCompleted(int result); void OnReadCompleted(int result); + bool ShouldTreatAsCertificateError(int result); + void RestartTransactionWithAuth(const std::wstring& username, const std::wstring& password); |