Home | History | Annotate | Download | only in ssl
      1 // Copyright (c) 2012 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_blocking_page.h"
      6 
      7 #include "base/command_line.h"
      8 #include "base/i18n/rtl.h"
      9 #include "base/metrics/field_trial.h"
     10 #include "base/metrics/histogram.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/string_piece.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/chrome_notification_types.h"
     17 #include "chrome/browser/history/history_service_factory.h"
     18 #include "chrome/browser/profiles/profile.h"
     19 #include "chrome/browser/renderer_preferences_util.h"
     20 #include "chrome/browser/ssl/ssl_error_info.h"
     21 #include "chrome/common/chrome_switches.h"
     22 #include "content/public/browser/cert_store.h"
     23 #include "content/public/browser/interstitial_page.h"
     24 #include "content/public/browser/navigation_controller.h"
     25 #include "content/public/browser/navigation_entry.h"
     26 #include "content/public/browser/notification_service.h"
     27 #include "content/public/browser/notification_types.h"
     28 #include "content/public/browser/render_process_host.h"
     29 #include "content/public/browser/render_view_host.h"
     30 #include "content/public/browser/web_contents.h"
     31 #include "content/public/common/ssl_status.h"
     32 #include "grit/app_locale_settings.h"
     33 #include "grit/browser_resources.h"
     34 #include "grit/generated_resources.h"
     35 #include "net/base/hash_value.h"
     36 #include "net/base/net_errors.h"
     37 #include "net/base/net_util.h"
     38 #include "ui/base/l10n/l10n_util.h"
     39 #include "ui/base/resource/resource_bundle.h"
     40 #include "ui/base/webui/jstemplate_builder.h"
     41 #include "ui/base/webui/web_ui_util.h"
     42 
     43 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
     44 #include "chrome/browser/captive_portal/captive_portal_service.h"
     45 #include "chrome/browser/captive_portal/captive_portal_service_factory.h"
     46 #endif
     47 
     48 #if defined(OS_WIN)
     49 #include "base/win/windows_version.h"
     50 #endif
     51 
     52 using base::ASCIIToUTF16;
     53 using base::TimeTicks;
     54 using content::InterstitialPage;
     55 using content::NavigationController;
     56 using content::NavigationEntry;
     57 
     58 namespace {
     59 
     60 // Events for UMA. Do not reorder or change!
     61 enum SSLBlockingPageEvent {
     62   SHOW_ALL,
     63   SHOW_OVERRIDABLE,
     64   PROCEED_OVERRIDABLE,
     65   PROCEED_NAME,
     66   PROCEED_DATE,
     67   PROCEED_AUTHORITY,
     68   DONT_PROCEED_OVERRIDABLE,
     69   DONT_PROCEED_NAME,
     70   DONT_PROCEED_DATE,
     71   DONT_PROCEED_AUTHORITY,
     72   MORE,
     73   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
     74   SHOW_INTERNAL_HOSTNAME,
     75   PROCEED_INTERNAL_HOSTNAME,
     76   SHOW_NEW_SITE,
     77   PROCEED_NEW_SITE,
     78   PROCEED_MANUAL_NONOVERRIDABLE,
     79   CAPTIVE_PORTAL_DETECTION_ENABLED,
     80   CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
     81   CAPTIVE_PORTAL_PROBE_COMPLETED,
     82   CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
     83   CAPTIVE_PORTAL_NO_RESPONSE,
     84   CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
     85   CAPTIVE_PORTAL_DETECTED,
     86   CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
     87   UNUSED_BLOCKING_PAGE_EVENT,
     88 };
     89 
     90 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
     91   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
     92                             event,
     93                             UNUSED_BLOCKING_PAGE_EVENT);
     94 }
     95 
     96 void RecordSSLBlockingPageDetailedStats(
     97     bool proceed,
     98     int cert_error,
     99     bool overridable,
    100     bool internal,
    101     int num_visits,
    102     bool captive_portal_detection_enabled,
    103     bool captive_portal_probe_completed,
    104     bool captive_portal_no_response,
    105     bool captive_portal_detected) {
    106   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
    107       SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
    108 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
    109   if (captive_portal_detection_enabled)
    110     RecordSSLBlockingPageEventStats(
    111         overridable ?
    112         CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE :
    113         CAPTIVE_PORTAL_DETECTION_ENABLED);
    114   if (captive_portal_probe_completed)
    115     RecordSSLBlockingPageEventStats(
    116         overridable ?
    117         CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE :
    118         CAPTIVE_PORTAL_PROBE_COMPLETED);
    119   // Log only one of portal detected and no response results.
    120   if (captive_portal_detected)
    121     RecordSSLBlockingPageEventStats(
    122         overridable ?
    123         CAPTIVE_PORTAL_DETECTED_OVERRIDABLE :
    124         CAPTIVE_PORTAL_DETECTED);
    125   else if (captive_portal_no_response)
    126     RecordSSLBlockingPageEventStats(
    127         overridable ?
    128         CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE :
    129         CAPTIVE_PORTAL_NO_RESPONSE);
    130 #endif
    131   if (!overridable) {
    132     if (proceed) {
    133       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
    134     }
    135     // Overridable is false if the user didn't have any option except to turn
    136     // back. If that's the case, don't record some of the metrics.
    137     return;
    138   }
    139   if (num_visits == 0)
    140     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
    141   if (proceed) {
    142     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
    143     if (internal)
    144       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
    145     if (num_visits == 0)
    146       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
    147   } else if (!proceed) {
    148     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
    149   }
    150   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
    151   switch (type) {
    152     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
    153       if (proceed)
    154         RecordSSLBlockingPageEventStats(PROCEED_NAME);
    155       else
    156         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
    157       break;
    158     }
    159     case SSLErrorInfo::CERT_DATE_INVALID: {
    160       if (proceed)
    161         RecordSSLBlockingPageEventStats(PROCEED_DATE);
    162       else
    163         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
    164       break;
    165     }
    166     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
    167       if (proceed)
    168         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
    169       else
    170         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
    171       break;
    172     }
    173     default: {
    174       break;
    175     }
    176   }
    177 }
    178 
    179 }  // namespace
    180 
    181 // Note that we always create a navigation entry with SSL errors.
    182 // No error happening loading a sub-resource triggers an interstitial so far.
    183 SSLBlockingPage::SSLBlockingPage(
    184     content::WebContents* web_contents,
    185     int cert_error,
    186     const net::SSLInfo& ssl_info,
    187     const GURL& request_url,
    188     bool overridable,
    189     bool strict_enforcement,
    190     const base::Callback<void(bool)>& callback)
    191     : callback_(callback),
    192       web_contents_(web_contents),
    193       cert_error_(cert_error),
    194       ssl_info_(ssl_info),
    195       request_url_(request_url),
    196       overridable_(overridable),
    197       strict_enforcement_(strict_enforcement),
    198       internal_(false),
    199       num_visits_(-1),
    200       captive_portal_detection_enabled_(false),
    201       captive_portal_probe_completed_(false),
    202       captive_portal_no_response_(false),
    203       captive_portal_detected_(false) {
    204   Profile* profile = Profile::FromBrowserContext(
    205       web_contents->GetBrowserContext());
    206   // For UMA stats.
    207   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
    208     internal_ = true;
    209   RecordSSLBlockingPageEventStats(SHOW_ALL);
    210   if (overridable_ && !strict_enforcement_) {
    211     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
    212     if (internal_)
    213       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
    214     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
    215         profile, Profile::EXPLICIT_ACCESS);
    216     if (history_service) {
    217       history_service->GetVisibleVisitCountToHost(
    218           request_url_,
    219           &request_consumer_,
    220           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
    221                     base::Unretained(this)));
    222     }
    223   }
    224 
    225 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
    226   CaptivePortalService* captive_portal_service =
    227       CaptivePortalServiceFactory::GetForProfile(profile);
    228   captive_portal_detection_enabled_ = captive_portal_service ->enabled();
    229   captive_portal_service ->DetectCaptivePortal();
    230   registrar_.Add(this,
    231                  chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
    232                  content::Source<Profile>(profile));
    233 #endif
    234 
    235   interstitial_page_ = InterstitialPage::Create(
    236       web_contents_, true, request_url, this);
    237   interstitial_page_->Show();
    238 }
    239 
    240 SSLBlockingPage::~SSLBlockingPage() {
    241   if (!callback_.is_null()) {
    242     RecordSSLBlockingPageDetailedStats(false,
    243                                        cert_error_,
    244                                        overridable_ && !strict_enforcement_,
    245                                        internal_,
    246                                        num_visits_,
    247                                        captive_portal_detection_enabled_,
    248                                        captive_portal_probe_completed_,
    249                                        captive_portal_no_response_,
    250                                        captive_portal_detected_);
    251     // The page is closed without the user having chosen what to do, default to
    252     // deny.
    253     NotifyDenyCertificate();
    254   }
    255 }
    256 
    257 std::string SSLBlockingPage::GetHTMLContents() {
    258   if (CommandLine::ForCurrentProcess()->HasSwitch(
    259           switches::kSSLInterstitialVersionV1) ||
    260       base::FieldTrialList::FindFullName("SSLInterstitialVersion") == "V1") {
    261     return GetHTMLContentsV1();
    262   }
    263   return GetHTMLContentsV2();
    264 }
    265 
    266 std::string SSLBlockingPage::GetHTMLContentsV1() {
    267   base::DictionaryValue strings;
    268   int resource_id;
    269   if (overridable_ && !strict_enforcement_) {
    270     // Let's build the overridable error page.
    271     SSLErrorInfo error_info =
    272         SSLErrorInfo::CreateError(
    273             SSLErrorInfo::NetErrorToErrorType(cert_error_),
    274             ssl_info_.cert.get(),
    275             request_url_);
    276 
    277     resource_id = IDR_SSL_ROAD_BLOCK_HTML;
    278     strings.SetString("headLine", error_info.title());
    279     strings.SetString("description", error_info.details());
    280     strings.SetString("moreInfoTitle",
    281         l10n_util::GetStringUTF16(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
    282     SetExtraInfo(&strings, error_info.extra_information());
    283 
    284     strings.SetString(
    285         "exit", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_EXIT));
    286     strings.SetString(
    287         "title", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_TITLE));
    288     strings.SetString(
    289         "proceed", l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_PAGE_PROCEED));
    290     strings.SetString(
    291         "reasonForNotProceeding", l10n_util::GetStringUTF16(
    292             IDS_SSL_OVERRIDABLE_PAGE_SHOULD_NOT_PROCEED));
    293     strings.SetString("errorType", "overridable");
    294     strings.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
    295   } else {
    296     // Let's build the blocking error page.
    297     resource_id = IDR_SSL_BLOCKING_HTML;
    298 
    299     // Strings that are not dependent on the URL.
    300     strings.SetString(
    301         "title", l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TITLE));
    302     strings.SetString(
    303         "reloadMsg", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_RELOAD));
    304     strings.SetString(
    305         "more", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_MORE));
    306     strings.SetString(
    307         "less", l10n_util::GetStringUTF16(IDS_ERRORPAGES_BUTTON_LESS));
    308     strings.SetString(
    309         "moreTitle",
    310         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TITLE));
    311     strings.SetString(
    312         "techTitle",
    313         l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_TECH_TITLE));
    314 
    315     // Strings that are dependent on the URL.
    316     base::string16 url(ASCIIToUTF16(request_url_.host()));
    317     bool rtl = base::i18n::IsRTL();
    318     strings.SetString("textDirection", rtl ? "rtl" : "ltr");
    319     if (rtl)
    320       base::i18n::WrapStringWithLTRFormatting(&url);
    321     strings.SetString(
    322         "headline", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HEADLINE,
    323                                                url.c_str()));
    324     strings.SetString(
    325         "message", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_BODY_TEXT,
    326                                               url.c_str()));
    327     strings.SetString(
    328         "moreMessage",
    329         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_MORE_TEXT,
    330                                    url.c_str()));
    331     strings.SetString("reloadUrl", request_url_.spec());
    332 
    333     // Strings that are dependent on the error type.
    334     SSLErrorInfo::ErrorType type =
    335         SSLErrorInfo::NetErrorToErrorType(cert_error_);
    336     base::string16 errorType;
    337     if (type == SSLErrorInfo::CERT_REVOKED) {
    338       errorType = base::string16(ASCIIToUTF16("Key revocation"));
    339       strings.SetString(
    340           "failure",
    341           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_REVOKED));
    342     } else if (type == SSLErrorInfo::CERT_INVALID) {
    343       errorType = base::string16(ASCIIToUTF16("Malformed certificate"));
    344       strings.SetString(
    345           "failure",
    346           l10n_util::GetStringUTF16(IDS_SSL_BLOCKING_PAGE_FORMATTED));
    347     } else if (type == SSLErrorInfo::CERT_PINNED_KEY_MISSING) {
    348       errorType = base::string16(ASCIIToUTF16("Certificate pinning failure"));
    349       strings.SetString(
    350           "failure",
    351           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_PINNING,
    352                                      url.c_str()));
    353     } else if (type == SSLErrorInfo::CERT_WEAK_KEY_DH) {
    354       errorType = base::string16(ASCIIToUTF16("Weak DH public key"));
    355       strings.SetString(
    356           "failure",
    357           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_WEAK_DH,
    358                                      url.c_str()));
    359     } else {
    360       // HSTS failure.
    361       errorType = base::string16(ASCIIToUTF16("HSTS failure"));
    362       strings.SetString(
    363           "failure",
    364           l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HSTS, url.c_str()));
    365     }
    366     if (rtl)
    367       base::i18n::WrapStringWithLTRFormatting(&errorType);
    368     strings.SetString(
    369         "errorType", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ERROR,
    370                                                 errorType.c_str()));
    371 
    372     // Strings that display the invalid cert.
    373     base::string16 subject(
    374         ASCIIToUTF16(ssl_info_.cert->subject().GetDisplayName()));
    375     base::string16 issuer(
    376         ASCIIToUTF16(ssl_info_.cert->issuer().GetDisplayName()));
    377     std::string hashes;
    378     for (std::vector<net::HashValue>::const_iterator it =
    379             ssl_info_.public_key_hashes.begin();
    380          it != ssl_info_.public_key_hashes.end();
    381          ++it) {
    382       base::StringAppendF(&hashes, "%s ", it->ToString().c_str());
    383     }
    384     base::string16 fingerprint(ASCIIToUTF16(hashes));
    385     if (rtl) {
    386       // These are always going to be LTR.
    387       base::i18n::WrapStringWithLTRFormatting(&subject);
    388       base::i18n::WrapStringWithLTRFormatting(&issuer);
    389       base::i18n::WrapStringWithLTRFormatting(&fingerprint);
    390     }
    391     strings.SetString(
    392         "subject", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_SUBJECT,
    393                                               subject.c_str()));
    394     strings.SetString(
    395         "issuer", l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_ISSUER,
    396                                              issuer.c_str()));
    397     strings.SetString(
    398         "fingerprint",
    399         l10n_util::GetStringFUTF16(IDS_SSL_BLOCKING_PAGE_HASHES,
    400                                    fingerprint.c_str()));
    401   }
    402 
    403   base::StringPiece html(
    404       ResourceBundle::GetSharedInstance().GetRawDataResource(
    405           resource_id));
    406   return webui::GetI18nTemplateHtml(html, &strings);
    407 }
    408 
    409 std::string SSLBlockingPage::GetHTMLContentsV2() {
    410   base::DictionaryValue load_time_data;
    411   base::string16 url(ASCIIToUTF16(request_url_.host()));
    412   if (base::i18n::IsRTL())
    413     base::i18n::WrapStringWithLTRFormatting(&url);
    414   webui::SetFontAndTextDirection(&load_time_data);
    415 
    416   // Shared values for both the overridable and non-overridable versions.
    417   load_time_data.SetBoolean("ssl", true);
    418   load_time_data.SetBoolean(
    419       "overridable", overridable_ && !strict_enforcement_);
    420   load_time_data.SetString(
    421       "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
    422   load_time_data.SetString(
    423       "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
    424   load_time_data.SetString(
    425       "primaryParagraph",
    426       l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
    427   load_time_data.SetString(
    428      "openDetails",
    429      l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
    430   load_time_data.SetString(
    431      "closeDetails",
    432      l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
    433 
    434   if (overridable_ && !strict_enforcement_) {  // Overridable.
    435     SSLErrorInfo error_info =
    436         SSLErrorInfo::CreateError(
    437             SSLErrorInfo::NetErrorToErrorType(cert_error_),
    438             ssl_info_.cert.get(),
    439             request_url_);
    440     load_time_data.SetString(
    441         "explanationParagraph", error_info.details());
    442     load_time_data.SetString(
    443         "primaryButtonText",
    444         l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
    445     load_time_data.SetString(
    446         "finalParagraph",
    447         l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH, url));
    448   } else {  // Non-overridable.
    449     load_time_data.SetBoolean("overridable", false);
    450     load_time_data.SetString(
    451         "explanationParagraph",
    452         l10n_util::GetStringFUTF16(IDS_SSL_NONOVERRIDABLE_MORE, url));
    453     load_time_data.SetString(
    454         "primaryButtonText",
    455         l10n_util::GetStringUTF16(IDS_SSL_NONOVERRIDABLE_RELOAD_BUTTON));
    456     // Customize the help link depending on the specific error type.
    457     // Only mark as HSTS if none of the more specific error types apply, and use
    458     // INVALID as a fallback if no other string is appropriate.
    459     SSLErrorInfo::ErrorType type =
    460         SSLErrorInfo::NetErrorToErrorType(cert_error_);
    461     load_time_data.SetInteger("errorType", type);
    462     int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
    463     switch (type) {
    464       case SSLErrorInfo::CERT_REVOKED:
    465         help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
    466         break;
    467       case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
    468         help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
    469         break;
    470       case SSLErrorInfo::CERT_INVALID:
    471         help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
    472         break;
    473       default:
    474         if (strict_enforcement_)
    475           help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
    476     }
    477     load_time_data.SetString(
    478         "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
    479     load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
    480   }
    481 
    482   base::StringPiece html(
    483      ResourceBundle::GetSharedInstance().GetRawDataResource(
    484          IRD_SSL_INTERSTITIAL_V2_HTML));
    485   webui::UseVersion2 version;
    486   return webui::GetI18nTemplateHtml(html, &load_time_data);
    487 }
    488 
    489 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
    490   int cert_id = content::CertStore::GetInstance()->StoreCert(
    491       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
    492   DCHECK(cert_id);
    493 
    494   entry->GetSSL().security_style =
    495       content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
    496   entry->GetSSL().cert_id = cert_id;
    497   entry->GetSSL().cert_status = ssl_info_.cert_status;
    498   entry->GetSSL().security_bits = ssl_info_.security_bits;
    499 }
    500 
    501 // This handles the commands sent from the interstitial JavaScript. They are
    502 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
    503 // DO NOT reorder or change this logic without also changing the JavaScript!
    504 void SSLBlockingPage::CommandReceived(const std::string& command) {
    505   int cmd = 0;
    506   bool retval = base::StringToInt(command, &cmd);
    507   DCHECK(retval);
    508   switch (cmd) {
    509     case CMD_DONT_PROCEED: {
    510       interstitial_page_->DontProceed();
    511       break;
    512     }
    513     case CMD_PROCEED: {
    514       interstitial_page_->Proceed();
    515       break;
    516     }
    517     case CMD_MORE: {
    518       RecordSSLBlockingPageEventStats(MORE);
    519       break;
    520     }
    521     case CMD_RELOAD: {
    522       // The interstitial can't refresh itself.
    523       web_contents_->GetController().Reload(true);
    524       break;
    525     }
    526     case CMD_HELP: {
    527       // The interstitial can't open a popup or navigate itself.
    528       // TODO(felt): We're going to need a new help page.
    529       content::NavigationController::LoadURLParams help_page_params(GURL(
    530           "https://support.google.com/chrome/answer/4454607"));
    531       web_contents_->GetController().LoadURLWithParams(help_page_params);
    532       break;
    533     }
    534     default: {
    535       NOTREACHED();
    536     }
    537   }
    538 }
    539 
    540 void SSLBlockingPage::OverrideRendererPrefs(
    541       content::RendererPreferences* prefs) {
    542   Profile* profile = Profile::FromBrowserContext(
    543       web_contents_->GetBrowserContext());
    544   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
    545 }
    546 
    547 void SSLBlockingPage::OnProceed() {
    548   RecordSSLBlockingPageDetailedStats(true,
    549                                      cert_error_,
    550                                      overridable_ && !strict_enforcement_,
    551                                      internal_,
    552                                      num_visits_,
    553                                      captive_portal_detection_enabled_,
    554                                      captive_portal_probe_completed_,
    555                                      captive_portal_no_response_,
    556                                      captive_portal_detected_);
    557   // Accepting the certificate resumes the loading of the page.
    558   NotifyAllowCertificate();
    559 }
    560 
    561 void SSLBlockingPage::OnDontProceed() {
    562   RecordSSLBlockingPageDetailedStats(false,
    563                                      cert_error_,
    564                                      overridable_ && !strict_enforcement_,
    565                                      internal_,
    566                                      num_visits_,
    567                                      captive_portal_detection_enabled_,
    568                                      captive_portal_probe_completed_,
    569                                      captive_portal_no_response_,
    570                                      captive_portal_detected_);
    571   NotifyDenyCertificate();
    572 }
    573 
    574 void SSLBlockingPage::NotifyDenyCertificate() {
    575   // It's possible that callback_ may not exist if the user clicks "Proceed"
    576   // followed by pressing the back button before the interstitial is hidden.
    577   // In that case the certificate will still be treated as allowed.
    578   if (callback_.is_null())
    579     return;
    580 
    581   callback_.Run(false);
    582   callback_.Reset();
    583 }
    584 
    585 void SSLBlockingPage::NotifyAllowCertificate() {
    586   DCHECK(!callback_.is_null());
    587 
    588   callback_.Run(true);
    589   callback_.Reset();
    590 }
    591 
    592 // static
    593 void SSLBlockingPage::SetExtraInfo(
    594     base::DictionaryValue* strings,
    595     const std::vector<base::string16>& extra_info) {
    596   DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
    597   const char* keys[5] = {
    598       "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
    599   };
    600   int i;
    601   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
    602     strings->SetString(keys[i], extra_info[i]);
    603   }
    604   for (; i < 5; i++) {
    605     strings->SetString(keys[i], std::string());
    606   }
    607 }
    608 
    609 void SSLBlockingPage::OnGotHistoryCount(HistoryService::Handle handle,
    610                                         bool success,
    611                                         int num_visits,
    612                                         base::Time first_visit) {
    613   num_visits_ = num_visits;
    614 }
    615 
    616 void SSLBlockingPage::Observe(
    617     int type,
    618     const content::NotificationSource& source,
    619     const content::NotificationDetails& details) {
    620 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
    621   // When detection is disabled, captive portal service always sends
    622   // RESULT_INTERNET_CONNECTED. Ignore any probe results in that case.
    623   if (!captive_portal_detection_enabled_)
    624     return;
    625   if (type == chrome::NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT) {
    626     captive_portal_probe_completed_ = true;
    627     CaptivePortalService::Results* results =
    628         content::Details<CaptivePortalService::Results>(
    629             details).ptr();
    630     // If a captive portal was detected at any point when the interstitial was
    631     // displayed, assume that the interstitial was caused by a captive portal.
    632     // Example scenario:
    633     // 1- Interstitial displayed and captive portal detected, setting the flag.
    634     // 2- Captive portal detection automatically opens portal login page.
    635     // 3- User logs in on the portal login page.
    636     // A notification will be received here for RESULT_INTERNET_CONNECTED. Make
    637     // sure we don't clear the captive portal flag, since the interstitial was
    638     // potentially caused by the captive portal.
    639     captive_portal_detected_ = captive_portal_detected_ ||
    640         (results->result == captive_portal::RESULT_BEHIND_CAPTIVE_PORTAL);
    641     // Also keep track of non-HTTP portals and error cases.
    642     captive_portal_no_response_ = captive_portal_no_response_ ||
    643         (results->result == captive_portal::RESULT_NO_RESPONSE);
    644   }
    645 #endif
    646 }
    647