Home | History | Annotate | Download | only in proxy
      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/proxy/proxy_server.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/strings/string_util.h"
     10 #include "net/base/net_util.h"
     11 #include "net/http/http_util.h"
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 // Parses the proxy type from a PAC string, to a ProxyServer::Scheme.
     18 // This mapping is case-insensitive. If no type could be matched
     19 // returns SCHEME_INVALID.
     20 ProxyServer::Scheme GetSchemeFromPacTypeInternal(
     21     std::string::const_iterator begin,
     22     std::string::const_iterator end) {
     23   if (LowerCaseEqualsASCII(begin, end, "proxy"))
     24     return ProxyServer::SCHEME_HTTP;
     25   if (LowerCaseEqualsASCII(begin, end, "socks")) {
     26     // Default to v4 for compatibility. This is because the SOCKS4 vs SOCKS5
     27     // notation didn't originally exist, so if a client returns SOCKS they
     28     // really meant SOCKS4.
     29     return ProxyServer::SCHEME_SOCKS4;
     30   }
     31   if (LowerCaseEqualsASCII(begin, end, "socks4"))
     32     return ProxyServer::SCHEME_SOCKS4;
     33   if (LowerCaseEqualsASCII(begin, end, "socks5"))
     34     return ProxyServer::SCHEME_SOCKS5;
     35   if (LowerCaseEqualsASCII(begin, end, "direct"))
     36     return ProxyServer::SCHEME_DIRECT;
     37   if (LowerCaseEqualsASCII(begin, end, "https"))
     38     return ProxyServer::SCHEME_HTTPS;
     39 
     40   return ProxyServer::SCHEME_INVALID;
     41 }
     42 
     43 // Parses the proxy scheme from a URL-like representation, to a
     44 // ProxyServer::Scheme. This corresponds with the values used in
     45 // ProxyServer::ToURI(). If no type could be matched, returns SCHEME_INVALID.
     46 ProxyServer::Scheme GetSchemeFromURIInternal(std::string::const_iterator begin,
     47                                              std::string::const_iterator end) {
     48   if (LowerCaseEqualsASCII(begin, end, "http"))
     49     return ProxyServer::SCHEME_HTTP;
     50   if (LowerCaseEqualsASCII(begin, end, "socks4"))
     51     return ProxyServer::SCHEME_SOCKS4;
     52   if (LowerCaseEqualsASCII(begin, end, "socks"))
     53     return ProxyServer::SCHEME_SOCKS5;
     54   if (LowerCaseEqualsASCII(begin, end, "socks5"))
     55     return ProxyServer::SCHEME_SOCKS5;
     56   if (LowerCaseEqualsASCII(begin, end, "direct"))
     57     return ProxyServer::SCHEME_DIRECT;
     58   if (LowerCaseEqualsASCII(begin, end, "https"))
     59     return ProxyServer::SCHEME_HTTPS;
     60   return ProxyServer::SCHEME_INVALID;
     61 }
     62 
     63 std::string HostNoBrackets(const std::string& host) {
     64   // Remove brackets from an RFC 2732-style IPv6 literal address.
     65   const std::string::size_type len = host.size();
     66   if (len >= 2 && host[0] == '[' && host[len - 1] == ']')
     67     return host.substr(1, len - 2);
     68   return host;
     69 }
     70 
     71 }  // namespace
     72 
     73 ProxyServer::ProxyServer(Scheme scheme, const HostPortPair& host_port_pair)
     74       : scheme_(scheme), host_port_pair_(host_port_pair) {
     75   if (scheme_ == SCHEME_DIRECT || scheme_ == SCHEME_INVALID) {
     76     // |host_port_pair| isn't relevant for these special schemes, so none should
     77     // have been specified. It is important for this to be consistent since we
     78     // do raw field comparisons in the equality and comparison functions.
     79     DCHECK(host_port_pair.Equals(HostPortPair()));
     80     host_port_pair_ = HostPortPair();
     81   }
     82 }
     83 
     84 const HostPortPair& ProxyServer::host_port_pair() const {
     85   // Doesn't make sense to call this if the URI scheme doesn't
     86   // have concept of a host.
     87   DCHECK(is_valid() && !is_direct());
     88   return host_port_pair_;
     89 }
     90 
     91 // static
     92 ProxyServer ProxyServer::FromURI(const std::string& uri,
     93                                  Scheme default_scheme) {
     94   return FromURI(uri.begin(), uri.end(), default_scheme);
     95 }
     96 
     97 // static
     98 ProxyServer ProxyServer::FromURI(std::string::const_iterator begin,
     99                                  std::string::const_iterator end,
    100                                  Scheme default_scheme) {
    101   // We will default to |default_scheme| if no scheme specifier was given.
    102   Scheme scheme = default_scheme;
    103 
    104   // Trim the leading/trailing whitespace.
    105   HttpUtil::TrimLWS(&begin, &end);
    106 
    107   // Check for [<scheme> "://"]
    108   std::string::const_iterator colon = std::find(begin, end, ':');
    109   if (colon != end &&
    110       (end - colon) >= 3 &&
    111       *(colon + 1) == '/' &&
    112       *(colon + 2) == '/') {
    113     scheme = GetSchemeFromURIInternal(begin, colon);
    114     begin = colon + 3;  // Skip past the "://"
    115   }
    116 
    117   // Now parse the <host>[":"<port>].
    118   return FromSchemeHostAndPort(scheme, begin, end);
    119 }
    120 
    121 std::string ProxyServer::ToURI() const {
    122   switch (scheme_) {
    123     case SCHEME_DIRECT:
    124       return "direct://";
    125     case SCHEME_HTTP:
    126       // Leave off "http://" since it is our default scheme.
    127       return host_port_pair().ToString();
    128     case SCHEME_SOCKS4:
    129       return std::string("socks4://") + host_port_pair().ToString();
    130     case SCHEME_SOCKS5:
    131       return std::string("socks5://") + host_port_pair().ToString();
    132     case SCHEME_HTTPS:
    133       return std::string("https://") + host_port_pair().ToString();
    134     default:
    135       // Got called with an invalid scheme.
    136       NOTREACHED();
    137       return std::string();
    138   }
    139 }
    140 
    141 // static
    142 ProxyServer ProxyServer::FromPacString(const std::string& pac_string) {
    143   return FromPacString(pac_string.begin(), pac_string.end());
    144 }
    145 
    146 // static
    147 ProxyServer ProxyServer::FromPacString(std::string::const_iterator begin,
    148                                        std::string::const_iterator end) {
    149   // Trim the leading/trailing whitespace.
    150   HttpUtil::TrimLWS(&begin, &end);
    151 
    152   // Input should match:
    153   // "DIRECT" | ( <type> 1*(LWS) <host-and-port> )
    154 
    155   // Start by finding the first space (if any).
    156   std::string::const_iterator space;
    157   for (space = begin; space != end; ++space) {
    158     if (HttpUtil::IsLWS(*space)) {
    159       break;
    160     }
    161   }
    162 
    163   // Everything to the left of the space is the scheme.
    164   Scheme scheme = GetSchemeFromPacTypeInternal(begin, space);
    165 
    166   // And everything to the right of the space is the
    167   // <host>[":" <port>].
    168   return FromSchemeHostAndPort(scheme, space, end);
    169 }
    170 
    171 std::string ProxyServer::ToPacString() const {
    172     switch (scheme_) {
    173     case SCHEME_DIRECT:
    174       return "DIRECT";
    175     case SCHEME_HTTP:
    176       return std::string("PROXY ") + host_port_pair().ToString();
    177     case SCHEME_SOCKS4:
    178       // For compatibility send SOCKS instead of SOCKS4.
    179       return std::string("SOCKS ") + host_port_pair().ToString();
    180     case SCHEME_SOCKS5:
    181       return std::string("SOCKS5 ") + host_port_pair().ToString();
    182     case SCHEME_HTTPS:
    183       return std::string("HTTPS ") + host_port_pair().ToString();
    184     default:
    185       // Got called with an invalid scheme.
    186       NOTREACHED();
    187       return std::string();
    188   }
    189 }
    190 
    191 // static
    192 int ProxyServer::GetDefaultPortForScheme(Scheme scheme) {
    193   switch (scheme) {
    194     case SCHEME_HTTP:
    195       return 80;
    196     case SCHEME_SOCKS4:
    197     case SCHEME_SOCKS5:
    198       return 1080;
    199     case SCHEME_HTTPS:
    200       return 443;
    201     default:
    202       return -1;
    203   }
    204 }
    205 
    206 // static
    207 ProxyServer::Scheme ProxyServer::GetSchemeFromURI(const std::string& scheme) {
    208   return GetSchemeFromURIInternal(scheme.begin(), scheme.end());
    209 }
    210 
    211 // TODO(bengr): Use |scheme_| to indicate that this is the data reduction proxy.
    212 #if defined(SPDY_PROXY_AUTH_ORIGIN)
    213 bool ProxyServer::isDataReductionProxy() const {
    214   return host_port_pair_.Equals(
    215       HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN)));
    216 }
    217 
    218 bool ProxyServer::isDataReductionProxyFallback() const {
    219 #if defined(DATA_REDUCTION_FALLBACK_HOST)
    220   return host_port_pair_.Equals(
    221       HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST)));
    222 #endif  // defined(DATA_REDUCTION_FALLBACK_HOST)
    223   return false;
    224 }
    225 #endif  // defined(SPDY_PROXY_AUTH_ORIGIN)
    226 
    227 // static
    228 ProxyServer ProxyServer::FromSchemeHostAndPort(
    229     Scheme scheme,
    230     std::string::const_iterator begin,
    231     std::string::const_iterator end) {
    232 
    233   // Trim leading/trailing space.
    234   HttpUtil::TrimLWS(&begin, &end);
    235 
    236   if (scheme == SCHEME_DIRECT && begin != end)
    237     return ProxyServer();  // Invalid -- DIRECT cannot have a host/port.
    238 
    239   HostPortPair host_port_pair;
    240 
    241   if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) {
    242     std::string host;
    243     int port = -1;
    244     // If the scheme has a host/port, parse it.
    245     bool ok = net::ParseHostAndPort(begin, end, &host, &port);
    246     if (!ok)
    247       return ProxyServer();  // Invalid -- failed parsing <host>[":"<port>]
    248 
    249     // Choose a default port number if none was given.
    250     if (port == -1)
    251       port = GetDefaultPortForScheme(scheme);
    252 
    253     host_port_pair = HostPortPair(HostNoBrackets(host), port);
    254   }
    255 
    256   return ProxyServer(scheme, host_port_pair);
    257 }
    258 
    259 }  // namespace net
    260