| 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 |