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 |