summaryrefslogtreecommitdiffstats
path: root/chrome/browser/safe_browsing
diff options
context:
space:
mode:
authorjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-23 21:05:34 +0000
committerjcampan@chromium.org <jcampan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-01-23 21:05:34 +0000
commit1b277e7f6d171b9cb2383f925373ffedcd3e4672 (patch)
tree931b42af6d84753cb1d24c1eec80e913f104c625 /chrome/browser/safe_browsing
parentdeb17b8d4fc8ef1bc2222bbb83414d6983fd7d02 (diff)
downloadchromium_src-1b277e7f6d171b9cb2383f925373ffedcd3e4672.zip
chromium_src-1b277e7f6d171b9cb2383f925373ffedcd3e4672.tar.gz
chromium_src-1b277e7f6d171b9cb2383f925373ffedcd3e4672.tar.bz2
This CL makes the safe browsing interstitial page support multiple unsafe resources in one page.
We had a bug when an interstitial was showing and another unsafe resource was detected. We would show another interstitial on top of the original one, causing the DontProceed method to be invoked several times. That would cause us to remove more than once an entry from the navigation controller and cause crashers. With this new CL, if an interstitial shows and a new resource is flagged as bad, the SafeBrowsingBlockingPage will queue that notification. If the user decides to proceed through the interstitial, we'll create another interstitial warning about all the unsafe resources we have received so far. This CL also contains a fix for a crasher that would happen when closing a tab with a safe browsing interstitial. BUG=5916,6207,6306 TEST=Test all actions in the interstitial you get when opening pages with the followin scenarios: - Main page is malware - Main page is fishing - Main page is OK contains resources (images,iframes...) which are malware - Main page is OK contains resources (images,iframes...) which are phishing - Main page is OK contains resources (images,iframes...) some of them phishing, some of then malware. Note that when there are more than one bad resource, it is normal to see a 1st interstitial, then another one listing all the other bad resources. (ex of malware site http://ianfette.org, phishing site http://cvisit.tripod.com) Review URL: http://codereview.chromium.org/18346 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@8578 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/safe_browsing')
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.cc433
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_blocking_page.h89
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.cc62
-rw-r--r--chrome/browser/safe_browsing/safe_browsing_service.h12
4 files changed, 426 insertions, 170 deletions
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 4d34450..c6b6feb 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -6,6 +6,7 @@
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
+#include "base/string_util.h"
#include "chrome/app/locales/locale_settings.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_resources.h"
@@ -38,23 +39,25 @@ static const char* const kSbReportPhishingUrl =
"http://www.google.com/safebrowsing/report_error/";
static const wchar_t* const kSbDiagnosticHtml =
- L"<a href=\"\" onClick=\"sendCommand(4); return false;\" onMouseDown=\"return false;\">%ls</a>";
+ L"<a href=\"\" onClick=\"sendCommand('showDiagnostic'); return false;\" onMouseDown=\"return false;\">%ls</a>";
+
+// The commands returned by the page when the user performs an action.
+static const char* const kShowDiagnosticCommand = "showDiagnostic";
+static const char* const kReportErrorCommand = "reportError";
+static const char* const kLearnMoreCommand = "learnMore";
+static const char* const kProceedCommand = "proceed";
+static const char* const kTakeMeBackCommand = "takeMeBack";
SafeBrowsingBlockingPage::SafeBrowsingBlockingPage(
SafeBrowsingService* sb_service,
- const SafeBrowsingService::BlockingPageParam& param)
- : InterstitialPage(tab_util::GetWebContentsByID(
- param.render_process_host_id, param.render_view_id),
- param.resource_type == ResourceType::MAIN_FRAME,
- param.url),
+ WebContents* web_contents,
+ const UnsafeResourceList& unsafe_resources)
+ : InterstitialPage(web_contents,
+ IsMainPage(unsafe_resources),
+ unsafe_resources[0].url),
sb_service_(sb_service),
- client_(param.client),
- render_process_host_id_(param.render_process_host_id),
- render_view_id_(param.render_view_id),
- result_(param.result),
- proceed_(false),
- did_notify_(false),
- is_main_frame_(param.resource_type == ResourceType::MAIN_FRAME) {
+ unsafe_resources_(unsafe_resources),
+ is_main_frame_(IsMainPage(unsafe_resources)) {
if (!is_main_frame_) {
navigation_entry_index_to_remove_ =
tab()->controller()->GetLastCommittedEntryIndex();
@@ -72,84 +75,200 @@ std::string SafeBrowsingBlockingPage::GetHTMLContents() {
ResourceBundle& rb = ResourceBundle::GetSharedInstance();
std::string html;
- if (result_ == SafeBrowsingService::URL_MALWARE) {
- std::wstring link = StringPrintf(kSbDiagnosticHtml,
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).
- c_str());
-
- strings.SetString(L"badURL", UTF8ToWide(url().host()));
- strings.SetString(L"title",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_TITLE));
- strings.SetString(L"headLine",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_HEADLINE));
-
- // Check to see if we're blocking the main page, or a sub-resource on the
- // main page.
- if (is_main_frame_) {
- strings.SetString(L"description1",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION1,
- UTF8ToWide(url().host())));
- strings.SetString(L"description2",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION2,
- link,
- UTF8ToWide(url().host())));
- } else {
- strings.SetString(L"description1",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION4,
- UTF8ToWide(tab()->GetURL().host()),
- UTF8ToWide(url().host())));
- strings.SetString(L"description2",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION5,
- link,
- UTF8ToWide(url().host())));
- }
+ if (unsafe_resources_.empty()) {
+ NOTREACHED();
+ return std::string();
+ }
- strings.SetString(L"description3",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3));
- strings.SetString(L"confirm_text",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
- strings.SetString(L"continue_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
- strings.SetString(L"back_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
- strings.SetString(L"textdirection",
- (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
- L"rtl" : L"ltr");
+ if (unsafe_resources_.size() > 1) {
+ PopulateMultipleThreatStringDictionary(&strings);
+ html = rb.GetDataResource(IDR_SAFE_BROWSING_MULTIPLE_THREAT_BLOCK);
+ } else if (unsafe_resources_[0].threat_type ==
+ SafeBrowsingService::URL_MALWARE) {
+ PopulateMalwareStringDictionary(&strings);
html = rb.GetDataResource(IDR_SAFE_BROWSING_MALWARE_BLOCK);
} else { // Phishing.
- strings.SetString(L"title",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_TITLE));
- strings.SetString(L"headLine",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_HEADLINE));
- strings.SetString(L"description1",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION1,
- UTF8ToWide(url().host())));
- strings.SetString(L"description2",
- l10n_util::GetStringF(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION2,
- UTF8ToWide(url().host())));
-
- strings.SetString(L"continue_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_PROCEED_BUTTON));
- strings.SetString(L"back_button",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
- strings.SetString(L"report_error",
- l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
- strings.SetString(L"textdirection",
- (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
- L"rtl" : L"ltr");
+ DCHECK(unsafe_resources_[0].threat_type ==
+ SafeBrowsingService::URL_PHISHING);
+ PopulatePhishingStringDictionary(&strings);
html = rb.GetDataResource(IDR_SAFE_BROWSING_PHISHING_BLOCK);
}
return jstemplate_builder::GetTemplateHtml(html, &strings, "template_root");
}
-void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) {
- if (command == "2") {
+void SafeBrowsingBlockingPage::PopulateStringDictionary(
+ DictionaryValue* strings,
+ const std::wstring& title,
+ const std::wstring& headline,
+ const std::wstring& description1,
+ const std::wstring& description2,
+ const std::wstring& description3) {
+ strings->SetString(L"title", title);
+ strings->SetString(L"headLine", headline);
+ strings->SetString(L"description1", description1);
+ strings->SetString(L"description2", description2);
+ strings->SetString(L"description3", description3);
+}
+
+void SafeBrowsingBlockingPage::PopulateMultipleThreatStringDictionary(
+ DictionaryValue* strings) {
+ bool malware = false;
+ bool phishing = false;
+
+ std::wstring phishing_label =
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_LABEL);
+ std::wstring phishing_link =
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR);
+ std::wstring malware_label =
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_LABEL);
+ std::wstring malware_link =
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE);
+
+ ListValue* error_strings = new ListValue;
+ for (UnsafeResourceList::const_iterator iter = unsafe_resources_.begin();
+ iter != unsafe_resources_.end(); ++iter) {
+ const SafeBrowsingService::UnsafeResource& resource = *iter;
+ DictionaryValue* current_error_strings = new DictionaryValue;
+ if (resource.threat_type == SafeBrowsingService::URL_MALWARE) {
+ malware = true;
+ current_error_strings->SetString(L"type", L"malware");
+ current_error_strings->SetString(L"typeLabel", malware_label);
+ current_error_strings->SetString(L"errorLink", malware_link);
+ } else {
+ DCHECK(resource.threat_type == SafeBrowsingService::URL_PHISHING);
+ phishing = true;
+ current_error_strings->SetString(L"type", L"phishing");
+ current_error_strings->SetString(L"typeLabel", phishing_label);
+ current_error_strings->SetString(L"errorLink", phishing_link);
+ }
+ current_error_strings->SetString(L"url", UTF8ToWide(resource.url.spec()));
+ error_strings->Append(current_error_strings);
+ }
+ strings->Set(L"errors", error_strings);
+ DCHECK(phishing || malware);
+
+ if (malware && phishing) {
+ PopulateStringDictionary(
+ strings,
+ // Use the malware headline, it is the scariest one.
+ l10n_util::GetString(IDS_SAFE_BROWSING_MULTI_THREAT_TITLE),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
+ l10n_util::GetStringF(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION1,
+ UTF8ToWide(tab()->GetURL().host())),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MULTI_THREAT_DESCRIPTION2),
+ L"");
+ } else if (malware) {
+ // Just malware.
+ PopulateStringDictionary(
+ strings,
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_TITLE),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
+ l10n_util::GetStringF(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION1,
+ UTF8ToWide(tab()->GetURL().host())),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MULTI_MALWARE_DESCRIPTION2),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3));
+ } else {
+ // Just phishing.
+ PopulateStringDictionary(
+ strings,
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_TITLE),
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
+ l10n_util::GetStringF(IDS_SAFE_BROWSING_MULTI_PHISHING_DESCRIPTION1,
+ UTF8ToWide(tab()->GetURL().host())),
+ L"", L"");
+ }
+
+ strings->SetString(L"confirm_text",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
+ strings->SetString(L"continue_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
+ strings->SetString(L"back_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
+ strings->SetString(L"textdirection",
+ (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
+ L"rtl" : L"ltr");
+}
+
+void SafeBrowsingBlockingPage::PopulateMalwareStringDictionary(
+ DictionaryValue* strings) {
+ std::wstring link = StringPrintf(kSbDiagnosticHtml,
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DIAGNOSTIC_PAGE).c_str());
+
+ strings->SetString(L"badURL", UTF8ToWide(url().host()));
+ // Check to see if we're blocking the main page, or a sub-resource on the
+ // main page.
+ std::wstring description1, description2;
+ if (is_main_frame_) {
+ description1 = l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION1,
+ UTF8ToWide(url().host()));
+ description2 = l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION2,
+ link,
+ UTF8ToWide(url().host()));
+ } else {
+ description1 = l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION4,
+ UTF8ToWide(tab()->GetURL().host()),
+ UTF8ToWide(url().host()));
+ description2 = l10n_util::GetStringF(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION5,
+ link,
+ UTF8ToWide(url().host()));
+ }
+
+ PopulateStringDictionary(
+ strings,
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_TITLE),
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_HEADLINE),
+ description1, description2,
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION3));
+
+ strings->SetString(L"confirm_text",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_DESCRIPTION_AGREE));
+ strings->SetString(L"continue_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_PROCEED_BUTTON));
+ strings->SetString(L"back_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_MALWARE_BACK_BUTTON));
+ strings->SetString(L"textdirection",
+ (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
+ L"rtl" : L"ltr");
+}
+
+void SafeBrowsingBlockingPage::PopulatePhishingStringDictionary(
+ DictionaryValue* strings) {
+ PopulateStringDictionary(
+ strings,
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_TITLE),
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_HEADLINE),
+ l10n_util::GetStringF(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION1,
+ UTF8ToWide(url().host())),
+ l10n_util::GetStringF(IDS_SAFE_BROWSING_PHISHING_DESCRIPTION2,
+ UTF8ToWide(url().host())),
+ L"");
+
+ strings->SetString(L"continue_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_PROCEED_BUTTON));
+ strings->SetString(L"back_button",
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_BACK_BUTTON));
+ strings->SetString(L"report_error",
+ l10n_util::GetString(IDS_SAFE_BROWSING_PHISHING_REPORT_ERROR));
+ strings->SetString(L"textdirection",
+ (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
+ L"rtl" : L"ltr");
+}
+
+void SafeBrowsingBlockingPage::CommandReceived(const std::string& cmd) {
+ std::string command(cmd); // Make a local copy so we can modify it.
+ // The Jasonified response has quotes, remove them.
+ if (command.length() > 1 && command[0] == '"') {
+ command = command.substr(1, command.length() - 2);
+ }
+
+ if (command == kLearnMoreCommand) {
// User pressed "Learn more".
GURL url;
- if (result_ == SafeBrowsingService::URL_MALWARE) {
+ if (unsafe_resources_[0].threat_type == SafeBrowsingService::URL_MALWARE) {
url = GURL(l10n_util::GetString(IDS_LEARN_MORE_MALWARE_URL));
- } else if (result_ == SafeBrowsingService::URL_PHISHING) {
+ } else if (unsafe_resources_[0].threat_type ==
+ SafeBrowsingService::URL_PHISHING) {
url = GURL(l10n_util::GetString(IDS_LEARN_MORE_PHISHING_URL));
} else {
NOTREACHED();
@@ -157,68 +276,164 @@ void SafeBrowsingBlockingPage::CommandReceived(const std::string& command) {
tab()->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
- if (command == "3") {
+
+ if (command == kProceedCommand) {
+ Proceed();
+ // We are deleted after this.
+ return;
+ }
+
+ if (command == kTakeMeBackCommand) {
+ DontProceed();
+ // We are deleted after this.
+ return;
+ }
+
+ // The "report error" and "show diagnostic" commands can have a number
+ // appended to them, which is the index of the element they apply to.
+ int element_index = 0;
+ size_t colon_index = command.find(':');
+ if (colon_index != std::string::npos) {
+ DCHECK(colon_index < command.size() - 1);
+ std::string index_str = command.substr(colon_index + 1);
+ command = command.substr(0, colon_index);
+ bool result = StringToInt(index_str, &element_index);
+ DCHECK(result);
+ }
+
+ if (element_index >= static_cast<int>(unsafe_resources_.size())) {
+ NOTREACHED();
+ return;
+ }
+
+ std::string bad_url_spec = unsafe_resources_[element_index].url.spec();
+ if (command == kReportErrorCommand) {
// User pressed "Report error" for a phishing site.
// Note that we cannot just put a link in the interstitial at this point.
// It is not OK to navigate in the context of an interstitial page.
- DCHECK(result_ == SafeBrowsingService::URL_PHISHING);
+ DCHECK(unsafe_resources_[element_index].threat_type ==
+ SafeBrowsingService::URL_PHISHING);
GURL report_url =
safe_browsing_util::GeneratePhishingReportUrl(kSbReportPhishingUrl,
- url().spec());
- Hide();
+ bad_url_spec);
tab()->OpenURL(report_url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
- if (command == "4") {
+
+ if (command == kShowDiagnosticCommand) {
// We're going to take the user to Google's SafeBrowsing diagnostic page.
std::string diagnostic =
StringPrintf(kSbDiagnosticUrl,
- EscapeQueryParamValue(url().spec()).c_str());
+ EscapeQueryParamValue(bad_url_spec).c_str());
GURL diagnostic_url(diagnostic);
diagnostic_url = google_util::AppendGoogleLocaleParam(diagnostic_url);
- DCHECK(result_ == SafeBrowsingService::URL_MALWARE);
+ DCHECK(unsafe_resources_[element_index].threat_type ==
+ SafeBrowsingService::URL_MALWARE);
tab()->OpenURL(diagnostic_url, GURL(), CURRENT_TAB, PageTransition::LINK);
return;
}
- proceed_ = command == "1";
+ NOTREACHED() << "Unexpected command: " << command;
+}
- if (proceed_)
- Proceed();
- else
- DontProceed();
+void SafeBrowsingBlockingPage::Proceed() {
+ NotifySafeBrowsingService(sb_service_, unsafe_resources_, true);
+
+ // Check to see if some new notifications of unsafe resources have been
+ // received while we were showing the interstitial.
+ UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
+ UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
+ SafeBrowsingBlockingPage* blocking_page = NULL;
+ if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
+ // Build an interstitial for all the unsafe resources notifications.
+ // Don't show it now as showing an interstitial while an interstitial is
+ // already showing would cause DontProceed() to be invoked.
+ blocking_page = new SafeBrowsingBlockingPage(sb_service_, tab(),
+ iter->second);
+ unsafe_resource_map->erase(iter);
+ }
- NotifyDone();
+ InterstitialPage::Proceed();
+ // We are now deleted.
+
+ // Now that this interstitial is gone, we can show the new one.
+ if (blocking_page)
+ blocking_page->Show();
}
void SafeBrowsingBlockingPage::DontProceed() {
- if (navigation_entry_index_to_remove_ != -1) {
+ NotifySafeBrowsingService(sb_service_, unsafe_resources_, false);
+
+ // The user does not want to proceed, clear the queued unsafe resources
+ // notifications we received while the interstitial was showing.
+ UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
+ UnsafeResourceMap::iterator iter = unsafe_resource_map->find(tab());
+ if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
+ NotifySafeBrowsingService(sb_service_, iter->second, false);
+ unsafe_resource_map->erase(iter);
+ }
+
+ // We don't remove the navigation entry if the tab is being destroyed as this
+ // would trigger a navigation that would cause trouble as the render view host
+ // for the tab has by then already been destroyed.
+ if (navigation_entry_index_to_remove_ != -1 && !tab()->is_being_destroyed()) {
tab()->controller()->RemoveEntryAtIndex(navigation_entry_index_to_remove_,
NewTabUIURL());
+ navigation_entry_index_to_remove_ = -1;
}
InterstitialPage::DontProceed();
// We are now deleted.
}
-void SafeBrowsingBlockingPage::NotifyDone() {
- if (did_notify_)
- return;
-
- did_notify_ = true;
-
+// static
+void SafeBrowsingBlockingPage::NotifySafeBrowsingService(
+ SafeBrowsingService* sb_service,
+ const UnsafeResourceList& unsafe_resources,
+ bool proceed) {
base::Thread* io_thread = g_browser_process->io_thread();
if (!io_thread)
return;
- SafeBrowsingService::BlockingPageParam param;
- param.url = url();
- param.result = result_;
- param.client = client_;
- param.render_process_host_id = render_process_host_id_;
- param.render_view_id = render_view_id_;
- param.proceed = proceed_;
io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- sb_service_,
- &SafeBrowsingService::OnBlockingPageDone,
- param));
+ sb_service, &SafeBrowsingService::OnBlockingPageDone, unsafe_resources,
+ proceed));
+}
+
+// static
+SafeBrowsingBlockingPage::UnsafeResourceMap*
+ SafeBrowsingBlockingPage::GetUnsafeResourcesMap() {
+ return Singleton<UnsafeResourceMap>::get();
+}
+
+// static
+void SafeBrowsingBlockingPage::ShowBlockingPage(
+ SafeBrowsingService* sb_service,
+ const SafeBrowsingService::UnsafeResource& unsafe_resource) {
+ WebContents* web_contents = tab_util::GetWebContentsByID(
+ unsafe_resource.render_process_host_id, unsafe_resource.render_view_id);
+
+ if (!InterstitialPage::GetInterstitialPage(web_contents)) {
+ // There are no interstitial currently showing in that tab, go ahead and
+ // show this interstitial.
+ std::vector<SafeBrowsingService::UnsafeResource> resources;
+ resources.push_back(unsafe_resource);
+ SafeBrowsingBlockingPage* blocking_page =
+ new SafeBrowsingBlockingPage(sb_service, web_contents, resources);
+ blocking_page->Show();
+ return;
+ }
+
+ // Let's queue the interstitial.
+ // Note we only expect resources from the page at this point.
+ DCHECK(unsafe_resource.resource_type != ResourceType::MAIN_FRAME);
+ UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
+ (*unsafe_resource_map)[web_contents].push_back(unsafe_resource);
+}
+
+// static
+bool SafeBrowsingBlockingPage::IsMainPage(
+ const UnsafeResourceList& unsafe_resources) {
+ return unsafe_resources.size() == 1 &&
+ unsafe_resources[0].resource_type == ResourceType::MAIN_FRAME;
}
+
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
index 7b94290..8e3d1fd 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.h
@@ -17,27 +17,47 @@
// The blocking page forwards the result of the user's choice back to the
// SafeBrowsingService so that we can cancel the request for the new page, or
// or allow it to continue.
+//
+// A web page may contain several resources flagged as malware/phishing. This
+// results into more than one interstitial being shown. On the first unsafe
+// resource received we show an interstitial. Any subsequent unsafe resource
+// notifications while the first interstitial is showing is queued. If the user
+// decides to proceed in the first interstitial, we display all queued unsafe
+// resources in a new interstitial.
#ifndef CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
#define CHROME_BROWSER_SAFE_BROWSING_SAFE_BROWSING_BLOCKING_PAGE_H_
+#include <map>
+#include <vector>
+
#include "base/logging.h"
#include "chrome/browser/tab_contents/interstitial_page.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "googleurl/src/gurl.h"
+class DictionaryValue;
class MessageLoop;
-class TabContents;
class NavigationController;
+class WebContents;
+
class SafeBrowsingBlockingPage : public InterstitialPage {
public:
- SafeBrowsingBlockingPage(SafeBrowsingService* service,
- const SafeBrowsingService::BlockingPageParam& param);
virtual ~SafeBrowsingBlockingPage();
+ // Shows a blocking page warning the user about phishing/malware for a
+ // specific resource.
+ // You can call this method several times, if an interstitial is already
+ // showing, the new one will be queued and displayed if the user decides
+ // to proceed on the currently showing interstitial.
+ static void ShowBlockingPage(
+ SafeBrowsingService* service,
+ const SafeBrowsingService::UnsafeResource& resource);
+
// InterstitialPage method:
virtual std::string GetHTMLContents();
+ virtual void Proceed();
virtual void DontProceed();
protected:
@@ -45,34 +65,48 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
virtual void CommandReceived(const std::string& command);
private:
- // Tells the SafeBrowsingService that the handling of the current page is
- // done.
- void NotifyDone();
+ typedef std::vector<SafeBrowsingService::UnsafeResource> UnsafeResourceList;
+
+ // Don't instanciate this class directly, use ShowBlockingPage instead.
+ SafeBrowsingBlockingPage(SafeBrowsingService* service,
+ WebContents* web_contents,
+ const UnsafeResourceList& unsafe_resources);
+
+ // Fills the passed dictionary with the strings passed to JS Template when
+ // creating the HTML.
+ void PopulateMultipleThreatStringDictionary(DictionaryValue* strings);
+ void PopulateMalwareStringDictionary(DictionaryValue* strings);
+ void PopulatePhishingStringDictionary(DictionaryValue* strings);
+
+ // A helper method used by the Populate methods above used to populate common
+ // fields.
+ void PopulateStringDictionary(DictionaryValue* strings,
+ const std::wstring& title,
+ const std::wstring& headline,
+ const std::wstring& description1,
+ const std::wstring& description2,
+ const std::wstring& description3);
+
+
+ // A list of SafeBrowsingService::UnsafeResource for a tab that the user
+ // should be warned about. They are queued when displaying more than one
+ // interstitial at a time.
+ typedef std::map<WebContents*, UnsafeResourceList> UnsafeResourceMap;
+ static UnsafeResourceMap* GetUnsafeResourcesMap();
+
+ // Notifies the SafeBrowsingService on the IO thread whether to proceed or not
+ // for the |resources|.
+ static void NotifySafeBrowsingService(SafeBrowsingService* sb_service,
+ const UnsafeResourceList& resources,
+ bool proceed);
+
+ // Returns true if the passed |unsafe_resources| is for the main page.
+ static bool IsMainPage(const UnsafeResourceList& unsafe_resources);
private:
// For reporting back user actions.
SafeBrowsingService* sb_service_;
- SafeBrowsingService::Client* client_;
MessageLoop* report_loop_;
- SafeBrowsingService::UrlCheckResult result_;
-
- // For determining which tab to block (note that we need this even though we
- // have access to the tab as when the interstitial is showing, retrieving the
- // tab RPH and RV id would return the ones of the interstitial, not the ones
- // for the page containing the malware).
- // TODO(jcampan): when we refactor the interstitial to run as a separate view
- // that does not interact with the WebContents as much, we can
- // get rid of these.
- int render_process_host_id_;
- int render_view_id_;
-
- // Inform the SafeBrowsingService whether we are continuing with this page
- // load or going back to the previous page.
- bool proceed_;
-
- // Whether we have notify the SafeBrowsingService yet that a decision had been
- // made whether to proceed or block the unsafe resource.
- bool did_notify_;
// Whether the flagged resource is the main page (or a sub-resource is false).
bool is_main_frame_;
@@ -81,6 +115,9 @@ class SafeBrowsingBlockingPage : public InterstitialPage {
// is invoked, -1 if not entry should be removed.
int navigation_entry_index_to_remove_;
+ // The list of unsafe resources this page is warning about.
+ UnsafeResourceList unsafe_resources_;
+
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingBlockingPage);
};
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index 14f31bc..ba6701e 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -267,39 +267,37 @@ void SafeBrowsingService::DisplayBlockingPage(const GURL& url,
}
}
- BlockingPageParam param;
- param.url = url;
- param.resource_type = resource_type;
- param.result = result;
- param.client = client;
- param.render_process_host_id = render_process_host_id;
- param.render_view_id = render_view_id;
+ UnsafeResource resource;
+ resource.url = url;
+ resource.resource_type = resource_type;
+ resource.threat_type= result;
+ resource.client = client;
+ resource.render_process_host_id = render_process_host_id;
+ resource.render_view_id = render_view_id;
// The blocking page must be created from the UI thread.
ui_loop->PostTask(FROM_HERE, NewRunnableMethod(this,
&SafeBrowsingService::DoDisplayBlockingPage,
- param));
+ resource));
}
// Invoked on the UI thread.
void SafeBrowsingService::DoDisplayBlockingPage(
- const BlockingPageParam& param) {
+ const UnsafeResource& resource) {
// The tab might have been closed.
- if (!tab_util::GetWebContentsByID(param.render_process_host_id,
- param.render_view_id)) {
+ if (!tab_util::GetWebContentsByID(resource.render_process_host_id,
+ resource.render_view_id)) {
// The tab is gone and we did not have a chance at showing the interstitial.
// Just act as "Don't Proceed" was chosen.
base::Thread* io_thread = g_browser_process->io_thread();
if (!io_thread)
return;
- BlockingPageParam response_param = param;
- response_param.proceed = false;
+ std::vector<UnsafeResource> resources;
+ resources.push_back(resource);
io_thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
- this, &SafeBrowsingService::OnBlockingPageDone, response_param));
+ this, &SafeBrowsingService::OnBlockingPageDone, resources, false));
return;
}
- SafeBrowsingBlockingPage* blocking_page = new SafeBrowsingBlockingPage(this,
- param);
- blocking_page->Show();
+ SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
}
void SafeBrowsingService::CancelCheck(Client* client) {
@@ -519,18 +517,24 @@ void SafeBrowsingService::DatabaseUpdateFinished(bool update_succeeded) {
GetDatabase()->UpdateFinished(update_succeeded);
}
-void SafeBrowsingService::OnBlockingPageDone(const BlockingPageParam& param) {
- NotifyClientBlockingComplete(param.client, param.proceed);
-
- if (param.proceed) {
- // Whitelist this domain and warning type for the given tab.
- WhiteListedEntry entry;
- entry.render_process_host_id = param.render_process_host_id;
- entry.render_view_id = param.render_view_id;
- entry.domain =
- net::RegistryControlledDomainService::GetDomainAndRegistry(param.url);
- entry.result = param.result;
- white_listed_entries_.push_back(entry);
+void SafeBrowsingService::OnBlockingPageDone(
+ const std::vector<UnsafeResource>& resources,
+ bool proceed) {
+ for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
+ iter != resources.end(); ++iter) {
+ const UnsafeResource& resource = *iter;
+ NotifyClientBlockingComplete(resource.client, proceed);
+
+ if (proceed) {
+ // Whitelist this domain and warning type for the given tab.
+ WhiteListedEntry entry;
+ entry.render_process_host_id = resource.render_process_host_id;
+ entry.render_view_id = resource.render_view_id;
+ entry.domain = net::RegistryControlledDomainService::GetDomainAndRegistry(
+ resource.url);
+ entry.result = resource.threat_type;
+ white_listed_entries_.push_back(entry);
+ }
}
}
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index 1d5f229..0917ec9 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -57,14 +57,13 @@ class SafeBrowsingService
// Structure used to pass parameters between the IO and UI thread when
// interacting with the blocking page.
- struct BlockingPageParam {
+ struct UnsafeResource {
GURL url;
- bool proceed;
- UrlCheckResult result;
+ ResourceType::Type resource_type;
+ UrlCheckResult threat_type;
Client* client;
int render_process_host_id;
int render_view_id;
- ResourceType::Type resource_type;
};
// Creates the safe browsing service. Need to initialize before using.
@@ -142,7 +141,8 @@ class SafeBrowsingService
void UpdateFinished(bool update_succeeded);
// The blocking page on the UI thread has completed.
- void OnBlockingPageDone(const BlockingPageParam& param);
+ void OnBlockingPageDone(const std::vector<UnsafeResource>& resources,
+ bool proceed);
// Called when the SafeBrowsingProtocolManager has received updated MAC keys.
void OnNewMacKeys(const std::string& client_key,
@@ -242,7 +242,7 @@ class SafeBrowsingService
void HandleResume();
// Invoked on the UI thread to show the blocking page.
- void DoDisplayBlockingPage(const BlockingPageParam& param);
+ void DoDisplayBlockingPage(const UnsafeResource& resource);
// During a reset or the initial load we may have to queue checks until the
// database is ready. This method is run once the database has loaded (or if