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