root/chrome/browser/safe_browsing/ui_manager.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. render_view_id
  2. StopOnIOThread
  3. LogPauseDelay
  4. CanReportStats
  5. OnBlockingPageDone
  6. DisplayBlockingPage
  7. ReportSafeBrowsingHit
  8. AddObserver
  9. RemoveObserver
  10. ReportSafeBrowsingHitOnIOThread
  11. SendSerializedMalwareDetails
  12. UpdateWhitelist
  13. IsWhitelisted

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/safe_browsing/ui_manager.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/debug/leak_tracker.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/safe_browsing/malware_details.h"
#include "chrome/browser/safe_browsing/ping_manager.h"
#include "chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"

using content::BrowserThread;
using content::NavigationEntry;
using content::WebContents;

struct SafeBrowsingUIManager::WhiteListedEntry {
  int render_process_host_id;
  int render_view_id;
  std::string domain;
  SBThreatType threat_type;
};

SafeBrowsingUIManager::UnsafeResource::UnsafeResource()
    : is_subresource(false),
      threat_type(SB_THREAT_TYPE_SAFE),
      render_process_host_id(-1),
      render_view_id(-1) {
}

SafeBrowsingUIManager::UnsafeResource::~UnsafeResource() { }

SafeBrowsingUIManager::SafeBrowsingUIManager(
    const scoped_refptr<SafeBrowsingService>& service)
    : sb_service_(service) {
}

SafeBrowsingUIManager::~SafeBrowsingUIManager() { }

void SafeBrowsingUIManager::StopOnIOThread(bool shutdown) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  if (shutdown)
    sb_service_ = NULL;
}

void SafeBrowsingUIManager::LogPauseDelay(base::TimeDelta time) {
  UMA_HISTOGRAM_LONG_TIMES("SB2.Delay", time);
}

// Only report SafeBrowsing related stats when UMA is enabled. User must also
// ensure that safe browsing is enabled from the calling profile.
bool SafeBrowsingUIManager::CanReportStats() const {
  const MetricsService* metrics = g_browser_process->metrics_service();
  return metrics && metrics->reporting_active();
}

void SafeBrowsingUIManager::OnBlockingPageDone(
    const std::vector<UnsafeResource>& resources,
    bool proceed) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
  for (std::vector<UnsafeResource>::const_iterator iter = resources.begin();
       iter != resources.end(); ++iter) {
    const UnsafeResource& resource = *iter;
    if (!resource.callback.is_null())
      resource.callback.Run(proceed);

    if (proceed) {
      BrowserThread::PostTask(
          BrowserThread::UI,
          FROM_HERE,
          base::Bind(&SafeBrowsingUIManager::UpdateWhitelist, this, resource));
    }
  }
}

void SafeBrowsingUIManager::DisplayBlockingPage(
    const UnsafeResource& resource) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Indicate to interested observers that the resource in question matched the
  // SB filters. If the resource is already whitelisted, OnSafeBrowsingHit
  // won't be called.
  if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
    FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingMatch(resource));
  }

  // Check if the user has already ignored our warning for this render_view
  // and domain.
  if (IsWhitelisted(resource)) {
    if (!resource.callback.is_null()) {
      BrowserThread::PostTask(
          BrowserThread::IO, FROM_HERE, base::Bind(resource.callback, true));
    }
    return;
  }

  // The tab might have been closed.
  WebContents* web_contents =
      tab_util::GetWebContentsByID(resource.render_process_host_id,
                                   resource.render_view_id);

  if (!web_contents) {
    // The tab is gone and we did not have a chance at showing the interstitial.
    // Just act as if "Don't Proceed" were chosen.
    std::vector<UnsafeResource> resources;
    resources.push_back(resource);
    BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&SafeBrowsingUIManager::OnBlockingPageDone,
                 this, resources, false));
    return;
  }

  if (resource.threat_type != SB_THREAT_TYPE_SAFE &&
      CanReportStats()) {
    GURL page_url = web_contents->GetURL();
    GURL referrer_url;
    NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
    if (entry)
      referrer_url = entry->GetReferrer().url;

    // When the malicious url is on the main frame, and resource.original_url
    // is not the same as the resource.url, that means we have a redirect from
    // resource.original_url to resource.url.
    // Also, at this point, page_url points to the _previous_ page that we
    // were on. We replace page_url with resource.original_url and referrer
    // with page_url.
    if (!resource.is_subresource &&
        !resource.original_url.is_empty() &&
        resource.original_url != resource.url) {
      referrer_url = page_url;
      page_url = resource.original_url;
    }
    ReportSafeBrowsingHit(resource.url, page_url, referrer_url,
                          resource.is_subresource, resource.threat_type,
                          std::string() /* post_data */);
  }
  if (resource.threat_type != SB_THREAT_TYPE_SAFE) {
    FOR_EACH_OBSERVER(Observer, observer_list_, OnSafeBrowsingHit(resource));
  }
  SafeBrowsingBlockingPage::ShowBlockingPage(this, resource);
}

// A safebrowsing hit is sent after a blocking page for malware/phishing
// or after the warning dialog for download urls, only for UMA users.
void SafeBrowsingUIManager::ReportSafeBrowsingHit(
    const GURL& malicious_url,
    const GURL& page_url,
    const GURL& referrer_url,
    bool is_subresource,
    SBThreatType threat_type,
    const std::string& post_data) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!CanReportStats())
    return;

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      base::Bind(&SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread, this,
                 malicious_url, page_url, referrer_url, is_subresource,
                 threat_type, post_data));
}

void SafeBrowsingUIManager::AddObserver(Observer* observer) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  observer_list_.AddObserver(observer);
}

void SafeBrowsingUIManager::RemoveObserver(Observer* observer) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  observer_list_.RemoveObserver(observer);
}

void SafeBrowsingUIManager::ReportSafeBrowsingHitOnIOThread(
    const GURL& malicious_url,
    const GURL& page_url,
    const GURL& referrer_url,
    bool is_subresource,
    SBThreatType threat_type,
    const std::string& post_data) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // The service may delete the ping manager (i.e. when user disabling service,
  // etc). This happens on the IO thread.
  if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
    return;

  DVLOG(1) << "ReportSafeBrowsingHit: " << malicious_url << " " << page_url
           << " " << referrer_url << " " << is_subresource << " "
           << threat_type;
  sb_service_->ping_manager()->ReportSafeBrowsingHit(
      malicious_url, page_url,
      referrer_url, is_subresource,
      threat_type, post_data);
}

// If the user had opted-in to send MalwareDetails, this gets called
// when the report is ready.
void SafeBrowsingUIManager::SendSerializedMalwareDetails(
    const std::string& serialized) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));

  // The service may delete the ping manager (i.e. when user disabling service,
  // etc). This happens on the IO thread.
  if (sb_service_.get() == NULL || sb_service_->ping_manager() == NULL)
    return;

  if (!serialized.empty()) {
    DVLOG(1) << "Sending serialized malware details.";
    sb_service_->ping_manager()->ReportMalwareDetails(serialized);
  }
}

void SafeBrowsingUIManager::UpdateWhitelist(const UnsafeResource& resource) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // 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::registry_controlled_domains::GetDomainAndRegistry(
      resource.url,
      net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
  entry.threat_type = resource.threat_type;
  white_listed_entries_.push_back(entry);
}

bool SafeBrowsingUIManager::IsWhitelisted(const UnsafeResource& resource) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // Check if the user has already ignored our warning for this render_view
  // and domain.
  for (size_t i = 0; i < white_listed_entries_.size(); ++i) {
    const WhiteListedEntry& entry = white_listed_entries_[i];
    if (entry.render_process_host_id == resource.render_process_host_id &&
        entry.render_view_id == resource.render_view_id &&
        // Threat type must be the same or they can either be client-side
        // phishing/malware URL or a SafeBrowsing phishing/malware URL.
        // If we show one type of phishing/malware warning we don't want to show
        // a second phishing/malware warning.
        (entry.threat_type == resource.threat_type ||
         (entry.threat_type == SB_THREAT_TYPE_URL_PHISHING &&
          resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL) ||
         (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_PHISHING_URL &&
          resource.threat_type == SB_THREAT_TYPE_URL_PHISHING) ||
         (entry.threat_type == SB_THREAT_TYPE_URL_MALWARE &&
          resource.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL) ||
         (entry.threat_type == SB_THREAT_TYPE_CLIENT_SIDE_MALWARE_URL &&
          resource.threat_type == SB_THREAT_TYPE_URL_MALWARE))) {
      return entry.domain ==
          net::registry_controlled_domains::GetDomainAndRegistry(
              resource.url,
              net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
    }
  }
  return false;
}


/* [<][>][^][v][top][bottom][index][help] */