| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h" | 5 #include "chrome/browser/renderer_host/safe_browsing_resource_throttle.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram_macros.h" | 8 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/values.h" | 9 #include "base/values.h" |
| 10 #include "chrome/browser/browser_process.h" | 10 #include "chrome/browser/browser_process.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 | 22 |
| 23 using net::NetLog; | 23 using net::NetLog; |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 | 26 |
| 27 // Maximum time in milliseconds to wait for the safe browsing service to | 27 // Maximum time in milliseconds to wait for the safe browsing service to |
| 28 // verify a URL. After this amount of time the outstanding check will be | 28 // verify a URL. After this amount of time the outstanding check will be |
| 29 // aborted, and the URL will be treated as if it were safe. | 29 // aborted, and the URL will be treated as if it were safe. |
| 30 const int kCheckUrlTimeoutMs = 5000; | 30 const int kCheckUrlTimeoutMs = 5000; |
| 31 | 31 |
| 32 // Return true for resource types that are very unlikely to produce a successful | |
| 33 // malware or phishing page without the main frame also being bad. This is a | |
| 34 // latency / safety trade-off, used only on mobile. We're conservative here, | |
| 35 // keeping this list small and leaving off uncommon types since they won't save | |
| 36 // us much on aggregate latency. | |
| 37 bool IsResourceTypeMostlySafe(content::ResourceType resource_type) { | |
| 38 switch (resource_type) { | |
| 39 case content::RESOURCE_TYPE_STYLESHEET: | |
| 40 case content::RESOURCE_TYPE_IMAGE: | |
| 41 case content::RESOURCE_TYPE_FONT_RESOURCE: | |
| 42 case content::RESOURCE_TYPE_FAVICON: | |
| 43 return true; | |
| 44 default: | |
| 45 return false; | |
| 46 } | |
| 47 } | |
| 48 | |
| 49 void RecordHistogramResourceTypeSafe(content::ResourceType resource_type) { | 32 void RecordHistogramResourceTypeSafe(content::ResourceType resource_type) { |
| 50 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Safe", resource_type, | 33 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Safe", resource_type, |
| 51 content::RESOURCE_TYPE_LAST_TYPE); | 34 content::RESOURCE_TYPE_LAST_TYPE); |
| 52 } | 35 } |
| 53 | 36 |
| 54 // Return a dictionary with "url"=|url-spec| and optionally | 37 // Return a dictionary with "url"=|url-spec| and optionally |
| 55 // |name|=|value| (if not null), for netlogging. | 38 // |name|=|value| (if not null), for netlogging. |
| 56 // This will also add a reference to the original request's net_log ID. | 39 // This will also add a reference to the original request's net_log ID. |
| 57 scoped_ptr<base::Value> NetLogUrlCallback( | 40 scoped_ptr<base::Value> NetLogUrlCallback( |
| 58 const net::URLRequest* request, | 41 const net::URLRequest* request, |
| (...skipping 23 matching lines...) Expand all Loading... |
| 82 } // namespace | 65 } // namespace |
| 83 | 66 |
| 84 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more | 67 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more |
| 85 // unit test coverage. | 68 // unit test coverage. |
| 86 | 69 |
| 87 // static | 70 // static |
| 88 SafeBrowsingResourceThrottle* SafeBrowsingResourceThrottle::MaybeCreate( | 71 SafeBrowsingResourceThrottle* SafeBrowsingResourceThrottle::MaybeCreate( |
| 89 net::URLRequest* request, | 72 net::URLRequest* request, |
| 90 content::ResourceType resource_type, | 73 content::ResourceType resource_type, |
| 91 SafeBrowsingService* sb_service) { | 74 SafeBrowsingService* sb_service) { |
| 92 #if defined(SAFE_BROWSING_DB_LOCAL) | 75 if (sb_service->database_manager()->IsSupported()) { |
| 93 // Throttle consults a local database before starting the resource request. | 76 return new SafeBrowsingResourceThrottle(request, resource_type, sb_service); |
| 94 return new SafeBrowsingResourceThrottle( | |
| 95 request, resource_type, sb_service, DEFER_AT_START, | |
| 96 SafeBrowsingService::CHECK_ALL_RESOURCE_TYPES); | |
| 97 #elif defined(SAFE_BROWSING_DB_REMOTE) | |
| 98 if (!sb_service->IsAndroidFieldTrialEnabled() || | |
| 99 !sb_service->database_manager()->IsSupported()) { | |
| 100 return nullptr; | |
| 101 } | 77 } |
| 102 | 78 return nullptr; |
| 103 // Throttle consults a remote database before processing the response. | |
| 104 return new SafeBrowsingResourceThrottle( | |
| 105 request, resource_type, sb_service, DONT_DEFER_AT_START, | |
| 106 sb_service->GetResourceTypesToCheck()); | |
| 107 #else | |
| 108 #error "Incompatible compile flags for safe_browsing_resource_throttle" | |
| 109 #endif | |
| 110 } | 79 } |
| 111 | 80 |
| 112 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle( | 81 SafeBrowsingResourceThrottle::SafeBrowsingResourceThrottle( |
| 113 const net::URLRequest* request, | 82 const net::URLRequest* request, |
| 114 content::ResourceType resource_type, | 83 content::ResourceType resource_type, |
| 115 SafeBrowsingService* sb_service, | 84 SafeBrowsingService* sb_service) |
| 116 DeferAtStartSetting defer_setting, | 85 : state_(STATE_NONE), |
| 117 SafeBrowsingService::ResourceTypesToCheck resource_types_to_check) | |
| 118 : defer_at_start_(defer_setting == DEFER_AT_START), | |
| 119 resource_types_to_check_(resource_types_to_check), | |
| 120 state_(STATE_NONE), | |
| 121 defer_state_(DEFERRED_NONE), | 86 defer_state_(DEFERRED_NONE), |
| 122 threat_type_(SB_THREAT_TYPE_SAFE), | 87 threat_type_(SB_THREAT_TYPE_SAFE), |
| 123 database_manager_(sb_service->database_manager()), | 88 database_manager_(sb_service->database_manager()), |
| 124 ui_manager_(sb_service->ui_manager()), | 89 ui_manager_(sb_service->ui_manager()), |
| 125 request_(request), | 90 request_(request), |
| 126 resource_type_(resource_type), | 91 resource_type_(resource_type), |
| 127 bound_net_log_(net::BoundNetLog::Make(request->net_log().net_log(), | 92 bound_net_log_(net::BoundNetLog::Make(request->net_log().net_log(), |
| 128 NetLog::SOURCE_SAFE_BROWSING)) {} | 93 NetLog::SOURCE_SAFE_BROWSING)) {} |
| 129 | 94 |
| 130 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() { | 95 SafeBrowsingResourceThrottle::~SafeBrowsingResourceThrottle() { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 159 type, base::Bind(&NetLogStringCallback, name, value)); | 124 type, base::Bind(&NetLogStringCallback, name, value)); |
| 160 request_->net_log().AddEvent( | 125 request_->net_log().AddEvent( |
| 161 type, bound_net_log_.source().ToEventParametersCallback()); | 126 type, bound_net_log_.source().ToEventParametersCallback()); |
| 162 } | 127 } |
| 163 | 128 |
| 164 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) { | 129 void SafeBrowsingResourceThrottle::WillStartRequest(bool* defer) { |
| 165 // We need to check the new URL before starting the request. | 130 // We need to check the new URL before starting the request. |
| 166 if (CheckUrl(request_->url())) | 131 if (CheckUrl(request_->url())) |
| 167 return; | 132 return; |
| 168 | 133 |
| 169 if (!defer_at_start_) | 134 // We let the check run in parallel with resource load only if this |
| 135 // db_manager only supports asynchronous checks, like on mobile. |
| 136 // Otherwise, we defer now. |
| 137 if (database_manager_->ChecksAreAlwaysAsync()) |
| 170 return; | 138 return; |
| 171 | 139 |
| 172 // If the URL couldn't be verified synchronously, defer starting the | 140 // If the URL couldn't be verified synchronously, defer starting the |
| 173 // request until the check has completed. | 141 // request until the check has completed. |
| 174 defer_state_ = DEFERRED_START; | 142 defer_state_ = DEFERRED_START; |
| 175 defer_start_time_ = base::TimeTicks::Now(); | 143 defer_start_time_ = base::TimeTicks::Now(); |
| 176 *defer = true; | 144 *defer = true; |
| 177 BeginNetLogEvent(NetLog::TYPE_SAFE_BROWSING_DEFERRED, request_->url(), | 145 BeginNetLogEvent(NetLog::TYPE_SAFE_BROWSING_DEFERRED, request_->url(), |
| 178 "defer_reason", "at_start"); | 146 "defer_reason", "at_start"); |
| 179 } | 147 } |
| 180 | 148 |
| 181 void SafeBrowsingResourceThrottle::WillProcessResponse(bool* defer) { | 149 void SafeBrowsingResourceThrottle::WillProcessResponse(bool* defer) { |
| 182 CHECK_EQ(defer_state_, DEFERRED_NONE); | 150 CHECK_EQ(defer_state_, DEFERRED_NONE); |
| 183 if (defer_at_start_) | 151 // TODO(nparker): Maybe remove this check, since it should have no effect. |
| 152 if (!database_manager_->ChecksAreAlwaysAsync()) |
| 184 return; | 153 return; |
| 185 | 154 |
| 186 if (state_ == STATE_CHECKING_URL || | 155 if (state_ == STATE_CHECKING_URL || |
| 187 state_ == STATE_DISPLAYING_BLOCKING_PAGE) { | 156 state_ == STATE_DISPLAYING_BLOCKING_PAGE) { |
| 188 defer_state_ = DEFERRED_PROCESSING; | 157 defer_state_ = DEFERRED_PROCESSING; |
| 189 defer_start_time_ = base::TimeTicks::Now(); | 158 defer_start_time_ = base::TimeTicks::Now(); |
| 190 *defer = true; | 159 *defer = true; |
| 191 BeginNetLogEvent(NetLog::TYPE_SAFE_BROWSING_DEFERRED, request_->url(), | 160 BeginNetLogEvent(NetLog::TYPE_SAFE_BROWSING_DEFERRED, request_->url(), |
| 192 "defer_reason", "at_response"); | 161 "defer_reason", "at_response"); |
| 193 } | 162 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 if (defer_state_ != DEFERRED_NONE) { | 308 if (defer_state_ != DEFERRED_NONE) { |
| 340 ResumeRequest(); | 309 ResumeRequest(); |
| 341 } | 310 } |
| 342 } else { | 311 } else { |
| 343 controller()->Cancel(); | 312 controller()->Cancel(); |
| 344 } | 313 } |
| 345 } | 314 } |
| 346 | 315 |
| 347 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) { | 316 bool SafeBrowsingResourceThrottle::CheckUrl(const GURL& url) { |
| 348 CHECK_EQ(state_, STATE_NONE); | 317 CHECK_EQ(state_, STATE_NONE); |
| 349 // To reduce aggregate latency on mobile, skip checking resources that | 318 // To reduce aggregate latency on mobile, check only the most dangerous |
| 350 // can't do much harm. | 319 // resource types. |
| 351 if (resource_types_to_check_ == | 320 if (!database_manager_->CanCheckResourceType(resource_type_)) { |
| 352 SafeBrowsingService::CHECK_ONLY_DANGEROUS_TYPES && | |
| 353 IsResourceTypeMostlySafe(resource_type_)) { | |
| 354 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Skipped", resource_type_, | 321 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Skipped", resource_type_, |
| 355 content::RESOURCE_TYPE_LAST_TYPE); | 322 content::RESOURCE_TYPE_LAST_TYPE); |
| 356 return true; | 323 return true; |
| 357 } | 324 } |
| 358 | 325 |
| 359 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this); | 326 bool succeeded_synchronously = database_manager_->CheckBrowseUrl(url, this); |
| 360 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Checked", resource_type_, | 327 UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes.Checked", resource_type_, |
| 361 content::RESOURCE_TYPE_LAST_TYPE); | 328 content::RESOURCE_TYPE_LAST_TYPE); |
| 362 | 329 |
| 363 if (succeeded_synchronously) { | 330 if (succeeded_synchronously) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 406 unchecked_redirect_url_, "defer_reason", | 373 unchecked_redirect_url_, "defer_reason", |
| 407 "resumed_redirect"); | 374 "resumed_redirect"); |
| 408 } | 375 } |
| 409 } | 376 } |
| 410 | 377 |
| 411 if (resume) { | 378 if (resume) { |
| 412 defer_state_ = DEFERRED_NONE; | 379 defer_state_ = DEFERRED_NONE; |
| 413 controller()->Resume(); | 380 controller()->Resume(); |
| 414 } | 381 } |
| 415 } | 382 } |
| OLD | NEW |