• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_config.h"
6 
7 #include "base/logging.h"
8 #include "base/string_tokenizer.h"
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "net/proxy/proxy_info.h"
12 
13 namespace net {
14 
15 namespace {
16 
17 // If |proxy| is valid, sets it in |dict| under the key |name|.
AddProxyToValue(const char * name,const ProxyServer & proxy,DictionaryValue * dict)18 void AddProxyToValue(const char* name,
19                      const ProxyServer& proxy,
20                      DictionaryValue* dict) {
21   if (proxy.is_valid())
22     dict->SetString(name, proxy.ToURI());
23 }
24 
25 }  // namespace
26 
ProxyRules()27 ProxyConfig::ProxyRules::ProxyRules()
28     : reverse_bypass(false),
29       type(TYPE_NO_RULES) {
30 }
31 
~ProxyRules()32 ProxyConfig::ProxyRules::~ProxyRules() {
33 }
34 
Apply(const GURL & url,ProxyInfo * result)35 void ProxyConfig::ProxyRules::Apply(const GURL& url, ProxyInfo* result) {
36   if (empty()) {
37     result->UseDirect();
38     return;
39   }
40 
41   bool bypass_proxy = bypass_rules.Matches(url);
42   if (reverse_bypass)
43     bypass_proxy = !bypass_proxy;
44   if (bypass_proxy) {
45     result->UseDirect();
46     return;
47   }
48 
49   switch (type) {
50     case ProxyRules::TYPE_SINGLE_PROXY: {
51       result->UseProxyServer(single_proxy);
52       return;
53     }
54     case ProxyRules::TYPE_PROXY_PER_SCHEME: {
55       const ProxyServer* entry = MapUrlSchemeToProxy(url.scheme());
56       if (entry) {
57         result->UseProxyServer(*entry);
58       } else {
59         // We failed to find a matching proxy server for the current URL
60         // scheme. Default to direct.
61         result->UseDirect();
62       }
63       return;
64     }
65     default: {
66       result->UseDirect();
67       NOTREACHED();
68       return;
69     }
70   }
71 }
72 
ParseFromString(const std::string & proxy_rules)73 void ProxyConfig::ProxyRules::ParseFromString(const std::string& proxy_rules) {
74   // Reset.
75   type = TYPE_NO_RULES;
76   single_proxy = ProxyServer();
77   proxy_for_http = ProxyServer();
78   proxy_for_https = ProxyServer();
79   proxy_for_ftp = ProxyServer();
80   fallback_proxy = ProxyServer();
81 
82   StringTokenizer proxy_server_list(proxy_rules, ";");
83   while (proxy_server_list.GetNext()) {
84     StringTokenizer proxy_server_for_scheme(
85         proxy_server_list.token_begin(), proxy_server_list.token_end(), "=");
86 
87     while (proxy_server_for_scheme.GetNext()) {
88       std::string url_scheme = proxy_server_for_scheme.token();
89 
90       // If we fail to get the proxy server here, it means that
91       // this is a regular proxy server configuration, i.e. proxies
92       // are not configured per protocol.
93       if (!proxy_server_for_scheme.GetNext()) {
94         if (type == TYPE_PROXY_PER_SCHEME)
95           continue;  // Unexpected.
96         single_proxy = ProxyServer::FromURI(url_scheme,
97                                             ProxyServer::SCHEME_HTTP);
98         type = TYPE_SINGLE_PROXY;
99         return;
100       }
101 
102       // Trim whitespace off the url scheme.
103       TrimWhitespaceASCII(url_scheme, TRIM_ALL, &url_scheme);
104 
105       // Add it to the per-scheme mappings (if supported scheme).
106       type = TYPE_PROXY_PER_SCHEME;
107       ProxyServer* entry = MapUrlSchemeToProxyNoFallback(url_scheme);
108       ProxyServer::Scheme default_scheme = ProxyServer::SCHEME_HTTP;
109 
110       // socks=XXX is inconsistent with the other formats, since "socks"
111       // is not a URL scheme. Rather this means "for everything else, send
112       // it to the SOCKS proxy server XXX".
113       if (url_scheme == "socks") {
114         DCHECK(!entry);
115         entry = &fallback_proxy;
116         default_scheme = ProxyServer::SCHEME_SOCKS4;
117       }
118 
119       if (entry) {
120         *entry = ProxyServer::FromURI(proxy_server_for_scheme.token(),
121                                       default_scheme);
122       }
123     }
124   }
125 }
126 
MapUrlSchemeToProxy(const std::string & url_scheme) const127 const ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxy(
128     const std::string& url_scheme) const {
129   const ProxyServer* proxy_server =
130       const_cast<ProxyRules*>(this)->MapUrlSchemeToProxyNoFallback(url_scheme);
131   if (proxy_server && proxy_server->is_valid())
132     return proxy_server;
133   if (fallback_proxy.is_valid())
134     return &fallback_proxy;
135   return NULL;  // No mapping for this scheme. Use direct.
136 }
137 
Equals(const ProxyRules & other) const138 bool ProxyConfig::ProxyRules::Equals(const ProxyRules& other) const {
139   return type == other.type &&
140          single_proxy == other.single_proxy &&
141          proxy_for_http == other.proxy_for_http &&
142          proxy_for_https == other.proxy_for_https &&
143          proxy_for_ftp == other.proxy_for_ftp &&
144          fallback_proxy == other.fallback_proxy &&
145          bypass_rules.Equals(other.bypass_rules) &&
146          reverse_bypass == other.reverse_bypass;
147 }
148 
MapUrlSchemeToProxyNoFallback(const std::string & scheme)149 ProxyServer* ProxyConfig::ProxyRules::MapUrlSchemeToProxyNoFallback(
150     const std::string& scheme) {
151   DCHECK_EQ(TYPE_PROXY_PER_SCHEME, type);
152   if (scheme == "http")
153     return &proxy_for_http;
154   if (scheme == "https")
155     return &proxy_for_https;
156   if (scheme == "ftp")
157     return &proxy_for_ftp;
158   return NULL;  // No mapping for this scheme.
159 }
160 
ProxyConfig()161 ProxyConfig::ProxyConfig() : auto_detect_(false), id_(INVALID_ID) {
162 }
163 
ProxyConfig(const ProxyConfig & config)164 ProxyConfig::ProxyConfig(const ProxyConfig& config)
165     : auto_detect_(config.auto_detect_),
166       pac_url_(config.pac_url_),
167       proxy_rules_(config.proxy_rules_),
168       id_(config.id_) {
169 }
170 
~ProxyConfig()171 ProxyConfig::~ProxyConfig() {
172 }
173 
operator =(const ProxyConfig & config)174 ProxyConfig& ProxyConfig::operator=(const ProxyConfig& config) {
175   auto_detect_ = config.auto_detect_;
176   pac_url_ = config.pac_url_;
177   proxy_rules_ = config.proxy_rules_;
178   id_ = config.id_;
179   return *this;
180 }
181 
Equals(const ProxyConfig & other) const182 bool ProxyConfig::Equals(const ProxyConfig& other) const {
183   // The two configs can have different IDs.  We are just interested in if they
184   // have the same settings.
185   return auto_detect_ == other.auto_detect_ &&
186          pac_url_ == other.pac_url_ &&
187          proxy_rules_.Equals(other.proxy_rules());
188 }
189 
HasAutomaticSettings() const190 bool ProxyConfig::HasAutomaticSettings() const {
191   return auto_detect_ || has_pac_url();
192 }
193 
ClearAutomaticSettings()194 void ProxyConfig::ClearAutomaticSettings() {
195   auto_detect_ = false;
196   pac_url_ = GURL();
197 }
198 
ToValue() const199 Value* ProxyConfig::ToValue() const {
200   DictionaryValue* dict = new DictionaryValue();
201 
202   // Output the automatic settings.
203   if (auto_detect_)
204     dict->SetBoolean("auto_detect", auto_detect_);
205   if (has_pac_url())
206     dict->SetString("pac_url", pac_url_.possibly_invalid_spec());
207 
208   // Output the manual settings.
209   if (proxy_rules_.type != ProxyRules::TYPE_NO_RULES) {
210     switch (proxy_rules_.type) {
211       case ProxyRules::TYPE_SINGLE_PROXY:
212         AddProxyToValue("single_proxy", proxy_rules_.single_proxy, dict);
213         break;
214       case ProxyRules::TYPE_PROXY_PER_SCHEME: {
215         DictionaryValue* dict2 = new DictionaryValue();
216         AddProxyToValue("http", proxy_rules_.proxy_for_http, dict2);
217         AddProxyToValue("https", proxy_rules_.proxy_for_https, dict2);
218         AddProxyToValue("ftp", proxy_rules_.proxy_for_ftp, dict2);
219         AddProxyToValue("fallback", proxy_rules_.fallback_proxy, dict2);
220         dict->Set("proxy_per_scheme", dict2);
221         break;
222       }
223       default:
224         NOTREACHED();
225     }
226 
227     // Output the bypass rules.
228     const ProxyBypassRules& bypass = proxy_rules_.bypass_rules;
229     if (!bypass.rules().empty()) {
230       if (proxy_rules_.reverse_bypass)
231         dict->SetBoolean("reverse_bypass", true);
232 
233       ListValue* list = new ListValue();
234 
235       for (ProxyBypassRules::RuleList::const_iterator it =
236               bypass.rules().begin();
237            it != bypass.rules().end(); ++it) {
238         list->Append(Value::CreateStringValue((*it)->ToString()));
239       }
240 
241       dict->Set("bypass_list", list);
242     }
243   }
244 
245   return dict;
246 }
247 
248 }  // namespace net
249 
250