1// Copyright (c) 2009 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/string_tokenizer.h" 10#include "base/string_util.h" 11#include "net/base/net_util.h" 12#include "net/http/http_util.h" 13 14namespace net { 15 16namespace { 17 18// Parse the proxy type from a PAC string, to a ProxyServer::Scheme. 19// This mapping is case-insensitive. If no type could be matched 20// returns SCHEME_INVALID. 21ProxyServer::Scheme GetSchemeFromPacType(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 38 return ProxyServer::SCHEME_INVALID; 39} 40 41// Parse the proxy scheme from a URL-like representation, to a 42// ProxyServer::Scheme. This corresponds with the values used in 43// ProxyServer::ToURI(). If no type could be matched, returns SCHEME_INVALID. 44ProxyServer::Scheme GetSchemeFromURI(std::string::const_iterator begin, 45 std::string::const_iterator end) { 46 if (LowerCaseEqualsASCII(begin, end, "http")) 47 return ProxyServer::SCHEME_HTTP; 48 if (LowerCaseEqualsASCII(begin, end, "socks4")) 49 return ProxyServer::SCHEME_SOCKS4; 50 if (LowerCaseEqualsASCII(begin, end, "socks")) 51 return ProxyServer::SCHEME_SOCKS4; 52 if (LowerCaseEqualsASCII(begin, end, "socks5")) 53 return ProxyServer::SCHEME_SOCKS5; 54 if (LowerCaseEqualsASCII(begin, end, "direct")) 55 return ProxyServer::SCHEME_DIRECT; 56 return ProxyServer::SCHEME_INVALID; 57} 58 59} // namespace 60 61std::string ProxyServer::HostNoBrackets() const { 62 // Doesn't make sense to call this if the URI scheme doesn't 63 // have concept of a host. 64 DCHECK(is_valid() && !is_direct()); 65 66 // Remove brackets from an RFC 2732-style IPv6 literal address. 67 const std::string::size_type len = host_.size(); 68 if (len != 0 && host_[0] == '[' && host_[len - 1] == ']') 69 return host_.substr(1, len - 2); 70 return host_; 71} 72 73int ProxyServer::port() const { 74 // Doesn't make sense to call this if the URI scheme doesn't 75 // have concept of a port. 76 DCHECK(is_valid() && !is_direct()); 77 return port_; 78} 79 80std::string ProxyServer::host_and_port() 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() && !is_direct()); 84 return host_ + ":" + IntToString(port_); 85} 86 87// static 88ProxyServer ProxyServer::FromURI(const std::string& uri, 89 Scheme default_scheme) { 90 return FromURI(uri.begin(), uri.end(), default_scheme); 91} 92 93// static 94ProxyServer ProxyServer::FromURI(std::string::const_iterator begin, 95 std::string::const_iterator end, 96 Scheme default_scheme) { 97 // We will default to |default_scheme| if no scheme specifier was given. 98 Scheme scheme = default_scheme; 99 100 // Trim the leading/trailing whitespace. 101 HttpUtil::TrimLWS(&begin, &end); 102 103 // Check for [<scheme> "://"] 104 std::string::const_iterator colon = std::find(begin, end, ':'); 105 if (colon != end && 106 (end - colon) >= 3 && 107 *(colon + 1) == '/' && 108 *(colon + 2) == '/') { 109 scheme = GetSchemeFromURI(begin, colon); 110 begin = colon + 3; // Skip past the "://" 111 } 112 113 // Now parse the <host>[":"<port>]. 114 return FromSchemeHostAndPort(scheme, begin, end); 115} 116 117std::string ProxyServer::ToURI() const { 118 switch (scheme_) { 119 case SCHEME_DIRECT: 120 return "direct://"; 121 case SCHEME_HTTP: 122 // Leave off "http://" since it is our default scheme. 123 return host_and_port(); 124 case SCHEME_SOCKS4: 125 return std::string("socks4://") + host_and_port(); 126 case SCHEME_SOCKS5: 127 return std::string("socks5://") + host_and_port(); 128 default: 129 // Got called with an invalid scheme. 130 NOTREACHED(); 131 return std::string(); 132 } 133} 134 135// static 136ProxyServer ProxyServer::FromPacString(const std::string& pac_string) { 137 return FromPacString(pac_string.begin(), pac_string.end()); 138} 139 140ProxyServer ProxyServer::FromPacString(std::string::const_iterator begin, 141 std::string::const_iterator end) { 142 // Trim the leading/trailing whitespace. 143 HttpUtil::TrimLWS(&begin, &end); 144 145 // Input should match: 146 // "DIRECT" | ( <type> 1*(LWS) <host-and-port> ) 147 148 // Start by finding the first space (if any). 149 std::string::const_iterator space; 150 for (space = begin; space != end; ++space) { 151 if (HttpUtil::IsLWS(*space)) { 152 break; 153 } 154 } 155 156 // Everything to the left of the space is the scheme. 157 Scheme scheme = GetSchemeFromPacType(begin, space); 158 159 // And everything to the right of the space is the 160 // <host>[":" <port>]. 161 return FromSchemeHostAndPort(scheme, space, end); 162} 163 164std::string ProxyServer::ToPacString() const { 165 switch (scheme_) { 166 case SCHEME_DIRECT: 167 return "DIRECT"; 168 case SCHEME_HTTP: 169 return std::string("PROXY ") + host_and_port(); 170 case SCHEME_SOCKS4: 171 // For compatibility send SOCKS instead of SOCKS4. 172 return std::string("SOCKS ") + host_and_port(); 173 case SCHEME_SOCKS5: 174 return std::string("SOCKS5 ") + host_and_port(); 175 default: 176 // Got called with an invalid scheme. 177 NOTREACHED(); 178 return std::string(); 179 } 180} 181 182// static 183int ProxyServer::GetDefaultPortForScheme(Scheme scheme) { 184 switch (scheme) { 185 case SCHEME_HTTP: 186 return 80; 187 case SCHEME_SOCKS4: 188 case SCHEME_SOCKS5: 189 return 1080; 190 default: 191 return -1; 192 } 193} 194 195// static 196ProxyServer ProxyServer::FromSchemeHostAndPort( 197 Scheme scheme, 198 std::string::const_iterator begin, 199 std::string::const_iterator end) { 200 201 // Trim leading/trailing space. 202 HttpUtil::TrimLWS(&begin, &end); 203 204 if (scheme == SCHEME_DIRECT && begin != end) 205 return ProxyServer(); // Invalid -- DIRECT cannot have a host/port. 206 207 std::string host; 208 int port = -1; 209 210 if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) { 211 // If the scheme has a host/port, parse it. 212 bool ok = net::ParseHostAndPort(begin, end, &host, &port); 213 if (!ok) 214 return ProxyServer(); // Invalid -- failed parsing <host>[":"<port>] 215 } 216 217 // Choose a default port number if none was given. 218 if (port == -1) 219 port = GetDefaultPortForScheme(scheme); 220 221 return ProxyServer(scheme, host, port); 222} 223 224} // namespace net 225