1 // Copyright (c) 2012 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.
5 #include "net/proxy/proxy_config.h"
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/string_tokenizer.h"
10 #include "base/values.h"
11 #include "net/proxy/proxy_info.h"
17 // If |proxies| is non-empty, sets it in |dict| under the key |name|.
18 void AddProxyListToValue(const char* name
,
19 const ProxyList
& proxies
,
20 base::DictionaryValue
* dict
) {
21 if (!proxies
.IsEmpty())
22 dict
->Set(name
, proxies
.ToValue());
25 // Split the |uri_list| on commas and add each entry to |proxy_list| in turn.
26 void AddProxyURIListToProxyList(std::string uri_list
,
27 ProxyList
* proxy_list
,
28 ProxyServer::Scheme default_scheme
) {
29 base::StringTokenizer
proxy_uri_list(uri_list
, ",");
30 while (proxy_uri_list
.GetNext()) {
31 proxy_list
->AddProxyServer(
32 ProxyServer::FromURI(proxy_uri_list
.token(), default_scheme
));
38 ProxyConfig::ProxyRules::ProxyRules()
39 : reverse_bypass(false),
43 ProxyConfig::ProxyRules::~ProxyRules() {
46 void ProxyConfig::ProxyRules::Apply(const GURL
& url
, ProxyInfo
* result
) const {
52 bool bypass_proxy
= bypass_rules
.Matches(url
);
54 bypass_proxy
= !bypass_proxy
;
56 result
->UseDirectWithBypassedProxy();
61 case ProxyRules::TYPE_SINGLE_PROXY
: {
62 result
->UseProxyList(single_proxies
);
65 case ProxyRules::TYPE_PROXY_PER_SCHEME
: {
66 const ProxyList
* entry
= MapUrlSchemeToProxyList(url
.scheme());
68 result
->UseProxyList(*entry
);
70 // We failed to find a matching proxy server for the current URL
71 // scheme. Default to direct.
84 void ProxyConfig::ProxyRules::ParseFromString(const std::string
& proxy_rules
) {
87 single_proxies
= ProxyList();
88 proxies_for_http
= ProxyList();
89 proxies_for_https
= ProxyList();
90 proxies_for_ftp
= ProxyList();
91 fallback_proxies
= ProxyList();
93 base::StringTokenizer
proxy_server_list(proxy_rules
, ";");
94 while (proxy_server_list
.GetNext()) {
95 base::StringTokenizer
proxy_server_for_scheme(
96 proxy_server_list
.token_begin(), proxy_server_list
.token_end(), "=");
98 while (proxy_server_for_scheme
.GetNext()) {
99 std::string url_scheme
= proxy_server_for_scheme
.token();
101 // If we fail to get the proxy server here, it means that
102 // this is a regular proxy server configuration, i.e. proxies
103 // are not configured per protocol.
104 if (!proxy_server_for_scheme
.GetNext()) {
105 if (type
== TYPE_PROXY_PER_SCHEME
)
106 continue; // Unexpected.
107 AddProxyURIListToProxyList(url_scheme
,
109 ProxyServer::SCHEME_HTTP
);
110 type
= TYPE_SINGLE_PROXY
;
114 // Trim whitespace off the url scheme.
115 base::TrimWhitespaceASCII(url_scheme
, base::TRIM_ALL
, &url_scheme
);
117 // Add it to the per-scheme mappings (if supported scheme).
118 type
= TYPE_PROXY_PER_SCHEME
;
119 ProxyList
* entry
= MapUrlSchemeToProxyListNoFallback(url_scheme
);
120 ProxyServer::Scheme default_scheme
= ProxyServer::SCHEME_HTTP
;
122 // socks=XXX is inconsistent with the other formats, since "socks"
123 // is not a URL scheme. Rather this means "for everything else, send
124 // it to the SOCKS proxy server XXX".
125 if (url_scheme
== "socks") {
127 entry
= &fallback_proxies
;
128 // Note that here 'socks' is understood to be SOCKS4, even though
129 // 'socks' maps to SOCKS5 in ProxyServer::GetSchemeFromURIInternal.
130 default_scheme
= ProxyServer::SCHEME_SOCKS4
;
134 AddProxyURIListToProxyList(proxy_server_for_scheme
.token(),
142 const ProxyList
* ProxyConfig::ProxyRules::MapUrlSchemeToProxyList(
143 const std::string
& url_scheme
) const {
144 const ProxyList
* proxy_server_list
= const_cast<ProxyRules
*>(this)->
145 MapUrlSchemeToProxyListNoFallback(url_scheme
);
146 if (proxy_server_list
&& !proxy_server_list
->IsEmpty())
147 return proxy_server_list
;
148 if (url_scheme
== "ws" || url_scheme
== "wss")
149 return GetProxyListForWebSocketScheme();
150 if (!fallback_proxies
.IsEmpty())
151 return &fallback_proxies
;
152 return NULL
; // No mapping for this scheme. Use direct.
155 bool ProxyConfig::ProxyRules::Equals(const ProxyRules
& other
) const {
156 return type
== other
.type
&&
157 single_proxies
.Equals(other
.single_proxies
) &&
158 proxies_for_http
.Equals(other
.proxies_for_http
) &&
159 proxies_for_https
.Equals(other
.proxies_for_https
) &&
160 proxies_for_ftp
.Equals(other
.proxies_for_ftp
) &&
161 fallback_proxies
.Equals(other
.fallback_proxies
) &&
162 bypass_rules
.Equals(other
.bypass_rules
) &&
163 reverse_bypass
== other
.reverse_bypass
;
166 ProxyList
* ProxyConfig::ProxyRules::MapUrlSchemeToProxyListNoFallback(
167 const std::string
& scheme
) {
168 DCHECK_EQ(TYPE_PROXY_PER_SCHEME
, type
);
169 if (scheme
== "http")
170 return &proxies_for_http
;
171 if (scheme
== "https")
172 return &proxies_for_https
;
174 return &proxies_for_ftp
;
175 return NULL
; // No mapping for this scheme.
178 const ProxyList
* ProxyConfig::ProxyRules::GetProxyListForWebSocketScheme()
180 if (!fallback_proxies
.IsEmpty())
181 return &fallback_proxies
;
182 if (!proxies_for_https
.IsEmpty())
183 return &proxies_for_https
;
184 if (!proxies_for_http
.IsEmpty())
185 return &proxies_for_http
;
189 ProxyConfig::ProxyConfig()
190 : auto_detect_(false), pac_mandatory_(false),
191 source_(PROXY_CONFIG_SOURCE_UNKNOWN
), id_(kInvalidConfigID
) {
194 ProxyConfig::ProxyConfig(const ProxyConfig
& config
)
195 : auto_detect_(config
.auto_detect_
),
196 pac_url_(config
.pac_url_
),
197 pac_mandatory_(config
.pac_mandatory_
),
198 proxy_rules_(config
.proxy_rules_
),
199 source_(config
.source_
),
203 ProxyConfig::~ProxyConfig() {
206 ProxyConfig
& ProxyConfig::operator=(const ProxyConfig
& config
) {
207 auto_detect_
= config
.auto_detect_
;
208 pac_url_
= config
.pac_url_
;
209 pac_mandatory_
= config
.pac_mandatory_
;
210 proxy_rules_
= config
.proxy_rules_
;
211 source_
= config
.source_
;
216 bool ProxyConfig::Equals(const ProxyConfig
& other
) const {
217 // The two configs can have different IDs and sources. We are just interested
218 // in if they have the same settings.
219 return auto_detect_
== other
.auto_detect_
&&
220 pac_url_
== other
.pac_url_
&&
221 pac_mandatory_
== other
.pac_mandatory_
&&
222 proxy_rules_
.Equals(other
.proxy_rules());
225 bool ProxyConfig::HasAutomaticSettings() const {
226 return auto_detect_
|| has_pac_url();
229 void ProxyConfig::ClearAutomaticSettings() {
230 auto_detect_
= false;
234 base::DictionaryValue
* ProxyConfig::ToValue() const {
235 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
237 // Output the automatic settings.
239 dict
->SetBoolean("auto_detect", auto_detect_
);
241 dict
->SetString("pac_url", pac_url_
.possibly_invalid_spec());
243 dict
->SetBoolean("pac_mandatory", pac_mandatory_
);
246 // Output the manual settings.
247 if (proxy_rules_
.type
!= ProxyRules::TYPE_NO_RULES
) {
248 switch (proxy_rules_
.type
) {
249 case ProxyRules::TYPE_SINGLE_PROXY
:
250 AddProxyListToValue("single_proxy", proxy_rules_
.single_proxies
,
253 case ProxyRules::TYPE_PROXY_PER_SCHEME
: {
254 scoped_ptr
<base::DictionaryValue
> dict2(new base::DictionaryValue());
255 AddProxyListToValue("http", proxy_rules_
.proxies_for_http
, dict2
.get());
256 AddProxyListToValue("https", proxy_rules_
.proxies_for_https
,
258 AddProxyListToValue("ftp", proxy_rules_
.proxies_for_ftp
, dict2
.get());
259 AddProxyListToValue("fallback", proxy_rules_
.fallback_proxies
,
261 dict
->Set("proxy_per_scheme", dict2
.Pass());
268 // Output the bypass rules.
269 const ProxyBypassRules
& bypass
= proxy_rules_
.bypass_rules
;
270 if (!bypass
.rules().empty()) {
271 if (proxy_rules_
.reverse_bypass
)
272 dict
->SetBoolean("reverse_bypass", true);
274 base::ListValue
* list
= new base::ListValue();
276 for (ProxyBypassRules::RuleList::const_iterator it
=
277 bypass
.rules().begin();
278 it
!= bypass
.rules().end(); ++it
) {
279 list
->Append(new base::StringValue((*it
)->ToString()));
282 dict
->Set("bypass_list", list
);
286 // Output the source.
287 dict
->SetString("source", ProxyConfigSourceToString(source_
));
289 return dict
.release();