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