OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/ssl/ssl_error_handler.h" |
| 6 |
| 7 #include "base/metrics/field_trial.h" |
| 8 #include "base/metrics/histogram.h" |
| 9 #include "base/time/time.h" |
| 10 #include "chrome/browser/profiles/profile.h" |
| 11 #include "chrome/browser/ssl/ssl_blocking_page.h" |
| 12 #include "content/public/browser/notification_service.h" |
| 13 #include "content/public/browser/notification_source.h" |
| 14 #include "content/public/browser/web_contents.h" |
| 15 |
| 16 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 17 #include "chrome/browser/captive_portal/captive_portal_service.h" |
| 18 #include "chrome/browser/captive_portal/captive_portal_service_factory.h" |
| 19 #include "chrome/browser/captive_portal/captive_portal_tab_helper.h" |
| 20 #include "chrome/browser/ssl/captive_portal_blocking_page.h" |
| 21 #endif |
| 22 |
| 23 namespace { |
| 24 |
| 25 // The type of the delay before displaying the SSL interstitial. This can be |
| 26 // changed in tests. |
| 27 SSLErrorHandler::InterstitialDelayType g_interstitial_delay_type = |
| 28 SSLErrorHandler::NORMAL; |
| 29 |
| 30 // Callback to call when the interstitial timer is started. Used for testing. |
| 31 SSLErrorHandler::TimerStartedCallback* g_timer_started_callback = nullptr; |
| 32 |
| 33 // Events for UMA. |
| 34 enum SSLErrorHandlerEvent { |
| 35 HANDLE_ALL, |
| 36 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE, |
| 37 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE, |
| 38 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE, |
| 39 SHOW_SSL_INTERSTITIAL_OVERRIDABLE, |
| 40 SSL_ERROR_HANDLER_EVENT_COUNT |
| 41 }; |
| 42 |
| 43 void RecordUMA(SSLErrorHandlerEvent event) { |
| 44 UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_handler", |
| 45 event, |
| 46 SSL_ERROR_HANDLER_EVENT_COUNT); |
| 47 } |
| 48 |
| 49 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 50 // The delay before displaying the SSL interstitial for cert errors. |
| 51 // - If a "captive portal detected" result arrives in this many seconds, |
| 52 // a captive portal interstitial is displayed. |
| 53 // - Otherwise, an SSL interstitial is displayed. |
| 54 const int kDefaultInterstitialDisplayDelayInSeconds = 2; |
| 55 |
| 56 base::TimeDelta GetInterstitialDisplayDelay( |
| 57 SSLErrorHandler::InterstitialDelayType delay) { |
| 58 switch (delay) { |
| 59 case SSLErrorHandler::LONG: |
| 60 return base::TimeDelta::FromHours(1); |
| 61 |
| 62 case SSLErrorHandler::NONE: |
| 63 return base::TimeDelta(); |
| 64 |
| 65 case SSLErrorHandler::NORMAL: |
| 66 return base::TimeDelta::FromSeconds( |
| 67 kDefaultInterstitialDisplayDelayInSeconds); |
| 68 |
| 69 default: |
| 70 NOTREACHED(); |
| 71 } |
| 72 return base::TimeDelta(); |
| 73 } |
| 74 #endif |
| 75 |
| 76 } // namespace |
| 77 |
| 78 DEFINE_WEB_CONTENTS_USER_DATA_KEY(SSLErrorHandler); |
| 79 |
| 80 void SSLErrorHandler::HandleSSLError( |
| 81 content::WebContents* web_contents, |
| 82 int cert_error, |
| 83 const net::SSLInfo& ssl_info, |
| 84 const GURL& request_url, |
| 85 int options_mask, |
| 86 const base::Callback<void(bool)>& callback) { |
| 87 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 88 CaptivePortalTabHelper* captive_portal_tab_helper = |
| 89 CaptivePortalTabHelper::FromWebContents(web_contents); |
| 90 if (captive_portal_tab_helper) { |
| 91 captive_portal_tab_helper->OnSSLCertError(ssl_info); |
| 92 } |
| 93 #endif |
| 94 DCHECK(!FromWebContents(web_contents)); |
| 95 web_contents->SetUserData(UserDataKey(), |
| 96 new SSLErrorHandler(web_contents, cert_error, |
| 97 ssl_info, request_url, |
| 98 options_mask, callback)); |
| 99 |
| 100 SSLErrorHandler* error_handler = |
| 101 SSLErrorHandler::FromWebContents(web_contents); |
| 102 error_handler->StartHandlingError(); |
| 103 } |
| 104 |
| 105 // static |
| 106 void SSLErrorHandler::SetInterstitialDelayTypeForTest( |
| 107 SSLErrorHandler::InterstitialDelayType delay) { |
| 108 g_interstitial_delay_type = delay; |
| 109 } |
| 110 |
| 111 // static |
| 112 void SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest( |
| 113 TimerStartedCallback* callback) { |
| 114 DCHECK(!callback || !callback->is_null()); |
| 115 g_timer_started_callback = callback; |
| 116 } |
| 117 |
| 118 SSLErrorHandler::SSLErrorHandler(content::WebContents* web_contents, |
| 119 int cert_error, |
| 120 const net::SSLInfo& ssl_info, |
| 121 const GURL& request_url, |
| 122 int options_mask, |
| 123 const base::Callback<void(bool)>& callback) |
| 124 : web_contents_(web_contents), |
| 125 cert_error_(cert_error), |
| 126 ssl_info_(ssl_info), |
| 127 request_url_(request_url), |
| 128 options_mask_(options_mask), |
| 129 callback_(callback) { |
| 130 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 131 Profile* profile = Profile::FromBrowserContext( |
| 132 web_contents->GetBrowserContext()); |
| 133 registrar_.Add(this, |
| 134 chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT, |
| 135 content::Source<Profile>(profile)); |
| 136 #endif |
| 137 } |
| 138 |
| 139 SSLErrorHandler::~SSLErrorHandler() { |
| 140 } |
| 141 |
| 142 void SSLErrorHandler::StartHandlingError() { |
| 143 RecordUMA(HANDLE_ALL); |
| 144 |
| 145 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 146 CheckForCaptivePortal(); |
| 147 timer_.Start(FROM_HERE, |
| 148 GetInterstitialDisplayDelay(g_interstitial_delay_type), |
| 149 this, &SSLErrorHandler::OnTimerExpired); |
| 150 if (g_timer_started_callback) |
| 151 g_timer_started_callback->Run(web_contents_); |
| 152 #else |
| 153 // Display an SSL interstitial. |
| 154 ShowSSLInterstitial(); |
| 155 #endif |
| 156 } |
| 157 |
| 158 void SSLErrorHandler::OnTimerExpired() { |
| 159 ShowSSLInterstitial(); |
| 160 } |
| 161 |
| 162 void SSLErrorHandler::CheckForCaptivePortal() { |
| 163 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 164 Profile* profile = Profile::FromBrowserContext( |
| 165 web_contents_->GetBrowserContext()); |
| 166 CaptivePortalService* captive_portal_service = |
| 167 CaptivePortalServiceFactory::GetForProfile(profile); |
| 168 captive_portal_service->DetectCaptivePortal(); |
| 169 #else |
| 170 NOTREACHED(); |
| 171 #endif |
| 172 } |
| 173 |
| 174 void SSLErrorHandler::ShowCaptivePortalInterstitial() { |
| 175 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 176 // Show captive portal blocking page. The interstitial owns the blocking page. |
| 177 RecordUMA(SSLBlockingPage::IsOptionsOverridable(options_mask_) ? |
| 178 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_OVERRIDABLE : |
| 179 SHOW_CAPTIVE_PORTAL_INTERSTITIAL_NONOVERRIDABLE); |
| 180 (new CaptivePortalBlockingPage(web_contents_, request_url_, |
| 181 callback_))->Show(); |
| 182 // Once an interstitial is displayed, no need to keep the handler around. |
| 183 // This is the equivalent of "delete this". |
| 184 web_contents_->RemoveUserData(UserDataKey()); |
| 185 #else |
| 186 NOTREACHED(); |
| 187 #endif |
| 188 } |
| 189 |
| 190 void SSLErrorHandler::ShowSSLInterstitial() { |
| 191 // Show SSL blocking page. The interstitial owns the blocking page. |
| 192 RecordUMA(SSLBlockingPage::IsOptionsOverridable(options_mask_) ? |
| 193 SHOW_SSL_INTERSTITIAL_OVERRIDABLE : |
| 194 SHOW_SSL_INTERSTITIAL_NONOVERRIDABLE); |
| 195 (new SSLBlockingPage(web_contents_, cert_error_, ssl_info_, request_url_, |
| 196 options_mask_, callback_))->Show(); |
| 197 // Once an interstitial is displayed, no need to keep the handler around. |
| 198 // This is the equivalent of "delete this". |
| 199 web_contents_->RemoveUserData(UserDataKey()); |
| 200 } |
| 201 |
| 202 void SSLErrorHandler::Observe( |
| 203 int type, |
| 204 const content::NotificationSource& source, |
| 205 const content::NotificationDetails& details) { |
| 206 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION) |
| 207 if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) { |
| 208 timer_.Stop(); |
| 209 CaptivePortalService::Results* results = |
| 210 content::Details<CaptivePortalService::Results>(details).ptr(); |
| 211 if (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL) |
| 212 ShowCaptivePortalInterstitial(); |
| 213 else |
| 214 ShowSSLInterstitial(); |
| 215 } |
| 216 #endif |
| 217 } |
OLD | NEW |