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 (!fallback_proxies
.IsEmpty())
149 return &fallback_proxies
;
150 return NULL
; // No mapping for this scheme. Use direct.
153 bool ProxyConfig::ProxyRules::Equals(const ProxyRules
& other
) const {
154 return type
== other
.type
&&
155 single_proxies
.Equals(other
.single_proxies
) &&
156 proxies_for_http
.Equals(other
.proxies_for_http
) &&
157 proxies_for_https
.Equals(other
.proxies_for_https
) &&
158 proxies_for_ftp
.Equals(other
.proxies_for_ftp
) &&
159 fallback_proxies
.Equals(other
.fallback_proxies
) &&
160 bypass_rules
.Equals(other
.bypass_rules
) &&
161 reverse_bypass
== other
.reverse_bypass
;
164 ProxyList
* ProxyConfig::ProxyRules::MapUrlSchemeToProxyListNoFallback(
165 const std::string
& scheme
) {
166 DCHECK_EQ(TYPE_PROXY_PER_SCHEME
, type
);
167 if (scheme
== "http")
168 return &proxies_for_http
;
169 if (scheme
== "https")
170 return &proxies_for_https
;
172 return &proxies_for_ftp
;
173 return NULL
; // No mapping for this scheme.
176 ProxyConfig::ProxyConfig()
177 : auto_detect_(false), pac_mandatory_(false),
178 source_(PROXY_CONFIG_SOURCE_UNKNOWN
), id_(kInvalidConfigID
) {
181 ProxyConfig::ProxyConfig(const ProxyConfig
& config
)
182 : auto_detect_(config
.auto_detect_
),
183 pac_url_(config
.pac_url_
),
184 pac_mandatory_(config
.pac_mandatory_
),
185 proxy_rules_(config
.proxy_rules_
),
186 source_(config
.source_
),
190 ProxyConfig::~ProxyConfig() {
193 ProxyConfig
& ProxyConfig::operator=(const ProxyConfig
& config
) {
194 auto_detect_
= config
.auto_detect_
;
195 pac_url_
= config
.pac_url_
;
196 pac_mandatory_
= config
.pac_mandatory_
;
197 proxy_rules_
= config
.proxy_rules_
;
198 source_
= config
.source_
;
203 bool ProxyConfig::Equals(const ProxyConfig
& other
) const {
204 // The two configs can have different IDs and sources. We are just interested
205 // in if they have the same settings.
206 return auto_detect_
== other
.auto_detect_
&&
207 pac_url_
== other
.pac_url_
&&
208 pac_mandatory_
== other
.pac_mandatory_
&&
209 proxy_rules_
.Equals(other
.proxy_rules());
212 bool ProxyConfig::HasAutomaticSettings() const {
213 return auto_detect_
|| has_pac_url();
216 void ProxyConfig::ClearAutomaticSettings() {
217 auto_detect_
= false;
221 base::DictionaryValue
* ProxyConfig::ToValue() const {
222 base::DictionaryValue
* dict
= new base::DictionaryValue();
224 // Output the automatic settings.
226 dict
->SetBoolean("auto_detect", auto_detect_
);
228 dict
->SetString("pac_url", pac_url_
.possibly_invalid_spec());
230 dict
->SetBoolean("pac_mandatory", pac_mandatory_
);
233 // Output the manual settings.
234 if (proxy_rules_
.type
!= ProxyRules::TYPE_NO_RULES
) {
235 switch (proxy_rules_
.type
) {
236 case ProxyRules::TYPE_SINGLE_PROXY
:
237 AddProxyListToValue("single_proxy",
238 proxy_rules_
.single_proxies
, dict
);
240 case ProxyRules::TYPE_PROXY_PER_SCHEME
: {
241 base::DictionaryValue
* dict2
= new base::DictionaryValue();
242 AddProxyListToValue("http", proxy_rules_
.proxies_for_http
, dict2
);
243 AddProxyListToValue("https", proxy_rules_
.proxies_for_https
, dict2
);
244 AddProxyListToValue("ftp", proxy_rules_
.proxies_for_ftp
, dict2
);
245 AddProxyListToValue("fallback", proxy_rules_
.fallback_proxies
, dict2
);
246 dict
->Set("proxy_per_scheme", dict2
);
253 // Output the bypass rules.
254 const ProxyBypassRules
& bypass
= proxy_rules_
.bypass_rules
;
255 if (!bypass
.rules().empty()) {
256 if (proxy_rules_
.reverse_bypass
)
257 dict
->SetBoolean("reverse_bypass", true);
259 base::ListValue
* list
= new base::ListValue();
261 for (ProxyBypassRules::RuleList::const_iterator it
=
262 bypass
.rules().begin();
263 it
!= bypass
.rules().end(); ++it
) {
264 list
->Append(new base::StringValue((*it
)->ToString()));
267 dict
->Set("bypass_list", list
);
271 // Output the source.
272 dict
->SetString("source", ProxyConfigSourceToString(source_
));