xref: /aosp_15_r20/external/cronet/net/base/host_mapping_rules.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2010 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/base/host_mapping_rules.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/strings/pattern.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_split.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_tokenizer.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
15*6777b538SAndroid Build Coastguard Worker #include "net/base/host_port_pair.h"
16*6777b538SAndroid Build Coastguard Worker #include "net/base/url_util.h"
17*6777b538SAndroid Build Coastguard Worker #include "url/gurl.h"
18*6777b538SAndroid Build Coastguard Worker #include "url/third_party/mozilla/url_parse.h"
19*6777b538SAndroid Build Coastguard Worker #include "url/url_canon.h"
20*6777b538SAndroid Build Coastguard Worker 
21*6777b538SAndroid Build Coastguard Worker namespace net {
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker struct HostMappingRules::MapRule {
24*6777b538SAndroid Build Coastguard Worker   MapRule() = default;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker   std::string hostname_pattern;
27*6777b538SAndroid Build Coastguard Worker   std::string replacement_hostname;
28*6777b538SAndroid Build Coastguard Worker   int replacement_port = -1;
29*6777b538SAndroid Build Coastguard Worker };
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker struct HostMappingRules::ExclusionRule {
32*6777b538SAndroid Build Coastguard Worker   std::string hostname_pattern;
33*6777b538SAndroid Build Coastguard Worker };
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker HostMappingRules::HostMappingRules() = default;
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker HostMappingRules::HostMappingRules(const HostMappingRules& host_mapping_rules) =
38*6777b538SAndroid Build Coastguard Worker     default;
39*6777b538SAndroid Build Coastguard Worker 
40*6777b538SAndroid Build Coastguard Worker HostMappingRules::~HostMappingRules() = default;
41*6777b538SAndroid Build Coastguard Worker 
42*6777b538SAndroid Build Coastguard Worker HostMappingRules& HostMappingRules::operator=(
43*6777b538SAndroid Build Coastguard Worker     const HostMappingRules& host_mapping_rules) = default;
44*6777b538SAndroid Build Coastguard Worker 
RewriteHost(HostPortPair * host_port) const45*6777b538SAndroid Build Coastguard Worker bool HostMappingRules::RewriteHost(HostPortPair* host_port) const {
46*6777b538SAndroid Build Coastguard Worker   // Check if the hostname was remapped.
47*6777b538SAndroid Build Coastguard Worker   for (const auto& map_rule : map_rules_) {
48*6777b538SAndroid Build Coastguard Worker     // The rule's hostname_pattern will be something like:
49*6777b538SAndroid Build Coastguard Worker     //     www.foo.com
50*6777b538SAndroid Build Coastguard Worker     //     *.foo.com
51*6777b538SAndroid Build Coastguard Worker     //     www.foo.com:1234
52*6777b538SAndroid Build Coastguard Worker     //     *.foo.com:1234
53*6777b538SAndroid Build Coastguard Worker     // First, we'll check for a match just on hostname.
54*6777b538SAndroid Build Coastguard Worker     // If that fails, we'll check for a match with both hostname and port.
55*6777b538SAndroid Build Coastguard Worker     if (!base::MatchPattern(host_port->host(), map_rule.hostname_pattern)) {
56*6777b538SAndroid Build Coastguard Worker       std::string host_port_string = host_port->ToString();
57*6777b538SAndroid Build Coastguard Worker       if (!base::MatchPattern(host_port_string, map_rule.hostname_pattern))
58*6777b538SAndroid Build Coastguard Worker         continue;  // This rule doesn't apply.
59*6777b538SAndroid Build Coastguard Worker     }
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker     // Check if the hostname was excluded.
62*6777b538SAndroid Build Coastguard Worker     for (const auto& exclusion_rule : exclusion_rules_) {
63*6777b538SAndroid Build Coastguard Worker       if (base::MatchPattern(host_port->host(),
64*6777b538SAndroid Build Coastguard Worker                              exclusion_rule.hostname_pattern))
65*6777b538SAndroid Build Coastguard Worker         return false;
66*6777b538SAndroid Build Coastguard Worker     }
67*6777b538SAndroid Build Coastguard Worker 
68*6777b538SAndroid Build Coastguard Worker     host_port->set_host(map_rule.replacement_hostname);
69*6777b538SAndroid Build Coastguard Worker     if (map_rule.replacement_port != -1)
70*6777b538SAndroid Build Coastguard Worker       host_port->set_port(static_cast<uint16_t>(map_rule.replacement_port));
71*6777b538SAndroid Build Coastguard Worker     return true;
72*6777b538SAndroid Build Coastguard Worker   }
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker   return false;
75*6777b538SAndroid Build Coastguard Worker }
76*6777b538SAndroid Build Coastguard Worker 
RewriteUrl(GURL & url) const77*6777b538SAndroid Build Coastguard Worker HostMappingRules::RewriteResult HostMappingRules::RewriteUrl(GURL& url) const {
78*6777b538SAndroid Build Coastguard Worker   // Must be a valid and standard URL. Otherwise, Chrome might not know how to
79*6777b538SAndroid Build Coastguard Worker   // find/replace the contained host or port.
80*6777b538SAndroid Build Coastguard Worker   DCHECK(url.is_valid());
81*6777b538SAndroid Build Coastguard Worker   DCHECK(url.IsStandard());
82*6777b538SAndroid Build Coastguard Worker   DCHECK(url.has_host());
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   HostPortPair host_port_pair = HostPortPair::FromURL(url);
85*6777b538SAndroid Build Coastguard Worker   if (!RewriteHost(&host_port_pair))
86*6777b538SAndroid Build Coastguard Worker     return RewriteResult::kNoMatchingRule;
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker   GURL::Replacements replacements;
89*6777b538SAndroid Build Coastguard Worker   std::string port_str = base::NumberToString(host_port_pair.port());
90*6777b538SAndroid Build Coastguard Worker   replacements.SetPortStr(port_str);
91*6777b538SAndroid Build Coastguard Worker   std::string host_str = host_port_pair.HostForURL();
92*6777b538SAndroid Build Coastguard Worker   replacements.SetHostStr(host_str);
93*6777b538SAndroid Build Coastguard Worker   GURL new_url = url.ReplaceComponents(replacements);
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   if (!new_url.is_valid())
96*6777b538SAndroid Build Coastguard Worker     return RewriteResult::kInvalidRewrite;
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   DCHECK(new_url.IsStandard());
99*6777b538SAndroid Build Coastguard Worker   DCHECK(new_url.has_host());
100*6777b538SAndroid Build Coastguard Worker   DCHECK_EQ(url.EffectiveIntPort() == url::PORT_UNSPECIFIED,
101*6777b538SAndroid Build Coastguard Worker             new_url.EffectiveIntPort() == url::PORT_UNSPECIFIED);
102*6777b538SAndroid Build Coastguard Worker 
103*6777b538SAndroid Build Coastguard Worker   url = std::move(new_url);
104*6777b538SAndroid Build Coastguard Worker   return RewriteResult::kRewritten;
105*6777b538SAndroid Build Coastguard Worker }
106*6777b538SAndroid Build Coastguard Worker 
AddRuleFromString(std::string_view rule_string)107*6777b538SAndroid Build Coastguard Worker bool HostMappingRules::AddRuleFromString(std::string_view rule_string) {
108*6777b538SAndroid Build Coastguard Worker   std::vector<std::string_view> parts = base::SplitStringPiece(
109*6777b538SAndroid Build Coastguard Worker       base::TrimWhitespaceASCII(rule_string, base::TRIM_ALL), " ",
110*6777b538SAndroid Build Coastguard Worker       base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
111*6777b538SAndroid Build Coastguard Worker 
112*6777b538SAndroid Build Coastguard Worker   // Test for EXCLUSION rule.
113*6777b538SAndroid Build Coastguard Worker   if (parts.size() == 2 &&
114*6777b538SAndroid Build Coastguard Worker       base::EqualsCaseInsensitiveASCII(parts[0], "exclude")) {
115*6777b538SAndroid Build Coastguard Worker     ExclusionRule rule;
116*6777b538SAndroid Build Coastguard Worker     rule.hostname_pattern = base::ToLowerASCII(parts[1]);
117*6777b538SAndroid Build Coastguard Worker     exclusion_rules_.push_back(rule);
118*6777b538SAndroid Build Coastguard Worker     return true;
119*6777b538SAndroid Build Coastguard Worker   }
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // Test for MAP rule.
122*6777b538SAndroid Build Coastguard Worker   if (parts.size() == 3 && base::EqualsCaseInsensitiveASCII(parts[0], "map")) {
123*6777b538SAndroid Build Coastguard Worker     MapRule rule;
124*6777b538SAndroid Build Coastguard Worker     rule.hostname_pattern = base::ToLowerASCII(parts[1]);
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker     if (!ParseHostAndPort(parts[2], &rule.replacement_hostname,
127*6777b538SAndroid Build Coastguard Worker                           &rule.replacement_port)) {
128*6777b538SAndroid Build Coastguard Worker       return false;  // Failed parsing the hostname/port.
129*6777b538SAndroid Build Coastguard Worker     }
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker     map_rules_.push_back(rule);
132*6777b538SAndroid Build Coastguard Worker     return true;
133*6777b538SAndroid Build Coastguard Worker   }
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker   return false;
136*6777b538SAndroid Build Coastguard Worker }
137*6777b538SAndroid Build Coastguard Worker 
SetRulesFromString(std::string_view rules_string)138*6777b538SAndroid Build Coastguard Worker void HostMappingRules::SetRulesFromString(std::string_view rules_string) {
139*6777b538SAndroid Build Coastguard Worker   exclusion_rules_.clear();
140*6777b538SAndroid Build Coastguard Worker   map_rules_.clear();
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker   std::vector<std::string_view> rules = base::SplitStringPiece(
143*6777b538SAndroid Build Coastguard Worker       rules_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
144*6777b538SAndroid Build Coastguard Worker   for (std::string_view rule : rules) {
145*6777b538SAndroid Build Coastguard Worker     bool ok = AddRuleFromString(rule);
146*6777b538SAndroid Build Coastguard Worker     LOG_IF(ERROR, !ok) << "Failed parsing rule: " << rule;
147*6777b538SAndroid Build Coastguard Worker   }
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker 
150*6777b538SAndroid Build Coastguard Worker }  // namespace net
151