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   if (LowerCaseEqualsASCII(begin, end, "quic"))
     40     return ProxyServer::SCHEME_QUIC;
     41 
     42   return ProxyServer::SCHEME_INVALID;
     43 }
     44 
     45 // Parses the proxy scheme from a URL-like representation, to a
     46 // ProxyServer::Scheme. This corresponds with the values used in
     47 // ProxyServer::ToURI(). If no type could be matched, returns SCHEME_INVALID.
     48 ProxyServer::Scheme GetSchemeFromURIInternal(std::string::const_iterator begin,
     49                                              std::string::const_iterator end) {
     50   if (LowerCaseEqualsASCII(begin, end, "http"))
     51     return ProxyServer::SCHEME_HTTP;
     52   if (LowerCaseEqualsASCII(begin, end, "socks4"))
     53     return ProxyServer::SCHEME_SOCKS4;
     54   if (LowerCaseEqualsASCII(begin, end, "socks"))
     55     return ProxyServer::SCHEME_SOCKS5;
     56   if (LowerCaseEqualsASCII(begin, end, "socks5"))
     57     return ProxyServer::SCHEME_SOCKS5;
     58   if (LowerCaseEqualsASCII(begin, end, "direct"))
     59     return ProxyServer::SCHEME_DIRECT;
     60   if (LowerCaseEqualsASCII(begin, end, "https"))
     61     return ProxyServer::SCHEME_HTTPS;
     62   if (LowerCaseEqualsASCII(begin, end, "quic"))
     63     return ProxyServer::SCHEME_QUIC;
     64   return ProxyServer::SCHEME_INVALID;
     65 }
     66 
     67 }  // namespace
     68 
     69 ProxyServer::ProxyServer(Scheme scheme, const HostPortPair& host_port_pair)
     70       : scheme_(scheme), host_port_pair_(host_port_pair) {
     71   if (scheme_ == SCHEME_DIRECT || scheme_ == SCHEME_INVALID) {
     72     // |host_port_pair| isn't relevant for these special schemes, so none should
     73     // have been specified. It is important for this to be consistent since we
     74     // do raw field comparisons in the equality and comparison functions.
     75     DCHECK(host_port_pair.Equals(HostPortPair()));
     76     host_port_pair_ = HostPortPair();
     77   }
     78 }
     79 
     80 const HostPortPair& ProxyServer::host_port_pair() const {
     81   // Doesn't make sense to call this if the URI scheme doesn't
     82   // have concept of a host.
     83   DCHECK(is_valid());
     84   DCHECK(!is_direct());
     85   return host_port_pair_;
     86 }
     87 
     88 // static
     89 ProxyServer ProxyServer::FromURI(const std::string& uri,
     90                                  Scheme default_scheme) {
     91   return FromURI(uri.begin(), uri.end(), default_scheme);
     92 }
     93 
     94 // static
     95 ProxyServer ProxyServer::FromURI(std::string::const_iterator begin,
     96                                  std::string::const_iterator end,
     97                                  Scheme default_scheme) {
     98   // We will default to |default_scheme| if no scheme specifier was given.
     99   Scheme scheme = default_scheme;
    100 
    101   // Trim the leading/trailing whitespace.
    102   HttpUtil::TrimLWS(&begin, &end);
    103 
    104   // Check for [<scheme> "://"]
    105   std::string::const_iterator colon = std::find(begin, end, ':');
    106   if (colon != end &&
    107       (end - colon) >= 3 &&
    108       *(colon + 1) == '/' &&
    109       *(colon + 2) == '/') {
    110     scheme = GetSchemeFromURIInternal(begin, colon);
    111     begin = colon + 3;  // Skip past the "://"
    112   }
    113 
    114   // Now parse the <host>[":"<port>].
    115   return FromSchemeHostAndPort(scheme, begin, end);
    116 }
    117 
    118 std::string ProxyServer::ToURI() const {
    119   switch (scheme_) {
    120     case SCHEME_DIRECT:
    121       return "direct://";
    122     case SCHEME_HTTP:
    123       // Leave off "http://" since it is our default scheme.
    124       return host_port_pair().ToString();
    125     case SCHEME_SOCKS4:
    126       return std::string("socks4://") + host_port_pair().ToString();
    127     case SCHEME_SOCKS5:
    128       return std::string("socks5://") + host_port_pair().ToString();
    129     case SCHEME_HTTPS:
    130       return std::string("https://") + host_port_pair().ToString();
    131     case SCHEME_QUIC:
    132       return std::string("quic://") + host_port_pair().ToString();
    133     default:
    134       // Got called with an invalid scheme.
    135       NOTREACHED();
    136       return std::string();
    137   }
    138 }
    139 
    140 // static
    141 ProxyServer ProxyServer::FromPacString(const std::string& pac_string) {
    142   return FromPacString(pac_string.begin(), pac_string.end());
    143 }
    144 
    145 // static
    146 ProxyServer ProxyServer::FromPacString(std::string::const_iterator begin,
    147                                        std::string::const_iterator end) {
    148   // Trim the leading/trailing whitespace.
    149   HttpUtil::TrimLWS(&begin, &end);
    150 
    151   // Input should match:
    152   // "DIRECT" | ( <type> 1*(LWS) <host-and-port> )
    153 
    154   // Start by finding the first space (if any).
    155   std::string::const_iterator space;
    156   for (space = begin; space != end; ++space) {
    157     if (HttpUtil::IsLWS(*space)) {
    158       break;
    159     }
    160   }
    161 
    162   // Everything to the left of the space is the scheme.
    163   Scheme scheme = GetSchemeFromPacTypeInternal(begin, space);
    164 
    165   // And everything to the right of the space is the
    166   // <host>[":" <port>].
    167   return FromSchemeHostAndPort(scheme, space, end);
    168 }
    169 
    170 std::string ProxyServer::ToPacString() const {
    171     switch (scheme_) {
    172     case SCHEME_DIRECT:
    173       return "DIRECT";
    174     case SCHEME_HTTP:
    175       return std::string("PROXY ") + host_port_pair().ToString();
    176     case SCHEME_SOCKS4:
    177       // For compatibility send SOCKS instead of SOCKS4.
    178       return std::string("SOCKS ") + host_port_pair().ToString();
    179     case SCHEME_SOCKS5:
    180       return std::string("SOCKS5 ") + host_port_pair().ToString();
    181     case SCHEME_HTTPS:
    182       return std::string("HTTPS ") + host_port_pair().ToString();
    183     case SCHEME_QUIC:
    184       return std::string("QUIC ") + host_port_pair().ToString();
    185     default:
    186       // Got called with an invalid scheme.
    187       NOTREACHED();
    188       return std::string();
    189   }
    190 }
    191 
    192 // static
    193 int ProxyServer::GetDefaultPortForScheme(Scheme scheme) {
    194   switch (scheme) {
    195     case SCHEME_HTTP:
    196       return 80;
    197     case SCHEME_SOCKS4:
    198     case SCHEME_SOCKS5:
    199       return 1080;
    200     case SCHEME_HTTPS:
    201     case SCHEME_QUIC:
    202       return 443;
    203     case SCHEME_INVALID:
    204     case SCHEME_DIRECT:
    205       break;
    206   }
    207   return -1;
    208 }
    209 
    210 // static
    211 ProxyServer::Scheme ProxyServer::GetSchemeFromURI(const std::string& scheme) {
    212   return GetSchemeFromURIInternal(scheme.begin(), scheme.end());
    213 }
    214 
    215 // static
    216 ProxyServer ProxyServer::FromSchemeHostAndPort(
    217     Scheme scheme,
    218     std::string::const_iterator begin,
    219     std::string::const_iterator end) {
    220 
    221   // Trim leading/trailing space.
    222   HttpUtil::TrimLWS(&begin, &end);
    223 
    224   if (scheme == SCHEME_DIRECT && begin != end)
    225     return ProxyServer();  // Invalid -- DIRECT cannot have a host/port.
    226 
    227   HostPortPair host_port_pair;
    228 
    229   if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) {
    230     std::string host;
    231     int port = -1;
    232     // If the scheme has a host/port, parse it.
    233     bool ok = net::ParseHostAndPort(begin, end, &host, &port);
    234     if (!ok)
    235       return ProxyServer();  // Invalid -- failed parsing <host>[":"<port>]
    236 
    237     // Choose a default port number if none was given.
    238     if (port == -1)
    239       port = GetDefaultPortForScheme(scheme);
    240 
    241     host_port_pair = HostPortPair(host, port);
    242   }
    243 
    244   return ProxyServer(scheme, host_port_pair);
    245 }
    246 
    247 }  // namespace net
    248