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