Adding instrumentation to locate the source of jankiness
[chromium-blink-merge.git] / chrome / browser / renderer_host / safe_browsing_resource_throttle.cc
blob935338405a26b25558b01b940f304b1ef97f048c
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
7 #include "base/logging.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/prerender/prerender_contents.h"
10 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/render_view_host.h"
13 #include "content/public/browser/resource_controller.h"
14 #include "content/public/browser/resource_request_info.h"
15 #include "content/public/browser/web_contents.h"
16 #include "net/base/load_flags.h"
17 #include "net/url_request/url_request.h"
19 // Maximum time in milliseconds to wait for the safe browsing service to
20 // verify a URL. After this amount of time the outstanding check will be
21 // aborted, and the URL will be treated as if it were safe.
22 static const int kCheckUrlTimeoutMs = 5000;
24 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
25 // unit test coverage.
27 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
28 const net::URLRequest* request,
29 content::ResourceType resource_type,
30 SafeBrowsingService* safe_browsing)
31 : state_(STATE_NONE),
32 defer_state_(DEFERRED_NONE),
33 threat_type_(SB_THREAT_TYPE_SAFE),
34 database_manager_(safe_browsing->database_manager()),
35 ui_manager_(safe_browsing->ui_manager()),
36 request_(request),
37 is_subresource_(resource_type != content::RESOURCE_TYPE_MAIN_FRAME),
38 is_subframe_(resource_type == content::RESOURCE_TYPE_SUB_FRAME) {
41 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
42 if (state_ == STATE_CHECKING_URL)
43 database_manager_->CancelCheck(this);
46 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
47 // We need to check the new URL before starting the request.
48 if (CheckUrl(request_->url()))
49 return;
51 // If the URL couldn't be verified synchronously, defer starting the
52 // request until the check has completed.
53 defer_state_ = DEFERRED_START;
54 *defer = true;
57 void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL& new_url,
58 bool* defer) {
59 CHECK(state_ == STATE_NONE);
60 CHECK(defer_state_ == DEFERRED_NONE);
62 // Save the redirect urls for possible malware detail reporting later.
63 redirect_urls_.push_back(new_url);
65 // We need to check the new URL before following the redirect.
66 if (CheckUrl(new_url))
67 return;
69 // If the URL couldn't be verified synchronously, defer following the
70 // redirect until the SafeBrowsing check is complete. Store the redirect
71 // context so we can pass it on to other handlers once we have completed
72 // our check.
73 defer_state_ = DEFERRED_REDIRECT;
74 *defer = true;
77 const char* SafeBrowsingResourceThrottle::GetNameForLogging() const {
78 return "SafeBrowsingResourceThrottle";
81 // SafeBrowsingService::Client implementation, called on the IO thread once
82 // the URL has been classified.
83 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
84 const GURL& url,
85 SBThreatType threat_type,
86 const std::string& metadata) {
87 CHECK(state_ == STATE_CHECKING_URL);
88 CHECK(defer_state_ != DEFERRED_NONE);
89 CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_
90 << " but got: " << url;
92 #if defined(OS_ANDROID)
93 // Temporarily disable SB interstitial during Finch experiment.
94 // The database check is still exercised, but the interstitial never shown.
95 threat_type = SB_THREAT_TYPE_SAFE;
96 #endif
98 timer_.Stop(); // Cancel the timeout timer.
99 threat_type_ = threat_type;
100 state_ = STATE_NONE;
102 if (threat_type == SB_THREAT_TYPE_SAFE) {
103 // Log how much time the safe browsing check cost us.
104 ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_);
106 // Continue the request.
107 ResumeRequest();
108 return;
111 if (request_->load_flags() & net::LOAD_PREFETCH) {
112 // Don't prefetch resources that fail safe browsing, disallow
113 // them.
114 controller()->Cancel();
115 return;
118 const content::ResourceRequestInfo* info =
119 content::ResourceRequestInfo::ForRequest(request_);
121 SafeBrowsingUIManager::UnsafeResource resource;
122 resource.url = url;
123 resource.original_url = request_->original_url();
124 resource.redirect_urls = redirect_urls_;
125 resource.is_subresource = is_subresource_;
126 resource.is_subframe = is_subframe_;
127 resource.threat_type = threat_type;
128 resource.threat_metadata = metadata;
129 resource.callback = base::Bind(
130 &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr());
131 resource.render_process_host_id = info->GetChildID();
132 resource.render_view_id = info->GetRouteID();
134 state_ = STATE_DISPLAYING_BLOCKING_PAGE;
136 content::BrowserThread::PostTask(
137 content::BrowserThread::UI,
138 FROM_HERE,
139 base::Bind(&SafeBrowsingResourceThrottle::StartDisplayingBlockingPage,
140 AsWeakPtr(), ui_manager_, resource));
143 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
144 const base::WeakPtr<SafeBrowsingResourceThrottle>& throttle,
145 scoped_refptr<SafeBrowsingUIManager> ui_manager,
146 const SafeBrowsingUIManager::UnsafeResource& resource) {
147 bool should_show_blocking_page = true;
149 content::RenderViewHost* rvh = content::RenderViewHost::FromID(
150 resource.render_process_host_id, resource.render_view_id);
151 if (rvh) {
152 content::WebContents* web_contents =
153 content::WebContents::FromRenderViewHost(rvh);
154 prerender::PrerenderContents* prerender_contents =
155 prerender::PrerenderContents::FromWebContents(web_contents);
156 if (prerender_contents) {
157 prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
158 should_show_blocking_page = false;
161 if (should_show_blocking_page) {
162 ui_manager->DisplayBlockingPage(resource);
163 return;
167 // Tab is gone or it's being prerendered.
168 content::BrowserThread::PostTask(
169 content::BrowserThread::IO,
170 FROM_HERE,
171 base::Bind(&SafeBrowsingResourceThrottle::Cancel, throttle));
174 void SafeBrowsingResourceThrottle::Cancel() {
175 controller()->Cancel();
178 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
179 // thread when the user has decided to proceed with the current request, or
180 // go back.
181 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
182 CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
183 state_ = STATE_NONE;
185 if (proceed) {
186 threat_type_ = SB_THREAT_TYPE_SAFE;
187 ResumeRequest();
188 } else {
189 controller()->Cancel();
193 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
194 CHECK(state_ == STATE_NONE);
195 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
196 if (succeeded_synchronously) {
197 threat_type_ = SB_THREAT_TYPE_SAFE;
198 ui_manager_->LogPauseDelay(base::TimeDelta()); // No delay.
199 return true;
202 state_ = STATE_CHECKING_URL;
203 url_being_checked_ = url;
205 // Record the start time of the check.
206 url_check_start_time_ = base::TimeTicks::Now();
208 // Start a timer to abort the check if it takes too long.
209 timer_.Start(FROM_HERE,
210 base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
211 this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
213 return false;
216 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
217 CHECK(state_ == STATE_CHECKING_URL);
218 CHECK(defer_state_ != DEFERRED_NONE);
220 database_manager_->CancelCheck(this);
221 OnCheckBrowseUrlResult(
222 url_being_checked_, SB_THREAT_TYPE_SAFE, std::string());
225 void SafeBrowsingResourceThrottle::ResumeRequest() {
226 CHECK(state_ == STATE_NONE);
227 CHECK(defer_state_ != DEFERRED_NONE);
229 defer_state_ = DEFERRED_NONE;
230 controller()->Resume();