1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsProtocolProxyService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1883 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim:set ts=4 sw=4 sts=4 et: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/ArrayUtils.h" 1.11 +#include "mozilla/Attributes.h" 1.12 + 1.13 +#include "nsProtocolProxyService.h" 1.14 +#include "nsProxyInfo.h" 1.15 +#include "nsIClassInfoImpl.h" 1.16 +#include "nsIIOService.h" 1.17 +#include "nsIObserverService.h" 1.18 +#include "nsIProtocolHandler.h" 1.19 +#include "nsIProtocolProxyCallback.h" 1.20 +#include "nsIChannel.h" 1.21 +#include "nsICancelable.h" 1.22 +#include "nsIDNSService.h" 1.23 +#include "nsPIDNSService.h" 1.24 +#include "nsIPrefService.h" 1.25 +#include "nsIPrefBranch.h" 1.26 +#include "nsThreadUtils.h" 1.27 +#include "nsString.h" 1.28 +#include "nsNetUtil.h" 1.29 +#include "nsNetCID.h" 1.30 +#include "prnetdb.h" 1.31 +#include "nsPACMan.h" 1.32 +#include "nsProxyRelease.h" 1.33 +#include "mozilla/Mutex.h" 1.34 +#include "mozilla/CondVar.h" 1.35 +#include "nsISystemProxySettings.h" 1.36 + 1.37 +//---------------------------------------------------------------------------- 1.38 + 1.39 +namespace mozilla { 1.40 + extern const char kProxyType_HTTP[]; 1.41 + extern const char kProxyType_SOCKS[]; 1.42 + extern const char kProxyType_SOCKS4[]; 1.43 + extern const char kProxyType_SOCKS5[]; 1.44 + extern const char kProxyType_DIRECT[]; 1.45 +} 1.46 + 1.47 +using namespace mozilla; 1.48 + 1.49 +#include "prlog.h" 1.50 +#if defined(PR_LOGGING) 1.51 +#endif 1.52 +#undef LOG 1.53 +#define LOG(args) PR_LOG(net::GetProxyLog(), PR_LOG_DEBUG, args) 1.54 + 1.55 +//---------------------------------------------------------------------------- 1.56 + 1.57 +#define PROXY_PREF_BRANCH "network.proxy" 1.58 +#define PROXY_PREF(x) PROXY_PREF_BRANCH "." x 1.59 + 1.60 +#define WPAD_URL "http://wpad/wpad.dat" 1.61 + 1.62 +//---------------------------------------------------------------------------- 1.63 + 1.64 +// This structure is intended to be allocated on the stack 1.65 +struct nsProtocolInfo { 1.66 + nsAutoCString scheme; 1.67 + uint32_t flags; 1.68 + int32_t defaultPort; 1.69 +}; 1.70 + 1.71 +//---------------------------------------------------------------------------- 1.72 + 1.73 +// The nsPACManCallback portion of this implementation should be run 1.74 +// on the main thread - so call nsPACMan::AsyncGetProxyForChannel() with 1.75 +// a true mainThreadResponse parameter. 1.76 +class nsAsyncResolveRequest MOZ_FINAL : public nsIRunnable 1.77 + , public nsPACManCallback 1.78 + , public nsICancelable 1.79 +{ 1.80 +public: 1.81 + NS_DECL_THREADSAFE_ISUPPORTS 1.82 + 1.83 + nsAsyncResolveRequest(nsProtocolProxyService *pps, nsIChannel *channel, 1.84 + uint32_t aResolveFlags, 1.85 + nsIProtocolProxyCallback *callback) 1.86 + : mStatus(NS_OK) 1.87 + , mDispatched(false) 1.88 + , mResolveFlags(aResolveFlags) 1.89 + , mPPS(pps) 1.90 + , mXPComPPS(pps) 1.91 + , mChannel(channel) 1.92 + , mCallback(callback) 1.93 + { 1.94 + NS_ASSERTION(mCallback, "null callback"); 1.95 + } 1.96 + 1.97 + ~nsAsyncResolveRequest() 1.98 + { 1.99 + if (!NS_IsMainThread()) { 1.100 + // these xpcom pointers might need to be proxied back to the 1.101 + // main thread to delete safely, but if this request had its 1.102 + // callbacks called normally they will all be null and this is a nop 1.103 + 1.104 + nsCOMPtr<nsIThread> mainThread; 1.105 + NS_GetMainThread(getter_AddRefs(mainThread)); 1.106 + 1.107 + if (mChannel) { 1.108 + nsIChannel *forgettable; 1.109 + mChannel.forget(&forgettable); 1.110 + NS_ProxyRelease(mainThread, forgettable, false); 1.111 + } 1.112 + 1.113 + if (mCallback) { 1.114 + nsIProtocolProxyCallback *forgettable; 1.115 + mCallback.forget(&forgettable); 1.116 + NS_ProxyRelease(mainThread, forgettable, false); 1.117 + } 1.118 + 1.119 + if (mProxyInfo) { 1.120 + nsIProxyInfo *forgettable; 1.121 + mProxyInfo.forget(&forgettable); 1.122 + NS_ProxyRelease(mainThread, forgettable, false); 1.123 + } 1.124 + 1.125 + if (mXPComPPS) { 1.126 + nsIProtocolProxyService *forgettable; 1.127 + mXPComPPS.forget(&forgettable); 1.128 + NS_ProxyRelease(mainThread, forgettable, false); 1.129 + } 1.130 + } 1.131 + } 1.132 + 1.133 + void SetResult(nsresult status, nsIProxyInfo *pi) 1.134 + { 1.135 + mStatus = status; 1.136 + mProxyInfo = pi; 1.137 + } 1.138 + 1.139 + NS_IMETHOD Run() 1.140 + { 1.141 + if (mCallback) 1.142 + DoCallback(); 1.143 + return NS_OK; 1.144 + } 1.145 + 1.146 + NS_IMETHOD Cancel(nsresult reason) 1.147 + { 1.148 + NS_ENSURE_ARG(NS_FAILED(reason)); 1.149 + 1.150 + // If we've already called DoCallback then, nothing more to do. 1.151 + if (!mCallback) 1.152 + return NS_OK; 1.153 + 1.154 + SetResult(reason, nullptr); 1.155 + return DispatchCallback(); 1.156 + } 1.157 + 1.158 + nsresult DispatchCallback() 1.159 + { 1.160 + if (mDispatched) // Only need to dispatch once 1.161 + return NS_OK; 1.162 + 1.163 + nsresult rv = NS_DispatchToCurrentThread(this); 1.164 + if (NS_FAILED(rv)) 1.165 + NS_WARNING("unable to dispatch callback event"); 1.166 + else { 1.167 + mDispatched = true; 1.168 + return NS_OK; 1.169 + } 1.170 + 1.171 + mCallback = nullptr; // break possible reference cycle 1.172 + return rv; 1.173 + } 1.174 + 1.175 +private: 1.176 + 1.177 + // Called asynchronously, so we do not need to post another PLEvent 1.178 + // before calling DoCallback. 1.179 + void OnQueryComplete(nsresult status, 1.180 + const nsCString &pacString, 1.181 + const nsCString &newPACURL) 1.182 + { 1.183 + // If we've already called DoCallback then, nothing more to do. 1.184 + if (!mCallback) 1.185 + return; 1.186 + 1.187 + // Provided we haven't been canceled... 1.188 + if (mStatus == NS_OK) { 1.189 + mStatus = status; 1.190 + mPACString = pacString; 1.191 + mPACURL = newPACURL; 1.192 + } 1.193 + 1.194 + // In the cancelation case, we may still have another PLEvent in 1.195 + // the queue that wants to call DoCallback. No need to wait for 1.196 + // it, just run the callback now. 1.197 + DoCallback(); 1.198 + } 1.199 + 1.200 + void DoCallback() 1.201 + { 1.202 + if (mStatus == NS_ERROR_NOT_AVAILABLE && !mProxyInfo) { 1.203 + // If the PAC service is not avail (e.g. failed pac load 1.204 + // or shutdown) then we will be going direct. Make that 1.205 + // mapping now so that any filters are still applied. 1.206 + mPACString = NS_LITERAL_CSTRING("DIRECT;"); 1.207 + mStatus = NS_OK; 1.208 + } 1.209 + 1.210 + // Generate proxy info from the PAC string if appropriate 1.211 + if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty()) { 1.212 + mPPS->ProcessPACString(mPACString, mResolveFlags, 1.213 + getter_AddRefs(mProxyInfo)); 1.214 + nsCOMPtr<nsIURI> uri; 1.215 + mChannel->GetURI(getter_AddRefs(uri)); 1.216 + 1.217 + // Now apply proxy filters 1.218 + nsProtocolInfo info; 1.219 + mStatus = mPPS->GetProtocolInfo(uri, &info); 1.220 + if (NS_SUCCEEDED(mStatus)) 1.221 + mPPS->ApplyFilters(mChannel, info, mProxyInfo); 1.222 + else 1.223 + mProxyInfo = nullptr; 1.224 + 1.225 + LOG(("pac thread callback %s\n", mPACString.get())); 1.226 + if (NS_SUCCEEDED(mStatus)) 1.227 + mPPS->MaybeDisableDNSPrefetch(mProxyInfo); 1.228 + mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus); 1.229 + } 1.230 + else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) { 1.231 + LOG(("pac thread callback indicates new pac file load\n")); 1.232 + 1.233 + // trigger load of new pac url 1.234 + nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false); 1.235 + if (NS_SUCCEEDED(rv)) { 1.236 + // now that the load is triggered, we can resubmit the query 1.237 + nsRefPtr<nsAsyncResolveRequest> newRequest = 1.238 + new nsAsyncResolveRequest(mPPS, mChannel, mResolveFlags, mCallback); 1.239 + rv = mPPS->mPACMan->AsyncGetProxyForChannel(mChannel, newRequest, true); 1.240 + } 1.241 + 1.242 + if (NS_FAILED(rv)) 1.243 + mCallback->OnProxyAvailable(this, mChannel, nullptr, rv); 1.244 + 1.245 + // do not call onproxyavailable() in SUCCESS case - the newRequest will 1.246 + // take care of that 1.247 + } 1.248 + else { 1.249 + LOG(("pac thread callback did not provide information %X\n", mStatus)); 1.250 + if (NS_SUCCEEDED(mStatus)) 1.251 + mPPS->MaybeDisableDNSPrefetch(mProxyInfo); 1.252 + mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus); 1.253 + } 1.254 + 1.255 + // We are on the main thread now and don't need these any more so 1.256 + // release them to avoid having to proxy them back to the main thread 1.257 + // in the dtor 1.258 + mCallback = nullptr; // in case the callback holds an owning ref to us 1.259 + mPPS = nullptr; 1.260 + mXPComPPS = nullptr; 1.261 + mChannel = nullptr; 1.262 + mProxyInfo = nullptr; 1.263 + } 1.264 + 1.265 +private: 1.266 + 1.267 + nsresult mStatus; 1.268 + nsCString mPACString; 1.269 + nsCString mPACURL; 1.270 + bool mDispatched; 1.271 + uint32_t mResolveFlags; 1.272 + 1.273 + nsProtocolProxyService *mPPS; 1.274 + nsCOMPtr<nsIProtocolProxyService> mXPComPPS; 1.275 + nsCOMPtr<nsIChannel> mChannel; 1.276 + nsCOMPtr<nsIProtocolProxyCallback> mCallback; 1.277 + nsCOMPtr<nsIProxyInfo> mProxyInfo; 1.278 +}; 1.279 + 1.280 +NS_IMPL_ISUPPORTS(nsAsyncResolveRequest, nsICancelable, nsIRunnable) 1.281 + 1.282 +//---------------------------------------------------------------------------- 1.283 + 1.284 +#define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t') 1.285 + 1.286 +// 1.287 +// apply mask to address (zeros out excluded bits). 1.288 +// 1.289 +// NOTE: we do the byte swapping here to minimize overall swapping. 1.290 +// 1.291 +static void 1.292 +proxy_MaskIPv6Addr(PRIPv6Addr &addr, uint16_t mask_len) 1.293 +{ 1.294 + if (mask_len == 128) 1.295 + return; 1.296 + 1.297 + if (mask_len > 96) { 1.298 + addr.pr_s6_addr32[3] = PR_htonl( 1.299 + PR_ntohl(addr.pr_s6_addr32[3]) & (~0L << (128 - mask_len))); 1.300 + } 1.301 + else if (mask_len > 64) { 1.302 + addr.pr_s6_addr32[3] = 0; 1.303 + addr.pr_s6_addr32[2] = PR_htonl( 1.304 + PR_ntohl(addr.pr_s6_addr32[2]) & (~0L << (96 - mask_len))); 1.305 + } 1.306 + else if (mask_len > 32) { 1.307 + addr.pr_s6_addr32[3] = 0; 1.308 + addr.pr_s6_addr32[2] = 0; 1.309 + addr.pr_s6_addr32[1] = PR_htonl( 1.310 + PR_ntohl(addr.pr_s6_addr32[1]) & (~0L << (64 - mask_len))); 1.311 + } 1.312 + else { 1.313 + addr.pr_s6_addr32[3] = 0; 1.314 + addr.pr_s6_addr32[2] = 0; 1.315 + addr.pr_s6_addr32[1] = 0; 1.316 + addr.pr_s6_addr32[0] = PR_htonl( 1.317 + PR_ntohl(addr.pr_s6_addr32[0]) & (~0L << (32 - mask_len))); 1.318 + } 1.319 +} 1.320 + 1.321 +static void 1.322 +proxy_GetStringPref(nsIPrefBranch *aPrefBranch, 1.323 + const char *aPref, 1.324 + nsCString &aResult) 1.325 +{ 1.326 + nsXPIDLCString temp; 1.327 + nsresult rv = aPrefBranch->GetCharPref(aPref, getter_Copies(temp)); 1.328 + if (NS_FAILED(rv)) 1.329 + aResult.Truncate(); 1.330 + else { 1.331 + aResult.Assign(temp); 1.332 + // all of our string prefs are hostnames, so we should remove any 1.333 + // whitespace characters that the user might have unknowingly entered. 1.334 + aResult.StripWhitespace(); 1.335 + } 1.336 +} 1.337 + 1.338 +static void 1.339 +proxy_GetIntPref(nsIPrefBranch *aPrefBranch, 1.340 + const char *aPref, 1.341 + int32_t &aResult) 1.342 +{ 1.343 + int32_t temp; 1.344 + nsresult rv = aPrefBranch->GetIntPref(aPref, &temp); 1.345 + if (NS_FAILED(rv)) 1.346 + aResult = -1; 1.347 + else 1.348 + aResult = temp; 1.349 +} 1.350 + 1.351 +static void 1.352 +proxy_GetBoolPref(nsIPrefBranch *aPrefBranch, 1.353 + const char *aPref, 1.354 + bool &aResult) 1.355 +{ 1.356 + bool temp; 1.357 + nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp); 1.358 + if (NS_FAILED(rv)) 1.359 + aResult = false; 1.360 + else 1.361 + aResult = temp; 1.362 +} 1.363 + 1.364 +//---------------------------------------------------------------------------- 1.365 + 1.366 +static const int32_t PROXYCONFIG_DIRECT4X = 3; 1.367 +static const int32_t PROXYCONFIG_COUNT = 6; 1.368 + 1.369 +NS_IMPL_ADDREF(nsProtocolProxyService) 1.370 +NS_IMPL_RELEASE(nsProtocolProxyService) 1.371 +NS_IMPL_CLASSINFO(nsProtocolProxyService, nullptr, nsIClassInfo::SINGLETON, 1.372 + NS_PROTOCOLPROXYSERVICE_CID) 1.373 +NS_IMPL_QUERY_INTERFACE_CI(nsProtocolProxyService, 1.374 + nsIProtocolProxyService, 1.375 + nsIProtocolProxyService2, 1.376 + nsIObserver) 1.377 +NS_IMPL_CI_INTERFACE_GETTER(nsProtocolProxyService, 1.378 + nsIProtocolProxyService, 1.379 + nsIProtocolProxyService2) 1.380 + 1.381 +nsProtocolProxyService::nsProtocolProxyService() 1.382 + : mFilterLocalHosts(false) 1.383 + , mFilters(nullptr) 1.384 + , mProxyConfig(PROXYCONFIG_DIRECT) 1.385 + , mHTTPProxyPort(-1) 1.386 + , mFTPProxyPort(-1) 1.387 + , mHTTPSProxyPort(-1) 1.388 + , mSOCKSProxyPort(-1) 1.389 + , mSOCKSProxyVersion(4) 1.390 + , mSOCKSProxyRemoteDNS(false) 1.391 + , mPACMan(nullptr) 1.392 + , mSessionStart(PR_Now()) 1.393 + , mFailedProxyTimeout(30 * 60) // 30 minute default 1.394 +{ 1.395 +} 1.396 + 1.397 +nsProtocolProxyService::~nsProtocolProxyService() 1.398 +{ 1.399 + // These should have been cleaned up in our Observe method. 1.400 + NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters == nullptr && 1.401 + mPACMan == nullptr, "what happened to xpcom-shutdown?"); 1.402 +} 1.403 + 1.404 +// nsProtocolProxyService methods 1.405 +nsresult 1.406 +nsProtocolProxyService::Init() 1.407 +{ 1.408 + // failure to access prefs is non-fatal 1.409 + nsCOMPtr<nsIPrefBranch> prefBranch = 1.410 + do_GetService(NS_PREFSERVICE_CONTRACTID); 1.411 + if (prefBranch) { 1.412 + // monitor proxy prefs 1.413 + prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false); 1.414 + 1.415 + // read all prefs 1.416 + PrefsChanged(prefBranch, nullptr); 1.417 + } 1.418 + 1.419 + // register for shutdown notification so we can clean ourselves up properly. 1.420 + nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); 1.421 + if (obs) 1.422 + obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); 1.423 + 1.424 + return NS_OK; 1.425 +} 1.426 + 1.427 +NS_IMETHODIMP 1.428 +nsProtocolProxyService::Observe(nsISupports *aSubject, 1.429 + const char *aTopic, 1.430 + const char16_t *aData) 1.431 +{ 1.432 + if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { 1.433 + // cleanup 1.434 + if (mHostFiltersArray.Length() > 0) { 1.435 + mHostFiltersArray.Clear(); 1.436 + } 1.437 + if (mFilters) { 1.438 + delete mFilters; 1.439 + mFilters = nullptr; 1.440 + } 1.441 + if (mPACMan) { 1.442 + mPACMan->Shutdown(); 1.443 + mPACMan = nullptr; 1.444 + } 1.445 + } 1.446 + else { 1.447 + NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0, 1.448 + "what is this random observer event?"); 1.449 + nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject); 1.450 + if (prefs) 1.451 + PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get()); 1.452 + } 1.453 + return NS_OK; 1.454 +} 1.455 + 1.456 +void 1.457 +nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch, 1.458 + const char *pref) 1.459 +{ 1.460 + nsresult rv = NS_OK; 1.461 + bool reloadPAC = false; 1.462 + nsXPIDLCString tempString; 1.463 + 1.464 + if (!pref || !strcmp(pref, PROXY_PREF("type"))) { 1.465 + int32_t type = -1; 1.466 + rv = prefBranch->GetIntPref(PROXY_PREF("type"), &type); 1.467 + if (NS_SUCCEEDED(rv)) { 1.468 + // bug 115720 - for ns4.x backwards compatibility 1.469 + if (type == PROXYCONFIG_DIRECT4X) { 1.470 + type = PROXYCONFIG_DIRECT; 1.471 + // Reset the type so that the dialog looks correct, and we 1.472 + // don't have to handle this case everywhere else 1.473 + // I'm paranoid about a loop of some sort - only do this 1.474 + // if we're enumerating all prefs, and ignore any error 1.475 + if (!pref) 1.476 + prefBranch->SetIntPref(PROXY_PREF("type"), type); 1.477 + } else if (type >= PROXYCONFIG_COUNT) { 1.478 + LOG(("unknown proxy type: %lu; assuming direct\n", type)); 1.479 + type = PROXYCONFIG_DIRECT; 1.480 + } 1.481 + mProxyConfig = type; 1.482 + reloadPAC = true; 1.483 + } 1.484 + 1.485 + if (mProxyConfig == PROXYCONFIG_SYSTEM) { 1.486 + mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); 1.487 + if (!mSystemProxySettings) 1.488 + mProxyConfig = PROXYCONFIG_DIRECT; 1.489 + ResetPACThread(); 1.490 + } else { 1.491 + if (mSystemProxySettings) { 1.492 + mSystemProxySettings = nullptr; 1.493 + ResetPACThread(); 1.494 + } 1.495 + } 1.496 + } 1.497 + 1.498 + if (!pref || !strcmp(pref, PROXY_PREF("http"))) 1.499 + proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost); 1.500 + 1.501 + if (!pref || !strcmp(pref, PROXY_PREF("http_port"))) 1.502 + proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort); 1.503 + 1.504 + if (!pref || !strcmp(pref, PROXY_PREF("ssl"))) 1.505 + proxy_GetStringPref(prefBranch, PROXY_PREF("ssl"), mHTTPSProxyHost); 1.506 + 1.507 + if (!pref || !strcmp(pref, PROXY_PREF("ssl_port"))) 1.508 + proxy_GetIntPref(prefBranch, PROXY_PREF("ssl_port"), mHTTPSProxyPort); 1.509 + 1.510 + if (!pref || !strcmp(pref, PROXY_PREF("ftp"))) 1.511 + proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost); 1.512 + 1.513 + if (!pref || !strcmp(pref, PROXY_PREF("ftp_port"))) 1.514 + proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort); 1.515 + 1.516 + if (!pref || !strcmp(pref, PROXY_PREF("socks"))) 1.517 + proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyHost); 1.518 + 1.519 + if (!pref || !strcmp(pref, PROXY_PREF("socks_port"))) 1.520 + proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort); 1.521 + 1.522 + if (!pref || !strcmp(pref, PROXY_PREF("socks_username"))) 1.523 + proxy_GetStringPref(prefBranch, PROXY_PREF("socks_username"), mSOCKSProxyUsername); 1.524 + 1.525 + if (!pref || !strcmp(pref, PROXY_PREF("socks_password"))) 1.526 + proxy_GetStringPref(prefBranch, PROXY_PREF("socks_password"), mSOCKSProxyPassword); 1.527 + 1.528 + if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) { 1.529 + int32_t version; 1.530 + proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version); 1.531 + // make sure this preference value remains sane 1.532 + if (version == 5) 1.533 + mSOCKSProxyVersion = 5; 1.534 + else 1.535 + mSOCKSProxyVersion = 4; 1.536 + } 1.537 + 1.538 + if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns"))) 1.539 + proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"), 1.540 + mSOCKSProxyRemoteDNS); 1.541 + 1.542 + if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout"))) 1.543 + proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"), 1.544 + mFailedProxyTimeout); 1.545 + 1.546 + if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) { 1.547 + rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"), 1.548 + getter_Copies(tempString)); 1.549 + if (NS_SUCCEEDED(rv)) 1.550 + LoadHostFilters(tempString.get()); 1.551 + } 1.552 + 1.553 + // We're done if not using something that could give us a PAC URL 1.554 + // (PAC, WPAD or System) 1.555 + if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD && 1.556 + mProxyConfig != PROXYCONFIG_SYSTEM) 1.557 + return; 1.558 + 1.559 + // OK, we need to reload the PAC file if: 1.560 + // 1) network.proxy.type changed, or 1.561 + // 2) network.proxy.autoconfig_url changed and PAC is configured 1.562 + 1.563 + if (!pref || !strcmp(pref, PROXY_PREF("autoconfig_url"))) 1.564 + reloadPAC = true; 1.565 + 1.566 + if (reloadPAC) { 1.567 + tempString.Truncate(); 1.568 + if (mProxyConfig == PROXYCONFIG_PAC) { 1.569 + prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"), 1.570 + getter_Copies(tempString)); 1.571 + } else if (mProxyConfig == PROXYCONFIG_WPAD) { 1.572 + // We diverge from the WPAD spec here in that we don't walk the 1.573 + // hosts's FQDN, stripping components until we hit a TLD. Doing so 1.574 + // is dangerous in the face of an incomplete list of TLDs, and TLDs 1.575 + // get added over time. We could consider doing only a single 1.576 + // substitution of the first component, if that proves to help 1.577 + // compatibility. 1.578 + tempString.AssignLiteral(WPAD_URL); 1.579 + } else if (mSystemProxySettings) { 1.580 + // Get System Proxy settings if available 1.581 + mSystemProxySettings->GetPACURI(tempString); 1.582 + } 1.583 + if (!tempString.IsEmpty()) 1.584 + ConfigureFromPAC(tempString, false); 1.585 + } 1.586 +} 1.587 + 1.588 +bool 1.589 +nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort) 1.590 +{ 1.591 + if (mHostFiltersArray.Length() == 0) 1.592 + return true; 1.593 + 1.594 + int32_t port; 1.595 + nsAutoCString host; 1.596 + 1.597 + nsresult rv = aURI->GetAsciiHost(host); 1.598 + if (NS_FAILED(rv) || host.IsEmpty()) 1.599 + return false; 1.600 + 1.601 + rv = aURI->GetPort(&port); 1.602 + if (NS_FAILED(rv)) 1.603 + return false; 1.604 + if (port == -1) 1.605 + port = defaultPort; 1.606 + 1.607 + PRNetAddr addr; 1.608 + bool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS); 1.609 + 1.610 + PRIPv6Addr ipv6; 1.611 + if (is_ipaddr) { 1.612 + // convert parsed address to IPv6 1.613 + if (addr.raw.family == PR_AF_INET) { 1.614 + // convert to IPv4-mapped address 1.615 + PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6); 1.616 + } 1.617 + else if (addr.raw.family == PR_AF_INET6) { 1.618 + // copy the address 1.619 + memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr)); 1.620 + } 1.621 + else { 1.622 + NS_WARNING("unknown address family"); 1.623 + return true; // allow proxying 1.624 + } 1.625 + } 1.626 + 1.627 + // Don't use proxy for local hosts (plain hostname, no dots) 1.628 + if (!is_ipaddr && mFilterLocalHosts && (kNotFound == host.FindChar('.'))) { 1.629 + LOG(("Not using proxy for this local host [%s]!\n", host.get())); 1.630 + return false; // don't allow proxying 1.631 + } 1.632 + 1.633 + int32_t index = -1; 1.634 + while (++index < int32_t(mHostFiltersArray.Length())) { 1.635 + HostInfo *hinfo = mHostFiltersArray[index]; 1.636 + 1.637 + if (is_ipaddr != hinfo->is_ipaddr) 1.638 + continue; 1.639 + if (hinfo->port && hinfo->port != port) 1.640 + continue; 1.641 + 1.642 + if (is_ipaddr) { 1.643 + // generate masked version of target IPv6 address 1.644 + PRIPv6Addr masked; 1.645 + memcpy(&masked, &ipv6, sizeof(PRIPv6Addr)); 1.646 + proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len); 1.647 + 1.648 + // check for a match 1.649 + if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0) 1.650 + return false; // proxy disallowed 1.651 + } 1.652 + else { 1.653 + uint32_t host_len = host.Length(); 1.654 + uint32_t filter_host_len = hinfo->name.host_len; 1.655 + 1.656 + if (host_len >= filter_host_len) { 1.657 + // 1.658 + // compare last |filter_host_len| bytes of target hostname. 1.659 + // 1.660 + const char *host_tail = host.get() + host_len - filter_host_len; 1.661 + if (!PL_strncasecmp(host_tail, hinfo->name.host, filter_host_len)) 1.662 + return false; // proxy disallowed 1.663 + } 1.664 + } 1.665 + } 1.666 + return true; 1.667 +} 1.668 + 1.669 +// kProxyType\* may be referred to externally in 1.670 +// nsProxyInfo in order to compare by string pointer 1.671 +namespace mozilla { 1.672 +const char kProxyType_HTTP[] = "http"; 1.673 +const char kProxyType_PROXY[] = "proxy"; 1.674 +const char kProxyType_SOCKS[] = "socks"; 1.675 +const char kProxyType_SOCKS4[] = "socks4"; 1.676 +const char kProxyType_SOCKS5[] = "socks5"; 1.677 +const char kProxyType_DIRECT[] = "direct"; 1.678 +const char kProxyType_UNKNOWN[] = "unknown"; 1.679 +} 1.680 + 1.681 +const char * 1.682 +nsProtocolProxyService::ExtractProxyInfo(const char *start, 1.683 + uint32_t aResolveFlags, 1.684 + nsProxyInfo **result) 1.685 +{ 1.686 + *result = nullptr; 1.687 + uint32_t flags = 0; 1.688 + 1.689 + // see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl 1.690 + 1.691 + // find end of proxy info delimiter 1.692 + const char *end = start; 1.693 + while (*end && *end != ';') ++end; 1.694 + 1.695 + // find end of proxy type delimiter 1.696 + const char *sp = start; 1.697 + while (sp < end && *sp != ' ' && *sp != '\t') ++sp; 1.698 + 1.699 + uint32_t len = sp - start; 1.700 + const char *type = nullptr; 1.701 + switch (len) { 1.702 + case 5: 1.703 + if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) 1.704 + type = kProxyType_HTTP; 1.705 + else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) 1.706 + type = kProxyType_SOCKS4; // assume v4 for 4x compat 1.707 + break; 1.708 + case 6: 1.709 + if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0) 1.710 + type = kProxyType_DIRECT; 1.711 + else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0) 1.712 + type = kProxyType_SOCKS4; 1.713 + else if (PL_strncasecmp(start, kProxyType_SOCKS5, 6) == 0) 1.714 + // map "SOCKS5" to "socks" to match contract-id of registered 1.715 + // SOCKS-v5 socket provider. 1.716 + type = kProxyType_SOCKS; 1.717 + break; 1.718 + } 1.719 + if (type) { 1.720 + const char *host = nullptr, *hostEnd = nullptr; 1.721 + int32_t port = -1; 1.722 + 1.723 + // If it's a SOCKS5 proxy, do name resolution on the server side. 1.724 + // We could use this with SOCKS4a servers too, but they might not 1.725 + // support it. 1.726 + if (type == kProxyType_SOCKS || mSOCKSProxyRemoteDNS) 1.727 + flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; 1.728 + 1.729 + // extract host:port 1.730 + start = sp; 1.731 + while ((*start == ' ' || *start == '\t') && start < end) 1.732 + start++; 1.733 + 1.734 + // port defaults 1.735 + if (type == kProxyType_HTTP) 1.736 + port = 80; 1.737 + else 1.738 + port = 1080; 1.739 + 1.740 + nsProxyInfo *pi = new nsProxyInfo(); 1.741 + pi->mType = type; 1.742 + pi->mFlags = flags; 1.743 + pi->mResolveFlags = aResolveFlags; 1.744 + pi->mTimeout = mFailedProxyTimeout; 1.745 + 1.746 + // www.foo.com:8080 and http://www.foo.com:8080 1.747 + nsDependentCSubstring maybeURL(start, end - start); 1.748 + nsCOMPtr<nsIURI> pacURI; 1.749 + 1.750 + nsAutoCString urlHost; 1.751 + if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) && 1.752 + NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) && 1.753 + !urlHost.IsEmpty()) { 1.754 + // http://www.example.com:8080 1.755 + 1.756 + pi->mHost = urlHost; 1.757 + 1.758 + int32_t tPort; 1.759 + if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) { 1.760 + port = tPort; 1.761 + } 1.762 + pi->mPort = port; 1.763 + } 1.764 + else { 1.765 + // www.example.com:8080 1.766 + if (start < end) { 1.767 + host = start; 1.768 + hostEnd = strchr(host, ':'); 1.769 + if (!hostEnd || hostEnd > end) { 1.770 + hostEnd = end; 1.771 + // no port, so assume default 1.772 + } 1.773 + else { 1.774 + port = atoi(hostEnd + 1); 1.775 + } 1.776 + } 1.777 + // YES, it is ok to specify a null proxy host. 1.778 + if (host) { 1.779 + pi->mHost.Assign(host, hostEnd - host); 1.780 + pi->mPort = port; 1.781 + } 1.782 + } 1.783 + NS_ADDREF(*result = pi); 1.784 + } 1.785 + 1.786 + while (*end == ';' || *end == ' ' || *end == '\t') 1.787 + ++end; 1.788 + return end; 1.789 +} 1.790 + 1.791 +void 1.792 +nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key) 1.793 +{ 1.794 + key.AssignASCII(pi->mType); 1.795 + if (!pi->mHost.IsEmpty()) { 1.796 + key.Append(' '); 1.797 + key.Append(pi->mHost); 1.798 + key.Append(':'); 1.799 + key.AppendInt(pi->mPort); 1.800 + } 1.801 +} 1.802 + 1.803 +uint32_t 1.804 +nsProtocolProxyService::SecondsSinceSessionStart() 1.805 +{ 1.806 + PRTime now = PR_Now(); 1.807 + 1.808 + // get time elapsed since session start 1.809 + int64_t diff = now - mSessionStart; 1.810 + 1.811 + // convert microseconds to seconds 1.812 + diff /= PR_USEC_PER_SEC; 1.813 + 1.814 + // return converted 32 bit value 1.815 + return uint32_t(diff); 1.816 +} 1.817 + 1.818 +void 1.819 +nsProtocolProxyService::EnableProxy(nsProxyInfo *pi) 1.820 +{ 1.821 + nsAutoCString key; 1.822 + GetProxyKey(pi, key); 1.823 + mFailedProxies.Remove(key); 1.824 +} 1.825 + 1.826 +void 1.827 +nsProtocolProxyService::DisableProxy(nsProxyInfo *pi) 1.828 +{ 1.829 + nsAutoCString key; 1.830 + GetProxyKey(pi, key); 1.831 + 1.832 + uint32_t dsec = SecondsSinceSessionStart(); 1.833 + 1.834 + // Add timeout to interval (this is the time when the proxy can 1.835 + // be tried again). 1.836 + dsec += pi->mTimeout; 1.837 + 1.838 + // NOTE: The classic codebase would increase the timeout value 1.839 + // incrementally each time a subsequent failure occurred. 1.840 + // We could do the same, but it would require that we not 1.841 + // remove proxy entries in IsProxyDisabled or otherwise 1.842 + // change the way we are recording disabled proxies. 1.843 + // Simpler is probably better for now, and at least the 1.844 + // user can tune the timeout setting via preferences. 1.845 + 1.846 + LOG(("DisableProxy %s %d\n", key.get(), dsec)); 1.847 + 1.848 + // If this fails, oh well... means we don't have enough memory 1.849 + // to remember the failed proxy. 1.850 + mFailedProxies.Put(key, dsec); 1.851 +} 1.852 + 1.853 +bool 1.854 +nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi) 1.855 +{ 1.856 + nsAutoCString key; 1.857 + GetProxyKey(pi, key); 1.858 + 1.859 + uint32_t val; 1.860 + if (!mFailedProxies.Get(key, &val)) 1.861 + return false; 1.862 + 1.863 + uint32_t dsec = SecondsSinceSessionStart(); 1.864 + 1.865 + // if time passed has exceeded interval, then try proxy again. 1.866 + if (dsec > val) { 1.867 + mFailedProxies.Remove(key); 1.868 + return false; 1.869 + } 1.870 + 1.871 + return true; 1.872 +} 1.873 + 1.874 +nsresult 1.875 +nsProtocolProxyService::SetupPACThread() 1.876 +{ 1.877 + if (mPACMan) 1.878 + return NS_OK; 1.879 + 1.880 + mPACMan = new nsPACMan(); 1.881 + 1.882 + bool mainThreadOnly; 1.883 + nsresult rv; 1.884 + if (mSystemProxySettings && 1.885 + NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && 1.886 + !mainThreadOnly) { 1.887 + rv = mPACMan->Init(mSystemProxySettings); 1.888 + } 1.889 + else { 1.890 + rv = mPACMan->Init(nullptr); 1.891 + } 1.892 + 1.893 + if (NS_FAILED(rv)) 1.894 + mPACMan = nullptr; 1.895 + return rv; 1.896 +} 1.897 + 1.898 +nsresult 1.899 +nsProtocolProxyService::ResetPACThread() 1.900 +{ 1.901 + if (!mPACMan) 1.902 + return NS_OK; 1.903 + 1.904 + mPACMan->Shutdown(); 1.905 + mPACMan = nullptr; 1.906 + return SetupPACThread(); 1.907 +} 1.908 + 1.909 +nsresult 1.910 +nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec, 1.911 + bool forceReload) 1.912 +{ 1.913 + SetupPACThread(); 1.914 + 1.915 + if (mPACMan->IsPACURI(spec) && !forceReload) 1.916 + return NS_OK; 1.917 + 1.918 + mFailedProxies.Clear(); 1.919 + 1.920 + return mPACMan->LoadPACFromURI(spec); 1.921 +} 1.922 + 1.923 +void 1.924 +nsProtocolProxyService::ProcessPACString(const nsCString &pacString, 1.925 + uint32_t aResolveFlags, 1.926 + nsIProxyInfo **result) 1.927 +{ 1.928 + if (pacString.IsEmpty()) { 1.929 + *result = nullptr; 1.930 + return; 1.931 + } 1.932 + 1.933 + const char *proxies = pacString.get(); 1.934 + 1.935 + nsProxyInfo *pi = nullptr, *first = nullptr, *last = nullptr; 1.936 + while (*proxies) { 1.937 + proxies = ExtractProxyInfo(proxies, aResolveFlags, &pi); 1.938 + if (pi) { 1.939 + if (last) { 1.940 + NS_ASSERTION(last->mNext == nullptr, "leaking nsProxyInfo"); 1.941 + last->mNext = pi; 1.942 + } 1.943 + else 1.944 + first = pi; 1.945 + last = pi; 1.946 + } 1.947 + } 1.948 + *result = first; 1.949 +} 1.950 + 1.951 +// nsIProtocolProxyService2 1.952 +NS_IMETHODIMP 1.953 +nsProtocolProxyService::ReloadPAC() 1.954 +{ 1.955 + nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); 1.956 + if (!prefs) 1.957 + return NS_OK; 1.958 + 1.959 + int32_t type; 1.960 + nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type); 1.961 + if (NS_FAILED(rv)) 1.962 + return NS_OK; 1.963 + 1.964 + nsXPIDLCString pacSpec; 1.965 + if (type == PROXYCONFIG_PAC) 1.966 + prefs->GetCharPref(PROXY_PREF("autoconfig_url"), getter_Copies(pacSpec)); 1.967 + else if (type == PROXYCONFIG_WPAD) 1.968 + pacSpec.AssignLiteral(WPAD_URL); 1.969 + 1.970 + if (!pacSpec.IsEmpty()) 1.971 + ConfigureFromPAC(pacSpec, true); 1.972 + return NS_OK; 1.973 +} 1.974 + 1.975 +// When sync interface is removed this can go away too 1.976 +// The nsPACManCallback portion of this implementation should be run 1.977 +// off the main thread, because it uses a condvar for signaling and 1.978 +// the main thread is blocking on that condvar - 1.979 +// so call nsPACMan::AsyncGetProxyForChannel() with 1.980 +// a false mainThreadResponse parameter. 1.981 +class nsAsyncBridgeRequest MOZ_FINAL : public nsPACManCallback 1.982 +{ 1.983 + NS_DECL_THREADSAFE_ISUPPORTS 1.984 + 1.985 + nsAsyncBridgeRequest() 1.986 + : mMutex("nsDeprecatedCallback") 1.987 + , mCondVar(mMutex, "nsDeprecatedCallback") 1.988 + , mCompleted(false) 1.989 + { 1.990 + } 1.991 + 1.992 + void OnQueryComplete(nsresult status, 1.993 + const nsCString &pacString, 1.994 + const nsCString &newPACURL) 1.995 + { 1.996 + MutexAutoLock lock(mMutex); 1.997 + mCompleted = true; 1.998 + mStatus = status; 1.999 + mPACString = pacString; 1.1000 + mPACURL = newPACURL; 1.1001 + mCondVar.Notify(); 1.1002 + } 1.1003 + 1.1004 + void Lock() { mMutex.Lock(); } 1.1005 + void Unlock() { mMutex.Unlock(); } 1.1006 + void Wait() { mCondVar.Wait(PR_SecondsToInterval(3)); } 1.1007 + 1.1008 +private: 1.1009 + ~nsAsyncBridgeRequest() 1.1010 + { 1.1011 + } 1.1012 + 1.1013 + friend class nsProtocolProxyService; 1.1014 + 1.1015 + Mutex mMutex; 1.1016 + CondVar mCondVar; 1.1017 + 1.1018 + nsresult mStatus; 1.1019 + nsCString mPACString; 1.1020 + nsCString mPACURL; 1.1021 + bool mCompleted; 1.1022 +}; 1.1023 +NS_IMPL_ISUPPORTS0(nsAsyncBridgeRequest) 1.1024 + 1.1025 +// nsProtocolProxyService 1.1026 +nsresult 1.1027 +nsProtocolProxyService::DeprecatedBlockingResolve(nsIChannel *aChannel, 1.1028 + uint32_t aFlags, 1.1029 + nsIProxyInfo **retval) 1.1030 +{ 1.1031 + NS_ENSURE_ARG_POINTER(aChannel); 1.1032 + 1.1033 + nsCOMPtr<nsIURI> uri; 1.1034 + aChannel->GetURI(getter_AddRefs(uri)); 1.1035 + 1.1036 + nsProtocolInfo info; 1.1037 + nsresult rv = GetProtocolInfo(uri, &info); 1.1038 + if (NS_FAILED(rv)) 1.1039 + return rv; 1.1040 + 1.1041 + nsCOMPtr<nsIProxyInfo> pi; 1.1042 + bool usePACThread; 1.1043 + 1.1044 + // SystemProxySettings and PAC files can block the main thread 1.1045 + // but if neither of them are in use, we can just do the work 1.1046 + // right here and directly invoke the callback 1.1047 + 1.1048 + rv = Resolve_Internal(aChannel, info, aFlags, &usePACThread, getter_AddRefs(pi)); 1.1049 + if (NS_FAILED(rv)) 1.1050 + return rv; 1.1051 + 1.1052 + if (!usePACThread || !mPACMan) { 1.1053 + ApplyFilters(aChannel, info, pi); 1.1054 + pi.forget(retval); 1.1055 + return NS_OK; 1.1056 + } 1.1057 + 1.1058 + // Use the PAC thread to do the work, so we don't have to reimplement that 1.1059 + // code, but block this thread on that completion. 1.1060 + nsRefPtr<nsAsyncBridgeRequest> ctx = new nsAsyncBridgeRequest(); 1.1061 + ctx->Lock(); 1.1062 + if (NS_SUCCEEDED(mPACMan->AsyncGetProxyForChannel(aChannel, ctx, false))) { 1.1063 + // this can really block the main thread, so cap it at 3 seconds 1.1064 + ctx->Wait(); 1.1065 + } 1.1066 + ctx->Unlock(); 1.1067 + if (!ctx->mCompleted) 1.1068 + return NS_ERROR_FAILURE; 1.1069 + if (NS_FAILED(ctx->mStatus)) 1.1070 + return ctx->mStatus; 1.1071 + 1.1072 + // pretty much duplicate real DoCallback logic 1.1073 + 1.1074 + // Generate proxy info from the PAC string if appropriate 1.1075 + if (!ctx->mPACString.IsEmpty()) { 1.1076 + LOG(("sync pac thread callback %s\n", ctx->mPACString.get())); 1.1077 + ProcessPACString(ctx->mPACString, 0, getter_AddRefs(pi)); 1.1078 + ApplyFilters(aChannel, info, pi); 1.1079 + pi.forget(retval); 1.1080 + return NS_OK; 1.1081 + } 1.1082 + 1.1083 + if (!ctx->mPACURL.IsEmpty()) { 1.1084 + NS_WARNING("sync pac thread callback indicates new pac file load\n"); 1.1085 + // This is a problem and is one of the reasons this blocking interface 1.1086 + // is deprecated. The main loop needs to spin to make this reload happen. So 1.1087 + // we are going to kick off the reload and return an error - it will work 1.1088 + // next time. Because this sync interface is only used in the java plugin it 1.1089 + // is extremely likely that the pac file has already been loaded anyhow. 1.1090 + 1.1091 + rv = ConfigureFromPAC(ctx->mPACURL, false); 1.1092 + if (NS_FAILED(rv)) 1.1093 + return rv; 1.1094 + return NS_ERROR_NOT_AVAILABLE; 1.1095 + } 1.1096 + 1.1097 + *retval = nullptr; 1.1098 + return NS_OK; 1.1099 +} 1.1100 + 1.1101 +nsresult 1.1102 +nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags, 1.1103 + nsIProtocolProxyCallback *callback, 1.1104 + nsICancelable **result, 1.1105 + bool isSyncOK) 1.1106 +{ 1.1107 + NS_ENSURE_ARG_POINTER(channel); 1.1108 + NS_ENSURE_ARG_POINTER(callback); 1.1109 + 1.1110 + nsCOMPtr<nsIURI> uri; 1.1111 + channel->GetURI(getter_AddRefs(uri)); 1.1112 + 1.1113 + *result = nullptr; 1.1114 + nsRefPtr<nsAsyncResolveRequest> ctx = 1.1115 + new nsAsyncResolveRequest(this, channel, flags, callback); 1.1116 + 1.1117 + nsProtocolInfo info; 1.1118 + nsresult rv = GetProtocolInfo(uri, &info); 1.1119 + if (NS_FAILED(rv)) 1.1120 + return rv; 1.1121 + 1.1122 + nsCOMPtr<nsIProxyInfo> pi; 1.1123 + bool usePACThread; 1.1124 + 1.1125 + // SystemProxySettings and PAC files can block the main thread 1.1126 + // but if neither of them are in use, we can just do the work 1.1127 + // right here and directly invoke the callback 1.1128 + 1.1129 + rv = Resolve_Internal(channel, info, flags, &usePACThread, getter_AddRefs(pi)); 1.1130 + if (NS_FAILED(rv)) 1.1131 + return rv; 1.1132 + 1.1133 + if (!usePACThread || !mPACMan) { 1.1134 + // we can do it locally 1.1135 + ApplyFilters(channel, info, pi); 1.1136 + ctx->SetResult(NS_OK, pi); 1.1137 + if (isSyncOK) { 1.1138 + ctx->Run(); 1.1139 + return NS_OK; 1.1140 + } 1.1141 + 1.1142 + rv = ctx->DispatchCallback(); 1.1143 + if (NS_SUCCEEDED(rv)) 1.1144 + ctx.forget(result); 1.1145 + return rv; 1.1146 + } 1.1147 + 1.1148 + // else kick off a PAC thread query 1.1149 + 1.1150 + rv = mPACMan->AsyncGetProxyForChannel(channel, ctx, true); 1.1151 + if (NS_SUCCEEDED(rv)) 1.1152 + ctx.forget(result); 1.1153 + return rv; 1.1154 +} 1.1155 + 1.1156 +// nsIProtocolProxyService 1.1157 +NS_IMETHODIMP 1.1158 +nsProtocolProxyService::AsyncResolve2(nsIChannel *channel, uint32_t flags, 1.1159 + nsIProtocolProxyCallback *callback, 1.1160 + nsICancelable **result) 1.1161 +{ 1.1162 + return AsyncResolveInternal(channel, flags, callback, result, true); 1.1163 +} 1.1164 + 1.1165 +NS_IMETHODIMP 1.1166 +nsProtocolProxyService::AsyncResolve(nsIChannel *channel, uint32_t flags, 1.1167 + nsIProtocolProxyCallback *callback, 1.1168 + nsICancelable **result) 1.1169 +{ 1.1170 + return AsyncResolveInternal(channel, flags, callback, result, false); 1.1171 +} 1.1172 + 1.1173 +NS_IMETHODIMP 1.1174 +nsProtocolProxyService::NewProxyInfo(const nsACString &aType, 1.1175 + const nsACString &aHost, 1.1176 + int32_t aPort, 1.1177 + uint32_t aFlags, 1.1178 + uint32_t aFailoverTimeout, 1.1179 + nsIProxyInfo *aFailoverProxy, 1.1180 + nsIProxyInfo **aResult) 1.1181 +{ 1.1182 + static const char *types[] = { 1.1183 + kProxyType_HTTP, 1.1184 + kProxyType_SOCKS, 1.1185 + kProxyType_SOCKS4, 1.1186 + kProxyType_DIRECT 1.1187 + }; 1.1188 + 1.1189 + // resolve type; this allows us to avoid copying the type string into each 1.1190 + // proxy info instance. we just reference the string literals directly :) 1.1191 + const char *type = nullptr; 1.1192 + for (uint32_t i=0; i<ArrayLength(types); ++i) { 1.1193 + if (aType.LowerCaseEqualsASCII(types[i])) { 1.1194 + type = types[i]; 1.1195 + break; 1.1196 + } 1.1197 + } 1.1198 + NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG); 1.1199 + 1.1200 + return NewProxyInfo_Internal(type, aHost, aPort, 1.1201 + mSOCKSProxyUsername, mSOCKSProxyPassword, 1.1202 + aFlags, aFailoverTimeout, 1.1203 + aFailoverProxy, 0, aResult); 1.1204 +} 1.1205 + 1.1206 +NS_IMETHODIMP 1.1207 +nsProtocolProxyService::NewSOCKSProxyInfo(const nsACString &aHost, 1.1208 + int32_t aPort, 1.1209 + const nsACString &aUsername, 1.1210 + const nsACString &aPassword, 1.1211 + uint32_t aFlags, 1.1212 + uint32_t aFailoverTimeout, 1.1213 + nsIProxyInfo *aFailoverProxy, 1.1214 + nsIProxyInfo **aResult) 1.1215 +{ 1.1216 + return NewProxyInfo_Internal(kProxyType_SOCKS, aHost, aPort, 1.1217 + aUsername, aPassword, 1.1218 + aFlags, aFailoverTimeout, 1.1219 + aFailoverProxy, 0, aResult); 1.1220 +} 1.1221 + 1.1222 +NS_IMETHODIMP 1.1223 +nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy, 1.1224 + nsIURI *aURI, 1.1225 + nsresult aStatus, 1.1226 + nsIProxyInfo **aResult) 1.1227 +{ 1.1228 + // We only support failover when a PAC file is configured, either 1.1229 + // directly or via system settings 1.1230 + if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD && 1.1231 + mProxyConfig != PROXYCONFIG_SYSTEM) 1.1232 + return NS_ERROR_NOT_AVAILABLE; 1.1233 + 1.1234 + // Verify that |aProxy| is one of our nsProxyInfo objects. 1.1235 + nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy); 1.1236 + NS_ENSURE_ARG(pi); 1.1237 + // OK, the QI checked out. We can proceed. 1.1238 + 1.1239 + // Remember that this proxy is down. 1.1240 + DisableProxy(pi); 1.1241 + 1.1242 + // NOTE: At this point, we might want to prompt the user if we have 1.1243 + // not already tried going DIRECT. This is something that the 1.1244 + // classic codebase supported; however, IE6 does not prompt. 1.1245 + 1.1246 + if (!pi->mNext) 1.1247 + return NS_ERROR_NOT_AVAILABLE; 1.1248 + 1.1249 + LOG(("PAC failover from %s %s:%d to %s %s:%d\n", 1.1250 + pi->mType, pi->mHost.get(), pi->mPort, 1.1251 + pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort)); 1.1252 + 1.1253 + NS_ADDREF(*aResult = pi->mNext); 1.1254 + return NS_OK; 1.1255 +} 1.1256 + 1.1257 +nsresult 1.1258 +nsProtocolProxyService::InsertFilterLink(FilterLink *link, uint32_t position) 1.1259 +{ 1.1260 + if (!mFilters) { 1.1261 + mFilters = link; 1.1262 + return NS_OK; 1.1263 + } 1.1264 + 1.1265 + // insert into mFilters in sorted order 1.1266 + FilterLink *last = nullptr; 1.1267 + for (FilterLink *iter = mFilters; iter; iter = iter->next) { 1.1268 + if (position < iter->position) { 1.1269 + if (last) { 1.1270 + link->next = last->next; 1.1271 + last->next = link; 1.1272 + } 1.1273 + else { 1.1274 + link->next = mFilters; 1.1275 + mFilters = link; 1.1276 + } 1.1277 + return NS_OK; 1.1278 + } 1.1279 + last = iter; 1.1280 + } 1.1281 + // our position is equal to or greater than the last link in the list 1.1282 + last->next = link; 1.1283 + return NS_OK; 1.1284 +} 1.1285 + 1.1286 +NS_IMETHODIMP 1.1287 +nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter, 1.1288 + uint32_t position) 1.1289 +{ 1.1290 + UnregisterFilter(filter); // remove this filter if we already have it 1.1291 + 1.1292 + FilterLink *link = new FilterLink(position, filter); 1.1293 + if (!link) 1.1294 + return NS_ERROR_OUT_OF_MEMORY; 1.1295 + return InsertFilterLink(link, position); 1.1296 +} 1.1297 + 1.1298 +NS_IMETHODIMP 1.1299 +nsProtocolProxyService::RegisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter, 1.1300 + uint32_t position) 1.1301 +{ 1.1302 + UnregisterChannelFilter(channelFilter); // remove this filter if we already have it 1.1303 + 1.1304 + FilterLink *link = new FilterLink(position, channelFilter); 1.1305 + if (!link) 1.1306 + return NS_ERROR_OUT_OF_MEMORY; 1.1307 + return InsertFilterLink(link, position); 1.1308 +} 1.1309 + 1.1310 +nsresult 1.1311 +nsProtocolProxyService::RemoveFilterLink(nsISupports* givenObject) 1.1312 +{ 1.1313 + FilterLink *last = nullptr; 1.1314 + for (FilterLink *iter = mFilters; iter; iter = iter->next) { 1.1315 + nsCOMPtr<nsISupports> object = do_QueryInterface(iter->filter); 1.1316 + if (object == givenObject) { 1.1317 + if (last) 1.1318 + last->next = iter->next; 1.1319 + else 1.1320 + mFilters = iter->next; 1.1321 + iter->next = nullptr; 1.1322 + delete iter; 1.1323 + return NS_OK; 1.1324 + } 1.1325 + last = iter; 1.1326 + } 1.1327 + 1.1328 + // No need to throw an exception in this case. 1.1329 + return NS_OK; 1.1330 +} 1.1331 + 1.1332 +NS_IMETHODIMP 1.1333 +nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter *filter) { 1.1334 + // QI to nsISupports so we can safely test object identity. 1.1335 + nsCOMPtr<nsISupports> givenObject = do_QueryInterface(filter); 1.1336 + return RemoveFilterLink(givenObject); 1.1337 +} 1.1338 + 1.1339 +NS_IMETHODIMP 1.1340 +nsProtocolProxyService::UnregisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter) { 1.1341 + // QI to nsISupports so we can safely test object identity. 1.1342 + nsCOMPtr<nsISupports> givenObject = do_QueryInterface(channelFilter); 1.1343 + return RemoveFilterLink(givenObject); 1.1344 +} 1.1345 + 1.1346 +NS_IMETHODIMP 1.1347 +nsProtocolProxyService::GetProxyConfigType(uint32_t* aProxyConfigType) 1.1348 +{ 1.1349 + *aProxyConfigType = mProxyConfig; 1.1350 + return NS_OK; 1.1351 +} 1.1352 + 1.1353 +void 1.1354 +nsProtocolProxyService::LoadHostFilters(const char *filters) 1.1355 +{ 1.1356 + // check to see the owners flag? /!?/ TODO 1.1357 + if (mHostFiltersArray.Length() > 0) { 1.1358 + mHostFiltersArray.Clear(); 1.1359 + } 1.1360 + 1.1361 + if (!filters) 1.1362 + return; // fail silently... 1.1363 + 1.1364 + // 1.1365 + // filter = ( host | domain | ipaddr ["/" mask] ) [":" port] 1.1366 + // filters = filter *( "," LWS filter) 1.1367 + // 1.1368 + // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string 1.1369 + mFilterLocalHosts = false; 1.1370 + while (*filters) { 1.1371 + // skip over spaces and , 1.1372 + while (*filters && (*filters == ',' || IS_ASCII_SPACE(*filters))) 1.1373 + filters++; 1.1374 + 1.1375 + const char *starthost = filters; 1.1376 + const char *endhost = filters + 1; // at least that... 1.1377 + const char *portLocation = 0; 1.1378 + const char *maskLocation = 0; 1.1379 + 1.1380 + while (*endhost && (*endhost != ',' && !IS_ASCII_SPACE(*endhost))) { 1.1381 + if (*endhost == ':') 1.1382 + portLocation = endhost; 1.1383 + else if (*endhost == '/') 1.1384 + maskLocation = endhost; 1.1385 + else if (*endhost == ']') // IPv6 address literals 1.1386 + portLocation = 0; 1.1387 + endhost++; 1.1388 + } 1.1389 + 1.1390 + filters = endhost; // advance iterator up front 1.1391 + 1.1392 + // locate end of host 1.1393 + const char *end = maskLocation ? maskLocation : 1.1394 + portLocation ? portLocation : 1.1395 + endhost; 1.1396 + 1.1397 + nsAutoCString str(starthost, end - starthost); 1.1398 + 1.1399 + // If the current host filter is "<local>", then all local (i.e. 1.1400 + // no dots in the hostname) hosts should bypass the proxy 1.1401 + if (str.EqualsIgnoreCase("<local>")) { 1.1402 + mFilterLocalHosts = true; 1.1403 + LOG(("loaded filter for local hosts " 1.1404 + "(plain host names, no dots)\n")); 1.1405 + // Continue to next host filter; 1.1406 + continue; 1.1407 + } 1.1408 + 1.1409 + // For all other host filters, create HostInfo object and add to list 1.1410 + HostInfo *hinfo = new HostInfo(); 1.1411 + hinfo->port = portLocation ? atoi(portLocation + 1) : 0; 1.1412 + 1.1413 + PRNetAddr addr; 1.1414 + if (PR_StringToNetAddr(str.get(), &addr) == PR_SUCCESS) { 1.1415 + hinfo->is_ipaddr = true; 1.1416 + hinfo->ip.family = PR_AF_INET6; // we always store address as IPv6 1.1417 + hinfo->ip.mask_len = maskLocation ? atoi(maskLocation + 1) : 128; 1.1418 + 1.1419 + if (hinfo->ip.mask_len == 0) { 1.1420 + NS_WARNING("invalid mask"); 1.1421 + goto loser; 1.1422 + } 1.1423 + 1.1424 + if (addr.raw.family == PR_AF_INET) { 1.1425 + // convert to IPv4-mapped address 1.1426 + PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr); 1.1427 + // adjust mask_len accordingly 1.1428 + if (hinfo->ip.mask_len <= 32) 1.1429 + hinfo->ip.mask_len += 96; 1.1430 + } 1.1431 + else if (addr.raw.family == PR_AF_INET6) { 1.1432 + // copy the address 1.1433 + memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr)); 1.1434 + } 1.1435 + else { 1.1436 + NS_WARNING("unknown address family"); 1.1437 + goto loser; 1.1438 + } 1.1439 + 1.1440 + // apply mask to IPv6 address 1.1441 + proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len); 1.1442 + } 1.1443 + else { 1.1444 + uint32_t startIndex, endIndex; 1.1445 + if (str.First() == '*') 1.1446 + startIndex = 1; // *.domain -> .domain 1.1447 + else 1.1448 + startIndex = 0; 1.1449 + endIndex = (portLocation ? portLocation : endhost) - starthost; 1.1450 + 1.1451 + hinfo->is_ipaddr = false; 1.1452 + hinfo->name.host = ToNewCString(Substring(str, startIndex, endIndex)); 1.1453 + 1.1454 + if (!hinfo->name.host) 1.1455 + goto loser; 1.1456 + 1.1457 + hinfo->name.host_len = endIndex - startIndex; 1.1458 + } 1.1459 + 1.1460 +//#define DEBUG_DUMP_FILTERS 1.1461 +#ifdef DEBUG_DUMP_FILTERS 1.1462 + printf("loaded filter[%u]:\n", mHostFiltersArray.Length()); 1.1463 + printf(" is_ipaddr = %u\n", hinfo->is_ipaddr); 1.1464 + printf(" port = %u\n", hinfo->port); 1.1465 + if (hinfo->is_ipaddr) { 1.1466 + printf(" ip.family = %x\n", hinfo->ip.family); 1.1467 + printf(" ip.mask_len = %u\n", hinfo->ip.mask_len); 1.1468 + 1.1469 + PRNetAddr netAddr; 1.1470 + PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr); 1.1471 + memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr)); 1.1472 + 1.1473 + char buf[256]; 1.1474 + PR_NetAddrToString(&netAddr, buf, sizeof(buf)); 1.1475 + 1.1476 + printf(" ip.addr = %s\n", buf); 1.1477 + } 1.1478 + else { 1.1479 + printf(" name.host = %s\n", hinfo->name.host); 1.1480 + } 1.1481 +#endif 1.1482 + 1.1483 + mHostFiltersArray.AppendElement(hinfo); 1.1484 + hinfo = nullptr; 1.1485 +loser: 1.1486 + delete hinfo; 1.1487 + } 1.1488 +} 1.1489 + 1.1490 +nsresult 1.1491 +nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info) 1.1492 +{ 1.1493 + NS_PRECONDITION(uri, "URI is null"); 1.1494 + NS_PRECONDITION(info, "info is null"); 1.1495 + 1.1496 + nsresult rv; 1.1497 + 1.1498 + rv = uri->GetScheme(info->scheme); 1.1499 + if (NS_FAILED(rv)) 1.1500 + return rv; 1.1501 + 1.1502 + nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv); 1.1503 + if (NS_FAILED(rv)) 1.1504 + return rv; 1.1505 + 1.1506 + nsCOMPtr<nsIProtocolHandler> handler; 1.1507 + rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler)); 1.1508 + if (NS_FAILED(rv)) 1.1509 + return rv; 1.1510 + 1.1511 + rv = handler->GetProtocolFlags(&info->flags); 1.1512 + if (NS_FAILED(rv)) 1.1513 + return rv; 1.1514 + 1.1515 + rv = handler->GetDefaultPort(&info->defaultPort); 1.1516 + return rv; 1.1517 +} 1.1518 + 1.1519 +nsresult 1.1520 +nsProtocolProxyService::NewProxyInfo_Internal(const char *aType, 1.1521 + const nsACString &aHost, 1.1522 + int32_t aPort, 1.1523 + const nsACString &aUsername, 1.1524 + const nsACString &aPassword, 1.1525 + uint32_t aFlags, 1.1526 + uint32_t aFailoverTimeout, 1.1527 + nsIProxyInfo *aFailoverProxy, 1.1528 + uint32_t aResolveFlags, 1.1529 + nsIProxyInfo **aResult) 1.1530 +{ 1.1531 + if (aPort <= 0) 1.1532 + aPort = -1; 1.1533 + 1.1534 + nsCOMPtr<nsProxyInfo> failover; 1.1535 + if (aFailoverProxy) { 1.1536 + failover = do_QueryInterface(aFailoverProxy); 1.1537 + NS_ENSURE_ARG(failover); 1.1538 + } 1.1539 + 1.1540 + nsProxyInfo *proxyInfo = new nsProxyInfo(); 1.1541 + if (!proxyInfo) 1.1542 + return NS_ERROR_OUT_OF_MEMORY; 1.1543 + 1.1544 + proxyInfo->mType = aType; 1.1545 + proxyInfo->mHost = aHost; 1.1546 + proxyInfo->mPort = aPort; 1.1547 + proxyInfo->mUsername = aUsername; 1.1548 + proxyInfo->mPassword = aPassword; 1.1549 + proxyInfo->mFlags = aFlags; 1.1550 + proxyInfo->mResolveFlags = aResolveFlags; 1.1551 + proxyInfo->mTimeout = aFailoverTimeout == UINT32_MAX 1.1552 + ? mFailedProxyTimeout : aFailoverTimeout; 1.1553 + failover.swap(proxyInfo->mNext); 1.1554 + 1.1555 + NS_ADDREF(*aResult = proxyInfo); 1.1556 + return NS_OK; 1.1557 +} 1.1558 + 1.1559 +nsresult 1.1560 +nsProtocolProxyService::Resolve_Internal(nsIChannel *channel, 1.1561 + const nsProtocolInfo &info, 1.1562 + uint32_t flags, 1.1563 + bool *usePACThread, 1.1564 + nsIProxyInfo **result) 1.1565 +{ 1.1566 + NS_ENSURE_ARG_POINTER(channel); 1.1567 + nsresult rv = SetupPACThread(); 1.1568 + if (NS_FAILED(rv)) 1.1569 + return rv; 1.1570 + 1.1571 + *usePACThread = false; 1.1572 + *result = nullptr; 1.1573 + 1.1574 + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) 1.1575 + return NS_OK; // Can't proxy this (filters may not override) 1.1576 + 1.1577 + nsCOMPtr<nsIURI> uri; 1.1578 + channel->GetURI(getter_AddRefs(uri)); 1.1579 + 1.1580 + // See bug #586908. 1.1581 + // Avoid endless loop if |uri| is the current PAC-URI. Returning OK 1.1582 + // here means that we will not use a proxy for this connection. 1.1583 + if (mPACMan && mPACMan->IsPACURI(uri)) 1.1584 + return NS_OK; 1.1585 + 1.1586 + bool mainThreadOnly; 1.1587 + if (mSystemProxySettings && 1.1588 + mProxyConfig == PROXYCONFIG_SYSTEM && 1.1589 + NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) && 1.1590 + !mainThreadOnly) { 1.1591 + *usePACThread = true; 1.1592 + return NS_OK; 1.1593 + } 1.1594 + 1.1595 + if (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM) { 1.1596 + // If the system proxy setting implementation is not threadsafe (e.g 1.1597 + // linux gconf), we'll do it inline here. Such implementations promise 1.1598 + // not to block 1.1599 + 1.1600 + nsAutoCString PACURI; 1.1601 + nsAutoCString pacString; 1.1602 + 1.1603 + if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) && 1.1604 + !PACURI.IsEmpty()) { 1.1605 + // There is a PAC URI configured. If it is unchanged, then 1.1606 + // just execute the PAC thread. If it is changed then load 1.1607 + // the new value 1.1608 + 1.1609 + if (mPACMan && mPACMan->IsPACURI(PACURI)) { 1.1610 + // unchanged 1.1611 + *usePACThread = true; 1.1612 + return NS_OK; 1.1613 + } 1.1614 + 1.1615 + ConfigureFromPAC(PACURI, false); 1.1616 + return NS_OK; 1.1617 + } 1.1618 + 1.1619 + nsAutoCString spec; 1.1620 + nsAutoCString host; 1.1621 + nsAutoCString scheme; 1.1622 + int32_t port = -1; 1.1623 + 1.1624 + uri->GetAsciiSpec(spec); 1.1625 + uri->GetAsciiHost(host); 1.1626 + uri->GetScheme(scheme); 1.1627 + uri->GetPort(&port); 1.1628 + 1.1629 + // now try the system proxy settings for this particular url 1.1630 + if (NS_SUCCEEDED(mSystemProxySettings-> 1.1631 + GetProxyForURI(spec, scheme, host, port, 1.1632 + pacString))) { 1.1633 + ProcessPACString(pacString, 0, result); 1.1634 + return NS_OK; 1.1635 + } 1.1636 + } 1.1637 + 1.1638 + // if proxies are enabled and this host:port combo is supposed to use a 1.1639 + // proxy, check for a proxy. 1.1640 + if (mProxyConfig == PROXYCONFIG_DIRECT || 1.1641 + (mProxyConfig == PROXYCONFIG_MANUAL && 1.1642 + !CanUseProxy(uri, info.defaultPort))) 1.1643 + return NS_OK; 1.1644 + 1.1645 + // Proxy auto config magic... 1.1646 + if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) { 1.1647 + // Do not query PAC now. 1.1648 + *usePACThread = true; 1.1649 + return NS_OK; 1.1650 + } 1.1651 + 1.1652 + // If we aren't in manual proxy configuration mode then we don't 1.1653 + // want to honor any manual specific prefs that might be still set 1.1654 + if (mProxyConfig != PROXYCONFIG_MANUAL) 1.1655 + return NS_OK; 1.1656 + 1.1657 + // proxy info values for manual configuration mode 1.1658 + const char *type = nullptr; 1.1659 + const nsACString *host = nullptr; 1.1660 + int32_t port = -1; 1.1661 + 1.1662 + uint32_t proxyFlags = 0; 1.1663 + 1.1664 + if ((flags & RESOLVE_PREFER_SOCKS_PROXY) && 1.1665 + !mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { 1.1666 + host = &mSOCKSProxyHost; 1.1667 + if (mSOCKSProxyVersion == 4) 1.1668 + type = kProxyType_SOCKS4; 1.1669 + else 1.1670 + type = kProxyType_SOCKS; 1.1671 + port = mSOCKSProxyPort; 1.1672 + if (mSOCKSProxyRemoteDNS) 1.1673 + proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; 1.1674 + } 1.1675 + else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) && 1.1676 + !mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0) { 1.1677 + host = &mHTTPSProxyHost; 1.1678 + type = kProxyType_HTTP; 1.1679 + port = mHTTPSProxyPort; 1.1680 + } 1.1681 + else if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 && 1.1682 + ((flags & RESOLVE_IGNORE_URI_SCHEME) || 1.1683 + info.scheme.EqualsLiteral("http"))) { 1.1684 + host = &mHTTPProxyHost; 1.1685 + type = kProxyType_HTTP; 1.1686 + port = mHTTPProxyPort; 1.1687 + } 1.1688 + else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 && 1.1689 + !(flags & RESOLVE_IGNORE_URI_SCHEME) && 1.1690 + info.scheme.EqualsLiteral("https")) { 1.1691 + host = &mHTTPSProxyHost; 1.1692 + type = kProxyType_HTTP; 1.1693 + port = mHTTPSProxyPort; 1.1694 + } 1.1695 + else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 && 1.1696 + !(flags & RESOLVE_IGNORE_URI_SCHEME) && 1.1697 + info.scheme.EqualsLiteral("ftp")) { 1.1698 + host = &mFTPProxyHost; 1.1699 + type = kProxyType_HTTP; 1.1700 + port = mFTPProxyPort; 1.1701 + } 1.1702 + else if (!mSOCKSProxyHost.IsEmpty() && mSOCKSProxyPort > 0) { 1.1703 + host = &mSOCKSProxyHost; 1.1704 + if (mSOCKSProxyVersion == 4) 1.1705 + type = kProxyType_SOCKS4; 1.1706 + else 1.1707 + type = kProxyType_SOCKS; 1.1708 + port = mSOCKSProxyPort; 1.1709 + if (mSOCKSProxyRemoteDNS) 1.1710 + proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST; 1.1711 + } 1.1712 + 1.1713 + if (type) { 1.1714 + rv = NewProxyInfo_Internal(type, *host, port, 1.1715 + mSOCKSProxyUsername, mSOCKSProxyPassword, 1.1716 + proxyFlags, UINT32_MAX, nullptr, flags, 1.1717 + result); 1.1718 + if (NS_FAILED(rv)) 1.1719 + return rv; 1.1720 + } 1.1721 + 1.1722 + return NS_OK; 1.1723 +} 1.1724 + 1.1725 +void 1.1726 +nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy) 1.1727 +{ 1.1728 + // Disable Prefetch in the DNS service if a proxy is in use. 1.1729 + if (!aProxy) 1.1730 + return; 1.1731 + 1.1732 + nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy); 1.1733 + if (!pi || 1.1734 + !pi->mType || 1.1735 + pi->mType == kProxyType_DIRECT) 1.1736 + return; 1.1737 + 1.1738 + nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID); 1.1739 + if (!dns) 1.1740 + return; 1.1741 + nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns); 1.1742 + if (!pdns) 1.1743 + return; 1.1744 + 1.1745 + // We lose the prefetch optimization for the life of the dns service. 1.1746 + pdns->SetPrefetchEnabled(false); 1.1747 +} 1.1748 + 1.1749 +void 1.1750 +nsProtocolProxyService::ApplyFilters(nsIChannel *channel, const nsProtocolInfo &info, 1.1751 + nsIProxyInfo **list) 1.1752 +{ 1.1753 + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY)) 1.1754 + return; 1.1755 + 1.1756 + // We prune the proxy list prior to invoking each filter. This may be 1.1757 + // somewhat inefficient, but it seems like a good idea since we want each 1.1758 + // filter to "see" a valid proxy list. 1.1759 + 1.1760 + nsresult rv; 1.1761 + nsCOMPtr<nsIProxyInfo> result; 1.1762 + 1.1763 + for (FilterLink *iter = mFilters; iter; iter = iter->next) { 1.1764 + PruneProxyInfo(info, list); 1.1765 + if (!!iter->filter) { 1.1766 + nsCOMPtr<nsIURI> uri; 1.1767 + channel->GetURI(getter_AddRefs(uri)); 1.1768 + if (!!uri) { 1.1769 + nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel); 1.1770 + nsCOMPtr<nsIURI> proxyURI = nullptr; 1.1771 + if (!!httpChannel) { 1.1772 + httpChannel->GetProxyURI(getter_AddRefs(proxyURI)); 1.1773 + } 1.1774 + rv = iter->filter->ApplyFilter(this, proxyURI ? proxyURI : uri, *list, 1.1775 + getter_AddRefs(result)); 1.1776 + } 1.1777 + } else if (!!iter->channelFilter) { 1.1778 + rv = iter->channelFilter->ApplyFilter(this, channel, *list, 1.1779 + getter_AddRefs(result)); 1.1780 + } 1.1781 + if (NS_FAILED(rv)) 1.1782 + continue; 1.1783 + result.swap(*list); 1.1784 + } 1.1785 + 1.1786 + PruneProxyInfo(info, list); 1.1787 +} 1.1788 + 1.1789 +void 1.1790 +nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info, 1.1791 + nsIProxyInfo **list) 1.1792 +{ 1.1793 + if (!*list) 1.1794 + return; 1.1795 + nsProxyInfo *head = nullptr; 1.1796 + CallQueryInterface(*list, &head); 1.1797 + if (!head) { 1.1798 + NS_NOTREACHED("nsIProxyInfo must QI to nsProxyInfo"); 1.1799 + return; 1.1800 + } 1.1801 + NS_RELEASE(*list); 1.1802 + 1.1803 + // Pruning of disabled proxies works like this: 1.1804 + // - If all proxies are disabled, return the full list 1.1805 + // - Otherwise, remove the disabled proxies. 1.1806 + // 1.1807 + // Pruning of disallowed proxies works like this: 1.1808 + // - If the protocol handler disallows the proxy, then we disallow it. 1.1809 + 1.1810 + // Start by removing all disallowed proxies if required: 1.1811 + if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) { 1.1812 + nsProxyInfo *last = nullptr, *iter = head; 1.1813 + while (iter) { 1.1814 + if (iter->Type() == kProxyType_HTTP) { 1.1815 + // reject! 1.1816 + if (last) 1.1817 + last->mNext = iter->mNext; 1.1818 + else 1.1819 + head = iter->mNext; 1.1820 + nsProxyInfo *next = iter->mNext; 1.1821 + iter->mNext = nullptr; 1.1822 + iter->Release(); 1.1823 + iter = next; 1.1824 + } else { 1.1825 + last = iter; 1.1826 + iter = iter->mNext; 1.1827 + } 1.1828 + } 1.1829 + if (!head) 1.1830 + return; 1.1831 + } 1.1832 + 1.1833 + // Now, scan to see if all remaining proxies are disabled. If so, then 1.1834 + // we'll just bail and return them all. Otherwise, we'll go and prune the 1.1835 + // disabled ones. 1.1836 + 1.1837 + bool allDisabled = true; 1.1838 + 1.1839 + nsProxyInfo *iter; 1.1840 + for (iter = head; iter; iter = iter->mNext) { 1.1841 + if (!IsProxyDisabled(iter)) { 1.1842 + allDisabled = false; 1.1843 + break; 1.1844 + } 1.1845 + } 1.1846 + 1.1847 + if (allDisabled) 1.1848 + LOG(("All proxies are disabled, so trying all again")); 1.1849 + else { 1.1850 + // remove any disabled proxies. 1.1851 + nsProxyInfo *last = nullptr; 1.1852 + for (iter = head; iter; ) { 1.1853 + if (IsProxyDisabled(iter)) { 1.1854 + // reject! 1.1855 + nsProxyInfo *reject = iter; 1.1856 + 1.1857 + iter = iter->mNext; 1.1858 + if (last) 1.1859 + last->mNext = iter; 1.1860 + else 1.1861 + head = iter; 1.1862 + 1.1863 + reject->mNext = nullptr; 1.1864 + NS_RELEASE(reject); 1.1865 + continue; 1.1866 + } 1.1867 + 1.1868 + // since we are about to use this proxy, make sure it is not on 1.1869 + // the disabled proxy list. we'll add it back to that list if 1.1870 + // we have to (in GetFailoverForProxy). 1.1871 + // 1.1872 + // XXX(darin): It might be better to do this as a final pass. 1.1873 + // 1.1874 + EnableProxy(iter); 1.1875 + 1.1876 + last = iter; 1.1877 + iter = iter->mNext; 1.1878 + } 1.1879 + } 1.1880 + 1.1881 + // if only DIRECT was specified then return no proxy info, and we're done. 1.1882 + if (head && !head->mNext && head->mType == kProxyType_DIRECT) 1.1883 + NS_RELEASE(head); 1.1884 + 1.1885 + *list = head; // Transfer ownership 1.1886 +}