blob: 2b23e01d5ae1fb70156133334cc4b4b62d5e750d [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
[email protected]57999812013-02-24 05:40:527#include "base/files/file_path.h"
thestig18dfb7a52014-08-26 10:44:048#include "base/files/file_util.h"
[email protected]c8ead2762013-07-23 15:57:259#include "base/strings/string_number_conversions.h"
brettwb45192d2015-06-29 22:53:2410#include "base/strings/string_split.h"
[email protected]f4ebe772013-02-02 00:21:3911#include "base/strings/string_tokenizer.h"
[email protected]9c7ddc92013-06-11 01:40:5712#include "base/strings/string_util.h"
[email protected]4200a2082010-04-27 23:19:4713#include "base/values.h"
[email protected]946b4ee02013-07-16 21:57:5214#include "chrome/common/importer/firefox_importer_utils.h"
[email protected]483bf122010-05-04 20:41:2415#include "net/proxy/proxy_config.h"
[email protected]4200a2082010-04-27 23:19:4716
17namespace {
18
[email protected]a65175d2010-08-17 04:00:5719const char* const kNetworkProxyTypeKey = "network.proxy.type";
[email protected]4200a2082010-04-27 23:19:4720const char* const kHTTPProxyKey = "network.proxy.http";
[email protected]a65175d2010-08-17 04:00:5721const char* const kHTTPProxyPortKey = "network.proxy.http_port";
[email protected]4200a2082010-04-27 23:19:4722const char* const kSSLProxyKey = "network.proxy.ssl";
[email protected]a65175d2010-08-17 04:00:5723const char* const kSSLProxyPortKey = "network.proxy.ssl_port";
[email protected]4200a2082010-04-27 23:19:4724const char* const kFTPProxyKey = "network.proxy.ftp";
[email protected]a65175d2010-08-17 04:00:5725const char* const kFTPProxyPortKey = "network.proxy.ftp_port";
[email protected]4200a2082010-04-27 23:19:4726const char* const kGopherProxyKey = "network.proxy.gopher";
[email protected]a65175d2010-08-17 04:00:5727const char* const kGopherProxyPortKey = "network.proxy.gopher_port";
[email protected]4200a2082010-04-27 23:19:4728const char* const kSOCKSHostKey = "network.proxy.socks";
[email protected]a65175d2010-08-17 04:00:5729const char* const kSOCKSHostPortKey = "network.proxy.socks_port";
30const char* const kSOCKSVersionKey = "network.proxy.socks_version";
[email protected]4200a2082010-04-27 23:19:4731const char* const kAutoconfigURL = "network.proxy.autoconfig_url";
32const char* const kNoProxyListKey = "network.proxy.no_proxies_on";
33const char* const kPrefFileName = "prefs.js";
34
35FirefoxProxySettings::ProxyConfig IntToProxyConfig(int type) {
36 switch (type) {
37 case 1:
38 return FirefoxProxySettings::MANUAL;
39 case 2:
40 return FirefoxProxySettings::AUTO_FROM_URL;
41 case 4:
42 return FirefoxProxySettings::AUTO_DETECT;
43 case 5:
44 return FirefoxProxySettings::SYSTEM;
45 default:
46 LOG(ERROR) << "Unknown Firefox proxy config type: " << type;
47 return FirefoxProxySettings::NO_PROXY;
48 }
49}
50
51FirefoxProxySettings::SOCKSVersion IntToSOCKSVersion(int type) {
52 switch (type) {
53 case 4:
54 return FirefoxProxySettings::V4;
55 case 5:
56 return FirefoxProxySettings::V5;
57 default:
58 LOG(ERROR) << "Unknown Firefox proxy config type: " << type;
59 return FirefoxProxySettings::UNKNONW;
60 }
61}
62
[email protected]c8ead2762013-07-23 15:57:2563// Parses the prefs found in the file |pref_file| and puts the key/value pairs
64// in |prefs|. Keys are strings, and values can be strings, booleans or
65// integers. Returns true if it succeeded, false otherwise (in which case
66// |prefs| is not filled).
67// Note: for strings, only valid UTF-8 string values are supported. If a
68// key/pair is not valid UTF-8, it is ignored and will not appear in |prefs|.
[email protected]cb1078de2013-12-23 20:04:2269bool ParsePrefFile(const base::FilePath& pref_file,
70 base::DictionaryValue* prefs) {
[email protected]c8ead2762013-07-23 15:57:2571 // The string that is before a pref key.
72 const std::string kUserPrefString = "user_pref(\"";
73 std::string contents;
[email protected]82f84b92013-08-30 18:23:5074 if (!base::ReadFileToString(pref_file, &contents))
[email protected]c8ead2762013-07-23 15:57:2575 return false;
76
brettwb45192d2015-06-29 22:53:2477 for (const std::string& line :
78 base::SplitString(contents, "\n", base::KEEP_WHITESPACE,
79 base::SPLIT_WANT_NONEMPTY)) {
[email protected]c8ead2762013-07-23 15:57:2580 size_t start_key = line.find(kUserPrefString);
81 if (start_key == std::string::npos)
82 continue; // Could be a comment or a blank line.
83 start_key += kUserPrefString.length();
84 size_t stop_key = line.find('"', start_key);
85 if (stop_key == std::string::npos) {
86 LOG(ERROR) << "Invalid key found in Firefox pref file '" <<
87 pref_file.value() << "' line is '" << line << "'.";
88 continue;
89 }
90 std::string key = line.substr(start_key, stop_key - start_key);
91 size_t start_value = line.find(',', stop_key + 1);
92 if (start_value == std::string::npos) {
93 LOG(ERROR) << "Invalid value found in Firefox pref file '" <<
94 pref_file.value() << "' line is '" << line << "'.";
95 continue;
96 }
97 size_t stop_value = line.find(");", start_value + 1);
98 if (stop_value == std::string::npos) {
99 LOG(ERROR) << "Invalid value found in Firefox pref file '" <<
100 pref_file.value() << "' line is '" << line << "'.";
101 continue;
102 }
103 std::string value = line.substr(start_value + 1,
104 stop_value - start_value - 1);
[email protected]8af69c6c2014-03-03 19:05:31105 base::TrimWhitespace(value, base::TRIM_ALL, &value);
[email protected]c8ead2762013-07-23 15:57:25106 // Value could be a boolean.
brettwbc17d2c82015-06-09 22:39:08107 bool is_value_true = base::LowerCaseEqualsASCII(value, "true");
108 if (is_value_true || base::LowerCaseEqualsASCII(value, "false")) {
[email protected]c8ead2762013-07-23 15:57:25109 prefs->SetBoolean(key, is_value_true);
110 continue;
111 }
112
113 // Value could be a string.
114 if (value.size() >= 2U &&
115 value[0] == '"' && value[value.size() - 1] == '"') {
116 value = value.substr(1, value.size() - 2);
117 // ValueString only accept valid UTF-8. Simply ignore that entry if it is
118 // not UTF-8.
[email protected]527965412014-05-07 14:38:26119 if (base::IsStringUTF8(value))
[email protected]c8ead2762013-07-23 15:57:25120 prefs->SetString(key, value);
121 else
122 VLOG(1) << "Non UTF8 value for key " << key << ", ignored.";
123 continue;
124 }
125
126 // Or value could be an integer.
127 int int_value = 0;
128 if (base::StringToInt(value, &int_value)) {
129 prefs->SetInteger(key, int_value);
130 continue;
131 }
132
133 LOG(ERROR) << "Invalid value found in Firefox pref file '"
134 << pref_file.value() << "' value is '" << value << "'.";
135 }
136 return true;
137}
138
[email protected]4200a2082010-04-27 23:19:47139} // namespace
140
141FirefoxProxySettings::FirefoxProxySettings() {
142 Reset();
143}
144
145FirefoxProxySettings::~FirefoxProxySettings() {
146}
147
148void FirefoxProxySettings::Reset() {
149 config_type_ = NO_PROXY;
150 http_proxy_.clear();
151 http_proxy_port_ = 0;
152 ssl_proxy_.clear();
153 ssl_proxy_port_ = 0;
154 ftp_proxy_.clear();
155 ftp_proxy_port_ = 0;
156 gopher_proxy_.clear();
157 gopher_proxy_port_ = 0;
158 socks_host_.clear();
159 socks_port_ = 0;
160 socks_version_ = UNKNONW;
161 proxy_bypass_list_.clear();
162 autoconfig_url_.clear();
163}
164
165// static
[email protected]483bf122010-05-04 20:41:24166bool FirefoxProxySettings::GetSettings(FirefoxProxySettings* settings) {
[email protected]4200a2082010-04-27 23:19:47167 DCHECK(settings);
168 settings->Reset();
169
[email protected]650b2d52013-02-10 03:41:45170 base::FilePath profile_path = GetFirefoxProfilePath();
[email protected]4200a2082010-04-27 23:19:47171 if (profile_path.empty())
172 return false;
[email protected]650b2d52013-02-10 03:41:45173 base::FilePath pref_file = profile_path.AppendASCII(kPrefFileName);
[email protected]4200a2082010-04-27 23:19:47174 return GetSettingsFromFile(pref_file, settings);
175}
176
[email protected]483bf122010-05-04 20:41:24177bool FirefoxProxySettings::ToProxyConfig(net::ProxyConfig* config) {
178 switch (config_type()) {
179 case NO_PROXY:
180 *config = net::ProxyConfig::CreateDirect();
181 return true;
182 case AUTO_DETECT:
183 *config = net::ProxyConfig::CreateAutoDetect();
184 return true;
185 case AUTO_FROM_URL:
186 *config = net::ProxyConfig::CreateFromCustomPacURL(
187 GURL(autoconfig_url()));
188 return true;
189 case SYSTEM:
190 // Can't convert this directly to a ProxyConfig.
191 return false;
192 case MANUAL:
193 // Handled outside of the switch (since it is a lot of code.)
194 break;
195 default:
196 NOTREACHED();
197 return false;
198 }
199
200 // The rest of this funciton is for handling the MANUAL case.
201 DCHECK_EQ(MANUAL, config_type());
202
203 *config = net::ProxyConfig();
204 config->proxy_rules().type =
205 net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
206
207 if (!http_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02208 config->proxy_rules().proxies_for_http.SetSingleProxyServer(
209 net::ProxyServer(
210 net::ProxyServer::SCHEME_HTTP,
211 net::HostPortPair(http_proxy(), http_proxy_port())));
[email protected]483bf122010-05-04 20:41:24212 }
213
214 if (!ftp_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02215 config->proxy_rules().proxies_for_ftp.SetSingleProxyServer(
216 net::ProxyServer(
217 net::ProxyServer::SCHEME_HTTP,
218 net::HostPortPair(ftp_proxy(), ftp_proxy_port())));
[email protected]483bf122010-05-04 20:41:24219 }
220
221 if (!ssl_proxy().empty()) {
[email protected]2189e092013-03-16 18:02:02222 config->proxy_rules().proxies_for_https.SetSingleProxyServer(
223 net::ProxyServer(
224 net::ProxyServer::SCHEME_HTTP,
225 net::HostPortPair(ssl_proxy(), ssl_proxy_port())));
[email protected]483bf122010-05-04 20:41:24226 }
227
228 if (!socks_host().empty()) {
229 net::ProxyServer::Scheme proxy_scheme = V5 == socks_version() ?
230 net::ProxyServer::SCHEME_SOCKS5 : net::ProxyServer::SCHEME_SOCKS4;
231
[email protected]2189e092013-03-16 18:02:02232 config->proxy_rules().fallback_proxies.SetSingleProxyServer(
233 net::ProxyServer(
234 proxy_scheme,
235 net::HostPortPair(socks_host(), socks_port())));
[email protected]483bf122010-05-04 20:41:24236 }
237
238 config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching(
239 JoinString(proxy_bypass_list_, ';'));
240
241 return true;
242}
243
[email protected]4200a2082010-04-27 23:19:47244// static
[email protected]650b2d52013-02-10 03:41:45245bool FirefoxProxySettings::GetSettingsFromFile(const base::FilePath& pref_file,
[email protected]4200a2082010-04-27 23:19:47246 FirefoxProxySettings* settings) {
[email protected]cb1078de2013-12-23 20:04:22247 base::DictionaryValue dictionary;
[email protected]4200a2082010-04-27 23:19:47248 if (!ParsePrefFile(pref_file, &dictionary))
249 return false;
250
251 int proxy_type = 0;
252 if (!dictionary.GetInteger(kNetworkProxyTypeKey, &proxy_type))
253 return true; // No type means no proxy.
254
255 settings->config_type_ = IntToProxyConfig(proxy_type);
256 if (settings->config_type_ == AUTO_FROM_URL) {
257 if (!dictionary.GetStringASCII(kAutoconfigURL,
258 &(settings->autoconfig_url_))) {
259 LOG(ERROR) << "Failed to retrieve Firefox proxy autoconfig URL";
260 }
[email protected]acd87532010-05-13 22:28:10261 return true;
[email protected]4200a2082010-04-27 23:19:47262 }
263
264 if (settings->config_type_ == MANUAL) {
265 if (!dictionary.GetStringASCII(kHTTPProxyKey, &(settings->http_proxy_)))
266 LOG(ERROR) << "Failed to retrieve Firefox proxy HTTP host";
267 if (!dictionary.GetInteger(kHTTPProxyPortKey,
268 &(settings->http_proxy_port_))) {
269 LOG(ERROR) << "Failed to retrieve Firefox proxy HTTP port";
270 }
271 if (!dictionary.GetStringASCII(kSSLProxyKey, &(settings->ssl_proxy_)))
272 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL host";
273 if (!dictionary.GetInteger(kSSLProxyPortKey, &(settings->ssl_proxy_port_)))
274 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL port";
275 if (!dictionary.GetStringASCII(kFTPProxyKey, &(settings->ftp_proxy_)))
276 LOG(ERROR) << "Failed to retrieve Firefox proxy FTP host";
277 if (!dictionary.GetInteger(kFTPProxyPortKey, &(settings->ftp_proxy_port_)))
278 LOG(ERROR) << "Failed to retrieve Firefox proxy SSL port";
279 if (!dictionary.GetStringASCII(kGopherProxyKey, &(settings->gopher_proxy_)))
280 LOG(ERROR) << "Failed to retrieve Firefox proxy gopher host";
281 if (!dictionary.GetInteger(kGopherProxyPortKey,
282 &(settings->gopher_proxy_port_))) {
283 LOG(ERROR) << "Failed to retrieve Firefox proxy gopher port";
284 }
285 if (!dictionary.GetStringASCII(kSOCKSHostKey, &(settings->socks_host_)))
286 LOG(ERROR) << "Failed to retrieve Firefox SOCKS host";
287 if (!dictionary.GetInteger(kSOCKSHostPortKey, &(settings->socks_port_)))
288 LOG(ERROR) << "Failed to retrieve Firefox SOCKS port";
289 int socks_version;
290 if (dictionary.GetInteger(kSOCKSVersionKey, &socks_version))
291 settings->socks_version_ = IntToSOCKSVersion(socks_version);
292
293 std::string proxy_bypass;
294 if (dictionary.GetStringASCII(kNoProxyListKey, &proxy_bypass) &&
295 !proxy_bypass.empty()) {
[email protected]f4ebe772013-02-02 00:21:39296 base::StringTokenizer string_tok(proxy_bypass, ",");
[email protected]4200a2082010-04-27 23:19:47297 while (string_tok.GetNext()) {
298 std::string token = string_tok.token();
[email protected]8af69c6c2014-03-03 19:05:31299 base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token);
[email protected]4200a2082010-04-27 23:19:47300 if (!token.empty())
301 settings->proxy_bypass_list_.push_back(token);
302 }
303 }
304 }
305 return true;
306}