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