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