Commit 61a0c349 authored by Kelvin Jiang's avatar Kelvin Jiang Committed by Commit Bot

[DNR] Return RequestAction for block/redirect rules in RulesetMatcher

This is CL 1/2 which moves the construction of RequestAction from
RulesetManager to RulesetMatcher. This is done in order to attribute
RequestActions to the matched rule it was constructed from.

Bug: 1009887
Change-Id: Ife65eec7b9a81b589753eeac7b4a712a300ff262
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1834561
Commit-Queue: Kelvin Jiang <kelvinjiang@chromium.org>
Reviewed-by: default avatarKaran Bhatia <karandeepb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#705621}
parent 9d9c37b8
...@@ -10,13 +10,14 @@ ...@@ -10,13 +10,14 @@
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h" #include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/browser/api/declarative_net_request/utils.h"
namespace extensions { namespace extensions {
namespace declarative_net_request { namespace declarative_net_request {
namespace flat_rule = url_pattern_index::flat; namespace flat_rule = url_pattern_index::flat;
using PageAccess = PermissionsData::PageAccess; using PageAccess = PermissionsData::PageAccess;
using RedirectAction = CompositeMatcher::RedirectAction; using RedirectActionInfo = CompositeMatcher::RedirectActionInfo;
namespace { namespace {
...@@ -50,45 +51,21 @@ bool HasMatchingAllowRule(const RulesetMatcher* matcher, ...@@ -50,45 +51,21 @@ bool HasMatchingAllowRule(const RulesetMatcher* matcher,
return params.allow_rule_cache[matcher]; return params.allow_rule_cache[matcher];
} }
// Upgrades the url's scheme to HTTPS.
GURL GetUpgradedUrl(const GURL& url) {
DCHECK(url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kFtpScheme));
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kHttpsScheme);
return url.ReplaceComponents(replacements);
}
// Compares |redirect_rule| and |upgrade_rule| and determines the redirect URL
// based on the rule with the higher priority.
GURL GetUrlByRulePriority(const flat_rule::UrlRule* redirect_rule,
const flat_rule::UrlRule* upgrade_rule,
const GURL& request_url,
GURL redirect_rule_url) {
DCHECK(upgrade_rule || redirect_rule);
if (!upgrade_rule)
return redirect_rule_url;
if (!redirect_rule)
return GetUpgradedUrl(request_url);
return upgrade_rule->priority() > redirect_rule->priority()
? GetUpgradedUrl(request_url)
: redirect_rule_url;
}
} // namespace } // namespace
RedirectAction::RedirectAction(base::Optional<GURL> redirect_url, RedirectActionInfo::RedirectActionInfo(base::Optional<RequestAction> action,
bool notify_request_withheld) bool notify_request_withheld)
: redirect_url(std::move(redirect_url)), : action(std::move(action)),
notify_request_withheld(notify_request_withheld) {} notify_request_withheld(notify_request_withheld) {
if (action)
DCHECK_EQ(RequestAction::Type::REDIRECT, action->type);
}
RedirectAction::~RedirectAction() = default; RedirectActionInfo::~RedirectActionInfo() = default;
RedirectAction::RedirectAction(RedirectAction&&) = default; RedirectActionInfo::RedirectActionInfo(RedirectActionInfo&&) = default;
RedirectAction& RedirectAction::operator=(RedirectAction&& other) = default; RedirectActionInfo& RedirectActionInfo::operator=(RedirectActionInfo&& other) =
default;
CompositeMatcher::CompositeMatcher(MatcherList matchers) CompositeMatcher::CompositeMatcher(MatcherList matchers)
: matchers_(std::move(matchers)) { : matchers_(std::move(matchers)) {
...@@ -123,7 +100,8 @@ void CompositeMatcher::AddOrUpdateRuleset( ...@@ -123,7 +100,8 @@ void CompositeMatcher::AddOrUpdateRuleset(
has_any_extra_headers_matcher_.reset(); has_any_extra_headers_matcher_.reset();
} }
bool CompositeMatcher::ShouldBlockRequest(const RequestParams& params) const { base::Optional<RequestAction> CompositeMatcher::GetBlockOrCollapseAction(
const RequestParams& params) const {
// TODO(karandeepb): change this to report time in micro-seconds. // TODO(karandeepb): change this to report time in micro-seconds.
SCOPED_UMA_HISTOGRAM_TIMER( SCOPED_UMA_HISTOGRAM_TIMER(
"Extensions.DeclarativeNetRequest.ShouldBlockRequestTime." "Extensions.DeclarativeNetRequest.ShouldBlockRequestTime."
...@@ -131,15 +109,18 @@ bool CompositeMatcher::ShouldBlockRequest(const RequestParams& params) const { ...@@ -131,15 +109,18 @@ bool CompositeMatcher::ShouldBlockRequest(const RequestParams& params) const {
for (const auto& matcher : matchers_) { for (const auto& matcher : matchers_) {
if (HasMatchingAllowRule(matcher.get(), params)) if (HasMatchingAllowRule(matcher.get(), params))
return false; return base::nullopt;
if (matcher->HasMatchingBlockRule(params))
return true; base::Optional<RequestAction> action =
matcher->GetBlockOrCollapseAction(params);
if (action)
return action;
} }
return false; return base::nullopt;
} }
RedirectAction CompositeMatcher::ShouldRedirectRequest( RedirectActionInfo CompositeMatcher::GetRedirectAction(
const RequestParams& params, const RequestParams& params,
PageAccess page_access) const { PageAccess page_access) const {
// TODO(karandeepb): change this to report time in micro-seconds. // TODO(karandeepb): change this to report time in micro-seconds.
...@@ -150,42 +131,35 @@ RedirectAction CompositeMatcher::ShouldRedirectRequest( ...@@ -150,42 +131,35 @@ RedirectAction CompositeMatcher::ShouldRedirectRequest(
bool notify_request_withheld = false; bool notify_request_withheld = false;
for (const auto& matcher : matchers_) { for (const auto& matcher : matchers_) {
if (HasMatchingAllowRule(matcher.get(), params)) { if (HasMatchingAllowRule(matcher.get(), params)) {
return RedirectAction(base::nullopt /* redirect_url */, return RedirectActionInfo(base::nullopt /* action */,
false /* notify_request_withheld */); false /* notify_request_withheld */);
} }
if (page_access == PageAccess::kAllowed) { if (page_access == PageAccess::kAllowed) {
GURL redirect_rule_url; base::Optional<RequestAction> action =
matcher->GetRedirectOrUpgradeActionByPriority(params);
const flat_rule::UrlRule* redirect_rule = if (!action)
matcher->GetRedirectRule(params, &redirect_rule_url);
const flat_rule::UrlRule* upgrade_rule = matcher->GetUpgradeRule(params);
if (!upgrade_rule && !redirect_rule)
continue; continue;
GURL redirect_url = return RedirectActionInfo(std::move(action),
GetUrlByRulePriority(redirect_rule, upgrade_rule, *params.url, false /* notify_request_withheld */);
std::move(redirect_rule_url));
return RedirectAction(std::move(redirect_url),
false /* notify_request_withheld */);
} }
// If the extension has no host permissions for the request, it can still // If the extension has no host permissions for the request, it can still
// upgrade the request. // upgrade the request.
if (matcher->GetUpgradeRule(params)) { base::Optional<RequestAction> upgrade_action =
return RedirectAction(GetUpgradedUrl(*params.url), matcher->GetUpgradeAction(params);
false /* notify_request_withheld */); if (upgrade_action) {
return RedirectActionInfo(std::move(upgrade_action),
false /* notify_request_withheld */);
} }
GURL redirect_url; notify_request_withheld |= (page_access == PageAccess::kWithheld &&
notify_request_withheld |= matcher->GetRedirectAction(params));
(page_access == PageAccess::kWithheld &&
matcher->GetRedirectRule(params, &redirect_url));
} }
return RedirectAction(base::nullopt /* redirect_url */, return RedirectActionInfo(base::nullopt /* action */,
notify_request_withheld); notify_request_withheld);
} }
uint8_t CompositeMatcher::GetRemoveHeadersMask(const RequestParams& params, uint8_t CompositeMatcher::GetRemoveHeadersMask(const RequestParams& params,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/ruleset_matcher.h" #include "extensions/browser/api/declarative_net_request/ruleset_matcher.h"
#include "extensions/common/permissions/permissions_data.h" #include "extensions/common/permissions/permissions_data.h"
...@@ -21,22 +22,22 @@ namespace declarative_net_request { ...@@ -21,22 +22,22 @@ namespace declarative_net_request {
// while respecting their priorities. // while respecting their priorities.
class CompositeMatcher { class CompositeMatcher {
public: public:
struct RedirectAction { struct RedirectActionInfo {
RedirectAction(base::Optional<GURL> redirect_url, bool notify); RedirectActionInfo(base::Optional<RequestAction> action, bool notify);
~RedirectAction(); ~RedirectActionInfo();
RedirectAction(RedirectAction&& other); RedirectActionInfo(RedirectActionInfo&& other);
RedirectAction& operator=(RedirectAction&& other); RedirectActionInfo& operator=(RedirectActionInfo&& other);
// The URL the request will be redirected to. The request should not be // The action to be taken for this request. If specified, the action type
// redirected if this is not specified. // must be |REDIRECT|.
base::Optional<GURL> redirect_url; base::Optional<RequestAction> action;
// Whether the extension should be notified that the request was unable to // Whether the extension should be notified that the request was unable to
// be redirected as the extension lacks the appropriate host permission for // be redirected as the extension lacks the appropriate host permission for
// the request. // the request.
bool notify_request_withheld = false; bool notify_request_withheld = false;
DISALLOW_COPY_AND_ASSIGN(RedirectAction); DISALLOW_COPY_AND_ASSIGN(RedirectActionInfo);
}; };
using MatcherList = std::vector<std::unique_ptr<RulesetMatcher>>; using MatcherList = std::vector<std::unique_ptr<RulesetMatcher>>;
...@@ -49,14 +50,15 @@ class CompositeMatcher { ...@@ -49,14 +50,15 @@ class CompositeMatcher {
// corresponding ID is already present, updates the matcher. // corresponding ID is already present, updates the matcher.
void AddOrUpdateRuleset(std::unique_ptr<RulesetMatcher> new_matcher); void AddOrUpdateRuleset(std::unique_ptr<RulesetMatcher> new_matcher);
// Returns whether the network request as specified by |params| should be // Returns a RequestAction if the network request specified by |params| should
// blocked. // be blocked.
bool ShouldBlockRequest(const RequestParams& params) const; base::Optional<RequestAction> GetBlockOrCollapseAction(
const RequestParams& params) const;
// Returns a RedirectAction struct containing a redirect URL if the request // Returns a RedirectActionInfo struct containing a RequestAction if the
// is to be redirected, and whether the extension should be notified if its // request is to be redirected, and whether the extension should be notified
// access to the request is withheld. // if its access to the request is withheld.
RedirectAction ShouldRedirectRequest( RedirectActionInfo GetRedirectAction(
const RequestParams& params, const RequestParams& params,
PermissionsData::PageAccess page_access) const; PermissionsData::PageAccess page_access) const;
......
...@@ -24,7 +24,7 @@ namespace extensions { ...@@ -24,7 +24,7 @@ namespace extensions {
namespace declarative_net_request { namespace declarative_net_request {
using PageAccess = PermissionsData::PageAccess; using PageAccess = PermissionsData::PageAccess;
using RedirectAction = CompositeMatcher::RedirectAction; using RedirectActionInfo = CompositeMatcher::RedirectActionInfo;
class CompositeMatcherTest : public ::testing::Test { class CompositeMatcherTest : public ::testing::Test {
public: public:
...@@ -86,7 +86,8 @@ TEST_F(CompositeMatcherTest, RulesetPriority) { ...@@ -86,7 +86,8 @@ TEST_F(CompositeMatcherTest, RulesetPriority) {
google_params.is_third_party = false; google_params.is_third_party = false;
// The second ruleset should get more priority. // The second ruleset should get more priority.
EXPECT_FALSE(composite_matcher->ShouldBlockRequest(google_params)); EXPECT_FALSE(
composite_matcher->GetBlockOrCollapseAction(google_params).has_value());
GURL example_url = GURL("http://example.com"); GURL example_url = GURL("http://example.com");
RequestParams example_params; RequestParams example_params;
...@@ -95,10 +96,11 @@ TEST_F(CompositeMatcherTest, RulesetPriority) { ...@@ -95,10 +96,11 @@ TEST_F(CompositeMatcherTest, RulesetPriority) {
url_pattern_index::flat::ElementType_SUBDOCUMENT; url_pattern_index::flat::ElementType_SUBDOCUMENT;
example_params.is_third_party = false; example_params.is_third_party = false;
RedirectAction action = composite_matcher->ShouldRedirectRequest( RedirectActionInfo action_info = composite_matcher->GetRedirectAction(
example_params, PageAccess::kAllowed); example_params, PageAccess::kAllowed);
EXPECT_EQ(GURL("http://ruleset2.com"), action.redirect_url); ASSERT_TRUE(action_info.action);
EXPECT_FALSE(action.notify_request_withheld); EXPECT_EQ(GURL("http://ruleset2.com"), action_info.action->redirect_url);
EXPECT_FALSE(action_info.notify_request_withheld);
// Now switch the priority of the two rulesets. This requires re-constructing // Now switch the priority of the two rulesets. This requires re-constructing
// the two ruleset matchers. // the two ruleset matchers.
...@@ -120,12 +122,14 @@ TEST_F(CompositeMatcherTest, RulesetPriority) { ...@@ -120,12 +122,14 @@ TEST_F(CompositeMatcherTest, RulesetPriority) {
example_params.allow_rule_cache.clear(); example_params.allow_rule_cache.clear();
// The first ruleset should get more priority. // The first ruleset should get more priority.
EXPECT_TRUE(composite_matcher->ShouldBlockRequest(google_params)); EXPECT_TRUE(
composite_matcher->GetBlockOrCollapseAction(google_params).has_value());
action = composite_matcher->ShouldRedirectRequest(example_params,
PageAccess::kAllowed); action_info = composite_matcher->GetRedirectAction(example_params,
EXPECT_EQ(GURL("http://ruleset1.com"), action.redirect_url); PageAccess::kAllowed);
EXPECT_FALSE(action.notify_request_withheld); ASSERT_TRUE(action_info.action);
EXPECT_EQ(GURL("http://ruleset1.com"), action_info.action->redirect_url);
EXPECT_FALSE(action_info.notify_request_withheld);
} }
// Ensure allow rules in a higher priority matcher override redirect // Ensure allow rules in a higher priority matcher override redirect
...@@ -188,10 +192,11 @@ TEST_F(CompositeMatcherTest, AllowRuleOverrides) { ...@@ -188,10 +192,11 @@ TEST_F(CompositeMatcherTest, AllowRuleOverrides) {
google_params.is_third_party = false; google_params.is_third_party = false;
// The second ruleset should get more priority. // The second ruleset should get more priority.
RedirectAction action = composite_matcher->ShouldRedirectRequest( RedirectActionInfo action_info =
google_params, PageAccess::kAllowed); composite_matcher->GetRedirectAction(google_params, PageAccess::kAllowed);
EXPECT_EQ(GURL("http://ruleset2.com"), action.redirect_url); ASSERT_TRUE(action_info.action);
EXPECT_FALSE(action.notify_request_withheld); EXPECT_EQ(GURL("http://ruleset2.com"), action_info.action->redirect_url);
EXPECT_FALSE(action_info.notify_request_withheld);
// Send a request to example.com with headers, expect the allow rule to be // Send a request to example.com with headers, expect the allow rule to be
// matched and the headers to remain. // matched and the headers to remain.
...@@ -226,10 +231,10 @@ TEST_F(CompositeMatcherTest, AllowRuleOverrides) { ...@@ -226,10 +231,10 @@ TEST_F(CompositeMatcherTest, AllowRuleOverrides) {
// The first ruleset should get more priority and so the request to google.com // The first ruleset should get more priority and so the request to google.com
// should not be redirected. // should not be redirected.
action = composite_matcher->ShouldRedirectRequest(google_params, action_info =
PageAccess::kAllowed); composite_matcher->GetRedirectAction(google_params, PageAccess::kAllowed);
EXPECT_FALSE(action.redirect_url); EXPECT_FALSE(action_info.action.has_value());
EXPECT_FALSE(action.notify_request_withheld); EXPECT_FALSE(action_info.notify_request_withheld);
// The request to example.com should now have its headers removed. // The request to example.com should now have its headers removed.
example_params.allow_rule_cache.clear(); example_params.allow_rule_cache.clear();
...@@ -310,11 +315,11 @@ TEST_F(CompositeMatcherTest, NotifyWithholdFromPageAccess) { ...@@ -310,11 +315,11 @@ TEST_F(CompositeMatcherTest, NotifyWithholdFromPageAccess) {
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT; params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = false; params.is_third_party = false;
RedirectAction redirect_action = RedirectActionInfo redirect_action_info =
composite_matcher->ShouldRedirectRequest(params, test_case.access); composite_matcher->GetRedirectAction(params, test_case.access);
EXPECT_EQ(test_case.should_notify_withheld, EXPECT_EQ(test_case.should_notify_withheld,
redirect_action.notify_request_withheld); redirect_action_info.notify_request_withheld);
} }
} }
...@@ -387,16 +392,18 @@ TEST_F(CompositeMatcherTest, GetRedirectUrlFromPriority) { ...@@ -387,16 +392,18 @@ TEST_F(CompositeMatcherTest, GetRedirectUrlFromPriority) {
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT; params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = false; params.is_third_party = false;
RedirectAction redirect_action = RedirectActionInfo redirect_action_info =
composite_matcher->ShouldRedirectRequest(params, PageAccess::kAllowed); composite_matcher->GetRedirectAction(params, PageAccess::kAllowed);
if (test_case.expected_final_url) { if (test_case.expected_final_url) {
EXPECT_EQ(test_case.expected_final_url->spec(), ASSERT_TRUE(redirect_action_info.action);
redirect_action.redirect_url->spec()); EXPECT_EQ(test_case.expected_final_url,
} else redirect_action_info.action->redirect_url);
EXPECT_FALSE(redirect_action.redirect_url); } else {
EXPECT_FALSE(redirect_action_info.action.has_value());
EXPECT_FALSE(redirect_action.notify_request_withheld); }
EXPECT_FALSE(redirect_action_info.notify_request_withheld);
} }
} }
......
...@@ -162,13 +162,6 @@ bool IsRequestPageAllowed(const WebRequestInfo& request, ...@@ -162,13 +162,6 @@ bool IsRequestPageAllowed(const WebRequestInfo& request,
allowed_pages.MatchesURL(*request.frame_data.pending_main_frame_url); allowed_pages.MatchesURL(*request.frame_data.pending_main_frame_url);
} }
bool ShouldCollapseResourceType(flat_rule::ElementType type) {
// TODO(crbug.com/848842): Add support for other element types like
// OBJECT.
return type == flat_rule::ElementType_IMAGE ||
type == flat_rule::ElementType_SUBDOCUMENT;
}
void NotifyRequestWithheld(const ExtensionId& extension_id, void NotifyRequestWithheld(const ExtensionId& extension_id,
const WebRequestInfo& request) { const WebRequestInfo& request) {
DCHECK(ExtensionsAPIClient::Get()); DCHECK(ExtensionsAPIClient::Get());
...@@ -404,13 +397,10 @@ base::Optional<RequestAction> RulesetManager::GetBlockOrCollapseAction( ...@@ -404,13 +397,10 @@ base::Optional<RequestAction> RulesetManager::GetBlockOrCollapseAction(
const std::vector<const ExtensionRulesetData*>& rulesets, const std::vector<const ExtensionRulesetData*>& rulesets,
const RequestParams& params) const { const RequestParams& params) const {
for (const ExtensionRulesetData* ruleset : rulesets) { for (const ExtensionRulesetData* ruleset : rulesets) {
if (ruleset->matcher->ShouldBlockRequest(params)) { base::Optional<RequestAction> action =
RequestAction action = ShouldCollapseResourceType(params.element_type) ruleset->matcher->GetBlockOrCollapseAction(params);
? RequestAction(RequestAction::Type::COLLAPSE) if (action)
: RequestAction(RequestAction::Type::BLOCK);
action.extension_id = ruleset->extension_id;
return action; return action;
}
} }
return base::nullopt; return base::nullopt;
} }
...@@ -439,23 +429,20 @@ base::Optional<RequestAction> RulesetManager::GetRedirectOrUpgradeAction( ...@@ -439,23 +429,20 @@ base::Optional<RequestAction> RulesetManager::GetRedirectOrUpgradeAction(
WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR, WebRequestPermissions::REQUIRE_HOST_PERMISSION_FOR_URL_AND_INITIATOR,
request.initiator, request.type); request.initiator, request.type);
CompositeMatcher::RedirectAction redirect_action = CompositeMatcher::RedirectActionInfo redirect_action_info =
ruleset->matcher->ShouldRedirectRequest(params, page_access); ruleset->matcher->GetRedirectAction(params, page_access);
DCHECK(!(redirect_action.redirect_url && DCHECK(!(redirect_action_info.action &&
redirect_action.notify_request_withheld)); redirect_action_info.notify_request_withheld));
if (redirect_action.notify_request_withheld) { if (redirect_action_info.notify_request_withheld) {
NotifyRequestWithheld(ruleset->extension_id, request); NotifyRequestWithheld(ruleset->extension_id, request);
continue; continue;
} }
if (!redirect_action.redirect_url) if (!redirect_action_info.action)
continue; continue;
RequestAction action(RequestAction::Type::REDIRECT); return std::move(redirect_action_info.action);
action.redirect_url = std::move(redirect_action.redirect_url);
action.extension_id = ruleset->extension_id;
return action;
} }
return base::nullopt; return base::nullopt;
......
...@@ -297,6 +297,22 @@ GURL GetTransformedURL(const RequestParams& params, ...@@ -297,6 +297,22 @@ GURL GetTransformedURL(const RequestParams& params,
return params.url->ReplaceComponents(replacements); return params.url->ReplaceComponents(replacements);
} }
bool ShouldCollapseResourceType(flat_rule::ElementType type) {
// TODO(crbug.com/848842): Add support for other element types like
// OBJECT.
return type == flat_rule::ElementType_IMAGE ||
type == flat_rule::ElementType_SUBDOCUMENT;
}
// Upgrades the url's scheme to HTTPS.
GURL GetUpgradedUrl(const GURL& url) {
DCHECK(url.SchemeIs(url::kHttpScheme) || url.SchemeIs(url::kFtpScheme));
GURL::Replacements replacements;
replacements.SetSchemeStr(url::kHttpsScheme);
return url.ReplaceComponents(replacements);
}
} // namespace } // namespace
RequestParams::RequestParams(const WebRequestInfo& info) RequestParams::RequestParams(const WebRequestInfo& info)
...@@ -343,13 +359,88 @@ RulesetMatcher::LoadRulesetResult RulesetMatcher::CreateVerifiedMatcher( ...@@ -343,13 +359,88 @@ RulesetMatcher::LoadRulesetResult RulesetMatcher::CreateVerifiedMatcher(
// Using WrapUnique instead of make_unique since this class has a private // Using WrapUnique instead of make_unique since this class has a private
// constructor. // constructor.
*matcher = base::WrapUnique(new RulesetMatcher( *matcher = base::WrapUnique(new RulesetMatcher(std::move(ruleset_data),
std::move(ruleset_data), source.id(), source.priority())); source.id(), source.priority(),
source.extension_id()));
return kLoadSuccess; return kLoadSuccess;
} }
RulesetMatcher::~RulesetMatcher() = default; RulesetMatcher::~RulesetMatcher() = default;
base::Optional<RequestAction> RulesetMatcher::GetBlockOrCollapseAction(
const RequestParams& params) const {
const flat_rule::UrlRule* rule =
GetMatchingRule(params, flat::ActionIndex_block);
if (!rule)
return base::nullopt;
RequestAction action = ShouldCollapseResourceType(params.element_type)
? RequestAction(RequestAction::Type::COLLAPSE)
: RequestAction(RequestAction::Type::BLOCK);
action.extension_id = extension_id_;
return action;
}
base::Optional<RequestAction> RulesetMatcher::GetRedirectAction(
const RequestParams& params) const {
GURL redirect_rule_url;
const flat_rule::UrlRule* redirect_rule =
GetRedirectRule(params, &redirect_rule_url);
if (!redirect_rule)
return base::nullopt;
RequestAction redirect_action(RequestAction::Type::REDIRECT);
redirect_action.extension_id = extension_id_;
redirect_action.redirect_url = std::move(redirect_rule_url);
return redirect_action;
}
base::Optional<RequestAction> RulesetMatcher::GetUpgradeAction(
const RequestParams& params) const {
const flat_rule::UrlRule* upgrade_rule = GetUpgradeRule(params);
if (!upgrade_rule)
return base::nullopt;
RequestAction upgrade_action(RequestAction::Type::REDIRECT);
upgrade_action.extension_id = extension_id_;
upgrade_action.redirect_url = GetUpgradedUrl(*params.url);
return upgrade_action;
}
base::Optional<RequestAction>
RulesetMatcher::GetRedirectOrUpgradeActionByPriority(
const RequestParams& params) const {
GURL redirect_rule_url;
const flat_rule::UrlRule* redirect_rule =
GetRedirectRule(params, &redirect_rule_url);
const flat_rule::UrlRule* upgrade_rule = GetUpgradeRule(params);
if (!redirect_rule && !upgrade_rule)
return base::nullopt;
GURL highest_priority_url;
if (!upgrade_rule) {
highest_priority_url = std::move(redirect_rule_url);
} else if (!redirect_rule) {
highest_priority_url = GetUpgradedUrl(*params.url);
} else {
highest_priority_url = upgrade_rule->priority() > redirect_rule->priority()
? GetUpgradedUrl(*params.url)
: std::move(redirect_rule_url);
}
RequestAction action(RequestAction::Type::REDIRECT);
action.extension_id = extension_id_;
action.redirect_url = std::move(highest_priority_url);
return action;
}
uint8_t RulesetMatcher::GetRemoveHeadersMask(const RequestParams& params, uint8_t RulesetMatcher::GetRemoveHeadersMask(const RequestParams& params,
uint8_t ignored_mask) const { uint8_t ignored_mask) const {
uint8_t mask = 0; uint8_t mask = 0;
...@@ -391,6 +482,19 @@ uint8_t RulesetMatcher::GetRemoveHeadersMask(const RequestParams& params, ...@@ -391,6 +482,19 @@ uint8_t RulesetMatcher::GetRemoveHeadersMask(const RequestParams& params,
return mask; return mask;
} }
RulesetMatcher::RulesetMatcher(std::string ruleset_data,
size_t id,
size_t priority,
const ExtensionId& extension_id)
: ruleset_data_(std::move(ruleset_data)),
root_(flat::GetExtensionIndexedRuleset(ruleset_data_.data())),
matchers_(GetMatchers(root_)),
metadata_list_(root_->extension_metadata()),
id_(id),
priority_(priority),
extension_id_(extension_id),
is_extra_headers_matcher_(IsExtraHeadersMatcherInternal(*root_)) {}
const flat_rule::UrlRule* RulesetMatcher::GetRedirectRule( const flat_rule::UrlRule* RulesetMatcher::GetRedirectRule(
const RequestParams& params, const RequestParams& params,
GURL* redirect_url) const { GURL* redirect_url) const {
...@@ -438,17 +542,6 @@ const flat_rule::UrlRule* RulesetMatcher::GetUpgradeRule( ...@@ -438,17 +542,6 @@ const flat_rule::UrlRule* RulesetMatcher::GetUpgradeRule(
: nullptr; : nullptr;
} }
RulesetMatcher::RulesetMatcher(std::string ruleset_data,
size_t id,
size_t priority)
: ruleset_data_(std::move(ruleset_data)),
root_(flat::GetExtensionIndexedRuleset(ruleset_data_.data())),
matchers_(GetMatchers(root_)),
metadata_list_(root_->extension_metadata()),
id_(id),
priority_(priority),
is_extra_headers_matcher_(IsExtraHeadersMatcherInternal(*root_)) {}
const flat_rule::UrlRule* RulesetMatcher::GetMatchingRule( const flat_rule::UrlRule* RulesetMatcher::GetMatchingRule(
const RequestParams& params, const RequestParams& params,
flat::ActionIndex index, flat::ActionIndex index,
......
...@@ -11,8 +11,10 @@ ...@@ -11,8 +11,10 @@
#include <vector> #include <vector>
#include "base/containers/flat_map.h" #include "base/containers/flat_map.h"
#include "base/optional.h"
#include "components/url_pattern_index/url_pattern_index.h" #include "components/url_pattern_index/url_pattern_index.h"
#include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h" #include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
#include "extensions/common/extension_id.h"
#include "url/gurl.h" #include "url/gurl.h"
#include "url/origin.h" #include "url/origin.h"
...@@ -20,6 +22,7 @@ namespace extensions { ...@@ -20,6 +22,7 @@ namespace extensions {
struct WebRequestInfo; struct WebRequestInfo;
namespace declarative_net_request { namespace declarative_net_request {
struct RequestAction;
class RulesetSource; class RulesetSource;
namespace flat { namespace flat {
...@@ -93,34 +96,39 @@ class RulesetMatcher { ...@@ -93,34 +96,39 @@ class RulesetMatcher {
~RulesetMatcher(); ~RulesetMatcher();
// Returns whether the ruleset has a matching blocking rule. // Returns the ruleset's matching RequestAction with type |BLOCK| or
bool HasMatchingBlockRule(const RequestParams& params) const { // |COLLAPSE|, or base::nullopt if the ruleset has no matching blocking rule.
return GetMatchingRule(params, flat::ActionIndex_block); base::Optional<RequestAction> GetBlockOrCollapseAction(
} const RequestParams& params) const;
// Returns whether the ruleset has a matching allow rule. // Returns whether the ruleset has a matching allow rule.
bool HasMatchingAllowRule(const RequestParams& params) const { bool HasMatchingAllowRule(const RequestParams& params) const {
return GetMatchingRule(params, flat::ActionIndex_allow); return GetMatchingRule(params, flat::ActionIndex_allow);
} }
// Returns the ruleset's matching redirect RequestAction if there is a
// matching redirect rule, otherwise returns base::nullopt.
base::Optional<RequestAction> GetRedirectAction(
const RequestParams& params) const;
// Returns the ruleset's matching RequestAction with |params.url| upgraded to
// HTTPS as the redirect url, or base::nullopt if no matching rule is found or
// if the request's scheme is not upgradeable.
base::Optional<RequestAction> GetUpgradeAction(
const RequestParams& params) const;
// Returns a RedirectAction constructed from the matching redirect or upgrade
// rule with the highest priority, or base::nullopt if no matching redirect or
// upgrade rules are found for this request.
base::Optional<RequestAction> GetRedirectOrUpgradeActionByPriority(
const RequestParams& params) const;
// Returns the bitmask of headers to remove from the request. The bitmask // Returns the bitmask of headers to remove from the request. The bitmask
// corresponds to RemoveHeadersMask type. |ignored_mask| denotes the mask of // corresponds to RemoveHeadersMask type. |ignored_mask| denotes the mask of
// headers to be skipped for evaluation and is excluded in the return value. // headers to be skipped for evaluation and is excluded in the return value.
uint8_t GetRemoveHeadersMask(const RequestParams& params, uint8_t GetRemoveHeadersMask(const RequestParams& params,
uint8_t ignored_mask) const; uint8_t ignored_mask) const;
// Returns the ruleset's matching redirect rule and populates
// |redirect_url| if there is a matching redirect rule, otherwise returns
// nullptr.
const url_pattern_index::flat::UrlRule* GetRedirectRule(
const RequestParams& params,
GURL* redirect_url) const;
// Returns the ruleset's matching upgrade scheme rule or nullptr if no
// matching rule is found or if the request's scheme is not upgradeable.
const url_pattern_index::flat::UrlRule* GetUpgradeRule(
const RequestParams& params) const;
// Returns whether this modifies "extraHeaders". // Returns whether this modifies "extraHeaders".
bool IsExtraHeadersMatcher() const { return is_extra_headers_matcher_; } bool IsExtraHeadersMatcher() const { return is_extra_headers_matcher_; }
...@@ -137,7 +145,22 @@ class RulesetMatcher { ...@@ -137,7 +145,22 @@ class RulesetMatcher {
using ExtensionMetadataList = using ExtensionMetadataList =
flatbuffers::Vector<flatbuffers::Offset<flat::UrlRuleMetadata>>; flatbuffers::Vector<flatbuffers::Offset<flat::UrlRuleMetadata>>;
explicit RulesetMatcher(std::string ruleset_data, size_t id, size_t priority); explicit RulesetMatcher(std::string ruleset_data,
size_t id,
size_t priority,
const ExtensionId& extension_id);
// Returns the ruleset's matching redirect rule and populates
// |redirect_url| if there is a matching redirect rule, otherwise returns
// nullptr.
const url_pattern_index::flat::UrlRule* GetRedirectRule(
const RequestParams& params,
GURL* redirect_url) const;
// Returns the ruleset's matching upgrade scheme rule or nullptr if no
// matching rule is found or if the request's scheme is not upgradeable.
const url_pattern_index::flat::UrlRule* GetUpgradeRule(
const RequestParams& params) const;
const url_pattern_index::flat::UrlRule* GetMatchingRule( const url_pattern_index::flat::UrlRule* GetMatchingRule(
const RequestParams& params, const RequestParams& params,
...@@ -154,8 +177,11 @@ class RulesetMatcher { ...@@ -154,8 +177,11 @@ class RulesetMatcher {
const ExtensionMetadataList* const metadata_list_; const ExtensionMetadataList* const metadata_list_;
size_t id_; const size_t id_;
size_t priority_; const size_t priority_;
// The ID of the extension from which this matcher's ruleset originates from.
const ExtensionId extension_id_;
const bool is_extra_headers_matcher_; const bool is_extra_headers_matcher_;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "components/url_pattern_index/flat/url_pattern_index_generated.h" #include "components/url_pattern_index/flat/url_pattern_index_generated.h"
#include "components/version_info/version_info.h" #include "components/version_info/version_info.h"
#include "extensions/browser/api/declarative_net_request/constants.h" #include "extensions/browser/api/declarative_net_request/constants.h"
#include "extensions/browser/api/declarative_net_request/request_action.h"
#include "extensions/browser/api/declarative_net_request/ruleset_source.h" #include "extensions/browser/api/declarative_net_request/ruleset_source.h"
#include "extensions/browser/api/declarative_net_request/test_utils.h" #include "extensions/browser/api/declarative_net_request/test_utils.h"
#include "extensions/browser/api/declarative_net_request/utils.h" #include "extensions/browser/api/declarative_net_request/utils.h"
...@@ -49,7 +50,7 @@ TEST_F(RulesetMatcherTest, BlockingRule) { ...@@ -49,7 +50,7 @@ TEST_F(RulesetMatcherTest, BlockingRule) {
auto should_block_request = [&matcher](const RequestParams& params) { auto should_block_request = [&matcher](const RequestParams& params) {
return !matcher->HasMatchingAllowRule(params) && return !matcher->HasMatchingAllowRule(params) &&
matcher->HasMatchingBlockRule(params); matcher->GetBlockOrCollapseAction(params).has_value();
}; };
GURL google_url("http://google.com"); GURL google_url("http://google.com");
...@@ -77,11 +78,6 @@ TEST_F(RulesetMatcherTest, RedirectRule) { ...@@ -77,11 +78,6 @@ TEST_F(RulesetMatcherTest, RedirectRule) {
std::unique_ptr<RulesetMatcher> matcher; std::unique_ptr<RulesetMatcher> matcher;
ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher)); ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher));
auto should_redirect_request = [&matcher](const RequestParams& params,
GURL* redirect_url) {
return matcher->GetRedirectRule(params, redirect_url) != nullptr;
};
GURL google_url("http://google.com"); GURL google_url("http://google.com");
GURL yahoo_url("http://yahoo.com"); GURL yahoo_url("http://yahoo.com");
...@@ -90,12 +86,13 @@ TEST_F(RulesetMatcherTest, RedirectRule) { ...@@ -90,12 +86,13 @@ TEST_F(RulesetMatcherTest, RedirectRule) {
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT; params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = true; params.is_third_party = true;
GURL redirect_url; base::Optional<RequestAction> redirect_action =
EXPECT_TRUE(should_redirect_request(params, &redirect_url)); matcher->GetRedirectAction(params);
EXPECT_EQ(yahoo_url, redirect_url); ASSERT_TRUE(redirect_action);
EXPECT_EQ(yahoo_url, redirect_action->redirect_url);
params.url = &yahoo_url; params.url = &yahoo_url;
EXPECT_FALSE(should_redirect_request(params, &redirect_url)); EXPECT_FALSE(matcher->GetRedirectAction(params));
} }
// Test that a URL cannot redirect to itself, as filed in crbug.com/954646. // Test that a URL cannot redirect to itself, as filed in crbug.com/954646.
...@@ -116,8 +113,7 @@ TEST_F(RulesetMatcherTest, PreventSelfRedirect) { ...@@ -116,8 +113,7 @@ TEST_F(RulesetMatcherTest, PreventSelfRedirect) {
params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT; params.element_type = url_pattern_index::flat::ElementType_SUBDOCUMENT;
params.is_third_party = true; params.is_third_party = true;
GURL redirect_url; EXPECT_FALSE(matcher->GetRedirectAction(params));
EXPECT_FALSE(matcher->GetRedirectRule(params, &redirect_url));
} }
// Tests a simple upgrade scheme rule. // Tests a simple upgrade scheme rule.
...@@ -131,7 +127,7 @@ TEST_F(RulesetMatcherTest, UpgradeRule) { ...@@ -131,7 +127,7 @@ TEST_F(RulesetMatcherTest, UpgradeRule) {
ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher)); ASSERT_TRUE(CreateVerifiedMatcher({rule}, CreateTemporarySource(), &matcher));
auto should_upgrade_request = [&matcher](const RequestParams& params) { auto should_upgrade_request = [&matcher](const RequestParams& params) {
return matcher->GetUpgradeRule(params) != nullptr; return matcher->GetUpgradeAction(params).has_value();
}; };
GURL google_url("http://google.com"); GURL google_url("http://google.com");
...@@ -232,21 +228,21 @@ TEST_F(RulesetMatcherTest, RedirectToExtensionPath) { ...@@ -232,21 +228,21 @@ TEST_F(RulesetMatcherTest, RedirectToExtensionPath) {
const size_t kId = 1; const size_t kId = 1;
const size_t kPriority = 1; const size_t kPriority = 1;
const size_t kRuleCountLimit = 10; const size_t kRuleCountLimit = 10;
const ExtensionId extension_id = "extension_id";
ASSERT_TRUE(CreateVerifiedMatcher( ASSERT_TRUE(CreateVerifiedMatcher(
{rule}, {rule}, CreateTemporarySource(kId, kPriority, kRuleCountLimit),
CreateTemporarySource(kId, kPriority, kRuleCountLimit, extension_id),
&matcher)); &matcher));
GURL example_url("http://example.com"); GURL example_url("http://example.com");
RequestParams params; RequestParams params;
params.url = &example_url; params.url = &example_url;
GURL redirect_url; base::Optional<RequestAction> redirect_action =
EXPECT_TRUE(matcher->GetRedirectRule(params, &redirect_url)); matcher->GetRedirectAction(params);
ASSERT_TRUE(redirect_action.has_value());
GURL expected_redirect_url( GURL expected_redirect_url(
"chrome-extension://extension_id/path/newfile.js?query#fragment"); "chrome-extension://extensionid/path/newfile.js?query#fragment");
EXPECT_EQ(expected_redirect_url, redirect_url); EXPECT_EQ(expected_redirect_url, redirect_action->redirect_url);
} }
// Tests a rule to redirect to a static url. // Tests a rule to redirect to a static url.
...@@ -265,10 +261,12 @@ TEST_F(RulesetMatcherTest, RedirectToStaticUrl) { ...@@ -265,10 +261,12 @@ TEST_F(RulesetMatcherTest, RedirectToStaticUrl) {
RequestParams params; RequestParams params;
params.url = &example_url; params.url = &example_url;
GURL redirect_url; base::Optional<RequestAction> redirect_action =
matcher->GetRedirectAction(params);
ASSERT_TRUE(redirect_action.has_value());
GURL expected_redirect_url("https://google.com"); GURL expected_redirect_url("https://google.com");
EXPECT_TRUE(matcher->GetRedirectRule(params, &redirect_url)); EXPECT_EQ(expected_redirect_url, redirect_action->redirect_url);
EXPECT_EQ(expected_redirect_url, redirect_url);
} }
// Tests url transformation rules. // Tests url transformation rules.
...@@ -396,17 +394,20 @@ TEST_F(RulesetMatcherTest, UrlTransform) { ...@@ -396,17 +394,20 @@ TEST_F(RulesetMatcherTest, UrlTransform) {
RequestParams params; RequestParams params;
params.url = &url; params.url = &url;
GURL redirect_url; base::Optional<RequestAction> redirect_action =
matcher->GetRedirectAction(params);
if (!test_case.expected_redirect_url) { if (!test_case.expected_redirect_url) {
EXPECT_FALSE(matcher->GetRedirectRule(params, &redirect_url)) EXPECT_FALSE(redirect_action) << redirect_action->redirect_url->spec();
<< redirect_url.spec();
continue; continue;
} }
ASSERT_TRUE(GURL(*test_case.expected_redirect_url).is_valid()) ASSERT_TRUE(GURL(*test_case.expected_redirect_url).is_valid())
<< *test_case.expected_redirect_url; << *test_case.expected_redirect_url;
EXPECT_TRUE(matcher->GetRedirectRule(params, &redirect_url));
EXPECT_EQ(*test_case.expected_redirect_url, redirect_url.spec()); ASSERT_TRUE(redirect_action.has_value());
EXPECT_EQ(GURL(*test_case.expected_redirect_url),
redirect_action->redirect_url);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment