Home | History | Annotate | Download | only in safe_browsing
      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 // Implementation of the SafeBrowsingBlockingPage class.
      6 
      7 #include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
      8 
      9 #include <string>
     10 
     11 #include "base/bind.h"
     12 #include "base/command_line.h"
     13 #include "base/i18n/rtl.h"
     14 #include "base/lazy_instance.h"
     15 #include "base/metrics/field_trial.h"
     16 #include "base/metrics/histogram.h"
     17 #include "base/prefs/pref_service.h"
     18 #include "base/strings/string_number_conversions.h"
     19 #include "base/strings/string_piece.h"
     20 #include "base/strings/stringprintf.h"
     21 #include "base/strings/utf_string_conversions.h"
     22 #include "base/time/time.h"
     23 #include "base/values.h"
     24 #include "chrome/browser/browser_process.h"
     25 #include "chrome/browser/history/history_service_factory.h"
     26 #include "chrome/browser/profiles/profile.h"
     27 #include "chrome/browser/renderer_preferences_util.h"
     28 #include "chrome/browser/safe_browsing/malware_details.h"
     29 #include "chrome/browser/safe_browsing/ui_manager.h"
     30 #include "chrome/browser/tab_contents/tab_util.h"
     31 #include "chrome/common/chrome_switches.h"
     32 #include "chrome/common/pref_names.h"
     33 #include "chrome/common/url_constants.h"
     34 #include "chrome/grit/generated_resources.h"
     35 #include "chrome/grit/locale_settings.h"
     36 #include "components/google/core/browser/google_util.h"
     37 #include "content/public/browser/browser_thread.h"
     38 #include "content/public/browser/interstitial_page.h"
     39 #include "content/public/browser/navigation_controller.h"
     40 #include "content/public/browser/user_metrics.h"
     41 #include "content/public/browser/web_contents.h"
     42 #include "grit/browser_resources.h"
     43 #include "net/base/escape.h"
     44 #include "ui/base/l10n/l10n_util.h"
     45 #include "ui/base/resource/resource_bundle.h"
     46 #include "ui/base/webui/jstemplate_builder.h"
     47 #include "ui/base/webui/web_ui_util.h"
     48 
     49 #if defined(ENABLE_EXTENSIONS)
     50 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
     51 #endif
     52 
     53 using base::UserMetricsAction;
     54 using content::BrowserThread;
     55 using content::InterstitialPage;
     56 using content::OpenURLParams;
     57 using content::Referrer;
     58 using content::WebContents;
     59 
     60 #if defined(ENABLE_EXTENSIONS)
     61 using extensions::ExperienceSamplingEvent;
     62 #endif
     63 
     64 namespace {
     65 
     66 // For malware interstitial pages, we link the problematic URL to Google's
     67 // diagnostic page.
     68 #if defined(GOOGLE_CHROME_BUILD)
     69 const char* const kSbDiagnosticUrl =
     70     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=googlechrome";
     71 #else
     72 const char* const kSbDiagnosticUrl =
     73     "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?site=%s&client=chromium";
     74 #endif
     75 
     76 // URL for malware and phishing, V2.
     77 const char kLearnMoreMalwareUrlV2[] =
     78     "https://www.google.com/transparencyreport/safebrowsing/";
     79 const char kLearnMorePhishingUrlV2[] =
     80     "https://www.google.com/transparencyreport/safebrowsing/";
     81 
     82 const char kPrivacyLinkHtml[] =
     83     "<a id=\"privacy-link\" href=\"\" onclick=\"sendCommand('showPrivacy'); "
     84     "return false;\" onmousedown=\"return false;\">%s</a>";
     85 
     86 // After a malware interstitial where the user opted-in to the report
     87 // but clicked "proceed anyway", we delay the call to
     88 // MalwareDetails::FinishCollection() by this much time (in
     89 // milliseconds).
     90 const int64 kMalwareDetailsProceedDelayMilliSeconds = 3000;
     91 
     92 // The commands returned by the page when the user performs an action.
     93 const char kDoReportCommand[] = "doReport";
     94 const char kDontReportCommand[] = "dontReport";
     95 const char kExpandedSeeMoreCommand[] = "expandedSeeMore";
     96 const char kLearnMoreCommand[] = "learnMore2";
     97 const char kProceedCommand[] = "proceed";
     98 const char kShowDiagnosticCommand[] = "showDiagnostic";
     99 const char kShowPrivacyCommand[] = "showPrivacy";
    100 const char kTakeMeBackCommand[] = "takeMeBack";
    101 
    102 // Other constants used to communicate with the JavaScript.
    103 const char kBoxChecked[] = "boxchecked";
    104 const char kDisplayCheckBox[] = "displaycheckbox";
    105 
    106 // Constants for the Experience Sampling instrumentation.
    107 #if defined(ENABLE_EXTENSIONS)
    108 const char kEventNameMalware[] = "safebrowsing_interstitial_";
    109 const char kEventNameHarmful[] = "harmful_interstitial_";
    110 const char kEventNamePhishing[] = "phishing_interstitial_";
    111 const char kEventNameOther[] = "safebrowsing_other_interstitial_";
    112 #endif
    113 
    114 base::LazyInstance<SafeBrowsingBlockingPage::UnsafeResourceMap>
    115     g_unsafe_resource_map = LAZY_INSTANCE_INITIALIZER;
    116 
    117 }  // namespace
    118 
    119 // static
    120 SafeBrowsingBlockingPageFactory* SafeBrowsingBlockingPage::factory_ = NULL;
    121 
    122 // The default SafeBrowsingBlockingPageFactory.  Global, made a singleton so we
    123 // don't leak it.
    124 class SafeBrowsingBlockingPageFactoryImpl
    125     : public SafeBrowsingBlockingPageFactory {
    126  public:
    127   virtual SafeBrowsingBlockingPage* CreateSafeBrowsingPage(
    128       SafeBrowsingUIManager* ui_manager,
    129       WebContents* web_contents,
    130       const SafeBrowsingBlockingPage::UnsafeResourceList& unsafe_resources)
    131       OVERRIDE {
    132     return new SafeBrowsingBlockingPage(ui_manager, web_contents,
    133         unsafe_resources);
    134   }
    135 
    136  private:
    137   friend struct base::DefaultLazyInstanceTraits<
    138       SafeBrowsingBlockingPageFactoryImpl>;
    139 
    140   SafeBrowsingBlockingPageFactoryImpl() { }
    141 
    142   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPageFactoryImpl);
    143 };
    144 
    145 static base::LazyInstance<SafeBrowsingBlockingPageFactoryImpl>
    146     g_safe_browsing_blocking_page_factory_impl = LAZY_INSTANCE_INITIALIZER;
    147 
    148 SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
    149     SafeBrowsingUIManager* ui_manager,
    150     WebContents* web_contents,
    151     const UnsafeResourceList& unsafe_resources)
    152     : malware_details_proceed_delay_ms_(
    153           kMalwareDetailsProceedDelayMilliSeconds),
    154       ui_manager_(ui_manager),
    155       report_loop_(NULL),
    156       is_main_frame_load_blocked_(IsMainPageLoadBlocked(unsafe_resources)),
    157       unsafe_resources_(unsafe_resources),
    158       proceeded_(false),
    159       web_contents_(web_contents),
    160       url_(unsafe_resources[0].url),
    161       interstitial_page_(NULL),
    162       create_view_(true),
    163       num_visits_(-1) {
    164   bool malware = false;
    165   bool harmful = false;
    166   bool phishing = false;
    167   for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
    168        iter != unsafe_resources_.end(); ++iter) {
    169     const UnsafeResource& resource = *iter;
    170     SBThreatType threat_type = resource.threat_type;
    171     if (threat_type == SB_THREAT_TYPE_URL_MALWARE ||
    172         threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) {
    173       malware = true;
    174     } else if (threat_type == SB_THREAT_TYPE_URL_HARMFUL) {
    175       harmful = true;
    176     } else {
    177       DCHECK(threat_type == SB_THREAT_TYPE_URL_PHISHING ||
    178              threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL);
    179       phishing = true;
    180     }
    181   }
    182   DCHECK(phishing || malware || harmful);
    183   if (malware)
    184     interstitial_type_ = TYPE_MALWARE;
    185   else if (harmful)
    186     interstitial_type_ = TYPE_HARMFUL;
    187   else
    188     interstitial_type_ = TYPE_PHISHING;
    189 
    190   RecordUserDecision(SHOW);
    191   RecordUserInteraction(TOTAL_VISITS);
    192   if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
    193     RecordUserDecision(PROCEEDING_DISABLED);
    194 
    195   HistoryService* history_service = HistoryServiceFactory::GetForProfile(
    196           Profile::FromBrowserContext(web_contents->GetBrowserContext()),
    197           Profile::EXPLICIT_ACCESS);
    198   if (history_service) {
    199     history_service->GetVisibleVisitCountToHost(
    200         url_,
    201         base::Bind(&SafeBrowsingBlockingPage::OnGotHistoryCount,
    202                    base::Unretained(this)),
    203         &request_tracker_);
    204   }
    205 
    206   if (!is_main_frame_load_blocked_) {
    207     navigation_entry_index_to_remove_ =
    208         web_contents->GetController().GetLastCommittedEntryIndex();
    209   } else {
    210     navigation_entry_index_to_remove_ = -1;
    211   }
    212 
    213   // Start computing malware details. They will be sent only
    214   // if the user opts-in on the blocking page later.
    215   // If there's more than one malicious resources, it means the user
    216   // clicked through the first warning, so we don't prepare additional
    217   // reports.
    218   if (unsafe_resources.size() == 1 &&
    219       unsafe_resources[0].threat_type == SB_THREAT_TYPE_URL_MALWARE &&
    220       malware_details_.get() == NULL && CanShowMalwareDetailsOption()) {
    221     malware_details_ = MalwareDetails::NewMalwareDetails(
    222         ui_manager_, web_contents, unsafe_resources[0]);
    223   }
    224 
    225 #if defined(ENABLE_EXTENSIONS)
    226   // ExperienceSampling: Set up new sampling event for this interstitial.
    227   // This needs to handle all types of warnings this interstitial can show.
    228   std::string event_name;
    229   switch (interstitial_type_) {
    230     case TYPE_MALWARE:
    231       event_name = kEventNameMalware;
    232       break;
    233     case TYPE_HARMFUL:
    234       event_name = kEventNameHarmful;
    235       break;
    236     case TYPE_PHISHING:
    237       event_name = kEventNamePhishing;
    238       break;
    239     default:
    240       event_name = kEventNameOther;
    241       break;
    242   }
    243   sampling_event_.reset(new ExperienceSamplingEvent(
    244       event_name,
    245       url_,
    246       web_contents_->GetLastCommittedURL(),
    247       web_contents_->GetBrowserContext()));
    248 #endif
    249 
    250   // Creating interstitial_page_ without showing it leaks memory, so don't
    251   // create it here.
    252 }
    253 
    254 bool SafeBrowsingBlockingPage::CanShowMalwareDetailsOption() {
    255   return (!web_contents_->GetBrowserContext()->IsOffTheRecord() &&
    256           web_contents_->GetURL().SchemeIs(url::kHttpScheme));
    257 }
    258 
    259 SafeBrowsingBlockingPage::~SafeBrowsingBlockingPage() {
    260 }
    261 
    262 void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
    263   std::string command(cmd);  // Make a local copy so we can modify it.
    264   // The Jasonified response has quotes, remove them.
    265   if (command.length() > 1 && command[0] == '"') {
    266     command = command.substr(1, command.length() - 2);
    267   }
    268   if (command == kDoReportCommand) {
    269     SetReportingPreference(true);
    270     return;
    271   }
    272 
    273   if (command == kDontReportCommand) {
    274     SetReportingPreference(false);
    275     return;
    276   }
    277 
    278   if (command == kLearnMoreCommand) {
    279     // User pressed "Learn more".
    280     RecordUserInteraction(SHOW_LEARN_MORE);
    281     GURL learn_more_url(interstitial_type_ == TYPE_PHISHING ?
    282                         kLearnMorePhishingUrlV2 : kLearnMoreMalwareUrlV2);
    283     learn_more_url = google_util::AppendGoogleLocaleParam(
    284         learn_more_url, g_browser_process->GetApplicationLocale());
    285     OpenURLParams params(learn_more_url,
    286                          Referrer(),
    287                          CURRENT_TAB,
    288                          ui::PAGE_TRANSITION_LINK,
    289                          false);
    290     web_contents_->OpenURL(params);
    291     return;
    292   }
    293 
    294   if (command == kShowPrivacyCommand) {
    295     // User pressed "Safe Browsing privacy policy".
    296     RecordUserInteraction(SHOW_PRIVACY_POLICY);
    297     GURL privacy_url(
    298         l10n_util::GetStringUTF8(IDS_SAFE_BROWSING_PRIVACY_POLICY_URL));
    299     privacy_url = google_util::AppendGoogleLocaleParam(
    300         privacy_url, g_browser_process->GetApplicationLocale());
    301     OpenURLParams params(privacy_url,
    302                          Referrer(),
    303                          CURRENT_TAB,
    304                          ui::PAGE_TRANSITION_LINK,
    305                          false);
    306     web_contents_->OpenURL(params);
    307     return;
    308   }
    309 
    310   bool proceed_blocked = false;
    311   if (command == kProceedCommand) {
    312     if (IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled)) {
    313       proceed_blocked = true;
    314     } else {
    315       RecordUserDecision(PROCEED);
    316       interstitial_page_->Proceed();
    317       // |this| has been deleted after Proceed() returns.
    318       return;
    319     }
    320   }
    321 
    322   if (command == kTakeMeBackCommand || proceed_blocked) {
    323     // Don't record the user action here because there are other ways of
    324     // triggering DontProceed, like clicking the back button.
    325     if (is_main_frame_load_blocked_) {
    326       // If the load is blocked, we want to close the interstitial and discard
    327       // the pending entry.
    328       interstitial_page_->DontProceed();
    329       // |this| has been deleted after DontProceed() returns.
    330       return;
    331     }
    332 
    333     // Otherwise the offending entry has committed, and we need to go back or
    334     // to a safe page.  We will close the interstitial when that page commits.
    335     if (web_contents_->GetController().CanGoBack()) {
    336       web_contents_->GetController().GoBack();
    337     } else {
    338       web_contents_->GetController().LoadURL(
    339           GURL(chrome::kChromeUINewTabURL),
    340           content::Referrer(),
    341           ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
    342           std::string());
    343     }
    344     return;
    345   }
    346 
    347   // The "report error" and "show diagnostic" commands can have a number
    348   // appended to them, which is the index of the element they apply to.
    349   size_t element_index = 0;
    350   size_t colon_index = command.find(':');
    351   if (colon_index != std::string::npos) {
    352     DCHECK(colon_index < command.size() - 1);
    353     int result_int = 0;
    354     bool result = base::StringToInt(base::StringPiece(command.begin() +
    355                                                       colon_index + 1,
    356                                                       command.end()),
    357                                     &result_int);
    358     command = command.substr(0, colon_index);
    359     if (result)
    360       element_index = static_cast<size_t>(result_int);
    361   }
    362 
    363   if (element_index >= unsafe_resources_.size()) {
    364     NOTREACHED();
    365     return;
    366   }
    367 
    368   std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
    369   if (command == kShowDiagnosticCommand) {
    370     // We're going to take the user to Google's SafeBrowsing diagnostic page.
    371     RecordUserInteraction(SHOW_DIAGNOSTIC);
    372     std::string diagnostic =
    373         base::StringPrintf(kSbDiagnosticUrl,
    374             net::EscapeQueryParamValue(bad_url_spec, true).c_str());
    375     GURL diagnostic_url(diagnostic);
    376     diagnostic_url = google_util::AppendGoogleLocaleParam(
    377         diagnostic_url, g_browser_process->GetApplicationLocale());
    378     DCHECK(unsafe_resources_[element_index].threat_type ==
    379            SB_THREAT_TYPE_URL_MALWARE ||
    380            unsafe_resources_[element_index].threat_type ==
    381            SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL);
    382     OpenURLParams params(
    383         diagnostic_url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_LINK,
    384         false);
    385     web_contents_->OpenURL(params);
    386     return;
    387   }
    388 
    389   if (command == kExpandedSeeMoreCommand) {
    390     RecordUserInteraction(SHOW_ADVANCED);
    391     return;
    392   }
    393 
    394   NOTREACHED() << "Unexpected command: " << command;
    395 }
    396 
    397 void SafeBrowsingBlockingPage::OverrideRendererPrefs(
    398       content::RendererPreferences* prefs) {
    399   Profile* profile = Profile::FromBrowserContext(
    400       web_contents_->GetBrowserContext());
    401   renderer_preferences_util::UpdateFromSystemSettings(prefs, profile);
    402  }
    403 
    404 void SafeBrowsingBlockingPage::SetReportingPreference(bool report) {
    405   Profile* profile = Profile::FromBrowserContext(
    406       web_contents_->GetBrowserContext());
    407   PrefService* pref = profile->GetPrefs();
    408   pref->SetBoolean(prefs::kSafeBrowsingExtendedReportingEnabled, report);
    409   UMA_HISTOGRAM_BOOLEAN("SB2.SetExtendedReportingEnabled", report);
    410 }
    411 
    412 void SafeBrowsingBlockingPage::OnProceed() {
    413   proceeded_ = true;
    414   // Send the malware details, if we opted to.
    415   FinishMalwareDetails(malware_details_proceed_delay_ms_);
    416 
    417   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, true);
    418 
    419   // Check to see if some new notifications of unsafe resources have been
    420   // received while we were showing the interstitial.
    421   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
    422   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
    423   SafeBrowsingBlockingPage* blocking_page = NULL;
    424   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
    425     // Build an interstitial for all the unsafe resources notifications.
    426     // Don't show it now as showing an interstitial while an interstitial is
    427     // already showing would cause DontProceed() to be invoked.
    428     blocking_page = factory_->CreateSafeBrowsingPage(ui_manager_, web_contents_,
    429                                                      iter->second);
    430     unsafe_resource_map->erase(iter);
    431   }
    432 
    433   // Now that this interstitial is gone, we can show the new one.
    434   if (blocking_page)
    435     blocking_page->Show();
    436 }
    437 
    438 void SafeBrowsingBlockingPage::DontCreateViewForTesting() {
    439   create_view_ = false;
    440 }
    441 
    442 void SafeBrowsingBlockingPage::Show() {
    443   DCHECK(!interstitial_page_);
    444   interstitial_page_ = InterstitialPage::Create(
    445       web_contents_, is_main_frame_load_blocked_, url_, this);
    446   if (!create_view_)
    447     interstitial_page_->DontCreateViewForTesting();
    448   interstitial_page_->Show();
    449 }
    450 
    451 void SafeBrowsingBlockingPage::OnDontProceed() {
    452   // We could have already called Proceed(), in which case we must not notify
    453   // the SafeBrowsingUIManager again, as the client has been deleted.
    454   if (proceeded_)
    455     return;
    456 
    457   if (!IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled))
    458     RecordUserDecision(DONT_PROCEED);
    459 
    460   // Send the malware details, if we opted to.
    461   FinishMalwareDetails(0);  // No delay
    462 
    463   NotifySafeBrowsingUIManager(ui_manager_, unsafe_resources_, false);
    464 
    465   // The user does not want to proceed, clear the queued unsafe resources
    466   // notifications we received while the interstitial was showing.
    467   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
    468   UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents_);
    469   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
    470     NotifySafeBrowsingUIManager(ui_manager_, iter->second, false);
    471     unsafe_resource_map->erase(iter);
    472   }
    473 
    474   // We don't remove the navigation entry if the tab is being destroyed as this
    475   // would trigger a navigation that would cause trouble as the render view host
    476   // for the tab has by then already been destroyed.  We also don't delete the
    477   // current entry if it has been committed again, which is possible on a page
    478   // that had a subresource warning.
    479   int last_committed_index =
    480       web_contents_->GetController().GetLastCommittedEntryIndex();
    481   if (navigation_entry_index_to_remove_ != -1 &&
    482       navigation_entry_index_to_remove_ != last_committed_index &&
    483       !web_contents_->IsBeingDestroyed()) {
    484     CHECK(web_contents_->GetController().RemoveEntryAtIndex(
    485         navigation_entry_index_to_remove_));
    486     navigation_entry_index_to_remove_ = -1;
    487   }
    488 }
    489 
    490 void SafeBrowsingBlockingPage::OnGotHistoryCount(bool success,
    491                                                  int num_visits,
    492                                                  base::Time first_visit) {
    493   if (success)
    494     num_visits_ = num_visits;
    495 }
    496 
    497 void SafeBrowsingBlockingPage::RecordUserDecision(Decision decision) {
    498   switch (interstitial_type_) {
    499     case TYPE_MALWARE:
    500       UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision",
    501                                 decision,
    502                                 MAX_DECISION);
    503       break;
    504     case TYPE_HARMFUL:
    505       UMA_HISTOGRAM_ENUMERATION("interstitial.harmful.decision",
    506                                 decision,
    507                                 MAX_DECISION);
    508       break;
    509     case TYPE_PHISHING:
    510       UMA_HISTOGRAM_ENUMERATION("interstitial.phishing.decision",
    511                                 decision,
    512                                 MAX_DECISION);
    513       break;
    514   }
    515 
    516 #if defined(ENABLE_EXTENSIONS)
    517   if (sampling_event_.get()) {
    518     switch (decision) {
    519       case PROCEED:
    520         sampling_event_->CreateUserDecisionEvent(
    521             ExperienceSamplingEvent::kProceed);
    522         break;
    523       case DONT_PROCEED:
    524         sampling_event_->CreateUserDecisionEvent(
    525             ExperienceSamplingEvent::kDeny);
    526         break;
    527       case SHOW:
    528       case PROCEEDING_DISABLED:
    529       case MAX_DECISION:
    530         break;
    531     }
    532   }
    533 #endif
    534 
    535   // Record additional information about malware sites that users have
    536   // visited before.
    537   if (num_visits_ < 1 || interstitial_type_ != TYPE_MALWARE)
    538     return;
    539   if (decision == PROCEED || decision == DONT_PROCEED) {
    540     UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision.repeat_visit",
    541                               SHOW,
    542                               MAX_DECISION);
    543     UMA_HISTOGRAM_ENUMERATION("interstitial.malware.decision.repeat_visit",
    544                               decision,
    545                               MAX_DECISION);
    546   }
    547 }
    548 
    549 void SafeBrowsingBlockingPage::RecordUserInteraction(Interaction interaction) {
    550   switch (interstitial_type_) {
    551     case TYPE_MALWARE:
    552       UMA_HISTOGRAM_ENUMERATION("interstitial.malware.interaction",
    553                                 interaction,
    554                                 MAX_INTERACTION);
    555       break;
    556     case TYPE_HARMFUL:
    557       UMA_HISTOGRAM_ENUMERATION("interstitial.harmful.interaction",
    558                                 interaction,
    559                                 MAX_INTERACTION);
    560       break;
    561     case TYPE_PHISHING:
    562       UMA_HISTOGRAM_ENUMERATION("interstitial.phishing.interaction",
    563                                 interaction,
    564                                 MAX_INTERACTION);
    565       break;
    566   }
    567 
    568 #if defined(ENABLE_EXTENSIONS)
    569   if (!sampling_event_.get())
    570     return;
    571   switch (interaction) {
    572     case SHOW_LEARN_MORE:
    573       sampling_event_->set_has_viewed_learn_more(true);
    574       break;
    575     case SHOW_ADVANCED:
    576       sampling_event_->set_has_viewed_details(true);
    577       break;
    578     case SHOW_PRIVACY_POLICY:
    579     case SHOW_DIAGNOSTIC:
    580     case TOTAL_VISITS:
    581     case MAX_INTERACTION:
    582       break;
    583   }
    584 #endif
    585 }
    586 
    587 void SafeBrowsingBlockingPage::FinishMalwareDetails(int64 delay_ms) {
    588   if (malware_details_.get() == NULL)
    589     return;  // Not all interstitials have malware details (eg phishing).
    590 
    591   const bool enabled =
    592       IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled);
    593   UMA_HISTOGRAM_BOOLEAN("SB2.ExtendedReportingIsEnabled", enabled);
    594   if (enabled) {
    595     // Finish the malware details collection, send it over.
    596     BrowserThread::PostDelayedTask(
    597         BrowserThread::IO, FROM_HERE,
    598         base::Bind(&MalwareDetails::FinishCollection, malware_details_.get()),
    599         base::TimeDelta::FromMilliseconds(delay_ms));
    600   }
    601 }
    602 
    603 bool SafeBrowsingBlockingPage::IsPrefEnabled(const char* pref) {
    604   Profile* profile =
    605       Profile::FromBrowserContext(web_contents_->GetBrowserContext());
    606   return profile->GetPrefs()->GetBoolean(pref);
    607 }
    608 
    609 // static
    610 void SafeBrowsingBlockingPage::NotifySafeBrowsingUIManager(
    611     SafeBrowsingUIManager* ui_manager,
    612     const UnsafeResourceList& unsafe_resources,
    613     bool proceed) {
    614   BrowserThread::PostTask(
    615       BrowserThread::IO, FROM_HERE,
    616       base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
    617                  ui_manager, unsafe_resources, proceed));
    618 }
    619 
    620 // static
    621 SafeBrowsingBlockingPage::UnsafeResourceMap*
    622     SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
    623   return g_unsafe_resource_map.Pointer();
    624 }
    625 
    626 // static
    627 SafeBrowsingBlockingPage* SafeBrowsingBlockingPage::CreateBlockingPage(
    628     SafeBrowsingUIManager* ui_manager,
    629     WebContents* web_contents,
    630     const UnsafeResource& unsafe_resource) {
    631   std::vector<UnsafeResource> resources;
    632   resources.push_back(unsafe_resource);
    633   // Set up the factory if this has not been done already (tests do that
    634   // before this method is called).
    635   if (!factory_)
    636     factory_ = g_safe_browsing_blocking_page_factory_impl.Pointer();
    637   return factory_->CreateSafeBrowsingPage(ui_manager, web_contents, resources);
    638 }
    639 
    640 // static
    641 void SafeBrowsingBlockingPage::ShowBlockingPage(
    642     SafeBrowsingUIManager* ui_manager,
    643     const UnsafeResource& unsafe_resource) {
    644   DVLOG(1) << __FUNCTION__ << " " << unsafe_resource.url.spec();
    645   WebContents* web_contents = tab_util::GetWebContentsByID(
    646       unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
    647 
    648   InterstitialPage* interstitial =
    649       InterstitialPage::GetInterstitialPage(web_contents);
    650   if (interstitial && !unsafe_resource.is_subresource) {
    651     // There is already an interstitial showing and we are about to display a
    652     // new one for the main frame. Just hide the current one, it is now
    653     // irrelevent
    654     interstitial->DontProceed();
    655     interstitial = NULL;
    656   }
    657 
    658   if (!interstitial) {
    659     // There are no interstitial currently showing in that tab, go ahead and
    660     // show this interstitial.
    661     SafeBrowsingBlockingPage* blocking_page =
    662         CreateBlockingPage(ui_manager, web_contents, unsafe_resource);
    663     blocking_page->Show();
    664     return;
    665   }
    666 
    667   // This is an interstitial for a page's resource, let's queue it.
    668   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
    669   (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
    670 }
    671 
    672 // static
    673 bool SafeBrowsingBlockingPage::IsMainPageLoadBlocked(
    674     const UnsafeResourceList& unsafe_resources) {
    675   // Client-side phishing detection interstitials never block the main frame
    676   // load, since they happen after the page is finished loading.
    677   if (unsafe_resources[0].threat_type ==
    678       SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) {
    679     return false;
    680   }
    681 
    682   // Otherwise, check the threat type.
    683   return unsafe_resources.size() == 1 && !unsafe_resources[0].is_subresource;
    684 }
    685 
    686 std::string SafeBrowsingBlockingPage::GetHTMLContents() {
    687   DCHECK(!unsafe_resources_.empty());
    688 
    689   // Fill in the shared values.
    690   base::DictionaryValue load_time_data;
    691   webui::SetFontAndTextDirection(&load_time_data);
    692   load_time_data.SetBoolean("ssl", false);
    693   load_time_data.SetString(
    694       "tabTitle", l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_TITLE));
    695   load_time_data.SetString(
    696       "openDetails",
    697       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_OPEN_DETAILS_BUTTON));
    698   load_time_data.SetString(
    699       "closeDetails",
    700       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_V3_CLOSE_DETAILS_BUTTON));
    701   load_time_data.SetString(
    702       "primaryButtonText",
    703       l10n_util::GetStringUTF16(IDS_SAFEBROWSING_OVERRIDABLE_SAFETY_BUTTON));
    704   load_time_data.SetBoolean(
    705       "overridable",
    706       !IsPrefEnabled(prefs::kSafeBrowsingProceedAnywayDisabled));
    707 
    708   switch (interstitial_type_) {
    709     case TYPE_MALWARE:
    710       PopulateMalwareLoadTimeData(&load_time_data);
    711       break;
    712     case TYPE_HARMFUL:
    713       PopulateHarmfulLoadTimeData(&load_time_data);
    714       break;
    715     case TYPE_PHISHING:
    716       PopulatePhishingLoadTimeData(&load_time_data);
    717       break;
    718   }
    719 
    720   base::StringPiece html(
    721       ResourceBundle::GetSharedInstance().GetRawDataResource(
    722           IRD_SECURITY_INTERSTITIAL_HTML));
    723   webui::UseVersion2 version;
    724   return webui::GetI18nTemplateHtml(html, &load_time_data);
    725 }
    726 
    727 void SafeBrowsingBlockingPage::PopulateMalwareLoadTimeData(
    728     base::DictionaryValue* load_time_data) {
    729   load_time_data->SetBoolean("phishing", false);
    730   load_time_data->SetString(
    731       "heading", l10n_util::GetStringUTF16(IDS_MALWARE_V3_HEADING));
    732   load_time_data->SetString(
    733       "primaryParagraph",
    734       l10n_util::GetStringFUTF16(
    735           IDS_MALWARE_V3_PRIMARY_PARAGRAPH,
    736           base::UTF8ToUTF16(url_.host())));
    737   load_time_data->SetString(
    738       "explanationParagraph",
    739       is_main_frame_load_blocked_ ?
    740           l10n_util::GetStringFUTF16(
    741               IDS_MALWARE_V3_EXPLANATION_PARAGRAPH,
    742               base::UTF8ToUTF16(url_.host())) :
    743           l10n_util::GetStringFUTF16(
    744               IDS_MALWARE_V3_EXPLANATION_PARAGRAPH_SUBRESOURCE,
    745               base::UTF8ToUTF16(web_contents_->GetURL().host()),
    746               base::UTF8ToUTF16(url_.host())));
    747   load_time_data->SetString(
    748       "finalParagraph",
    749       l10n_util::GetStringUTF16(IDS_MALWARE_V3_PROCEED_PARAGRAPH));
    750 
    751   load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
    752   if (CanShowMalwareDetailsOption()) {
    753     std::string privacy_link = base::StringPrintf(
    754         kPrivacyLinkHtml,
    755         l10n_util::GetStringUTF8(
    756             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
    757     load_time_data->SetString(
    758         "optInLink",
    759         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
    760                                    base::UTF8ToUTF16(privacy_link)));
    761     load_time_data->SetBoolean(
    762         kBoxChecked,
    763         IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled));
    764   }
    765 }
    766 
    767 void SafeBrowsingBlockingPage::PopulateHarmfulLoadTimeData(
    768     base::DictionaryValue* load_time_data) {
    769   load_time_data->SetBoolean("phishing", false);
    770   load_time_data->SetString(
    771       "heading", l10n_util::GetStringUTF16(IDS_HARMFUL_V3_HEADING));
    772   load_time_data->SetString(
    773       "primaryParagraph",
    774       l10n_util::GetStringFUTF16(
    775           IDS_HARMFUL_V3_PRIMARY_PARAGRAPH,
    776           base::UTF8ToUTF16(url_.host())));
    777   load_time_data->SetString(
    778       "explanationParagraph",
    779       l10n_util::GetStringFUTF16(
    780           IDS_HARMFUL_V3_EXPLANATION_PARAGRAPH,
    781           base::UTF8ToUTF16(url_.host())));
    782   load_time_data->SetString(
    783       "finalParagraph",
    784       l10n_util::GetStringUTF16(IDS_HARMFUL_V3_PROCEED_PARAGRAPH));
    785 
    786   load_time_data->SetBoolean(kDisplayCheckBox, CanShowMalwareDetailsOption());
    787   if (CanShowMalwareDetailsOption()) {
    788     std::string privacy_link = base::StringPrintf(
    789         kPrivacyLinkHtml,
    790         l10n_util::GetStringUTF8(
    791             IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE).c_str());
    792     load_time_data->SetString(
    793         "optInLink",
    794         l10n_util::GetStringFUTF16(IDS_SAFE_BROWSING_MALWARE_REPORTING_AGREE,
    795                                    base::UTF8ToUTF16(privacy_link)));
    796     load_time_data->SetBoolean(
    797         kBoxChecked,
    798         IsPrefEnabled(prefs::kSafeBrowsingExtendedReportingEnabled));
    799   }
    800 }
    801 
    802 void SafeBrowsingBlockingPage::PopulatePhishingLoadTimeData(
    803     base::DictionaryValue* load_time_data) {
    804   load_time_data->SetBoolean("phishing", true);
    805   load_time_data->SetString(
    806       "heading",
    807       l10n_util::GetStringUTF16(IDS_PHISHING_V3_HEADING));
    808   load_time_data->SetString(
    809       "primaryParagraph",
    810       l10n_util::GetStringFUTF16(
    811           IDS_PHISHING_V3_PRIMARY_PARAGRAPH,
    812           base::UTF8ToUTF16(url_.host())));
    813   load_time_data->SetString(
    814       "explanationParagraph",
    815       l10n_util::GetStringFUTF16(IDS_PHISHING_V3_EXPLANATION_PARAGRAPH,
    816                                  base::UTF8ToUTF16(url_.host())));
    817   load_time_data->SetString(
    818       "finalParagraph",
    819       l10n_util::GetStringUTF16(IDS_PHISHING_V3_PROCEED_PARAGRAPH));
    820 }
    821