blob: e6ce194c0032dcdb0a6c40079eb6b3d256d2e0ca [file]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/subresource_filter/core/common/document_subresource_filter.h"
#include <memory>
#include <string_view>
#include <utility>
#include "base/check.h"
#include "base/check_op.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/strcat.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "components/subresource_filter/core/common/first_party_origin.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
#include "components/subresource_filter/core/common/scoped_timers.h"
#include "components/subresource_filter/core/common/time_measurements.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace subresource_filter {
DocumentSubresourceFilter::DocumentSubresourceFilter(
url::Origin document_origin,
mojom::ActivationState activation_state,
scoped_refptr<const MemoryMappedRuleset> ruleset,
std::string_view uma_tag)
: activation_state_(activation_state),
ruleset_(std::move(ruleset)),
ruleset_matcher_(ruleset_->data()),
uma_tag_(uma_tag) {
CHECK_NE(activation_state_.activation_level,
mojom::ActivationLevel::kDisabled);
if (!activation_state_.filtering_disabled_for_document) {
document_origin_ =
std::make_unique<FirstPartyOrigin>(std::move(document_origin));
}
}
DocumentSubresourceFilter::~DocumentSubresourceFilter() = default;
LoadPolicy DocumentSubresourceFilter::GetLoadPolicy(
const GURL& subresource_url,
url_pattern_index::proto::ElementType subresource_type,
ScopedRule* out_rule) {
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"),
"DocumentSubresourceFilter::GetLoadPolicy", "url",
subresource_url.spec());
++statistics_.num_loads_total;
if (activation_state_.filtering_disabled_for_document) {
return LoadPolicy::ALLOW;
}
if (subresource_url.SchemeIs(url::kDataScheme)) {
return LoadPolicy::ALLOW;
}
// If ThreadTicks is not supported, then no CPU time measurements have been
// collected. Don't report both CPU and wall duration to be consistent.
auto wall_duration_timer = ScopedTimers::StartIf(
activation_state_.measure_performance &&
ScopedThreadTimers::IsSupported(),
[this](base::TimeDelta delta) {
static bool first_run = true;
statistics_.evaluation_total_wall_duration += delta;
// Here we use custom histograms to maintain subresource filter
// metrics, which used UMA_HISTOGRAM_MICRO_TIMES prior to introducing
// support for fingerprinting protection filter counterpart.
UmaHistogramCustomMicrosecondsTimes(
base::StrCat(
{uma_tag_, ".SubresourceLoad.Evaluation.WallDuration"}),
delta, base::Microseconds(1), base::Seconds(1), 50);
if (first_run) {
UmaHistogramCustomMicrosecondsTimes(
base::StrCat(
{uma_tag_,
".SubresourceLoad.Evaluation.WallDuration.FirstRun"}),
delta, base::Microseconds(1), base::Seconds(1), 50);
first_run = false;
}
});
auto cpu_duration_timer = ScopedThreadTimers::StartIf(
activation_state_.measure_performance, [this](base::TimeDelta delta) {
statistics_.evaluation_total_cpu_duration += delta;
UmaHistogramCustomMicrosecondsTimes(
base::StrCat({uma_tag_, ".SubresourceLoad.Evaluation.CPUDuration"}),
delta, base::Microseconds(1), base::Seconds(1), 50);
});
++statistics_.num_loads_evaluated;
CHECK(document_origin_);
const url_pattern_index::flat::UrlRule* rule = nullptr;
LoadPolicy result = ruleset_matcher_.GetLoadPolicyForResourceLoad(
subresource_url, *document_origin_, subresource_type,
activation_state_.generic_blocking_rules_disabled, /*out_rule=*/&rule);
if (out_rule && rule) {
*out_rule = ScopedRule(ruleset_, rule);
}
CHECK_NE(LoadPolicy::WOULD_DISALLOW, result);
if (result == LoadPolicy::DISALLOW) {
++statistics_.num_loads_matching_rules;
if (activation_state_.activation_level ==
mojom::ActivationLevel::kEnabled) {
++statistics_.num_loads_disallowed;
return LoadPolicy::DISALLOW;
} else if (activation_state_.activation_level ==
mojom::ActivationLevel::kDryRun) {
return LoadPolicy::WOULD_DISALLOW;
}
}
return result;
}
bool DocumentSubresourceFilter::MaybeHasStyleRule(uint32_t hash) const {
if (activation_state_.filtering_disabled_for_document) {
return false;
}
return ruleset_matcher_.MaybeHasStyleRule(hash);
}
void DocumentSubresourceFilter::GetDomainSelectors(
std::vector<std::string_view>& out_selectors) const {
if (activation_state_.filtering_disabled_for_document) {
return;
}
CHECK(document_origin_);
ruleset_matcher_.GetDomainSelectors(document_origin_->origin(),
out_selectors);
}
void DocumentSubresourceFilter::GetSelectorsByClass(
std::string_view class_name,
uint32_t hash,
std::vector<std::string_view>& out_selectors) const {
if (activation_state_.filtering_disabled_for_document) {
return;
}
CHECK(document_origin_);
ruleset_matcher_.GetSelectorsByClass(document_origin_->origin(), class_name,
hash, out_selectors);
}
void DocumentSubresourceFilter::GetSelectorsById(
std::string_view id_name,
uint32_t hash,
std::vector<std::string_view>& out_selectors) const {
if (activation_state_.filtering_disabled_for_document) {
return;
}
CHECK(document_origin_);
ruleset_matcher_.GetSelectorsById(document_origin_->origin(), id_name, hash,
out_selectors);
}
const url_pattern_index::flat::UrlRule*
DocumentSubresourceFilter::FindMatchingUrlRule(
const GURL& subresource_url,
url_pattern_index::proto::ElementType subresource_type) {
if (activation_state_.filtering_disabled_for_document) {
return nullptr;
}
if (subresource_url.SchemeIs(url::kDataScheme)) {
return nullptr;
}
return ruleset_matcher_.MatchedUrlRule(
subresource_url, *document_origin_, subresource_type,
activation_state_.generic_blocking_rules_disabled);
}
uint64_t DocumentSubresourceFilter::GetRulesetId() const {
return ruleset_matcher_.ruleset_id();
}
} // namespace subresource_filter