Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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/. */
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/AutoRestore.h"
#include "nsProtocolProxyService.h"
#include "nsProxyInfo.h"
#include "nsIClassInfoImpl.h"
#include "nsIIOService.h"
#include "nsIObserverService.h"
#include "nsIProtocolHandler.h"
#include "nsIProtocolProxyCallback.h"
#include "nsIChannel.h"
#include "nsICancelable.h"
#include "nsDNSService2.h"
#include "nsPIDNSService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsContentUtils.h"
#include "nsCRT.h"
#include "nsThreadUtils.h"
#include "nsQueryObject.h"
#include "nsSOCKSIOLayer.h"
#include "nsString.h"
#include "nsNetUtil.h"
#include "nsNetCID.h"
#include "prnetdb.h"
#include "nsPACMan.h"
#include "nsProxyRelease.h"
#include "mozilla/Mutex.h"
#include "mozilla/CondVar.h"
#include "nsISystemProxySettings.h"
#include "nsINetworkLinkService.h"
#include "nsIHttpChannelInternal.h"
#include "mozilla/dom/nsMixedContentBlocker.h"
#include "mozilla/Logging.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_network.h"
#include "mozilla/Tokenizer.h"
#include "mozilla/Unused.h"
//----------------------------------------------------------------------------
namespace mozilla {
namespace net {
extern const char kProxyType_HTTP[];
extern const char kProxyType_HTTPS[];
extern const char kProxyType_SOCKS[];
extern const char kProxyType_SOCKS4[];
extern const char kProxyType_SOCKS5[];
extern const char kProxyType_DIRECT[];
extern const char kProxyType_PROXY[];
#undef LOG
#define LOG(args) MOZ_LOG(gProxyLog, LogLevel::Debug, args)
//----------------------------------------------------------------------------
#define PROXY_PREF_BRANCH "network.proxy"
#define PROXY_PREF(x) PROXY_PREF_BRANCH "." x
//----------------------------------------------------------------------------
// This structure is intended to be allocated on the stack
struct nsProtocolInfo {
nsAutoCString scheme;
uint32_t flags = 0;
int32_t defaultPort = 0;
};
//----------------------------------------------------------------------------
// Return the channel's proxy URI, or if it doesn't exist, the
// channel's main URI.
static nsresult GetProxyURI(nsIChannel* channel, nsIURI** aOut) {
nsresult rv = NS_OK;
nsCOMPtr<nsIURI> proxyURI;
nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(channel));
if (httpChannel) {
rv = httpChannel->GetProxyURI(getter_AddRefs(proxyURI));
}
if (!proxyURI) {
rv = channel->GetURI(getter_AddRefs(proxyURI));
}
if (NS_FAILED(rv)) {
return rv;
}
proxyURI.forget(aOut);
return NS_OK;
}
//-----------------------------------------------------------------------------
nsProtocolProxyService::FilterLink::FilterLink(uint32_t p,
nsIProtocolProxyFilter* f)
: position(p), filter(f), channelFilter(nullptr) {
LOG(("nsProtocolProxyService::FilterLink::FilterLink %p, filter=%p", this,
f));
}
nsProtocolProxyService::FilterLink::FilterLink(
uint32_t p, nsIProtocolProxyChannelFilter* cf)
: position(p), filter(nullptr), channelFilter(cf) {
LOG(("nsProtocolProxyService::FilterLink::FilterLink %p, channel-filter=%p",
this, cf));
}
nsProtocolProxyService::FilterLink::~FilterLink() {
LOG(("nsProtocolProxyService::FilterLink::~FilterLink %p", this));
}
//-----------------------------------------------------------------------------
// 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
nsAsyncResolveRequest(nsProtocolProxyService* pps, nsIChannel* channel,
uint32_t aResolveFlags,
nsIProtocolProxyCallback* callback)
: mResolveFlags(aResolveFlags),
mPPS(pps),
mXPComPPS(pps),
mChannel(channel),
mCallback(callback) {
NS_ASSERTION(mCallback, "null callback");
}
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;
}
nsCOMPtr<nsIProxyInfo> proxyInfo =
pi->CloneProxyInfoWithNewResolveFlags(mResolveFlags);
mProxyInfo.swap(proxyInfo);
}
public:
nsresult ProcessLocally(nsProtocolInfo& info, nsIProxyInfo* pi,
bool isSyncOK) {
SetResult(NS_OK, pi);
auto consumeFiltersResult = [isSyncOK](nsAsyncResolveRequest* ctx,
nsIProxyInfo* pi,
bool aCalledAsync) -> nsresult {
ctx->SetResult(NS_OK, pi);
if (isSyncOK || aCalledAsync) {
ctx->Run();
return NS_OK;
}
return ctx->DispatchCallback();
};
mAsyncFilterApplier = new AsyncApplyFilters(info, consumeFiltersResult);
// may call consumeFiltersResult() directly
return mAsyncFilterApplier->AsyncProcess(this);
}
void SetResult(nsresult status, nsIProxyInfo* pi) {
mStatus = status;
mProxyInfo = pi;
}
NS_IMETHOD Run() override {
if (mCallback) DoCallback();
return NS_OK;
}
NS_IMETHOD Cancel(nsresult reason) override {
NS_ENSURE_ARG(NS_FAILED(reason));
if (mAsyncFilterApplier) {
mAsyncFilterApplier->Cancel(reason);
}
// If we've already called DoCallback then, nothing more to do.
if (!mCallback) return NS_OK;
SetResult(reason, nullptr);
return DispatchCallback();
}
nsresult DispatchCallback() {
if (mDispatched) { // Only need to dispatch once
return NS_OK;
}
nsresult rv = NS_DispatchToCurrentThread(this);
if (NS_FAILED(rv)) {
NS_WARNING("unable to dispatch callback event");
} else {
mDispatched = true;
return NS_OK;
}
mCallback = nullptr; // break possible reference cycle
return rv;
}
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));
// Now apply proxy filters
nsProtocolInfo info;
mStatus = mPPS->GetProtocolInfo(proxyURI, &info);
auto consumeFiltersResult = [pacAvailable](nsAsyncResolveRequest* self,
nsIProxyInfo* pi,
bool async) -> nsresult {
LOG(("DoCallback::consumeFiltersResult this=%p, pi=%p, async=%d", self,
pi, async));
self->mProxyInfo = pi;
if (pacAvailable) {
// if !pacAvailable, it was already logged above
LOG(("pac thread callback %s\n", self->mPACString.get()));
}
if (NS_SUCCEEDED(self->mStatus)) {
self->mPPS->MaybeDisableDNSPrefetch(self->mProxyInfo);
}
self->EnsureResolveFlagsMatch();
self->mCallback->OnProxyAvailable(self, self->mChannel,
self->mProxyInfo, self->mStatus);
return NS_OK;
};
if (NS_SUCCEEDED(mStatus)) {
mAsyncFilterApplier = new AsyncApplyFilters(info, consumeFiltersResult);
// This may call consumeFiltersResult() directly.
mAsyncFilterApplier->AsyncProcess(this);
return;
}
consumeFiltersResult(this, nullptr, false);
} else if (NS_SUCCEEDED(mStatus) && !mPACURL.IsEmpty()) {
LOG(("pac thread callback indicates new pac file load\n"));
nsCOMPtr<nsIURI> proxyURI;
GetProxyURI(mChannel, getter_AddRefs(proxyURI));
// 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;
}
private:
nsresult mStatus{NS_OK};
nsCString mPACString;
nsCString mPACURL;
bool mDispatched{false};
uint32_t mResolveFlags;
nsProtocolProxyService* mPPS;
nsCOMPtr<nsIProtocolProxyService> mXPComPPS;
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIProtocolProxyCallback> mCallback;
nsCOMPtr<nsIProxyInfo> mProxyInfo;
RefPtr<AsyncApplyFilters> mAsyncFilterApplier;
};
NS_IMPL_ISUPPORTS(nsAsyncResolveRequest, nsICancelable, nsIRunnable)
NS_IMPL_ISUPPORTS(nsAsyncResolveRequest::AsyncApplyFilters,
nsIProxyProtocolFilterResult, nsICancelable, nsIRunnable)
nsAsyncResolveRequest::AsyncApplyFilters::AsyncApplyFilters(
nsProtocolInfo& aInfo, Callback const& aCallback)
: mInfo(aInfo),
mCallback(aCallback),
mNextFilterIndex(0),
mProcessingInLoop(false),
mFilterCalledBack(false) {
LOG(("AsyncApplyFilters %p", this));
}
nsAsyncResolveRequest::AsyncApplyFilters::~AsyncApplyFilters() {
LOG(("~AsyncApplyFilters %p", this));
MOZ_ASSERT(!mRequest);
MOZ_ASSERT(!mProxyInfo);
MOZ_ASSERT(!mFiltersCopy.Length());
}
nsresult nsAsyncResolveRequest::AsyncApplyFilters::AsyncProcess(
nsAsyncResolveRequest* aRequest) {
LOG(("AsyncApplyFilters::AsyncProcess %p for req %p", this, aRequest));
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);
}
mProcessingThread = NS_GetCurrentThread();
mRequest = aRequest;
mProxyInfo = aRequest->mProxyInfo;
aRequest->mPPS->CopyFilters(mFiltersCopy);
// 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);
mozilla::AutoRestore<bool> restore(mProcessingInLoop);
mProcessingInLoop = true;
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);
LOG(("AsyncApplyFilters::ProcessNextFilter %p LEAVE pi=%p", this,
mProxyInfo.get()));
return NS_OK;
}
NS_IMETHODIMP
nsAsyncResolveRequest::AsyncApplyFilters::OnProxyFilterResult(
nsIProxyInfo* aProxyInfo) {
LOG(("AsyncApplyFilters::OnProxyFilterResult %p pi=%p", this, aProxyInfo));
MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
MOZ_ASSERT(!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;
}
NS_IMETHODIMP
nsAsyncResolveRequest::AsyncApplyFilters::Run() {
LOG(("AsyncApplyFilters::Run %p", this));
MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
ProcessNextFilter();
return NS_OK;
}
nsresult nsAsyncResolveRequest::AsyncApplyFilters::Finish() {
LOG(("AsyncApplyFilters::Finish %p pi=%p", this, mProxyInfo.get()));
MOZ_ASSERT(mRequest);
mFiltersCopy.Clear();
RefPtr<nsAsyncResolveRequest> request;
request.swap(mRequest);
nsCOMPtr<nsIProxyInfo> pi;
pi.swap(mProxyInfo);
request->mPPS->PruneProxyInfo(mInfo, pi);
return mCallback(request, pi, !mProcessingInLoop);
}
NS_IMETHODIMP
nsAsyncResolveRequest::AsyncApplyFilters::Cancel(nsresult reason) {
LOG(("AsyncApplyFilters::Cancel %p", this));
MOZ_ASSERT(mProcessingThread && mProcessingThread->IsOnCurrentThread());
// 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);
AsyncGetPACURIRequestOrSystemWPADSetting(
nsProtocolProxyService* aService, CallbackFunc aCallback,
nsISystemProxySettings* aSystemProxySettings, bool aMainThreadOnly,
bool aForceReload, bool aResetPACThread, bool aSystemWPADAllowed)
: mIsMainThreadOnly(aMainThreadOnly),
mService(aService),
mServiceHolder(do_QueryObject(aService)),
mCallback(aCallback),
mSystemProxySettings(aSystemProxySettings),
mForceReload(aForceReload),
mResetPACThread(aResetPACThread),
mSystemWPADAllowed(aSystemWPADAllowed) {
MOZ_ASSERT(NS_IsMainThread());
Unused << mIsMainThreadOnly;
}
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread() == mIsMainThreadOnly);
nsresult rv;
nsCString pacUri;
bool systemWPADSetting = false;
if (mSystemWPADAllowed) {
mSystemProxySettings->GetSystemWPADSetting(&systemWPADSetting);
}
rv = mSystemProxySettings->GetPACURI(pacUri);
nsCOMPtr<nsIRunnable> event =
NewNonOwningCancelableRunnableMethod<bool, bool, nsresult, nsCString,
bool>(
"AsyncGetPACURIRequestOrSystemWPADSettingCallback", mService,
mCallback, mForceReload, mResetPACThread, rv, pacUri,
systemWPADSetting);
return NS_DispatchToMainThread(event);
}
private:
~AsyncGetPACURIRequestOrSystemWPADSetting() {
NS_ReleaseOnMainThread(
"AsyncGetPACURIRequestOrSystemWPADSetting::mServiceHolder",
mServiceHolder.forget());
}
bool mIsMainThreadOnly;
nsProtocolProxyService* mService; // ref-count is hold by mServiceHolder
nsCOMPtr<nsIProtocolProxyService2> mServiceHolder;
CallbackFunc mCallback;
nsCOMPtr<nsISystemProxySettings> mSystemProxySettings;
bool mForceReload;
bool mResetPACThread;
bool mSystemWPADAllowed;
};
NS_IMPL_ISUPPORTS(AsyncGetPACURIRequestOrSystemWPADSetting, nsIRunnable)
//----------------------------------------------------------------------------
//
// apply mask to address (zeros out excluded bits).
//
// NOTE: we do the byte swapping here to minimize overall swapping.
//
static void proxy_MaskIPv6Addr(PRIPv6Addr& addr, uint16_t mask_len) {
if (mask_len == 128) return;
if (mask_len > 96) {
addr.pr_s6_addr32[3] =
PR_htonl(PR_ntohl(addr.pr_s6_addr32[3]) & (~0uL << (128 - mask_len)));
} else if (mask_len > 64) {
addr.pr_s6_addr32[3] = 0;
addr.pr_s6_addr32[2] =
PR_htonl(PR_ntohl(addr.pr_s6_addr32[2]) & (~0uL << (96 - mask_len)));
} else if (mask_len > 32) {
addr.pr_s6_addr32[3] = 0;
addr.pr_s6_addr32[2] = 0;
addr.pr_s6_addr32[1] =
PR_htonl(PR_ntohl(addr.pr_s6_addr32[1]) & (~0uL << (64 - mask_len)));
} else {
addr.pr_s6_addr32[3] = 0;
addr.pr_s6_addr32[2] = 0;
addr.pr_s6_addr32[1] = 0;
addr.pr_s6_addr32[0] =
PR_htonl(PR_ntohl(addr.pr_s6_addr32[0]) & (~0uL << (32 - mask_len)));
}
}
static void proxy_GetStringPref(nsIPrefBranch* aPrefBranch, const char* 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();
}
}
static void proxy_GetIntPref(nsIPrefBranch* aPrefBranch, const char* aPref,
int32_t& aResult) {
int32_t temp;
nsresult rv = aPrefBranch->GetIntPref(aPref, &temp);
if (NS_FAILED(rv)) {
aResult = -1;
} else {
aResult = temp;
}
}
static void proxy_GetBoolPref(nsIPrefBranch* aPrefBranch, const char* aPref,
bool& aResult) {
bool temp;
nsresult rv = aPrefBranch->GetBoolPref(aPref, &temp);
if (NS_FAILED(rv)) {
aResult = false;
} else {
aResult = temp;
}
}
//----------------------------------------------------------------------------
static const int32_t PROXYCONFIG_DIRECT4X = 3;
static const int32_t PROXYCONFIG_COUNT = 6;
NS_IMPL_ADDREF(nsProtocolProxyService)
NS_IMPL_RELEASE(nsProtocolProxyService)
NS_IMPL_CLASSINFO(nsProtocolProxyService, nullptr, nsIClassInfo::SINGLETON,
NS_PROTOCOLPROXYSERVICE_CID)
// NS_IMPL_QUERY_INTERFACE_CI with the nsProtocolProxyService QI change
NS_INTERFACE_MAP_BEGIN(nsProtocolProxyService)
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyService)
NS_INTERFACE_MAP_ENTRY(nsIProtocolProxyService2)