Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / safe_browsing_resource_throttle.cc
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.
4
5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h"
6
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"
18
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;
23
24 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more
25 //               unit test coverage.
26
27 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
28     const net::URLRequest* request,
29     bool is_subresource,
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_(is_subresource) {
38 }
39
40 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
41   if (state_ == STATE_CHECKING_URL)
42     database_manager_->CancelCheck(this);
43 }
44
45 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
46   // We need to check the new URL before starting the request.
47   if (CheckUrl(request_->url()))
48     return;
49
50   // If the URL couldn't be verified synchronously, defer starting the
51   // request until the check has completed.
52   defer_state_ = DEFERRED_START;
53   *defer = true;
54 }
55
56 void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL& new_url,
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;
67
68   // If the URL couldn't be verified synchronously, defer following the
69   // redirect until the SafeBrowsing check is complete. Store the redirect
70   // context so we can pass it on to other handlers once we have completed
71   // our check.
72   defer_state_ = DEFERRED_REDIRECT;
73   *defer = true;
74 }
75
76 const char* SafeBrowsingResourceThrottle::GetNameForLogging() const {
77   return "SafeBrowsingResourceThrottle";
78 }
79
80 // SafeBrowsingService::Client implementation, called on the IO thread once
81 // the URL has been classified.
82 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
83     const GURL& url, SBThreatType threat_type) {
84   CHECK(state_ == STATE_CHECKING_URL);
85   CHECK(defer_state_ != DEFERRED_NONE);
86   CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_
87                                    << " but got: " << url;
88
89   timer_.Stop();  // Cancel the timeout timer.
90   threat_type_ = threat_type;
91   state_ = STATE_NONE;
92
93   if (threat_type == SB_THREAT_TYPE_SAFE) {
94     // Log how much time the safe browsing check cost us.
95     ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_);
96
97     // Continue the request.
98     ResumeRequest();
99     return;
100   }
101
102   if (request_->load_flags() & net::LOAD_PREFETCH) {
103     // Don't prefetch resources that fail safe browsing, disallow
104     // them.
105     controller()->Cancel();
106     return;
107   }
108
109   const content::ResourceRequestInfo* info =
110       content::ResourceRequestInfo::ForRequest(request_);
111
112   SafeBrowsingUIManager::UnsafeResource resource;
113   resource.url = url;
114   resource.original_url = request_->original_url();
115   resource.redirect_urls = redirect_urls_;
116   resource.is_subresource = is_subresource_;
117   resource.threat_type = threat_type;
118   resource.callback = base::Bind(
119       &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr());
120   resource.render_process_host_id = info->GetChildID();
121   resource.render_view_id =  info->GetRouteID();
122
123   state_ = STATE_DISPLAYING_BLOCKING_PAGE;
124
125   content::BrowserThread::PostTask(
126       content::BrowserThread::UI,
127       FROM_HERE,
128       base::Bind(&SafeBrowsingResourceThrottle::StartDisplayingBlockingPage,
129                  AsWeakPtr(), ui_manager_, resource));
130 }
131
132 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
133     const base::WeakPtr<SafeBrowsingResourceThrottle>& throttle,
134     scoped_refptr<SafeBrowsingUIManager> ui_manager,
135     const SafeBrowsingUIManager::UnsafeResource& resource) {
136   bool should_show_blocking_page = true;
137
138   content::RenderViewHost* rvh = content::RenderViewHost::FromID(
139       resource.render_process_host_id, resource.render_view_id);
140   if (rvh) {
141     content::WebContents* web_contents =
142         content::WebContents::FromRenderViewHost(rvh);
143     prerender::PrerenderContents* prerender_contents =
144         prerender::PrerenderContents::FromWebContents(web_contents);
145     if (prerender_contents) {
146       prerender_contents->Destroy(prerender::FINAL_STATUS_SAFE_BROWSING);
147       should_show_blocking_page = false;
148     }
149
150     if (should_show_blocking_page)  {
151       ui_manager->DisplayBlockingPage(resource);
152       return;
153     }
154   }
155
156   // Tab is gone or it's being prerendered.
157   content::BrowserThread::PostTask(
158       content::BrowserThread::IO,
159       FROM_HERE,
160       base::Bind(&SafeBrowsingResourceThrottle::Cancel, throttle));
161 }
162
163 void SafeBrowsingResourceThrottle::Cancel() {
164   controller()->Cancel();
165 }
166
167 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
168 // thread when the user has decided to proceed with the current request, or
169 // go back.
170 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
171   CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
172   state_ = STATE_NONE;
173
174   if (proceed) {
175     threat_type_ = SB_THREAT_TYPE_SAFE;
176     ResumeRequest();
177   } else {
178     controller()->Cancel();
179   }
180 }
181
182 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
183   CHECK(state_ == STATE_NONE);
184   bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
185   if (succeeded_synchronously) {
186     threat_type_ = SB_THREAT_TYPE_SAFE;
187     ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay.
188     return true;
189   }
190
191   state_ = STATE_CHECKING_URL;
192   url_being_checked_ = url;
193
194   // Record the start time of the check.
195   url_check_start_time_ = base::TimeTicks::Now();
196
197   // Start a timer to abort the check if it takes too long.
198   timer_.Start(FROM_HERE,
199                base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
200                this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
201
202   return false;
203 }
204
205 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
206   CHECK(state_ == STATE_CHECKING_URL);
207   CHECK(defer_state_ != DEFERRED_NONE);
208
209   database_manager_->CancelCheck(this);
210   OnCheckBrowseUrlResult(url_being_checked_, SB_THREAT_TYPE_SAFE);
211 }
212
213 void SafeBrowsingResourceThrottle::ResumeRequest() {
214   CHECK(state_ == STATE_NONE);
215   CHECK(defer_state_ != DEFERRED_NONE);
216
217   defer_state_ = DEFERRED_NONE;
218   controller()->Resume();
219 }