summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.cc58
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host.h8
-rw-r--r--chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc3
-rw-r--r--chrome/browser/renderer_host/resource_handler.h12
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.cc303
-rw-r--r--chrome/browser/renderer_host/safe_browsing_resource_handler.h98
6 files changed, 331 insertions, 151 deletions
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.cc b/chrome/browser/renderer_host/resource_dispatcher_host.cc
index 9a245c7..d7985d7 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.cc
@@ -435,21 +435,22 @@ void ResourceDispatcherHost::BeginRequest(
this);
}
+ // Insert a buffered event handler before the actual one.
+ handler = new BufferedResourceHandler(handler, this, request);
+
+ // Insert safe browsing at the front of the chain, so it gets to decide
+ // on policies first.
if (safe_browsing_->enabled() &&
safe_browsing_->CanCheckUrl(request_data.url)) {
handler = new SafeBrowsingResourceHandler(handler,
child_id,
route_id,
- request_data.url,
request_data.resource_type,
safe_browsing_,
this,
receiver_);
}
- // Insert a buffered event handler before the actual one.
- handler = new BufferedResourceHandler(handler, this, request);
-
// Make extra info and read footer (contains request ID).
ResourceDispatcherHostRequestInfo* extra_info =
new ResourceDispatcherHostRequestInfo(
@@ -605,7 +606,6 @@ void ResourceDispatcherHost::BeginDownload(
handler = new SafeBrowsingResourceHandler(handler,
child_id,
route_id,
- url,
ResourceType::MAIN_FRAME,
safe_browsing_,
this,
@@ -728,6 +728,24 @@ void ResourceDispatcherHost::FollowDeferredRedirect(
i->second->FollowDeferredRedirect();
}
+void ResourceDispatcherHost::StartDeferredRequest(int process_unique_id,
+ int request_id) {
+ GlobalRequestID global_id(process_unique_id, request_id);
+ PendingRequestList::iterator i = pending_requests_.find(global_id);
+ if (i == pending_requests_.end()) {
+ // The request may have been destroyed
+ LOG(WARNING) << "Trying to resume a non-existent request ("
+ << process_unique_id << ", " << request_id << ")";
+ return;
+ }
+
+ // TODO(eroman): are there other considerations for paused or blocked
+ // requests?
+
+ URLRequest* request = i->second;
+ InsertIntoResourceQueue(request, *InfoForRequest(request));
+}
+
bool ResourceDispatcherHost::WillSendData(int child_id,
int request_id) {
PendingRequestList::iterator i = pending_requests_.find(
@@ -1187,7 +1205,35 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request) {
GlobalRequestID global_id(info->child_id(), info->request_id());
pending_requests_[global_id] = request;
- resource_queue_.AddRequest(request, *info);
+
+ // Give the resource handlers an opportunity to delay the URLRequest from
+ // being started.
+ //
+ // There are three cases:
+ //
+ // (1) if OnWillStart() returns false, the request is cancelled (regardless
+ // of whether |defer_start| was set).
+ // (2) If |defer_start| was set to true, then the request is not added
+ // into the resource queue, and will only be started in response to
+ // calling StartDeferredRequest().
+ // (3) If |defer_start| is not set, then the request is inserted into
+ // the resource_queue_ (which may pause it further, or start it).
+ bool defer_start = false;
+ if (!info->resource_handler()->OnWillStart(
+ info->request_id(), request->url(),
+ &defer_start)) {
+ CancelRequest(info->child_id(), info->request_id(), false);
+ return;
+ }
+
+ if (!defer_start)
+ InsertIntoResourceQueue(request, *info);
+}
+
+void ResourceDispatcherHost::InsertIntoResourceQueue(
+ URLRequest* request,
+ const ResourceDispatcherHostRequestInfo& request_info) {
+ resource_queue_.AddRequest(request, request_info);
// Make sure we have the load state monitor running
if (!update_load_states_timer_.IsRunning()) {
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host.h b/chrome/browser/renderer_host/resource_dispatcher_host.h
index c410f3a..121265f 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host.h
+++ b/chrome/browser/renderer_host/resource_dispatcher_host.h
@@ -139,6 +139,9 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
bool has_new_first_party_for_cookies,
const GURL& new_first_party_for_cookies);
+ // Starts a request that was deferred during ResourceHandler::OnWillStart().
+ void StartDeferredRequest(int process_unique_id, int request_id);
+
// Returns true if it's ok to send the data. If there are already too many
// data messages pending, it pauses the request and returns false. In this
// case the caller should not send the data.
@@ -318,6 +321,11 @@ class ResourceDispatcherHost : public URLRequest::Delegate {
// Helper function for regular and download requests.
void BeginRequestInternal(URLRequest* request);
+ // Helper function that inserts |request| into the resource queue.
+ void InsertIntoResourceQueue(
+ URLRequest* request,
+ const ResourceDispatcherHostRequestInfo& request_info);
+
// Updates the "cost" of outstanding requests for |process_unique_id|.
// The "cost" approximates how many bytes are consumed by all the in-memory
// data structures supporting this request (URLRequest object,
diff --git a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
index 38f4dd4..1edc26b 100644
--- a/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
+++ b/chrome/browser/renderer_host/resource_dispatcher_host_unittest.cc
@@ -20,6 +20,9 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/appcache/appcache_interfaces.h"
+// TODO(eroman): Write unit tests for SafeBrowsing that exercise
+// SafeBrowsingResourceHandler.
+
namespace {
// Returns the resource response header structure for this request.
diff --git a/chrome/browser/renderer_host/resource_handler.h b/chrome/browser/renderer_host/resource_handler.h
index 526c6a2..2d6d797 100644
--- a/chrome/browser/renderer_host/resource_handler.h
+++ b/chrome/browser/renderer_host/resource_handler.h
@@ -49,6 +49,18 @@ class ResourceHandler
virtual bool OnResponseStarted(int request_id,
ResourceResponse* response) = 0;
+ // Called before the URLRequest for |request_id| (whose url is |url|) is to be
+ // started. If the handler returns false, then the request is cancelled.
+ // Otherwise if the return value is true, the ResourceHandler can delay the
+ // request from starting by setting |*defer = true|. A deferred request will
+ // not have called URLRequest::Start(), and will not resume until someone
+ // calls ResourceDispatcherHost::StartDeferredRequest().
+ virtual bool OnWillStart(int request_id, const GURL& url, bool* defer) {
+ // TODO(eroman): This should be a pure virtual method (no default
+ // implementation).
+ return true;
+ }
+
// Data will be read for the response. Upon success, this method places the
// size and address of the buffer where the data is to be written in its
// out-params. This call will be followed by either OnReadCompleted or
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
index 68301e8..06beb0c 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.cc
@@ -11,38 +11,31 @@
#include "net/base/net_errors.h"
#include "net/base/io_buffer.h"
-// Maximum time to wait for a gethash response from the Safe Browsing servers.
-static const int kMaxGetHashMs = 1000;
+// Maximum time in milliseconds to wait for the safe browsing service to
+// verify a URL. After this amount of time the outstanding check will be
+// aborted, and the URL will be treated as if it were safe.
+static const int kCheckUrlTimeoutMs = 1000;
+
+// TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
+// unit test coverage.
SafeBrowsingResourceHandler::SafeBrowsingResourceHandler(
ResourceHandler* handler,
int render_process_host_id,
int render_view_id,
- const GURL& url,
ResourceType::Type resource_type,
SafeBrowsingService* safe_browsing,
ResourceDispatcherHost* resource_dispatcher_host,
ResourceDispatcherHost::Receiver* receiver)
- : next_handler_(handler),
+ : state_(STATE_NONE),
+ defer_state_(DEFERRED_NONE),
+ deferred_request_id_(-1),
+ next_handler_(handler),
render_process_host_id_(render_process_host_id),
render_view_id_(render_view_id),
- paused_request_id_(-1),
- in_safe_browsing_check_(false),
- displaying_blocking_page_(false),
safe_browsing_(safe_browsing),
- queued_error_request_id_(-1),
rdh_(resource_dispatcher_host),
- resource_type_(resource_type),
- redirect_id_(-1) {
- if (safe_browsing_->CheckUrl(url, this)) {
- safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
- safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay.
- } else {
- AddRef();
- in_safe_browsing_check_ = true;
- // Can't pause now because it's too early, so we'll do it in OnWillRead.
- }
-
+ resource_type_(resource_type) {
registrar_.Add(this, NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN,
Source<ResourceMessageFilter>(
static_cast<ResourceMessageFilter*>(receiver)));
@@ -54,6 +47,8 @@ SafeBrowsingResourceHandler::~SafeBrowsingResourceHandler() {
bool SafeBrowsingResourceHandler::OnUploadProgress(int request_id,
uint64 position,
uint64 size) {
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ = DEFERRED_NONE);
return next_handler_->OnUploadProgress(request_id, position, size);
}
@@ -62,59 +57,64 @@ bool SafeBrowsingResourceHandler::OnRequestRedirected(
const GURL& new_url,
ResourceResponse* response,
bool* defer) {
- if (in_safe_browsing_check_) {
- // Defer following the redirect until the SafeBrowsing check is complete.
- // Store the redirect context so we can pass it on to other handlers once we
- // have completed our check.
- redirect_response_ = response;
- redirect_url_ = new_url;
- redirect_id_ = request_id;
- *defer = true;
- return true;
- }
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ == DEFERRED_NONE);
- if (safe_browsing_->CheckUrl(new_url, this)) {
- safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
- safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay.
- } else {
- AddRef();
- in_safe_browsing_check_ = true;
- // Can't pause now because it's too early, so we'll do it in OnWillRead.
+ // We need to check the new URL before following the redirect.
+ if (CheckUrl(new_url)) {
+ return next_handler_->OnRequestRedirected(
+ request_id, new_url, response, defer);
}
- return next_handler_->OnRequestRedirected(
- request_id, new_url, response, defer);
+ // If the URL couldn't be verified synchronously, defer following the
+ // redirect until the SafeBrowsing check is complete. Store the redirect
+ // context so we can pass it on to other handlers once we have completed
+ // our check.
+ defer_state_ = DEFERRED_REDIRECT;
+ deferred_request_id_ = request_id;
+ deferred_url_ = new_url;
+ deferred_redirect_response_ = response;
+ *defer = true;
+
+ return true;
}
bool SafeBrowsingResourceHandler::OnResponseStarted(
int request_id, ResourceResponse* response) {
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ == DEFERRED_NONE);
return next_handler_->OnResponseStarted(request_id, response);
}
-void SafeBrowsingResourceHandler::OnGetHashTimeout() {
- if (!in_safe_browsing_check_)
- return;
-
+void SafeBrowsingResourceHandler::OnCheckUrlTimeout() {
+ CHECK(state_ == STATE_CHECKING_URL);
+ CHECK(defer_state_ != DEFERRED_NONE);
safe_browsing_->CancelCheck(this);
OnUrlCheckResult(GURL(), SafeBrowsingService::URL_SAFE);
}
+bool SafeBrowsingResourceHandler::OnWillStart(int request_id,
+ const GURL& url,
+ bool* defer) {
+ // We need to check the new URL before starting the request.
+ if (CheckUrl(url))
+ return next_handler_->OnWillStart(request_id, url, defer);
+
+ // If the URL couldn't be verified synchronously, defer starting the
+ // request until the check has completed.
+ defer_state_ = DEFERRED_START;
+ deferred_request_id_ = request_id;
+ deferred_url_ = url;
+ *defer = true;
+
+ return true;
+}
+
bool SafeBrowsingResourceHandler::OnWillRead(int request_id,
net::IOBuffer** buf, int* buf_size,
int min_size) {
- if (in_safe_browsing_check_ && pause_time_.is_null()) {
- pause_time_ = base::Time::Now();
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- NewRunnableMethod(this, &SafeBrowsingResourceHandler::OnGetHashTimeout),
- kMaxGetHashMs);
- }
-
- if (in_safe_browsing_check_ || displaying_blocking_page_) {
- rdh_->PauseRequest(render_process_host_id_, request_id, true);
- paused_request_id_ = request_id;
- }
-
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ == DEFERRED_NONE);
bool rv = next_handler_->OnWillRead(request_id, buf, buf_size, min_size);
// TODO(willchan): Remove after debugging bug 16371.
if (rv)
@@ -124,25 +124,16 @@ bool SafeBrowsingResourceHandler::OnWillRead(int request_id,
bool SafeBrowsingResourceHandler::OnReadCompleted(int request_id,
int* bytes_read) {
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ == DEFERRED_NONE);
return next_handler_->OnReadCompleted(request_id, bytes_read);
}
bool SafeBrowsingResourceHandler::OnResponseCompleted(
int request_id, const URLRequestStatus& status,
const std::string& security_info) {
- if ((in_safe_browsing_check_ ||
- safe_browsing_result_ != SafeBrowsingService::URL_SAFE) &&
- status.status() == URLRequestStatus::FAILED &&
- status.os_error() == net::ERR_NAME_NOT_RESOLVED) {
- // Got a DNS error while the safebrowsing check is in progress or we
- // already know that the site is unsafe. Don't show the the dns error
- // page.
- queued_error_.reset(new URLRequestStatus(status));
- queued_error_request_id_ = request_id;
- queued_security_info_ = security_info;
- return true;
- }
-
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ == DEFERRED_NONE);
return next_handler_->OnResponseCompleted(request_id, status, security_info);
}
@@ -150,104 +141,158 @@ bool SafeBrowsingResourceHandler::OnResponseCompleted(
// the URL has been classified.
void SafeBrowsingResourceHandler::OnUrlCheckResult(
const GURL& url, SafeBrowsingService::UrlCheckResult result) {
- DCHECK(in_safe_browsing_check_);
- DCHECK(!displaying_blocking_page_);
+ CHECK(state_ == STATE_CHECKING_URL);
+ CHECK(defer_state_ != DEFERRED_NONE);
+ CHECK(url == deferred_url_);
+ timer_.Stop(); // Cancel the timeout timer.
safe_browsing_result_ = result;
- in_safe_browsing_check_ = false;
+ state_ = STATE_NONE;
if (result == SafeBrowsingService::URL_SAFE) {
- // Resume following any redirect response we've deferred.
- if (redirect_id_ != -1) {
- ResumeRedirect();
- return;
- }
-
- if (paused_request_id_ != -1) {
- rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
- paused_request_id_ = -1;
- }
-
+ // Log how much time the safe browsing check cost us.
base::TimeDelta pause_delta;
- if (!pause_time_.is_null())
- pause_delta = base::Time::Now() - pause_time_;
+ pause_delta = base::TimeTicks::Now() - url_check_start_time_;
safe_browsing_->LogPauseDelay(pause_delta);
- if (queued_error_.get()) {
- next_handler_->OnResponseCompleted(
- queued_error_request_id_, *queued_error_.get(),
- queued_security_info_);
- queued_error_.reset();
- queued_security_info_.clear();
- }
-
- Release();
+ // Continue the request.
+ ResumeRequest();
} else {
- displaying_blocking_page_ = true;
- safe_browsing_->DisplayBlockingPage(
- url, resource_type_, result, this, render_process_host_id_,
- render_view_id_);
+ StartDisplayingBlockingPage(url, result);
}
+
+ Release(); // Balances the AddRef() in CheckingUrl().
+}
+
+void SafeBrowsingResourceHandler::StartDisplayingBlockingPage(
+ const GURL& url,
+ SafeBrowsingService::UrlCheckResult result) {
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ != DEFERRED_NONE);
+
+ state_ = STATE_DISPLAYING_BLOCKING_PAGE;
+ AddRef(); // Balanced in OnBlockingPageComplete().
+
+ safe_browsing_->DisplayBlockingPage(
+ url, resource_type_, result, this, render_process_host_id_,
+ render_view_id_);
}
// SafeBrowsingService::Client implementation, called on the IO thread when
// the user has decided to proceed with the current request, or go back.
void SafeBrowsingResourceHandler::OnBlockingPageComplete(bool proceed) {
- DCHECK(displaying_blocking_page_);
- displaying_blocking_page_ = false;
+ CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
+ state_ = STATE_NONE;
if (proceed) {
- // Resume following any deferred redirect.
- if (redirect_id_ != -1) {
- ResumeRedirect();
- return;
- }
-
safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
- if (paused_request_id_ != -1) {
- rdh_->PauseRequest(render_process_host_id_, paused_request_id_, false);
- paused_request_id_ = -1;
- }
-
- if (queued_error_.get()) {
- next_handler_->OnResponseCompleted(
- queued_error_request_id_, *queued_error_.get(),
- queued_security_info_);
- queued_error_.reset();
- queued_security_info_.clear();
- }
+ ResumeRequest();
} else {
- rdh_->CancelRequest(render_process_host_id_, paused_request_id_, false);
+ rdh_->CancelRequest(render_process_host_id_, deferred_request_id_, false);
}
- Release();
+ Release(); // Balances the AddRef() in StartDisplayingBlockingPage().
}
void SafeBrowsingResourceHandler::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type.value == NotificationType::RESOURCE_MESSAGE_FILTER_SHUTDOWN);
- if (in_safe_browsing_check_) {
+ if (state_ == STATE_CHECKING_URL) {
safe_browsing_->CancelCheck(this);
- in_safe_browsing_check_ = false;
+ state_ = STATE_NONE;
+ // Balance the AddRef() from CheckUrl() which would ordinarily be
+ // balanced by OnUrlCheckResult().
Release();
}
}
+bool SafeBrowsingResourceHandler::CheckUrl(const GURL& url) {
+ CHECK(state_ == STATE_NONE);
+ bool succeeded_synchronously = safe_browsing_->CheckUrl(url, this);
+ if (succeeded_synchronously) {
+ safe_browsing_result_ = SafeBrowsingService::URL_SAFE;
+ safe_browsing_->LogPauseDelay(base::TimeDelta()); // No delay.
+ return true;
+ }
+
+ AddRef(); // Balanced in OnUrlCheckResult().
+ state_ = STATE_CHECKING_URL;
+
+ // Record the start time of the check.
+ url_check_start_time_ = base::TimeTicks::Now();
+
+ // Start a timer to abort the check if it takes too long.
+ timer_.Start(base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
+ this, &SafeBrowsingResourceHandler::OnCheckUrlTimeout);
+
+ return false;
+}
+
+void SafeBrowsingResourceHandler::ResumeRequest() {
+ CHECK(state_ == STATE_NONE);
+ CHECK(defer_state_ != DEFERRED_NONE);
+
+ // Resume whatever stage got paused by the safe browsing check.
+ switch (defer_state_) {
+ case DEFERRED_START:
+ ResumeStart();
+ break;
+ case DEFERRED_REDIRECT:
+ ResumeRedirect();
+ break;
+ case DEFERRED_NONE:
+ NOTREACHED();
+ break;
+ }
+}
+
+void SafeBrowsingResourceHandler::ResumeStart() {
+ CHECK(defer_state_ == DEFERRED_START);
+ CHECK(deferred_request_id_ != -1);
+ defer_state_ = DEFERRED_NONE;
+
+ // Retrieve the details for the paused OnWillStart().
+ int request_id = deferred_request_id_;
+ GURL url = deferred_url_;
+
+ ClearDeferredRequestInfo();
+
+ // Give the other resource handlers a chance to defer starting.
+ bool defer = false;
+ // TODO(eroman): the return value is being lost here. Should
+ // use it to cancel the request.
+ next_handler_->OnWillStart(request_id, url, &defer);
+ if (!defer)
+ rdh_->StartDeferredRequest(render_process_host_id_, request_id);
+}
+
void SafeBrowsingResourceHandler::ResumeRedirect() {
- DCHECK(redirect_id_ != -1);
+ CHECK(defer_state_ == DEFERRED_REDIRECT);
+ defer_state_ = DEFERRED_NONE;
+
+ // Retrieve the details for the paused OnReceivedRedirect().
+ int request_id = deferred_request_id_;
+ GURL redirect_url = deferred_url_;
+ scoped_refptr<ResourceResponse> redirect_response =
+ deferred_redirect_response_;
+
+ ClearDeferredRequestInfo();
// Give the other resource handlers a chance to handle the redirect.
bool defer = false;
- next_handler_->OnRequestRedirected(redirect_id_, redirect_url_,
- redirect_response_, &defer);
+ // TODO(eroman): the return value is being lost here. Should
+ // use it to cancel the request.
+ next_handler_->OnRequestRedirected(request_id, redirect_url,
+ redirect_response, &defer);
if (!defer) {
- // TODO(wtc): should we pass a new first party for cookies URL?
- rdh_->FollowDeferredRedirect(render_process_host_id_, redirect_id_,
+ rdh_->FollowDeferredRedirect(render_process_host_id_, request_id,
false, GURL());
}
+}
- redirect_response_ = NULL;
- redirect_id_ = -1;
- Release();
+void SafeBrowsingResourceHandler::ClearDeferredRequestInfo() {
+ deferred_request_id_ = -1;
+ deferred_url_ = GURL();
+ deferred_redirect_response_ = NULL;
}
diff --git a/chrome/browser/renderer_host/safe_browsing_resource_handler.h b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
index f7b75be..e1105b3 100644
--- a/chrome/browser/renderer_host/safe_browsing_resource_handler.h
+++ b/chrome/browser/renderer_host/safe_browsing_resource_handler.h
@@ -9,12 +9,34 @@
#include "base/ref_counted.h"
#include "base/time.h"
+#include "base/timer.h"
#include "chrome/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/renderer_host/resource_handler.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "chrome/common/notification_registrar.h"
-// Checks that a url is safe.
+// SafeBrowsingResourceHandler checks that URLs are "safe" before navigating
+// to them. To be considered "safe", a URL must not appear in the
+// malware/phishing blacklists (see SafeBrowsingService for details).
+//
+// This check is done before requesting the original URL, and additionally
+// before following any subsequent redirect.
+//
+// In the common case, the check completes synchronously (no match in the bloom
+// filter), so the request's flow is un-interrupted.
+//
+// However if the URL fails this quick check, it has the possibility of being
+// on the blacklist. Now the request is suspended (prevented from starting),
+// and a more expensive safe browsing check is begun (fetches the full hashes).
+//
+// Note that the safe browsing check takes at most kCheckUrlTimeoutMs
+// milliseconds. If it takes longer than this, then the system defaults to
+// treating the URL as safe.
+//
+// Once the safe browsing check has completed, if the URL was decided to be
+// dangerous, a warning page is thrown up and the request remains suspended.
+// If on the other hand the URL was decided to be safe, the request is
+// resumed.
class SafeBrowsingResourceHandler : public ResourceHandler,
public SafeBrowsingService::Client,
public NotificationObserver {
@@ -22,7 +44,6 @@ class SafeBrowsingResourceHandler : public ResourceHandler,
SafeBrowsingResourceHandler(ResourceHandler* handler,
int render_process_host_id,
int render_view_id,
- const GURL& url,
ResourceType::Type resource_type,
SafeBrowsingService* safe_browsing,
ResourceDispatcherHost* resource_dispatcher_host,
@@ -33,7 +54,7 @@ class SafeBrowsingResourceHandler : public ResourceHandler,
bool OnRequestRedirected(int request_id, const GURL& new_url,
ResourceResponse* response, bool* defer);
bool OnResponseStarted(int request_id, ResourceResponse* response);
- void OnGetHashTimeout();
+ bool OnWillStart(int request_id, const GURL& url, bool* defer);
bool OnWillRead(int request_id, net::IOBuffer** buf, int* buf_size,
int min_size);
bool OnReadCompleted(int request_id, int* bytes_read);
@@ -56,30 +77,75 @@ class SafeBrowsingResourceHandler : public ResourceHandler,
const NotificationDetails& details);
private:
+ // Describes what phase of the check a handler is in.
+ enum State {
+ STATE_NONE,
+ STATE_CHECKING_URL,
+ STATE_DISPLAYING_BLOCKING_PAGE,
+ };
+
+ // Describes what stage of the request got paused by the check.
+ enum DeferState {
+ DEFERRED_NONE,
+ DEFERRED_START,
+ DEFERRED_REDIRECT,
+ };
+
~SafeBrowsingResourceHandler();
- // Helper function for resuming the following of a redirect response.
+ // Starts running |url| through the safe browsing check. Returns true if the
+ // URL is safe to visit. Otherwise returns false and will call
+ // OnUrlCheckResult() when the check has completed.
+ bool CheckUrl(const GURL& url);
+
+ // Callback for when the safe browsing check (which was initiated by
+ // StartCheckingUrl()) has taken longer than kCheckUrlTimeoutMs.
+ void OnCheckUrlTimeout();
+
+ // Starts displaying the safe browsing interstitial page.
+ void StartDisplayingBlockingPage(const GURL& url,
+ SafeBrowsingService::UrlCheckResult result);
+
+ // Resumes the request, by continuing the deferred action (either starting the
+ // request, or following a redirect).
+ void ResumeRequest();
+
+ // Resumes the deferred "start".
+ void ResumeStart();
+
+ // Resumes the deferred redirect.
void ResumeRedirect();
+ // Erases the state associated with a deferred "start" or redirect
+ // (i.e. the deferred URL and request ID).
+ void ClearDeferredRequestInfo();
+
+ State state_;
+ DeferState defer_state_;
+
+ // The result of the most recent safe browsing check. Only valid to read this
+ // when state_ != STATE_CHECKING_URL.
+ SafeBrowsingService::UrlCheckResult safe_browsing_result_;
+
+ // The time when the outstanding safe browsing check was started.
+ base::TimeTicks url_check_start_time_;
+
+ // Timer to abort the safe browsing check if it takes too long.
+ base::OneShotTimer<SafeBrowsingResourceHandler> timer_;
+
+ // Details on the deferred request (either a start or redirect). It is only
+ // valid to access these members when defer_state_ != DEFERRED_NONE.
+ GURL deferred_url_;
+ int deferred_request_id_;
+ scoped_refptr<ResourceResponse> deferred_redirect_response_;
+
NotificationRegistrar registrar_;
scoped_refptr<ResourceHandler> next_handler_;
int render_process_host_id_;
int render_view_id_;
- int paused_request_id_; // -1 if not paused
- bool in_safe_browsing_check_;
- bool displaying_blocking_page_;
- SafeBrowsingService::UrlCheckResult safe_browsing_result_;
scoped_refptr<SafeBrowsingService> safe_browsing_;
- scoped_ptr<URLRequestStatus> queued_error_;
- std::string queued_security_info_;
- int queued_error_request_id_;
ResourceDispatcherHost* rdh_;
- base::Time pause_time_;
ResourceType::Type resource_type_;
- // Context for handling deferred redirects.
- scoped_refptr<ResourceResponse> redirect_response_;
- GURL redirect_url_;
- int redirect_id_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingResourceHandler);
};