OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/subresource_filter/content/common/document_subresource_filt
er.h" | |
6 | |
7 #include <climits> | |
8 | |
9 #include "base/logging.h" | |
10 #include "base/strings/string_piece.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "base/trace_event/trace_event.h" | |
13 #include "components/subresource_filter/core/common/first_party_origin.h" | |
14 #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" | |
15 #include "components/subresource_filter/core/common/scoped_timers.h" | |
16 #include "components/subresource_filter/core/common/time_measurements.h" | |
17 #include "third_party/WebKit/public/platform/WebURL.h" | |
18 | |
19 namespace subresource_filter { | |
20 | |
21 namespace { | |
22 | |
23 proto::ElementType ToElementType( | |
24 blink::WebURLRequest::RequestContext request_context) { | |
25 switch (request_context) { | |
26 case blink::WebURLRequest::RequestContextAudio: | |
27 case blink::WebURLRequest::RequestContextVideo: | |
28 case blink::WebURLRequest::RequestContextTrack: | |
29 return proto::ELEMENT_TYPE_MEDIA; | |
30 case blink::WebURLRequest::RequestContextBeacon: | |
31 case blink::WebURLRequest::RequestContextPing: | |
32 return proto::ELEMENT_TYPE_PING; | |
33 case blink::WebURLRequest::RequestContextEmbed: | |
34 case blink::WebURLRequest::RequestContextObject: | |
35 case blink::WebURLRequest::RequestContextPlugin: | |
36 return proto::ELEMENT_TYPE_OBJECT; | |
37 case blink::WebURLRequest::RequestContextEventSource: | |
38 case blink::WebURLRequest::RequestContextFetch: | |
39 case blink::WebURLRequest::RequestContextXMLHttpRequest: | |
40 return proto::ELEMENT_TYPE_XMLHTTPREQUEST; | |
41 case blink::WebURLRequest::RequestContextFavicon: | |
42 case blink::WebURLRequest::RequestContextImage: | |
43 case blink::WebURLRequest::RequestContextImageSet: | |
44 return proto::ELEMENT_TYPE_IMAGE; | |
45 case blink::WebURLRequest::RequestContextFont: | |
46 return proto::ELEMENT_TYPE_FONT; | |
47 case blink::WebURLRequest::RequestContextFrame: | |
48 case blink::WebURLRequest::RequestContextForm: | |
49 case blink::WebURLRequest::RequestContextHyperlink: | |
50 case blink::WebURLRequest::RequestContextIframe: | |
51 case blink::WebURLRequest::RequestContextInternal: | |
52 case blink::WebURLRequest::RequestContextLocation: | |
53 return proto::ELEMENT_TYPE_SUBDOCUMENT; | |
54 case blink::WebURLRequest::RequestContextScript: | |
55 case blink::WebURLRequest::RequestContextServiceWorker: | |
56 case blink::WebURLRequest::RequestContextSharedWorker: | |
57 return proto::ELEMENT_TYPE_SCRIPT; | |
58 case blink::WebURLRequest::RequestContextStyle: | |
59 case blink::WebURLRequest::RequestContextXSLT: | |
60 return proto::ELEMENT_TYPE_STYLESHEET; | |
61 | |
62 case blink::WebURLRequest::RequestContextPrefetch: | |
63 case blink::WebURLRequest::RequestContextSubresource: | |
64 return proto::ELEMENT_TYPE_OTHER; | |
65 | |
66 case blink::WebURLRequest::RequestContextCSPReport: | |
67 case blink::WebURLRequest::RequestContextDownload: | |
68 case blink::WebURLRequest::RequestContextImport: | |
69 case blink::WebURLRequest::RequestContextManifest: | |
70 case blink::WebURLRequest::RequestContextUnspecified: | |
71 default: | |
72 return proto::ELEMENT_TYPE_UNSPECIFIED; | |
73 } | |
74 } | |
75 | |
76 ActivationState ComputeActivationStateImpl( | |
77 const GURL& document_url, | |
78 const url::Origin& parent_document_origin, | |
79 const ActivationState& parent_activation_state, | |
80 const IndexedRulesetMatcher& matcher) { | |
81 ActivationState activation_state = parent_activation_state; | |
82 if (activation_state.filtering_disabled_for_document) | |
83 return activation_state; | |
84 | |
85 // TODO(pkalinnikov): Match several activation types in a batch. | |
86 if (matcher.ShouldDisableFilteringForDocument( | |
87 document_url, parent_document_origin, | |
88 proto::ACTIVATION_TYPE_DOCUMENT)) { | |
89 activation_state.filtering_disabled_for_document = true; | |
90 } else if (!activation_state.generic_blocking_rules_disabled && | |
91 matcher.ShouldDisableFilteringForDocument( | |
92 document_url, parent_document_origin, | |
93 proto::ACTIVATION_TYPE_GENERICBLOCK)) { | |
94 activation_state.generic_blocking_rules_disabled = true; | |
95 } | |
96 return activation_state; | |
97 } | |
98 | |
99 } // namespace | |
100 | |
101 ActivationState ComputeActivationState( | |
102 const GURL& document_url, | |
103 const url::Origin& parent_document_origin, | |
104 const ActivationState& parent_activation_state, | |
105 const MemoryMappedRuleset* ruleset) { | |
106 DCHECK(ruleset); | |
107 IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length()); | |
108 return ComputeActivationStateImpl(document_url, parent_document_origin, | |
109 parent_activation_state, matcher); | |
110 } | |
111 | |
112 ActivationState ComputeActivationState( | |
113 ActivationLevel activation_level, | |
114 bool measure_performance, | |
115 const std::vector<GURL>& ancestor_document_urls, | |
116 const MemoryMappedRuleset* ruleset) { | |
117 SCOPED_UMA_HISTOGRAM_MICRO_TIMER( | |
118 "SubresourceFilter.DocumentLoad.Activation.WallDuration"); | |
119 SCOPED_UMA_HISTOGRAM_MICRO_THREAD_TIMER( | |
120 "SubresourceFilter.DocumentLoad.Activation.CPUDuration"); | |
121 | |
122 ActivationState activation_state(activation_level); | |
123 activation_state.measure_performance = measure_performance; | |
124 DCHECK(ruleset); | |
125 | |
126 IndexedRulesetMatcher matcher(ruleset->data(), ruleset->length()); | |
127 | |
128 url::Origin parent_document_origin; | |
129 for (auto iter = ancestor_document_urls.rbegin(), | |
130 rend = ancestor_document_urls.rend(); | |
131 iter != rend; ++iter) { | |
132 const GURL& document_url(*iter); | |
133 activation_state = ComputeActivationStateImpl( | |
134 document_url, parent_document_origin, activation_state, matcher); | |
135 parent_document_origin = url::Origin(document_url); | |
136 } | |
137 | |
138 return activation_state; | |
139 } | |
140 | |
141 DocumentSubresourceFilter::DocumentSubresourceFilter( | |
142 url::Origin document_origin, | |
143 ActivationState activation_state, | |
144 scoped_refptr<const MemoryMappedRuleset> ruleset, | |
145 base::OnceClosure first_disallowed_load_callback) | |
146 : activation_state_(activation_state), | |
147 ruleset_(std::move(ruleset)), | |
148 ruleset_matcher_(ruleset_->data(), ruleset_->length()), | |
149 first_disallowed_load_callback_( | |
150 std::move(first_disallowed_load_callback)) { | |
151 DCHECK_NE(activation_state_.activation_level, ActivationLevel::DISABLED); | |
152 if (!activation_state_.filtering_disabled_for_document) | |
153 document_origin_.reset(new FirstPartyOrigin(std::move(document_origin))); | |
154 } | |
155 | |
156 DocumentSubresourceFilter::~DocumentSubresourceFilter() = default; | |
157 | |
158 blink::WebDocumentSubresourceFilter::LoadPolicy | |
159 DocumentSubresourceFilter::getLoadPolicy( | |
160 const blink::WebURL& resourceUrl, | |
161 blink::WebURLRequest::RequestContext request_context) { | |
162 ++statistics_.num_loads_total; | |
163 | |
164 if (activation_state_.filtering_disabled_for_document) | |
165 return Allow; | |
166 if (resourceUrl.protocolIs(url::kDataScheme)) | |
167 return Allow; | |
168 | |
169 // TODO(pkalinnikov): Would be good to avoid converting to GURL. | |
170 return EvaluateLoadPolicy(GURL(resourceUrl), ToElementType(request_context)); | |
171 } | |
172 | |
173 blink::WebDocumentSubresourceFilter::LoadPolicy | |
174 DocumentSubresourceFilter::GetLoadPolicyForSubdocument( | |
175 const GURL& subdocument_url) { | |
176 ++statistics_.num_loads_total; | |
177 | |
178 if (activation_state_.filtering_disabled_for_document) | |
179 return Allow; | |
180 if (subdocument_url.SchemeIs(url::kDataScheme)) | |
181 return Allow; | |
182 return EvaluateLoadPolicy(subdocument_url, proto::ELEMENT_TYPE_SUBDOCUMENT); | |
183 } | |
184 | |
185 void DocumentSubresourceFilter::reportDisallowedLoad() { | |
186 if (first_disallowed_load_callback_.is_null()) | |
187 return; | |
188 std::move(first_disallowed_load_callback_).Run(); | |
189 } | |
190 | |
191 blink::WebDocumentSubresourceFilter::LoadPolicy | |
192 DocumentSubresourceFilter::EvaluateLoadPolicy(const GURL& resource_url, | |
193 proto::ElementType element_type) { | |
194 TRACE_EVENT1("loader", "DocumentSubresourceFilter::EvaluateLoadPolicy", "url", | |
195 resource_url.spec()); | |
196 | |
197 auto wall_duration_timer = ScopedTimers::StartIf( | |
198 activation_state_.measure_performance && | |
199 ScopedThreadTimers::IsSupported(), | |
200 [this](base::TimeDelta delta) { | |
201 statistics_.evaluation_total_wall_duration += delta; | |
202 UMA_HISTOGRAM_MICRO_TIMES( | |
203 "SubresourceFilter.SubresourceLoad.Evaluation.WallDuration", delta); | |
204 }); | |
205 auto cpu_duration_timer = ScopedThreadTimers::StartIf( | |
206 activation_state_.measure_performance, [this](base::TimeDelta delta) { | |
207 statistics_.evaluation_total_cpu_duration += delta; | |
208 UMA_HISTOGRAM_MICRO_TIMES( | |
209 "SubresourceFilter.SubresourceLoad.Evaluation.CPUDuration", delta); | |
210 }); | |
211 | |
212 ++statistics_.num_loads_evaluated; | |
213 DCHECK(document_origin_); | |
214 if (ruleset_matcher_.ShouldDisallowResourceLoad( | |
215 resource_url, *document_origin_, element_type, | |
216 activation_state_.generic_blocking_rules_disabled)) { | |
217 ++statistics_.num_loads_matching_rules; | |
218 if (activation_state_.activation_level == ActivationLevel::ENABLED) { | |
219 ++statistics_.num_loads_disallowed; | |
220 return Disallow; | |
221 } else if (activation_state_.activation_level == ActivationLevel::DRYRUN) { | |
222 return WouldDisallow; | |
223 } | |
224 } | |
225 return Allow; | |
226 } | |
227 | |
228 } // namespace subresource_filter | |
OLD | NEW |