|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim:set ts=4 sw=4 sts=4 et: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "mozilla/ArrayUtils.h" |
|
8 #include "mozilla/Attributes.h" |
|
9 |
|
10 #include "nsProtocolProxyService.h" |
|
11 #include "nsProxyInfo.h" |
|
12 #include "nsIClassInfoImpl.h" |
|
13 #include "nsIIOService.h" |
|
14 #include "nsIObserverService.h" |
|
15 #include "nsIProtocolHandler.h" |
|
16 #include "nsIProtocolProxyCallback.h" |
|
17 #include "nsIChannel.h" |
|
18 #include "nsICancelable.h" |
|
19 #include "nsIDNSService.h" |
|
20 #include "nsPIDNSService.h" |
|
21 #include "nsIPrefService.h" |
|
22 #include "nsIPrefBranch.h" |
|
23 #include "nsThreadUtils.h" |
|
24 #include "nsString.h" |
|
25 #include "nsNetUtil.h" |
|
26 #include "nsNetCID.h" |
|
27 #include "prnetdb.h" |
|
28 #include "nsPACMan.h" |
|
29 #include "nsProxyRelease.h" |
|
30 #include "mozilla/Mutex.h" |
|
31 #include "mozilla/CondVar.h" |
|
32 #include "nsISystemProxySettings.h" |
|
33 |
|
34 //---------------------------------------------------------------------------- |
|
35 |
|
36 namespace mozilla { |
|
37 extern const char kProxyType_HTTP[]; |
|
38 extern const char kProxyType_SOCKS[]; |
|
39 extern const char kProxyType_SOCKS4[]; |
|
40 extern const char kProxyType_SOCKS5[]; |
|
41 extern const char kProxyType_DIRECT[]; |
|
42 } |
|
43 |
|
44 using namespace mozilla; |
|
45 |
|
46 #include "prlog.h" |
|
47 #if defined(PR_LOGGING) |
|
48 #endif |
|
49 #undef LOG |
|
50 #define LOG(args) PR_LOG(net::GetProxyLog(), PR_LOG_DEBUG, args) |
|
51 |
|
52 //---------------------------------------------------------------------------- |
|
53 |
|
54 #define PROXY_PREF_BRANCH "network.proxy" |
|
55 #define PROXY_PREF(x) PROXY_PREF_BRANCH "." x |
|
56 |
|
57 #define WPAD_URL "http://wpad/wpad.dat" |
|
58 |
|
59 //---------------------------------------------------------------------------- |
|
60 |
|
61 // This structure is intended to be allocated on the stack |
|
62 struct nsProtocolInfo { |
|
63 nsAutoCString scheme; |
|
64 uint32_t flags; |
|
65 int32_t defaultPort; |
|
66 }; |
|
67 |
|
68 //---------------------------------------------------------------------------- |
|
69 |
|
70 // The nsPACManCallback portion of this implementation should be run |
|
71 // on the main thread - so call nsPACMan::AsyncGetProxyForChannel() with |
|
72 // a true mainThreadResponse parameter. |
|
73 class nsAsyncResolveRequest MOZ_FINAL : public nsIRunnable |
|
74 , public nsPACManCallback |
|
75 , public nsICancelable |
|
76 { |
|
77 public: |
|
78 NS_DECL_THREADSAFE_ISUPPORTS |
|
79 |
|
80 nsAsyncResolveRequest(nsProtocolProxyService *pps, nsIChannel *channel, |
|
81 uint32_t aResolveFlags, |
|
82 nsIProtocolProxyCallback *callback) |
|
83 : mStatus(NS_OK) |
|
84 , mDispatched(false) |
|
85 , mResolveFlags(aResolveFlags) |
|
86 , mPPS(pps) |
|
87 , mXPComPPS(pps) |
|
88 , mChannel(channel) |
|
89 , mCallback(callback) |
|
90 { |
|
91 NS_ASSERTION(mCallback, "null callback"); |
|
92 } |
|
93 |
|
94 ~nsAsyncResolveRequest() |
|
95 { |
|
96 if (!NS_IsMainThread()) { |
|
97 // these xpcom pointers might need to be proxied back to the |
|
98 // main thread to delete safely, but if this request had its |
|
99 // callbacks called normally they will all be null and this is a nop |
|
100 |
|
101 nsCOMPtr<nsIThread> mainThread; |
|
102 NS_GetMainThread(getter_AddRefs(mainThread)); |
|
103 |
|
104 if (mChannel) { |
|
105 nsIChannel *forgettable; |
|
106 mChannel.forget(&forgettable); |
|
107 NS_ProxyRelease(mainThread, forgettable, false); |
|
108 } |
|
109 |
|
110 if (mCallback) { |
|
111 nsIProtocolProxyCallback *forgettable; |
|
112 mCallback.forget(&forgettable); |
|
113 NS_ProxyRelease(mainThread, forgettable, false); |
|
114 } |
|
115 |
|
116 if (mProxyInfo) { |
|
117 nsIProxyInfo *forgettable; |
|
118 mProxyInfo.forget(&forgettable); |
|
119 NS_ProxyRelease(mainThread, forgettable, false); |
|
120 } |
|
121 |
|
122 if (mXPComPPS) { |
|
123 nsIProtocolProxyService *forgettable; |
|
124 mXPComPPS.forget(&forgettable); |
|
125 NS_ProxyRelease(mainThread, forgettable, false); |
|
126 } |
|
127 } |
|
128 } |
|
129 |
|
130 void SetResult(nsresult status, nsIProxyInfo *pi) |
|
131 { |
|
132 mStatus = status; |
|
133 mProxyInfo = pi; |
|
134 } |
|
135 |
|
136 NS_IMETHOD Run() |
|
137 { |
|
138 if (mCallback) |
|
139 DoCallback(); |
|
140 return NS_OK; |
|
141 } |
|
142 |
|
143 NS_IMETHOD Cancel(nsresult reason) |
|
144 { |
|
145 NS_ENSURE_ARG(NS_FAILED(reason)); |
|
146 |
|
147 // If we've already called DoCallback then, nothing more to do. |
|
148 if (!mCallback) |
|
149 return NS_OK; |
|
150 |
|
151 SetResult(reason, nullptr); |
|
152 return DispatchCallback(); |
|
153 } |
|
154 |
|
155 nsresult DispatchCallback() |
|
156 { |
|
157 if (mDispatched) // Only need to dispatch once |
|
158 return NS_OK; |
|
159 |
|
160 nsresult rv = NS_DispatchToCurrentThread(this); |
|
161 if (NS_FAILED(rv)) |
|
162 NS_WARNING("unable to dispatch callback event"); |
|
163 else { |
|
164 mDispatched = true; |
|
165 return NS_OK; |
|
166 } |
|
167 |
|
168 mCallback = nullptr; // break possible reference cycle |
|
169 return rv; |
|
170 } |
|
171 |
|
172 private: |
|
173 |
|
174 // Called asynchronously, so we do not need to post another PLEvent |
|
175 // before calling DoCallback. |
|
176 void OnQueryComplete(nsresult status, |
|
177 const nsCString &pacString, |
|
178 const nsCString &newPACURL) |
|
179 { |
|
180 // If we've already called DoCallback then, nothing more to do. |
|
181 if (!mCallback) |
|
182 return; |
|
183 |
|
184 // Provided we haven't been canceled... |
|
185 if (mStatus == NS_OK) { |
|
186 mStatus = status; |
|
187 mPACString = pacString; |
|
188 mPACURL = newPACURL; |
|
189 } |
|
190 |
|
191 // In the cancelation case, we may still have another PLEvent in |
|
192 // the queue that wants to call DoCallback. No need to wait for |
|
193 // it, just run the callback now. |
|
194 DoCallback(); |
|
195 } |
|
196 |
|
197 void DoCallback() |
|
198 { |
|
199 if (mStatus == NS_ERROR_NOT_AVAILABLE && !mProxyInfo) { |
|
200 // If the PAC service is not avail (e.g. failed pac load |
|
201 // or shutdown) then we will be going direct. Make that |
|
202 // mapping now so that any filters are still applied. |
|
203 mPACString = NS_LITERAL_CSTRING("DIRECT;"); |
|
204 mStatus = NS_OK; |
|
205 } |
|
206 |
|
207 // Generate proxy info from the PAC string if appropriate |
|
208 if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty()) { |
|
209 mPPS->ProcessPACString(mPACString, mResolveFlags, |
|
210 getter_AddRefs(mProxyInfo)); |
|
211 nsCOMPtr<nsIURI> uri; |
|
212 mChannel->GetURI(getter_AddRefs(uri)); |
|
213 |
|
214 // Now apply proxy filters |
|
215 nsProtocolInfo info; |
|
216 mStatus = mPPS->GetProtocolInfo(uri, &info); |
|
217 if (NS_SUCCEEDED(mStatus)) |
|
218 mPPS->ApplyFilters(mChannel, info, mProxyInfo); |
|
219 else |
|
220 mProxyInfo = nullptr; |
|
221 |
|
222 LOG(("pac thread callback %s\n", mPACString.get())); |
|
223 if (NS_SUCCEEDED(mStatus)) |
|
224 mPPS->MaybeDisableDNSPrefetch(mProxyInfo); |
|
225 mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus); |
|
226 } |
|
227 else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) { |
|
228 LOG(("pac thread callback indicates new pac file load\n")); |
|
229 |
|
230 // trigger load of new pac url |
|
231 nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false); |
|
232 if (NS_SUCCEEDED(rv)) { |
|
233 // now that the load is triggered, we can resubmit the query |
|
234 nsRefPtr<nsAsyncResolveRequest> newRequest = |
|
235 new nsAsyncResolveRequest(mPPS, mChannel, mResolveFlags, mCallback); |
|
236 rv = mPPS->mPACMan->AsyncGetProxyForChannel(mChannel, newRequest, true); |
|
237 } |
|
238 |
|
239 if (NS_FAILED(rv)) |
|
240 mCallback->OnProxyAvailable(this, mChannel, nullptr, rv); |
|
241 |
|
242 // do not call onproxyavailable() in SUCCESS case - the newRequest will |
|
243 // take care of that |
|
244 } |
|
245 else { |
|
246 LOG(("pac thread callback did not provide information %X\n", mStatus)); |
|
247 if (NS_SUCCEEDED(mStatus)) |
|
248 mPPS->MaybeDisableDNSPrefetch(mProxyInfo); |
|
249 mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus); |
|
250 } |
|
251 |
|
252 // We are on the main thread now and don't need these any more so |
|
253 // release them to avoid having to proxy them back to the main thread |
|
254 // in the dtor |
|
255 mCallback = nullptr; // in case the callback holds an owning ref to us |
|
256 mPPS = nullptr; |
|
257 mXPComPPS = nullptr; |
|
258 mChannel = nullptr; |
|
259 mProxyInfo = nullptr; |
|
260 } |
|
261 |
|
262 private: |
|
263 |
|
264 nsresult mStatus; |
|
265 nsCString mPACString; |
|
266 nsCString mPACURL; |
|
267 bool mDispatched; |
|
268 uint32_t mResolveFlags; |
|
269 |
|
270 nsProtocolProxyService *mPPS; |
|
271 nsCOMPtr<nsIProtocolProxyService> mXPComPPS; |
|
272 nsCOMPtr<nsIChannel> mChannel; |
|
273 nsCOMPtr<nsIProtocolProxyCallback> mCallback; |
|
274 nsCOMPtr<nsIProxyInfo> mProxyInfo; |
|
275 }; |
|
276 |
|
277 NS_IMPL_ISUPPORTS(nsAsyncResolveRequest, nsICancelable, nsIRunnable) |
|
278 |
|
279 //---------------------------------------------------------------------------- |
|
280 |
|
281 #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t') |
|
282 |
|
283 // |
|
284 // apply mask to address (zeros out excluded bits). |
|
285 // |
|
286 // NOTE: we do the byte swapping here to minimize overall swapping. |
|
287 // |
|
288 static void |
|
289 proxy_MaskIPv6Addr(PRIPv6Addr &addr, uint16_t mask_len) |
|
290 { |
|
291 if (mask_len == 128) |
|
292 return; |
|
293 |
|
294 if (mask_len > 96) { |
|
295 addr.pr_s6_addr32[3] = PR_htonl( |
|
296 PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); |
|
297 } |
|
298 else if (mask_len > 64) { |
|
299 addr.pr_s6_addr32[3] = 0; |
|
300 addr.pr_s6_addr32[2] = PR_htonl( |
|
301 PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); |
|
302 } |
|
303 else if (mask_len > 32) { |
|
304 addr.pr_s6_addr32[3] = 0; |
|
305 addr.pr_s6_addr32[2] = 0; |
|
306 addr.pr_s6_addr32[1] = PR_htonl( |
|
307 PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); |
|
308 } |
|
309 else { |
|
310 addr.pr_s6_addr32[3] = 0; |
|
311 addr.pr_s6_addr32[2] = 0; |
|
312 addr.pr_s6_addr32[1] = 0; |
|
313 addr.pr_s6_addr32[0] = PR_htonl( |
|
314 PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); |
|
315 } |
|
316 } |
|
317 |
|
318 static void |
|
319 proxy_GetStringPref(nsIPrefBranch *aPrefBranch, |
|
320 const char *aPref, |
|
321 nsCString &aResult) |
|
322 { |
|
323 nsXPIDLCString temp; |
|
324 nsresult rv = aPrefBranch->GetCharPref(aPref, getter_Copies(temp)); |
|
325 if (NS_FAILED(rv)) |
|
326 aResult.Truncate(); |
|
327 else { |
|
328 aResult.Assign(temp); |
|
329 // all of our string prefs are hostnames, so we should remove any |
|
330 // whitespace characters that the user might have unknowingly entered. |
|
331 aResult.StripWhitespace(); |
|
332 } |
|
333 } |
|
334 |
|
335 static void |
|
336 proxy_GetIntPref(nsIPrefBranch *aPrefBranch, |
|
337 const char *aPref, |
|
338 int32_t &aResult) |
|
339 { |
|
340 int32_t temp; |
|
341 nsresult rv = aPrefBranch->GetIntPref(aPref, &temp); |
|
342 if (NS_FAILED(rv)) |
|
343 aResult = -1; |
|
344 else |
|
345 aResult = temp; |
|
346 } |
|
347 |
|
348 static void |
|
349 proxy_GetBoolPref(nsIPrefBranch *aPrefBranch, |
|
350 const char *aPref, |
|
351 bool &aResult) |
|
352 { |
|
353 bool temp; |
|
354 nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp); |
|
355 if (NS_FAILED(rv)) |
|
356 aResult = false; |
|
357 else |
|
358 aResult = temp; |
|
359 } |
|
360 |
|
361 //---------------------------------------------------------------------------- |
|
362 |
|
363 static const int32_t PROXYCONFIG_DIRECT4X = 3; |
|
364 static const int32_t PROXYCONFIG_COUNT = 6; |
|
365 |
|
366 NS_IMPL_ADDREF(nsProtocolProxyService) |
|
367 NS_IMPL_RELEASE(nsProtocolProxyService) |
|
368 NS_IMPL_CLASSINFO(nsProtocolProxyService, nullptr, nsIClassInfo::SINGLETON, |
|
369 NS_PROTOCOLPROXYSERVICE_CID) |
|
370 NS_IMPL_QUERY_INTERFACE_CI(nsProtocolProxyService, |
|
371 nsIProtocolProxyService, |
|
372 nsIProtocolProxyService2, |
|
373 nsIObserver) |
|
374 NS_IMPL_CI_INTERFACE_GETTER(nsProtocolProxyService, |
|
375 nsIProtocolProxyService, |
|
376 nsIProtocolProxyService2) |
|
377 |
|
378 nsProtocolProxyService::nsProtocolProxyService() |
|
379 : mFilterLocalHosts(false) |
|
380 , mFilters(nullptr) |
|
381 , mProxyConfig(PROXYCONFIG_DIRECT) |
|
382 , mHTTPProxyPort(-1) |
|
383 , mFTPProxyPort(-1) |
|
384 , mHTTPSProxyPort(-1) |
|
385 , mSOCKSProxyPort(-1) |
|
386 , mSOCKSProxyVersion(4) |
|
387 , mSOCKSProxyRemoteDNS(false) |
|
388 , mPACMan(nullptr) |
|
389 , mSessionStart(PR_Now()) |
|
390 , mFailedProxyTimeout(30 * 60) // 30 minute default |
|
391 { |
|
392 } |
|
393 |
|
394 nsProtocolProxyService::~nsProtocolProxyService() |
|
395 { |
|
396 // These should have been cleaned up in our Observe method. |
|
397 NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters == nullptr && |
|
398 mPACMan == nullptr, "what happened to xpcom-shutdown?"); |
|
399 } |
|
400 |
|
401 // nsProtocolProxyService methods |
|
402 nsresult |
|
403 nsProtocolProxyService::Init() |
|
404 { |
|
405 // failure to access prefs is non-fatal |
|
406 nsCOMPtr<nsIPrefBranch> prefBranch = |
|
407 do_GetService(NS_PREFSERVICE_CONTRACTID); |
|
408 if (prefBranch) { |
|
409 // monitor proxy prefs |
|
410 prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false); |
|
411 |
|
412 // read all prefs |
|
413 PrefsChanged(prefBranch, nullptr); |
|
414 } |
|
415 |
|
416 // register for shutdown notification so we can clean ourselves up properly. |
|
417 nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
|
418 if (obs) |
|
419 obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); |
|
420 |
|
421 return NS_OK; |
|
422 } |
|
423 |
|
424 NS_IMETHODIMP |
|
425 nsProtocolProxyService::Observe(nsISupports *aSubject, |
|
426 const char *aTopic, |
|
427 const char16_t *aData) |
|
428 { |
|
429 if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { |
|
430 // cleanup |
|
431 if (mHostFiltersArray.Length() > 0) { |
|
432 mHostFiltersArray.Clear(); |
|
433 } |
|
434 if (mFilters) { |
|
435 delete mFilters; |
|
436 mFilters = nullptr; |
|
437 } |
|
438 if (mPACMan) { |
|
439 mPACMan->Shutdown(); |
|
440 mPACMan = nullptr; |
|
441 } |
|
442 } |
|
443 else { |
|
444 NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, |
|
445 "what is this random observer event?"); |
|
446 nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject); |
|
447 if (prefs) |
|
448 PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get()); |
|
449 } |
|
450 return NS_OK; |
|
451 } |
|
452 |
|
453 void |
|
454 nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, |
|
455 const char *pref) |
|
456 { |
|
457 nsresult rv = NS_OK; |
|
458 bool reloadPAC = false; |
|
459 nsXPIDLCString tempString; |
|
460 |
|
461 if (!pref || !strcmp(pref, PROXY_PREF("type"))) { |
|
462 int32_t type = -1; |
|
463 rv = prefBranch->GetIntPref(PROXY_PREF("type"), &type); |
|
464 if (NS_SUCCEEDED(rv)) { |
|
465 // bug 115720 - for ns4.x backwards compatibility |
|
466 if (type == PROXYCONFIG_DIRECT4X) { |
|
467 type = PROXYCONFIG_DIRECT; |
|
468 // Reset the type so that the dialog looks correct, and we |
|
469 // don't have to handle this case everywhere else |
|
470 // I'm paranoid about a loop of some sort - only do this |
|
471 // if we're enumerating all prefs, and ignore any error |
|
472 if (!pref) |
|
473 prefBranch->SetIntPref(PROXY_PREF("type"), type); |
|
474 } else if (type >= PROXYCONFIG_COUNT) { |
|
475 LOG(("unknown proxy type: %lu; assuming direct\n", type)); |
|
476 type = PROXYCONFIG_DIRECT; |
|
477 } |
|
478 mProxyConfig = type; |
|
479 reloadPAC = true; |
|
480 } |
|
481 |
|
482 if (mProxyConfig == PROXYCONFIG_SYSTEM) { |
|
483 mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); |
|
484 if (!mSystemProxySettings) |
|
485 mProxyConfig = PROXYCONFIG_DIRECT; |
|
486 ResetPACThread(); |
|
487 } else { |
|
488 if (mSystemProxySettings) { |
|
489 mSystemProxySettings = nullptr; |
|
490 ResetPACThread(); |
|
491 } |
|
492 } |
|
493 } |
|
494 |
|
495 if (!pref || !strcmp(pref, PROXY_PREF("http"))) |
|
496 proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost); |
|
497 |
|
498 if (!pref || !strcmp(pref, PROXY_PREF("http_port"))) |
|
499 proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort); |
|
500 |
|
501 if (!pref || !strcmp(pref, PROXY_PREF("ssl"))) |
|
502 proxy_GetStringPref(prefBranch, PROXY_PREF("ssl"), mHTTPSProxyHost); |
|
503 |
|
504 if (!pref || !strcmp(pref, PROXY_PREF("ssl_port"))) |
|
505 proxy_GetIntPref(prefBranch, PROXY_PREF("ssl_port"), mHTTPSProxyPort); |
|
506 |
|
507 if (!pref || !strcmp(pref, PROXY_PREF("ftp"))) |
|
508 proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost); |
|
509 |
|
510 if (!pref || !strcmp(pref, PROXY_PREF("ftp_port"))) |
|
511 proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort); |
|
512 |
|
513 if (!pref || !strcmp(pref, PROXY_PREF("socks"))) |
|
514 proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyHost); |
|
515 |
|
516 if (!pref || !strcmp(pref, PROXY_PREF("socks_port"))) |
|
517 proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort); |
|
518 |
|
519 if (!pref || !strcmp(pref, PROXY_PREF("socks_username"))) |
|
520 proxy_GetStringPref(prefBranch, PROXY_PREF("socks_username"), mSOCKSProxyUsername); |
|
521 |
|
522 if (!pref || !strcmp(pref, PROXY_PREF("socks_password"))) |
|
523 proxy_GetStringPref(prefBranch, PROXY_PREF("socks_password"), mSOCKSProxyPassword); |
|
524 |
|
525 if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) { |
|
526 int32_t version; |
|
527 proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version); |
|
528 // make sure this preference value remains sane |
|
529 if (version == 5) |
|
530 mSOCKSProxyVersion = 5; |
|
531 else |
|
532 mSOCKSProxyVersion = 4; |
|
533 } |
|
534 |
|
535 if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns"))) |
|
536 proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"), |
|
537 mSOCKSProxyRemoteDNS); |
|
538 |
|
539 if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout"))) |
|
540 proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"), |
|
541 mFailedProxyTimeout); |
|
542 |
|
543 if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) { |
|
544 rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"), |
|
545 getter_Copies(tempString)); |
|
546 if (NS_SUCCEEDED(rv)) |
|
547 LoadHostFilters(tempString.get()); |
|
548 } |
|
549 |
|
550 // We're done if not using something that could give us a PAC URL |
|
551 // (PAC, WPAD or System) |
|
552 if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD && |
|
553 mProxyConfig != PROXYCONFIG_SYSTEM) |
|
554 return; |
|
555 |
|
556 // OK, we need to reload the PAC file if: |
|
557 // 1) network.proxy.type changed, or |
|
558 // 2) network.proxy.autoconfig_url changed and PAC is configured |
|
559 |
|
560 if (!pref || !strcmp(pref, PROXY_PREF("autoconfig_url"))) |
|
561 reloadPAC = true; |
|
562 |
|
563 if (reloadPAC) { |
|
564 tempString.Truncate(); |
|
565 if (mProxyConfig == PROXYCONFIG_PAC) { |
|
566 prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"), |
|
567 getter_Copies(tempString)); |
|
568 } else if (mProxyConfig == PROXYCONFIG_WPAD) { |
|
569 // We diverge from the WPAD spec here in that we don't walk the |
|
570 // hosts's FQDN, stripping components until we hit a TLD. Doing so |
|
571 // is dangerous in the face of an incomplete list of TLDs, and TLDs |
|
572 // get added over time. We could consider doing only a single |
|
573 // substitution of the first component, if that proves to help |
|
574 // compatibility. |
|
575 tempString.AssignLiteral(WPAD_URL); |
|
576 } else if (mSystemProxySettings) { |
|
577 // Get System Proxy settings if available |
|
578 mSystemProxySettings->GetPACURI(tempString); |
|
579 } |
|
580 if (!tempString.IsEmpty()) |
|
581 ConfigureFromPAC(tempString, false); |
|
582 } |
|
583 } |
|
584 |
|
585 bool |
|
586 nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort) |
|
587 { |
|
588 if (mHostFiltersArray.Length() == 0) |
|
589 return true; |
|
590 |
|
591 int32_t port; |
|
592 nsAutoCString host; |
|
593 |
|
594 nsresult rv = aURI->GetAsciiHost(host); |
|
595 if (NS_FAILED(rv) || host.IsEmpty()) |
|
596 return false; |
|
597 |
|
598 rv = aURI->GetPort(&port); |
|
599 if (NS_FAILED(rv)) |
|
600 return false; |
|
601 if (port == -1) |
|
602 port = defaultPort; |
|
603 |
|
604 PRNetAddr addr; |
|
605 bool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS); |
|
606 |
|
607 PRIPv6Addr ipv6; |
|
608 if (is_ipaddr) { |
|
609 // convert parsed address to IPv6 |
|
610 if (addr.raw.family == PR_AF_INET) { |
|
611 // convert to IPv4-mapped address |
|
612 PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6); |
|
613 } |
|
614 else if (addr.raw.family == PR_AF_INET6) { |
|
615 // copy the address |
|
616 memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr)); |
|
617 } |
|
618 else { |
|
619 NS_WARNING("unknown address family"); |
|
620 return true; // allow proxying |
|
621 } |
|
622 } |
|
623 |
|
624 // Don't use proxy for local hosts (plain hostname, no dots) |
|
625 if (!is_ipaddr && mFilterLocalHosts && (kNotFound == host.FindChar('.'))) { |
|
626 LOG(("Not using proxy for this local host [%s]!\n", host.get())); |
|
627 return false; // don't allow proxying |
|
628 } |
|
629 |
|
630 int32_t index = -1; |
|
631 while (++index < int32_t(mHostFiltersArray.Length())) { |
|
632 HostInfo *hinfo = mHostFiltersArray[index]; |
|
633 |
|
634 if (is_ipaddr != hinfo->is_ipaddr) |
|
635 continue; |
|
636 if (hinfo->port && hinfo->port != port) |
|
637 continue; |
|
638 |
|
639 if (is_ipaddr) { |
|
640 // generate masked version of target IPv6 address |
|
641 PRIPv6Addr masked; |
|
642 memcpy(&masked, &ipv6, sizeof(PRIPv6Addr)); |
|
643 proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len); |
|
644 |
|
645 // check for a match |
|
646 if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0) |
|
647 return false; // proxy disallowed |
|
648 } |
|
649 else { |
|
650 uint32_t host_len = host.Length(); |
|
651 uint32_t filter_host_len = hinfo->name.host_len; |
|
652 |
|
653 if (host_len >= filter_host_len) { |
|
654 // |
|
655 // compare last |filter_host_len| bytes of target hostname. |
|
656 // |
|
657 const char *host_tail = host.get() + host_len - filter_host_len; |
|
658 if (!PL_strncasecmp(host_tail, hinfo->name.host, filter_host_len)) |
|
659 return false; // proxy disallowed |
|
660 } |
|
661 } |
|
662 } |
|
663 return true; |
|
664 } |
|
665 |
|
666 // kProxyType\* may be referred to externally in |
|
667 // nsProxyInfo in order to compare by string pointer |
|
668 namespace mozilla { |
|
669 const char kProxyType_HTTP[] = "http"; |
|
670 const char kProxyType_PROXY[] = "proxy"; |
|
671 const char kProxyType_SOCKS[] = "socks"; |
|
672 const char kProxyType_SOCKS4[] = "socks4"; |
|
673 const char kProxyType_SOCKS5[] = "socks5"; |
|
674 const char kProxyType_DIRECT[] = "direct"; |
|
675 const char kProxyType_UNKNOWN[] = "unknown"; |
|
676 } |
|
677 |
|
678 const char * |
|
679 nsProtocolProxyService::ExtractProxyInfo(const char *start, |
|
680 uint32_t aResolveFlags, |
|
681 nsProxyInfo **result) |
|
682 { |
|
683 *result = nullptr; |
|
684 uint32_t flags = 0; |
|
685 |
|
686 // see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl |
|
687 |
|
688 // find end of proxy info delimiter |
|
689 const char *end = start; |
|
690 while (*end && *end != ';') ++end; |
|
691 |
|
692 // find end of proxy type delimiter |
|
693 const char *sp = start; |
|
694 while (sp < end && *sp != ' ' && *sp != '\t') ++sp; |
|
695 |
|
696 uint32_t len = sp - start; |
|
697 const char *type = nullptr; |
|
698 switch (len) { |
|
699 case 5: |
|
700 if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) |
|
701 type = kProxyType_HTTP; |
|
702 else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) |
|
703 type = kProxyType_SOCKS4; // assume v4 for 4x compat |
|
704 break; |
|
705 case 6: |
|
706 if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0) |
|
707 type = kProxyType_DIRECT; |
|
708 else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0) |
|
709 type = kProxyType_SOCKS4; |
|
710 else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0) |
|
711 // map "SOCKS5" to "socks" to match contract-id of registered |
|
712 // SOCKS-v5 socket provider. |
|
713 type = kProxyType_SOCKS; |
|
714 break; |
|
715 } |
|
716 if (type) { |
|
717 const char *host = nullptr, *hostEnd = nullptr; |
|
718 int32_t port = -1; |
|
719 |
|
720 // If it's a SOCKS5 proxy, do name resolution on the server side. |
|
721 // We could use this with SOCKS4a servers too, but they might not |
|
722 // support it. |
|
723 if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS) |
|
724 flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; |
|
725 |
|
726 // extract host:port |
|
727 start = sp; |
|
728 while ((*start == ' ' || *start == '\t') && start < end) |
|
729 start++; |
|
730 |
|
731 // port defaults |
|
732 if (type == kProxyType_HTTP) |
|
733 port = 80; |
|
734 else |
|
735 port = 1080; |
|
736 |
|
737 nsProxyInfo *pi = new nsProxyInfo(); |
|
738 pi->mType = type; |
|
739 pi->mFlags = flags; |
|
740 pi->mResolveFlags = aResolveFlags; |
|
741 pi->mTimeout = mFailedProxyTimeout; |
|
742 |
|
743 // www.foo.com:8080 and http://www.foo.com:8080 |
|
744 nsDependentCSubstring maybeURL(start, end - start); |
|
745 nsCOMPtr<nsIURI> pacURI; |
|
746 |
|
747 nsAutoCString urlHost; |
|
748 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) && |
|
749 NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) && |
|
750 !urlHost.IsEmpty()) { |
|
751 // http://www.example.com:8080 |
|
752 |
|
753 pi->mHost = urlHost; |
|
754 |
|
755 int32_t tPort; |
|
756 if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) { |
|
757 port = tPort; |
|
758 } |
|
759 pi->mPort = port; |
|
760 } |
|
761 else { |
|
762 // www.example.com:8080 |
|
763 if (start < end) { |
|
764 host = start; |
|
765 hostEnd = strchr(host, ':'); |
|
766 if (!hostEnd || hostEnd > end) { |
|
767 hostEnd = end; |
|
768 // no port, so assume default |
|
769 } |
|
770 else { |
|
771 port = atoi(hostEnd + 1); |
|
772 } |
|
773 } |
|
774 // YES, it is ok to specify a null proxy host. |
|
775 if (host) { |
|
776 pi->mHost.Assign(host, hostEnd - host); |
|
777 pi->mPort = port; |
|
778 } |
|
779 } |
|
780 NS_ADDREF(*result = pi); |
|
781 } |
|
782 |
|
783 while (*end == ';' || *end == ' ' || *end == '\t') |
|
784 ++end; |
|
785 return end; |
|
786 } |
|
787 |
|
788 void |
|
789 nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key) |
|
790 { |
|
791 key.AssignASCII(pi->mType); |
|
792 if (!pi->mHost.IsEmpty()) { |
|
793 key.Append(' '); |
|
794 key.Append(pi->mHost); |
|
795 key.Append(':'); |
|
796 key.AppendInt(pi->mPort); |
|
797 } |
|
798 } |
|
799 |
|
800 uint32_t |
|
801 nsProtocolProxyService::SecondsSinceSessionStart() |
|
802 { |
|
803 PRTime now = PR_Now(); |
|
804 |
|
805 // get time elapsed since session start |
|
806 int64_t diff = now - mSessionStart; |
|
807 |
|
808 // convert microseconds to seconds |
|
809 diff /= PR_USEC_PER_SEC; |
|
810 |
|
811 // return converted 32 bit value |
|
812 return uint32_t(diff); |
|
813 } |
|
814 |
|
815 void |
|
816 nsProtocolProxyService::EnableProxy(nsProxyInfo *pi) |
|
817 { |
|
818 nsAutoCString key; |
|
819 GetProxyKey(pi, key); |
|
820 mFailedProxies.Remove(key); |
|
821 } |
|
822 |
|
823 void |
|
824 nsProtocolProxyService::DisableProxy(nsProxyInfo *pi) |
|
825 { |
|
826 nsAutoCString key; |
|
827 GetProxyKey(pi, key); |
|
828 |
|
829 uint32_t dsec = SecondsSinceSessionStart(); |
|
830 |
|
831 // Add timeout to interval (this is the time when the proxy can |
|
832 // be tried again). |
|
833 dsec += pi->mTimeout; |
|
834 |
|
835 // NOTE: The classic codebase would increase the timeout value |
|
836 // incrementally each time a subsequent failure occurred. |
|
837 // We could do the same, but it would require that we not |
|
838 // remove proxy entries in IsProxyDisabled or otherwise |
|
839 // change the way we are recording disabled proxies. |
|
840 // Simpler is probably better for now, and at least the |
|
841 // user can tune the timeout setting via preferences. |
|
842 |
|
843 LOG(("DisableProxy %s %d\n", key.get(), dsec)); |
|
844 |
|
845 // If this fails, oh well... means we don't have enough memory |
|
846 // to remember the failed proxy. |
|
847 mFailedProxies.Put(key, dsec); |
|
848 } |
|
849 |
|
850 bool |
|
851 nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi) |
|
852 { |
|
853 nsAutoCString key; |
|
854 GetProxyKey(pi, key); |
|
855 |
|
856 uint32_t val; |
|
857 if (!mFailedProxies.Get(key, &val)) |
|
858 return false; |
|
859 |
|
860 uint32_t dsec = SecondsSinceSessionStart(); |
|
861 |
|
862 // if time passed has exceeded interval, then try proxy again. |
|
863 if (dsec > val) { |
|
864 mFailedProxies.Remove(key); |
|
865 return false; |
|
866 } |
|
867 |
|
868 return true; |
|
869 } |
|
870 |
|
871 nsresult |
|
872 nsProtocolProxyService::SetupPACThread() |
|
873 { |
|
874 if (mPACMan) |
|
875 return NS_OK; |
|
876 |
|
877 mPACMan = new nsPACMan(); |
|
878 |
|
879 bool mainThreadOnly; |
|
880 nsresult rv; |
|
881 if (mSystemProxySettings && |
|
882 NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && |
|
883 !mainThreadOnly) { |
|
884 rv = mPACMan->Init(mSystemProxySettings); |
|
885 } |
|
886 else { |
|
887 rv = mPACMan->Init(nullptr); |
|
888 } |
|
889 |
|
890 if (NS_FAILED(rv)) |
|
891 mPACMan = nullptr; |
|
892 return rv; |
|
893 } |
|
894 |
|
895 nsresult |
|
896 nsProtocolProxyService::ResetPACThread() |
|
897 { |
|
898 if (!mPACMan) |
|
899 return NS_OK; |
|
900 |
|
901 mPACMan->Shutdown(); |
|
902 mPACMan = nullptr; |
|
903 return SetupPACThread(); |
|
904 } |
|
905 |
|
906 nsresult |
|
907 nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec, |
|
908 bool forceReload) |
|
909 { |
|
910 SetupPACThread(); |
|
911 |
|
912 if (mPACMan->IsPACURI(spec) && !forceReload) |
|
913 return NS_OK; |
|
914 |
|
915 mFailedProxies.Clear(); |
|
916 |
|
917 return mPACMan->LoadPACFromURI(spec); |
|
918 } |
|
919 |
|
920 void |
|
921 nsProtocolProxyService::ProcessPACString(const nsCString &pacString, |
|
922 uint32_t aResolveFlags, |
|
923 nsIProxyInfo **result) |
|
924 { |
|
925 if (pacString.IsEmpty()) { |
|
926 *result = nullptr; |
|
927 return; |
|
928 } |
|
929 |
|
930 const char *proxies = pacString.get(); |
|
931 |
|
932 nsProxyInfo *pi = nullptr, *first = nullptr, *last = nullptr; |
|
933 while (*proxies) { |
|
934 proxies = ExtractProxyInfo(proxies, aResolveFlags, &pi); |
|
935 if (pi) { |
|
936 if (last) { |
|
937 NS_ASSERTION(last->mNext == nullptr, "leaking nsProxyInfo"); |
|
938 last->mNext = pi; |
|
939 } |
|
940 else |
|
941 first = pi; |
|
942 last = pi; |
|
943 } |
|
944 } |
|
945 *result = first; |
|
946 } |
|
947 |
|
948 // nsIProtocolProxyService2 |
|
949 NS_IMETHODIMP |
|
950 nsProtocolProxyService::ReloadPAC() |
|
951 { |
|
952 nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); |
|
953 if (!prefs) |
|
954 return NS_OK; |
|
955 |
|
956 int32_t type; |
|
957 nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type); |
|
958 if (NS_FAILED(rv)) |
|
959 return NS_OK; |
|
960 |
|
961 nsXPIDLCString pacSpec; |
|
962 if (type == PROXYCONFIG_PAC) |
|
963 prefs->GetCharPref(PROXY_PREF("autoconfig_url"), getter_Copies(pacSpec)); |
|
964 else if (type == PROXYCONFIG_WPAD) |
|
965 pacSpec.AssignLiteral(WPAD_URL); |
|
966 |
|
967 if (!pacSpec.IsEmpty()) |
|
968 ConfigureFromPAC(pacSpec, true); |
|
969 return NS_OK; |
|
970 } |
|
971 |
|
972 // When sync interface is removed this can go away too |
|
973 // The nsPACManCallback portion of this implementation should be run |
|
974 // off the main thread, because it uses a condvar for signaling and |
|
975 // the main thread is blocking on that condvar - |
|
976 // so call nsPACMan::AsyncGetProxyForChannel() with |
|
977 // a false mainThreadResponse parameter. |
|
978 class nsAsyncBridgeRequest MOZ_FINAL : public nsPACManCallback |
|
979 { |
|
980 NS_DECL_THREADSAFE_ISUPPORTS |
|
981 |
|
982 nsAsyncBridgeRequest() |
|
983 : mMutex("nsDeprecatedCallback") |
|
984 , mCondVar(mMutex, "nsDeprecatedCallback") |
|
985 , mCompleted(false) |
|
986 { |
|
987 } |
|
988 |
|
989 void OnQueryComplete(nsresult status, |
|
990 const nsCString &pacString, |
|
991 const nsCString &newPACURL) |
|
992 { |
|
993 MutexAutoLock lock(mMutex); |
|
994 mCompleted = true; |
|
995 mStatus = status; |
|
996 mPACString = pacString; |
|
997 mPACURL = newPACURL; |
|
998 mCondVar.Notify(); |
|
999 } |
|
1000 |
|
1001 void Lock() { mMutex.Lock(); } |
|
1002 void Unlock() { mMutex.Unlock(); } |
|
1003 void Wait() { mCondVar.Wait(PR_SecondsToInterval(3)); } |
|
1004 |
|
1005 private: |
|
1006 ~nsAsyncBridgeRequest() |
|
1007 { |
|
1008 } |
|
1009 |
|
1010 friend class nsProtocolProxyService; |
|
1011 |
|
1012 Mutex mMutex; |
|
1013 CondVar mCondVar; |
|
1014 |
|
1015 nsresult mStatus; |
|
1016 nsCString mPACString; |
|
1017 nsCString mPACURL; |
|
1018 bool mCompleted; |
|
1019 }; |
|
1020 NS_IMPL_ISUPPORTS0(nsAsyncBridgeRequest) |
|
1021 |
|
1022 // nsProtocolProxyService |
|
1023 nsresult |
|
1024 nsProtocolProxyService::DeprecatedBlockingResolve(nsIChannel *aChannel, |
|
1025 uint32_t aFlags, |
|
1026 nsIProxyInfo **retval) |
|
1027 { |
|
1028 NS_ENSURE_ARG_POINTER(aChannel); |
|
1029 |
|
1030 nsCOMPtr<nsIURI> uri; |
|
1031 aChannel->GetURI(getter_AddRefs(uri)); |
|
1032 |
|
1033 nsProtocolInfo info; |
|
1034 nsresult rv = GetProtocolInfo(uri, &info); |
|
1035 if (NS_FAILED(rv)) |
|
1036 return rv; |
|
1037 |
|
1038 nsCOMPtr<nsIProxyInfo> pi; |
|
1039 bool usePACThread; |
|
1040 |
|
1041 // SystemProxySettings and PAC files can block the main thread |
|
1042 // but if neither of them are in use, we can just do the work |
|
1043 // right here and directly invoke the callback |
|
1044 |
|
1045 rv = Resolve_Internal(aChannel, info, aFlags, &usePACThread, getter_AddRefs(pi)); |
|
1046 if (NS_FAILED(rv)) |
|
1047 return rv; |
|
1048 |
|
1049 if (!usePACThread || !mPACMan) { |
|
1050 ApplyFilters(aChannel, info, pi); |
|
1051 pi.forget(retval); |
|
1052 return NS_OK; |
|
1053 } |
|
1054 |
|
1055 // Use the PAC thread to do the work, so we don't have to reimplement that |
|
1056 // code, but block this thread on that completion. |
|
1057 nsRefPtr<nsAsyncBridgeRequest> ctx = new nsAsyncBridgeRequest(); |
|
1058 ctx->Lock(); |
|
1059 if (NS_SUCCEEDED(mPACMan->AsyncGetProxyForChannel(aChannel, ctx, false))) { |
|
1060 // this can really block the main thread, so cap it at 3 seconds |
|
1061 ctx->Wait(); |
|
1062 } |
|
1063 ctx->Unlock(); |
|
1064 if (!ctx->mCompleted) |
|
1065 return NS_ERROR_FAILURE; |
|
1066 if (NS_FAILED(ctx->mStatus)) |
|
1067 return ctx->mStatus; |
|
1068 |
|
1069 // pretty much duplicate real DoCallback logic |
|
1070 |
|
1071 // Generate proxy info from the PAC string if appropriate |
|
1072 if (!ctx->mPACString.IsEmpty()) { |
|
1073 LOG(("sync pac thread callback %s\n", ctx->mPACString.get())); |
|
1074 ProcessPACString(ctx->mPACString, 0, getter_AddRefs(pi)); |
|
1075 ApplyFilters(aChannel, info, pi); |
|
1076 pi.forget(retval); |
|
1077 return NS_OK; |
|
1078 } |
|
1079 |
|
1080 if (!ctx->mPACURL.IsEmpty()) { |
|
1081 NS_WARNING("sync pac thread callback indicates new pac file load\n"); |
|
1082 // This is a problem and is one of the reasons this blocking interface |
|
1083 // is deprecated. The main loop needs to spin to make this reload happen. So |
|
1084 // we are going to kick off the reload and return an error - it will work |
|
1085 // next time. Because this sync interface is only used in the java plugin it |
|
1086 // is extremely likely that the pac file has already been loaded anyhow. |
|
1087 |
|
1088 rv = ConfigureFromPAC(ctx->mPACURL, false); |
|
1089 if (NS_FAILED(rv)) |
|
1090 return rv; |
|
1091 return NS_ERROR_NOT_AVAILABLE; |
|
1092 } |
|
1093 |
|
1094 *retval = nullptr; |
|
1095 return NS_OK; |
|
1096 } |
|
1097 |
|
1098 nsresult |
|
1099 nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags, |
|
1100 nsIProtocolProxyCallback *callback, |
|
1101 nsICancelable **result, |
|
1102 bool isSyncOK) |
|
1103 { |
|
1104 NS_ENSURE_ARG_POINTER(channel); |
|
1105 NS_ENSURE_ARG_POINTER(callback); |
|
1106 |
|
1107 nsCOMPtr<nsIURI> uri; |
|
1108 channel->GetURI(getter_AddRefs(uri)); |
|
1109 |
|
1110 *result = nullptr; |
|
1111 nsRefPtr<nsAsyncResolveRequest> ctx = |
|
1112 new nsAsyncResolveRequest(this, channel, flags, callback); |
|
1113 |
|
1114 nsProtocolInfo info; |
|
1115 nsresult rv = GetProtocolInfo(uri, &info); |
|
1116 if (NS_FAILED(rv)) |
|
1117 return rv; |
|
1118 |
|
1119 nsCOMPtr<nsIProxyInfo> pi; |
|
1120 bool usePACThread; |
|
1121 |
|
1122 // SystemProxySettings and PAC files can block the main thread |
|
1123 // but if neither of them are in use, we can just do the work |
|
1124 // right here and directly invoke the callback |
|
1125 |
|
1126 rv = Resolve_Internal(channel, info, flags, &usePACThread, getter_AddRefs(pi)); |
|
1127 if (NS_FAILED(rv)) |
|
1128 return rv; |
|
1129 |
|
1130 if (!usePACThread || !mPACMan) { |
|
1131 // we can do it locally |
|
1132 ApplyFilters(channel, info, pi); |
|
1133 ctx->SetResult(NS_OK, pi); |
|
1134 if (isSyncOK) { |
|
1135 ctx->Run(); |
|
1136 return NS_OK; |
|
1137 } |
|
1138 |
|
1139 rv = ctx->DispatchCallback(); |
|
1140 if (NS_SUCCEEDED(rv)) |
|
1141 ctx.forget(result); |
|
1142 return rv; |
|
1143 } |
|
1144 |
|
1145 // else kick off a PAC thread query |
|
1146 |
|
1147 rv = mPACMan->AsyncGetProxyForChannel(channel, ctx, true); |
|
1148 if (NS_SUCCEEDED(rv)) |
|
1149 ctx.forget(result); |
|
1150 return rv; |
|
1151 } |
|
1152 |
|
1153 // nsIProtocolProxyService |
|
1154 NS_IMETHODIMP |
|
1155 nsProtocolProxyService::AsyncResolve2(nsIChannel *channel, uint32_t flags, |
|
1156 nsIProtocolProxyCallback *callback, |
|
1157 nsICancelable **result) |
|
1158 { |
|
1159 return AsyncResolveInternal(channel, flags, callback, result, true); |
|
1160 } |
|
1161 |
|
1162 NS_IMETHODIMP |
|
1163 nsProtocolProxyService::AsyncResolve(nsIChannel *channel, uint32_t flags, |
|
1164 nsIProtocolProxyCallback *callback, |
|
1165 nsICancelable **result) |
|
1166 { |
|
1167 return AsyncResolveInternal(channel, flags, callback, result, false); |
|
1168 } |
|
1169 |
|
1170 NS_IMETHODIMP |
|
1171 nsProtocolProxyService::NewProxyInfo(const nsACString &aType, |
|
1172 const nsACString &aHost, |
|
1173 int32_t aPort, |
|
1174 uint32_t aFlags, |
|
1175 uint32_t aFailoverTimeout, |
|
1176 nsIProxyInfo *aFailoverProxy, |
|
1177 nsIProxyInfo **aResult) |
|
1178 { |
|
1179 static const char *types[] = { |
|
1180 kProxyType_HTTP, |
|
1181 kProxyType_SOCKS, |
|
1182 kProxyType_SOCKS4, |
|
1183 kProxyType_DIRECT |
|
1184 }; |
|
1185 |
|
1186 // resolve type; this allows us to avoid copying the type string into each |
|
1187 // proxy info instance. we just reference the string literals directly :) |
|
1188 const char *type = nullptr; |
|
1189 for (uint32_t i=0; i<ArrayLength(types); ++i) { |
|
1190 if (aType.LowerCaseEqualsASCII(types[i])) { |
|
1191 type = types[i]; |
|
1192 break; |
|
1193 } |
|
1194 } |
|
1195 NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG); |
|
1196 |
|
1197 return NewProxyInfo_Internal(type, aHost, aPort, |
|
1198 mSOCKSProxyUsername, mSOCKSProxyPassword, |
|
1199 aFlags, aFailoverTimeout, |
|
1200 aFailoverProxy, 0, aResult); |
|
1201 } |
|
1202 |
|
1203 NS_IMETHODIMP |
|
1204 nsProtocolProxyService::NewSOCKSProxyInfo(const nsACString &aHost, |
|
1205 int32_t aPort, |
|
1206 const nsACString &aUsername, |
|
1207 const nsACString &aPassword, |
|
1208 uint32_t aFlags, |
|
1209 uint32_t aFailoverTimeout, |
|
1210 nsIProxyInfo *aFailoverProxy, |
|
1211 nsIProxyInfo **aResult) |
|
1212 { |
|
1213 return NewProxyInfo_Internal(kProxyType_SOCKS, aHost, aPort, |
|
1214 aUsername, aPassword, |
|
1215 aFlags, aFailoverTimeout, |
|
1216 aFailoverProxy, 0, aResult); |
|
1217 } |
|
1218 |
|
1219 NS_IMETHODIMP |
|
1220 nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy, |
|
1221 nsIURI *aURI, |
|
1222 nsresult aStatus, |
|
1223 nsIProxyInfo **aResult) |
|
1224 { |
|
1225 // We only support failover when a PAC file is configured, either |
|
1226 // directly or via system settings |
|
1227 if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD && |
|
1228 mProxyConfig != PROXYCONFIG_SYSTEM) |
|
1229 return NS_ERROR_NOT_AVAILABLE; |
|
1230 |
|
1231 // Verify that |aProxy| is one of our nsProxyInfo objects. |
|
1232 nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy); |
|
1233 NS_ENSURE_ARG(pi); |
|
1234 // OK, the QI checked out. We can proceed. |
|
1235 |
|
1236 // Remember that this proxy is down. |
|
1237 DisableProxy(pi); |
|
1238 |
|
1239 // NOTE: At this point, we might want to prompt the user if we have |
|
1240 // not already tried going DIRECT. This is something that the |
|
1241 // classic codebase supported; however, IE6 does not prompt. |
|
1242 |
|
1243 if (!pi->mNext) |
|
1244 return NS_ERROR_NOT_AVAILABLE; |
|
1245 |
|
1246 LOG(("PAC failover from %s %s:%d to %s %s:%d\n", |
|
1247 pi->mType, pi->mHost.get(), pi->mPort, |
|
1248 pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort)); |
|
1249 |
|
1250 NS_ADDREF(*aResult = pi->mNext); |
|
1251 return NS_OK; |
|
1252 } |
|
1253 |
|
1254 nsresult |
|
1255 nsProtocolProxyService::InsertFilterLink(FilterLink *link, uint32_t position) |
|
1256 { |
|
1257 if (!mFilters) { |
|
1258 mFilters = link; |
|
1259 return NS_OK; |
|
1260 } |
|
1261 |
|
1262 // insert into mFilters in sorted order |
|
1263 FilterLink *last = nullptr; |
|
1264 for (FilterLink *iter = mFilters; iter; iter = iter->next) { |
|
1265 if (position < iter->position) { |
|
1266 if (last) { |
|
1267 link->next = last->next; |
|
1268 last->next = link; |
|
1269 } |
|
1270 else { |
|
1271 link->next = mFilters; |
|
1272 mFilters = link; |
|
1273 } |
|
1274 return NS_OK; |
|
1275 } |
|
1276 last = iter; |
|
1277 } |
|
1278 // our position is equal to or greater than the last link in the list |
|
1279 last->next = link; |
|
1280 return NS_OK; |
|
1281 } |
|
1282 |
|
1283 NS_IMETHODIMP |
|
1284 nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter, |
|
1285 uint32_t position) |
|
1286 { |
|
1287 UnregisterFilter(filter); // remove this filter if we already have it |
|
1288 |
|
1289 FilterLink *link = new FilterLink(position, filter); |
|
1290 if (!link) |
|
1291 return NS_ERROR_OUT_OF_MEMORY; |
|
1292 return InsertFilterLink(link, position); |
|
1293 } |
|
1294 |
|
1295 NS_IMETHODIMP |
|
1296 nsProtocolProxyService::RegisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter, |
|
1297 uint32_t position) |
|
1298 { |
|
1299 UnregisterChannelFilter(channelFilter); // remove this filter if we already have it |
|
1300 |
|
1301 FilterLink *link = new FilterLink(position, channelFilter); |
|
1302 if (!link) |
|
1303 return NS_ERROR_OUT_OF_MEMORY; |
|
1304 return InsertFilterLink(link, position); |
|
1305 } |
|
1306 |
|
1307 nsresult |
|
1308 nsProtocolProxyService::RemoveFilterLink(nsISupports* givenObject) |
|
1309 { |
|
1310 FilterLink *last = nullptr; |
|
1311 for (FilterLink *iter = mFilters; iter; iter = iter->next) { |
|
1312 nsCOMPtr<nsISupports> object = do_QueryInterface(iter->filter); |
|
1313 if (object == givenObject) { |
|
1314 if (last) |
|
1315 last->next = iter->next; |
|
1316 else |
|
1317 mFilters = iter->next; |
|
1318 iter->next = nullptr; |
|
1319 delete iter; |
|
1320 return NS_OK; |
|
1321 } |
|
1322 last = iter; |
|
1323 } |
|
1324 |
|
1325 // No need to throw an exception in this case. |
|
1326 return NS_OK; |
|
1327 } |
|
1328 |
|
1329 NS_IMETHODIMP |
|
1330 nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter *filter) { |
|
1331 // QI to nsISupports so we can safely test object identity. |
|
1332 nsCOMPtr<nsISupports> givenObject = do_QueryInterface(filter); |
|
1333 return RemoveFilterLink(givenObject); |
|
1334 } |
|
1335 |
|
1336 NS_IMETHODIMP |
|
1337 nsProtocolProxyService::UnregisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter) { |
|
1338 // QI to nsISupports so we can safely test object identity. |
|
1339 nsCOMPtr<nsISupports> givenObject = do_QueryInterface(channelFilter); |
|
1340 return RemoveFilterLink(givenObject); |
|
1341 } |
|
1342 |
|
1343 NS_IMETHODIMP |
|
1344 nsProtocolProxyService::GetProxyConfigType(uint32_t* aProxyConfigType) |
|
1345 { |
|
1346 *aProxyConfigType = mProxyConfig; |
|
1347 return NS_OK; |
|
1348 } |
|
1349 |
|
1350 void |
|
1351 nsProtocolProxyService::LoadHostFilters(const char *filters) |
|
1352 { |
|
1353 // check to see the owners flag? /!?/ TODO |
|
1354 if (mHostFiltersArray.Length() > 0) { |
|
1355 mHostFiltersArray.Clear(); |
|
1356 } |
|
1357 |
|
1358 if (!filters) |
|
1359 return; // fail silently... |
|
1360 |
|
1361 // |
|
1362 // filter = ( host | domain | ipaddr ["/" mask] ) [":" port] |
|
1363 // filters = filter *( "," LWS filter) |
|
1364 // |
|
1365 // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string |
|
1366 mFilterLocalHosts = false; |
|
1367 while (*filters) { |
|
1368 // skip over spaces and , |
|
1369 while (*filters && (*filters == ',' || IS_ASCII_SPACE(*filters))) |
|
1370 filters++; |
|
1371 |
|
1372 const char *starthost = filters; |
|
1373 const char *endhost = filters + 1; // at least that... |
|
1374 const char *portLocation = 0; |
|
1375 const char *maskLocation = 0; |
|
1376 |
|
1377 while (*endhost && (*endhost != ',' && !IS_ASCII_SPACE(*endhost))) { |
|
1378 if (*endhost == ':') |
|
1379 portLocation = endhost; |
|
1380 else if (*endhost == '/') |
|
1381 maskLocation = endhost; |
|
1382 else if (*endhost == ']') // IPv6 address literals |
|
1383 portLocation = 0; |
|
1384 endhost++; |
|
1385 } |
|
1386 |
|
1387 filters = endhost; // advance iterator up front |
|
1388 |
|
1389 // locate end of host |
|
1390 const char *end = maskLocation ? maskLocation : |
|
1391 portLocation ? portLocation : |
|
1392 endhost; |
|
1393 |
|
1394 nsAutoCString str(starthost, end - starthost); |
|
1395 |
|
1396 // If the current host filter is "<local>", then all local (i.e. |
|
1397 // no dots in the hostname) hosts should bypass the proxy |
|
1398 if (str.EqualsIgnoreCase("<local>")) { |
|
1399 mFilterLocalHosts = true; |
|
1400 LOG(("loaded filter for local hosts " |
|
1401 "(plain host names, no dots)\n")); |
|
1402 // Continue to next host filter; |
|
1403 continue; |
|
1404 } |
|
1405 |
|
1406 // For all other host filters, create HostInfo object and add to list |
|
1407 HostInfo *hinfo = new HostInfo(); |
|
1408 hinfo->port = portLocation ? atoi(portLocation + 1) : 0; |
|
1409 |
|
1410 PRNetAddr addr; |
|
1411 if (PR_StringToNetAddr(str.get(), &addr) == PR_SUCCESS) { |
|
1412 hinfo->is_ipaddr = true; |
|
1413 hinfo->ip.family = PR_AF_INET6; // we always store address as IPv6 |
|
1414 hinfo->ip.mask_len = maskLocation ? atoi(maskLocation + 1) : 128; |
|
1415 |
|
1416 if (hinfo->ip.mask_len == 0) { |
|
1417 NS_WARNING("invalid mask"); |
|
1418 goto loser; |
|
1419 } |
|
1420 |
|
1421 if (addr.raw.family == PR_AF_INET) { |
|
1422 // convert to IPv4-mapped address |
|
1423 PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr); |
|
1424 // adjust mask_len accordingly |
|
1425 if (hinfo->ip.mask_len <= 32) |
|
1426 hinfo->ip.mask_len += 96; |
|
1427 } |
|
1428 else if (addr.raw.family == PR_AF_INET6) { |
|
1429 // copy the address |
|
1430 memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr)); |
|
1431 } |
|
1432 else { |
|
1433 NS_WARNING("unknown address family"); |
|
1434 goto loser; |
|
1435 } |
|
1436 |
|
1437 // apply mask to IPv6 address |
|
1438 proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len); |
|
1439 } |
|
1440 else { |
|
1441 uint32_t startIndex, endIndex; |
|
1442 if (str.First() == '*') |
|
1443 startIndex = 1; // *.domain -> .domain |
|
1444 else |
|
1445 startIndex = 0; |
|
1446 endIndex = (portLocation ? portLocation : endhost) - starthost; |
|
1447 |
|
1448 hinfo->is_ipaddr = false; |
|
1449 hinfo->name.host = ToNewCString(Substring(str, startIndex, endIndex)); |
|
1450 |
|
1451 if (!hinfo->name.host) |
|
1452 goto loser; |
|
1453 |
|
1454 hinfo->name.host_len = endIndex - startIndex; |
|
1455 } |
|
1456 |
|
1457 //#define DEBUG_DUMP_FILTERS |
|
1458 #ifdef DEBUG_DUMP_FILTERS |
|
1459 printf("loaded filter[%u]:\n", mHostFiltersArray.Length()); |
|
1460 printf(" is_ipaddr = %u\n", hinfo->is_ipaddr); |
|
1461 printf(" port = %u\n", hinfo->port); |
|
1462 if (hinfo->is_ipaddr) { |
|
1463 printf(" ip.family = %x\n", hinfo->ip.family); |
|
1464 printf(" ip.mask_len = %u\n", hinfo->ip.mask_len); |
|
1465 |
|
1466 PRNetAddr netAddr; |
|
1467 PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr); |
|
1468 memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr)); |
|
1469 |
|
1470 char buf[256]; |
|
1471 PR_NetAddrToString(&netAddr, buf, sizeof(buf)); |
|
1472 |
|
1473 printf(" ip.addr = %s\n", buf); |
|
1474 } |
|
1475 else { |
|
1476 printf(" name.host = %s\n", hinfo->name.host); |
|
1477 } |
|
1478 #endif |
|
1479 |
|
1480 mHostFiltersArray.AppendElement(hinfo); |
|
1481 hinfo = nullptr; |
|
1482 loser: |
|
1483 delete hinfo; |
|
1484 } |
|
1485 } |
|
1486 |
|
1487 nsresult |
|
1488 nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info) |
|
1489 { |
|
1490 NS_PRECONDITION(uri, "URI is null"); |
|
1491 NS_PRECONDITION(info, "info is null"); |
|
1492 |
|
1493 nsresult rv; |
|
1494 |
|
1495 rv = uri->GetScheme(info->scheme); |
|
1496 if (NS_FAILED(rv)) |
|
1497 return rv; |
|
1498 |
|
1499 nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv); |
|
1500 if (NS_FAILED(rv)) |
|
1501 return rv; |
|
1502 |
|
1503 nsCOMPtr<nsIProtocolHandler> handler; |
|
1504 rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler)); |
|
1505 if (NS_FAILED(rv)) |
|
1506 return rv; |
|
1507 |
|
1508 rv = handler->GetProtocolFlags(&info->flags); |
|
1509 if (NS_FAILED(rv)) |
|
1510 return rv; |
|
1511 |
|
1512 rv = handler->GetDefaultPort(&info->defaultPort); |
|
1513 return rv; |
|
1514 } |
|
1515 |
|
1516 nsresult |
|
1517 nsProtocolProxyService::NewProxyInfo_Internal(const char *aType, |
|
1518 const nsACString &aHost, |
|
1519 int32_t aPort, |
|
1520 const nsACString &aUsername, |
|
1521 const nsACString &aPassword, |
|
1522 uint32_t aFlags, |
|
1523 uint32_t aFailoverTimeout, |
|
1524 nsIProxyInfo *aFailoverProxy, |
|
1525 uint32_t aResolveFlags, |
|
1526 nsIProxyInfo **aResult) |
|
1527 { |
|
1528 if (aPort <= 0) |
|
1529 aPort = -1; |
|
1530 |
|
1531 nsCOMPtr<nsProxyInfo> failover; |
|
1532 if (aFailoverProxy) { |
|
1533 failover = do_QueryInterface(aFailoverProxy); |
|
1534 NS_ENSURE_ARG(failover); |
|
1535 } |
|
1536 |
|
1537 nsProxyInfo *proxyInfo = new nsProxyInfo(); |
|
1538 if (!proxyInfo) |
|
1539 return NS_ERROR_OUT_OF_MEMORY; |
|
1540 |
|
1541 proxyInfo->mType = aType; |
|
1542 proxyInfo->mHost = aHost; |
|
1543 proxyInfo->mPort = aPort; |
|
1544 proxyInfo->mUsername = aUsername; |
|
1545 proxyInfo->mPassword = aPassword; |
|
1546 proxyInfo->mFlags = aFlags; |
|
1547 proxyInfo->mResolveFlags = aResolveFlags; |
|
1548 proxyInfo->mTimeout = aFailoverTimeout == UINT32_MAX |
|
1549 ? mFailedProxyTimeout : aFailoverTimeout; |
|
1550 failover.swap(proxyInfo->mNext); |
|
1551 |
|
1552 NS_ADDREF(*aResult = proxyInfo); |
|
1553 return NS_OK; |
|
1554 } |
|
1555 |
|
1556 nsresult |
|
1557 nsProtocolProxyService::Resolve_Internal(nsIChannel *channel, |
|
1558 const nsProtocolInfo &info, |
|
1559 uint32_t flags, |
|
1560 bool *usePACThread, |
|
1561 nsIProxyInfo **result) |
|
1562 { |
|
1563 NS_ENSURE_ARG_POINTER(channel); |
|
1564 nsresult rv = SetupPACThread(); |
|
1565 if (NS_FAILED(rv)) |
|
1566 return rv; |
|
1567 |
|
1568 *usePACThread = false; |
|
1569 *result = nullptr; |
|
1570 |
|
1571 if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) |
|
1572 return NS_OK; // Can't proxy this (filters may not override) |
|
1573 |
|
1574 nsCOMPtr<nsIURI> uri; |
|
1575 channel->GetURI(getter_AddRefs(uri)); |
|
1576 |
|
1577 // See bug #586908. |
|
1578 // Avoid endless loop if |uri| is the current PAC-URI. Returning OK |
|
1579 // here means that we will not use a proxy for this connection. |
|
1580 if (mPACMan && mPACMan->IsPACURI(uri)) |
|
1581 return NS_OK; |
|
1582 |
|
1583 bool mainThreadOnly; |
|
1584 if (mSystemProxySettings && |
|
1585 mProxyConfig == PROXYCONFIG_SYSTEM && |
|
1586 NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && |
|
1587 !mainThreadOnly) { |
|
1588 *usePACThread = true; |
|
1589 return NS_OK; |
|
1590 } |
|
1591 |
|
1592 if (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM) { |
|
1593 // If the system proxy setting implementation is not threadsafe (e.g |
|
1594 // linux gconf), we'll do it inline here. Such implementations promise |
|
1595 // not to block |
|
1596 |
|
1597 nsAutoCString PACURI; |
|
1598 nsAutoCString pacString; |
|
1599 |
|
1600 if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) && |
|
1601 !PACURI.IsEmpty()) { |
|
1602 // There is a PAC URI configured. If it is unchanged, then |
|
1603 // just execute the PAC thread. If it is changed then load |
|
1604 // the new value |
|
1605 |
|
1606 if (mPACMan && mPACMan->IsPACURI(PACURI)) { |
|
1607 // unchanged |
|
1608 *usePACThread = true; |
|
1609 return NS_OK; |
|
1610 } |
|
1611 |
|
1612 ConfigureFromPAC(PACURI, false); |
|
1613 return NS_OK; |
|
1614 } |
|
1615 |
|
1616 nsAutoCString spec; |
|
1617 nsAutoCString host; |
|
1618 nsAutoCString scheme; |
|
1619 int32_t port = -1; |
|
1620 |
|
1621 uri->GetAsciiSpec(spec); |
|
1622 uri->GetAsciiHost(host); |
|
1623 uri->GetScheme(scheme); |
|
1624 uri->GetPort(&port); |
|
1625 |
|
1626 // now try the system proxy settings for this particular url |
|
1627 if (NS_SUCCEEDED(mSystemProxySettings-> |
|
1628 GetProxyForURI(spec, scheme, host, port, |
|
1629 pacString))) { |
|
1630 ProcessPACString(pacString, 0, result); |
|
1631 return NS_OK; |
|
1632 } |
|
1633 } |
|
1634 |
|
1635 // if proxies are enabled and this host:port combo is supposed to use a |
|
1636 // proxy, check for a proxy. |
|
1637 if (mProxyConfig == PROXYCONFIG_DIRECT || |
|
1638 (mProxyConfig == PROXYCONFIG_MANUAL && |
|
1639 !CanUseProxy(uri, info.defaultPort))) |
|
1640 return NS_OK; |
|
1641 |
|
1642 // Proxy auto config magic... |
|
1643 if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) { |
|
1644 // Do not query PAC now. |
|
1645 *usePACThread = true; |
|
1646 return NS_OK; |
|
1647 } |
|
1648 |
|
1649 // If we aren't in manual proxy configuration mode then we don't |
|
1650 // want to honor any manual specific prefs that might be still set |
|
1651 if (mProxyConfig != PROXYCONFIG_MANUAL) |
|
1652 return NS_OK; |
|
1653 |
|
1654 // proxy info values for manual configuration mode |
|
1655 const char *type = nullptr; |
|
1656 const nsACString *host = nullptr; |
|
1657 int32_t port = -1; |
|
1658 |
|
1659 uint32_t proxyFlags = 0; |
|
1660 |
|
1661 if ((flags & RESOLVE_PREFER_SOCKS_PROXY) && |
|
1662 !mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { |
|
1663 host = &mSOCKSProxyHost; |
|
1664 if (mSOCKSProxyVersion == 4) |
|
1665 type = kProxyType_SOCKS4; |
|
1666 else |
|
1667 type = kProxyType_SOCKS; |
|
1668 port = mSOCKSProxyPort; |
|
1669 if (mSOCKSProxyRemoteDNS) |
|
1670 proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; |
|
1671 } |
|
1672 else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) && |
|
1673 !mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0) { |
|
1674 host = &mHTTPSProxyHost; |
|
1675 type = kProxyType_HTTP; |
|
1676 port = mHTTPSProxyPort; |
|
1677 } |
|
1678 else if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 && |
|
1679 ((flags & RESOLVE_IGNORE_URI_SCHEME) || |
|
1680 info.scheme.EqualsLiteral("http"))) { |
|
1681 host = &mHTTPProxyHost; |
|
1682 type = kProxyType_HTTP; |
|
1683 port = mHTTPProxyPort; |
|
1684 } |
|
1685 else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 && |
|
1686 !(flags & RESOLVE_IGNORE_URI_SCHEME) && |
|
1687 info.scheme.EqualsLiteral("https")) { |
|
1688 host = &mHTTPSProxyHost; |
|
1689 type = kProxyType_HTTP; |
|
1690 port = mHTTPSProxyPort; |
|
1691 } |
|
1692 else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 && |
|
1693 !(flags & RESOLVE_IGNORE_URI_SCHEME) && |
|
1694 info.scheme.EqualsLiteral("ftp")) { |
|
1695 host = &mFTPProxyHost; |
|
1696 type = kProxyType_HTTP; |
|
1697 port = mFTPProxyPort; |
|
1698 } |
|
1699 else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { |
|
1700 host = &mSOCKSProxyHost; |
|
1701 if (mSOCKSProxyVersion == 4) |
|
1702 type = kProxyType_SOCKS4; |
|
1703 else |
|
1704 type = kProxyType_SOCKS; |
|
1705 port = mSOCKSProxyPort; |
|
1706 if (mSOCKSProxyRemoteDNS) |
|
1707 proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; |
|
1708 } |
|
1709 |
|
1710 if (type) { |
|
1711 rv = NewProxyInfo_Internal(type, *host, port, |
|
1712 mSOCKSProxyUsername, mSOCKSProxyPassword, |
|
1713 proxyFlags, UINT32_MAX, nullptr, flags, |
|
1714 result); |
|
1715 if (NS_FAILED(rv)) |
|
1716 return rv; |
|
1717 } |
|
1718 |
|
1719 return NS_OK; |
|
1720 } |
|
1721 |
|
1722 void |
|
1723 nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy) |
|
1724 { |
|
1725 // Disable Prefetch in the DNS service if a proxy is in use. |
|
1726 if (!aProxy) |
|
1727 return; |
|
1728 |
|
1729 nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy); |
|
1730 if (!pi || |
|
1731 !pi->mType || |
|
1732 pi->mType == kProxyType_DIRECT) |
|
1733 return; |
|
1734 |
|
1735 nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); |
|
1736 if (!dns) |
|
1737 return; |
|
1738 nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns); |
|
1739 if (!pdns) |
|
1740 return; |
|
1741 |
|
1742 // We lose the prefetch optimization for the life of the dns service. |
|
1743 pdns->SetPrefetchEnabled(false); |
|
1744 } |
|
1745 |
|
1746 void |
|
1747 nsProtocolProxyService::ApplyFilters(nsIChannel *channel, const nsProtocolInfo &info, |
|
1748 nsIProxyInfo **list) |
|
1749 { |
|
1750 if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) |
|
1751 return; |
|
1752 |
|
1753 // We prune the proxy list prior to invoking each filter. This may be |
|
1754 // somewhat inefficient, but it seems like a good idea since we want each |
|
1755 // filter to "see" a valid proxy list. |
|
1756 |
|
1757 nsresult rv; |
|
1758 nsCOMPtr<nsIProxyInfo> result; |
|
1759 |
|
1760 for (FilterLink *iter = mFilters; iter; iter = iter->next) { |
|
1761 PruneProxyInfo(info, list); |
|
1762 if (!!iter->filter) { |
|
1763 nsCOMPtr<nsIURI> uri; |
|
1764 channel->GetURI(getter_AddRefs(uri)); |
|
1765 if (!!uri) { |
|
1766 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel); |
|
1767 nsCOMPtr<nsIURI> proxyURI = nullptr; |
|
1768 if (!!httpChannel) { |
|
1769 httpChannel->GetProxyURI(getter_AddRefs(proxyURI)); |
|
1770 } |
|
1771 rv = iter->filter->ApplyFilter(this, proxyURI ? proxyURI : uri, *list, |
|
1772 getter_AddRefs(result)); |
|
1773 } |
|
1774 } else if (!!iter->channelFilter) { |
|
1775 rv = iter->channelFilter->ApplyFilter(this, channel, *list, |
|
1776 getter_AddRefs(result)); |
|
1777 } |
|
1778 if (NS_FAILED(rv)) |
|
1779 continue; |
|
1780 result.swap(*list); |
|
1781 } |
|
1782 |
|
1783 PruneProxyInfo(info, list); |
|
1784 } |
|
1785 |
|
1786 void |
|
1787 nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info, |
|
1788 nsIProxyInfo **list) |
|
1789 { |
|
1790 if (!*list) |
|
1791 return; |
|
1792 nsProxyInfo *head = nullptr; |
|
1793 CallQueryInterface(*list, &head); |
|
1794 if (!head) { |
|
1795 NS_NOTREACHED("nsIProxyInfo must QI to nsProxyInfo"); |
|
1796 return; |
|
1797 } |
|
1798 NS_RELEASE(*list); |
|
1799 |
|
1800 // Pruning of disabled proxies works like this: |
|
1801 // - If all proxies are disabled, return the full list |
|
1802 // - Otherwise, remove the disabled proxies. |
|
1803 // |
|
1804 // Pruning of disallowed proxies works like this: |
|
1805 // - If the protocol handler disallows the proxy, then we disallow it. |
|
1806 |
|
1807 // Start by removing all disallowed proxies if required: |
|
1808 if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) { |
|
1809 nsProxyInfo *last = nullptr, *iter = head; |
|
1810 while (iter) { |
|
1811 if (iter->Type() == kProxyType_HTTP) { |
|
1812 // reject! |
|
1813 if (last) |
|
1814 last->mNext = iter->mNext; |
|
1815 else |
|
1816 head = iter->mNext; |
|
1817 nsProxyInfo *next = iter->mNext; |
|
1818 iter->mNext = nullptr; |
|
1819 iter->Release(); |
|
1820 iter = next; |
|
1821 } else { |
|
1822 last = iter; |
|
1823 iter = iter->mNext; |
|
1824 } |
|
1825 } |
|
1826 if (!head) |
|
1827 return; |
|
1828 } |
|
1829 |
|
1830 // Now, scan to see if all remaining proxies are disabled. If so, then |
|
1831 // we'll just bail and return them all. Otherwise, we'll go and prune the |
|
1832 // disabled ones. |
|
1833 |
|
1834 bool allDisabled = true; |
|
1835 |
|
1836 nsProxyInfo *iter; |
|
1837 for (iter = head; iter; iter = iter->mNext) { |
|
1838 if (!IsProxyDisabled(iter)) { |
|
1839 allDisabled = false; |
|
1840 break; |
|
1841 } |
|
1842 } |
|
1843 |
|
1844 if (allDisabled) |
|
1845 LOG(("All proxies are disabled, so trying all again")); |
|
1846 else { |
|
1847 // remove any disabled proxies. |
|
1848 nsProxyInfo *last = nullptr; |
|
1849 for (iter = head; iter; ) { |
|
1850 if (IsProxyDisabled(iter)) { |
|
1851 // reject! |
|
1852 nsProxyInfo *reject = iter; |
|
1853 |
|
1854 iter = iter->mNext; |
|
1855 if (last) |
|
1856 last->mNext = iter; |
|
1857 else |
|
1858 head = iter; |
|
1859 |
|
1860 reject->mNext = nullptr; |
|
1861 NS_RELEASE(reject); |
|
1862 continue; |
|
1863 } |
|
1864 |
|
1865 // since we are about to use this proxy, make sure it is not on |
|
1866 // the disabled proxy list. we'll add it back to that list if |
|
1867 // we have to (in GetFailoverForProxy). |
|
1868 // |
|
1869 // XXX(darin): It might be better to do this as a final pass. |
|
1870 // |
|
1871 EnableProxy(iter); |
|
1872 |
|
1873 last = iter; |
|
1874 iter = iter->mNext; |
|
1875 } |
|
1876 } |
|
1877 |
|
1878 // if only DIRECT was specified then return no proxy info, and we're done. |
|
1879 if (head && !head->mNext && head->mType == kProxyType_DIRECT) |
|
1880 NS_RELEASE(head); |
|
1881 |
|
1882 *list = head; // Transfer ownership |
|
1883 } |