| Index: extensions/common/api/declarative_net_request/indexed_rule.cc
|
| diff --git a/extensions/common/api/declarative_net_request/indexed_rule.cc b/extensions/common/api/declarative_net_request/indexed_rule.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..9bb6394f82d21433ec55edbe1a9e5dc725298474
|
| --- /dev/null
|
| +++ b/extensions/common/api/declarative_net_request/indexed_rule.cc
|
| @@ -0,0 +1,276 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "extensions/common/api/declarative_net_request/indexed_rule.h"
|
| +
|
| +#include <set>
|
| +#include <utility>
|
| +
|
| +#include "base/numerics/safe_conversions.h"
|
| +#include "base/stl_util.h"
|
| +#include "extensions/common/api/declarative_net_request/constants.h"
|
| +
|
| +namespace extensions {
|
| +namespace declarative_net_request {
|
| +
|
| +namespace {
|
| +
|
| +class UrlFilterParser {
|
| + public:
|
| + UrlFilterParser(std::string url_filter, IndexedRule* indexed_rule)
|
| + : url_filter_(std::move(url_filter)),
|
| + url_filter_len_(url_filter_.length()),
|
| + index_(0),
|
| + result_(ParseResult::SUCCESS),
|
| + indexed_rule_(indexed_rule) {
|
| + DCHECK_NE(0u, url_filter_len_);
|
| + }
|
| +
|
| + ParseResult Parse() {
|
| + DCHECK_EQ(0u, index_);
|
| + DCHECK_EQ(ParseResult::SUCCESS, result_);
|
| +
|
| + ParseLeftAnchor();
|
| + DCHECK(result_ != ParseResult::SUCCESS || index_ <= 2u);
|
| +
|
| + ParseFilterString();
|
| + DCHECK(result_ != ParseResult::SUCCESS || index_ == url_filter_len_ ||
|
| + index_ + 1 == url_filter_len_);
|
| +
|
| + ParseRightAnchor();
|
| + DCHECK(result_ != ParseResult::SUCCESS || index_ == url_filter_len_);
|
| +
|
| + return result_;
|
| + }
|
| +
|
| + void ParseLeftAnchor() {
|
| + DCHECK_EQ(0u, index_);
|
| + DCHECK_EQ(ParseResult::SUCCESS, result_);
|
| +
|
| + indexed_rule_->anchor_left = AnchorType::AnchorType_NONE;
|
| +
|
| + if (IsAtAnchor()) {
|
| + index_++;
|
| + indexed_rule_->anchor_left = AnchorType::AnchorType_BOUNDARY;
|
| + if (IsAtAnchor()) {
|
| + index_++;
|
| + indexed_rule_->anchor_left = AnchorType::AnchorType_SUBDOMAIN;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void ParseFilterString() {
|
| + if (result_ != ParseResult::SUCCESS)
|
| + return;
|
| +
|
| + indexed_rule_->url_pattern_type = UrlPatternType::UrlPatternType_SUBSTRING;
|
| + int left_index = index_;
|
| + while (index_ < url_filter_len_) {
|
| + if (IsAtRightAnchor())
|
| + break;
|
| + if (IsAtSeparatorOrWildcard())
|
| + indexed_rule_->url_pattern_type =
|
| + UrlPatternType::UrlPatternType_WILDCARDED;
|
| + index_++;
|
| + }
|
| + // Note empty url patterns need to be supported.
|
| + indexed_rule_->url_pattern =
|
| + url_filter_.substr(left_index, index_ - left_index);
|
| + }
|
| +
|
| + void ParseRightAnchor() {
|
| + if (result_ != ParseResult::SUCCESS)
|
| + return;
|
| + indexed_rule_->anchor_right = AnchorType::AnchorType_NONE;
|
| + if (IsAtRightAnchor()) {
|
| + index_++;
|
| + indexed_rule_->anchor_right = AnchorType::AnchorType_BOUNDARY;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + bool IsAtSeparatorOrWildcard() const {
|
| + return IsAtValidIndex() && (url_filter_[index_] == kSeparatorCharacter ||
|
| + url_filter_[index_] == kWildcardCharacter);
|
| + }
|
| +
|
| + bool IsAtRightAnchor() const {
|
| + return IsAtAnchor() && index_ > 0 && index_ + 1 == url_filter_len_;
|
| + }
|
| +
|
| + bool IsAtValidIndex() const { return index_ < url_filter_len_; }
|
| +
|
| + bool IsAtAnchor() const {
|
| + return IsAtValidIndex() && url_filter_[index_] == kAnchorCharacter;
|
| + }
|
| +
|
| + static constexpr char kAnchorCharacter = '|';
|
| + static constexpr char kSeparatorCharacter = '^';
|
| + static constexpr char kWildcardCharacter = '*';
|
| +
|
| + const std::string url_filter_;
|
| + const size_t url_filter_len_;
|
| + size_t index_;
|
| + ParseResult result_;
|
| + IndexedRule* indexed_rule_; // Weak.
|
| +};
|
| +
|
| +uint8_t GetOptionsMask(const Rule& parsed_rule) {
|
| + uint8_t mask = OptionFlag::OptionFlag_NONE;
|
| + if (parsed_rule.action.type ==
|
| + api::declarative_net_request::RULE_ACTION_TYPE_WHITELIST)
|
| + mask |= OptionFlag::OptionFlag_IS_WHITELIST;
|
| + if (parsed_rule.condition.url_filter_is_case_sensitive &&
|
| + *parsed_rule.condition.url_filter_is_case_sensitive)
|
| + mask |= OptionFlag::OptionFlag_IS_MATCH_CASE;
|
| +
|
| + switch (parsed_rule.condition.domain_type) {
|
| + case api::declarative_net_request::DOMAIN_TYPE_FIRST_PARTY:
|
| + mask |= OptionFlag::OptionFlag_APPLIES_TO_FIRST_PARTY;
|
| + break;
|
| + case api::declarative_net_request::DOMAIN_TYPE_THIRD_PARTY:
|
| + mask |= OptionFlag::OptionFlag_APPLIES_TO_THIRD_PARTY;
|
| + break;
|
| + case api::declarative_net_request::DOMAIN_TYPE_ANY:
|
| + case api::declarative_net_request::DOMAIN_TYPE_NONE:
|
| + mask |= (OptionFlag::OptionFlag_APPLIES_TO_FIRST_PARTY |
|
| + OptionFlag::OptionFlag_APPLIES_TO_THIRD_PARTY);
|
| + break;
|
| + }
|
| + return mask;
|
| +}
|
| +
|
| +uint8_t GetActivationTypes(const Rule& parsed_rule) {
|
| + // Extensions don't use any activation types.
|
| + return ActivationType::ActivationType_NONE;
|
| +}
|
| +
|
| +ElementType GetElementType(
|
| + api::declarative_net_request::ResourceType resource_type) {
|
| + switch (resource_type) {
|
| + case api::declarative_net_request::RESOURCE_TYPE_NONE:
|
| + return ElementType::ElementType_NONE;
|
| + case api::declarative_net_request::RESOURCE_TYPE_SUB_FRAME:
|
| + return ElementType::ElementType_SUBDOCUMENT;
|
| + case api::declarative_net_request::RESOURCE_TYPE_STYLESHEET:
|
| + return ElementType::ElementType_STYLESHEET;
|
| + case api::declarative_net_request::RESOURCE_TYPE_SCRIPT:
|
| + return ElementType::ElementType_SCRIPT;
|
| + case api::declarative_net_request::RESOURCE_TYPE_IMAGE:
|
| + return ElementType::ElementType_IMAGE;
|
| + case api::declarative_net_request::RESOURCE_TYPE_FONT:
|
| + return ElementType::ElementType_FONT;
|
| + case api::declarative_net_request::RESOURCE_TYPE_OBJECT:
|
| + return ElementType::ElementType_OBJECT;
|
| + case api::declarative_net_request::RESOURCE_TYPE_XMLHTTPREQUEST:
|
| + return ElementType::ElementType_XMLHTTPREQUEST;
|
| + case api::declarative_net_request::RESOURCE_TYPE_PING:
|
| + return ElementType::ElementType_PING;
|
| + case api::declarative_net_request::RESOURCE_TYPE_MEDIA:
|
| + return ElementType::ElementType_MEDIA;
|
| + case api::declarative_net_request::RESOURCE_TYPE_WEBSOCKET:
|
| + return ElementType::ElementType_WEBSOCKET;
|
| + case api::declarative_net_request::RESOURCE_TYPE_OTHER:
|
| + return ElementType::ElementType_OTHER;
|
| + }
|
| + NOTREACHED();
|
| + return ElementType::ElementType_NONE;
|
| +}
|
| +
|
| +uint16_t GetResourceTypesMask(
|
| + const std::vector<api::declarative_net_request::ResourceType>*
|
| + resource_types) {
|
| + if (!resource_types)
|
| + return ElementType::ElementType_NONE;
|
| +
|
| + uint16_t mask = ElementType::ElementType_NONE;
|
| + for (const auto resource_type : *resource_types)
|
| + mask |= GetElementType(resource_type);
|
| + DCHECK(!(mask & (ElementType::ElementType_OBJECT_SUBREQUEST |
|
| + ElementType::ElementType_POPUP)));
|
| + return mask;
|
| +}
|
| +
|
| +ParseResult ComputeElementTypes(const Rule& rule, uint16_t* element_types) {
|
| + uint16_t include_element_type_mask =
|
| + GetResourceTypesMask(rule.condition.resource_types.get());
|
| + uint16_t exclude_element_type_mask =
|
| + GetResourceTypesMask(rule.condition.exclude_resource_types.get());
|
| + exclude_element_type_mask |= (ElementType::ElementType_POPUP |
|
| + ElementType::ElementType_OBJECT_SUBREQUEST);
|
| + if (include_element_type_mask & exclude_element_type_mask)
|
| + return ParseResult::ERROR_RESOURCE_TYPE_DUPLICATED;
|
| + *element_types = (include_element_type_mask ? include_element_type_mask
|
| + : ElementType::ElementType_ANY) &
|
| + (~exclude_element_type_mask);
|
| + return ParseResult::SUCCESS;
|
| +}
|
| +
|
| +std::vector<std::string> GetSortedAndUniqueDomains(
|
| + std::unique_ptr<std::vector<std::string>> domains) {
|
| + std::vector<std::string> result;
|
| + if (!domains)
|
| + return result;
|
| + // TODO is std::move necessary already rvalue.
|
| + result = std::move(*domains.release());
|
| + std::sort(result.begin(), result.end());
|
| + result.erase(std::unique(result.begin(), result.end()), result.end());
|
| + return result;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +IndexedRule::IndexedRule() = default;
|
| +IndexedRule::~IndexedRule() = default;
|
| +
|
| +ParseResult CreateIndexedRule(std::unique_ptr<Rule> parsed_rule,
|
| + IndexedRule* indexed_rule) {
|
| + DCHECK(indexed_rule);
|
| +
|
| + if (parsed_rule->id < kMinValidID)
|
| + return ParseResult::ERROR_INVALID_RULE_ID;
|
| +
|
| + const bool is_redirect_rule =
|
| + parsed_rule->action.type ==
|
| + api::declarative_net_request::RULE_ACTION_TYPE_REDIRECT;
|
| + if (is_redirect_rule && (!parsed_rule->action.redirect_url ||
|
| + parsed_rule->action.redirect_url->empty()))
|
| + return ParseResult::ERROR_EMPTY_REDIRECT_URL;
|
| + if (is_redirect_rule && !parsed_rule->priority)
|
| + return ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY;
|
| + if (is_redirect_rule && *parsed_rule->priority < kMinValidPriority)
|
| + return ParseResult::ERROR_INVALID_REDIRECT_RULE_PRIORITY;
|
| +
|
| + indexed_rule->id = base::checked_cast<uint32_t>(parsed_rule->id);
|
| + indexed_rule->priority = base::checked_cast<uint32_t>(
|
| + parsed_rule->priority ? *parsed_rule->priority : kDefaultPriority);
|
| + indexed_rule->options = GetOptionsMask(*parsed_rule);
|
| + indexed_rule->activation_types = GetActivationTypes(*parsed_rule);
|
| +
|
| + // TODO is std::move needed here, already an rvalue.
|
| +
|
| + indexed_rule->domains_included =
|
| + GetSortedAndUniqueDomains(std::move(parsed_rule->condition.domains));
|
| + indexed_rule->domains_excluded = GetSortedAndUniqueDomains(
|
| + std::move(parsed_rule->condition.excluded_domains));
|
| +
|
| + ParseResult result =
|
| + ComputeElementTypes(*parsed_rule, &indexed_rule->element_types);
|
| + if (result != ParseResult::SUCCESS)
|
| + return result;
|
| +
|
| + if (parsed_rule->condition.url_filter &&
|
| + !parsed_rule->condition.url_filter->empty()) {
|
| + UrlFilterParser parser(
|
| + std::move(*parsed_rule->condition.url_filter.release()), indexed_rule);
|
| + result = parser.Parse();
|
| + if (result != ParseResult::SUCCESS)
|
| + return result;
|
| + }
|
| +
|
| + return ParseResult::SUCCESS;
|
| +}
|
| +
|
| +} // namespace extensions
|
| +} // namespace declarative_net_request
|
|
|