blob: 82ed70603de0dbc5bbf126f37dbc276a3af1d83e [file] [log] [blame]
// 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/browser/api/declarative_net_request/ruleset_matcher.h"
#include <utility>
#include "base/containers/span.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/timer/elapsed_timer.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/utils.h"
#include "extensions/common/api/declarative_net_request/utils.h"
#include "url/gurl.h"
namespace extensions {
namespace declarative_net_request {
namespace flat_rule = url_pattern_index::flat;
namespace {
using FindRuleStrategy =
url_pattern_index::UrlPatternIndexMatcher::FindRuleStrategy;
} // namespace
// static
RulesetMatcher::LoadRulesetResult RulesetMatcher::CreateVerifiedMatcher(
const base::FilePath& indexed_ruleset_path,
int expected_ruleset_checksum,
std::unique_ptr<RulesetMatcher>* matcher) {
DCHECK(matcher);
DCHECK(IsAPIAvailable());
base::ElapsedTimer timer;
if (!base::PathExists(indexed_ruleset_path))
return kLoadErrorInvalidPath;
std::string ruleset_data;
if (!base::ReadFileToString(indexed_ruleset_path, &ruleset_data))
return kLoadErrorFileRead;
if (!StripVersionHeaderAndParseVersion(&ruleset_data))
return kLoadErrorVersionMismatch;
// This guarantees that no memory access will end up outside the buffer.
if (!IsValidRulesetData(
base::make_span(reinterpret_cast<const uint8_t*>(ruleset_data.data()),
ruleset_data.size()),
expected_ruleset_checksum)) {
return kLoadErrorChecksumMismatch;
}
UMA_HISTOGRAM_TIMES(
"Extensions.DeclarativeNetRequest.CreateVerifiedMatcherTime",
timer.Elapsed());
// Using WrapUnique instead of make_unique since this class has a private
// constructor.
*matcher = base::WrapUnique(new RulesetMatcher(std::move(ruleset_data)));
return kLoadSuccess;
}
RulesetMatcher::~RulesetMatcher() = default;
bool RulesetMatcher::ShouldBlockRequest(const GURL& url,
const url::Origin& first_party_origin,
flat_rule::ElementType element_type,
bool is_third_party) const {
SCOPED_UMA_HISTOGRAM_TIMER(
"Extensions.DeclarativeNetRequest.ShouldBlockRequestTime."
"SingleExtension");
// Don't exclude generic rules from being matched. A generic rule is one with
// an empty included domains list.
const bool disable_generic_rules = false;
bool success =
!!blocking_matcher_.FindMatch(
url, first_party_origin, element_type, flat_rule::ActivationType_NONE,
is_third_party, disable_generic_rules, FindRuleStrategy::kAny) &&
!allowing_matcher_.FindMatch(
url, first_party_origin, element_type, flat_rule::ActivationType_NONE,
is_third_party, disable_generic_rules, FindRuleStrategy::kAny);
return success;
}
bool RulesetMatcher::ShouldRedirectRequest(
const GURL& url,
const url::Origin& first_party_origin,
flat_rule::ElementType element_type,
bool is_third_party,
GURL* redirect_url) const {
DCHECK(redirect_url);
DCHECK_NE(flat_rule::ElementType_WEBSOCKET, element_type);
SCOPED_UMA_HISTOGRAM_TIMER(
"Extensions.DeclarativeNetRequest.ShouldRedirectRequestTime."
"SingleExtension");
// Don't exclude generic rules from being matched. A generic rule is one with
// an empty included domains list.
const bool disable_generic_rules = false;
// Retrieve the highest priority matching rule corresponding to the given
// request parameters.
const flat_rule::UrlRule* rule = redirect_matcher_.FindMatch(
url, first_party_origin, element_type, flat_rule::ActivationType_NONE,
is_third_party, disable_generic_rules,
FindRuleStrategy::kHighestPriority);
if (!rule)
return false;
// Find the UrlRuleMetadata corresponding to |rule|. Since |metadata_list_| is
// sorted by rule id, use LookupByKey which binary searches for fast lookup.
const flat::UrlRuleMetadata* metadata =
metadata_list_->LookupByKey(rule->id());
// There must be a UrlRuleMetadata object corresponding to each redirect rule.
DCHECK(metadata);
DCHECK_EQ(metadata->id(), rule->id());
*redirect_url = GURL(base::StringPiece(metadata->redirect_url()->c_str(),
metadata->redirect_url()->size()));
DCHECK(redirect_url->is_valid());
return true;
}
RulesetMatcher::RulesetMatcher(std::string ruleset_data)
: ruleset_data_(std::move(ruleset_data)),
root_(flat::GetExtensionIndexedRuleset(ruleset_data_.data())),
blocking_matcher_(root_->blocking_index()),
allowing_matcher_(root_->allowing_index()),
redirect_matcher_(root_->redirect_index()),
metadata_list_(root_->extension_metadata()) {}
} // namespace declarative_net_request
} // namespace extensions