1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,322 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <windows.h> 1.10 +#include <ras.h> 1.11 +#include <wininet.h> 1.12 + 1.13 +#include "mozilla/ArrayUtils.h" 1.14 +#include "mozilla/Attributes.h" 1.15 +#include "nsISystemProxySettings.h" 1.16 +#include "nsIServiceManager.h" 1.17 +#include "mozilla/ModuleUtils.h" 1.18 +#include "nsPrintfCString.h" 1.19 +#include "nsNetUtil.h" 1.20 +#include "nsISupportsPrimitives.h" 1.21 +#include "nsIURI.h" 1.22 + 1.23 +class nsWindowsSystemProxySettings MOZ_FINAL : public nsISystemProxySettings 1.24 +{ 1.25 +public: 1.26 + NS_DECL_THREADSAFE_ISUPPORTS 1.27 + NS_DECL_NSISYSTEMPROXYSETTINGS 1.28 + 1.29 + nsWindowsSystemProxySettings() {}; 1.30 + nsresult Init(); 1.31 + 1.32 +private: 1.33 + ~nsWindowsSystemProxySettings() {}; 1.34 + 1.35 + bool MatchOverride(const nsACString& aHost); 1.36 + bool PatternMatch(const nsACString& aHost, const nsACString& aOverride); 1.37 +}; 1.38 + 1.39 +NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings) 1.40 + 1.41 +NS_IMETHODIMP 1.42 +nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) 1.43 +{ 1.44 + *aMainThreadOnly = false; 1.45 + return NS_OK; 1.46 +} 1.47 + 1.48 + 1.49 +nsresult 1.50 +nsWindowsSystemProxySettings::Init() 1.51 +{ 1.52 + return NS_OK; 1.53 +} 1.54 + 1.55 +static void SetProxyResult(const char* aType, const nsACString& aHostPort, 1.56 + nsACString& aResult) 1.57 +{ 1.58 + aResult.AssignASCII(aType); 1.59 + aResult.Append(' '); 1.60 + aResult.Append(aHostPort); 1.61 +} 1.62 + 1.63 +static void SetProxyResultDirect(nsACString& aResult) 1.64 +{ 1.65 + // For whatever reason, a proxy is not to be used. 1.66 + aResult.AssignASCII("DIRECT"); 1.67 +} 1.68 + 1.69 +static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags, 1.70 + nsAString& aValue) 1.71 +{ 1.72 + DWORD connFlags = 0; 1.73 + WCHAR connName[RAS_MaxEntryName + 1]; 1.74 + MOZ_SEH_TRY { 1.75 + InternetGetConnectedStateExW(&connFlags, connName, 1.76 + mozilla::ArrayLength(connName), 0); 1.77 + } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1.78 + return NS_ERROR_FAILURE; 1.79 + } 1.80 + 1.81 + INTERNET_PER_CONN_OPTIONW options[2]; 1.82 + options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI; 1.83 + options[1].dwOption = aOption; 1.84 + 1.85 + INTERNET_PER_CONN_OPTION_LISTW list; 1.86 + list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW); 1.87 + list.pszConnection = connFlags & INTERNET_CONNECTION_MODEM ? 1.88 + connName : nullptr; 1.89 + list.dwOptionCount = mozilla::ArrayLength(options); 1.90 + list.dwOptionError = 0; 1.91 + list.pOptions = options; 1.92 + 1.93 + unsigned long size = sizeof(INTERNET_PER_CONN_OPTION_LISTW); 1.94 + if (!InternetQueryOptionW(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, 1.95 + &list, &size)) { 1.96 + if (GetLastError() != ERROR_INVALID_PARAMETER) { 1.97 + return NS_ERROR_FAILURE; 1.98 + } 1.99 + options[0].dwOption = INTERNET_PER_CONN_FLAGS; 1.100 + size = sizeof(INTERNET_PER_CONN_OPTION_LISTW); 1.101 + MOZ_SEH_TRY { 1.102 + if (!InternetQueryOptionW(nullptr, 1.103 + INTERNET_OPTION_PER_CONNECTION_OPTION, 1.104 + &list, &size)) { 1.105 + return NS_ERROR_FAILURE; 1.106 + } 1.107 + } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1.108 + return NS_ERROR_FAILURE; 1.109 + } 1.110 + } 1.111 + 1.112 + aFlags = options[0].Value.dwValue; 1.113 + aValue.Assign(options[1].Value.pszValue); 1.114 + GlobalFree(options[1].Value.pszValue); 1.115 + 1.116 + return NS_OK; 1.117 +} 1.118 + 1.119 +bool 1.120 +nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) 1.121 +{ 1.122 + nsresult rv; 1.123 + uint32_t flags = 0; 1.124 + nsAutoString buf; 1.125 + 1.126 + rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf); 1.127 + if (NS_FAILED(rv)) 1.128 + return false; 1.129 + 1.130 + NS_ConvertUTF16toUTF8 cbuf(buf); 1.131 + 1.132 + nsAutoCString host(aHost); 1.133 + int32_t start = 0; 1.134 + int32_t end = cbuf.Length(); 1.135 + 1.136 + // Windows formats its proxy override list in the form: 1.137 + // server;server;server where 'server' is a server name pattern or IP 1.138 + // address, or "<local>". "<local>" must be translated to 1.139 + // "localhost;127.0.0.1". 1.140 + // In a server name pattern, a '*' character matches any substring and 1.141 + // all other characters must match themselves; the whole pattern must match 1.142 + // the whole hostname. 1.143 + while (true) { 1.144 + int32_t delimiter = cbuf.FindCharInSet(" ;", start); 1.145 + if (delimiter == -1) 1.146 + delimiter = end; 1.147 + 1.148 + if (delimiter != start) { 1.149 + const nsAutoCString override(Substring(cbuf, start, 1.150 + delimiter - start)); 1.151 + if (override.EqualsLiteral("<local>")) { 1.152 + // This override matches local addresses. 1.153 + if (host.EqualsLiteral("localhost") || 1.154 + host.EqualsLiteral("127.0.0.1")) 1.155 + return true; 1.156 + } else if (PatternMatch(host, override)) { 1.157 + return true; 1.158 + } 1.159 + } 1.160 + 1.161 + if (delimiter == end) 1.162 + break; 1.163 + start = ++delimiter; 1.164 + } 1.165 + 1.166 + return false; 1.167 +} 1.168 + 1.169 +bool 1.170 +nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost, 1.171 + const nsACString& aOverride) 1.172 +{ 1.173 + nsAutoCString host(aHost); 1.174 + nsAutoCString override(aOverride); 1.175 + int32_t overrideLength = override.Length(); 1.176 + int32_t tokenStart = 0; 1.177 + int32_t offset = 0; 1.178 + bool star = false; 1.179 + 1.180 + while (tokenStart < overrideLength) { 1.181 + int32_t tokenEnd = override.FindChar('*', tokenStart); 1.182 + if (tokenEnd == tokenStart) { 1.183 + star = true; 1.184 + tokenStart++; 1.185 + // If the character following the '*' is a '.' character then skip 1.186 + // it so that "*.foo.com" allows "foo.com". 1.187 + if (override.FindChar('.', tokenStart) == tokenStart) 1.188 + tokenStart++; 1.189 + } else { 1.190 + if (tokenEnd == -1) 1.191 + tokenEnd = overrideLength; 1.192 + nsAutoCString token(Substring(override, tokenStart, 1.193 + tokenEnd - tokenStart)); 1.194 + offset = host.Find(token, offset); 1.195 + if (offset == -1 || (!star && offset)) 1.196 + return false; 1.197 + star = false; 1.198 + tokenStart = tokenEnd; 1.199 + offset += token.Length(); 1.200 + } 1.201 + } 1.202 + 1.203 + return (star || (offset == host.Length())); 1.204 +} 1.205 + 1.206 +nsresult 1.207 +nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult) 1.208 +{ 1.209 + nsresult rv; 1.210 + uint32_t flags = 0; 1.211 + nsAutoString buf; 1.212 + 1.213 + rv = ReadInternetOption(INTERNET_PER_CONN_AUTOCONFIG_URL, flags, buf); 1.214 + if (!(flags & PROXY_TYPE_AUTO_PROXY_URL)) { 1.215 + aResult.Truncate(); 1.216 + return rv; 1.217 + } 1.218 + 1.219 + if (NS_SUCCEEDED(rv)) 1.220 + aResult = NS_ConvertUTF16toUTF8(buf); 1.221 + return rv; 1.222 +} 1.223 + 1.224 +nsresult 1.225 +nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec, 1.226 + const nsACString & aScheme, 1.227 + const nsACString & aHost, 1.228 + const int32_t aPort, 1.229 + nsACString & aResult) 1.230 +{ 1.231 + nsresult rv; 1.232 + uint32_t flags = 0; 1.233 + nsAutoString buf; 1.234 + 1.235 + rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf); 1.236 + if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) { 1.237 + SetProxyResultDirect(aResult); 1.238 + return NS_OK; 1.239 + } 1.240 + 1.241 + if (MatchOverride(aHost)) { 1.242 + SetProxyResultDirect(aResult); 1.243 + return NS_OK; 1.244 + } 1.245 + 1.246 + NS_ConvertUTF16toUTF8 cbuf(buf); 1.247 + 1.248 + nsAutoCString prefix; 1.249 + ToLowerCase(aScheme, prefix); 1.250 + 1.251 + prefix.Append('='); 1.252 + 1.253 + nsAutoCString specificProxy; 1.254 + nsAutoCString defaultProxy; 1.255 + nsAutoCString socksProxy; 1.256 + int32_t start = 0; 1.257 + int32_t end = cbuf.Length(); 1.258 + 1.259 + while (true) { 1.260 + int32_t delimiter = cbuf.FindCharInSet(" ;", start); 1.261 + if (delimiter == -1) 1.262 + delimiter = end; 1.263 + 1.264 + if (delimiter != start) { 1.265 + const nsAutoCString proxy(Substring(cbuf, start, 1.266 + delimiter - start)); 1.267 + if (proxy.FindChar('=') == -1) { 1.268 + // If a proxy name is listed by itself, it is used as the 1.269 + // default proxy for any protocols that do not have a specific 1.270 + // proxy specified. 1.271 + // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx) 1.272 + defaultProxy = proxy; 1.273 + } else if (proxy.Find(prefix) == 0) { 1.274 + // To list a proxy for a specific protocol, the string must 1.275 + // follow the format "<protocol>=<protocol>://<proxy_name>". 1.276 + // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx) 1.277 + specificProxy = Substring(proxy, prefix.Length()); 1.278 + break; 1.279 + } else if (proxy.Find("socks=") == 0) { 1.280 + // SOCKS proxy. 1.281 + socksProxy = Substring(proxy, 5); // "socks=" length. 1.282 + } 1.283 + } 1.284 + 1.285 + if (delimiter == end) 1.286 + break; 1.287 + start = ++delimiter; 1.288 + } 1.289 + 1.290 + if (!specificProxy.IsEmpty()) 1.291 + SetProxyResult("PROXY", specificProxy, aResult); // Protocol-specific proxy. 1.292 + else if (!defaultProxy.IsEmpty()) 1.293 + SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy. 1.294 + else if (!socksProxy.IsEmpty()) 1.295 + SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy. 1.296 + else 1.297 + SetProxyResultDirect(aResult); // Direct connection. 1.298 + 1.299 + return NS_OK; 1.300 +} 1.301 + 1.302 +#define NS_WINDOWSSYSTEMPROXYSERVICE_CID /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\ 1.303 + { 0x4e22d3ea, 0xaaa2, 0x436e, \ 1.304 + {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } } 1.305 + 1.306 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init) 1.307 +NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID); 1.308 + 1.309 +static const mozilla::Module::CIDEntry kSysProxyCIDs[] = { 1.310 + { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, nullptr, nsWindowsSystemProxySettingsConstructor }, 1.311 + { nullptr } 1.312 +}; 1.313 + 1.314 +static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = { 1.315 + { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID }, 1.316 + { nullptr } 1.317 +}; 1.318 + 1.319 +static const mozilla::Module kSysProxyModule = { 1.320 + mozilla::Module::kVersion, 1.321 + kSysProxyCIDs, 1.322 + kSysProxyContracts 1.323 +}; 1.324 + 1.325 +NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule;