blob: 8ff23bd8d809e652afdb3da160e166ddd58fc935 [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.
#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_
#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <string_view>
#include <vector>
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "components/subresource_filter/core/common/flat/indexed_ruleset_generated.h"
#include "components/subresource_filter/core/common/load_policy.h"
#include "components/subresource_filter/core/common/style_rule_indexer.h"
#include "components/subresource_filter/core/common/style_rule_matcher.h"
#include "components/url_pattern_index/url_pattern_index.h"
#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h"
class GURL;
namespace url {
class Origin;
}
namespace url_pattern_index {
namespace proto {
class StyleRule;
class UrlRule;
}
} // namespace url_pattern_index
namespace subresource_filter {
class FirstPartyOrigin;
// Returns a hash for a style rule's anchor (e.g., a class or ID name without
// the '.' or '#' prefix). This is meant to provide the exact same hash value as
// blink's `AtomicString` would, and there are blink unittests to verify as
// much.
uint32_t GetStyleRuleHash(std::string_view name);
// Detailed result of IndexedRulesetMatcher::Verify.
// Note: Logged to UMA, keep in sync with SubresourceFilterVerifyStatus in
// enums.xml. Add new entries to the end and do not renumber.
enum class VerifyStatus {
kPassValidChecksum = 0,
kChecksumFailVerifierPass = 1,
kChecksumFailVerifierFail = 2,
kVerifierFailChecksumPass = 3,
kVerifierFailChecksumZero = 4,
kPassChecksumZero = 5,
kMaxValue = kPassChecksumZero
};
// The class used to construct flat data structures representing the set of URL
// filtering rules, as well as the index of those. Internally owns a
// FlatBufferBuilder storing the structures.
class RulesetIndexer {
public:
// The current binary format version of the indexed ruleset.
//
// Increase this value when introducing an incompatible change in
// IndexedRuleset format, or otherwise willing to nudge clients to rebuild
// their ruleset (e.g., a change is compatible, but significantly reduces the
// size of the buffer). Note: The PRESUBMIT.py script tries to keep
// contributors aware of that.
static const int kIndexedFormatVersion;
explicit RulesetIndexer(uint64_t ruleset_id);
RulesetIndexer(const RulesetIndexer&) = delete;
RulesetIndexer& operator=(const RulesetIndexer&) = delete;
~RulesetIndexer();
// Adds |rule| to the ruleset and the index unless the |rule| has unsupported
// filter options, in which case the data structures remain unmodified.
// Returns whether the |rule| has been serialized and added to the index.
bool AddUrlRule(const url_pattern_index::proto::UrlRule& rule);
// Adds |rule| to the style rule index.
bool AddStyleRuleFromProto(const url_pattern_index::proto::StyleRule& rule);
// Finalizes construction of the data structures.
void Finish();
// Returns the checksum for the data buffer.
int GetChecksum() const;
// Returns a pointer to the buffer containing the serialized flat data
// structures. Should only be called after Finish().
base::span<const uint8_t> data() const LIFETIME_BOUND {
return UNSAFE_TODO(
base::span(builder_.GetBufferPointer(), builder_.GetSize()));
}
uint64_t ruleset_id() const { return ruleset_id_; }
private:
flatbuffers::FlatBufferBuilder builder_;
url_pattern_index::UrlPatternIndexBuilder blocklist_;
url_pattern_index::UrlPatternIndexBuilder allowlist_;
url_pattern_index::UrlPatternIndexBuilder deactivation_;
StyleRuleIndexer style_rule_indexer_;
// Maintains a map of domain vectors to their existing offsets, to avoid
// storing a particular vector more than once.
url_pattern_index::FlatDomainMap domain_map_;
uint64_t ruleset_id_ = 0;
};
// Matches URLs against the FlatBuffer representation of an indexed ruleset.
class IndexedRulesetMatcher {
public:
// Returns whether the |buffer| of the given |size| contains a valid
// flat::IndexedRuleset FlatBuffer.
static bool Verify(base::span<const uint8_t> buffer,
int expected_checksum,
std::string_view uma_tag);
// Creates an instance that matches URLs against the flat::IndexedRuleset
// provided as the root object of serialized data in the |buffer|.
explicit IndexedRulesetMatcher(base::span<const uint8_t> buffer);
IndexedRulesetMatcher(const IndexedRulesetMatcher&) = delete;
IndexedRulesetMatcher& operator=(const IndexedRulesetMatcher&) = delete;
~IndexedRulesetMatcher();
// Returns whether the subset of subresource filtering rules specified by the
// |activation_type| should be disabled for the |document| loaded from
// |parent_document_origin|. Always returns false if |activation_type| ==
// ACTIVATION_TYPE_UNSPECIFIED or the |document_url| is not valid. Unlike
// page-level activation, such rules can be used to have fine-grained control
// over the activation of filtering within (sub-)documents.
bool ShouldDisableFilteringForDocument(
const GURL& document_url,
const url::Origin& parent_document_origin,
url_pattern_index::proto::ActivationType activation_type) const;
// Returns the LoadPolicy for a network request to |url| of |element_type|
// initiated by |document_origin|. Always returns ALLOW if the |url| is not
// valid or |element_type| == ELEMENT_TYPE_UNSPECIFIED. If `out_rule` is
// non-null and the result load policy is DISALLOW, then `out_rule` will be
// populated with a pointer to the matching filterlist rule. `out_rule` is
// valid as long as the ruleset is kept alive.
LoadPolicy GetLoadPolicyForResourceLoad(
const GURL& url,
const FirstPartyOrigin& first_party,
url_pattern_index::proto::ElementType element_type,
bool disable_generic_rules,
const url_pattern_index::flat::UrlRule** out_rule) const;
// Like ShouldDisallowResourceLoad, but returns the matching rule that
// determines whether the request should be allowed or not. Allowlist rules
// override blocklist rules. If no rule matches, returns nullptr.
const url_pattern_index::flat::UrlRule* MatchedUrlRule(
const GURL& url,
const FirstPartyOrigin& first_party,
url_pattern_index::proto::ElementType element_type,
bool disable_generic_rules) const;
uint64_t ruleset_id() const { return root_->ruleset_id(); }
// Returns the selectors that apply to the `document_origin`.
void GetDomainSelectors(const url::Origin& document_origin,
std::vector<std::string_view>& out_selectors) const;
// Note: several methods below take a `hash` argument. It is a hash of either
// the class or id in question. The `hash` should be the same as that would
// be provided by `blink::AtomicString::hash()` if the string is ascii,
// otherwise the string needs to be converted to UTF8 and `GetStyleRuleHash`
// should be called on it.
// Returns whether the ruleset might have any selectors matching the given
// `hash`. This is backed by a bloom filter, so it may return false positives
// but not false negatives.
bool MaybeHasStyleRule(uint32_t hash) const;
// Returns the selectors that contain `class_name` and apply to the
// `document_origin`.
void GetSelectorsByClass(const url::Origin& document_origin,
std::string_view class_name,
uint32_t hash,
std::vector<std::string_view>& out_selectors) const;
// Returns the selectors that contain `id_name` and apply to the
// `document_origin`.
void GetSelectorsById(const url::Origin& document_origin,
std::string_view id_name,
uint32_t hash,
std::vector<std::string_view>& out_selectors) const;
private:
raw_ptr<const flat::IndexedRuleset> root_;
url_pattern_index::UrlPatternIndexMatcher blocklist_;
url_pattern_index::UrlPatternIndexMatcher allowlist_;
url_pattern_index::UrlPatternIndexMatcher deactivation_;
StyleRuleMatcher style_rule_matcher_;
};
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_INDEXED_RULESET_H_