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" |
20 #include "content/public/browser/web_contents.h" | 21 #include "content/public/browser/web_contents.h" |
21 #include "net/base/net_errors.h" | 22 #include "net/base/net_errors.h" |
22 #include "url/gurl.h" | 23 #include "url/gurl.h" |
23 | 24 |
24 DEFINE_WEB_CONTENTS_USER_DATA_KEY( | 25 DEFINE_WEB_CONTENTS_USER_DATA_KEY( |
25 subresource_filter::ContentSubresourceFilterDriverFactory); | 26 subresource_filter::ContentSubresourceFilterDriverFactory); |
26 | 27 |
27 namespace subresource_filter { | 28 namespace subresource_filter { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
| 32 std::string DistillURLToHostAndPath(const GURL& url) { |
| 33 return url.host() + url.path(); |
| 34 } |
| 35 |
31 // Returns true with a probability given by |performance_measurement_rate| if | 36 // Returns true with a probability given by |performance_measurement_rate| if |
32 // ThreadTicks is supported, otherwise returns false. | 37 // ThreadTicks is supported, otherwise returns false. |
33 bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) { | 38 bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) { |
34 if (!base::ThreadTicks::IsSupported()) | 39 if (!base::ThreadTicks::IsSupported()) |
35 return false; | 40 return false; |
36 return performance_measurement_rate == 1 || | 41 return performance_measurement_rate == 1 || |
37 (performance_measurement_rate > 0 && | 42 (performance_measurement_rate > 0 && |
38 base::RandDouble() < performance_measurement_rate); | 43 base::RandDouble() < performance_measurement_rate); |
39 } | 44 } |
40 | 45 |
(...skipping 27 matching lines...) Expand all Loading... |
68 client_(client), | 73 client_(client), |
69 throttle_manager_( | 74 throttle_manager_( |
70 base::MakeUnique<ContentSubresourceFilterThrottleManager>( | 75 base::MakeUnique<ContentSubresourceFilterThrottleManager>( |
71 this, | 76 this, |
72 client_->GetRulesetDealer(), | 77 client_->GetRulesetDealer(), |
73 web_contents)) {} | 78 web_contents)) {} |
74 | 79 |
75 ContentSubresourceFilterDriverFactory:: | 80 ContentSubresourceFilterDriverFactory:: |
76 ~ContentSubresourceFilterDriverFactory() {} | 81 ~ContentSubresourceFilterDriverFactory() {} |
77 | 82 |
78 void ContentSubresourceFilterDriverFactory::OnSafeBrowsingMatchComputed( | 83 void ContentSubresourceFilterDriverFactory:: |
79 content::NavigationHandle* navigation_handle, | 84 OnMainResourceMatchedSafeBrowsingBlacklist( |
80 safe_browsing::SBThreatType threat_type, | 85 const GURL& url, |
81 safe_browsing::ThreatPatternType threat_type_metadata) { | 86 safe_browsing::SBThreatType threat_type, |
82 DCHECK(navigation_handle->IsInMainFrame()); | 87 safe_browsing::ThreatPatternType threat_type_metadata) { |
83 DCHECK(!navigation_handle->IsSameDocument()); | 88 AddActivationListMatch( |
84 if (navigation_handle->GetNetErrorCode() != net::OK) | 89 url, GetListForThreatTypeAndMetadata(threat_type, threat_type_metadata)); |
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); | |
128 } | 90 } |
129 | 91 |
130 void ContentSubresourceFilterDriverFactory:: | 92 void ContentSubresourceFilterDriverFactory:: |
131 ComputeActivationForMainFrameNavigation( | 93 ComputeActivationForMainFrameNavigation( |
132 content::NavigationHandle* navigation_handle, | 94 content::NavigationHandle* navigation_handle) { |
133 ActivationList matched_list) { | |
134 const GURL& url(navigation_handle->GetURL()); | 95 const GURL& url(navigation_handle->GetURL()); |
135 | 96 |
136 if (!url.SchemeIsHTTPOrHTTPS()) { | 97 if (!url.SchemeIsHTTPOrHTTPS()) { |
137 activation_decision_ = ActivationDecision::UNSUPPORTED_SCHEME; | 98 activation_decision_ = ActivationDecision::UNSUPPORTED_SCHEME; |
138 activation_options_ = Configuration::ActivationOptions(); | 99 activation_options_ = Configuration::ActivationOptions(); |
139 return; | 100 return; |
140 } | 101 } |
141 | 102 |
142 const auto config_list = GetEnabledConfigurations(); | 103 const auto config_list = GetEnabledConfigurations(); |
143 const auto highest_priority_activated_config = | 104 const auto highest_priority_activated_config = |
144 std::find_if(config_list->configs_by_decreasing_priority().begin(), | 105 std::find_if(config_list->configs_by_decreasing_priority().begin(), |
145 config_list->configs_by_decreasing_priority().end(), | 106 config_list->configs_by_decreasing_priority().end(), |
146 [&url, matched_list, this](const Configuration& config) { | 107 [&url, this](const Configuration& config) { |
147 return DoesMainFrameURLSatisfyActivationConditions( | 108 return DoesMainFrameURLSatisfyActivationConditions( |
148 url, config.activation_conditions, matched_list); | 109 url, config.activation_conditions); |
149 }); | 110 }); |
150 | 111 |
151 bool has_activated_config = | 112 bool has_activated_config = |
152 highest_priority_activated_config != | 113 highest_priority_activated_config != |
153 config_list->configs_by_decreasing_priority().end(); | 114 config_list->configs_by_decreasing_priority().end(); |
154 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), | 115 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"), |
155 "ContentSubresourceFilterDriverFactory::" | 116 "ContentSubresourceFilterDriverFactory::" |
156 "ComputeActivationForMainFrameNavigation", | 117 "ComputeActivationForMainFrameNavigation", |
157 "highest_priority_activated_config", | 118 "highest_priority_activated_config", |
158 has_activated_config | 119 has_activated_config |
159 ? highest_priority_activated_config->ToTracedValue() | 120 ? highest_priority_activated_config->ToTracedValue() |
160 : base::MakeUnique<base::trace_event::TracedValue>()); | 121 : base::MakeUnique<base::trace_event::TracedValue>()); |
161 if (!has_activated_config) { | 122 if (!has_activated_config) { |
162 activation_decision_ = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; | 123 activation_decision_ = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET; |
163 activation_options_ = Configuration::ActivationOptions(); | 124 activation_options_ = Configuration::ActivationOptions(); |
164 return; | 125 return; |
165 } | 126 } |
166 | 127 |
167 activation_options_ = highest_priority_activated_config->activation_options; | 128 activation_options_ = highest_priority_activated_config->activation_options; |
168 activation_decision_ = | 129 activation_decision_ = |
169 activation_options_.activation_level == ActivationLevel::DISABLED | 130 activation_options_.activation_level == ActivationLevel::DISABLED |
170 ? ActivationDecision::ACTIVATION_DISABLED | 131 ? ActivationDecision::ACTIVATION_DISABLED |
171 : ActivationDecision::ACTIVATED; | 132 : ActivationDecision::ACTIVATED; |
172 } | 133 } |
173 | 134 |
174 bool ContentSubresourceFilterDriverFactory:: | 135 bool ContentSubresourceFilterDriverFactory:: |
175 DoesMainFrameURLSatisfyActivationConditions( | 136 DoesMainFrameURLSatisfyActivationConditions( |
176 const GURL& url, | 137 const GURL& url, |
177 const Configuration::ActivationConditions& conditions, | 138 const Configuration::ActivationConditions& conditions) const { |
178 ActivationList matched_list) const { | |
179 switch (conditions.activation_scope) { | 139 switch (conditions.activation_scope) { |
180 case ActivationScope::ALL_SITES: | 140 case ActivationScope::ALL_SITES: |
181 return true; | 141 return true; |
182 case ActivationScope::ACTIVATION_LIST: | 142 case ActivationScope::ACTIVATION_LIST: |
183 if (conditions.activation_list == matched_list) | 143 if (DidURLMatchActivationList(url, conditions.activation_list)) |
184 return true; | 144 return true; |
185 if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL && | 145 if (conditions.activation_list == ActivationList::PHISHING_INTERSTITIAL && |
186 matched_list == ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL) { | 146 DidURLMatchActivationList( |
| 147 url, ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL)) { |
187 // Handling special case, where activation on the phishing sites also | 148 // Handling special case, where activation on the phishing sites also |
188 // mean the activation on the sites with social engineering metadata. | 149 // mean the activation on the sites with social engineering metadata. |
189 return true; | 150 return true; |
190 } | 151 } |
191 return false; | 152 return false; |
192 case ActivationScope::NO_SITES: | 153 case ActivationScope::NO_SITES: |
193 return false; | 154 return false; |
194 } | 155 } |
195 NOTREACHED(); | 156 NOTREACHED(); |
196 return false; | 157 return false; |
197 } | 158 } |
198 | 159 |
199 void ContentSubresourceFilterDriverFactory::OnReloadRequested() { | 160 void ContentSubresourceFilterDriverFactory::OnReloadRequested() { |
200 UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true); | 161 UMA_HISTOGRAM_BOOLEAN("SubresourceFilter.Prompt.NumReloads", true); |
201 const GURL& whitelist_url = web_contents()->GetLastCommittedURL(); | 162 const GURL& whitelist_url = web_contents()->GetLastCommittedURL(); |
202 | 163 |
203 // Only whitelist via content settings when using the experimental UI, | 164 // Only whitelist via content settings when using the experimental UI, |
204 // otherwise could get into a situation where content settings cannot be | 165 // otherwise could get into a situation where content settings cannot be |
205 // adjusted. | 166 // adjusted. |
206 if (base::FeatureList::IsEnabled( | 167 if (base::FeatureList::IsEnabled( |
207 subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)) { | 168 subresource_filter::kSafeBrowsingSubresourceFilterExperimentalUI)) { |
208 client_->WhitelistByContentSettings(whitelist_url); | 169 client_->WhitelistByContentSettings(whitelist_url); |
209 } else { | 170 } else { |
210 client_->WhitelistInCurrentWebContents(whitelist_url); | 171 client_->WhitelistInCurrentWebContents(whitelist_url); |
211 } | 172 } |
212 web_contents()->GetController().Reload(content::ReloadType::NORMAL, true); | 173 web_contents()->GetController().Reload(content::ReloadType::NORMAL, true); |
213 } | 174 } |
214 | 175 |
| 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 |
215 void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() { | 225 void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() { |
216 if (activation_options_.should_suppress_notifications) | 226 if (activation_options_.should_suppress_notifications) |
217 return; | 227 return; |
218 client_->ToggleNotificationVisibility(activation_options_.activation_level == | 228 client_->ToggleNotificationVisibility(activation_options_.activation_level == |
219 ActivationLevel::ENABLED); | 229 ActivationLevel::ENABLED); |
220 } | 230 } |
221 | 231 |
222 void ContentSubresourceFilterDriverFactory::DidStartNavigation( | 232 void ContentSubresourceFilterDriverFactory::DidStartNavigation( |
223 content::NavigationHandle* navigation_handle) { | 233 content::NavigationHandle* navigation_handle) { |
224 if (navigation_handle->IsInMainFrame() && | 234 if (navigation_handle->IsInMainFrame() && |
225 !navigation_handle->IsSameDocument()) { | 235 !navigation_handle->IsSameDocument()) { |
226 activation_decision_ = ActivationDecision::UNKNOWN; | 236 activation_decision_ = ActivationDecision::UNKNOWN; |
| 237 activation_list_matches_.clear(); |
227 client_->ToggleNotificationVisibility(false); | 238 client_->ToggleNotificationVisibility(false); |
228 } | 239 } |
229 } | 240 } |
230 | 241 |
231 void ContentSubresourceFilterDriverFactory::DidFinishNavigation( | 242 void ContentSubresourceFilterDriverFactory::DidFinishNavigation( |
232 content::NavigationHandle* navigation_handle) { | 243 content::NavigationHandle* navigation_handle) { |
233 if (navigation_handle->IsInMainFrame() && | 244 if (navigation_handle->IsInMainFrame() && |
234 !navigation_handle->IsSameDocument() && | 245 !navigation_handle->IsSameDocument() && |
235 activation_decision_ == ActivationDecision::UNKNOWN && | 246 activation_decision_ == ActivationDecision::UNKNOWN && |
236 navigation_handle->HasCommitted()) { | 247 navigation_handle->HasCommitted()) { |
237 activation_decision_ = ActivationDecision::ACTIVATION_DISABLED; | 248 activation_decision_ = ActivationDecision::ACTIVATION_DISABLED; |
238 activation_options_ = Configuration::ActivationOptions(); | 249 activation_options_ = Configuration::ActivationOptions(); |
239 } | 250 } |
240 } | 251 } |
241 | 252 |
| 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 |
242 } // namespace subresource_filter | 271 } // namespace subresource_filter |
OLD | NEW |