blob: 59f217d20ba8861c05e0fcd92564688bef8ec829 [file] [log] [blame]
[email protected]c8ead2762013-07-23 15:57:251// Copyright 2013 The Chromium Authors. All rights reserved.
[email protected]4200a2082010-04-27 23:19:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]c8ead2762013-07-23 15:57:255#include "chrome/browser/net/firefox_proxy_settings.h"
[email protected]4200a2082010-04-27 23:19:476
avi6846aef2015-12-26 01:09:387#include <stddef.h>
8
[email protected]57999812013-02-24 05:40:529#include "base/files/file_path.h"
thestig18dfb7a52014-08-26 10:44:0410#include "base/files/file_util.h"
[email protected]c8ead2762013-07-23 15:57:2511#include "base/strings/string_number_conversions.h"
brettwb45192d2015-06-29 22:53:2412#include "base/strings/string_split.h"
[email protected]f4ebe772013-02-02 00:21:3913#include "base/strings/string_tokenizer.h"
[email protected]9c7ddc92013-06-11 01:40:5714#include "base/strings/string_util.h"
[email protected]4200a2082010-04-27 23:19:4715#include "base/values.h"
[email protected]946b4ee02013-07-16 21:57:5216#include "chrome/common/importer/firefox_importer_utils.h"
[email protected]483bf122010-05-04 20:41:2417#include "net/proxy/proxy_config.h"
[email protected]4200a2082010-04-27 23:19:4718
19namespace {
20
[email protected]a65175d2010-08-17 04:00:5721const char* const kNetworkProxyTypeKey = "network.proxy.type";
[email protected]4200a2082010-04-27 23:19:4722const char* const kHTTPProxyKey = "network.proxy.http";
[email protected]a65175d2010-08-17 04:00:5723const char* const kHTTPProxyPortKey = "network.proxy.http_port";
[email protected]4200a2082010-04-27 23:19:4724const char* const kSSLProxyKey = "network.proxy.ssl";
[email protected]a65175d2010-08-17 04:00:5725const char* const kSSLProxyPortKey = "network.proxy.ssl_port";
[email protected]4200a2082010-04-27 23:19:4726const char* const kFTPProxyKey = "network.proxy.ftp";
[email protected]a65175d2010-08-17 04:00:5727const char* const kFTPProxyPortKey = "network.proxy.ftp_port";
[email protected]4200a2082010-04-27 23:19:4728const char* const kGopherProxyKey = "network.proxy.gopher";
[email protected]a65175d2010-08-17 04:00:5729const char* const kGopherProxyPortKey = "network.proxy.gopher_port";
[email protected]4200a2082010-04-27 23:19:4730const char* const kSOCKSHostKey = "network.proxy.socks";
[email protected]a65175d2010-08-17 04:00:5731const char* const kSOCKSHostPortKey = "network.proxy.socks_port";
32const char* const kSOCKSVersionKey = "network.proxy.socks_version";
[email protected]4200a2082010-04-27 23:19:4733const char* const kAutoconfigURL = "network.proxy.autoconfig_url";
34const char* const kNoProxyListKey = "network.proxy.no_proxies_on";
35const char* const kPrefFileName = "prefs.js";
36
37FirefoxProxySettings::ProxyConfig IntToProxyConfig(int type) {
38 switch (type) {
39 case 1:
40 return FirefoxProxySettings::MANUAL;
41 case 2:
42 return FirefoxProxySettings::AUTO_FROM_URL;
43 case 4:
44 return FirefoxProxySettings::AUTO_DETECT;
45 case 5:
46 return FirefoxProxySettings::SYSTEM;
47 default:
48 LOG(ERROR) << "Unknown Firefox proxy config type: " << type;
49 return FirefoxProxySettings::NO_PROXY;
50 }
51}
52
53FirefoxProxySettings::SOCKSVersion IntToSOCKSVersion(int type) {
54 switch (type) {
55 case 4:
56 return FirefoxProxySettings::V4;
57 case 5:
58 return FirefoxProxySettings::V5;
59 default:
60 LOG(ERROR) << "Unknown Firefox proxy config type: " << type;
61 return FirefoxProxySettings::UNKNONW;
62 }
63}
64
[email protected]c8ead2762013-07-23 15:57:2565// Parses the prefs found in the file |pref_file| and puts the key/value pairs
66// in |prefs|. Keys are strings, and values can be strings, booleans or
67// integers. Returns true if it succeeded, false otherwise (in which case
68// |prefs| is not filled).
69// Note: for strings, only valid UTF-8 string values are supported. If a
70// key/pair is not valid UTF-8, it is ignored and will not appear in |prefs|.
[email protected]cb1078de2013-12-23 20:04:2271bool ParsePrefFile(const base::FilePath& pref_file,
72 base::DictionaryValue* prefs) {
[email protected]c8ead2762013-07-23 15:57:2573 // The string that is before a pref key.
74 const std::string kUserPrefString = "user_pref(\"";
75 std::string contents;
[email protected]82f84b92013-08-30 18:23:5076 if (!base::ReadFileToString(pref_file, &contents))
[email protected]c8ead2762013-07-23 15:57:2577 return false;
78
brettwb45192d2015-06-29 22:53:2479 for (const std::string& line :
80 base::SplitString(contents, "\n", base::KEEP_WHITESPACE,
81 base::SPLIT_WANT_NONEMPTY)) {
[email protected]c8ead2762013-07-23 15:57:2582 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 << "'.";
90 continue;
91 }
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 << "'.";
97 continue;
98 }
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 << "'.";
103 continue;
104 }
105 std::string value = line.substr(start_value + 1,
106 stop_value - start_value - 1);
tfarina023b1dcc2015-12-06 13:25:41107 base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
[email protected]c8ead2762013-07-23 15:57:25108 // Value could be a boolean.
brettwbc17d2c82015-06-09 22:39:08109 bool is_value_true = base::LowerCaseEqualsASCII(value, "true");
110 if (is_value_true || base::LowerCaseEqualsASCII(value, "false")) {
[email protected]c8ead2762013-07-23 15:57:25111 prefs->SetBoolean(key, is_value_true);
112 continue;
113 }
114
115 // Value could be a string.
thestig84abdbb72016-07-08 01:41:06116 if (value.size() >= 2U && value[0] == '"' && value.back() == '"') {
[email protected]c8ead2762013-07-23 15:57:25117 value = value.substr(1, value.size() - 2);
118 // ValueString only accept valid UTF-8. Simply ignore that entry if it is
119 // not UTF-8.
[email protected]527965412014-05-07 14:38:26120 if (base::IsStringUTF8(value))
[email protected]c8ead2762013-07-23 15:57:25121 prefs->SetString(key, value);
122 else
123 VLOG(1) << "Non UTF8 value for key " << key << ", ignored.";
124 continue;
125 }
126
127 // Or value could be an integer.
128 int int_value = 0;
129 if (base::StringToInt(value, &int_value)) {
130 prefs->SetInteger(key, int_value);
131 continue;
132 }
133
134 LOG(ERROR) << "Invalid value found in Firefox pref file '"
135 << pref_file.value() << "' value is '" << value << "'.";
136 }
137 return true;
138}
139
[email protected]4200a2082010-04-27 23:19:47140} // namespace
141
142FirefoxProxySettings::FirefoxProxySettings() {
143 Reset();
144}
145
146FirefoxProxySettings::~FirefoxProxySettings() {
147}
148
149void FirefoxProxySettings::Reset() {
150 config_type_ = NO_PROXY;
151 http_proxy_.clear();
152 http_proxy_port_ = 0;
153 ssl_proxy_.clear();
154 ssl_proxy_port_ = 0;
155 ftp_proxy_.clear();
156 ftp_proxy_port_ = 0;
157 gopher_proxy_.clear();
158 gopher_proxy_port_ = 0;
159 socks_host_.clear();
160 socks_port_ = 0;
161 socks_version_ = UNKNONW;
162 proxy_bypass_list_.clear();
163 autoconfig_url_.clear();
164}
165
166// static
[email protected]483bf122010-05-04 20:41:24167bool FirefoxProxySettings::GetSettings(FirefoxProxySettings* settings) {
[email protected]4200a2082010-04-27 23:19:47168 DCHECK(settings);
169 settings->Reset();
170
[email protected]650b2d52013-02-10 03:41:45171 base::FilePath profile_path = GetFirefoxProfilePath();
[email protected]4200a2082010-04-27 23:19:47172 if (profile_path.empty())
173 return false;
[email protected]650b2d52013-02-10 03:41:45174 base::FilePath pref_file = profile_path.AppendASCII(kPrefFileName);
[email protected]4200a2082010-04-27 23:19:47175 return GetSettingsFromFile(pref_file, settings);
176}
177
[email protected]483bf122010-05-04 20:41:24178bool FirefoxProxySettings::ToProxyConfig(net::ProxyConfig* config) {
179 switch (config_type()) {
180 case NO_PROXY:
181 *config = net::ProxyConfig::CreateDirect();
182 return true;
183 case AUTO_DETECT:
184 *config = net::ProxyConfig::CreateAutoDetect();
185 return true;
186 case AUTO_FROM_URL:
187 *config = net::ProxyConfig::CreateFromCustomPacURL(
188 GURL(autoconfig_url()));
189 return true;
190 case SYSTEM:
191 // Can't convert this directly to a ProxyConfig.
192 return false;
193 case MANUAL:
194 // Handled outside of the switch (since it is a lot of code.)
195 break;
196 default:
197 NOTREACHED();
198 return false;
199 }
200
201 // The rest of this funciton is for handling the MANUAL case.
202 DCHECK_EQ(MANUAL, config_type());
203
204 *config = net::ProxyConfig();
205 config->proxy_rules().type =
206 net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
207
208 if (!http_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02209 config->proxy_rules().proxies_for_http.SetSingleProxyServer(
210 net::ProxyServer(
211 net::ProxyServer::SCHEME_HTTP,
212 net::HostPortPair(http_proxy(), http_proxy_port())));
[email protected]483bf122010-05-04 20:41:24213 }
214
215 if (!ftp_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02216 config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(
217 net::ProxyServer(
218 net::ProxyServer::SCHEME_HTTP,
219 net::HostPortPair(ftp_proxy(), ftp_proxy_port())));
[email protected]483bf122010-05-04 20:41:24220 }
221
222 if (!ssl_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02223 config->proxy_rules().proxies_for_https.SetSingleProxyServer(
224 net::ProxyServer(
225 net::ProxyServer::SCHEME_HTTP,
226 net::HostPortPair(ssl_proxy(), ssl_proxy_port())));
[email protected]483bf122010-05-04 20:41:24227 }
228
229 if (!socks_host().empty()) {
230 net::ProxyServer::Scheme proxy_scheme = V5 == socks_version() ?
231 net::ProxyServer::SCHEME_SOCKS5 : net::ProxyServer::SCHEME_SOCKS4;
232
[email protected]2189e092013-03-16 18:02:02233 config->proxy_rules().fallback_proxies.SetSingleProxyServer(
234 net::ProxyServer(
235 proxy_scheme,
236 net::HostPortPair(socks_host(), socks_port())));
[email protected]483bf122010-05-04 20:41:24237 }
238
239 config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
brettwd94a22142015-07-15 05:19:26240 base::JoinString(proxy_bypass_list_, ";"));
[email protected]483bf122010-05-04 20:41:24241
242 return true;
243}
244
[email protected]4200a2082010-04-27 23:19:47245// static
[email protected]650b2d52013-02-10 03:41:45246bool FirefoxProxySettings::GetSettingsFromFile(const base::FilePath& pref_file,
[email protected]4200a2082010-04-27 23:19:47247 FirefoxProxySettings* settings) {
[email protected]cb1078de2013-12-23 20:04:22248 base::DictionaryValue dictionary;
[email protected]4200a2082010-04-27 23:19:47249 if (!ParsePrefFile(pref_file, &dictionary))
250 return false;
251
252 int proxy_type = 0;
253 if (!dictionary.GetInteger(kNetworkProxyTypeKey, &proxy_type))
254 return true; // No type means no proxy.
255
256 settings->config_type_ = IntToProxyConfig(proxy_type);
257 if (settings->config_type_ == AUTO_FROM_URL) {
258 if (!dictionary.GetStringASCII(kAutoconfigURL,
259 &(settings->autoconfig_url_))) {
260 LOG(ERROR) << "Failed to retrieve Firefox proxy autoconfig URL";
261 }
[email protected]acd87532010-05-13 22:28:10262 return true;
[email protected]4200a2082010-04-27 23:19:47263 }
264
265 if (settings->config_type_ == MANUAL) {
266 if (!dictionary.GetStringASCII(kHTTPProxyKey, &(settings->http_proxy_)))
267 LOG(ERROR) << "Failed to retrieve Firefox proxy HTTP host";
268 if (!dictionary.GetInteger(kHTTPProxyPortKey,
269 &(settings->http_proxy_port_))) {
270 LOG(ERROR) << "Failed to retrieve Firefox proxy HTTP port";
271 }
272 if (!dictionary.GetStringASCII(kSSLProxyKey, &(settings->ssl_proxy_)))
273 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL host";
274 if (!dictionary.GetInteger(kSSLProxyPortKey, &(settings->ssl_proxy_port_)))
275 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL port";
276 if (!dictionary.GetStringASCII(kFTPProxyKey, &(settings->ftp_proxy_)))
277 LOG(ERROR) << "Failed to retrieve Firefox proxy FTP host";
278 if (!dictionary.GetInteger(kFTPProxyPortKey, &(settings->ftp_proxy_port_)))
279 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL port";
280 if (!dictionary.GetStringASCII(kGopherProxyKey, &(settings->gopher_proxy_)))
281 LOG(ERROR) << "Failed to retrieve Firefox proxy gopher host";
282 if (!dictionary.GetInteger(kGopherProxyPortKey,
283 &(settings->gopher_proxy_port_))) {
284 LOG(ERROR) << "Failed to retrieve Firefox proxy gopher port";
285 }
286 if (!dictionary.GetStringASCII(kSOCKSHostKey, &(settings->socks_host_)))
287 LOG(ERROR) << "Failed to retrieve Firefox SOCKS host";
288 if (!dictionary.GetInteger(kSOCKSHostPortKey, &(settings->socks_port_)))
289 LOG(ERROR) << "Failed to retrieve Firefox SOCKS port";
290 int socks_version;
291 if (dictionary.GetInteger(kSOCKSVersionKey, &socks_version))
292 settings->socks_version_ = IntToSOCKSVersion(socks_version);
293
294 std::string proxy_bypass;
295 if (dictionary.GetStringASCII(kNoProxyListKey, &proxy_bypass) &&
296 !proxy_bypass.empty()) {
[email protected]f4ebe772013-02-02 00:21:39297 base::StringTokenizer string_tok(proxy_bypass, ",");
[email protected]4200a2082010-04-27 23:19:47298 while (string_tok.GetNext()) {
299 std::string token = string_tok.token();
[email protected]8af69c6c2014-03-03 19:05:31300 base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token);
[email protected]4200a2082010-04-27 23:19:47301 if (!token.empty())
302 settings->proxy_bypass_list_.push_back(token);
303 }
304 }
305 }
306 return true;
307}