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/string_tokenizer.h"
9 #include "base/string_util.h"
10 #include "base/values.h"
11 #include "net/proxy/proxy_info.h"
17 // If |proxy| is valid, sets it in |dict| under the key |name|.
18 void AddProxyToValue(const char* name
,
19 const ProxyServer
& proxy
,
20 DictionaryValue
* dict
) {
22 dict
->SetString(name
, proxy
.ToURI());
27 ProxyConfig::ProxyRules::ProxyRules()
28 : reverse_bypass(false),
32 ProxyConfig::ProxyRules::~ProxyRules() {
35 void ProxyConfig::ProxyRules::Apply(const GURL
& url
, ProxyInfo
* result
) const {
41 bool bypass_proxy
= bypass_rules
.Matches(url
);
43 bypass_proxy
= !bypass_proxy
;
45 result
->UseDirectWithBypassedProxy();
50 case ProxyRules::TYPE_SINGLE_PROXY
: {
51 result
->UseProxyServer(single_proxy
);
54 case ProxyRules::TYPE_PROXY_PER_SCHEME
: {
55 const ProxyServer
* entry
= MapUrlSchemeToProxy(url
.scheme());
57 result
->UseProxyServer(*entry
);
59 // We failed to find a matching proxy server for the current URL
60 // scheme. Default to direct.
73 void ProxyConfig::ProxyRules::ParseFromString(const std::string
& proxy_rules
) {
76 single_proxy
= ProxyServer();
77 proxy_for_http
= ProxyServer();
78 proxy_for_https
= ProxyServer();
79 proxy_for_ftp
= ProxyServer();
80 fallback_proxy
= ProxyServer();
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(), "=");
87 while (proxy_server_for_scheme
.GetNext()) {
88 std::string url_scheme
= proxy_server_for_scheme
.token();
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
;
102 // Trim whitespace off the url scheme.
103 TrimWhitespaceASCII(url_scheme
, TRIM_ALL
, &url_scheme
);
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
;
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") {
115 entry
= &fallback_proxy
;
116 default_scheme
= ProxyServer::SCHEME_SOCKS4
;
120 *entry
= ProxyServer::FromURI(proxy_server_for_scheme
.token(),
127 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())
133 if (fallback_proxy
.is_valid())
134 return &fallback_proxy
;
135 return NULL
; // No mapping for this scheme. Use direct.
138 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
;
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
;
157 return &proxy_for_ftp
;
158 return NULL
; // No mapping for this scheme.
161 ProxyConfig::ProxyConfig()
162 : auto_detect_(false), pac_mandatory_(false),
163 source_(PROXY_CONFIG_SOURCE_UNKNOWN
), id_(kInvalidConfigID
) {
166 ProxyConfig::ProxyConfig(const ProxyConfig
& config
)
167 : auto_detect_(config
.auto_detect_
),
168 pac_url_(config
.pac_url_
),
169 pac_mandatory_(config
.pac_mandatory_
),
170 proxy_rules_(config
.proxy_rules_
),
171 source_(config
.source_
),
175 ProxyConfig::~ProxyConfig() {
178 ProxyConfig
& ProxyConfig::operator=(const ProxyConfig
& config
) {
179 auto_detect_
= config
.auto_detect_
;
180 pac_url_
= config
.pac_url_
;
181 pac_mandatory_
= config
.pac_mandatory_
;
182 proxy_rules_
= config
.proxy_rules_
;
183 source_
= config
.source_
;
188 bool ProxyConfig::Equals(const ProxyConfig
& other
) const {
189 // The two configs can have different IDs and sources. We are just interested
190 // in if they have the same settings.
191 return auto_detect_
== other
.auto_detect_
&&
192 pac_url_
== other
.pac_url_
&&
193 pac_mandatory_
== other
.pac_mandatory_
&&
194 proxy_rules_
.Equals(other
.proxy_rules());
197 bool ProxyConfig::HasAutomaticSettings() const {
198 return auto_detect_
|| has_pac_url();
201 void ProxyConfig::ClearAutomaticSettings() {
202 auto_detect_
= false;
206 Value
* ProxyConfig::ToValue() const {
207 DictionaryValue
* dict
= new DictionaryValue();
209 // Output the automatic settings.
211 dict
->SetBoolean("auto_detect", auto_detect_
);
213 dict
->SetString("pac_url", pac_url_
.possibly_invalid_spec());
215 dict
->SetBoolean("pac_mandatory", pac_mandatory_
);
218 // Output the manual settings.
219 if (proxy_rules_
.type
!= ProxyRules::TYPE_NO_RULES
) {
220 switch (proxy_rules_
.type
) {
221 case ProxyRules::TYPE_SINGLE_PROXY
:
222 AddProxyToValue("single_proxy", proxy_rules_
.single_proxy
, dict
);
224 case ProxyRules::TYPE_PROXY_PER_SCHEME
: {
225 DictionaryValue
* dict2
= new DictionaryValue();
226 AddProxyToValue("http", proxy_rules_
.proxy_for_http
, dict2
);
227 AddProxyToValue("https", proxy_rules_
.proxy_for_https
, dict2
);
228 AddProxyToValue("ftp", proxy_rules_
.proxy_for_ftp
, dict2
);
229 AddProxyToValue("fallback", proxy_rules_
.fallback_proxy
, dict2
);
230 dict
->Set("proxy_per_scheme", dict2
);
237 // Output the bypass rules.
238 const ProxyBypassRules
& bypass
= proxy_rules_
.bypass_rules
;
239 if (!bypass
.rules().empty()) {
240 if (proxy_rules_
.reverse_bypass
)
241 dict
->SetBoolean("reverse_bypass", true);
243 ListValue
* list
= new ListValue();
245 for (ProxyBypassRules::RuleList::const_iterator it
=
246 bypass
.rules().begin();
247 it
!= bypass
.rules().end(); ++it
) {
248 list
->Append(Value::CreateStringValue((*it
)->ToString()));
251 dict
->Set("bypass_list", list
);
255 // Output the source.
256 dict
->SetString("source", ProxyConfigSourceToString(source_
));