/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=4 sw=2 sts=2 et: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This structure is intended to be allocated on the stack struct nsProtocolInfo {
nsAutoCString scheme;
uint32_t flags = 0;
int32_t defaultPort = 0;
};
// The nsPACManCallback portion of this implementation should be run // on the main thread - so call nsPACMan::AsyncGetProxyForURI() with // a true mainThreadResponse parameter. class nsAsyncResolveRequest final : public nsIRunnable, public nsPACManCallback, public nsICancelable { public:
NS_DECL_THREADSAFE_ISUPPORTS
private:
~nsAsyncResolveRequest() { if (!NS_IsMainThread()) { // these xpcom pointers might need to be proxied back to the // main thread to delete safely, but if this request had its // callbacks called normally they will all be null and this is a nop
if (mChannel) {
NS_ReleaseOnMainThread("nsAsyncResolveRequest::mChannel",
mChannel.forget());
}
if (mCallback) {
NS_ReleaseOnMainThread("nsAsyncResolveRequest::mCallback",
mCallback.forget());
}
if (mProxyInfo) {
NS_ReleaseOnMainThread("nsAsyncResolveRequest::mProxyInfo",
mProxyInfo.forget());
}
if (mXPComPPS) {
NS_ReleaseOnMainThread("nsAsyncResolveRequest::mXPComPPS",
mXPComPPS.forget());
}
}
}
// Helper class to loop over all registered asynchronous filters. // There is a cycle between nsAsyncResolveRequest and this class that // is broken after the last filter has called back on this object. class AsyncApplyFilters final : public nsIProxyProtocolFilterResult, public nsIRunnable, public nsICancelable { // The reference counter is thread-safe, but the processing logic is // considered single thread only. We want the counter be thread safe, // since this class can be released on a background thread.
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIPROXYPROTOCOLFILTERRESULT
NS_DECL_NSIRUNNABLE
NS_DECL_NSICANCELABLE
using Callback =
std::function<nsresult(nsAsyncResolveRequest*, nsIProxyInfo*, bool)>;
explicit AsyncApplyFilters(nsProtocolInfo& aInfo,
Callback const& aCallback); // This method starts the processing or filters. If all of them // answer synchronously (call back from within applyFilters) this method // will return immediately and the returning result will carry return // result of the callback given in constructor. // This method is looping the registered filters (that have been copied // locally) as long as an answer from a filter is obtained synchronously. // Note that filters are processed serially to let them build a list // of proxy info.
nsresult AsyncProcess(nsAsyncResolveRequest* aRequest);
private: using FilterLink = nsProtocolProxyService::FilterLink;
virtual ~AsyncApplyFilters(); // Processes the next filter and loops until a filter is successfully // called on or it has called back to us.
nsresult ProcessNextFilter(); // Called after the last filter has been processed (=called back or failed // to be called on)
nsresult Finish();
nsProtocolInfo mInfo; // This is nullified before we call back on the request or when // Cancel() on this object has been called to break the cycle // and signal to stop.
RefPtr<nsAsyncResolveRequest> mRequest;
Callback mCallback; // A shallow snapshot of filters as they were registered at the moment // we started to process filters for the given resolve request.
nsTArray<RefPtr<FilterLink>> mFiltersCopy;
nsTArray<RefPtr<FilterLink>>::index_type mNextFilterIndex; // true when we are calling ProcessNextFilter() from inside AsyncProcess(), // false otherwise. bool mProcessingInLoop; // true after a filter called back to us with a result, dropped to false // just before we call a filter. bool mFilterCalledBack;
// This keeps the initial value we pass to the first filter in line and also // collects the result from each filter call.
nsCOMPtr<nsIProxyInfo> mProxyInfo;
// The logic is written as non-thread safe, assert single-thread usage.
nsCOMPtr<nsISerialEventTarget> mProcessingThread;
};
void EnsureResolveFlagsMatch() {
nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(mProxyInfo); if (!pi || pi->ResolveFlags() == mResolveFlags) { return;
}
private: // Called asynchronously, so we do not need to post another PLEvent // before calling DoCallback. void OnQueryComplete(nsresult status, const nsACString& pacString, const nsACString& newPACURL) override { // If we've already called DoCallback then, nothing more to do. if (!mCallback) return;
// Provided we haven't been canceled... if (mStatus == NS_OK) {
mStatus = status;
mPACString = pacString;
mPACURL = newPACURL;
}
// In the cancelation case, we may still have another PLEvent in // the queue that wants to call DoCallback. No need to wait for // it, just run the callback now.
DoCallback();
}
void DoCallback() { bool pacAvailable = true; if (mStatus == NS_ERROR_NOT_AVAILABLE && !mProxyInfo) { // If the PAC service is not avail (e.g. failed pac load // or shutdown) then we will be going direct. Make that // mapping now so that any filters are still applied.
mPACString = "DIRECT;"_ns;
mStatus = NS_OK;
LOG(("pac not available, use DIRECT\n"));
pacAvailable = false;
}
// Generate proxy info from the PAC string if appropriate if (NS_SUCCEEDED(mStatus) && !mProxyInfo && !mPACString.IsEmpty()) {
mPPS->ProcessPACString(mPACString, mResolveFlags,
getter_AddRefs(mProxyInfo));
nsCOMPtr<nsIURI> proxyURI;
GetProxyURI(mChannel, getter_AddRefs(proxyURI));
if (NS_SUCCEEDED(mStatus)) {
mAsyncFilterApplier = new AsyncApplyFilters(info, consumeFiltersResult); // This may call consumeFiltersResult() directly.
mAsyncFilterApplier->AsyncProcess(this); return;
}
// trigger load of new pac url
nsresult rv = mPPS->ConfigureFromPAC(mPACURL, false); if (NS_SUCCEEDED(rv)) { // now that the load is triggered, we can resubmit the query
RefPtr<nsAsyncResolveRequest> newRequest = new nsAsyncResolveRequest(mPPS, mChannel, mResolveFlags, mCallback);
rv = mPPS->mPACMan->AsyncGetProxyForURI(proxyURI, newRequest,
mResolveFlags, true);
}
if (NS_FAILED(rv)) {
mCallback->OnProxyAvailable(this, mChannel, nullptr, rv);
}
// do not call onproxyavailable() in SUCCESS case - the newRequest will // take care of that
} else {
LOG(("pac thread callback did not provide information %" PRIX32 "\n", static_cast<uint32_t>(mStatus))); if (NS_SUCCEEDED(mStatus)) mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
EnsureResolveFlagsMatch();
mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus);
}
// We are on the main thread now and don't need these any more so // release them to avoid having to proxy them back to the main thread // in the dtor
mCallback = nullptr; // in case the callback holds an owning ref to us
mPPS = nullptr;
mXPComPPS = nullptr;
mChannel = nullptr;
mProxyInfo = nullptr;
}
MOZ_ASSERT(!mRequest, "AsyncApplyFilters started more than once!");
if (!(mInfo.flags & nsIProtocolHandler::ALLOWS_PROXY)) { // Calling the callback directly (not via Finish()) since we // don't want to prune. return mCallback(aRequest, aRequest->mProxyInfo, false);
}
// We want to give filters a chance to process in a single loop to prevent // any current-thread dispatch delays when those are not needed. // This code is rather "loopy" than "recursive" to prevent long stack traces. do {
MOZ_ASSERT(!mProcessingInLoop);
nsresult rv = ProcessNextFilter(); if (NS_FAILED(rv)) { return rv;
}
} while (mFilterCalledBack);
return NS_OK;
}
nsresult nsAsyncResolveRequest::AsyncApplyFilters::ProcessNextFilter() {
LOG(("AsyncApplyFilters::ProcessNextFilter %p ENTER pi=%p", this,
mProxyInfo.get()));
RefPtr<FilterLink> filter; do {
mFilterCalledBack = false;
if (!mRequest) { // We got canceled
LOG((" canceled")); return NS_OK; // should we let the consumer know?
}
if (mNextFilterIndex == mFiltersCopy.Length()) { return Finish();
}
filter = mFiltersCopy[mNextFilterIndex++];
// Loop until a call to a filter succeeded. Other option is to recurse // but that would waste stack trace when a number of filters gets registered // and all from some reason tend to fail. // The !mFilterCalledBack part of the condition is there to protect us from // calling on another filter when the current one managed to call back and // then threw. We already have the result so take it and use it since // the next filter will be processed by the root loop or a call to // ProcessNextFilter has already been dispatched to this thread.
LOG((" calling filter %p pi=%p", filter.get(), mProxyInfo.get()));
} while (!mRequest->mPPS->ApplyFilter(filter, mRequest->mChannel, mInfo,
mProxyInfo, this) &&
!mFilterCalledBack);
if (mFilterCalledBack) {
LOG((" duplicate notification?")); return NS_OK;
}
mFilterCalledBack = true;
if (!mRequest) { // We got canceled
LOG((" canceled")); return NS_OK;
}
mProxyInfo = aProxyInfo;
if (mProcessingInLoop) { // No need to call/dispatch ProcessNextFilter(), we are in a control // loop that will do this for us and save recursion/dispatching.
LOG((" in a root loop")); return NS_OK;
}
if (mNextFilterIndex == mFiltersCopy.Length()) { // We are done, all filters have been called on!
Finish(); return NS_OK;
}
// Redispatch, since we don't want long stacks when filters respond // synchronously.
LOG((" redispatching"));
NS_DispatchToCurrentThread(this); return NS_OK;
}
// This will be called only from inside the request, so don't call // its's callback. Dropping the members means we simply break the cycle.
mFiltersCopy.Clear();
mProxyInfo = nullptr;
mRequest = nullptr;
return NS_OK;
}
// Bug 1366133: make GetPACURI and GetSystemWPADSetting off-main-thread since it // may hang on Windows platform class AsyncGetPACURIRequestOrSystemWPADSetting final : public nsIRunnable { public:
NS_DECL_THREADSAFE_ISUPPORTS
using CallbackFunc = nsresult (nsProtocolProxyService::*)(bool, bool,
nsresult, const nsACString&, bool);
nsProtocolProxyService* mService; // ref-count is hold by mServiceHolder
nsCOMPtr<nsIProtocolProxyService2> mServiceHolder;
CallbackFunc mCallback;
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
// // apply mask to address (zeros out excluded bits). // // NOTE: we do the byte swapping here to minimize overall swapping. // staticvoid proxy_MaskIPv6Addr(PRIPv6Addr& addr, uint16_t mask_len) { if (mask_len == 128) return;
staticvoid proxy_GetStringPref(nsIPrefBranch* aPrefBranch, constchar* aPref,
nsCString& aResult) {
nsAutoCString temp;
nsresult rv = aPrefBranch->GetCharPref(aPref, temp); if (NS_FAILED(rv)) {
aResult.Truncate();
} else {
aResult.Assign(temp); // all of our string prefs are hostnames, so we should remove any // whitespace characters that the user might have unknowingly entered.
aResult.StripWhitespace();
}
}
nsProtocolProxyService::~nsProtocolProxyService() { // These should have been cleaned up in our Observe method.
NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters.Length() == 0 &&
mPACMan == nullptr, "what happened to xpcom-shutdown?");
}
// nsProtocolProxyService methods
nsresult nsProtocolProxyService::Init() { // failure to access prefs is non-fatal
nsCOMPtr<nsIPrefBranch> prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefBranch) { // monitor proxy prefs
prefBranch->AddObserver(PROXY_PREF_BRANCH, this, false);
// read all prefs
PrefsChanged(prefBranch, nullptr);
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (obs) { // register for shutdown notification so we can clean ourselves up // properly.
obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
obs->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
}
return NS_OK;
}
// ReloadNetworkPAC() checks if there's a non-networked PAC in use then avoids // to call ReloadPAC()
nsresult nsProtocolProxyService::ReloadNetworkPAC() {
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (!prefs) { return NS_OK;
}
if (!pref || !strcmp(pref, PROXY_PREF("type")) ||
!strcmp(pref, PROXY_PREF("system_wpad"))) {
int32_t type = -1;
rv = prefBranch->GetIntPref(PROXY_PREF("type"), &type); if (NS_SUCCEEDED(rv)) { // bug 115720 - for ns4.x backwards compatibility if (type == PROXYCONFIG_DIRECT4X) {
type = PROXYCONFIG_DIRECT; // Reset the type so that the dialog looks correct, and we // don't have to handle this case everywhere else // I'm paranoid about a loop of some sort - only do this // if we're enumerating all prefs, and ignore any error if (!pref) prefBranch->SetIntPref(PROXY_PREF("type"), type);
} elseif (type >= PROXYCONFIG_COUNT) {
LOG(("unknown proxy type: %" PRId32 "; assuming direct\n", type));
type = PROXYCONFIG_DIRECT;
}
mProxyConfig = type;
reloadPAC = true;
}
if (mProxyConfig == PROXYCONFIG_SYSTEM) {
mSystemProxySettings = do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); if (!mSystemProxySettings) mProxyConfig = PROXYCONFIG_DIRECT;
ResetPACThread();
} else { if (mSystemProxySettings) {
mSystemProxySettings = nullptr;
ResetPACThread();
}
}
}
if (!pref || !strcmp(pref, PROXY_PREF("http"))) {
proxy_GetStringPref(prefBranch, PROXY_PREF("http"), mHTTPProxyHost);
}
if (!pref || !strcmp(pref, PROXY_PREF("http_port"))) {
proxy_GetIntPref(prefBranch, PROXY_PREF("http_port"), mHTTPProxyPort);
}
if (!pref || !strcmp(pref, PROXY_PREF("ssl"))) {
proxy_GetStringPref(prefBranch, PROXY_PREF("ssl"), mHTTPSProxyHost);
}
if (!pref || !strcmp(pref, PROXY_PREF("ssl_port"))) {
proxy_GetIntPref(prefBranch, PROXY_PREF("ssl_port"), mHTTPSProxyPort);
}
if (!pref || !strcmp(pref, PROXY_PREF("socks"))) {
proxy_GetStringPref(prefBranch, PROXY_PREF("socks"), mSOCKSProxyTarget);
}
if (!pref || !strcmp(pref, PROXY_PREF("socks_port"))) {
proxy_GetIntPref(prefBranch, PROXY_PREF("socks_port"), mSOCKSProxyPort);
}
if (!pref || !strcmp(pref, PROXY_PREF("socks_version"))) {
int32_t version;
proxy_GetIntPref(prefBranch, PROXY_PREF("socks_version"), version); // make sure this preference value remains sane if (version == nsIProxyInfo::SOCKS_V5) {
mSOCKSProxyVersion = nsIProxyInfo::SOCKS_V5;
} else {
mSOCKSProxyVersion = nsIProxyInfo::SOCKS_V4;
}
}
if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns"))) {
proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"),
mSOCKS4ProxyRemoteDNS);
}
if (!pref || !strcmp(pref, PROXY_PREF("socks5_remote_dns"))) {
proxy_GetBoolPref(prefBranch, PROXY_PREF("socks5_remote_dns"),
mSOCKS5ProxyRemoteDNS);
}
if (!pref || !strcmp(pref, PROXY_PREF("proxy_over_tls"))) {
proxy_GetBoolPref(prefBranch, PROXY_PREF("proxy_over_tls"), mProxyOverTLS);
}
if (!pref || !strcmp(pref, PROXY_PREF("failover_timeout"))) {
proxy_GetIntPref(prefBranch, PROXY_PREF("failover_timeout"),
mFailedProxyTimeout);
}
if (!pref || !strcmp(pref, PROXY_PREF("no_proxies_on"))) {
rv = prefBranch->GetCharPref(PROXY_PREF("no_proxies_on"), tempString); if (NS_SUCCEEDED(rv)) LoadHostFilters(tempString);
}
// We're done if not using something that could give us a PAC URL // (PAC, WPAD or System) if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
mProxyConfig != PROXYCONFIG_SYSTEM) { return;
}
// OK, we need to reload the PAC file if: // 1) network.proxy.type changed, or // 2) network.proxy.autoconfig_url changed and PAC is configured
if (!pref || !strcmp(pref, PROXY_PREF("autoconfig_url"))) reloadPAC = true;
if (reloadPAC) {
tempString.Truncate(); if (mProxyConfig == PROXYCONFIG_PAC) {
prefBranch->GetCharPref(PROXY_PREF("autoconfig_url"), tempString); if (mPACMan && !mPACMan->IsPACURI(tempString)) {
LOG(("PAC Thread URI Changed - Reset Pac Thread"));
ResetPACThread();
}
} elseif (mProxyConfig == PROXYCONFIG_WPAD) {
LOG(("Auto-detecting proxy - Reset Pac Thread"));
ResetPACThread();
} elseif (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM &&
StaticPrefs::network_proxy_system_wpad()) {
AsyncConfigureWPADOrFromPAC(false, false, true);
} elseif (mSystemProxySettings) { // Get System Proxy settings if available
AsyncConfigureWPADOrFromPAC(false, false, false);
} if (!tempString.IsEmpty() || mProxyConfig == PROXYCONFIG_WPAD) {
ConfigureFromPAC(tempString, false);
}
}
}
PRIPv6Addr ipv6; if (is_ipaddr) { // convert parsed address to IPv6 if (addr.raw.family == PR_AF_INET) { // convert to IPv4-mapped address
PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &ipv6);
} elseif (addr.raw.family == PR_AF_INET6) { // copy the address
memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
} else {
NS_WARNING("unknown address family"); returntrue; // allow proxying
}
}
// Don't use proxy for local hosts (plain hostname, no dots) if ((!is_ipaddr && mFilterLocalHosts && !host.Contains('.')) || // This method detects if we have network.proxy.allow_hijacking_localhost // pref enabled. If it's true then this method will always return false // otherwise it returns true if the host matches an address that's // hardcoded to the loopback address.
(!StaticPrefs::network_proxy_allow_hijacking_localhost() &&
nsMixedContentBlocker::IsPotentiallyTrustworthyLoopbackHost(host))) {
LOG(("Not using proxy for this local host [%s]!\n", host.get())); returnfalse; // don't allow proxying
}
int32_t index = -1; while (++index < int32_t(mHostFiltersArray.Length())) { constauto& hinfo = mHostFiltersArray[index];
if (is_ipaddr != hinfo->is_ipaddr) continue; if (hinfo->port && hinfo->port != port) continue;
if (is_ipaddr) { // generate masked version of target IPv6 address
PRIPv6Addr masked;
memcpy(&masked, &ipv6, sizeof(PRIPv6Addr));
proxy_MaskIPv6Addr(masked, hinfo->ip.mask_len);
// check for a match if (memcmp(&masked, &hinfo->ip.addr, sizeof(PRIPv6Addr)) == 0) { returnfalse; // proxy disallowed
}
} else {
uint32_t host_len = host.Length();
uint32_t filter_host_len = hinfo->name.host_len;
if (host_len >= filter_host_len) { // // compare last |filter_host_len| bytes of target hostname. // constchar* host_tail = host.get() + host_len - filter_host_len; if (!nsCRT::strncasecmp(host_tail, hinfo->name.host, filter_host_len)) { // If the tail of the host string matches the filter
if (filter_host_len > 0 && hinfo->name.host[0] == '.') { // If the filter was of the form .foo.bar.tld, all such // matches are correct returnfalse; // proxy disallowed
}
// abc-def.example.org should not match def.example.org // however, *.def.example.org should match .def.example.org // We check that the filter doesn't start with a `.`. If it does, // then the strncasecmp above should suffice. If it doesn't, // then we should only consider it a match if the strncasecmp happened // at a subdomain boundary if (host_len > filter_host_len && *(host_tail - 1) == '.') { // If the host was something.foo.bar.tld and the filter // was foo.bar.tld, it's still a match. // the character right before the tail must be a // `.` for this to work returnfalse; // proxy disallowed
}
if (host_len == filter_host_len) { // If the host and filter are of the same length, // they should match returnfalse; // proxy disallowed
}
}
}
}
} returntrue;
}
// kProxyType\* may be referred to externally in // nsProxyInfo in order to compare by string pointer constchar kProxyType_HTTP[] = "http"; constchar kProxyType_HTTPS[] = "https"; constchar kProxyType_PROXY[] = "proxy"; constchar kProxyType_SOCKS[] = "socks"; constchar kProxyType_SOCKS4[] = "socks4"; constchar kProxyType_SOCKS5[] = "socks5"; constchar kProxyType_DIRECT[] = "direct";
// see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl
// find end of proxy info delimiter constchar* end = start; while (*end && *end != ';') ++end;
// find end of proxy type delimiter constchar* sp = start; while (sp < end && *sp != ' ' && *sp != '\t') ++sp;
uint32_t len = sp - start; constchar* type = nullptr; switch (len) { case 4: if (nsCRT::strncasecmp(start, kProxyType_HTTP, 4) == 0) {
type = kProxyType_HTTP;
} break; case 5: if (nsCRT::strncasecmp(start, kProxyType_PROXY, 5) == 0) {
type = kProxyType_HTTP;
} elseif (nsCRT::strncasecmp(start, kProxyType_SOCKS, 5) == 0) {
type = kProxyType_SOCKS4; // assume v4 for 4x compat if (StaticPrefs::network_proxy_default_pac_script_socks_version() ==
5) {
type = kProxyType_SOCKS;
}
} elseif (nsCRT::strncasecmp(start, kProxyType_HTTPS, 5) == 0) {
type = kProxyType_HTTPS;
} break; case 6: if (nsCRT::strncasecmp(start, kProxyType_DIRECT, 6) == 0) {
type = kProxyType_DIRECT;
} elseif (nsCRT::strncasecmp(start, kProxyType_SOCKS4, 6) == 0) {
type = kProxyType_SOCKS4;
} elseif (nsCRT::strncasecmp(start, kProxyType_SOCKS5, 6) == 0) { // map "SOCKS5" to "socks" to match contract-id of registered // SOCKS-v5 socket provider.
type = kProxyType_SOCKS;
} break;
} if (type) {
int32_t port = -1;
// If it's a SOCKS5 proxy, do name resolution on the server side. // We could use this with SOCKS4a servers too, but they might not // support it. if (type == kProxyType_SOCKS || mSOCKS5ProxyRemoteDNS) {
flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
}
// port defaults if (type == kProxyType_HTTP) {
port = 80;
} elseif (type == kProxyType_HTTPS) {
port = 443;
} else {
port = 1080;
}
RefPtr<nsProxyInfo> pi = new nsProxyInfo();
pi->mType = type;
pi->mFlags = flags;
pi->mResolveFlags = aResolveFlags;
pi->mTimeout = mFailedProxyTimeout;
// www.foo.com:8080 and http://www.foo.com:8080
nsDependentCSubstring maybeURL(start, end - start);
nsCOMPtr<nsIURI> pacURI;
nsAutoCString urlHost; // First assume the scheme is present, e.g. http://www.example.com:8080 if (NS_FAILED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) ||
NS_FAILED(pacURI->GetAsciiHost(urlHost)) || urlHost.IsEmpty()) { // It isn't, assume www.example.com:8080
maybeURL.Insert("http://", 0);
if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL))) {
pacURI->GetAsciiHost(urlHost);
}
}
if (!urlHost.IsEmpty()) {
pi->mHost = urlHost;
int32_t tPort; if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) {
port = tPort;
}
pi->mPort = port;
}
// Add timeout to interval (this is the time when the proxy can // be tried again).
dsec += pi->mTimeout;
// NOTE: The classic codebase would increase the timeout value // incrementally each time a subsequent failure occurred. // We could do the same, but it would require that we not // remove proxy entries in IsProxyDisabled or otherwise // change the way we are recording disabled proxies. // Simpler is probably better for now, and at least the // user can tune the timeout setting via preferences.
LOG(("DisableProxy %s %d\n", key.get(), dsec));
// If this fails, oh well... means we don't have enough memory // to remember the failed proxy.
mFailedProxies.InsertOrUpdate(key, dsec);
}
if (!pacSpec.IsEmpty() || type == PROXYCONFIG_WPAD) {
ConfigureFromPAC(pacSpec, true);
} return NS_OK;
}
// When sync interface is removed this can go away too // The nsPACManCallback portion of this implementation should be run // off the main thread, because it uses a condvar for signaling and // the main thread is blocking on that condvar - // so call nsPACMan::AsyncGetProxyForURI() with // a false mainThreadResponse parameter. class nsAsyncBridgeRequest final : public nsPACManCallback {
NS_DECL_THREADSAFE_ISUPPORTS
nsProtocolInfo info;
rv = GetProtocolInfo(uri, &info); if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIProxyInfo> pi; bool usePACThread;
// adapt to realtime changes in the system proxy service if (mProxyConfig == PROXYCONFIG_SYSTEM &&
!StaticPrefs::network_proxy_system_wpad()) {
nsCOMPtr<nsISystemProxySettings> sp2 =
do_GetService(NS_SYSTEMPROXYSETTINGS_CONTRACTID); if (sp2 != mSystemProxySettings) {
mSystemProxySettings = sp2;
ResetPACThread();
}
}
rv = SetupPACThread(mainThreadEventTarget); if (NS_FAILED(rv)) { return rv;
}
// SystemProxySettings and PAC files can block the main thread // but if neither of them are in use, we can just do the work // right here and directly invoke the callback
if (!usePACThread || !mPACMan) { // we can do it locally
rv = ctx->ProcessLocally(info, pi, isSyncOK); if (NS_SUCCEEDED(rv) && !isSyncOK) {
ctx.forget(result);
} return rv;
}
// else kick off a PAC thread query
rv = mPACMan->AsyncGetProxyForURI(uri, ctx, flags, true); if (NS_SUCCEEDED(rv)) ctx.forget(result); return rv;
}
NS_IMETHODIMP
nsProtocolProxyService::AsyncResolve(
nsISupports* channelOrURI, uint32_t flags,
nsIProtocolProxyCallback* callback,
nsISerialEventTarget* mainThreadEventTarget, nsICancelable** result) {
nsresult rv; // Check if we got a channel:
nsCOMPtr<nsIChannel> channel = do_QueryInterface(channelOrURI); if (!channel) {
nsCOMPtr<nsIURI> uri = do_QueryInterface(channelOrURI); if (!uri) { return NS_ERROR_NO_INTERFACE;
}
// creating a temporary channel from the URI which is not // used to perform any network loads, hence its safe to // use systemPrincipal as the loadingPrincipal.
rv = NS_NewChannel(getter_AddRefs(channel), uri,
nsContentUtils::GetSystemPrincipal(),
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
nsIContentPolicy::TYPE_OTHER);
NS_ENSURE_SUCCESS(rv, rv);
}
// resolve type; this allows us to avoid copying the type string into each // proxy info instance. we just reference the string literals directly :) constchar* type = nullptr; for (auto& t : types) { if (aType.LowerCaseEqualsASCII(t)) {
type = t; break;
}
}
NS_ENSURE_TRUE(type, NS_ERROR_INVALID_ARG);
// We have only implemented username/password for SOCKS proxies. if ((!aUsername.IsEmpty() || !aPassword.IsEmpty()) &&
!aType.LowerCaseEqualsASCII(kProxyType_SOCKS) &&
!aType.LowerCaseEqualsASCII(kProxyType_SOCKS4)) { return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo* aProxy, nsIURI* aURI,
nsresult aStatus,
nsIProxyInfo** aResult) { // Failover is supported through a variety of methods including: // * PAC scripts (PROXYCONFIG_PAC and PROXYCONFIG_WPAD) // * System proxy // * Extensions // With extensions the mProxyConfig can be any type and the extension // is still involved in the proxy filtering. It may have also supplied // any number of failover proxies. We cannot determine what the mix is // here, so we will attempt to get a failover regardless of the config // type. MANUAL configuration will not disable a proxy.
// Verify that |aProxy| is one of our nsProxyInfo objects.
nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
NS_ENSURE_ARG(pi); // OK, the QI checked out. We can proceed.
// Remember that this proxy is down. If the user has manually configured some // proxies we do not want to disable them. if (mProxyConfig != PROXYCONFIG_MANUAL) {
DisableProxy(pi);
}
// NOTE: At this point, we might want to prompt the user if we have // not already tried going DIRECT. This is something that the // classic codebase supported; however, IE6 does not prompt.
if (!pi->mNext) return NS_ERROR_NOT_AVAILABLE;
LOG(("PAC failover from %s %s:%d to %s %s:%d\n", pi->mType, pi->mHost.get(),
pi->mPort, pi->mNext->mType, pi->mNext->mHost.get(), pi->mNext->mPort));
// If we add a new element with the same position as an existing one, we want // to preserve the insertion order to avoid surprises.
mFilters.InsertElementSorted(link, ProxyFilterPositionComparator());
NotifyProxyConfigChangedInternal();
return NS_OK;
}
NS_IMETHODIMP
nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter* filter,
uint32_t position) {
UnregisterFilter(filter); // remove this filter if we already have it
RefPtr<FilterLink> link = new FilterLink(position, filter); return InsertFilterLink(std::move(link));
}
NS_IMETHODIMP
nsProtocolProxyService::RegisterChannelFilter(
nsIProtocolProxyChannelFilter* channelFilter, uint32_t position) {
UnregisterChannelFilter(
channelFilter); // remove this filter if we already have it
RefPtr<FilterLink> link = new FilterLink(position, channelFilter); return InsertFilterLink(std::move(link));
}
NS_IMETHODIMP
nsProtocolProxyService::UnregisterFilter(nsIProtocolProxyFilter* filter) { // QI to nsISupports so we can safely test object identity.
nsCOMPtr<nsISupports> givenObject = do_QueryInterface(filter); return RemoveFilterLink(givenObject);
}
NS_IMETHODIMP
nsProtocolProxyService::UnregisterChannelFilter(
nsIProtocolProxyChannelFilter* channelFilter) { // QI to nsISupports so we can safely test object identity.
nsCOMPtr<nsISupports> givenObject = do_QueryInterface(channelFilter); return RemoveFilterLink(givenObject);
}
if (token.Equals(mozilla::Tokenizer::Token::Char('['))) {
parsingIPv6 = true; continue;
}
if (!parsingIPv6 && token.Equals(mozilla::Tokenizer::Token::Char(':'))) { // Port is starting. Claim the previous as host. if (parsingMask) {
t.Claim(maskStr);
} else {
t.Claim(hostStr);
}
t.Record();
parsingPort = true; continue;
}
if (token.Equals(mozilla::Tokenizer::Token::Char('/'))) {
t.Claim(hostStr);
t.Record();
parsingMask = true; continue;
}
if (token.Equals(mozilla::Tokenizer::Token::Char(']'))) {
parsingIPv6 = false; continue;
}
} if (!parsingPort && !parsingMask) {
t.Claim(hostStr);
} elseif (parsingPort) {
t.Claim(portStr);
} elseif (parsingMask) {
t.Claim(maskStr);
} else {
NS_WARNING("Could not parse this rule"); continue;
}
if (hostStr.IsEmpty()) { continue;
}
// If the current host filter is "<local>", then all local (i.e. // no dots in the hostname) hosts should bypass the proxy if (hostStr.EqualsIgnoreCase("")) {
mFilterLocalHosts = true;
LOG(
("loaded filter for local hosts " "(plain host names, no dots)\n")); // Continue to next host filter; continue;
}
// For all other host filters, create HostInfo object and add to list
HostInfo* hinfo = new HostInfo();
nsresult rv = NS_OK;
int32_t port = portStr.ToInteger(&rv); if (NS_FAILED(rv)) {
port = 0;
}
hinfo->port = port;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.