1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/browser/api/declarative_net_request/extension_url_pattern_index_matcher.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <list>
10 #include <string>
11 #include <utility>
12
13 #include "base/check_op.h"
14 #include "base/notreached.h"
15 #include "extensions/browser/api/declarative_net_request/request_action.h"
16 #include "extensions/browser/api/declarative_net_request/request_params.h"
17 #include "extensions/common/api/declarative_net_request.h"
18
19 namespace extensions {
20 namespace declarative_net_request {
21 namespace flat_rule = url_pattern_index::flat;
22 namespace dnr_api = api::declarative_net_request;
23
24 namespace {
25
26 using FindRuleStrategy =
27 url_pattern_index::UrlPatternIndexMatcher::FindRuleStrategy;
28
GetMatchers(const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList * index_list)29 std::vector<url_pattern_index::UrlPatternIndexMatcher> GetMatchers(
30 const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList* index_list) {
31 DCHECK(index_list);
32 DCHECK_EQ(flat::IndexType_count, index_list->size());
33
34 std::vector<url_pattern_index::UrlPatternIndexMatcher> matchers;
35 matchers.reserve(flat::IndexType_count);
36 for (const flat_rule::UrlPatternIndex* index : *index_list)
37 matchers.emplace_back(index);
38 return matchers;
39 }
40
IsExtraHeadersMatcherInternal(const std::vector<url_pattern_index::UrlPatternIndexMatcher> & matchers)41 bool IsExtraHeadersMatcherInternal(
42 const std::vector<url_pattern_index::UrlPatternIndexMatcher>& matchers) {
43 static_assert(flat::IndexType_count == 3,
44 "Modify this method to ensure IsExtraHeadersMatcherInternal is "
45 "updated as new actions are added.");
46 return matchers[flat::IndexType_modify_headers].GetRulesCount() > 0;
47 }
48
GetRulesCountInternal(const std::vector<url_pattern_index::UrlPatternIndexMatcher> & matchers)49 size_t GetRulesCountInternal(
50 const std::vector<url_pattern_index::UrlPatternIndexMatcher>& matchers) {
51 size_t rules_count = 0;
52 for (const auto& matcher : matchers)
53 rules_count += matcher.GetRulesCount();
54
55 return rules_count;
56 }
57
58 } // namespace
59
ExtensionUrlPatternIndexMatcher(const ExtensionId & extension_id,RulesetID ruleset_id,const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList * index_list,const ExtensionMetadataList * metadata_list)60 ExtensionUrlPatternIndexMatcher::ExtensionUrlPatternIndexMatcher(
61 const ExtensionId& extension_id,
62 RulesetID ruleset_id,
63 const ExtensionUrlPatternIndexMatcher::UrlPatternIndexList* index_list,
64 const ExtensionMetadataList* metadata_list)
65 : RulesetMatcherBase(extension_id, ruleset_id),
66 metadata_list_(metadata_list),
67 matchers_(GetMatchers(index_list)),
68 is_extra_headers_matcher_(IsExtraHeadersMatcherInternal(matchers_)),
69 rules_count_(GetRulesCountInternal(matchers_)) {}
70
71 ExtensionUrlPatternIndexMatcher::~ExtensionUrlPatternIndexMatcher() = default;
72
73 base::Optional<RequestAction>
GetAllowAllRequestsAction(const RequestParams & params) const74 ExtensionUrlPatternIndexMatcher::GetAllowAllRequestsAction(
75 const RequestParams& params) const {
76 const flat_rule::UrlRule* rule =
77 GetMatchingRule(params, flat::IndexType_allow_all_requests,
78 FindRuleStrategy::kHighestPriority);
79 if (!rule)
80 return base::nullopt;
81
82 return CreateAllowAllRequestsAction(params, *rule);
83 }
84
85 std::vector<RequestAction>
GetModifyHeadersActions(const RequestParams & params,base::Optional<uint64_t> min_priority) const86 ExtensionUrlPatternIndexMatcher::GetModifyHeadersActions(
87 const RequestParams& params,
88 base::Optional<uint64_t> min_priority) const {
89 // TODO(crbug.com/1083178): Plumb |min_priority| into UrlPatternIndexMatcher
90 // to prune more rules before matching on url filters.
91 std::vector<const flat_rule::UrlRule*> rules =
92 GetAllMatchingRules(params, flat::IndexType_modify_headers);
93
94 if (min_priority) {
95 base::EraseIf(rules, [&min_priority](const flat_rule::UrlRule* rule) {
96 return rule->priority() <= *min_priority;
97 });
98 }
99
100 return GetModifyHeadersActionsFromMetadata(params, rules, *metadata_list_);
101 }
102
103 base::Optional<RequestAction>
GetBeforeRequestActionIgnoringAncestors(const RequestParams & params) const104 ExtensionUrlPatternIndexMatcher::GetBeforeRequestActionIgnoringAncestors(
105 const RequestParams& params) const {
106 return GetMaxPriorityAction(GetBeforeRequestActionHelper(params),
107 GetAllowAllRequestsAction(params));
108 }
109
110 base::Optional<RequestAction>
GetBeforeRequestActionHelper(const RequestParams & params) const111 ExtensionUrlPatternIndexMatcher::GetBeforeRequestActionHelper(
112 const RequestParams& params) const {
113 const flat_rule::UrlRule* rule = GetMatchingRule(
114 params, flat::IndexType_before_request_except_allow_all_requests,
115 FindRuleStrategy::kHighestPriority);
116 if (!rule)
117 return base::nullopt;
118
119 const flat::UrlRuleMetadata* metadata =
120 metadata_list_->LookupByKey(rule->id());
121 DCHECK(metadata);
122 DCHECK_EQ(metadata->id(), rule->id());
123 switch (metadata->action()) {
124 case flat::ActionType_block:
125 return CreateBlockOrCollapseRequestAction(params, *rule);
126 case flat::ActionType_allow:
127 return CreateAllowAction(params, *rule);
128 case flat::ActionType_redirect:
129 return CreateRedirectActionFromMetadata(params, *rule, *metadata_list_);
130 case flat::ActionType_upgrade_scheme:
131 return CreateUpgradeAction(params, *rule);
132 case flat::ActionType_allow_all_requests:
133 case flat::ActionType_modify_headers:
134 case flat::ActionType_count:
135 NOTREACHED();
136 }
137
138 return base::nullopt;
139 }
140
GetMatchingRule(const RequestParams & params,flat::IndexType index,FindRuleStrategy strategy) const141 const flat_rule::UrlRule* ExtensionUrlPatternIndexMatcher::GetMatchingRule(
142 const RequestParams& params,
143 flat::IndexType index,
144 FindRuleStrategy strategy) const {
145 DCHECK_LT(index, flat::IndexType_count);
146 DCHECK_GE(index, 0);
147 DCHECK(params.url);
148
149 // Don't exclude generic rules from being matched. A generic rule is one with
150 // an empty included domains list.
151 const bool kDisableGenericRules = false;
152
153 return matchers_[index].FindMatch(
154 *params.url, params.first_party_origin, params.element_type,
155 flat_rule::ActivationType_NONE, params.is_third_party,
156 kDisableGenericRules, strategy);
157 }
158
159 std::vector<const url_pattern_index::flat::UrlRule*>
GetAllMatchingRules(const RequestParams & params,flat::IndexType index) const160 ExtensionUrlPatternIndexMatcher::GetAllMatchingRules(
161 const RequestParams& params,
162 flat::IndexType index) const {
163 DCHECK_LT(index, flat::IndexType_count);
164 DCHECK_GE(index, 0);
165 DCHECK(params.url);
166
167 // Don't exclude generic rules from being matched. A generic rule is one with
168 // an empty included domains list.
169 const bool kDisableGenericRules = false;
170
171 return matchers_[index].FindAllMatches(
172 *params.url, params.first_party_origin, params.element_type,
173 flat_rule::ActivationType_NONE, params.is_third_party,
174 kDisableGenericRules);
175 }
176
177 } // namespace declarative_net_request
178 } // namespace extensions
179