| OLD | NEW | 
|---|
| 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 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 "components/safe_browsing/base_resource_throttle.h" | 5 #include "components/safe_browsing/request_checker.h" | 
|  | 6 | 
|  | 7 #include <memory> | 
|  | 8 #include <utility> | 
| 6 | 9 | 
| 7 #include "base/metrics/histogram_macros.h" | 10 #include "base/metrics/histogram_macros.h" | 
| 8 #include "base/trace_event/trace_event.h" | 11 #include "base/trace_event/trace_event.h" | 
| 9 #include "base/values.h" | 12 #include "base/values.h" | 
| 10 #include "components/safe_browsing/base_ui_manager.h" | 13 #include "components/safe_browsing/base_ui_manager.h" | 
|  | 14 #include "components/safe_browsing_db/database_manager.h" | 
| 11 #include "components/safe_browsing_db/util.h" | 15 #include "components/safe_browsing_db/util.h" | 
| 12 #include "components/security_interstitials/content/unsafe_resource.h" | 16 #include "components/security_interstitials/content/unsafe_resource.h" | 
| 13 #include "content/public/browser/browser_thread.h" | 17 #include "content/public/browser/browser_thread.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" | 18 #include "net/base/load_flags.h" | 
| 17 #include "net/log/net_log_capture_mode.h" | 19 #include "net/log/net_log_capture_mode.h" | 
| 18 #include "net/log/net_log_source.h" | 20 #include "net/log/net_log_source.h" | 
| 19 #include "net/log/net_log_source_type.h" | 21 #include "net/log/net_log_source_type.h" | 
| 20 #include "net/url_request/redirect_info.h" | 22 #include "net/url_request/redirect_info.h" | 
| 21 #include "net/url_request/url_request.h" | 23 #include "net/url_request/url_request.h" | 
| 22 | 24 | 
| 23 using net::NetLogEventType; | 25 using net::NetLogEventType; | 
| 24 using net::NetLogSourceType; | 26 using net::NetLogSourceType; | 
| 25 | 27 | 
| 26 namespace safe_browsing { | 28 namespace safe_browsing { | 
| 27 | 29 | 
| 28 namespace { | 30 namespace { | 
| 29 | 31 | 
| 30 // Maximum time in milliseconds to wait for the safe browsing service to | 32 // Maximum time in milliseconds to wait for the safe browsing service to | 
| 31 // verify a URL. After this amount of time the outstanding check will be | 33 // verify a URL. After this amount of time the outstanding check will be | 
| 32 // aborted, and the URL will be treated as if it were safe. | 34 // aborted, and the URL will be treated as if it were safe. | 
| 33 const int kCheckUrlTimeoutMs = 5000; | 35 // Mutable for testing purposes. | 
|  | 36 int g_check_url_timeout_ms = 5000; | 
| 34 | 37 | 
| 35 // Return a dictionary with "url"=|url-spec| and optionally | 38 // Return a dictionary with "url"=|url-spec| and optionally | 
| 36 // |name|=|value| (if not null), for netlogging. | 39 // |name|=|value| (if not null), for netlogging. | 
| 37 // This will also add a reference to the original request's net_log ID. | 40 // This will also add a reference to the original request's net_log ID. | 
| 38 std::unique_ptr<base::Value> NetLogUrlCallback( | 41 std::unique_ptr<base::Value> NetLogUrlCallback( | 
| 39     const net::URLRequest* request, | 42     const net::URLRequest* request, | 
| 40     const GURL& url, | 43     const GURL& url, | 
| 41     const char* name, | 44     const char* name, | 
| 42     const char* value, | 45     const char* value, | 
| 43     net::NetLogCaptureMode /* capture_mode */) { | 46     net::NetLogCaptureMode /* capture_mode */) { | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 56                                                   net::NetLogCaptureMode) { | 59                                                   net::NetLogCaptureMode) { | 
| 57   std::unique_ptr<base::DictionaryValue> event_params( | 60   std::unique_ptr<base::DictionaryValue> event_params( | 
| 58       new base::DictionaryValue()); | 61       new base::DictionaryValue()); | 
| 59   if (name && value) | 62   if (name && value) | 
| 60     event_params->SetString(name, value); | 63     event_params->SetString(name, value); | 
| 61   return std::move(event_params); | 64   return std::move(event_params); | 
| 62 } | 65 } | 
| 63 | 66 | 
| 64 }  // namespace | 67 }  // namespace | 
| 65 | 68 | 
| 66 // TODO(eroman): Downgrade these CHECK()s to DCHECKs once there is more | 69 RequestChecker::RequestChecker( | 
| 67 //               unit test coverage. |  | 
| 68 |  | 
| 69 BaseResourceThrottle::BaseResourceThrottle( |  | 
| 70     const net::URLRequest* request, | 70     const net::URLRequest* request, | 
| 71     content::ResourceType resource_type, | 71     content::ResourceType resource_type, | 
| 72     scoped_refptr<SafeBrowsingDatabaseManager> database_manager, | 72     scoped_refptr<SafeBrowsingDatabaseManager> database_manager, | 
| 73     scoped_refptr<BaseUIManager> ui_manager) | 73     scoped_refptr<BaseUIManager> ui_manager, | 
| 74     : ui_manager_(ui_manager), | 74     Delegate* delegate) | 
| 75       threat_type_(SB_THREAT_TYPE_SAFE), | 75     : state_(STATE_NONE), | 
| 76       database_manager_(database_manager), |  | 
| 77       request_(request), |  | 
| 78       state_(STATE_NONE), |  | 
| 79       defer_state_(DEFERRED_NONE), | 76       defer_state_(DEFERRED_NONE), | 
| 80       resource_type_(resource_type), | 77       resource_type_(resource_type), | 
|  | 78       threat_type_(SB_THREAT_TYPE_SAFE), | 
|  | 79       request_(request), | 
|  | 80       ui_manager_(std::move(ui_manager)), | 
|  | 81       database_manager_(std::move(database_manager)), | 
| 81       net_log_with_source_( | 82       net_log_with_source_( | 
| 82           net::NetLogWithSource::Make(request->net_log().net_log(), | 83           net::NetLogWithSource::Make(request->net_log().net_log(), | 
| 83                                       NetLogSourceType::SAFE_BROWSING)) {} | 84                                       NetLogSourceType::SAFE_BROWSING)), | 
|  | 85       delegate_(std::move(delegate)), | 
|  | 86       weak_factory_(this) {} | 
| 84 | 87 | 
| 85 // static | 88 RequestChecker::~RequestChecker() { | 
| 86 BaseResourceThrottle* BaseResourceThrottle::MaybeCreate( |  | 
| 87     net::URLRequest* request, |  | 
| 88     content::ResourceType resource_type, |  | 
| 89     scoped_refptr<SafeBrowsingDatabaseManager> database_manager, |  | 
| 90     scoped_refptr<BaseUIManager> ui_manager) { |  | 
| 91   if (database_manager->IsSupported()) { |  | 
| 92     return new BaseResourceThrottle(request, resource_type, |  | 
| 93                                     database_manager, ui_manager); |  | 
| 94   } |  | 
| 95   return nullptr; |  | 
| 96 } |  | 
| 97 |  | 
| 98 BaseResourceThrottle::~BaseResourceThrottle() { |  | 
| 99   if (defer_state_ != DEFERRED_NONE) { | 89   if (defer_state_ != DEFERRED_NONE) { | 
| 100     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr); | 90     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr); | 
| 101   } | 91   } | 
| 102 | 92 | 
| 103   if (state_ == STATE_CHECKING_URL) { | 93   if (state_ == STATE_CHECKING_URL) { | 
| 104     database_manager_->CancelCheck(this); | 94     database_manager_->CancelCheck(this); | 
| 105     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result", | 95     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result", | 
| 106                    "request_canceled"); | 96                    "request_canceled"); | 
| 107   } | 97   } | 
| 108 } | 98 } | 
| 109 | 99 | 
| 110 // Note on net_log calls: SAFE_BROWSING_DEFERRED events must be wholly | 100 RequestChecker::DeferDecision RequestChecker::CheckNewRequest() { | 
| 111 // nested within SAFE_BROWSING_CHECKING_URL events.  Synchronous checks |  | 
| 112 // are not logged at all. |  | 
| 113 void BaseResourceThrottle::BeginNetLogEvent(NetLogEventType type, |  | 
| 114                                             const GURL& url, |  | 
| 115                                             const char* name, |  | 
| 116                                             const char* value) { |  | 
| 117   net_log_with_source_.BeginEvent( |  | 
| 118       type, base::Bind(&NetLogUrlCallback, request_, url, name, value)); |  | 
| 119   request_->net_log().AddEvent( |  | 
| 120       type, net_log_with_source_.source().ToEventParametersCallback()); |  | 
| 121 } |  | 
| 122 |  | 
| 123 void BaseResourceThrottle::EndNetLogEvent(NetLogEventType type, |  | 
| 124                                           const char* name, |  | 
| 125                                           const char* value) { |  | 
| 126   net_log_with_source_.EndEvent(type, |  | 
| 127                                 base::Bind(&NetLogStringCallback, name, value)); |  | 
| 128   request_->net_log().AddEvent( |  | 
| 129       type, net_log_with_source_.source().ToEventParametersCallback()); |  | 
| 130 } |  | 
| 131 |  | 
| 132 void BaseResourceThrottle::WillStartRequest(bool* defer) { |  | 
| 133   // We need to check the new URL before starting the request. | 101   // We need to check the new URL before starting the request. | 
| 134   if (CheckUrl(request_->url())) | 102   DeferDecision decision = CheckUrl(request_->url()); | 
| 135     return; | 103   DCHECK_NE(decision, PROCEED_ALWAYS_ASYNC); | 
|  | 104   if (decision != DEFER) | 
|  | 105     return decision; | 
| 136 | 106 | 
| 137   // We let the check run in parallel with resource load only if this | 107   // We let the check run in parallel with resource load only if this | 
| 138   // db_manager only supports asynchronous checks, like on mobile. | 108   // db_manager only supports asynchronous checks, like on mobile. | 
| 139   // Otherwise, we defer now. | 109   // Otherwise, we defer now. | 
| 140   if (database_manager_->ChecksAreAlwaysAsync()) | 110   if (database_manager_->ChecksAreAlwaysAsync()) | 
| 141     return; | 111     return PROCEED_ALWAYS_ASYNC; | 
| 142 | 112 | 
| 143   // If the URL couldn't be verified synchronously, defer starting the | 113   // If the URL couldn't be verified synchronously, defer starting the | 
| 144   // request until the check has completed. | 114   // request until the check has completed. | 
| 145   defer_state_ = DEFERRED_START; | 115   defer_state_ = DEFERRED_START; | 
| 146   defer_start_time_ = base::TimeTicks::Now(); | 116   defer_start_time_ = base::TimeTicks::Now(); | 
| 147   *defer = true; |  | 
| 148   BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(), | 117   BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(), | 
| 149                    "defer_reason", "at_start"); | 118                    "defer_reason", "at_start"); | 
|  | 119   return DEFER; | 
| 150 } | 120 } | 
| 151 | 121 | 
| 152 void BaseResourceThrottle::WillProcessResponse(bool* defer) { | 122 RequestChecker::DeferDecision RequestChecker::CheckRedirect( | 
| 153   CHECK_EQ(defer_state_, DEFERRED_NONE); | 123     const GURL& new_url) { | 
| 154   // TODO(nparker): Maybe remove this check, since it should have no effect. |  | 
| 155   if (!database_manager_->ChecksAreAlwaysAsync()) |  | 
| 156     return; |  | 
| 157 |  | 
| 158   if (state_ == STATE_CHECKING_URL || |  | 
| 159       state_ == STATE_DISPLAYING_BLOCKING_PAGE) { |  | 
| 160     defer_state_ = DEFERRED_PROCESSING; |  | 
| 161     defer_start_time_ = base::TimeTicks::Now(); |  | 
| 162     *defer = true; |  | 
| 163     BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(), |  | 
| 164                      "defer_reason", "at_response"); |  | 
| 165   } |  | 
| 166 } |  | 
| 167 |  | 
| 168 bool BaseResourceThrottle::MustProcessResponseBeforeReadingBody() { |  | 
| 169   // On Android, SafeBrowsing may only decide to cancel the request when the |  | 
| 170   // response has been received. Therefore, no part of it should be cached |  | 
| 171   // until this ResourceThrottle has been able to check the response. This |  | 
| 172   // prevents the following scenario: |  | 
| 173   //   1) A request is made for foo.com which has been hacked. |  | 
| 174   //   2) The request is only canceled at WillProcessResponse stage, but part of |  | 
| 175   //   it has been cached. |  | 
| 176   //   3) foo.com is no longer hacked and removed from the SafeBrowsing list. |  | 
| 177   //   4) The user requests foo.com, which is not on the SafeBrowsing list. This |  | 
| 178   //   is deemed safe. However, the resource is actually served from cache, |  | 
| 179   //   using the version that was previously stored. |  | 
| 180   //   5) This results in the  user accessing an unsafe resource without being |  | 
| 181   //   notified that it's dangerous. |  | 
| 182   // TODO(clamy): Add a browser test that checks this specific scenario. |  | 
| 183   return true; |  | 
| 184 } |  | 
| 185 |  | 
| 186 void BaseResourceThrottle::WillRedirectRequest( |  | 
| 187     const net::RedirectInfo& redirect_info, |  | 
| 188     bool* defer) { |  | 
| 189   CHECK_EQ(defer_state_, DEFERRED_NONE); | 124   CHECK_EQ(defer_state_, DEFERRED_NONE); | 
| 190 | 125 | 
| 191   // Prev check completed and was safe. | 126   // Prev check completed and was safe. | 
| 192   if (state_ == STATE_NONE) { | 127   if (state_ == STATE_NONE) { | 
| 193     // Save the redirect urls for possible malware detail reporting later. | 128     // Save the redirect urls for possible malware detail reporting later. | 
| 194     redirect_urls_.push_back(redirect_info.new_url); | 129     redirect_urls_.push_back(new_url); | 
| 195 | 130 | 
| 196     // We need to check the new URL before following the redirect. | 131     // We need to check the new URL before following the redirect. | 
| 197     if (CheckUrl(redirect_info.new_url)) | 132     DeferDecision decision = CheckUrl(new_url); | 
| 198       return; | 133     if (decision == PROCEED_SAFE) | 
|  | 134       return PROCEED_SAFE; | 
|  | 135     DCHECK_EQ(decision, DEFER); | 
| 199     defer_state_ = DEFERRED_REDIRECT; | 136     defer_state_ = DEFERRED_REDIRECT; | 
| 200   } else { | 137   } else { | 
| 201     CHECK(state_ == STATE_CHECKING_URL || | 138     DCHECK(state_ == STATE_CHECKING_URL || | 
| 202           state_ == STATE_DISPLAYING_BLOCKING_PAGE); | 139            state_ == STATE_DISPLAYING_BLOCKING_PAGE); | 
|  | 140     DCHECK(database_manager_->ChecksAreAlwaysAsync()); | 
| 203     // We can't check this new URL until we have finished checking | 141     // We can't check this new URL until we have finished checking | 
| 204     // the prev one, or resumed from the blocking page. | 142     // the prev one, or resumed from the blocking page. | 
| 205     unchecked_redirect_url_ = redirect_info.new_url; | 143     unchecked_redirect_url_ = new_url; | 
| 206     defer_state_ = DEFERRED_UNCHECKED_REDIRECT; | 144     defer_state_ = DEFERRED_UNCHECKED_REDIRECT; | 
| 207   } | 145   } | 
| 208 | 146 | 
| 209   defer_start_time_ = base::TimeTicks::Now(); | 147   defer_start_time_ = base::TimeTicks::Now(); | 
| 210   *defer = true; |  | 
| 211   BeginNetLogEvent( | 148   BeginNetLogEvent( | 
| 212       NetLogEventType::SAFE_BROWSING_DEFERRED, redirect_info.new_url, | 149       NetLogEventType::SAFE_BROWSING_DEFERRED, new_url, "defer_reason", | 
| 213       "defer_reason", |  | 
| 214       defer_state_ == DEFERRED_REDIRECT ? "redirect" : "unchecked_redirect"); | 150       defer_state_ == DEFERRED_REDIRECT ? "redirect" : "unchecked_redirect"); | 
|  | 151   return DEFER; | 
| 215 } | 152 } | 
| 216 | 153 | 
| 217 const char* BaseResourceThrottle::GetNameForLogging() const { | 154 RequestChecker::DeferDecision RequestChecker::ShouldDeferResponse() { | 
| 218   return "BaseResourceThrottle"; | 155   CHECK_EQ(defer_state_, DEFERRED_NONE); | 
|  | 156   if (state_ == STATE_CHECKING_URL || | 
|  | 157       state_ == STATE_DISPLAYING_BLOCKING_PAGE) { | 
|  | 158     DCHECK(database_manager_->ChecksAreAlwaysAsync()); | 
|  | 159     defer_state_ = DEFERRED_PROCESSING; | 
|  | 160     defer_start_time_ = base::TimeTicks::Now(); | 
|  | 161     BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, request_->url(), | 
|  | 162                      "defer_reason", "at_response"); | 
|  | 163     return DEFER; | 
|  | 164   } | 
|  | 165 | 
|  | 166   return PROCEED_SAFE; | 
| 219 } | 167 } | 
| 220 | 168 | 
| 221 void BaseResourceThrottle::MaybeDestroyPrerenderContents( |  | 
| 222     const content::ResourceRequestInfo* info) {} |  | 
| 223 |  | 
| 224 // SafeBrowsingService::Client implementation, called on the IO thread once | 169 // SafeBrowsingService::Client implementation, called on the IO thread once | 
| 225 // the URL has been classified. | 170 // the URL has been classified. | 
| 226 void BaseResourceThrottle::OnCheckBrowseUrlResult( | 171 void RequestChecker::OnCheckBrowseUrlResult(const GURL& url, | 
| 227     const GURL& url, | 172                                             SBThreatType threat_type, | 
| 228     SBThreatType threat_type, | 173                                             const ThreatMetadata& metadata) { | 
| 229     const ThreatMetadata& metadata) { | 174   DCHECK_EQ(state_, STATE_CHECKING_URL); | 
| 230   CHECK_EQ(state_, STATE_CHECKING_URL); | 175   DCHECK(url.is_valid()); | 
| 231   CHECK(url.is_valid()); | 176   DCHECK(url_being_checked_.is_valid()); | 
| 232   CHECK(url_being_checked_.is_valid()); | 177   DCHECK_EQ(url, url_being_checked_); | 
| 233   CHECK_EQ(url, url_being_checked_); |  | 
| 234 | 178 | 
| 235   timer_.Stop();  // Cancel the timeout timer. | 179   timer_.Stop();  // Cancel the timeout timer. | 
| 236   threat_type_ = threat_type; | 180   threat_type_ = threat_type; | 
| 237   state_ = STATE_NONE; | 181   state_ = STATE_NONE; | 
| 238 | 182 | 
| 239   if (defer_state_ != DEFERRED_NONE) { | 183   if (defer_state_ != DEFERRED_NONE) { | 
| 240     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr); | 184     EndNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, nullptr, nullptr); | 
| 241   } | 185   } | 
| 242   EndNetLogEvent( | 186   EndNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result", | 
| 243       NetLogEventType::SAFE_BROWSING_CHECKING_URL, "result", | 187                  threat_type_ == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe"); | 
| 244       threat_type_ == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe"); |  | 
| 245 | 188 | 
| 246   if (threat_type == SB_THREAT_TYPE_SAFE) { | 189   if (threat_type == SB_THREAT_TYPE_SAFE) { | 
| 247     if (defer_state_ != DEFERRED_NONE) { | 190     if (defer_state_ != DEFERRED_NONE) { | 
| 248       // Log how much time the safe browsing check cost us. | 191       // Log how much time the safe browsing check cost us. | 
| 249       ui_manager_->LogPauseDelay(base::TimeTicks::Now() - defer_start_time_); | 192       ui_manager_->LogPauseDelay(base::TimeTicks::Now() - defer_start_time_); | 
| 250       ResumeRequest(); | 193       ResumeRequest(); | 
| 251     } else { | 194     } else { | 
| 252       ui_manager_->LogPauseDelay(base::TimeDelta()); | 195       ui_manager_->LogPauseDelay(base::TimeDelta()); | 
| 253     } | 196     } | 
| 254     return; | 197     return; | 
| 255   } | 198   } | 
| 256 | 199 | 
| 257   const content::ResourceRequestInfo* info = |  | 
| 258       content::ResourceRequestInfo::ForRequest(request_); |  | 
| 259 |  | 
| 260   if (request_->load_flags() & net::LOAD_PREFETCH) { | 200   if (request_->load_flags() & net::LOAD_PREFETCH) { | 
| 261     // Destroy the prefetch with FINAL_STATUS_SAFEBROSWING. | 201     // Destroy the prefetch with FINAL_STATUS_SAFEBROWSING. | 
| 262     if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME) { | 202     if (resource_type_ == content::RESOURCE_TYPE_MAIN_FRAME) { | 
| 263       MaybeDestroyPrerenderContents(info); | 203       delegate_->MaybeDestroyPrerenderContents(request_); | 
| 264     } | 204     } | 
| 265     // Don't prefetch resources that fail safe browsing, disallow them. | 205     // Don't prefetch resources that fail safe browsing, disallow them. | 
| 266     Cancel(); | 206     delegate_->CancelResourceLoad(); | 
| 267     UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.UnsafePrefetchCanceled", | 207     UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.UnsafePrefetchCanceled", | 
| 268                               resource_type_, content::RESOURCE_TYPE_LAST_TYPE); | 208                               resource_type_, content::RESOURCE_TYPE_LAST_TYPE); | 
| 269     return; | 209     return; | 
| 270   } | 210   } | 
| 271 | 211 | 
| 272   UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_, | 212   UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Unsafe", resource_type_, | 
| 273                             content::RESOURCE_TYPE_LAST_TYPE); | 213                             content::RESOURCE_TYPE_LAST_TYPE); | 
| 274 | 214 | 
| 275   security_interstitials::UnsafeResource resource; | 215   security_interstitials::UnsafeResource resource; | 
| 276   resource.url = url; | 216   resource.url = url; | 
| 277   resource.original_url = request_->original_url(); | 217   resource.original_url = request_->original_url(); | 
| 278   resource.redirect_urls = redirect_urls_; | 218   resource.redirect_urls = redirect_urls_; | 
| 279   resource.is_subresource = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME; | 219   resource.is_subresource = resource_type_ != content::RESOURCE_TYPE_MAIN_FRAME; | 
| 280   resource.is_subframe = resource_type_ == content::RESOURCE_TYPE_SUB_FRAME; | 220   resource.is_subframe = resource_type_ == content::RESOURCE_TYPE_SUB_FRAME; | 
| 281   resource.threat_type = threat_type; | 221   resource.threat_type = threat_type; | 
| 282   resource.threat_metadata = metadata; | 222   resource.threat_metadata = metadata; | 
| 283   resource.callback = base::Bind( | 223   resource.callback = base::Bind(&RequestChecker::OnBlockingPageComplete, | 
| 284       &BaseResourceThrottle::OnBlockingPageComplete, AsWeakPtr()); | 224                                  weak_factory_.GetWeakPtr()); | 
| 285   resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread( | 225   resource.callback_thread = content::BrowserThread::GetTaskRunnerForThread( | 
| 286       content::BrowserThread::IO); | 226       content::BrowserThread::IO); | 
| 287   resource.web_contents_getter = info->GetWebContentsGetterForRequest(); | 227   resource.web_contents_getter = | 
|  | 228       delegate_->GetWebContentsGetterForRequest(request_); | 
| 288   resource.threat_source = database_manager_->GetThreatSource(); | 229   resource.threat_source = database_manager_->GetThreatSource(); | 
| 289 | 230 | 
| 290   state_ = STATE_DISPLAYING_BLOCKING_PAGE; | 231   state_ = STATE_DISPLAYING_BLOCKING_PAGE; | 
| 291 | 232 | 
| 292   StartDisplayingBlockingPageHelper(resource); | 233   delegate_->StartDisplayingBlockingPage(std::move(resource), ui_manager_); | 
| 293 } | 234 } | 
| 294 | 235 | 
| 295 void BaseResourceThrottle::StartDisplayingBlockingPageHelper( | 236 void RequestChecker::OnBlockingPageComplete(bool proceed) { | 
| 296     security_interstitials::UnsafeResource resource) { |  | 
| 297   content::BrowserThread::PostTask( |  | 
| 298       content::BrowserThread::UI, FROM_HERE, |  | 
| 299       base::Bind(&BaseResourceThrottle::StartDisplayingBlockingPage, |  | 
| 300                  AsWeakPtr(), ui_manager_, resource)); |  | 
| 301 } |  | 
| 302 |  | 
| 303 // Static |  | 
| 304 void BaseResourceThrottle::StartDisplayingBlockingPage( |  | 
| 305     const base::WeakPtr<BaseResourceThrottle>& throttle, |  | 
| 306     scoped_refptr<BaseUIManager> ui_manager, |  | 
| 307     const security_interstitials::UnsafeResource& resource) { |  | 
| 308   content::WebContents* web_contents = resource.web_contents_getter.Run(); |  | 
| 309   if (web_contents) { |  | 
| 310     ui_manager->DisplayBlockingPage(resource); |  | 
| 311     return; |  | 
| 312   } |  | 
| 313 |  | 
| 314   // Tab is gone or it's being prerendered. |  | 
| 315   content::BrowserThread::PostTask( |  | 
| 316       content::BrowserThread::IO, FROM_HERE, |  | 
| 317       base::Bind(&BaseResourceThrottle::Cancel, throttle)); |  | 
| 318 } |  | 
| 319 |  | 
| 320 void BaseResourceThrottle::OnBlockingPageComplete(bool proceed) { |  | 
| 321   CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE); | 237   CHECK_EQ(state_, STATE_DISPLAYING_BLOCKING_PAGE); | 
| 322   state_ = STATE_NONE; | 238   state_ = STATE_NONE; | 
| 323 | 239 | 
| 324   if (proceed) { | 240   if (proceed) { | 
| 325     threat_type_ = SB_THREAT_TYPE_SAFE; | 241     threat_type_ = SB_THREAT_TYPE_SAFE; | 
| 326     if (defer_state_ != DEFERRED_NONE) { | 242     if (defer_state_ != DEFERRED_NONE) { | 
| 327       ResumeRequest(); | 243       ResumeRequest(); | 
| 328     } | 244     } | 
| 329   } else { | 245   } else { | 
| 330     CancelResourceLoad(); | 246     delegate_->CancelResourceLoad(); | 
| 331   } | 247   } | 
| 332 } | 248 } | 
| 333 | 249 | 
| 334 void BaseResourceThrottle::CancelResourceLoad() { | 250 RequestChecker::DeferDecision RequestChecker::CheckUrl(const GURL& url) { | 
| 335   Cancel(); | 251   TRACE_EVENT1("loader", "RequestChecker::CheckUrl", "url", url.spec()); | 
| 336 } |  | 
| 337 |  | 
| 338 scoped_refptr<BaseUIManager> BaseResourceThrottle::ui_manager() { |  | 
| 339   return ui_manager_; |  | 
| 340 } |  | 
| 341 |  | 
| 342 bool BaseResourceThrottle::CheckUrl(const GURL& url) { |  | 
| 343   TRACE_EVENT1("loader", "BaseResourceThrottle::CheckUrl", "url", |  | 
| 344                url.spec()); |  | 
| 345   CHECK_EQ(state_, STATE_NONE); | 252   CHECK_EQ(state_, STATE_NONE); | 
| 346   // To reduce aggregate latency on mobile, check only the most dangerous | 253   // To reduce aggregate latency on mobile, check only the most dangerous | 
| 347   // resource types. | 254   // resource types. | 
| 348   if (!database_manager_->CanCheckResourceType(resource_type_)) { | 255   if (!database_manager_->CanCheckResourceType(resource_type_)) { | 
| 349     // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType | 256     // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType | 
| 350     // to be consistent with the other PVer4 metrics. | 257     // to be consistent with the other PVer4 metrics. | 
| 351     UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Skipped", resource_type_, | 258     UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Skipped", resource_type_, | 
| 352                               content::RESOURCE_TYPE_LAST_TYPE); | 259                               content::RESOURCE_TYPE_LAST_TYPE); | 
| 353     return true; | 260     return PROCEED_SKIPPED; | 
| 354   } | 261   } | 
| 355 | 262 | 
| 356   // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType to | 263   // TODO(vakh): Consider changing this metric to SafeBrowsing.V4ResourceType to | 
| 357   // be consistent with the other PVer4 metrics. | 264   // be consistent with the other PVer4 metrics. | 
| 358   UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Checked", resource_type_, | 265   UMA_HISTOGRAM_ENUMERATION("SB2.ResourceTypes2.Checked", resource_type_, | 
| 359                             content::RESOURCE_TYPE_LAST_TYPE); | 266                             content::RESOURCE_TYPE_LAST_TYPE); | 
| 360 | 267 | 
| 361   if (database_manager_->CheckBrowseUrl(url, this)) { | 268   if (database_manager_->CheckBrowseUrl(url, this)) { | 
| 362     threat_type_ = SB_THREAT_TYPE_SAFE; | 269     threat_type_ = SB_THREAT_TYPE_SAFE; | 
| 363     ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay. | 270     ui_manager_->LogPauseDelay(base::TimeDelta());  // No delay. | 
| 364     return true; | 271     return PROCEED_SAFE; | 
| 365   } | 272   } | 
| 366 | 273 | 
| 367   state_ = STATE_CHECKING_URL; | 274   state_ = STATE_CHECKING_URL; | 
| 368   url_being_checked_ = url; | 275   url_being_checked_ = url; | 
| 369   BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr, | 276   BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_CHECKING_URL, url, nullptr, | 
| 370                    nullptr); | 277                    nullptr); | 
| 371 | 278 | 
| 372   // Start a timer to abort the check if it takes too long. | 279   // Start a timer to abort the check if it takes too long. | 
| 373   // TODO(nparker): Set this only when we defer, based on remaining time, | 280   // TODO(nparker): Set this only when we defer, based on remaining time, | 
| 374   // so we don't cancel earlier than necessary. | 281   // so we don't cancel earlier than necessary. | 
| 375   timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kCheckUrlTimeoutMs), | 282   timer_.Start(FROM_HERE, | 
| 376                this, &BaseResourceThrottle::OnCheckUrlTimeout); | 283                base::TimeDelta::FromMilliseconds(g_check_url_timeout_ms), this, | 
|  | 284                &RequestChecker::OnCheckUrlTimeout); | 
| 377 | 285 | 
| 378   return false; | 286   return DEFER; | 
| 379 } | 287 } | 
| 380 | 288 | 
| 381 void BaseResourceThrottle::OnCheckUrlTimeout() { | 289 void RequestChecker::OnCheckUrlTimeout() { | 
| 382   CHECK_EQ(state_, STATE_CHECKING_URL); | 290   CHECK_EQ(state_, STATE_CHECKING_URL); | 
| 383 | 291 | 
| 384   database_manager_->CancelCheck(this); | 292   database_manager_->CancelCheck(this); | 
| 385 | 293 | 
| 386   OnCheckBrowseUrlResult(url_being_checked_, safe_browsing::SB_THREAT_TYPE_SAFE, | 294   OnCheckBrowseUrlResult(url_being_checked_, safe_browsing::SB_THREAT_TYPE_SAFE, | 
| 387                          ThreatMetadata()); | 295                          ThreatMetadata()); | 
| 388 } | 296 } | 
| 389 | 297 | 
| 390 void BaseResourceThrottle::ResumeRequest() { | 298 void RequestChecker::ResumeRequest() { | 
| 391   CHECK_EQ(state_, STATE_NONE); | 299   CHECK_EQ(state_, STATE_NONE); | 
| 392   CHECK_NE(defer_state_, DEFERRED_NONE); | 300   CHECK_NE(defer_state_, DEFERRED_NONE); | 
| 393 | 301 | 
| 394   bool resume = true; | 302   bool resume = true; | 
| 395   if (defer_state_ == DEFERRED_UNCHECKED_REDIRECT) { | 303   if (defer_state_ == DEFERRED_UNCHECKED_REDIRECT) { | 
|  | 304     DCHECK(unchecked_redirect_url_.is_valid()); | 
|  | 305     GURL unchecked_redirect_url; | 
|  | 306     unchecked_redirect_url_.Swap(&unchecked_redirect_url); | 
| 396     // Save the redirect urls for possible malware detail reporting later. | 307     // Save the redirect urls for possible malware detail reporting later. | 
| 397     redirect_urls_.push_back(unchecked_redirect_url_); | 308     redirect_urls_.push_back(unchecked_redirect_url); | 
| 398     if (!CheckUrl(unchecked_redirect_url_)) { | 309     if (!CheckUrl(unchecked_redirect_url)) { | 
| 399       // We're now waiting for the unchecked_redirect_url_. | 310       // We're now waiting for the unchecked_redirect_url. | 
| 400       defer_state_ = DEFERRED_REDIRECT; | 311       defer_state_ = DEFERRED_REDIRECT; | 
| 401       resume = false; | 312       resume = false; | 
| 402       BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, | 313       BeginNetLogEvent(NetLogEventType::SAFE_BROWSING_DEFERRED, | 
| 403                        unchecked_redirect_url_, "defer_reason", | 314                        unchecked_redirect_url, "defer_reason", | 
| 404                        "resumed_redirect"); | 315                        "resumed_redirect"); | 
| 405     } | 316     } | 
| 406   } | 317   } | 
| 407 | 318 | 
| 408   if (resume) { | 319   if (resume) { | 
| 409     defer_state_ = DEFERRED_NONE; | 320     defer_state_ = DEFERRED_NONE; | 
| 410     Resume(); | 321     delegate_->ResumeResourceRequest(); | 
| 411   } | 322   } | 
| 412 } | 323 } | 
| 413 | 324 | 
|  | 325 // Note on net_log calls: SAFE_BROWSING_DEFERRED events must be wholly | 
|  | 326 // nested within SAFE_BROWSING_CHECKING_URL events.  Synchronous checks | 
|  | 327 // are not logged at all. | 
|  | 328 void RequestChecker::BeginNetLogEvent(NetLogEventType type, | 
|  | 329                                       const GURL& url, | 
|  | 330                                       const char* name, | 
|  | 331                                       const char* value) { | 
|  | 332   net_log_with_source_.BeginEvent( | 
|  | 333       type, base::Bind(&NetLogUrlCallback, request_, url, name, value)); | 
|  | 334   request_->net_log().AddEvent( | 
|  | 335       type, net_log_with_source_.source().ToEventParametersCallback()); | 
|  | 336 } | 
|  | 337 | 
|  | 338 void RequestChecker::EndNetLogEvent(NetLogEventType type, | 
|  | 339                                     const char* name, | 
|  | 340                                     const char* value) { | 
|  | 341   net_log_with_source_.EndEvent(type, | 
|  | 342                                 base::Bind(&NetLogStringCallback, name, value)); | 
|  | 343   request_->net_log().AddEvent( | 
|  | 344       type, net_log_with_source_.source().ToEventParametersCallback()); | 
|  | 345 } | 
|  | 346 | 
|  | 347 ScopedTimeoutForTesting::ScopedTimeoutForTesting(int new_timeout_ms) | 
|  | 348     : original_timeout_ms_(g_check_url_timeout_ms) { | 
|  | 349   g_check_url_timeout_ms = new_timeout_ms; | 
|  | 350 } | 
|  | 351 | 
|  | 352 ScopedTimeoutForTesting::ScopedTimeoutForTesting(ScopedTimeoutForTesting&& rhs) | 
|  | 353     : original_timeout_ms_(rhs.original_timeout_ms_) { | 
|  | 354   rhs.original_timeout_ms_ = -1; | 
|  | 355 } | 
|  | 356 | 
|  | 357 ScopedTimeoutForTesting::~ScopedTimeoutForTesting() { | 
|  | 358   if (original_timeout_ms_ != -1) | 
|  | 359     g_check_url_timeout_ms = original_timeout_ms_; | 
|  | 360 } | 
|  | 361 | 
| 414 }  // namespace safe_browsing | 362 }  // namespace safe_browsing | 
| OLD | NEW | 
|---|