[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 1 | // Copyright 2013 The Chromium Authors. All rights reserved. |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 5 | #include "chrome/browser/net/firefox_proxy_settings.h" |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 6 | |
[email protected] | 5799981 | 2013-02-24 05:40:52 | [diff] [blame] | 7 | #include "base/files/file_path.h" |
thestig | 18dfb7a5 | 2014-08-26 10:44:04 | [diff] [blame] | 8 | #include "base/files/file_util.h" |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 9 | #include "base/strings/string_number_conversions.h" |
brettw | b45192d | 2015-06-29 22:53:24 | [diff] [blame^] | 10 | #include "base/strings/string_split.h" |
[email protected] | f4ebe77 | 2013-02-02 00:21:39 | [diff] [blame] | 11 | #include "base/strings/string_tokenizer.h" |
[email protected] | 9c7ddc9 | 2013-06-11 01:40:57 | [diff] [blame] | 12 | #include "base/strings/string_util.h" |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 13 | #include "base/values.h" |
[email protected] | 946b4ee0 | 2013-07-16 21:57:52 | [diff] [blame] | 14 | #include "chrome/common/importer/firefox_importer_utils.h" |
[email protected] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 15 | #include "net/proxy/proxy_config.h" |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 16 | |
| 17 | namespace { |
| 18 | |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 19 | const char* const kNetworkProxyTypeKey = "network.proxy.type"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 20 | const char* const kHTTPProxyKey = "network.proxy.http"; |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 21 | const char* const kHTTPProxyPortKey = "network.proxy.http_port"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 22 | const char* const kSSLProxyKey = "network.proxy.ssl"; |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 23 | const char* const kSSLProxyPortKey = "network.proxy.ssl_port"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 24 | const char* const kFTPProxyKey = "network.proxy.ftp"; |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 25 | const char* const kFTPProxyPortKey = "network.proxy.ftp_port"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 26 | const char* const kGopherProxyKey = "network.proxy.gopher"; |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 27 | const char* const kGopherProxyPortKey = "network.proxy.gopher_port"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 28 | const char* const kSOCKSHostKey = "network.proxy.socks"; |
[email protected] | a65175d | 2010-08-17 04:00:57 | [diff] [blame] | 29 | const char* const kSOCKSHostPortKey = "network.proxy.socks_port"; |
| 30 | const char* const kSOCKSVersionKey = "network.proxy.socks_version"; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 31 | const char* const kAutoconfigURL = "network.proxy.autoconfig_url"; |
| 32 | const char* const kNoProxyListKey = "network.proxy.no_proxies_on"; |
| 33 | const char* const kPrefFileName = "prefs.js"; |
| 34 | |
| 35 | FirefoxProxySettings::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 | |
| 51 | FirefoxProxySettings::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] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 63 | // 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] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 69 | bool ParsePrefFile(const base::FilePath& pref_file, |
| 70 | base::DictionaryValue* prefs) { |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 71 | // The string that is before a pref key. |
| 72 | const std::string kUserPrefString = "user_pref(\""; |
| 73 | std::string contents; |
[email protected] | 82f84b9 | 2013-08-30 18:23:50 | [diff] [blame] | 74 | if (!base::ReadFileToString(pref_file, &contents)) |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 75 | return false; |
| 76 | |
brettw | b45192d | 2015-06-29 22:53:24 | [diff] [blame^] | 77 | for (const std::string& line : |
| 78 | base::SplitString(contents, "\n", base::KEEP_WHITESPACE, |
| 79 | base::SPLIT_WANT_NONEMPTY)) { |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 80 | 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] | 8af69c6c | 2014-03-03 19:05:31 | [diff] [blame] | 105 | base::TrimWhitespace(value, base::TRIM_ALL, &value); |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 106 | // Value could be a boolean. |
brettw | bc17d2c8 | 2015-06-09 22:39:08 | [diff] [blame] | 107 | bool is_value_true = base::LowerCaseEqualsASCII(value, "true"); |
| 108 | if (is_value_true || base::LowerCaseEqualsASCII(value, "false")) { |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 109 | 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] | 52796541 | 2014-05-07 14:38:26 | [diff] [blame] | 119 | if (base::IsStringUTF8(value)) |
[email protected] | c8ead276 | 2013-07-23 15:57:25 | [diff] [blame] | 120 | 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] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 139 | } // namespace |
| 140 | |
| 141 | FirefoxProxySettings::FirefoxProxySettings() { |
| 142 | Reset(); |
| 143 | } |
| 144 | |
| 145 | FirefoxProxySettings::~FirefoxProxySettings() { |
| 146 | } |
| 147 | |
| 148 | void 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] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 166 | bool FirefoxProxySettings::GetSettings(FirefoxProxySettings* settings) { |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 167 | DCHECK(settings); |
| 168 | settings->Reset(); |
| 169 | |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 170 | base::FilePath profile_path = GetFirefoxProfilePath(); |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 171 | if (profile_path.empty()) |
| 172 | return false; |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 173 | base::FilePath pref_file = profile_path.AppendASCII(kPrefFileName); |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 174 | return GetSettingsFromFile(pref_file, settings); |
| 175 | } |
| 176 | |
[email protected] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 177 | bool 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] | 2189e09 | 2013-03-16 18:02:02 | [diff] [blame] | 208 | 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] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 212 | } |
| 213 | |
| 214 | if (!ftp_proxy().empty()) { |
[email protected] | 2189e09 | 2013-03-16 18:02:02 | [diff] [blame] | 215 | 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] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | if (!ssl_proxy().empty()) { |
[email protected] | 2189e09 | 2013-03-16 18:02:02 | [diff] [blame] | 222 | 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] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 226 | } |
| 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] | 2189e09 | 2013-03-16 18:02:02 | [diff] [blame] | 232 | config->proxy_rules().fallback_proxies.SetSingleProxyServer( |
| 233 | net::ProxyServer( |
| 234 | proxy_scheme, |
| 235 | net::HostPortPair(socks_host(), socks_port()))); |
[email protected] | 483bf12 | 2010-05-04 20:41:24 | [diff] [blame] | 236 | } |
| 237 | |
| 238 | config->proxy_rules().bypass_rules.ParseFromStringUsingSuffixMatching( |
| 239 | JoinString(proxy_bypass_list_, ';')); |
| 240 | |
| 241 | return true; |
| 242 | } |
| 243 | |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 244 | // static |
[email protected] | 650b2d5 | 2013-02-10 03:41:45 | [diff] [blame] | 245 | bool FirefoxProxySettings::GetSettingsFromFile(const base::FilePath& pref_file, |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 246 | FirefoxProxySettings* settings) { |
[email protected] | cb1078de | 2013-12-23 20:04:22 | [diff] [blame] | 247 | base::DictionaryValue dictionary; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 248 | 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] | acd8753 | 2010-05-13 22:28:10 | [diff] [blame] | 261 | return true; |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 262 | } |
| 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] | f4ebe77 | 2013-02-02 00:21:39 | [diff] [blame] | 296 | base::StringTokenizer string_tok(proxy_bypass, ","); |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 297 | while (string_tok.GetNext()) { |
| 298 | std::string token = string_tok.token(); |
[email protected] | 8af69c6c | 2014-03-03 19:05:31 | [diff] [blame] | 299 | base::TrimWhitespaceASCII(token, base::TRIM_ALL, &token); |
[email protected] | 4200a208 | 2010-04-27 23:19:47 | [diff] [blame] | 300 | if (!token.empty()) |
| 301 | settings->proxy_bypass_list_.push_back(token); |
| 302 | } |
| 303 | } |
| 304 | } |
| 305 | return true; |
| 306 | } |