Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ssl / ssl_blocking_page.cc
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/build_time.h"
8 #include "base/command_line.h"
9 #include "base/i18n/rtl.h"
10 #include "base/i18n/time_formatting.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/metrics/histogram.h"
13 #include "base/process/launch.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_piece.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/history/history_service_factory.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/renderer_preferences_util.h"
26 #include "chrome/browser/ssl/ssl_error_classification.h"
27 #include "chrome/browser/ssl/ssl_error_info.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/grit/chromium_strings.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "components/google/core/browser/google_util.h"
32 #include "content/public/browser/cert_store.h"
33 #include "content/public/browser/interstitial_page.h"
34 #include "content/public/browser/navigation_controller.h"
35 #include "content/public/browser/navigation_entry.h"
36 #include "content/public/browser/notification_service.h"
37 #include "content/public/browser/notification_types.h"
38 #include "content/public/browser/render_process_host.h"
39 #include "content/public/browser/render_view_host.h"
40 #include "content/public/browser/web_contents.h"
41 #include "content/public/common/ssl_status.h"
42 #include "grit/browser_resources.h"
43 #include "net/base/hash_value.h"
44 #include "net/base/net_errors.h"
45 #include "net/base/net_util.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/resource/resource_bundle.h"
48 #include "ui/base/webui/jstemplate_builder.h"
49 #include "ui/base/webui/web_ui_util.h"
50
51 #if defined(ENABLE_EXTENSIONS)
52 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
53 #endif
54
55 #if defined(OS_WIN)
56 #include "base/base_paths_win.h"
57 #include "base/path_service.h"
58 #include "base/strings/string16.h"
59 #include "base/win/windows_version.h"
60 #endif
61
62 #if defined(OS_CHROMEOS)
63 #include "chrome/browser/profiles/profile_manager.h"
64 #include "chrome/browser/ui/chrome_pages.h"
65 #include "chrome/common/url_constants.h"
66 #endif
67
68 using base::ASCIIToUTF16;
69 using base::TimeTicks;
70 using content::InterstitialPage;
71 using content::NavigationController;
72 using content::NavigationEntry;
73
74 #if defined(ENABLE_EXTENSIONS)
75 using extensions::ExperienceSamplingEvent;
76 #endif
77
78 namespace {
79
80 // URL for help page.
81 const char kHelpURL[] = "https://support.google.com/chrome/answer/4454607";
82
83 // Constants for the Experience Sampling instrumentation.
84 #if defined(ENABLE_EXTENSIONS)
85 const char kEventNameBase[] = "ssl_interstitial_";
86 const char kEventNotOverridable[] = "notoverridable_";
87 const char kEventOverridable[] = "overridable_";
88 #endif
89
90 // Events for UMA. Do not reorder or change!
91 enum SSLBlockingPageEvent {
92   SHOW_ALL,
93   SHOW_OVERRIDABLE,
94   PROCEED_OVERRIDABLE,
95   PROCEED_NAME,
96   PROCEED_DATE,
97   PROCEED_AUTHORITY,
98   DONT_PROCEED_OVERRIDABLE,
99   DONT_PROCEED_NAME,
100   DONT_PROCEED_DATE,
101   DONT_PROCEED_AUTHORITY,
102   MORE,
103   SHOW_UNDERSTAND,  // Used by the summer 2013 Finch trial. Deprecated.
104   SHOW_INTERNAL_HOSTNAME,
105   PROCEED_INTERNAL_HOSTNAME,
106   SHOW_NEW_SITE,
107   PROCEED_NEW_SITE,
108   PROCEED_MANUAL_NONOVERRIDABLE,
109   // Captive Portal errors moved to ssl_error_classification.
110   DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED,
111   DEPRECATED_CAPTIVE_PORTAL_DETECTION_ENABLED_OVERRIDABLE,
112   DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED,
113   DEPRECATED_CAPTIVE_PORTAL_PROBE_COMPLETED_OVERRIDABLE,
114   DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE,
115   DEPRECATED_CAPTIVE_PORTAL_NO_RESPONSE_OVERRIDABLE,
116   DEPRECATED_CAPTIVE_PORTAL_DETECTED,
117   DEPRECATED_CAPTIVE_PORTAL_DETECTED_OVERRIDABLE,
118   UNUSED_BLOCKING_PAGE_EVENT,
119 };
120
121 // Events for UMA. Do not reorder or change!
122 enum SSLExpirationAndDecision {
123   EXPIRED_AND_PROCEED,
124   EXPIRED_AND_DO_NOT_PROCEED,
125   NOT_EXPIRED_AND_PROCEED,
126   NOT_EXPIRED_AND_DO_NOT_PROCEED,
127   END_OF_SSL_EXPIRATION_AND_DECISION,
128 };
129
130 void RecordSSLBlockingPageEventStats(SSLBlockingPageEvent event) {
131   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl",
132                             event,
133                             UNUSED_BLOCKING_PAGE_EVENT);
134 }
135
136 void RecordSSLExpirationPageEventState(bool expired_but_previously_allowed,
137                                        bool proceed,
138                                        bool overridable) {
139   SSLExpirationAndDecision event;
140   if (expired_but_previously_allowed && proceed)
141     event = EXPIRED_AND_PROCEED;
142   else if (expired_but_previously_allowed && !proceed)
143     event = EXPIRED_AND_DO_NOT_PROCEED;
144   else if (!expired_but_previously_allowed && proceed)
145     event = NOT_EXPIRED_AND_PROCEED;
146   else
147     event = NOT_EXPIRED_AND_DO_NOT_PROCEED;
148
149   if (overridable) {
150     UMA_HISTOGRAM_ENUMERATION(
151         "interstitial.ssl.expiration_and_decision.overridable",
152         event,
153         END_OF_SSL_EXPIRATION_AND_DECISION);
154   } else {
155     UMA_HISTOGRAM_ENUMERATION(
156         "interstitial.ssl.expiration_and_decision.nonoverridable",
157         event,
158         END_OF_SSL_EXPIRATION_AND_DECISION);
159   }
160 }
161
162 void RecordSSLBlockingPageDetailedStats(bool proceed,
163                                         int cert_error,
164                                         bool overridable,
165                                         bool internal,
166                                         int num_visits,
167                                         bool expired_but_previously_allowed) {
168   UMA_HISTOGRAM_ENUMERATION("interstitial.ssl_error_type",
169       SSLErrorInfo::NetErrorToErrorType(cert_error), SSLErrorInfo::END_OF_ENUM);
170   RecordSSLExpirationPageEventState(
171       expired_but_previously_allowed, proceed, overridable);
172   if (!overridable) {
173     if (proceed) {
174       RecordSSLBlockingPageEventStats(PROCEED_MANUAL_NONOVERRIDABLE);
175     }
176     // Overridable is false if the user didn't have any option except to turn
177     // back. If that's the case, don't record some of the metrics.
178     return;
179   }
180   if (num_visits == 0)
181     RecordSSLBlockingPageEventStats(SHOW_NEW_SITE);
182   if (proceed) {
183     RecordSSLBlockingPageEventStats(PROCEED_OVERRIDABLE);
184     if (internal)
185       RecordSSLBlockingPageEventStats(PROCEED_INTERNAL_HOSTNAME);
186     if (num_visits == 0)
187       RecordSSLBlockingPageEventStats(PROCEED_NEW_SITE);
188   } else if (!proceed) {
189     RecordSSLBlockingPageEventStats(DONT_PROCEED_OVERRIDABLE);
190   }
191   SSLErrorInfo::ErrorType type = SSLErrorInfo::NetErrorToErrorType(cert_error);
192   switch (type) {
193     case SSLErrorInfo::CERT_COMMON_NAME_INVALID: {
194       if (proceed)
195         RecordSSLBlockingPageEventStats(PROCEED_NAME);
196       else
197         RecordSSLBlockingPageEventStats(DONT_PROCEED_NAME);
198       break;
199     }
200     case SSLErrorInfo::CERT_DATE_INVALID: {
201       if (proceed)
202         RecordSSLBlockingPageEventStats(PROCEED_DATE);
203       else
204         RecordSSLBlockingPageEventStats(DONT_PROCEED_DATE);
205       break;
206     }
207     case SSLErrorInfo::CERT_AUTHORITY_INVALID: {
208       if (proceed)
209         RecordSSLBlockingPageEventStats(PROCEED_AUTHORITY);
210       else
211         RecordSSLBlockingPageEventStats(DONT_PROCEED_AUTHORITY);
212       break;
213     }
214     default: {
215       break;
216     }
217   }
218 }
219
220 void LaunchDateAndTimeSettings() {
221 #if defined(OS_CHROMEOS)
222   std::string sub_page = std::string(chrome::kSearchSubPage) + "#" +
223       l10n_util::GetStringUTF8(IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME);
224   chrome::ShowSettingsSubPageForProfile(
225       ProfileManager::GetActiveUserProfile(), sub_page);
226   return;
227 #elif defined(OS_ANDROID)
228   CommandLine command(base::FilePath("/system/bin/am"));
229   command.AppendArg("start");
230   command.AppendArg(
231       "'com.android.settings/.Settings$DateTimeSettingsActivity'");
232 #elif defined(OS_IOS)
233   // Apparently, iOS really does not have a way to launch the date and time
234   // settings. Weird. TODO(palmer): Do something more graceful than ignoring
235   // the user's click! crbug.com/394993
236   return;
237 #elif defined(OS_LINUX)
238   struct ClockCommand {
239     const char* pathname;
240     const char* argument;
241   };
242   static const ClockCommand kClockCommands[] = {
243     // GNOME
244     //
245     // NOTE: On old Ubuntu, naming control panels doesn't work, so it
246     // opens the overview. This will have to be good enough.
247     { "/usr/bin/gnome-control-center", "datetime" },
248     { "/usr/local/bin/gnome-control-center", "datetime" },
249     { "/opt/bin/gnome-control-center", "datetime" },
250     // KDE
251     { "/usr/bin/kcmshell4", "clock" },
252     { "/usr/local/bin/kcmshell4", "clock" },
253     { "/opt/bin/kcmshell4", "clock" },
254   };
255
256   CommandLine command(base::FilePath(""));
257   for (size_t i = 0; i < arraysize(kClockCommands); ++i) {
258     base::FilePath pathname(kClockCommands[i].pathname);
259     if (base::PathExists(pathname)) {
260       command.SetProgram(pathname);
261       command.AppendArg(kClockCommands[i].argument);
262       break;
263     }
264   }
265   if (command.GetProgram().empty()) {
266     // Alas, there is nothing we can do.
267     return;
268   }
269 #elif defined(OS_MACOSX)
270   CommandLine command(base::FilePath("/usr/bin/open"));
271   command.AppendArg("/System/Library/PreferencePanes/DateAndTime.prefPane");
272 #elif defined(OS_WIN)
273   base::FilePath path;
274   PathService::Get(base::DIR_SYSTEM, &path);
275   static const base::char16 kControlPanelExe[] = L"control.exe";
276   path = path.Append(base::string16(kControlPanelExe));
277   CommandLine command(path);
278   command.AppendArg(std::string("/name"));
279   command.AppendArg(std::string("Microsoft.DateAndTime"));
280 #else
281   return;
282 #endif
283
284 #if !defined(OS_CHROMEOS)
285   base::LaunchOptions options;
286   options.wait = false;
287 #if defined(OS_LINUX)
288   options.allow_new_privs = true;
289 #endif
290   base::LaunchProcess(command, options, NULL);
291 #endif
292 }
293
294 bool IsErrorDueToBadClock(const base::Time& now, int error) {
295   if (SSLErrorInfo::NetErrorToErrorType(error) !=
296           SSLErrorInfo::CERT_DATE_INVALID) {
297     return false;
298   }
299   return SSLErrorClassification::IsUserClockInThePast(now) ||
300       SSLErrorClassification::IsUserClockInTheFuture(now);
301 }
302
303 }  // namespace
304
305 // Note that we always create a navigation entry with SSL errors.
306 // No error happening loading a sub-resource triggers an interstitial so far.
307 SSLBlockingPage::SSLBlockingPage(content::WebContents* web_contents,
308                                  int cert_error,
309                                  const net::SSLInfo& ssl_info,
310                                  const GURL& request_url,
311                                  int options_mask,
312                                  const base::Callback<void(bool)>& callback)
313     : callback_(callback),
314       web_contents_(web_contents),
315       cert_error_(cert_error),
316       ssl_info_(ssl_info),
317       request_url_(request_url),
318       overridable_(options_mask & OVERRIDABLE &&
319                    !(options_mask & STRICT_ENFORCEMENT)),
320       strict_enforcement_((options_mask & STRICT_ENFORCEMENT) != 0),
321       interstitial_page_(NULL),
322       internal_(false),
323       num_visits_(-1),
324       expired_but_previously_allowed_(
325           (options_mask & EXPIRED_BUT_PREVIOUSLY_ALLOWED) != 0) {
326   Profile* profile = Profile::FromBrowserContext(
327       web_contents->GetBrowserContext());
328   // For UMA stats.
329   if (net::IsHostnameNonUnique(request_url_.HostNoBrackets()))
330     internal_ = true;
331   RecordSSLBlockingPageEventStats(SHOW_ALL);
332   if (overridable_) {
333     RecordSSLBlockingPageEventStats(SHOW_OVERRIDABLE);
334     if (internal_)
335       RecordSSLBlockingPageEventStats(SHOW_INTERNAL_HOSTNAME);
336     HistoryService* history_service = HistoryServiceFactory::GetForProfile(
337         profile, Profile::EXPLICIT_ACCESS);
338     if (history_service) {
339       history_service->GetVisibleVisitCountToHost(
340           request_url_,
341           base::Bind(&SSLBlockingPage::OnGotHistoryCount,
342                      base::Unretained(this)),
343           &request_tracker_);
344     }
345   }
346
347   ssl_error_classification_.reset(new SSLErrorClassification(
348       web_contents_,
349       base::Time::NowFromSystemTime(),
350       request_url_,
351       cert_error_,
352       *ssl_info_.cert.get()));
353   ssl_error_classification_->RecordUMAStatistics(overridable_);
354
355 #if defined(ENABLE_CAPTIVE_PORTAL_DETECTION)
356   ssl_error_classification_->RecordCaptivePortalUMAStatistics(overridable_);
357 #endif
358
359 #if defined(ENABLE_EXTENSIONS)
360   // ExperienceSampling: Set up new sampling event for this interstitial.
361   std::string event_name(kEventNameBase);
362   if (overridable_ && !strict_enforcement_)
363     event_name.append(kEventOverridable);
364   else
365     event_name.append(kEventNotOverridable);
366   event_name.append(net::ErrorToString(cert_error_));
367   sampling_event_.reset(new ExperienceSamplingEvent(
368       event_name,
369       request_url_,
370       web_contents_->GetLastCommittedURL(),
371       web_contents_->GetBrowserContext()));
372 #endif
373
374   // Creating an interstitial without showing (e.g. from chrome://interstitials)
375   // it leaks memory, so don't create it here.
376 }
377
378 SSLBlockingPage::~SSLBlockingPage() {
379   // InvalidCommonNameSeverityScore() and InvalidDateSeverityScore() are in the
380   // destructor because they depend on knowing whether captive portal detection
381   // happened before the user made a decision.
382   SSLErrorInfo::ErrorType type =
383       SSLErrorInfo::NetErrorToErrorType(cert_error_);
384   switch (type) {
385     case SSLErrorInfo::CERT_DATE_INVALID:
386       ssl_error_classification_->InvalidDateSeverityScore();
387       break;
388     case SSLErrorInfo::CERT_COMMON_NAME_INVALID:
389       ssl_error_classification_->InvalidCommonNameSeverityScore();
390       break;
391     default:
392       break;
393   }
394   if (!callback_.is_null()) {
395     RecordSSLBlockingPageDetailedStats(false,
396                                        cert_error_,
397                                        overridable_,
398                                        internal_,
399                                        num_visits_,
400                                        expired_but_previously_allowed_);
401     // The page is closed without the user having chosen what to do, default to
402     // deny.
403     NotifyDenyCertificate();
404   }
405 }
406
407 void SSLBlockingPage::Show() {
408   DCHECK(!interstitial_page_);
409   interstitial_page_ = InterstitialPage::Create(
410       web_contents_, true, request_url_, this);
411   interstitial_page_->Show();
412 }
413
414 std::string SSLBlockingPage::GetHTMLContents() {
415   base::DictionaryValue load_time_data;
416   base::string16 url(ASCIIToUTF16(request_url_.host()));
417   if (base::i18n::IsRTL())
418     base::i18n::WrapStringWithLTRFormatting(&url);
419   webui::SetFontAndTextDirection(&load_time_data);
420
421   // Shared values for both the overridable and non-overridable versions.
422   load_time_data.SetBoolean("ssl", true);
423   load_time_data.SetBoolean("overridable", overridable_);
424   load_time_data.SetString(
425       "tabTitle", l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
426   load_time_data.SetString(
427       "heading", l10n_util::GetStringUTF16(IDS_SSL_V2_HEADING));
428
429   base::Time now = base::Time::NowFromSystemTime();
430   bool bad_clock = IsErrorDueToBadClock(now, cert_error_);
431   if (bad_clock) {
432     load_time_data.SetString("primaryParagraph",
433                              l10n_util::GetStringFUTF16(
434                                  IDS_SSL_CLOCK_ERROR,
435                                  url,
436                                  base::TimeFormatShortDate(now)));
437   } else {
438     load_time_data.SetString(
439         "primaryParagraph",
440         l10n_util::GetStringFUTF16(IDS_SSL_V2_PRIMARY_PARAGRAPH, url));
441   }
442
443   load_time_data.SetString(
444      "openDetails",
445      l10n_util::GetStringUTF16(IDS_SSL_V2_OPEN_DETAILS_BUTTON));
446   load_time_data.SetString(
447      "closeDetails",
448      l10n_util::GetStringUTF16(IDS_SSL_V2_CLOSE_DETAILS_BUTTON));
449   load_time_data.SetString("errorCode", net::ErrorToString(cert_error_));
450
451   if (overridable_) {
452     SSLErrorInfo error_info =
453         SSLErrorInfo::CreateError(
454             SSLErrorInfo::NetErrorToErrorType(cert_error_),
455             ssl_info_.cert.get(),
456             request_url_);
457     if (bad_clock) {
458       load_time_data.SetString("explanationParagraph",
459                                l10n_util::GetStringFUTF16(
460                                    IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
461     } else {
462       load_time_data.SetString("explanationParagraph", error_info.details());
463     }
464     load_time_data.SetString(
465         "primaryButtonText",
466         l10n_util::GetStringUTF16(IDS_SSL_OVERRIDABLE_SAFETY_BUTTON));
467     load_time_data.SetString(
468         "finalParagraph",
469         l10n_util::GetStringFUTF16(IDS_SSL_OVERRIDABLE_PROCEED_PARAGRAPH,
470                                    url));
471   } else {
472     SSLErrorInfo::ErrorType type =
473         SSLErrorInfo::NetErrorToErrorType(cert_error_);
474     if (type == SSLErrorInfo::CERT_INVALID && SSLErrorClassification::
475         MaybeWindowsLacksSHA256Support()) {
476       load_time_data.SetString(
477           "explanationParagraph",
478           l10n_util::GetStringFUTF16(
479               IDS_SSL_NONOVERRIDABLE_MORE_INVALID_SP3, url));
480     } else if (bad_clock) {
481       load_time_data.SetString("explanationParagraph",
482                                l10n_util::GetStringFUTF16(
483                                    IDS_SSL_CLOCK_ERROR_EXPLANATION, url));
484     } else {
485       load_time_data.SetString("explanationParagraph",
486                                l10n_util::GetStringFUTF16(
487                                    IDS_SSL_NONOVERRIDABLE_MORE, url));
488     }
489     load_time_data.SetString(
490         "primaryButtonText",
491         l10n_util::GetStringUTF16(IDS_SSL_NONOVERRIDABLE_RELOAD_BUTTON));
492     // Customize the help link depending on the specific error type.
493     // Only mark as HSTS if none of the more specific error types apply, and use
494     // INVALID as a fallback if no other string is appropriate.
495     load_time_data.SetInteger("errorType", type);
496     int help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
497     switch (type) {
498       case SSLErrorInfo::CERT_REVOKED:
499         help_string = IDS_SSL_NONOVERRIDABLE_REVOKED;
500         break;
501       case SSLErrorInfo::CERT_PINNED_KEY_MISSING:
502         help_string = IDS_SSL_NONOVERRIDABLE_PINNED;
503         break;
504       case SSLErrorInfo::CERT_INVALID:
505         help_string = IDS_SSL_NONOVERRIDABLE_INVALID;
506         break;
507       default:
508         if (strict_enforcement_)
509           help_string = IDS_SSL_NONOVERRIDABLE_HSTS;
510     }
511     load_time_data.SetString(
512         "finalParagraph", l10n_util::GetStringFUTF16(help_string, url));
513   }
514
515   // Set debugging information at the bottom of the warning.
516   load_time_data.SetString(
517       "subject", ssl_info_.cert->subject().GetDisplayName());
518   load_time_data.SetString(
519       "issuer", ssl_info_.cert->issuer().GetDisplayName());
520   load_time_data.SetString(
521       "expirationDate",
522       base::TimeFormatShortDate(ssl_info_.cert->valid_expiry()));
523   load_time_data.SetString(
524       "currentDate", base::TimeFormatShortDate(now));
525   std::vector<std::string> encoded_chain;
526   ssl_info_.cert->GetPEMEncodedChain(&encoded_chain);
527   load_time_data.SetString("pem", JoinString(encoded_chain, std::string()));
528
529   base::StringPiece html(
530      ResourceBundle::GetSharedInstance().GetRawDataResource(
531          IRD_SECURITY_INTERSTITIAL_HTML));
532   webui::UseVersion2 version;
533   return webui::GetI18nTemplateHtml(html, &load_time_data);
534 }
535
536 void SSLBlockingPage::OverrideEntry(NavigationEntry* entry) {
537   int cert_id = content::CertStore::GetInstance()->StoreCert(
538       ssl_info_.cert.get(), web_contents_->GetRenderProcessHost()->GetID());
539   DCHECK(cert_id);
540
541   entry->GetSSL().security_style =
542       content::SECURITY_STYLE_AUTHENTICATION_BROKEN;
543   entry->GetSSL().cert_id = cert_id;
544   entry->GetSSL().cert_status = ssl_info_.cert_status;
545   entry->GetSSL().security_bits = ssl_info_.security_bits;
546 }
547
548 // This handles the commands sent from the interstitial JavaScript. They are
549 // defined in chrome/browser/resources/ssl/ssl_errors_common.js.
550 // DO NOT reorder or change this logic without also changing the JavaScript!
551 void SSLBlockingPage::CommandReceived(const std::string& command) {
552   int cmd = 0;
553   bool retval = base::StringToInt(command, &cmd);
554   DCHECK(retval);
555   switch (cmd) {
556     case CMD_DONT_PROCEED: {
557       interstitial_page_->DontProceed();
558       break;
559     }
560     case CMD_PROCEED: {
561       interstitial_page_->Proceed();
562       break;
563     }
564     case CMD_MORE: {
565       RecordSSLBlockingPageEventStats(MORE);
566 #if defined(ENABLE_EXTENSIONS)
567       if (sampling_event_.get())
568         sampling_event_->set_has_viewed_details(true);
569 #endif
570       break;
571     }
572     case CMD_RELOAD: {
573       // The interstitial can't refresh itself.
574       web_contents_->GetController().Reload(true);
575       break;
576     }
577     case CMD_HELP: {
578       content::NavigationController::LoadURLParams help_page_params(
579           google_util::AppendGoogleLocaleParam(
580               GURL(kHelpURL), g_browser_process->GetApplicationLocale()));
581 #if defined(ENABLE_EXTENSIONS)
582       if (sampling_event_.get())
583         sampling_event_->set_has_viewed_learn_more(true);
584 #endif
585       web_contents_->GetController().LoadURLWithParams(help_page_params);
586       break;
587     }
588     case CMD_CLOCK: {
589       LaunchDateAndTimeSettings();
590       break;
591     }
592     default: {
593       NOTREACHED();
594     }
595   }
596 }
597
598 void SSLBlockingPage::OverrideRendererPrefs(
599       content::RendererPreferences* prefs) {
600   Profile* profile = Profile::FromBrowserContext(
601       web_contents_->GetBrowserContext());
602   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
603 }
604
605 void SSLBlockingPage::OnProceed() {
606   RecordSSLBlockingPageDetailedStats(true,
607                                      cert_error_,
608                                      overridable_,
609                                      internal_,
610                                      num_visits_,
611                                      expired_but_previously_allowed_);
612 #if defined(ENABLE_EXTENSIONS)
613   // ExperienceSampling: Notify that user decided to proceed.
614   if (sampling_event_.get())
615     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
616 #endif
617
618   // Accepting the certificate resumes the loading of the page.
619   NotifyAllowCertificate();
620 }
621
622 void SSLBlockingPage::OnDontProceed() {
623   RecordSSLBlockingPageDetailedStats(false,
624                                      cert_error_,
625                                      overridable_,
626                                      internal_,
627                                      num_visits_,
628                                      expired_but_previously_allowed_);
629 #if defined(ENABLE_EXTENSIONS)
630   // ExperienceSampling: Notify that user decided to not proceed.
631   // This also occurs if the user navigates away or closes the tab.
632   if (sampling_event_.get())
633     sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
634 #endif
635   NotifyDenyCertificate();
636 }
637
638 void SSLBlockingPage::NotifyDenyCertificate() {
639   // It's possible that callback_ may not exist if the user clicks "Proceed"
640   // followed by pressing the back button before the interstitial is hidden.
641   // In that case the certificate will still be treated as allowed.
642   if (callback_.is_null())
643     return;
644
645   callback_.Run(false);
646   callback_.Reset();
647 }
648
649 void SSLBlockingPage::NotifyAllowCertificate() {
650   DCHECK(!callback_.is_null());
651
652   callback_.Run(true);
653   callback_.Reset();
654 }
655
656 // static
657 void SSLBlockingPage::SetExtraInfo(
658     base::DictionaryValue* strings,
659     const std::vector<base::string16>& extra_info) {
660   DCHECK_LT(extra_info.size(), 5U);  // We allow 5 paragraphs max.
661   const char* keys[5] = {
662       "moreInfo1", "moreInfo2", "moreInfo3", "moreInfo4", "moreInfo5"
663   };
664   int i;
665   for (i = 0; i < static_cast<int>(extra_info.size()); i++) {
666     strings->SetString(keys[i], extra_info[i]);
667   }
668   for (; i < 5; i++) {
669     strings->SetString(keys[i], std::string());
670   }
671 }
672
673 void SSLBlockingPage::OnGotHistoryCount(bool success,
674                                         int num_visits,
675                                         base::Time first_visit) {
676   num_visits_ = num_visits;
677 }