- add sources.
[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_tracker.h"
10 #include "chrome/browser/renderer_host/chrome_url_request_user_data.h"
11 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
12 #include "content/public/browser/resource_controller.h"
13 #include "content/public/browser/resource_request_info.h"
14 #include "net/base/load_flags.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
25 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle(
26     const net::URLRequest* request,
27     bool is_subresource,
28     SafeBrowsingService* safe_browsing)
29     : state_(STATE_NONE),
30       defer_state_(DEFERRED_NONE),
31       threat_type_(SB_THREAT_TYPE_SAFE),
32       database_manager_(safe_browsing->database_manager()),
33       ui_manager_(safe_browsing->ui_manager()),
34       request_(request),
35       is_subresource_(is_subresource) {
36 }
37
38 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() {
39   if (state_ == STATE_CHECKING_URL)
40     database_manager_->CancelCheck(this);
41 }
42
43 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) {
44   // We need to check the new URL before starting the request.
45   if (CheckUrl(request_->url()))
46     return;
47
48   // If the URL couldn't be verified synchronously, defer starting the
49   // request until the check has completed.
50   defer_state_ = DEFERRED_START;
51   *defer = true;
52 }
53
54 void SafeBrowsingResourceThrottle::WillRedirectRequest(const GURL& new_url,
55                                                        bool* defer) {
56   CHECK(state_ == STATE_NONE);
57   CHECK(defer_state_ == DEFERRED_NONE);
58
59   // Save the redirect urls for possible malware detail reporting later.
60   redirect_urls_.push_back(new_url);
61
62   // We need to check the new URL before following the redirect.
63   if (CheckUrl(new_url))
64     return;
65
66   // If the URL couldn't be verified synchronously, defer following the
67   // redirect until the SafeBrowsing check is complete. Store the redirect
68   // context so we can pass it on to other handlers once we have completed
69   // our check.
70   defer_state_ = DEFERRED_REDIRECT;
71   *defer = true;
72 }
73
74 // SafeBrowsingService::Client implementation, called on the IO thread once
75 // the URL has been classified.
76 void SafeBrowsingResourceThrottle::OnCheckBrowseUrlResult(
77     const GURL& url, SBThreatType threat_type) {
78   CHECK(state_ == STATE_CHECKING_URL);
79   CHECK(defer_state_ != DEFERRED_NONE);
80   CHECK(url == url_being_checked_) << "Was expecting: " << url_being_checked_
81                                    << " but got: " << url;
82
83   timer_.Stop();  // Cancel the timeout timer.
84   threat_type_ = threat_type;
85   state_ = STATE_NONE;
86
87   if (threat_type == SB_THREAT_TYPE_SAFE) {
88     // Log how much time the safe browsing check cost us.
89     ui_manager_->LogPauseDelay(base::TimeTicks::Now() - url_check_start_time_);
90
91     // Continue the request.
92     ResumeRequest();
93   } else {
94     bool should_show_blocking_page = true;
95     if (request_->load_flags() & net::LOAD_PREFETCH) {
96       // Don't prefetch resources that fail safe browsing, disallow
97       // them.
98       controller()->Cancel();
99       should_show_blocking_page = false;
100     } else {
101       ChromeURLRequestUserData* user_data =
102           ChromeURLRequestUserData::Get(request_);
103       if (user_data && user_data->is_prerender()) {
104         const content::ResourceRequestInfo* info =
105             content::ResourceRequestInfo::ForRequest(request_);
106         prerender::PrerenderTracker* prerender_tracker = g_browser_process->
107             prerender_tracker();
108         if (prerender_tracker->TryCancelOnIOThread(
109                 info->GetChildID(),
110                 info->GetRouteID(),
111                 prerender::FINAL_STATUS_SAFE_BROWSING)) {
112           controller()->Cancel();
113           should_show_blocking_page = false;
114         }
115       }
116     }
117     if (should_show_blocking_page)
118       StartDisplayingBlockingPage(url, threat_type);
119   }
120 }
121
122 void SafeBrowsingResourceThrottle::StartDisplayingBlockingPage(
123     const GURL& url, SBThreatType threat_type) {
124   CHECK(state_ == STATE_NONE);
125   CHECK(defer_state_ != DEFERRED_NONE);
126
127   state_ = STATE_DISPLAYING_BLOCKING_PAGE;
128
129   const content::ResourceRequestInfo* info =
130       content::ResourceRequestInfo::ForRequest(request_);
131   ui_manager_->DisplayBlockingPage(
132       url,
133       request_->original_url(),
134       redirect_urls_,
135       is_subresource_,
136       threat_type,
137       base::Bind(
138           &SafeBrowsingResourceThrottle::OnBlockingPageComplete, AsWeakPtr()),
139       info->GetChildID(),
140       info->GetRouteID());
141 }
142
143 // SafeBrowsingService::UrlCheckCallback implementation, called on the IO
144 // thread when the user has decided to proceed with the current request, or
145 // go back.
146 void SafeBrowsingResourceThrottle::OnBlockingPageComplete(bool proceed) {
147   CHECK(state_ == STATE_DISPLAYING_BLOCKING_PAGE);
148   state_ = STATE_NONE;
149
150   if (proceed) {
151     threat_type_ = SB_THREAT_TYPE_SAFE;
152     ResumeRequest();
153   } else {
154     controller()->Cancel();
155   }
156 }
157
158 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) {
159   CHECK(state_ == STATE_NONE);
160   bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this);
161   if (succeeded_synchronously) {
162     threat_type_ = SB_THREAT_TYPE_SAFE;
163     ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay.
164     return true;
165   }
166
167   state_ = STATE_CHECKING_URL;
168   url_being_checked_ = url;
169
170   // Record the start time of the check.
171   url_check_start_time_ = base::TimeTicks::Now();
172
173   // Start a timer to abort the check if it takes too long.
174   timer_.Start(FROM_HERE,
175                base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs),
176                this, &SafeBrowsingResourceThrottle::OnCheckUrlTimeout);
177
178   return false;
179 }
180
181 void SafeBrowsingResourceThrottle::OnCheckUrlTimeout() {
182   CHECK(state_ == STATE_CHECKING_URL);
183   CHECK(defer_state_ != DEFERRED_NONE);
184
185   database_manager_->CancelCheck(this);
186   OnCheckBrowseUrlResult(url_being_checked_, SB_THREAT_TYPE_SAFE);
187 }
188
189 void SafeBrowsingResourceThrottle::ResumeRequest() {
190   CHECK(state_ == STATE_NONE);
191   CHECK(defer_state_ != DEFERRED_NONE);
192
193   defer_state_ = DEFERRED_NONE;
194   controller()->Resume();
195 }