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