1 // Copyright 2013 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 "chrome/browser/net/firefox_proxy_settings.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_tokenizer.h"
11 #include "base/strings/string_util.h"
12 #include "base/values.h"
13 #include "chrome/common/importer/firefox_importer_utils.h"
14 #include "net/proxy/proxy_config.h"
18 const char* const kNetworkProxyTypeKey
= "network.proxy.type";
19 const char* const kHTTPProxyKey
= "network.proxy.http";
20 const char* const kHTTPProxyPortKey
= "network.proxy.http_port";
21 const char* const kSSLProxyKey
= "network.proxy.ssl";
22 const char* const kSSLProxyPortKey
= "network.proxy.ssl_port";
23 const char* const kFTPProxyKey
= "network.proxy.ftp";
24 const char* const kFTPProxyPortKey
= "network.proxy.ftp_port";
25 const char* const kGopherProxyKey
= "network.proxy.gopher";
26 const char* const kGopherProxyPortKey
= "network.proxy.gopher_port";
27 const char* const kSOCKSHostKey
= "network.proxy.socks";
28 const char* const kSOCKSHostPortKey
= "network.proxy.socks_port";
29 const char* const kSOCKSVersionKey
= "network.proxy.socks_version";
30 const char* const kAutoconfigURL
= "network.proxy.autoconfig_url";
31 const char* const kNoProxyListKey
= "network.proxy.no_proxies_on";
32 const char* const kPrefFileName
= "prefs.js";
34 FirefoxProxySettings::ProxyConfig
IntToProxyConfig(int type
) {
37 return FirefoxProxySettings::MANUAL
;
39 return FirefoxProxySettings::AUTO_FROM_URL
;
41 return FirefoxProxySettings::AUTO_DETECT
;
43 return FirefoxProxySettings::SYSTEM
;
45 LOG(ERROR
) << "Unknown Firefox proxy config type: " << type
;
46 return FirefoxProxySettings::NO_PROXY
;
50 FirefoxProxySettings::SOCKSVersion
IntToSOCKSVersion(int type
) {
53 return FirefoxProxySettings::V4
;
55 return FirefoxProxySettings::V5
;
57 LOG(ERROR
) << "Unknown Firefox proxy config type: " << type
;
58 return FirefoxProxySettings::UNKNONW
;
62 // Parses the prefs found in the file |pref_file| and puts the key/value pairs
63 // in |prefs|. Keys are strings, and values can be strings, booleans or
64 // integers. Returns true if it succeeded, false otherwise (in which case
65 // |prefs| is not filled).
66 // Note: for strings, only valid UTF-8 string values are supported. If a
67 // key/pair is not valid UTF-8, it is ignored and will not appear in |prefs|.
68 bool ParsePrefFile(const base::FilePath
& pref_file
,
69 base::DictionaryValue
* prefs
) {
70 // The string that is before a pref key.
71 const std::string kUserPrefString
= "user_pref(\"";
73 if (!base::ReadFileToString(pref_file
, &contents
))
76 std::vector
<std::string
> lines
;
77 Tokenize(contents
, "\n", &lines
);
79 for (std::vector
<std::string
>::const_iterator iter
= lines
.begin();
80 iter
!= lines
.end(); ++iter
) {
81 const std::string
& line
= *iter
;
82 size_t start_key
= line
.find(kUserPrefString
);
83 if (start_key
== std::string::npos
)
84 continue; // Could be a comment or a blank line.
85 start_key
+= kUserPrefString
.length();
86 size_t stop_key
= line
.find('"', start_key
);
87 if (stop_key
== std::string::npos
) {
88 LOG(ERROR
) << "Invalid key found in Firefox pref file '" <<
89 pref_file
.value() << "' line is '" << line
<< "'.";
92 std::string key
= line
.substr(start_key
, stop_key
- start_key
);
93 size_t start_value
= line
.find(',', stop_key
+ 1);
94 if (start_value
== std::string::npos
) {
95 LOG(ERROR
) << "Invalid value found in Firefox pref file '" <<
96 pref_file
.value() << "' line is '" << line
<< "'.";
99 size_t stop_value
= line
.find(");", start_value
+ 1);
100 if (stop_value
== std::string::npos
) {
101 LOG(ERROR
) << "Invalid value found in Firefox pref file '" <<
102 pref_file
.value() << "' line is '" << line
<< "'.";
105 std::string value
= line
.substr(start_value
+ 1,
106 stop_value
- start_value
- 1);
107 base::TrimWhitespace(value
, base::TRIM_ALL
, &value
);
108 // Value could be a boolean.
109 bool is_value_true
= LowerCaseEqualsASCII(value
, "true");
110 if (is_value_true
|| LowerCaseEqualsASCII(value
, "false")) {
111 prefs
->SetBoolean(key
, is_value_true
);
115 // Value could be a string.
116 if (value
.size() >= 2U &&
117 value
[0] == '"' && value
[value
.size() - 1] == '"') {
118 value
= value
.substr(1, value
.size() - 2);
119 // ValueString only accept valid UTF-8. Simply ignore that entry if it is
121 if (base::IsStringUTF8(value
))
122 prefs
->SetString(key
, value
);
124 VLOG(1) << "Non UTF8 value for key " << key
<< ", ignored.";
128 // Or value could be an integer.
130 if (base::StringToInt(value
, &int_value
)) {
131 prefs
->SetInteger(key
, int_value
);
135 LOG(ERROR
) << "Invalid value found in Firefox pref file '"
136 << pref_file
.value() << "' value is '" << value
<< "'.";
143 FirefoxProxySettings::FirefoxProxySettings() {
147 FirefoxProxySettings::~FirefoxProxySettings() {
150 void FirefoxProxySettings::Reset() {
151 config_type_
= NO_PROXY
;
153 http_proxy_port_
= 0;
158 gopher_proxy_
.clear();
159 gopher_proxy_port_
= 0;
162 socks_version_
= UNKNONW
;
163 proxy_bypass_list_
.clear();
164 autoconfig_url_
.clear();
168 bool FirefoxProxySettings::GetSettings(FirefoxProxySettings
* settings
) {
172 base::FilePath profile_path
= GetFirefoxProfilePath();
173 if (profile_path
.empty())
175 base::FilePath pref_file
= profile_path
.AppendASCII(kPrefFileName
);
176 return GetSettingsFromFile(pref_file
, settings
);
179 bool FirefoxProxySettings::ToProxyConfig(net::ProxyConfig
* config
) {
180 switch (config_type()) {
182 *config
= net::ProxyConfig::CreateDirect();
185 *config
= net::ProxyConfig::CreateAutoDetect();
188 *config
= net::ProxyConfig::CreateFromCustomPacURL(
189 GURL(autoconfig_url()));
192 // Can't convert this directly to a ProxyConfig.
195 // Handled outside of the switch (since it is a lot of code.)
202 // The rest of this funciton is for handling the MANUAL case.
203 DCHECK_EQ(MANUAL
, config_type());
205 *config
= net::ProxyConfig();
206 config
->proxy_rules().type
=
207 net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME
;
209 if (!http_proxy().empty()) {
210 config
->proxy_rules().proxies_for_http
.SetSingleProxyServer(
212 net::ProxyServer::SCHEME_HTTP
,
213 net::HostPortPair(http_proxy(), http_proxy_port())));
216 if (!ftp_proxy().empty()) {
217 config
->proxy_rules().proxies_for_ftp
.SetSingleProxyServer(
219 net::ProxyServer::SCHEME_HTTP
,
220 net::HostPortPair(ftp_proxy(), ftp_proxy_port())));
223 if (!ssl_proxy().empty()) {
224 config
->proxy_rules().proxies_for_https
.SetSingleProxyServer(
226 net::ProxyServer::SCHEME_HTTP
,
227 net::HostPortPair(ssl_proxy(), ssl_proxy_port())));
230 if (!socks_host().empty()) {
231 net::ProxyServer::Scheme proxy_scheme
= V5
== socks_version() ?
232 net::ProxyServer::SCHEME_SOCKS5
: net::ProxyServer::SCHEME_SOCKS4
;
234 config
->proxy_rules().fallback_proxies
.SetSingleProxyServer(
237 net::HostPortPair(socks_host(), socks_port())));
240 config
->proxy_rules().bypass_rules
.ParseFromStringUsingSuffixMatching(
241 JoinString(proxy_bypass_list_
, ';'));
247 bool FirefoxProxySettings::GetSettingsFromFile(const base::FilePath
& pref_file
,
248 FirefoxProxySettings
* settings
) {
249 base::DictionaryValue dictionary
;
250 if (!ParsePrefFile(pref_file
, &dictionary
))
254 if (!dictionary
.GetInteger(kNetworkProxyTypeKey
, &proxy_type
))
255 return true; // No type means no proxy.
257 settings
->config_type_
= IntToProxyConfig(proxy_type
);
258 if (settings
->config_type_
== AUTO_FROM_URL
) {
259 if (!dictionary
.GetStringASCII(kAutoconfigURL
,
260 &(settings
->autoconfig_url_
))) {
261 LOG(ERROR
) << "Failed to retrieve Firefox proxy autoconfig URL";
266 if (settings
->config_type_
== MANUAL
) {
267 if (!dictionary
.GetStringASCII(kHTTPProxyKey
, &(settings
->http_proxy_
)))
268 LOG(ERROR
) << "Failed to retrieve Firefox proxy HTTP host";
269 if (!dictionary
.GetInteger(kHTTPProxyPortKey
,
270 &(settings
->http_proxy_port_
))) {
271 LOG(ERROR
) << "Failed to retrieve Firefox proxy HTTP port";
273 if (!dictionary
.GetStringASCII(kSSLProxyKey
, &(settings
->ssl_proxy_
)))
274 LOG(ERROR
) << "Failed to retrieve Firefox proxy SSL host";
275 if (!dictionary
.GetInteger(kSSLProxyPortKey
, &(settings
->ssl_proxy_port_
)))
276 LOG(ERROR
) << "Failed to retrieve Firefox proxy SSL port";
277 if (!dictionary
.GetStringASCII(kFTPProxyKey
, &(settings
->ftp_proxy_
)))
278 LOG(ERROR
) << "Failed to retrieve Firefox proxy FTP host";
279 if (!dictionary
.GetInteger(kFTPProxyPortKey
, &(settings
->ftp_proxy_port_
)))
280 LOG(ERROR
) << "Failed to retrieve Firefox proxy SSL port";
281 if (!dictionary
.GetStringASCII(kGopherProxyKey
, &(settings
->gopher_proxy_
)))
282 LOG(ERROR
) << "Failed to retrieve Firefox proxy gopher host";
283 if (!dictionary
.GetInteger(kGopherProxyPortKey
,
284 &(settings
->gopher_proxy_port_
))) {
285 LOG(ERROR
) << "Failed to retrieve Firefox proxy gopher port";
287 if (!dictionary
.GetStringASCII(kSOCKSHostKey
, &(settings
->socks_host_
)))
288 LOG(ERROR
) << "Failed to retrieve Firefox SOCKS host";
289 if (!dictionary
.GetInteger(kSOCKSHostPortKey
, &(settings
->socks_port_
)))
290 LOG(ERROR
) << "Failed to retrieve Firefox SOCKS port";
292 if (dictionary
.GetInteger(kSOCKSVersionKey
, &socks_version
))
293 settings
->socks_version_
= IntToSOCKSVersion(socks_version
);
295 std::string proxy_bypass
;
296 if (dictionary
.GetStringASCII(kNoProxyListKey
, &proxy_bypass
) &&
297 !proxy_bypass
.empty()) {
298 base::StringTokenizer
string_tok(proxy_bypass
, ",");
299 while (string_tok
.GetNext()) {
300 std::string token
= string_tok
.token();
301 base::TrimWhitespaceASCII(token
, base::TRIM_ALL
, &token
);
303 settings
->proxy_bypass_list_
.push_back(token
);