| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/subresource_filter/content/browser/content_subresource_filt
er_driver_factory.h" | 5 #include "components/subresource_filter/content/browser/content_subresource_filt
er_driver_factory.h" |
| 6 | 6 |
| 7 #include "base/feature_list.h" | 7 #include "base/feature_list.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 10 #include "base/rand_util.h" | 10 #include "base/rand_util.h" |
| 11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
| 12 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
| 13 #include "base/trace_event/trace_event_argument.h" | 13 #include "base/trace_event/trace_event_argument.h" |
| 14 #include "components/subresource_filter/content/browser/content_activation_list_
utils.h" | 14 #include "components/subresource_filter/content/browser/content_activation_list_
utils.h" |
| 15 #include "components/subresource_filter/content/browser/subresource_filter_clien
t.h" | 15 #include "components/subresource_filter/content/browser/subresource_filter_clien
t.h" |
| 16 #include "components/subresource_filter/core/browser/subresource_filter_features
.h" | 16 #include "components/subresource_filter/core/browser/subresource_filter_features
.h" |
| 17 #include "components/subresource_filter/core/common/activation_list.h" | 17 #include "components/subresource_filter/core/common/activation_list.h" |
| 18 #include "components/subresource_filter/core/common/activation_state.h" | 18 #include "components/subresource_filter/core/common/activation_state.h" |
| 19 #include "content/public/browser/navigation_handle.h" | 19 #include "content/public/browser/navigation_handle.h" |
| 20 #include "content/public/browser/navigation_throttle.h" | |
| 21 #include "content/public/browser/web_contents.h" | 20 #include "content/public/browser/web_contents.h" |
| 22 #include "net/base/net_errors.h" | 21 #include "net/base/net_errors.h" |
| 23 #include "url/gurl.h" | 22 #include "url/gurl.h" |
| 24 | 23 |
| 25 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | 24 DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
| 26 subresource_filter::ContentSubresourceFilterDriverFactory); | 25 subresource_filter::ContentSubresourceFilterDriverFactory); |
| 27 | 26 |
| 28 namespace subresource_filter { | 27 namespace subresource_filter { |
| 29 | 28 |
| 30 namespace { | 29 namespace { |
| 31 | 30 |
| 32 std::string DistillURLToHostAndPath(const GURL& url) { | |
| 33 return url.host() + url.path(); | |
| 34 } | |
| 35 | |
| 36 // Returns true with a probability given by |performance_measurement_rate| if | 31 // Returns true with a probability given by |performance_measurement_rate| if |
| 37 // ThreadTicks is supported, otherwise returns false. | 32 // ThreadTicks is supported, otherwise returns false. |
| 38 bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) { | 33 bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) { |
| 39 if (!base::ThreadTicks::IsSupported()) | 34 if (!base::ThreadTicks::IsSupported()) |
| 40 return false; | 35 return false; |
| 41 return performance_measurement_rate == 1 || | 36 return performance_measurement_rate == 1 || |
| 42 (performance_measurement_rate > 0 && | 37 (performance_measurement_rate > 0 && |
| 43 base::RandDouble() < performance_measurement_rate); | 38 base::RandDouble() < performance_measurement_rate); |
| 44 } | 39 } |
| 45 | 40 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 73 client_(client), | 68 client_(client), |
| 74 throttle_manager_( | 69 throttle_manager_( |
| 75 base::MakeUnique<ContentSubresourceFilterThrottleManager>( | 70 base::MakeUnique<ContentSubresourceFilterThrottleManager>( |
| 76 this, | 71 this, |
| 77 client_->GetRulesetDealer(), | 72 client_->GetRulesetDealer(), |
| 78 web_contents)) {} | 73 web_contents)) {} |
| 79 | 74 |
| 80 ContentSubresourceFilterDriverFactory:: | 75 ContentSubresourceFilterDriverFactory:: |
| 81 ~ContentSubresourceFilterDriverFactory() {} | 76 ~ContentSubresourceFilterDriverFactory() {} |
| 82 | 77 |
| 83 void ContentSubresourceFilterDriverFactory:: | 78 void ContentSubresourceFilterDriverFactory::OnSafeBrowsingMatchComputed( |
| 84 OnMainResourceMatchedSafeBrowsingBlacklist( | 79 content::NavigationHandle* navigation_handle, |
| 85 const GURL& url, | 80 safe_browsing::SBThreatType threat_type, |
| 86 safe_browsing::SBThreatType threat_type, | 81 safe_browsing::ThreatPatternType threat_type_metadata) { |
| 87 safe_browsing::ThreatPatternType threat_type_metadata) { | 82 DCHECK(navigation_handle->IsInMainFrame()); |
| 88 AddActivationListMatch( | 83 DCHECK(!navigation_handle->IsSameDocument()); |
| 89 url, GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata)); | 84 if (navigation_handle->GetNetErrorCode() != net::OK) |
| 85 return; |
| 86 |
| 87 ActivationList activation_list = |
| 88 GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata); |
| 89 const GURL& url = navigation_handle->GetURL(); |
| 90 const content::Referrer& referrer = navigation_handle->GetReferrer(); |
| 91 ui::PageTransition transition = navigation_handle->GetPageTransition(); |
| 92 |
| 93 if (activation_options_.should_whitelist_site_on_reload && |
| 94 NavigationIsPageReload(url, referrer, transition)) { |
| 95 // Whitelist this host for the current as well as subsequent navigations. |
| 96 client_->WhitelistInCurrentWebContents(url); |
| 97 } |
| 98 |
| 99 ComputeActivationForMainFrameNavigation(navigation_handle, activation_list); |
| 100 DCHECK_NE(activation_decision_, ActivationDecision::UNKNOWN); |
| 101 |
| 102 // Check for whitelisted status last, so that the client gets an accurate |
| 103 // indication of whether there would be activation otherwise. |
| 104 bool whitelisted = client_->OnPageActivationComputed( |
| 105 navigation_handle, |
| 106 activation_options_.activation_level == ActivationLevel::ENABLED); |
| 107 |
| 108 // Only reset the activation decision reason if we would have activated. |
| 109 if (whitelisted && activation_decision_ == ActivationDecision::ACTIVATED) { |
| 110 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationWhitelisted"); |
| 111 activation_decision_ = ActivationDecision::URL_WHITELISTED; |
| 112 activation_options_ = Configuration::ActivationOptions(); |
| 113 } |
| 114 |
| 115 if (activation_decision_ != ActivationDecision::ACTIVATED) { |
| 116 DCHECK_EQ(activation_options_.activation_level, ActivationLevel::DISABLED); |
| 117 return; |
| 118 } |
| 119 |
| 120 DCHECK_NE(activation_options_.activation_level, ActivationLevel::DISABLED); |
| 121 ActivationState state = ActivationState(activation_options_.activation_level); |
| 122 state.measure_performance = ShouldMeasurePerformanceForPageLoad( |
| 123 activation_options_.performance_measurement_rate); |
| 124 // TODO(csharrison): Set state.enable_logging based on metadata returns from |
| 125 // the safe browsing filter, when it is available. Add tests for this |
| 126 // behavior. |
| 127 throttle_manager_->NotifyPageActivationComputed(navigation_handle, state); |
| 90 } | 128 } |
| 91 | 129 |
| 92 void ContentSubresourceFilterDriverFactory:: | 130 void ContentSubresourceFilterDriverFactory:: |
| 93 ComputeActivationForMainFrameNavigation( | 131 ComputeActivationForMainFrameNavigation( |
| 94 content::NavigationHandle* navigation_handle) { | 132 content::NavigationHandle* navigation_handle, |
| 133 ActivationList matched_list) { |
| 95 const GURL& url(navigation_handle->GetURL()); | 134 const GURL& url(navigation_handle->GetURL()); |
| 96 | 135 |
| 97 if (!url.SchemeIsHTTPOrHTTPS()) { | 136 if (!url.SchemeIsHTTPOrHTTPS()) { |
| 98 activation_decision_ = ActivationDecision::UNSUPPORTED_SCHEME; | 137 activation_decision_ = ActivationDecision::UNSUPPORTED_SCHEME; |
| 99 activation_options_ = Configuration::ActivationOptions(); | 138 activation_options_ = Configuration::ActivationOptions(); |
| 100 return; | 139 return; |
| 101 } | 140 } |
| 102 | 141 |
| 103 const auto config_list = GetEnabledConfigurations(); | 142 const auto config_list = GetEnabledConfigurations(); |
| 104 const auto highest_priority_activated_config = | 143 const auto highest_priority_activated_config = |
| 105 std::find_if(config_list->configs_by_decreasing_priority().begin(), | 144 std::find_if(config_list->configs_by_decreasing_priority().begin(), |
| 106 config_list->configs_by_decreasing_priority().end(), | 145 config_list->configs_by_decreasing_priority().end(), |
| 107 [&url, this](const Configuration& config) { | 146 [&url, matched_list, this](const Configuration& config) { |
| 108 return DoesMainFrameURLSatisfyActivationConditions( | 147 return DoesMainFrameURLSatisfyActivationConditions( |
| 109 url, config.activation_conditions); | 148 url, config.activation_conditions, matched_list); |
| 110 }); | 149 }); |
| 111 | 150 |
| 112 bool has_activated_config = | 151 bool has_activated_config = |
| 113 highest_priority_activated_config != | 152 highest_priority_activated_config != |
| 114 config_list->configs_by_decreasing_priority().end(); | 153 config_list->configs_by_decreasing_priority().end(); |
| 115 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), | 154 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), |
| 116 "ContentSubresourceFilterDriverFactory::" | 155 "ContentSubresourceFilterDriverFactory::" |
| 117 "ComputeActivationForMainFrameNavigation", | 156 "ComputeActivationForMainFrameNavigation", |
| 118 "highest_priority_activated_config", | 157 "highest_priority_activated_config", |
| 119 has_activated_config | 158 has_activated_config |
| 120 ? highest_priority_activated_config->ToTracedValue() | 159 ? highest_priority_activated_config->ToTracedValue() |
| 121 : base::MakeUnique<base::trace_event::TracedValue>()); | 160 : base::MakeUnique<base::trace_event::TracedValue>()); |
| 122 if (!has_activated_config) { | 161 if (!has_activated_config) { |
| 123 activation_decision_ = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; | 162 activation_decision_ = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; |
| 124 activation_options_ = Configuration::ActivationOptions(); | 163 activation_options_ = Configuration::ActivationOptions(); |
| 125 return; | 164 return; |
| 126 } | 165 } |
| 127 | 166 |
| 128 activation_options_ = highest_priority_activated_config->activation_options; | 167 activation_options_ = highest_priority_activated_config->activation_options; |
| 129 activation_decision_ = | 168 activation_decision_ = |
| 130 activation_options_.activation_level == ActivationLevel::DISABLED | 169 activation_options_.activation_level == ActivationLevel::DISABLED |
| 131 ? ActivationDecision::ACTIVATION_DISABLED | 170 ? ActivationDecision::ACTIVATION_DISABLED |
| 132 : ActivationDecision::ACTIVATED; | 171 : ActivationDecision::ACTIVATED; |
| 133 } | 172 } |
| 134 | 173 |
| 135 bool ContentSubresourceFilterDriverFactory:: | 174 bool ContentSubresourceFilterDriverFactory:: |
| 136 DoesMainFrameURLSatisfyActivationConditions( | 175 DoesMainFrameURLSatisfyActivationConditions( |
| 137 const GURL& url, | 176 const GURL& url, |
| 138 const Configuration::ActivationConditions& conditions) const { | 177 const Configuration::ActivationConditions& conditions, |
| 178 ActivationList matched_list) const { |
| 139 switch (conditions.activation_scope) { | 179 switch (conditions.activation_scope) { |
| 140 case ActivationScope::ALL_SITES: | 180 case ActivationScope::ALL_SITES: |
| 141 return true; | 181 return true; |
| 142 case ActivationScope::ACTIVATION_LIST: | 182 case ActivationScope::ACTIVATION_LIST: |
| 143 if (DidURLMatchActivationList(url, conditions.activation_list)) | 183 if (conditions.activation_list == matched_list) |
| 144 return true; | 184 return true; |
| 145 if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL && | 185 if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL && |
| 146 DidURLMatchActivationList( | 186 matched_list == ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) { |
| 147 url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL)) { | |
| 148 // Handling special case, where activation on the phishing sites also | 187 // Handling special case, where activation on the phishing sites also |
| 149 // mean the activation on the sites with social engineering metadata. | 188 // mean the activation on the sites with social engineering metadata. |
| 150 return true; | 189 return true; |
| 151 } | 190 } |
| 152 return false; | 191 return false; |
| 153 case ActivationScope::NO_SITES: | 192 case ActivationScope::NO_SITES: |
| 154 return false; | 193 return false; |
| 155 } | 194 } |
| 156 NOTREACHED(); | 195 NOTREACHED(); |
| 157 return false; | 196 return false; |
| 158 } | 197 } |
| 159 | 198 |
| 160 void ContentSubresourceFilterDriverFactory::OnReloadRequested() { | 199 void ContentSubresourceFilterDriverFactory::OnReloadRequested() { |
| 161 UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true); | 200 UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true); |
| 162 const GURL& whitelist_url = web_contents()->GetLastCommittedURL(); | 201 const GURL& whitelist_url = web_contents()->GetLastCommittedURL(); |
| 163 | 202 |
| 164 // Only whitelist via content settings when using the experimental UI, | 203 // Only whitelist via content settings when using the experimental UI, |
| 165 // otherwise could get into a situation where content settings cannot be | 204 // otherwise could get into a situation where content settings cannot be |
| 166 // adjusted. | 205 // adjusted. |
| 167 if (base::FeatureList::IsEnabled( | 206 if (base::FeatureList::IsEnabled( |
| 168 subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)) { | 207 subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)) { |
| 169 client_->WhitelistByContentSettings(whitelist_url); | 208 client_->WhitelistByContentSettings(whitelist_url); |
| 170 } else { | 209 } else { |
| 171 client_->WhitelistInCurrentWebContents(whitelist_url); | 210 client_->WhitelistInCurrentWebContents(whitelist_url); |
| 172 } | 211 } |
| 173 web_contents()->GetController().Reload(content::ReloadType::NORMAL, true); | 212 web_contents()->GetController().Reload(content::ReloadType::NORMAL, true); |
| 174 } | 213 } |
| 175 | 214 |
| 176 void ContentSubresourceFilterDriverFactory::WillProcessResponse( | |
| 177 content::NavigationHandle* navigation_handle) { | |
| 178 DCHECK(!navigation_handle->IsSameDocument()); | |
| 179 if (!navigation_handle->IsInMainFrame() || | |
| 180 navigation_handle->GetNetErrorCode() != net::OK) { | |
| 181 return; | |
| 182 } | |
| 183 | |
| 184 const GURL& url = navigation_handle->GetURL(); | |
| 185 const content::Referrer& referrer = navigation_handle->GetReferrer(); | |
| 186 ui::PageTransition transition = navigation_handle->GetPageTransition(); | |
| 187 | |
| 188 if (activation_options_.should_whitelist_site_on_reload && | |
| 189 NavigationIsPageReload(url, referrer, transition)) { | |
| 190 // Whitelist this host for the current as well as subsequent navigations. | |
| 191 client_->WhitelistInCurrentWebContents(url); | |
| 192 } | |
| 193 | |
| 194 ComputeActivationForMainFrameNavigation(navigation_handle); | |
| 195 DCHECK_NE(activation_decision_, ActivationDecision::UNKNOWN); | |
| 196 | |
| 197 // Check for whitelisted status last, so that the client gets an accurate | |
| 198 // indication of whether there would be activation otherwise. | |
| 199 bool whitelisted = client_->OnPageActivationComputed( | |
| 200 navigation_handle, | |
| 201 activation_options_.activation_level == ActivationLevel::ENABLED); | |
| 202 | |
| 203 // Only reset the activation decision reason if we would have activated. | |
| 204 if (whitelisted && activation_decision_ == ActivationDecision::ACTIVATED) { | |
| 205 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ActivationWhitelisted"); | |
| 206 activation_decision_ = ActivationDecision::URL_WHITELISTED; | |
| 207 activation_options_ = Configuration::ActivationOptions(); | |
| 208 } | |
| 209 | |
| 210 if (activation_decision_ != ActivationDecision::ACTIVATED) { | |
| 211 DCHECK_EQ(activation_options_.activation_level, ActivationLevel::DISABLED); | |
| 212 return; | |
| 213 } | |
| 214 | |
| 215 DCHECK_NE(activation_options_.activation_level, ActivationLevel::DISABLED); | |
| 216 ActivationState state = ActivationState(activation_options_.activation_level); | |
| 217 state.measure_performance = ShouldMeasurePerformanceForPageLoad( | |
| 218 activation_options_.performance_measurement_rate); | |
| 219 // TODO(csharrison): Set state.enable_logging based on metadata returns from | |
| 220 // the safe browsing filter, when it is available. Add tests for this | |
| 221 // behavior. | |
| 222 throttle_manager_->NotifyPageActivationComputed(navigation_handle, state); | |
| 223 } | |
| 224 | |
| 225 void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() { | 215 void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() { |
| 226 if (activation_options_.should_suppress_notifications) | 216 if (activation_options_.should_suppress_notifications) |
| 227 return; | 217 return; |
| 228 client_->ToggleNotificationVisibility(activation_options_.activation_level == | 218 client_->ToggleNotificationVisibility(activation_options_.activation_level == |
| 229 ActivationLevel::ENABLED); | 219 ActivationLevel::ENABLED); |
| 230 } | 220 } |
| 231 | 221 |
| 232 void ContentSubresourceFilterDriverFactory::DidStartNavigation( | 222 void ContentSubresourceFilterDriverFactory::DidStartNavigation( |
| 233 content::NavigationHandle* navigation_handle) { | 223 content::NavigationHandle* navigation_handle) { |
| 234 if (navigation_handle->IsInMainFrame() && | 224 if (navigation_handle->IsInMainFrame() && |
| 235 !navigation_handle->IsSameDocument()) { | 225 !navigation_handle->IsSameDocument()) { |
| 236 activation_decision_ = ActivationDecision::UNKNOWN; | 226 activation_decision_ = ActivationDecision::UNKNOWN; |
| 237 activation_list_matches_.clear(); | |
| 238 client_->ToggleNotificationVisibility(false); | 227 client_->ToggleNotificationVisibility(false); |
| 239 } | 228 } |
| 240 } | 229 } |
| 241 | 230 |
| 242 void ContentSubresourceFilterDriverFactory::DidFinishNavigation( | 231 void ContentSubresourceFilterDriverFactory::DidFinishNavigation( |
| 243 content::NavigationHandle* navigation_handle) { | 232 content::NavigationHandle* navigation_handle) { |
| 244 if (navigation_handle->IsInMainFrame() && | 233 if (navigation_handle->IsInMainFrame() && |
| 245 !navigation_handle->IsSameDocument() && | 234 !navigation_handle->IsSameDocument() && |
| 246 activation_decision_ == ActivationDecision::UNKNOWN && | 235 activation_decision_ == ActivationDecision::UNKNOWN && |
| 247 navigation_handle->HasCommitted()) { | 236 navigation_handle->HasCommitted()) { |
| 248 activation_decision_ = ActivationDecision::ACTIVATION_DISABLED; | 237 activation_decision_ = ActivationDecision::ACTIVATION_DISABLED; |
| 249 activation_options_ = Configuration::ActivationOptions(); | 238 activation_options_ = Configuration::ActivationOptions(); |
| 250 } | 239 } |
| 251 } | 240 } |
| 252 | 241 |
| 253 bool ContentSubresourceFilterDriverFactory::DidURLMatchActivationList( | |
| 254 const GURL& url, | |
| 255 ActivationList activation_list) const { | |
| 256 auto match_types = | |
| 257 activation_list_matches_.find(DistillURLToHostAndPath(url)); | |
| 258 return match_types != activation_list_matches_.end() && | |
| 259 match_types->second.find(activation_list) != match_types->second.end(); | |
| 260 } | |
| 261 | |
| 262 void ContentSubresourceFilterDriverFactory::AddActivationListMatch( | |
| 263 const GURL& url, | |
| 264 ActivationList match_type) { | |
| 265 if (match_type == ActivationList::NONE) | |
| 266 return; | |
| 267 if (url.has_host() && url.SchemeIsHTTPOrHTTPS()) | |
| 268 activation_list_matches_[DistillURLToHostAndPath(url)].insert(match_type); | |
| 269 } | |
| 270 | |
| 271 } // namespace subresource_filter | 242 } // namespace subresource_filter |
| OLD | NEW |