|
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/. */ |
|
5 |
|
6 #include <windows.h> |
|
7 #include <ras.h> |
|
8 #include <wininet.h> |
|
9 |
|
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" |
|
19 |
|
20 class nsWindowsSystemProxySettings MOZ_FINAL : public nsISystemProxySettings |
|
21 { |
|
22 public: |
|
23 NS_DECL_THREADSAFE_ISUPPORTS |
|
24 NS_DECL_NSISYSTEMPROXYSETTINGS |
|
25 |
|
26 nsWindowsSystemProxySettings() {}; |
|
27 nsresult Init(); |
|
28 |
|
29 private: |
|
30 ~nsWindowsSystemProxySettings() {}; |
|
31 |
|
32 bool MatchOverride(const nsACString& aHost); |
|
33 bool PatternMatch(const nsACString& aHost, const nsACString& aOverride); |
|
34 }; |
|
35 |
|
36 NS_IMPL_ISUPPORTS(nsWindowsSystemProxySettings, nsISystemProxySettings) |
|
37 |
|
38 NS_IMETHODIMP |
|
39 nsWindowsSystemProxySettings::GetMainThreadOnly(bool *aMainThreadOnly) |
|
40 { |
|
41 *aMainThreadOnly = false; |
|
42 return NS_OK; |
|
43 } |
|
44 |
|
45 |
|
46 nsresult |
|
47 nsWindowsSystemProxySettings::Init() |
|
48 { |
|
49 return NS_OK; |
|
50 } |
|
51 |
|
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 } |
|
59 |
|
60 static void SetProxyResultDirect(nsACString& aResult) |
|
61 { |
|
62 // For whatever reason, a proxy is not to be used. |
|
63 aResult.AssignASCII("DIRECT"); |
|
64 } |
|
65 |
|
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 } |
|
77 |
|
78 INTERNET_PER_CONN_OPTIONW options[2]; |
|
79 options[0].dwOption = INTERNET_PER_CONN_FLAGS_UI; |
|
80 options[1].dwOption = aOption; |
|
81 |
|
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; |
|
89 |
|
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 } |
|
108 |
|
109 aFlags = options[0].Value.dwValue; |
|
110 aValue.Assign(options[1].Value.pszValue); |
|
111 GlobalFree(options[1].Value.pszValue); |
|
112 |
|
113 return NS_OK; |
|
114 } |
|
115 |
|
116 bool |
|
117 nsWindowsSystemProxySettings::MatchOverride(const nsACString& aHost) |
|
118 { |
|
119 nsresult rv; |
|
120 uint32_t flags = 0; |
|
121 nsAutoString buf; |
|
122 |
|
123 rv = ReadInternetOption(INTERNET_PER_CONN_PROXY_BYPASS, flags, buf); |
|
124 if (NS_FAILED(rv)) |
|
125 return false; |
|
126 |
|
127 NS_ConvertUTF16toUTF8 cbuf(buf); |
|
128 |
|
129 nsAutoCString host(aHost); |
|
130 int32_t start = 0; |
|
131 int32_t end = cbuf.Length(); |
|
132 |
|
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; |
|
144 |
|
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 } |
|
157 |
|
158 if (delimiter == end) |
|
159 break; |
|
160 start = ++delimiter; |
|
161 } |
|
162 |
|
163 return false; |
|
164 } |
|
165 |
|
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; |
|
176 |
|
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 } |
|
199 |
|
200 return (star || (offset == host.Length())); |
|
201 } |
|
202 |
|
203 nsresult |
|
204 nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult) |
|
205 { |
|
206 nsresult rv; |
|
207 uint32_t flags = 0; |
|
208 nsAutoString buf; |
|
209 |
|
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 } |
|
215 |
|
216 if (NS_SUCCEEDED(rv)) |
|
217 aResult = NS_ConvertUTF16toUTF8(buf); |
|
218 return rv; |
|
219 } |
|
220 |
|
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; |
|
231 |
|
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 } |
|
237 |
|
238 if (MatchOverride(aHost)) { |
|
239 SetProxyResultDirect(aResult); |
|
240 return NS_OK; |
|
241 } |
|
242 |
|
243 NS_ConvertUTF16toUTF8 cbuf(buf); |
|
244 |
|
245 nsAutoCString prefix; |
|
246 ToLowerCase(aScheme, prefix); |
|
247 |
|
248 prefix.Append('='); |
|
249 |
|
250 nsAutoCString specificProxy; |
|
251 nsAutoCString defaultProxy; |
|
252 nsAutoCString socksProxy; |
|
253 int32_t start = 0; |
|
254 int32_t end = cbuf.Length(); |
|
255 |
|
256 while (true) { |
|
257 int32_t delimiter = cbuf.FindCharInSet(" ;", start); |
|
258 if (delimiter == -1) |
|
259 delimiter = end; |
|
260 |
|
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 } |
|
281 |
|
282 if (delimiter == end) |
|
283 break; |
|
284 start = ++delimiter; |
|
285 } |
|
286 |
|
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. |
|
295 |
|
296 return NS_OK; |
|
297 } |
|
298 |
|
299 #define NS_WINDOWSSYSTEMPROXYSERVICE_CID /* 4e22d3ea-aaa2-436e-ada4-9247de57d367 */\ |
|
300 { 0x4e22d3ea, 0xaaa2, 0x436e, \ |
|
301 {0xad, 0xa4, 0x92, 0x47, 0xde, 0x57, 0xd3, 0x67 } } |
|
302 |
|
303 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsWindowsSystemProxySettings, Init) |
|
304 NS_DEFINE_NAMED_CID(NS_WINDOWSSYSTEMPROXYSERVICE_CID); |
|
305 |
|
306 static const mozilla::Module::CIDEntry kSysProxyCIDs[] = { |
|
307 { &kNS_WINDOWSSYSTEMPROXYSERVICE_CID, false, nullptr, nsWindowsSystemProxySettingsConstructor }, |
|
308 { nullptr } |
|
309 }; |
|
310 |
|
311 static const mozilla::Module::ContractIDEntry kSysProxyContracts[] = { |
|
312 { NS_SYSTEMPROXYSETTINGS_CONTRACTID, &kNS_WINDOWSSYSTEMPROXYSERVICE_CID }, |
|
313 { nullptr } |
|
314 }; |
|
315 |
|
316 static const mozilla::Module kSysProxyModule = { |
|
317 mozilla::Module::kVersion, |
|
318 kSysProxyCIDs, |
|
319 kSysProxyContracts |
|
320 }; |
|
321 |
|
322 NSMODULE_DEFN(nsWindowsProxyModule) = &kSysProxyModule; |