Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2011 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 #include "chrome/browser/renderer_host/safe_browsing_resource_handler.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/browser/renderer_host/global_request_id.h"
      9 #include "content/browser/renderer_host/resource_dispatcher_host.h"
     10 #include "content/browser/renderer_host/resource_message_filter.h"
     11 #include "content/common/resource_response.h"
     12 #include "net/base/io_buffer.h"
     13 #include "net/base/load_flags.h"
     14 #include "net/base/net_errors.h"
     15 #include "net/url_request/url_request.h"
     16 
     17 // Maximum time in milliseconds to wait for the safe browsing service to
     18 // verify a URL. After this amount of time the outstanding check will be
     19 // aborted, and the URL will be treated as if it were safe.
     20 static const int kCheckUrlTimeoutMs = 5000;
     21 
     22 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
     23 //               unit test coverage.
     24 
     25 SafeBrowsingResourceHandler::SafeBrowsingResourceHandler(
     26     ResourceHandler* handler,
     27     int render_process_host_id,
     28     int render_view_id,
     29     ResourceType::Type resource_type,
     30     SafeBrowsingService* safe_browsing,
     31     ResourceDispatcherHost* resource_dispatcher_host)
     32     : state_(STATE_NONE),
     33       defer_state_(DEFERRED_NONE),
     34       safe_browsing_result_(SafeBrowsingService::SAFE),
     35       deferred_request_id_(-1),
     36       next_handler_(handler),
     37       render_process_host_id_(render_process_host_id),
     38       render_view_id_(render_view_id),
     39       safe_browsing_(safe_browsing),
     40       rdh_(resource_dispatcher_host),
     41       resource_type_(resource_type) {
     42 }
     43 
     44 SafeBrowsingResourceHandler::~SafeBrowsingResourceHandler() {
     45 }
     46 
     47 bool SafeBrowsingResourceHandler::OnUploadProgress(int request_id,
     48                                                    uint64 position,
     49                                                    uint64 size) {
     50   return next_handler_->OnUploadProgress(request_id, position, size);
     51 }
     52 
     53 bool SafeBrowsingResourceHandler::OnRequestRedirected(
     54     int request_id,
     55     const GURL& new_url,
     56     ResourceResponse* response,
     57     bool* defer) {
     58   CHECK(state_ == STATE_NONE);
     59   CHECK(defer_state_ == DEFERRED_NONE);
     60 
     61   // Save the redirect urls for possible malware detail reporting later.
     62   redirect_urls_.push_back(new_url);
     63 
     64   // We need to check the new URL before following the redirect.
     65   if (CheckUrl(new_url)) {
     66     return next_handler_->OnRequestRedirected(
     67         request_id, new_url, response, defer);
     68   }
     69 
     70   // If the URL couldn't be verified synchronously, defer following the
     71   // redirect until the SafeBrowsing check is complete. Store the redirect
     72   // context so we can pass it on to other handlers once we have completed
     73   // our check.
     74   defer_state_ = DEFERRED_REDIRECT;
     75   deferred_request_id_ = request_id;
     76   deferred_url_ = new_url;
     77   deferred_redirect_response_ = response;
     78   *defer = true;
     79 
     80   return true;
     81 }
     82 
     83 bool SafeBrowsingResourceHandler::OnResponseStarted(
     84     int request_id, ResourceResponse* response) {
     85   CHECK(state_ == STATE_NONE);
     86   CHECK(defer_state_ == DEFERRED_NONE);
     87   return next_handler_->OnResponseStarted(request_id, response);
     88 }
     89 
     90 void SafeBrowsingResourceHandler::OnCheckUrlTimeout() {
     91   CHECK(state_ == STATE_CHECKING_URL);
     92   CHECK(defer_state_ != DEFERRED_NONE);
     93   safe_browsing_->CancelCheck(this);
     94   OnBrowseUrlCheckResult(deferred_url_, SafeBrowsingService::SAFE);
     95 }
     96 
     97 bool SafeBrowsingResourceHandler::OnWillStart(int request_id,
     98                                               const GURL& url,
     99                                               bool* defer) {
    100   // We need to check the new URL before starting the request.
    101   if (CheckUrl(url))
    102     return next_handler_->OnWillStart(request_id, url, defer);
    103 
    104   // If the URL couldn't be verified synchronously, defer starting the
    105   // request until the check has completed.
    106   defer_state_ = DEFERRED_START;
    107   deferred_request_id_ = request_id;
    108   deferred_url_ = url;
    109   *defer = true;
    110 
    111   return true;
    112 }
    113 
    114 bool SafeBrowsingResourceHandler::OnWillRead(int request_id,
    115                                              net::IOBuffer** buf, int* buf_size,
    116                                              int min_size) {
    117   CHECK(state_ == STATE_NONE);
    118   CHECK(defer_state_ == DEFERRED_NONE);
    119   return next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
    120 }
    121 
    122 bool SafeBrowsingResourceHandler::OnReadCompleted(int request_id,
    123                                                   int* bytes_read) {
    124   CHECK(state_ == STATE_NONE);
    125   CHECK(defer_state_ == DEFERRED_NONE);
    126   return next_handler_->OnReadCompleted(request_id, bytes_read);
    127 }
    128 
    129 bool SafeBrowsingResourceHandler::OnResponseCompleted(
    130     int request_id, const net::URLRequestStatus& status,
    131     const std::string& security_info) {
    132   Shutdown();
    133   return next_handler_->OnResponseCompleted(request_id, status, security_info);
    134 }
    135 
    136 void SafeBrowsingResourceHandler::OnRequestClosed() {
    137   Shutdown();
    138   next_handler_->OnRequestClosed();
    139 }
    140 
    141 // SafeBrowsingService::Client implementation, called on the IO thread once
    142 // the URL has been classified.
    143 void SafeBrowsingResourceHandler::OnBrowseUrlCheckResult(
    144     const GURL& url, SafeBrowsingService::UrlCheckResult result) {
    145   CHECK(state_ == STATE_CHECKING_URL);
    146   CHECK(defer_state_ != DEFERRED_NONE);
    147   CHECK(url == deferred_url_) << "Was expecting: " << deferred_url_
    148                               << " but got: " << url;
    149 
    150   timer_.Stop();  // Cancel the timeout timer.
    151   safe_browsing_result_ = result;
    152   state_ = STATE_NONE;
    153 
    154   if (result == SafeBrowsingService::SAFE) {
    155     // Log how much time the safe browsing check cost us.
    156     base::TimeDelta pause_delta;
    157     pause_delta = base::TimeTicks::Now() - url_check_start_time_;
    158     safe_browsing_->LogPauseDelay(pause_delta);
    159 
    160     // Continue the request.
    161     ResumeRequest();
    162   } else {
    163     const net::URLRequest* request = rdh_->GetURLRequest(
    164         GlobalRequestID(render_process_host_id_, deferred_request_id_));
    165     if (request->load_flags() & net::LOAD_PREFETCH) {
    166       // Don't prefetch resources that fail safe browsing, disallow
    167       // them.
    168       rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false);
    169     } else {
    170       StartDisplayingBlockingPage(url, result);
    171     }
    172   }
    173 
    174   Release();  // Balances the AddRef() in CheckingUrl().
    175 }
    176 
    177 void SafeBrowsingResourceHandler::StartDisplayingBlockingPage(
    178     const GURL& url,
    179     SafeBrowsingService::UrlCheckResult result) {
    180   CHECK(state_ == STATE_NONE);
    181   CHECK(defer_state_ != DEFERRED_NONE);
    182   CHECK(deferred_request_id_ != -1);
    183 
    184   state_ = STATE_DISPLAYING_BLOCKING_PAGE;
    185   AddRef();  // Balanced in OnBlockingPageComplete().
    186 
    187   // Grab the original url of this request as well.
    188   GURL original_url;
    189   net::URLRequest* request = rdh_->GetURLRequest(
    190       GlobalRequestID(render_process_host_id_, deferred_request_id_));
    191   if (request)
    192     original_url = request->original_url();
    193   else
    194     original_url = url;
    195 
    196   safe_browsing_->DisplayBlockingPage(
    197       url, original_url, redirect_urls_, resource_type_,
    198       result, this, render_process_host_id_, render_view_id_);
    199 }
    200 
    201 // SafeBrowsingService::Client implementation, called on the IO thread when
    202 // the user has decided to proceed with the current request, or go back.
    203 void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) {
    204   CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
    205   state_ = STATE_NONE;
    206 
    207   if (proceed) {
    208     safe_browsing_result_ = SafeBrowsingService::SAFE;
    209     net::URLRequest* request = rdh_->GetURLRequest(
    210         GlobalRequestID(render_process_host_id_, deferred_request_id_));
    211 
    212     // The request could be canceled by renderer at this stage.
    213     // As a result, click proceed will do nothing (crbug.com/76460).
    214     if (request)
    215       ResumeRequest();
    216   } else {
    217     rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false);
    218   }
    219 
    220   Release();  // Balances the AddRef() in StartDisplayingBlockingPage().
    221 }
    222 
    223 void SafeBrowsingResourceHandler::Shutdown() {
    224   if (state_ == STATE_CHECKING_URL) {
    225     timer_.Stop();
    226     safe_browsing_->CancelCheck(this);
    227     state_ = STATE_NONE;
    228     // Balance the AddRef() from CheckUrl() which would ordinarily be
    229     // balanced by OnUrlCheckResult().
    230     Release();
    231   }
    232 }
    233 
    234 bool SafeBrowsingResourceHandler::CheckUrl(const GURL& url) {
    235   CHECK(state_ == STATE_NONE);
    236   bool succeeded_synchronously = safe_browsing_->CheckBrowseUrl(url, this);
    237   if (succeeded_synchronously) {
    238     safe_browsing_result_ = SafeBrowsingService::SAFE;
    239     safe_browsing_->LogPauseDelay(base::TimeDelta());  // No delay.
    240     return true;
    241   }
    242 
    243   AddRef();  // Balanced in OnUrlCheckResult().
    244   state_ = STATE_CHECKING_URL;
    245 
    246   // Record the start time of the check.
    247   url_check_start_time_ = base::TimeTicks::Now();
    248 
    249   // Start a timer to abort the check if it takes too long.
    250   timer_.Start(base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
    251                this, &SafeBrowsingResourceHandler::OnCheckUrlTimeout);
    252 
    253   return false;
    254 }
    255 
    256 void SafeBrowsingResourceHandler::ResumeRequest() {
    257   CHECK(state_ == STATE_NONE);
    258   CHECK(defer_state_ != DEFERRED_NONE);
    259 
    260   // Resume whatever stage got paused by the safe browsing check.
    261   switch (defer_state_) {
    262     case DEFERRED_START:
    263       ResumeStart();
    264       break;
    265     case DEFERRED_REDIRECT:
    266       ResumeRedirect();
    267       break;
    268     case DEFERRED_NONE:
    269       NOTREACHED();
    270       break;
    271   }
    272 }
    273 
    274 void SafeBrowsingResourceHandler::ResumeStart() {
    275   CHECK(defer_state_ == DEFERRED_START);
    276   CHECK(deferred_request_id_ != -1);
    277   defer_state_ = DEFERRED_NONE;
    278 
    279   // Retrieve the details for the paused OnWillStart().
    280   int request_id = deferred_request_id_;
    281   GURL url = deferred_url_;
    282 
    283   ClearDeferredRequestInfo();
    284 
    285   // Give the other resource handlers a chance to defer starting.
    286   bool defer = false;
    287   // TODO(eroman): the return value is being lost here. Should
    288   // use it to cancel the request.
    289   next_handler_->OnWillStart(request_id, url, &defer);
    290   if (!defer)
    291     rdh_->StartDeferredRequest(render_process_host_id_, request_id);
    292 }
    293 
    294 void SafeBrowsingResourceHandler::ResumeRedirect() {
    295   CHECK(defer_state_ == DEFERRED_REDIRECT);
    296   defer_state_ = DEFERRED_NONE;
    297 
    298   // Retrieve the details for the paused OnReceivedRedirect().
    299   int request_id = deferred_request_id_;
    300   GURL redirect_url = deferred_url_;
    301   scoped_refptr<ResourceResponse> redirect_response =
    302       deferred_redirect_response_;
    303 
    304   ClearDeferredRequestInfo();
    305 
    306   // Give the other resource handlers a chance to handle the redirect.
    307   bool defer = false;
    308   // TODO(eroman): the return value is being lost here. Should
    309   // use it to cancel the request.
    310   next_handler_->OnRequestRedirected(request_id, redirect_url,
    311                                      redirect_response, &defer);
    312   if (!defer) {
    313     rdh_->FollowDeferredRedirect(render_process_host_id_, request_id,
    314                                  false, GURL());
    315   }
    316 }
    317 
    318 void SafeBrowsingResourceHandler::ClearDeferredRequestInfo() {
    319   deferred_request_id_ = -1;
    320   deferred_url_ = GURL();
    321   deferred_redirect_response_ = NULL;
    322 }
    323