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 std::string HostNoBrackets(const std::string& host) { 68 // Remove brackets from an RFC 2732-style IPv6 literal address. 69 const std::string::size_type len = host.size(); 70 if (len >= 2 && host[0] == '[' && host[len - 1] == ']') 71 return host.substr(1, len - 2); 72 return host; 73 } 74 75 } // namespace 76 77 ProxyServer::ProxyServer(Scheme scheme, const HostPortPair& host_port_pair) 78 : scheme_(scheme), host_port_pair_(host_port_pair) { 79 if (scheme_ == SCHEME_DIRECT || scheme_ == SCHEME_INVALID) { 80 // |host_port_pair| isn't relevant for these special schemes, so none should 81 // have been specified. It is important for this to be consistent since we 82 // do raw field comparisons in the equality and comparison functions. 83 DCHECK(host_port_pair.Equals(HostPortPair())); 84 host_port_pair_ = HostPortPair(); 85 } 86 } 87 88 const HostPortPair& ProxyServer::host_port_pair() const { 89 // Doesn't make sense to call this if the URI scheme doesn't 90 // have concept of a host. 91 DCHECK(is_valid() && !is_direct()); 92 return host_port_pair_; 93 } 94 95 // static 96 ProxyServer ProxyServer::FromURI(const std::string& uri, 97 Scheme default_scheme) { 98 return FromURI(uri.begin(), uri.end(), default_scheme); 99 } 100 101 // static 102 ProxyServer ProxyServer::FromURI(std::string::const_iterator begin, 103 std::string::const_iterator end, 104 Scheme default_scheme) { 105 // We will default to |default_scheme| if no scheme specifier was given. 106 Scheme scheme = default_scheme; 107 108 // Trim the leading/trailing whitespace. 109 HttpUtil::TrimLWS(&begin, &end); 110 111 // Check for [<scheme> "://"] 112 std::string::const_iterator colon = std::find(begin, end, ':'); 113 if (colon != end && 114 (end - colon) >= 3 && 115 *(colon + 1) == '/' && 116 *(colon + 2) == '/') { 117 scheme = GetSchemeFromURIInternal(begin, colon); 118 begin = colon + 3; // Skip past the "://" 119 } 120 121 // Now parse the <host>[":"<port>]. 122 return FromSchemeHostAndPort(scheme, begin, end); 123 } 124 125 std::string ProxyServer::ToURI() const { 126 switch (scheme_) { 127 case SCHEME_DIRECT: 128 return "direct://"; 129 case SCHEME_HTTP: 130 // Leave off "http://" since it is our default scheme. 131 return host_port_pair().ToString(); 132 case SCHEME_SOCKS4: 133 return std::string("socks4://") + host_port_pair().ToString(); 134 case SCHEME_SOCKS5: 135 return std::string("socks5://") + host_port_pair().ToString(); 136 case SCHEME_HTTPS: 137 return std::string("https://") + host_port_pair().ToString(); 138 case SCHEME_QUIC: 139 return std::string("quic://") + host_port_pair().ToString(); 140 default: 141 // Got called with an invalid scheme. 142 NOTREACHED(); 143 return std::string(); 144 } 145 } 146 147 // static 148 ProxyServer ProxyServer::FromPacString(const std::string& pac_string) { 149 return FromPacString(pac_string.begin(), pac_string.end()); 150 } 151 152 // static 153 ProxyServer ProxyServer::FromPacString(std::string::const_iterator begin, 154 std::string::const_iterator end) { 155 // Trim the leading/trailing whitespace. 156 HttpUtil::TrimLWS(&begin, &end); 157 158 // Input should match: 159 // "DIRECT" | ( <type> 1*(LWS) <host-and-port> ) 160 161 // Start by finding the first space (if any). 162 std::string::const_iterator space; 163 for (space = begin; space != end; ++space) { 164 if (HttpUtil::IsLWS(*space)) { 165 break; 166 } 167 } 168 169 // Everything to the left of the space is the scheme. 170 Scheme scheme = GetSchemeFromPacTypeInternal(begin, space); 171 172 // And everything to the right of the space is the 173 // <host>[":" <port>]. 174 return FromSchemeHostAndPort(scheme, space, end); 175 } 176 177 std::string ProxyServer::ToPacString() const { 178 switch (scheme_) { 179 case SCHEME_DIRECT: 180 return "DIRECT"; 181 case SCHEME_HTTP: 182 return std::string("PROXY ") + host_port_pair().ToString(); 183 case SCHEME_SOCKS4: 184 // For compatibility send SOCKS instead of SOCKS4. 185 return std::string("SOCKS ") + host_port_pair().ToString(); 186 case SCHEME_SOCKS5: 187 return std::string("SOCKS5 ") + host_port_pair().ToString(); 188 case SCHEME_HTTPS: 189 return std::string("HTTPS ") + host_port_pair().ToString(); 190 case SCHEME_QUIC: 191 return std::string("QUIC ") + host_port_pair().ToString(); 192 default: 193 // Got called with an invalid scheme. 194 NOTREACHED(); 195 return std::string(); 196 } 197 } 198 199 // static 200 int ProxyServer::GetDefaultPortForScheme(Scheme scheme) { 201 switch (scheme) { 202 case SCHEME_HTTP: 203 return 80; 204 case SCHEME_SOCKS4: 205 case SCHEME_SOCKS5: 206 return 1080; 207 case SCHEME_HTTPS: 208 case SCHEME_QUIC: 209 return 443; 210 case SCHEME_INVALID: 211 case SCHEME_DIRECT: 212 break; 213 } 214 return -1; 215 } 216 217 // static 218 ProxyServer::Scheme ProxyServer::GetSchemeFromURI(const std::string& scheme) { 219 return GetSchemeFromURIInternal(scheme.begin(), scheme.end()); 220 } 221 222 // TODO(bengr): Use |scheme_| to indicate that this is the data reduction proxy. 223 #if defined(SPDY_PROXY_AUTH_ORIGIN) 224 bool ProxyServer::isDataReductionProxy() const { 225 bool dev_host = false; 226 #if defined (DATA_REDUCTION_DEV_HOST) 227 dev_host = host_port_pair_.Equals( 228 HostPortPair::FromURL(GURL(DATA_REDUCTION_DEV_HOST))); 229 #endif 230 return dev_host || host_port_pair_.Equals( 231 HostPortPair::FromURL(GURL(SPDY_PROXY_AUTH_ORIGIN))); 232 } 233 234 bool ProxyServer::isDataReductionProxyFallback() const { 235 #if defined(DATA_REDUCTION_FALLBACK_HOST) 236 return host_port_pair_.Equals( 237 HostPortPair::FromURL(GURL(DATA_REDUCTION_FALLBACK_HOST))); 238 #endif // defined(DATA_REDUCTION_FALLBACK_HOST) 239 return false; 240 } 241 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) 242 243 // static 244 ProxyServer ProxyServer::FromSchemeHostAndPort( 245 Scheme scheme, 246 std::string::const_iterator begin, 247 std::string::const_iterator end) { 248 249 // Trim leading/trailing space. 250 HttpUtil::TrimLWS(&begin, &end); 251 252 if (scheme == SCHEME_DIRECT && begin != end) 253 return ProxyServer(); // Invalid -- DIRECT cannot have a host/port. 254 255 HostPortPair host_port_pair; 256 257 if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) { 258 std::string host; 259 int port = -1; 260 // If the scheme has a host/port, parse it. 261 bool ok = net::ParseHostAndPort(begin, end, &host, &port); 262 if (!ok) 263 return ProxyServer(); // Invalid -- failed parsing <host>[":"<port>] 264 265 // Choose a default port number if none was given. 266 if (port == -1) 267 port = GetDefaultPortForScheme(scheme); 268 269 host_port_pair = HostPortPair(HostNoBrackets(host), port); 270 } 271 272 return ProxyServer(scheme, host_port_pair); 273 } 274 275 } // namespace net 276