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