910e62b5创建于 1月15日历史提交
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/api/declarative_net_request/ruleset_source.h"

#include <utility>

#include "base/containers/span.h"
#include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/flat_ruleset_indexer.h"
#include "extensions/browser/api/declarative_net_request/indexed_rule.h"
#include "extensions/browser/api/declarative_net_request/parse_info.h"
#include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/extension.h"
#include "third_party/flatbuffers/src/include/flatbuffers/flatbuffers.h"
#include "url/gurl.h"

namespace extensions::declarative_net_request {

RulesetSource::RulesetSource(RulesetID id,
                             size_t rule_count_limit,
                             ExtensionId extension_id,
                             bool enabled)
    : id_(id),
      rule_count_limit_(rule_count_limit),
      extension_id_(std::move(extension_id)),
      enabled_by_default_(enabled) {}

RulesetSource::~RulesetSource() = default;
RulesetSource::RulesetSource(RulesetSource&&) = default;
RulesetSource& RulesetSource::operator=(RulesetSource&&) = default;

ParseInfo RulesetSource::IndexRules(
    std::vector<api::declarative_net_request::Rule> rules,
    uint8_t parse_flags) const {
  DCHECK_LE(rules.size(), rule_count_limit_);

  // Only warnings or errors can be raised for problematic rules, not both.
  DCHECK(!((parse_flags & ParseFlags::kRaiseErrorOnInvalidRules) &&
           (parse_flags & ParseFlags::kRaiseWarningOnInvalidRules)));
  DCHECK(!((parse_flags & ParseFlags::kRaiseErrorOnLargeRegexRules) &&
           (parse_flags & ParseFlags::kRaiseWarningOnLargeRegexRules)));

  FlatRulesetIndexer indexer;
  std::vector<ParseInfo::RuleWarning> rule_warnings;

  size_t rules_count = 0;
  size_t regex_rules_count = 0;
  {
    std::set<int> id_set;  // Ensure all ids are distinct.
    const GURL base_url = Extension::GetBaseURLFromExtensionId(extension_id_);
    for (auto& rule : rules) {
      int rule_id = rule.id;
      bool inserted = id_set.insert(rule_id).second;
      if (!inserted) {
        if (parse_flags & ParseFlags::kRaiseErrorOnInvalidRules) {
          return ParseInfo(ParseResult::ERROR_DUPLICATE_IDS, rule_id);
        }

        if (parse_flags & ParseFlags::kRaiseWarningOnInvalidRules) {
          rule_warnings.push_back(
              {rule_id,
               GetParseError(ParseResult::ERROR_DUPLICATE_IDS, rule_id)});
        }
        continue;
      }

      // Ignore rules that specify response header matching conditions if the
      // feature is disabled.
      // TODO(crbug.com/40727004): Enable this feature for all versions once
      // initial testing is complete.
      bool has_response_header_conditions =
          rule.condition.response_headers.has_value() ||
          rule.condition.excluded_response_headers.has_value();
      if (has_response_header_conditions &&
          !IsResponseHeaderMatchingEnabled()) {
        continue;
      }

      IndexedRule indexed_rule;
      ParseResult parse_result = IndexedRule::CreateIndexedRule(
          std::move(rule), base_url, id(), &indexed_rule);

      if (parse_result == ParseResult::ERROR_REGEX_TOO_LARGE) {
        if (parse_flags & ParseFlags::kRaiseErrorOnLargeRegexRules) {
          return ParseInfo(parse_result, rule_id);
        }

        if (parse_flags & ParseFlags::kRaiseWarningOnLargeRegexRules) {
          rule_warnings.push_back(
              {rule_id, GetParseError(parse_result, rule_id)});
        }
        continue;
      }

      if (parse_result != ParseResult::SUCCESS) {
        if (parse_flags & ParseFlags::kRaiseErrorOnInvalidRules) {
          return ParseInfo(parse_result, rule_id);
        }

        if (parse_flags & ParseFlags::kRaiseWarningOnInvalidRules) {
          rule_warnings.push_back(
              {rule_id, GetParseError(parse_result, rule_id)});
        }
        continue;
      }

      indexer.AddUrlRule(indexed_rule);
      rules_count++;

      if (indexed_rule.url_pattern_type ==
          url_pattern_index::flat::UrlPatternType_REGEXP) {
        regex_rules_count++;
      }
    }
  }

  flatbuffers::DetachedBuffer buffer = indexer.FinishAndReleaseBuffer();
  int ruleset_checksum = GetChecksum(buffer);
  return ParseInfo(rules_count, regex_rules_count, std::move(rule_warnings),
                   std::move(buffer), ruleset_checksum);
}

LoadRulesetResult RulesetSource::CreateVerifiedMatcher(
    std::string data,
    std::unique_ptr<RulesetMatcher>* matcher) const {
  DCHECK(matcher);

  flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t*>(data.data()),
                                 data.size());

  // TODO(karandeepb): This should use a different LoadRulesetResult since it's
  // not a checksum mismatch.
  // This guarantees that no memory access will end up outside the buffer.
  if (!flat::VerifyExtensionIndexedRulesetBuffer(verifier)) {
    return LoadRulesetResult::kErrorChecksumMismatch;
  }

  *matcher =
      std::make_unique<RulesetMatcher>(std::move(data), id(), extension_id());
  return LoadRulesetResult::kSuccess;
}

}  // namespace extensions::declarative_net_request