1 // Copyright (c) 2010 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 "net/base/host_mapping_rules.h"
6 
7 #include <string>
8 
9 #include "base/logging.h"
10 #include "base/strings/pattern.h"
11 #include "base/strings/string_split.h"
12 #include "base/strings/string_tokenizer.h"
13 #include "base/strings/string_util.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/url_util.h"
16 
17 namespace net {
18 
19 struct HostMappingRules::MapRule {
MapRulenet::HostMappingRules::MapRule20   MapRule() : replacement_port(-1) {}
21 
22   std::string hostname_pattern;
23   std::string replacement_hostname;
24   int replacement_port;
25 };
26 
27 struct HostMappingRules::ExclusionRule {
28   std::string hostname_pattern;
29 };
30 
31 HostMappingRules::HostMappingRules() = default;
32 
33 HostMappingRules::HostMappingRules(const HostMappingRules& host_mapping_rules) =
34     default;
35 
36 HostMappingRules::~HostMappingRules() = default;
37 
38 HostMappingRules& HostMappingRules::operator=(
39     const HostMappingRules& host_mapping_rules) = default;
40 
RewriteHost(HostPortPair * host_port) const41 bool HostMappingRules::RewriteHost(HostPortPair* host_port) const {
42   // Check if the hostname was remapped.
43   for (const auto& rule : map_rules_) {
44     // The rule's hostname_pattern will be something like:
45     //     www.foo.com
46     //     *.foo.com
47     //     www.foo.com:1234
48     //     *.foo.com:1234
49     // First, we'll check for a match just on hostname.
50     // If that fails, we'll check for a match with both hostname and port.
51     if (!base::MatchPattern(host_port->host(), rule.hostname_pattern)) {
52       std::string host_port_string = host_port->ToString();
53       if (!base::MatchPattern(host_port_string, rule.hostname_pattern))
54         continue;  // This rule doesn't apply.
55     }
56 
57     // Check if the hostname was excluded.
58     for (const auto& rule : exclusion_rules_) {
59       if (base::MatchPattern(host_port->host(), rule.hostname_pattern))
60         return false;
61     }
62 
63     host_port->set_host(rule.replacement_hostname);
64     if (rule.replacement_port != -1)
65       host_port->set_port(static_cast<uint16_t>(rule.replacement_port));
66     return true;
67   }
68 
69   return false;
70 }
71 
AddRuleFromString(base::StringPiece rule_string)72 bool HostMappingRules::AddRuleFromString(base::StringPiece rule_string) {
73   std::vector<base::StringPiece> parts = base::SplitStringPiece(
74       base::TrimWhitespaceASCII(rule_string, base::TRIM_ALL), " ",
75       base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
76 
77   // Test for EXCLUSION rule.
78   if (parts.size() == 2 && base::LowerCaseEqualsASCII(parts[0], "exclude")) {
79     ExclusionRule rule;
80     rule.hostname_pattern = base::ToLowerASCII(parts[1]);
81     exclusion_rules_.push_back(rule);
82     return true;
83   }
84 
85   // Test for MAP rule.
86   if (parts.size() == 3 && base::LowerCaseEqualsASCII(parts[0], "map")) {
87     MapRule rule;
88     rule.hostname_pattern = base::ToLowerASCII(parts[1]);
89 
90     if (!ParseHostAndPort(parts[2], &rule.replacement_hostname,
91                           &rule.replacement_port)) {
92       return false;  // Failed parsing the hostname/port.
93     }
94 
95     map_rules_.push_back(rule);
96     return true;
97   }
98 
99   return false;
100 }
101 
SetRulesFromString(base::StringPiece rules_string)102 void HostMappingRules::SetRulesFromString(base::StringPiece rules_string) {
103   exclusion_rules_.clear();
104   map_rules_.clear();
105 
106   std::vector<base::StringPiece> rules = base::SplitStringPiece(
107       rules_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
108   for (base::StringPiece rule : rules) {
109     bool ok = AddRuleFromString(rule);
110     LOG_IF(ERROR, !ok) << "Failed parsing rule: " << rule;
111   }
112 }
113 
114 }  // namespace net
115