host_mapping_rules.cc 4.7 KB

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