Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2006-2008 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/proxy/proxy_config.h"
      6 
      7 #include "base/string_tokenizer.h"
      8 #include "base/string_util.h"
      9 
     10 namespace net {
     11 
     12 ProxyConfig::ProxyConfig()
     13     : auto_detect(false),
     14       proxy_bypass_local_names(false),
     15       id_(INVALID_ID) {
     16 }
     17 
     18 bool ProxyConfig::Equals(const ProxyConfig& other) const {
     19   // The two configs can have different IDs.  We are just interested in if they
     20   // have the same settings.
     21   return auto_detect == other.auto_detect &&
     22          pac_url == other.pac_url &&
     23          proxy_rules == other.proxy_rules &&
     24          proxy_bypass == other.proxy_bypass &&
     25          proxy_bypass_local_names == other.proxy_bypass_local_names;
     26 }
     27 
     28 bool ProxyConfig::MayRequirePACResolver() const {
     29   return auto_detect || pac_url.is_valid();
     30 }
     31 
     32 void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
     33   // Reset.
     34   type = TYPE_NO_RULES;
     35   single_proxy = ProxyServer();
     36   proxy_for_http = ProxyServer();
     37   proxy_for_https = ProxyServer();
     38   proxy_for_ftp = ProxyServer();
     39   socks_proxy = ProxyServer();
     40 
     41   StringTokenizer proxy_server_list(proxy_rules, ";");
     42   while (proxy_server_list.GetNext()) {
     43     StringTokenizer proxy_server_for_scheme(
     44         proxy_server_list.token_begin(), proxy_server_list.token_end(), "=");
     45 
     46     while (proxy_server_for_scheme.GetNext()) {
     47       std::string url_scheme = proxy_server_for_scheme.token();
     48 
     49       // If we fail to get the proxy server here, it means that
     50       // this is a regular proxy server configuration, i.e. proxies
     51       // are not configured per protocol.
     52       if (!proxy_server_for_scheme.GetNext()) {
     53         if (type == TYPE_PROXY_PER_SCHEME)
     54           continue;  // Unexpected.
     55         single_proxy = ProxyServer::FromURI(url_scheme,
     56                                             ProxyServer::SCHEME_HTTP);
     57         type = TYPE_SINGLE_PROXY;
     58         return;
     59       }
     60 
     61       // Trim whitespace off the url scheme.
     62       TrimWhitespaceASCII(url_scheme, TRIM_ALL, &url_scheme);
     63 
     64       // Add it to the per-scheme mappings (if supported scheme).
     65       type = TYPE_PROXY_PER_SCHEME;
     66       if (ProxyServer* entry = MapSchemeToProxy(url_scheme)) {
     67         std::string proxy_server_token = proxy_server_for_scheme.token();
     68         ProxyServer::Scheme scheme = (entry == &socks_proxy) ?
     69             ProxyServer::SCHEME_SOCKS4 : ProxyServer::SCHEME_HTTP;
     70         *entry = ProxyServer::FromURI(proxy_server_token, scheme);
     71       }
     72     }
     73   }
     74 }
     75 
     76 const ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxy(
     77     const std::string& url_scheme) const {
     78   const ProxyServer* proxy_server =
     79       const_cast<ProxyRules*>(this)->MapSchemeToProxy(url_scheme);
     80   if (proxy_server && proxy_server->is_valid())
     81     return proxy_server;
     82   if (socks_proxy.is_valid())
     83     return &socks_proxy;
     84   return NULL;  // No mapping for this scheme. Use direct.
     85 }
     86 
     87 ProxyServer* ProxyConfig::ProxyRules::MapSchemeToProxy(
     88     const std::string& scheme) {
     89   DCHECK(type == TYPE_PROXY_PER_SCHEME);
     90   if (scheme == "http")
     91     return &proxy_for_http;
     92   if (scheme == "https")
     93     return &proxy_for_https;
     94   if (scheme == "ftp")
     95     return &proxy_for_ftp;
     96   if (scheme == "socks")
     97     return &socks_proxy;
     98   return NULL;  // No mapping for this scheme.
     99 }
    100 
    101 namespace {
    102 
    103 // Returns true if the given string represents an IP address.
    104 bool IsIPAddress(const std::string& domain) {
    105   // From GURL::HostIsIPAddress()
    106   url_canon::RawCanonOutputT<char, 128> ignored_output;
    107   url_canon::CanonHostInfo host_info;
    108   url_parse::Component domain_comp(0, domain.size());
    109   url_canon::CanonicalizeIPAddress(domain.c_str(), domain_comp,
    110                                    &ignored_output, &host_info);
    111   return host_info.IsIPAddress();
    112 }
    113 
    114 }  // namespace
    115 
    116 void ProxyConfig::ParseNoProxyList(const std::string& no_proxy) {
    117   proxy_bypass.clear();
    118   if (no_proxy.empty())
    119     return;
    120   // Traditional semantics:
    121   // A single "*" is specifically allowed and unproxies anything.
    122   // "*" wildcards other than a single "*" entry are not universally
    123   // supported. We will support them, as we get * wildcards for free
    124   // (see MatchPatternASCII() called from
    125   // ProxyService::ShouldBypassProxyForURL()).
    126   // no_proxy is a comma-separated list of <trailing_domain>[:<port>].
    127   // If no port is specified then any port matches.
    128   // The historical definition has trailing_domain match using a simple
    129   // string "endswith" test, so that the match need not correspond to a
    130   // "." boundary. For example: "google.com" matches "igoogle.com" too.
    131   // Seems like that could be confusing, but we'll obey tradition.
    132   // IP CIDR patterns are supposed to be supported too. We intend
    133   // to do this in proxy_service.cc, but it's currently a TODO.
    134   // See: http://crbug.com/9835.
    135   StringTokenizer no_proxy_list(no_proxy, ",");
    136   while (no_proxy_list.GetNext()) {
    137     std::string bypass_entry = no_proxy_list.token();
    138     TrimWhitespaceASCII(bypass_entry, TRIM_ALL, &bypass_entry);
    139     if (bypass_entry.empty())
    140       continue;
    141     if (bypass_entry.at(0) != '*') {
    142       // Insert a wildcard * to obtain an endsWith match, unless the
    143       // entry looks like it might be an IP or CIDR.
    144       // First look for either a :<port> or CIDR mask length suffix.
    145       std::string::const_iterator begin = bypass_entry.begin();
    146       std::string::const_iterator scan = bypass_entry.end() - 1;
    147       while (scan > begin && IsAsciiDigit(*scan))
    148         --scan;
    149       std::string potential_ip;
    150       if (*scan == '/' || *scan == ':')
    151         potential_ip = std::string(begin, scan - 1);
    152       else
    153         potential_ip = bypass_entry;
    154       if (!IsIPAddress(potential_ip)) {
    155         // Do insert a wildcard.
    156         bypass_entry.insert(0, "*");
    157       }
    158       // TODO(sdoyon): When CIDR matching is implemented in
    159       // proxy_service.cc, consider making proxy_bypass more
    160       // sophisticated to avoid parsing out the string on every
    161       // request.
    162     }
    163     proxy_bypass.push_back(bypass_entry);
    164   }
    165 }
    166 
    167 }  // namespace net
    168 
    169 namespace {
    170 
    171 // Helper to stringize a ProxyServer.
    172 std::ostream& operator<<(std::ostream& out,
    173                          const net::ProxyServer& proxy_server) {
    174   if (proxy_server.is_valid())
    175     out << proxy_server.ToURI();
    176   return out;
    177 }
    178 
    179 const char* BoolToYesNoString(bool b) {
    180   return b ? "Yes" : "No";
    181 }
    182 
    183 }  // namespace
    184 
    185 std::ostream& operator<<(std::ostream& out,
    186                          const net::ProxyConfig::ProxyRules& rules) {
    187   // Stringize the type enum.
    188   std::string type;
    189   switch (rules.type) {
    190     case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
    191       type = "TYPE_NO_RULES";
    192       break;
    193     case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
    194       type = "TYPE_PROXY_PER_SCHEME";
    195       break;
    196     case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
    197       type = "TYPE_SINGLE_PROXY";
    198       break;
    199     default:
    200       type = IntToString(rules.type);
    201       break;
    202   }
    203   return out << "  {\n"
    204              << "    type: " << type << "\n"
    205              << "    single_proxy: " << rules.single_proxy << "\n"
    206              << "    proxy_for_http: " << rules.proxy_for_http << "\n"
    207              << "    proxy_for_https: " << rules.proxy_for_https << "\n"
    208              << "    proxy_for_ftp: " << rules.proxy_for_ftp << "\n"
    209              << "    socks_proxy: " << rules.socks_proxy << "\n"
    210              << "  }";
    211 }
    212 
    213 std::ostream& operator<<(std::ostream& out, const net::ProxyConfig& config) {
    214   // "Automatic" settings.
    215   out << "Automatic settings:\n";
    216   out << "  Auto-detect: " << BoolToYesNoString(config.auto_detect) << "\n";
    217   out << "  Custom PAC script: ";
    218   if (config.pac_url.is_valid())
    219     out << config.pac_url;
    220   else
    221     out << "[None]";
    222   out << "\n";
    223 
    224   // "Manual" settings.
    225   out << "Manual settings:\n";
    226   out << "  Proxy server: ";
    227 
    228   switch (config.proxy_rules.type) {
    229     case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
    230       out << "[None]\n";
    231       break;
    232     case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
    233       out << config.proxy_rules.single_proxy;
    234       out << "\n";
    235       break;
    236     case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
    237       out << "\n";
    238       if (config.proxy_rules.proxy_for_http.is_valid())
    239         out << "    HTTP: " << config.proxy_rules.proxy_for_http << "\n";
    240       if (config.proxy_rules.proxy_for_https.is_valid())
    241         out << "    HTTPS: " << config.proxy_rules.proxy_for_https << "\n";
    242       if (config.proxy_rules.proxy_for_ftp.is_valid())
    243         out << "    FTP: " << config.proxy_rules.proxy_for_ftp << "\n";
    244       if (config.proxy_rules.socks_proxy.is_valid())
    245         out << "    SOCKS: " << config.proxy_rules.socks_proxy << "\n";
    246       break;
    247   }
    248 
    249   out << "  Bypass list: ";
    250   if (config.proxy_bypass.empty()) {
    251     out << "[None]\n";
    252   } else {
    253     out << "\n";
    254     std::vector<std::string>::const_iterator it;
    255     for (it = config.proxy_bypass.begin();
    256          it != config.proxy_bypass.end(); ++it) {
    257       out << "    " << *it << "\n";
    258     }
    259   }
    260 
    261   out << "  Bypass local names: "
    262       << BoolToYesNoString(config.proxy_bypass_local_names);
    263   return out;
    264 }
    265