• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SafeBrowsingResourceHandler(ResourceHandler * handler,int render_process_host_id,int render_view_id,ResourceType::Type resource_type,SafeBrowsingService * safe_browsing,ResourceDispatcherHost * resource_dispatcher_host)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 
~SafeBrowsingResourceHandler()44 SafeBrowsingResourceHandler::~SafeBrowsingResourceHandler() {
45 }
46 
OnUploadProgress(int request_id,uint64 position,uint64 size)47 bool SafeBrowsingResourceHandler::OnUploadProgress(int request_id,
48                                                    uint64 position,
49                                                    uint64 size) {
50   return next_handler_->OnUploadProgress(request_id, position, size);
51 }
52 
OnRequestRedirected(int request_id,const GURL & new_url,ResourceResponse * response,bool * defer)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 
OnResponseStarted(int request_id,ResourceResponse * response)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 
OnCheckUrlTimeout()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 
OnWillStart(int request_id,const GURL & url,bool * defer)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 
OnWillRead(int request_id,net::IOBuffer ** buf,int * buf_size,int min_size)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 
OnReadCompleted(int request_id,int * bytes_read)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 
OnResponseCompleted(int request_id,const net::URLRequestStatus & status,const std::string & security_info)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 
OnRequestClosed()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.
OnBrowseUrlCheckResult(const GURL & url,SafeBrowsingService::UrlCheckResult result)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 
StartDisplayingBlockingPage(const GURL & url,SafeBrowsingService::UrlCheckResult result)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.
OnBlockingPageComplete(bool proceed)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 
Shutdown()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 
CheckUrl(const GURL & url)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 
ResumeRequest()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 
ResumeStart()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 
ResumeRedirect()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 
ClearDeferredRequestInfo()318 void SafeBrowsingResourceHandler::ClearDeferredRequestInfo() {
319   deferred_request_id_ = -1;
320   deferred_url_ = GURL();
321   deferred_redirect_response_ = NULL;
322 }
323