| Index: chrome/browser/ssl/ssl_error_handler.cc
|
| diff --git a/chrome/browser/ssl/ssl_error_handler.cc b/chrome/browser/ssl/ssl_error_handler.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..552902cb187deaaccc96ba88a8ff6447041644f0
|
| --- /dev/null
|
| +++ b/chrome/browser/ssl/ssl_error_handler.cc
|
| @@ -0,0 +1,217 @@
|
| +// Copyright 2014 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 "chrome/browser/ssl/ssl_error_handler.h"
|
| +
|
| +#include "base/metrics/field_trial.h"
|
| +#include "base/metrics/histogram.h"
|
| +#include "base/time/time.h"
|
| +#include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/ssl/ssl_blocking_page.h"
|
| +#include "content/public/browser/notification_service.h"
|
| +#include "content/public/browser/notification_source.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| +#include "chrome/browser/captive_portal/captive_portal_service.h"
|
| +#include "chrome/browser/captive_portal/captive_portal_service_factory.h"
|
| +#include "chrome/browser/captive_portal/captive_portal_tab_helper.h"
|
| +#include "chrome/browser/ssl/captive_portal_blocking_page.h"
|
| +#endif
|
| +
|
| +namespace {
|
| +
|
| +// The type of the delay before displaying the SSL interstitial. This can be
|
| +// changed in tests.
|
| +SSLErrorHandler::InterstitialDelayType g_interstitial_delay_type =
|
| + SSLErrorHandler::NORMAL;
|
| +
|
| +// Callback to call when the interstitial timer is started. Used for testing.
|
| +SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr;
|
| +
|
| +// Events for UMA.
|
| +enum SSLErrorHandlerEvent {
|
| + HANDLE_ALL,
|
| + SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE,
|
| + SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE,
|
| + SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE,
|
| + SHOW_SSL_INTERSTITIAL_OVERRIDABLE,
|
| + SSL_ERROR_HANDLER_EVENT_COUNT
|
| +};
|
| +
|
| +void RecordUMA(SSLErrorHandlerEvent event) {
|
| + UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler",
|
| + event,
|
| + SSL_ERROR_HANDLER_EVENT_COUNT);
|
| +}
|
| +
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| +// The delay before displaying the SSL interstitial for cert errors.
|
| +// - If a "captive portal detected" result arrives in this many seconds,
|
| +// a captive portal interstitial is displayed.
|
| +// - Otherwise, an SSL interstitial is displayed.
|
| +const int kDefaultInterstitialDisplayDelayInSeconds = 2;
|
| +
|
| +base::TimeDelta GetInterstitialDisplayDelay(
|
| + SSLErrorHandler::InterstitialDelayType delay) {
|
| + switch (delay) {
|
| + case SSLErrorHandler::LONG:
|
| + return base::TimeDelta::FromHours(1);
|
| +
|
| + case SSLErrorHandler::NONE:
|
| + return base::TimeDelta();
|
| +
|
| + case SSLErrorHandler::NORMAL:
|
| + return base::TimeDelta::FromSeconds(
|
| + kDefaultInterstitialDisplayDelayInSeconds);
|
| +
|
| + default:
|
| + NOTREACHED();
|
| + }
|
| + return base::TimeDelta();
|
| +}
|
| +#endif
|
| +
|
| +} // namespace
|
| +
|
| +DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler);
|
| +
|
| +void SSLErrorHandler::HandleSSLError(
|
| + content::WebContents* web_contents,
|
| + int cert_error,
|
| + const net::SSLInfo& ssl_info,
|
| + const GURL& request_url,
|
| + int options_mask,
|
| + const base::Callback<void(bool)>& callback) {
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + CaptivePortalTabHelper* captive_portal_tab_helper =
|
| + CaptivePortalTabHelper::FromWebContents(web_contents);
|
| + if (captive_portal_tab_helper) {
|
| + captive_portal_tab_helper->OnSSLCertError(ssl_info);
|
| + }
|
| +#endif
|
| + DCHECK(!FromWebContents(web_contents));
|
| + web_contents->SetUserData(UserDataKey(),
|
| + new SSLErrorHandler(web_contents, cert_error,
|
| + ssl_info, request_url,
|
| + options_mask, callback));
|
| +
|
| + SSLErrorHandler* error_handler =
|
| + SSLErrorHandler::FromWebContents(web_contents);
|
| + error_handler->StartHandlingError();
|
| +}
|
| +
|
| +// static
|
| +void SSLErrorHandler::SetInterstitialDelayTypeForTest(
|
| + SSLErrorHandler::InterstitialDelayType delay) {
|
| + g_interstitial_delay_type = delay;
|
| +}
|
| +
|
| +// static
|
| +void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(
|
| + TimerStartedCallback* callback) {
|
| + DCHECK(!callback || !callback->is_null());
|
| + g_timer_started_callback = callback;
|
| +}
|
| +
|
| +SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents,
|
| + int cert_error,
|
| + const net::SSLInfo& ssl_info,
|
| + const GURL& request_url,
|
| + int options_mask,
|
| + const base::Callback<void(bool)>& callback)
|
| + : web_contents_(web_contents),
|
| + cert_error_(cert_error),
|
| + ssl_info_(ssl_info),
|
| + request_url_(request_url),
|
| + options_mask_(options_mask),
|
| + callback_(callback) {
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + Profile* profile = Profile::FromBrowserContext(
|
| + web_contents->GetBrowserContext());
|
| + registrar_.Add(this,
|
| + chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
|
| + content::Source<Profile>(profile));
|
| +#endif
|
| +}
|
| +
|
| +SSLErrorHandler::~SSLErrorHandler() {
|
| +}
|
| +
|
| +void SSLErrorHandler::StartHandlingError() {
|
| + RecordUMA(HANDLE_ALL);
|
| +
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + CheckForCaptivePortal();
|
| + timer_.Start(FROM_HERE,
|
| + GetInterstitialDisplayDelay(g_interstitial_delay_type),
|
| + this, &SSLErrorHandler::OnTimerExpired);
|
| + if (g_timer_started_callback)
|
| + g_timer_started_callback->Run(web_contents_);
|
| +#else
|
| + // Display an SSL interstitial.
|
| + ShowSSLInterstitial();
|
| +#endif
|
| +}
|
| +
|
| +void SSLErrorHandler::OnTimerExpired() {
|
| + ShowSSLInterstitial();
|
| +}
|
| +
|
| +void SSLErrorHandler::CheckForCaptivePortal() {
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + Profile* profile = Profile::FromBrowserContext(
|
| + web_contents_->GetBrowserContext());
|
| + CaptivePortalService* captive_portal_service =
|
| + CaptivePortalServiceFactory::GetForProfile(profile);
|
| + captive_portal_service->DetectCaptivePortal();
|
| +#else
|
| + NOTREACHED();
|
| +#endif
|
| +}
|
| +
|
| +void SSLErrorHandler::ShowCaptivePortalInterstitial() {
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + // Show captive portal blocking page. The interstitial owns the blocking page.
|
| + RecordUMA(SSLBlockingPage::IsOptionsOverridable(options_mask_) ?
|
| + SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE :
|
| + SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE);
|
| + (new CaptivePortalBlockingPage(web_contents_, request_url_,
|
| + callback_))->Show();
|
| + // Once an interstitial is displayed, no need to keep the handler around.
|
| + // This is the equivalent of "delete this".
|
| + web_contents_->RemoveUserData(UserDataKey());
|
| +#else
|
| + NOTREACHED();
|
| +#endif
|
| +}
|
| +
|
| +void SSLErrorHandler::ShowSSLInterstitial() {
|
| + // Show SSL blocking page. The interstitial owns the blocking page.
|
| + RecordUMA(SSLBlockingPage::IsOptionsOverridable(options_mask_) ?
|
| + SHOW_SSL_INTERSTITIAL_OVERRIDABLE :
|
| + SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE);
|
| + (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_,
|
| + options_mask_, callback_))->Show();
|
| + // Once an interstitial is displayed, no need to keep the handler around.
|
| + // This is the equivalent of "delete this".
|
| + web_contents_->RemoveUserData(UserDataKey());
|
| +}
|
| +
|
| +void SSLErrorHandler::Observe(
|
| + int type,
|
| + const content::NotificationSource& source,
|
| + const content::NotificationDetails& details) {
|
| +#if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
|
| + if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
|
| + timer_.Stop();
|
| + CaptivePortalService::Results* results =
|
| + content::Details<CaptivePortalService::Results>(details).ptr();
|
| + if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL)
|
| + ShowCaptivePortalInterstitial();
|
| + else
|
| + ShowSSLInterstitial();
|
| + }
|
| +#endif
|
| +}
|
|
|