15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/browser_process.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/prerender/prerender_tracker.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/renderer_host/chrome_url_request_user_data.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/safe_browsing/safe_browsing_service.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/resource_controller.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/load_flags.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum time in milliseconds to wait for the safe browsing service to
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// verify a URL. After this amount of time the outstanding check will be
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// aborted, and the URL will be treated as if it were safe.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kCheckUrlTimeoutMs = 5000;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//               unit test coverage.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const net::URLRequest* request,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_process_host_id,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int render_view_id,
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool is_subresource,
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SafeBrowsingService* safe_browsing)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : state_(STATE_NONE),
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      defer_state_(DEFERRED_NONE),
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      threat_type_(SB_THREAT_TYPE_SAFE),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_process_host_id_(render_process_host_id),
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_id_(render_view_id),
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      database_manager_(safe_browsing->database_manager()),
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ui_manager_(safe_browsing->ui_manager()),
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_(request),
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_subresource_(is_subresource) {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (state_ == STATE_CHECKING_URL)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    database_manager_->CancelCheck(this);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to check the new URL before starting the request.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CheckUrl(request_->url()))
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL couldn't be verified synchronously, defer starting the
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // request until the check has completed.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  defer_state_ = DEFERRED_START;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *defer = true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL& new_url,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                       bool* defer) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_NONE);
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(defer_state_ == DEFERRED_NONE);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Save the redirect urls for possible malware detail reporting later.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  redirect_urls_.push_back(new_url);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We need to check the new URL before following the redirect.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (CheckUrl(new_url))
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the URL couldn't be verified synchronously, defer following the
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // redirect until the SafeBrowsing check is complete. Store the redirect
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // context so we can pass it on to other handlers once we have completed
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our check.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  defer_state_ = DEFERRED_REDIRECT;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *defer = true;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SafeBrowsingService::Client implementation, called on the IO thread once
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the URL has been classified.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url, SBThreatType threat_type) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_CHECKING_URL);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(defer_state_ != DEFERRED_NONE);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   << " but got: " << url;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Stop();  // Cancel the timeout timer.
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  threat_type_ = threat_type;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = STATE_NONE;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (threat_type == SB_THREAT_TYPE_SAFE) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Log how much time the safe browsing check cost us.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Continue the request.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResumeRequest();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool should_show_blocking_page = true;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (request_->load_flags() & net::LOAD_PREFETCH) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Don't prefetch resources that fail safe browsing, disallow
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // them.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      controller()->Cancel();
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      should_show_blocking_page = false;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ChromeURLRequestUserData* user_data =
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ChromeURLRequestUserData::Get(request_);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (user_data && user_data->is_prerender()) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        prerender::PrerenderTracker* prerender_tracker = g_browser_process->
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            prerender_tracker();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (prerender_tracker->TryCancelOnIOThread(
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                render_process_host_id_,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                render_view_id_,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                prerender::FINAL_STATUS_SAFE_BROWSING)) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          controller()->Cancel();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          should_show_blocking_page = false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (should_show_blocking_page)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StartDisplayingBlockingPage(url, threat_type);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const GURL& url, SBThreatType threat_type) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_NONE);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(defer_state_ != DEFERRED_NONE);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = STATE_DISPLAYING_BLOCKING_PAGE;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ui_manager_->DisplayBlockingPage(
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      url,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      request_->original_url(),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_urls_,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_subresource_,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      threat_type,
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr()),
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_process_host_id_,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      render_view_id_);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SafeBrowsingService::UrlCheckCallback implementation, called on the IO
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// thread when the user has decided to proceed with the current request, or
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// go back.
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = STATE_NONE;
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (proceed) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    threat_type_ = SB_THREAT_TYPE_SAFE;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ResumeRequest();
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    controller()->Cancel();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_NONE);
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (succeeded_synchronously) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    threat_type_ = SB_THREAT_TYPE_SAFE;
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  state_ = STATE_CHECKING_URL;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_being_checked_ = url;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Record the start time of the check.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  url_check_start_time_ = base::TimeTicks::Now();
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start a timer to abort the check if it takes too long.
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  timer_.Start(FROM_HERE,
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)               this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_CHECKING_URL);
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(defer_state_ != DEFERRED_NONE);
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  database_manager_->CancelCheck(this);
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnCheckBrowseUrlResult(url_being_checked_, SB_THREAT_TYPE_SAFE);
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SafeBrowsingResourceThrottle::ResumeRequest() {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(state_ == STATE_NONE);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(defer_state_ != DEFERRED_NONE);
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  defer_state_ = DEFERRED_NONE;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  controller()->Resume();
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195