Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include <windows.h>
7 #include <ras.h>
8 #include <wininet.h>
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Attributes.h"
12 #include "nsISystemProxySettings.h"
13 #include "nsIServiceManager.h"
14 #include "mozilla/ModuleUtils.h"
15 #include "nsPrintfCString.h"
16 #include "nsNetUtil.h"
17 #include "nsISupportsPrimitives.h"
18 #include "nsIURI.h"
20 class nsWindowsSystemProxySettings MOZ_FINAL : public nsISystemProxySettings
21 {
22 public:
23 NS_DECL_THREADSAFE_ISUPPORTS
24 NS_DECL_NSISYSTEMPROXYSETTINGS
26 nsWindowsSystemProxySettings() {};
27 nsresult Init();
29 private:
30 ~nsWindowsSystemProxySettings() {};
32 bool MatchOverride(const nsACString& aHost);
33 bool PatternMatch(const nsACString& aHost, const nsACString& aOverride);
34 };
36 NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings)
38 NS_IMETHODIMP
39 nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly)
40 {
41 *aMainThreadOnly = false;
42 return NS_OK;
43 }
46 nsresult
47 nsWindowsSystemProxySettings::Init()
48 {
49 return NS_OK;
50 }
52 static void SetProxyResult(const char* aType, const nsACString& aHostPort,
53 nsACString& aResult)
54 {
55 aResult.AssignASCII(aType);
56 aResult.Append(' ');
57 aResult.Append(aHostPort);
58 }
60 static void SetProxyResultDirect(nsACString& aResult)
61 {
62 // For whatever reason, a proxy is not to be used.
63 aResult.AssignASCII("DIRECT");
64 }
66 static nsresult ReadInternetOption(uint32_t aOption, uint32_t& aFlags,
67 nsAString& aValue)
68 {
69 DWORD connFlags = 0;
70 WCHAR connName[RAS_MaxEntryName + 1];
71 MOZ_SEH_TRY {
72 InternetGetConnectedStateExW(&connFlags, connName,
73 mozilla::ArrayLength(connName), 0);
74 } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
75 return NS_ERROR_FAILURE;
76 }
78 INTERNET_PER_CONN_OPTIONW options[2];
79 options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI;
80 options[1].dwOption = aOption;
82 INTERNET_PER_CONN_OPTION_LISTW list;
83 list.dwSize = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
84 list.pszConnection = connFlags & INTERNET_CONNECTION_MODEM ?
85 connName : nullptr;
86 list.dwOptionCount = mozilla::ArrayLength(options);
87 list.dwOptionError = 0;
88 list.pOptions = options;
90 unsigned long size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
91 if (!InternetQueryOptionW(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION,
92 &list, &size)) {
93 if (GetLastError() != ERROR_INVALID_PARAMETER) {
94 return NS_ERROR_FAILURE;
95 }
96 options[0].dwOption = INTERNET_PER_CONN_FLAGS;
97 size = sizeof(INTERNET_PER_CONN_OPTION_LISTW);
98 MOZ_SEH_TRY {
99 if (!InternetQueryOptionW(nullptr,
100 INTERNET_OPTION_PER_CONNECTION_OPTION,
101 &list, &size)) {
102 return NS_ERROR_FAILURE;
103 }
104 } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
105 return NS_ERROR_FAILURE;
106 }
107 }
109 aFlags = options[0].Value.dwValue;
110 aValue.Assign(options[1].Value.pszValue);
111 GlobalFree(options[1].Value.pszValue);
113 return NS_OK;
114 }
116 bool
117 nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost)
118 {
119 nsresult rv;
120 uint32_t flags = 0;
121 nsAutoString buf;
123 rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf);
124 if (NS_FAILED(rv))
125 return false;
127 NS_ConvertUTF16toUTF8 cbuf(buf);
129 nsAutoCString host(aHost);
130 int32_t start = 0;
131 int32_t end = cbuf.Length();
133 // Windows formats its proxy override list in the form:
134 // server;server;server where 'server' is a server name pattern or IP
135 // address, or "<local>". "<local>" must be translated to
136 // "localhost;127.0.0.1".
137 // In a server name pattern, a '*' character matches any substring and
138 // all other characters must match themselves; the whole pattern must match
139 // the whole hostname.
140 while (true) {
141 int32_t delimiter = cbuf.FindCharInSet(" ;", start);
142 if (delimiter == -1)
143 delimiter = end;
145 if (delimiter != start) {
146 const nsAutoCString override(Substring(cbuf, start,
147 delimiter - start));
148 if (override.EqualsLiteral("<local>")) {
149 // This override matches local addresses.
150 if (host.EqualsLiteral("localhost") ||
151 host.EqualsLiteral("127.0.0.1"))
152 return true;
153 } else if (PatternMatch(host, override)) {
154 return true;
155 }
156 }
158 if (delimiter == end)
159 break;
160 start = ++delimiter;
161 }
163 return false;
164 }
166 bool
167 nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost,
168 const nsACString& aOverride)
169 {
170 nsAutoCString host(aHost);
171 nsAutoCString override(aOverride);
172 int32_t overrideLength = override.Length();
173 int32_t tokenStart = 0;
174 int32_t offset = 0;
175 bool star = false;
177 while (tokenStart < overrideLength) {
178 int32_t tokenEnd = override.FindChar('*', tokenStart);
179 if (tokenEnd == tokenStart) {
180 star = true;
181 tokenStart++;
182 // If the character following the '*' is a '.' character then skip
183 // it so that "*.foo.com" allows "foo.com".
184 if (override.FindChar('.', tokenStart) == tokenStart)
185 tokenStart++;
186 } else {
187 if (tokenEnd == -1)
188 tokenEnd = overrideLength;
189 nsAutoCString token(Substring(override, tokenStart,
190 tokenEnd - tokenStart));
191 offset = host.Find(token, offset);
192 if (offset == -1 || (!star && offset))
193 return false;
194 star = false;
195 tokenStart = tokenEnd;
196 offset += token.Length();
197 }
198 }
200 return (star || (offset == host.Length()));
201 }
203 nsresult
204 nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult)
205 {
206 nsresult rv;
207 uint32_t flags = 0;
208 nsAutoString buf;
210 rv = ReadInternetOption(INTERNET_PER_CONN_AUTOCONFIG_URL, flags, buf);
211 if (!(flags & PROXY_TYPE_AUTO_PROXY_URL)) {
212 aResult.Truncate();
213 return rv;
214 }
216 if (NS_SUCCEEDED(rv))
217 aResult = NS_ConvertUTF16toUTF8(buf);
218 return rv;
219 }
221 nsresult
222 nsWindowsSystemProxySettings::GetProxyForURI(const nsACString & aSpec,
223 const nsACString & aScheme,
224 const nsACString & aHost,
225 const int32_t aPort,
226 nsACString & aResult)
227 {
228 nsresult rv;
229 uint32_t flags = 0;
230 nsAutoString buf;
232 rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_SERVER, flags, buf);
233 if (NS_FAILED(rv) || !(flags & PROXY_TYPE_PROXY)) {
234 SetProxyResultDirect(aResult);
235 return NS_OK;
236 }
238 if (MatchOverride(aHost)) {
239 SetProxyResultDirect(aResult);
240 return NS_OK;
241 }
243 NS_ConvertUTF16toUTF8 cbuf(buf);
245 nsAutoCString prefix;
246 ToLowerCase(aScheme, prefix);
248 prefix.Append('=');
250 nsAutoCString specificProxy;
251 nsAutoCString defaultProxy;
252 nsAutoCString socksProxy;
253 int32_t start = 0;
254 int32_t end = cbuf.Length();
256 while (true) {
257 int32_t delimiter = cbuf.FindCharInSet(" ;", start);
258 if (delimiter == -1)
259 delimiter = end;
261 if (delimiter != start) {
262 const nsAutoCString proxy(Substring(cbuf, start,
263 delimiter - start));
264 if (proxy.FindChar('=') == -1) {
265 // If a proxy name is listed by itself, it is used as the
266 // default proxy for any protocols that do not have a specific
267 // proxy specified.
268 // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
269 defaultProxy = proxy;
270 } else if (proxy.Find(prefix) == 0) {
271 // To list a proxy for a specific protocol, the string must
272 // follow the format "<protocol>=<protocol>://<proxy_name>".
273 // (http://msdn.microsoft.com/en-us/library/aa383996%28VS.85%29.aspx)
274 specificProxy = Substring(proxy, prefix.Length());
275 break;
276 } else if (proxy.Find("socks=") == 0) {
277 // SOCKS proxy.
278 socksProxy = Substring(proxy, 5); // "socks=" length.
279 }
280 }
282 if (delimiter == end)
283 break;
284 start = ++delimiter;
285 }
287 if (!specificProxy.IsEmpty())
288 SetProxyResult("PROXY", specificProxy, aResult); // Protocol-specific proxy.
289 else if (!defaultProxy.IsEmpty())
290 SetProxyResult("PROXY", defaultProxy, aResult); // Default proxy.
291 else if (!socksProxy.IsEmpty())
292 SetProxyResult("SOCKS", socksProxy, aResult); // SOCKS proxy.
293 else
294 SetProxyResultDirect(aResult); // Direct connection.
296 return NS_OK;
297 }
299 #define NS_WINDOWSSYSTEMPROXYSERVICE_CID /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\
300 { 0x4e22d3ea, 0xaaa2, 0x436e, \
301 {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } }
303 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init)
304 NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID);
306 static const mozilla::Module::CIDEntry kSysProxyCIDs[] = {
307 { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, nullptr, nsWindowsSystemProxySettingsConstructor },
308 { nullptr }
309 };
311 static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = {
312 { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID },
313 { nullptr }
314 };
316 static const mozilla::Module kSysProxyModule = {
317 mozilla::Module::kVersion,
318 kSysProxyCIDs,
319 kSysProxyContracts
320 };
322 NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule;