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