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