// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// 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 "base/logging.h"
#include "base/string_split.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_util.h"

namespace net {

struct HostMappingRules::MapRule {
  MapRule() : replacement_port(-1) {}

  std::string hostname_pattern;
  std::string replacement_hostname;
  int replacement_port;
};

struct HostMappingRules::ExclusionRule {
  std::string hostname_pattern;
};

HostMappingRules::HostMappingRules() {}

HostMappingRules::~HostMappingRules() {}

bool HostMappingRules::RewriteHost(HostPortPair* host_port) const {
  // Check if the hostname was excluded.
  for (ExclusionRuleList::const_iterator it = exclusion_rules_.begin();
       it != exclusion_rules_.end(); ++it) {
    const ExclusionRule& rule = *it;
    if (MatchPattern(host_port->host(), rule.hostname_pattern))
      return false;
  }

  // Check if the hostname was remapped.
  for (MapRuleList::const_iterator it = map_rules_.begin();
       it != map_rules_.end(); ++it) {
    const MapRule& rule = *it;

    // 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 (!MatchPattern(host_port->host(), rule.hostname_pattern)) {
      std::string host_port_string = host_port->ToString();
      if (!MatchPattern(host_port_string, rule.hostname_pattern))
        continue;  // This rule doesn't apply.
    }

    host_port->set_host(rule.replacement_hostname);
    if (rule.replacement_port != -1)
      host_port->set_port(rule.replacement_port);
    return true;
  }

  return false;
}

bool HostMappingRules::AddRuleFromString(const std::string& rule_string) {
  std::string trimmed;
  TrimWhitespaceASCII(rule_string, TRIM_ALL, &trimmed);
  std::vector<std::string> parts;
  base::SplitString(trimmed, ' ', &parts);

  // Test for EXCLUSION rule.
  if (parts.size() == 2 && LowerCaseEqualsASCII(parts[0], "exclude")) {
    ExclusionRule rule;
    rule.hostname_pattern = StringToLowerASCII(parts[1]);
    exclusion_rules_.push_back(rule);
    return true;
  }

  // Test for MAP rule.
  if (parts.size() == 3 && LowerCaseEqualsASCII(parts[0], "map")) {
    MapRule rule;
    rule.hostname_pattern = StringToLowerASCII(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(const std::string& rules_string) {
  exclusion_rules_.clear();
  map_rules_.clear();

  StringTokenizer rules(rules_string, ",");
  while (rules.GetNext()) {
    bool ok = AddRuleFromString(rules.token());
    LOG_IF(ERROR, !ok) << "Failed parsing rule: " << rules.token();
  }
}

}  // namespace net
