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