123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* vim:set ts=4 sw=4 sts=4 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 "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 "nsIDNSService.h"
- #include "nsPIDNSService.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsIPrefService.h"
- #include "nsIPrefBranch.h"
- #include "nsThreadUtils.h"
- #include "nsSOCKSIOLayer.h"
- #include "nsString.h"
- #include "nsNetUtil.h"
- #include "nsNetCID.h"
- #include "plstr.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/Logging.h"
- #include "mozilla/Tokenizer.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[];
- #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
- #define WPAD_URL "http://wpad/wpad.dat"
- //----------------------------------------------------------------------------
- // This structure is intended to be allocated on the stack
- struct nsProtocolInfo {
- nsAutoCString scheme;
- uint32_t flags;
- int32_t defaultPort;
- };
- //----------------------------------------------------------------------------
- // 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;
- }
- //-----------------------------------------------------------------------------
- // 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)
- : mStatus(NS_OK)
- , mDispatched(false)
- , 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(mChannel.forget());
- }
- if (mCallback) {
- NS_ReleaseOnMainThread(mCallback.forget());
- }
- if (mProxyInfo) {
- NS_ReleaseOnMainThread(mProxyInfo.forget());
- }
- if (mXPComPPS) {
- NS_ReleaseOnMainThread(mXPComPPS.forget());
- }
- }
- }
- public:
- 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 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 nsCString &pacString,
- const nsCString &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 = NS_LITERAL_CSTRING("DIRECT;");
- 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);
- if (NS_SUCCEEDED(mStatus))
- mPPS->ApplyFilters(mChannel, info, mProxyInfo);
- else
- mProxyInfo = nullptr;
- if(pacAvailable) {
- // if !pacAvailable, it was already logged above
- LOG(("pac thread callback %s\n", mPACString.get()));
- }
- if (NS_SUCCEEDED(mStatus))
- mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
- mCallback->OnProxyAvailable(this, mChannel, mProxyInfo, mStatus);
- }
- 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,
- 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 %X\n", mStatus));
- if (NS_SUCCEEDED(mStatus))
- mPPS->MaybeDisableDNSPrefetch(mProxyInfo);
- 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;
- nsCString mPACString;
- nsCString mPACURL;
- bool mDispatched;
- uint32_t mResolveFlags;
- nsProtocolProxyService *mPPS;
- nsCOMPtr<nsIProtocolProxyService> mXPComPPS;
- nsCOMPtr<nsIChannel> mChannel;
- nsCOMPtr<nsIProtocolProxyCallback> mCallback;
- nsCOMPtr<nsIProxyInfo> mProxyInfo;
- };
- NS_IMPL_ISUPPORTS(nsAsyncResolveRequest, nsICancelable, nsIRunnable)
- //----------------------------------------------------------------------------
- #define IS_ASCII_SPACE(_c) ((_c) == ' ' || (_c) == '\t')
- //
- // 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]) & (~0L << (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]) & (~0L << (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]) & (~0L << (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]) & (~0L << (32 - mask_len)));
- }
- }
- static void
- proxy_GetStringPref(nsIPrefBranch *aPrefBranch,
- const char *aPref,
- nsCString &aResult)
- {
- nsXPIDLCString temp;
- nsresult rv = aPrefBranch->GetCharPref(aPref, getter_Copies(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)
- NS_INTERFACE_MAP_ENTRY(nsIObserver)
- if ( aIID.Equals(NS_GET_IID(nsProtocolProxyService)) ) foundInterface = static_cast<nsIProtocolProxyService2*>(this); else
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIProtocolProxyService)
- NS_IMPL_QUERY_CLASSINFO(nsProtocolProxyService)
- NS_INTERFACE_MAP_END
- NS_IMPL_CI_INTERFACE_GETTER(nsProtocolProxyService,
- nsIProtocolProxyService,
- nsIProtocolProxyService2)
- nsProtocolProxyService::nsProtocolProxyService()
- : mFilterLocalHosts(false)
- , mFilters(nullptr)
- , mProxyConfig(PROXYCONFIG_DIRECT)
- , mHTTPProxyPort(-1)
- , mFTPProxyPort(-1)
- , mHTTPSProxyPort(-1)
- , mSOCKSProxyPort(-1)
- , mSOCKSProxyVersion(4)
- , mSOCKSProxyRemoteDNS(false)
- , mProxyOverTLS(true)
- , mPACMan(nullptr)
- , mSessionStart(PR_Now())
- , mFailedProxyTimeout(30 * 60) // 30 minute default
- {
- }
- nsProtocolProxyService::~nsProtocolProxyService()
- {
- // These should have been cleaned up in our Observe method.
- NS_ASSERTION(mHostFiltersArray.Length() == 0 && mFilters == nullptr &&
- 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;
- }
- int32_t type;
- nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
- if (NS_FAILED(rv)) {
- return NS_OK;
- }
- if (type == PROXYCONFIG_PAC) {
- nsXPIDLCString pacSpec;
- prefs->GetCharPref(PROXY_PREF("autoconfig_url"),
- getter_Copies(pacSpec));
- if (!pacSpec.IsEmpty()) {
- nsCOMPtr<nsIURI> pacURI;
- rv = NS_NewURI(getter_AddRefs(pacURI), pacSpec);
- if(!NS_SUCCEEDED(rv)) {
- return rv;
- }
- nsProtocolInfo pac;
- rv = GetProtocolInfo(pacURI, &pac);
- if(!NS_SUCCEEDED(rv)) {
- return rv;
- }
- if (!pac.scheme.EqualsLiteral("file") &&
- !pac.scheme.EqualsLiteral("data")) {
- LOG((": received network changed event, reload PAC"));
- ReloadPAC();
- }
- }
- } else if ((type == PROXYCONFIG_WPAD) || (type == PROXYCONFIG_SYSTEM)) {
- ReloadPAC();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsProtocolProxyService::Observe(nsISupports *aSubject,
- const char *aTopic,
- const char16_t *aData)
- {
- if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
- // cleanup
- if (mHostFiltersArray.Length() > 0) {
- mHostFiltersArray.Clear();
- }
- if (mFilters) {
- delete mFilters;
- mFilters = nullptr;
- }
- if (mPACMan) {
- mPACMan->Shutdown();
- mPACMan = nullptr;
- }
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- if (obs) {
- obs->RemoveObserver(this, NS_NETWORK_LINK_TOPIC);
- obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
- }
- } else if (strcmp(aTopic, NS_NETWORK_LINK_TOPIC) == 0) {
- nsCString converted = NS_ConvertUTF16toUTF8(aData);
- const char *state = converted.get();
- if (!strcmp(state, NS_NETWORK_LINK_DATA_CHANGED)) {
- ReloadNetworkPAC();
- }
- }
- else {
- NS_ASSERTION(strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID) == 0,
- "what is this random observer event?");
- nsCOMPtr<nsIPrefBranch> prefs = do_QueryInterface(aSubject);
- if (prefs)
- PrefsChanged(prefs, NS_LossyConvertUTF16toASCII(aData).get());
- }
- return NS_OK;
- }
- void
- nsProtocolProxyService::PrefsChanged(nsIPrefBranch *prefBranch,
- const char *pref)
- {
- nsresult rv = NS_OK;
- bool reloadPAC = false;
- nsXPIDLCString tempString;
- if (!pref || !strcmp(pref, PROXY_PREF("type"))) {
- 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);
- } else if (type >= PROXYCONFIG_COUNT) {
- LOG(("unknown proxy type: %lu; 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("ftp")))
- proxy_GetStringPref(prefBranch, PROXY_PREF("ftp"), mFTPProxyHost);
- if (!pref || !strcmp(pref, PROXY_PREF("ftp_port")))
- proxy_GetIntPref(prefBranch, PROXY_PREF("ftp_port"), mFTPProxyPort);
- 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 == 5)
- mSOCKSProxyVersion = 5;
- else
- mSOCKSProxyVersion = 4;
- }
- if (!pref || !strcmp(pref, PROXY_PREF("socks_remote_dns")))
- proxy_GetBoolPref(prefBranch, PROXY_PREF("socks_remote_dns"),
- mSOCKSProxyRemoteDNS);
- 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"),
- getter_Copies(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"),
- getter_Copies(tempString));
- if (mPACMan && !mPACMan->IsPACURI(tempString)) {
- LOG(("PAC Thread URI Changed - Reset Pac Thread"));
- ResetPACThread();
- }
- } else if (mProxyConfig == PROXYCONFIG_WPAD) {
- // We diverge from the WPAD spec here in that we don't walk the
- // hosts's FQDN, stripping components until we hit a TLD. Doing so
- // is dangerous in the face of an incomplete list of TLDs, and TLDs
- // get added over time. We could consider doing only a single
- // substitution of the first component, if that proves to help
- // compatibility.
- tempString.AssignLiteral(WPAD_URL);
- } else if (mSystemProxySettings) {
- // Get System Proxy settings if available
- mSystemProxySettings->GetPACURI(tempString);
- }
- if (!tempString.IsEmpty())
- ConfigureFromPAC(tempString, false);
- }
- }
- bool
- nsProtocolProxyService::CanUseProxy(nsIURI *aURI, int32_t defaultPort)
- {
- if (mHostFiltersArray.Length() == 0)
- return true;
- int32_t port;
- nsAutoCString host;
- nsresult rv = aURI->GetAsciiHost(host);
- if (NS_FAILED(rv) || host.IsEmpty())
- return false;
- rv = aURI->GetPort(&port);
- if (NS_FAILED(rv))
- return false;
- if (port == -1)
- port = defaultPort;
- PRNetAddr addr;
- bool is_ipaddr = (PR_StringToNetAddr(host.get(), &addr) == PR_SUCCESS);
- 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);
- }
- else if (addr.raw.family == PR_AF_INET6) {
- // copy the address
- memcpy(&ipv6, &addr.ipv6.ip, sizeof(PRIPv6Addr));
- }
- else {
- NS_WARNING("unknown address family");
- return true; // allow proxying
- }
- }
- // Don't use proxy for local hosts (plain hostname, no dots)
- if ((!is_ipaddr && mFilterLocalHosts && !host.Contains('.')) ||
- host.EqualsLiteral("127.0.0.1") ||
- host.EqualsLiteral("::1")) {
- LOG(("Not using proxy for this local host [%s]!\n", host.get()));
- return false; // don't allow proxying
- }
- int32_t index = -1;
- while (++index < int32_t(mHostFiltersArray.Length())) {
- HostInfo *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)
- return false; // 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.
- //
- const char *host_tail = host.get() + host_len - filter_host_len;
- if (!PL_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
- return false; // 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
- return false; // proxy disallowed
- }
- if (host_len == filter_host_len) {
- // If the host and filter are of the same length,
- // they should match
- return false; // proxy disallowed
- }
- }
- }
- }
- }
- return true;
- }
- // kProxyType\* may be referred to externally in
- // nsProxyInfo in order to compare by string pointer
- const char kProxyType_HTTP[] = "http";
- const char kProxyType_HTTPS[] = "https";
- const char kProxyType_PROXY[] = "proxy";
- const char kProxyType_SOCKS[] = "socks";
- const char kProxyType_SOCKS4[] = "socks4";
- const char kProxyType_SOCKS5[] = "socks5";
- const char kProxyType_DIRECT[] = "direct";
- const char *
- nsProtocolProxyService::ExtractProxyInfo(const char *start,
- uint32_t aResolveFlags,
- nsProxyInfo **result)
- {
- *result = nullptr;
- uint32_t flags = 0;
- // see BNF in ProxyAutoConfig.h and notes in nsISystemProxySettings.idl
- // find end of proxy info delimiter
- const char *end = start;
- while (*end && *end != ';') ++end;
- // find end of proxy type delimiter
- const char *sp = start;
- while (sp < end && *sp != ' ' && *sp != '\t') ++sp;
- uint32_t len = sp - start;
- const char *type = nullptr;
- switch (len) {
- case 4:
- if (PL_strncasecmp(start, kProxyType_HTTP, 5) == 0) {
- type = kProxyType_HTTP;
- }
- break;
- case 5:
- if (PL_strncasecmp(start, kProxyType_PROXY, 5) == 0) {
- type = kProxyType_HTTP;
- } else if (PL_strncasecmp(start, kProxyType_SOCKS, 5) == 0) {
- type = kProxyType_SOCKS4; // assume v4 for 4x compat
- } else if (PL_strncasecmp(start, kProxyType_HTTPS, 5) == 0) {
- type = kProxyType_HTTPS;
- }
- break;
- case 6:
- if (PL_strncasecmp(start, kProxyType_DIRECT, 6) == 0)
- type = kProxyType_DIRECT;
- else if (PL_strncasecmp(start, kProxyType_SOCKS4, 6) == 0)
- type = kProxyType_SOCKS4;
- else if (PL_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) {
- const char *host = nullptr, *hostEnd = nullptr;
- 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 || mSOCKSProxyRemoteDNS)
- flags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
- // extract host:port
- start = sp;
- while ((*start == ' ' || *start == '\t') && start < end)
- start++;
- // port defaults
- if (type == kProxyType_HTTP) {
- port = 80;
- } else if (type == kProxyType_HTTPS) {
- port = 443;
- } else {
- port = 1080;
- }
- 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;
- if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(pacURI), maybeURL)) &&
- NS_SUCCEEDED(pacURI->GetAsciiHost(urlHost)) &&
- !urlHost.IsEmpty()) {
- // http://www.example.com:8080
- pi->mHost = urlHost;
- int32_t tPort;
- if (NS_SUCCEEDED(pacURI->GetPort(&tPort)) && tPort != -1) {
- port = tPort;
- }
- pi->mPort = port;
- }
- else {
- // www.example.com:8080
- if (start < end) {
- host = start;
- hostEnd = strchr(host, ':');
- if (!hostEnd || hostEnd > end) {
- hostEnd = end;
- // no port, so assume default
- }
- else {
- port = atoi(hostEnd + 1);
- }
- }
- // YES, it is ok to specify a null proxy host.
- if (host) {
- pi->mHost.Assign(host, hostEnd - host);
- pi->mPort = port;
- }
- }
- NS_ADDREF(*result = pi);
- }
- while (*end == ';' || *end == ' ' || *end == '\t')
- ++end;
- return end;
- }
- void
- nsProtocolProxyService::GetProxyKey(nsProxyInfo *pi, nsCString &key)
- {
- key.AssignASCII(pi->mType);
- if (!pi->mHost.IsEmpty()) {
- key.Append(' ');
- key.Append(pi->mHost);
- key.Append(':');
- key.AppendInt(pi->mPort);
- }
- }
- uint32_t
- nsProtocolProxyService::SecondsSinceSessionStart()
- {
- PRTime now = PR_Now();
- // get time elapsed since session start
- int64_t diff = now - mSessionStart;
- // convert microseconds to seconds
- diff /= PR_USEC_PER_SEC;
- // return converted 32 bit value
- return uint32_t(diff);
- }
- void
- nsProtocolProxyService::EnableProxy(nsProxyInfo *pi)
- {
- nsAutoCString key;
- GetProxyKey(pi, key);
- mFailedProxies.Remove(key);
- }
- void
- nsProtocolProxyService::DisableProxy(nsProxyInfo *pi)
- {
- nsAutoCString key;
- GetProxyKey(pi, key);
- uint32_t dsec = SecondsSinceSessionStart();
- // 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.Put(key, dsec);
- }
- bool
- nsProtocolProxyService::IsProxyDisabled(nsProxyInfo *pi)
- {
- nsAutoCString key;
- GetProxyKey(pi, key);
- uint32_t val;
- if (!mFailedProxies.Get(key, &val))
- return false;
- uint32_t dsec = SecondsSinceSessionStart();
- // if time passed has exceeded interval, then try proxy again.
- if (dsec > val) {
- mFailedProxies.Remove(key);
- return false;
- }
- return true;
- }
- nsresult
- nsProtocolProxyService::SetupPACThread()
- {
- if (mPACMan)
- return NS_OK;
- mPACMan = new nsPACMan();
- bool mainThreadOnly;
- nsresult rv;
- if (mSystemProxySettings &&
- NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) &&
- !mainThreadOnly) {
- rv = mPACMan->Init(mSystemProxySettings);
- }
- else {
- rv = mPACMan->Init(nullptr);
- }
- if (NS_FAILED(rv))
- mPACMan = nullptr;
- return rv;
- }
- nsresult
- nsProtocolProxyService::ResetPACThread()
- {
- if (!mPACMan)
- return NS_OK;
- mPACMan->Shutdown();
- mPACMan = nullptr;
- return SetupPACThread();
- }
- nsresult
- nsProtocolProxyService::ConfigureFromPAC(const nsCString &spec,
- bool forceReload)
- {
- SetupPACThread();
- if (mPACMan->IsPACURI(spec) && !forceReload)
- return NS_OK;
- mFailedProxies.Clear();
- return mPACMan->LoadPACFromURI(spec);
- }
- void
- nsProtocolProxyService::ProcessPACString(const nsCString &pacString,
- uint32_t aResolveFlags,
- nsIProxyInfo **result)
- {
- if (pacString.IsEmpty()) {
- *result = nullptr;
- return;
- }
- const char *proxies = pacString.get();
- nsProxyInfo *pi = nullptr, *first = nullptr, *last = nullptr;
- while (*proxies) {
- proxies = ExtractProxyInfo(proxies, aResolveFlags, &pi);
- if (pi && (pi->mType == kProxyType_HTTPS) && !mProxyOverTLS) {
- delete pi;
- pi = nullptr;
- }
- if (pi) {
- if (last) {
- NS_ASSERTION(last->mNext == nullptr, "leaking nsProxyInfo");
- last->mNext = pi;
- }
- else
- first = pi;
- last = pi;
- }
- }
- *result = first;
- }
- // nsIProtocolProxyService2
- NS_IMETHODIMP
- nsProtocolProxyService::ReloadPAC()
- {
- nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
- if (!prefs)
- return NS_OK;
- int32_t type;
- nsresult rv = prefs->GetIntPref(PROXY_PREF("type"), &type);
- if (NS_FAILED(rv))
- return NS_OK;
- nsXPIDLCString pacSpec;
- if (type == PROXYCONFIG_PAC)
- prefs->GetCharPref(PROXY_PREF("autoconfig_url"), getter_Copies(pacSpec));
- else if (type == PROXYCONFIG_WPAD)
- pacSpec.AssignLiteral(WPAD_URL);
- if (!pacSpec.IsEmpty())
- 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
- nsAsyncBridgeRequest()
- : mMutex("nsDeprecatedCallback")
- , mCondVar(mMutex, "nsDeprecatedCallback")
- , mStatus(NS_OK)
- , mCompleted(false)
- {
- }
- void OnQueryComplete(nsresult status,
- const nsCString &pacString,
- const nsCString &newPACURL) override
- {
- MutexAutoLock lock(mMutex);
- mCompleted = true;
- mStatus = status;
- mPACString = pacString;
- mPACURL = newPACURL;
- mCondVar.Notify();
- }
- void Lock() { mMutex.Lock(); }
- void Unlock() { mMutex.Unlock(); }
- void Wait() { mCondVar.Wait(PR_SecondsToInterval(3)); }
- private:
- ~nsAsyncBridgeRequest()
- {
- }
- friend class nsProtocolProxyService;
- Mutex mMutex;
- CondVar mCondVar;
- nsresult mStatus;
- nsCString mPACString;
- nsCString mPACURL;
- bool mCompleted;
- };
- NS_IMPL_ISUPPORTS0(nsAsyncBridgeRequest)
- // nsProtocolProxyService
- nsresult
- nsProtocolProxyService::DeprecatedBlockingResolve(nsIChannel *aChannel,
- uint32_t aFlags,
- nsIProxyInfo **retval)
- {
- NS_ENSURE_ARG_POINTER(aChannel);
- nsCOMPtr<nsIURI> uri;
- nsresult rv = GetProxyURI(aChannel, getter_AddRefs(uri));
- if (NS_FAILED(rv)) return rv;
- nsProtocolInfo info;
- rv = GetProtocolInfo(uri, &info);
- if (NS_FAILED(rv))
- return rv;
- nsCOMPtr<nsIProxyInfo> pi;
- bool usePACThread;
- // 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
- rv = Resolve_Internal(aChannel, info, aFlags,
- &usePACThread, getter_AddRefs(pi));
- if (NS_FAILED(rv))
- return rv;
- if (!usePACThread || !mPACMan) {
- ApplyFilters(aChannel, info, pi);
- pi.forget(retval);
- return NS_OK;
- }
- // Use the PAC thread to do the work, so we don't have to reimplement that
- // code, but block this thread on that completion.
- RefPtr<nsAsyncBridgeRequest> ctx = new nsAsyncBridgeRequest();
- ctx->Lock();
- if (NS_SUCCEEDED(mPACMan->AsyncGetProxyForURI(uri, ctx, false))) {
- // this can really block the main thread, so cap it at 3 seconds
- ctx->Wait();
- }
- ctx->Unlock();
- if (!ctx->mCompleted)
- return NS_ERROR_FAILURE;
- if (NS_FAILED(ctx->mStatus))
- return ctx->mStatus;
- // pretty much duplicate real DoCallback logic
- // Generate proxy info from the PAC string if appropriate
- if (!ctx->mPACString.IsEmpty()) {
- LOG(("sync pac thread callback %s\n", ctx->mPACString.get()));
- ProcessPACString(ctx->mPACString, 0, getter_AddRefs(pi));
- ApplyFilters(aChannel, info, pi);
- pi.forget(retval);
- return NS_OK;
- }
- if (!ctx->mPACURL.IsEmpty()) {
- NS_WARNING("sync pac thread callback indicates new pac file load\n");
- // This is a problem and is one of the reasons this blocking interface
- // is deprecated. The main loop needs to spin to make this reload happen. So
- // we are going to kick off the reload and return an error - it will work
- // next time. Because this sync interface is only used in the java plugin it
- // is extremely likely that the pac file has already been loaded anyhow.
- rv = ConfigureFromPAC(ctx->mPACURL, false);
- if (NS_FAILED(rv))
- return rv;
- return NS_ERROR_NOT_AVAILABLE;
- }
- *retval = nullptr;
- return NS_OK;
- }
- nsresult
- nsProtocolProxyService::AsyncResolveInternal(nsIChannel *channel, uint32_t flags,
- nsIProtocolProxyCallback *callback,
- nsICancelable **result,
- bool isSyncOK)
- {
- NS_ENSURE_ARG_POINTER(channel);
- NS_ENSURE_ARG_POINTER(callback);
- nsCOMPtr<nsIURI> uri;
- nsresult rv = GetProxyURI(channel, getter_AddRefs(uri));
- if (NS_FAILED(rv)) return rv;
- *result = nullptr;
- RefPtr<nsAsyncResolveRequest> ctx =
- new nsAsyncResolveRequest(this, channel, flags, callback);
- nsProtocolInfo info;
- rv = GetProtocolInfo(uri, &info);
- if (NS_FAILED(rv))
- return rv;
- nsCOMPtr<nsIProxyInfo> pi;
- bool usePACThread;
- // 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
- rv = Resolve_Internal(channel, info, flags,
- &usePACThread, getter_AddRefs(pi));
- if (NS_FAILED(rv))
- return rv;
- if (!usePACThread || !mPACMan) {
- // we can do it locally
- ApplyFilters(channel, info, pi);
- ctx->SetResult(NS_OK, pi);
- if (isSyncOK) {
- ctx->Run();
- return NS_OK;
- }
- rv = ctx->DispatchCallback();
- if (NS_SUCCEEDED(rv))
- ctx.forget(result);
- return rv;
- }
- // else kick off a PAC thread query
- rv = mPACMan->AsyncGetProxyForURI(uri, ctx, true);
- if (NS_SUCCEEDED(rv))
- ctx.forget(result);
- return rv;
- }
- // nsIProtocolProxyService
- NS_IMETHODIMP
- nsProtocolProxyService::AsyncResolve2(nsIChannel *channel, uint32_t flags,
- nsIProtocolProxyCallback *callback,
- nsICancelable **result)
- {
- return AsyncResolveInternal(channel, flags, callback, result, true);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::AsyncResolve(nsISupports *channelOrURI, uint32_t flags,
- nsIProtocolProxyCallback *callback,
- 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;
- }
- nsCOMPtr<nsIScriptSecurityManager> secMan(
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPrincipal> systemPrincipal;
- rv = secMan->GetSystemPrincipal(getter_AddRefs(systemPrincipal));
- NS_ENSURE_SUCCESS(rv, rv);
- // 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,
- systemPrincipal,
- nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
- nsIContentPolicy::TYPE_OTHER);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- return AsyncResolveInternal(channel, flags, callback, result, false);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::NewProxyInfo(const nsACString &aType,
- const nsACString &aHost,
- int32_t aPort,
- uint32_t aFlags,
- uint32_t aFailoverTimeout,
- nsIProxyInfo *aFailoverProxy,
- nsIProxyInfo **aResult)
- {
- return NewProxyInfoWithAuth(aType, aHost, aPort,
- EmptyCString(), EmptyCString(),
- aFlags, aFailoverTimeout,
- aFailoverProxy, aResult);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::NewProxyInfoWithAuth(const nsACString &aType,
- const nsACString &aHost,
- int32_t aPort,
- const nsACString &aUsername,
- const nsACString &aPassword,
- uint32_t aFlags,
- uint32_t aFailoverTimeout,
- nsIProxyInfo *aFailoverProxy,
- nsIProxyInfo **aResult)
- {
- static const char *types[] = {
- kProxyType_HTTP,
- kProxyType_HTTPS,
- kProxyType_SOCKS,
- kProxyType_SOCKS4,
- kProxyType_DIRECT
- };
- // resolve type; this allows us to avoid copying the type string into each
- // proxy info instance. we just reference the string literals directly :)
- const char *type = nullptr;
- for (uint32_t i = 0; i < ArrayLength(types); ++i) {
- if (aType.LowerCaseEqualsASCII(types[i])) {
- type = types[i];
- 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;
- }
- return NewProxyInfo_Internal(type, aHost, aPort,
- aUsername, aPassword,
- aFlags, aFailoverTimeout,
- aFailoverProxy, 0, aResult);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::GetFailoverForProxy(nsIProxyInfo *aProxy,
- nsIURI *aURI,
- nsresult aStatus,
- nsIProxyInfo **aResult)
- {
- // We only support failover when a PAC file is configured, either
- // directly or via system settings
- if (mProxyConfig != PROXYCONFIG_PAC && mProxyConfig != PROXYCONFIG_WPAD &&
- mProxyConfig != PROXYCONFIG_SYSTEM)
- return NS_ERROR_NOT_AVAILABLE;
- // 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.
- 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));
- NS_ADDREF(*aResult = pi->mNext);
- return NS_OK;
- }
- nsresult
- nsProtocolProxyService::InsertFilterLink(FilterLink *link, uint32_t position)
- {
- if (!mFilters) {
- mFilters = link;
- return NS_OK;
- }
- // insert into mFilters in sorted order
- FilterLink *last = nullptr;
- for (FilterLink *iter = mFilters; iter; iter = iter->next) {
- if (position < iter->position) {
- if (last) {
- link->next = last->next;
- last->next = link;
- }
- else {
- link->next = mFilters;
- mFilters = link;
- }
- return NS_OK;
- }
- last = iter;
- }
- // our position is equal to or greater than the last link in the list
- last->next = link;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsProtocolProxyService::RegisterFilter(nsIProtocolProxyFilter *filter,
- uint32_t position)
- {
- UnregisterFilter(filter); // remove this filter if we already have it
- FilterLink *link = new FilterLink(position, filter);
- if (!link) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- return InsertFilterLink(link, position);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::RegisterChannelFilter(nsIProtocolProxyChannelFilter *channelFilter,
- uint32_t position)
- {
- UnregisterChannelFilter(channelFilter); // remove this filter if we already have it
- FilterLink *link = new FilterLink(position, channelFilter);
- if (!link) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- return InsertFilterLink(link, position);
- }
- nsresult
- nsProtocolProxyService::RemoveFilterLink(nsISupports* givenObject)
- {
- FilterLink *last = nullptr;
- for (FilterLink *iter = mFilters; iter; iter = iter->next) {
- nsCOMPtr<nsISupports> object = do_QueryInterface(iter->filter);
- nsCOMPtr<nsISupports> object2 = do_QueryInterface(iter->channelFilter);
- if (object == givenObject || object2 == givenObject) {
- if (last)
- last->next = iter->next;
- else
- mFilters = iter->next;
- iter->next = nullptr;
- delete iter;
- return NS_OK;
- }
- last = iter;
- }
- // No need to throw an exception in this case.
- return NS_OK;
- }
- 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);
- }
- NS_IMETHODIMP
- nsProtocolProxyService::GetProxyConfigType(uint32_t* aProxyConfigType)
- {
- *aProxyConfigType = mProxyConfig;
- return NS_OK;
- }
- void
- nsProtocolProxyService::LoadHostFilters(const nsACString& aFilters)
- {
- // check to see the owners flag? /!?/ TODO
- if (mHostFiltersArray.Length() > 0) {
- mHostFiltersArray.Clear();
- }
- if (aFilters.IsEmpty()) {
- return;
- }
- //
- // filter = ( host | domain | ipaddr ["/" mask] ) [":" port]
- // filters = filter *( "," LWS filter)
- //
- // Reset mFilterLocalHosts - will be set to true if "<local>" is in pref string
- mFilterLocalHosts = false;
- mozilla::Tokenizer t(aFilters);
- mozilla::Tokenizer::Token token;
- bool eof = false;
- // while (*filters) {
- while (!eof) {
- // skip over spaces and ,
- t.SkipWhites();
- while (t.CheckChar(',')) {
- t.SkipWhites();
- }
- nsAutoCString portStr;
- nsAutoCString hostStr;
- nsAutoCString maskStr;
- t.Record();
- bool parsingIPv6 = false;
- bool parsingPort = false;
- bool parsingMask = false;
- while (t.Next(token)) {
- if (token.Equals(mozilla::Tokenizer::Token::EndOfFile())) {
- eof = true;
- break;
- }
- if (token.Equals(mozilla::Tokenizer::Token::Char(',')) ||
- token.Type() == mozilla::Tokenizer::TOKEN_WS) {
- break;
- }
- 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;
- } else if (token.Equals(mozilla::Tokenizer::Token::Char('/'))) {
- t.Claim(hostStr);
- t.Record();
- parsingMask = true;
- continue;
- } else if (token.Equals(mozilla::Tokenizer::Token::Char(']'))) {
- parsingIPv6 = false;
- continue;
- }
- }
- if (!parsingPort && !parsingMask) {
- t.Claim(hostStr);
- } else if (parsingPort) {
- t.Claim(portStr);
- } else if (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("<local>")) {
- 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;
- int32_t maskLen = maskStr.ToInteger(&rv);
- if (NS_FAILED(rv)) {
- maskLen = 128;
- }
- // PR_StringToNetAddr can't parse brackets enclosed IPv6
- nsAutoCString addrString = hostStr;
- if (hostStr.First() == '[' && hostStr.Last() == ']') {
- addrString = Substring(hostStr, 1, hostStr.Length() - 2);
- }
- PRNetAddr addr;
- if (PR_StringToNetAddr(addrString.get(), &addr) == PR_SUCCESS) {
- hinfo->is_ipaddr = true;
- hinfo->ip.family = PR_AF_INET6; // we always store address as IPv6
- hinfo->ip.mask_len = maskLen;
- if (hinfo->ip.mask_len == 0) {
- NS_WARNING("invalid mask");
- goto loser;
- }
- if (addr.raw.family == PR_AF_INET) {
- // convert to IPv4-mapped address
- PR_ConvertIPv4AddrToIPv6(addr.inet.ip, &hinfo->ip.addr);
- // adjust mask_len accordingly
- if (hinfo->ip.mask_len <= 32)
- hinfo->ip.mask_len += 96;
- }
- else if (addr.raw.family == PR_AF_INET6) {
- // copy the address
- memcpy(&hinfo->ip.addr, &addr.ipv6.ip, sizeof(PRIPv6Addr));
- }
- else {
- NS_WARNING("unknown address family");
- goto loser;
- }
- // apply mask to IPv6 address
- proxy_MaskIPv6Addr(hinfo->ip.addr, hinfo->ip.mask_len);
- }
- else {
- nsAutoCString host;
- if (hostStr.First() == '*') {
- host = Substring(hostStr, 1);
- } else {
- host = hostStr;
- }
- if (host.IsEmpty()) {
- hinfo->name.host = nullptr;
- goto loser;
- }
- hinfo->name.host_len = host.Length();
- hinfo->is_ipaddr = false;
- hinfo->name.host = ToNewCString(host);
- if (!hinfo->name.host)
- goto loser;
- }
- //#define DEBUG_DUMP_FILTERS
- #ifdef DEBUG_DUMP_FILTERS
- printf("loaded filter[%zu]:\n", mHostFiltersArray.Length());
- printf(" is_ipaddr = %u\n", hinfo->is_ipaddr);
- printf(" port = %u\n", hinfo->port);
- printf(" host = %s\n", hostStr.get());
- if (hinfo->is_ipaddr) {
- printf(" ip.family = %x\n", hinfo->ip.family);
- printf(" ip.mask_len = %u\n", hinfo->ip.mask_len);
- PRNetAddr netAddr;
- PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr);
- memcpy(&netAddr.ipv6.ip, &hinfo->ip.addr, sizeof(hinfo->ip.addr));
- char buf[256];
- PR_NetAddrToString(&netAddr, buf, sizeof(buf));
- printf(" ip.addr = %s\n", buf);
- }
- else {
- printf(" name.host = %s\n", hinfo->name.host);
- }
- #endif
- mHostFiltersArray.AppendElement(hinfo);
- hinfo = nullptr;
- loser:
- delete hinfo;
- }
- }
- nsresult
- nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info)
- {
- NS_PRECONDITION(uri, "URI is null");
- NS_PRECONDITION(info, "info is null");
- nsresult rv;
- rv = uri->GetScheme(info->scheme);
- if (NS_FAILED(rv))
- return rv;
- nsCOMPtr<nsIIOService> ios = do_GetIOService(&rv);
- if (NS_FAILED(rv))
- return rv;
- nsCOMPtr<nsIProtocolHandler> handler;
- rv = ios->GetProtocolHandler(info->scheme.get(), getter_AddRefs(handler));
- if (NS_FAILED(rv))
- return rv;
- rv = handler->DoGetProtocolFlags(uri, &info->flags);
- if (NS_FAILED(rv))
- return rv;
- rv = handler->GetDefaultPort(&info->defaultPort);
- return rv;
- }
- nsresult
- nsProtocolProxyService::NewProxyInfo_Internal(const char *aType,
- const nsACString &aHost,
- int32_t aPort,
- const nsACString &aUsername,
- const nsACString &aPassword,
- uint32_t aFlags,
- uint32_t aFailoverTimeout,
- nsIProxyInfo *aFailoverProxy,
- uint32_t aResolveFlags,
- nsIProxyInfo **aResult)
- {
- if (aPort <= 0)
- aPort = -1;
- nsCOMPtr<nsProxyInfo> failover;
- if (aFailoverProxy) {
- failover = do_QueryInterface(aFailoverProxy);
- NS_ENSURE_ARG(failover);
- }
- nsProxyInfo *proxyInfo = new nsProxyInfo();
- if (!proxyInfo)
- return NS_ERROR_OUT_OF_MEMORY;
- proxyInfo->mType = aType;
- proxyInfo->mHost = aHost;
- proxyInfo->mPort = aPort;
- proxyInfo->mUsername = aUsername;
- proxyInfo->mPassword = aPassword;
- proxyInfo->mFlags = aFlags;
- proxyInfo->mResolveFlags = aResolveFlags;
- proxyInfo->mTimeout = aFailoverTimeout == UINT32_MAX
- ? mFailedProxyTimeout : aFailoverTimeout;
- failover.swap(proxyInfo->mNext);
- NS_ADDREF(*aResult = proxyInfo);
- return NS_OK;
- }
- nsresult
- nsProtocolProxyService::Resolve_Internal(nsIChannel *channel,
- const nsProtocolInfo &info,
- uint32_t flags,
- bool *usePACThread,
- nsIProxyInfo **result)
- {
- NS_ENSURE_ARG_POINTER(channel);
- nsresult rv = SetupPACThread();
- if (NS_FAILED(rv))
- return rv;
- *usePACThread = false;
- *result = nullptr;
- if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
- return NS_OK; // Can't proxy this (filters may not override)
- nsCOMPtr<nsIURI> uri;
- rv = GetProxyURI(channel, getter_AddRefs(uri));
- if (NS_FAILED(rv)) return rv;
- // See bug #586908.
- // Avoid endless loop if |uri| is the current PAC-URI. Returning OK
- // here means that we will not use a proxy for this connection.
- if (mPACMan && mPACMan->IsPACURI(uri))
- return NS_OK;
- // If proxies are enabled and this host:port combo is supposed to use a
- // proxy, check for a proxy.
- if ((mProxyConfig == PROXYCONFIG_DIRECT) ||
- !CanUseProxy(uri, info.defaultPort)) {
- return NS_OK;
- }
- bool mainThreadOnly;
- if (mSystemProxySettings &&
- mProxyConfig == PROXYCONFIG_SYSTEM &&
- NS_SUCCEEDED(mSystemProxySettings->GetMainThreadOnly(&mainThreadOnly)) &&
- !mainThreadOnly) {
- *usePACThread = true;
- return NS_OK;
- }
- if (mSystemProxySettings && mProxyConfig == PROXYCONFIG_SYSTEM) {
- // If the system proxy setting implementation is not threadsafe (e.g
- // linux gconf), we'll do it inline here. Such implementations promise
- // not to block
- nsAutoCString PACURI;
- nsAutoCString pacString;
- if (NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) &&
- !PACURI.IsEmpty()) {
- // There is a PAC URI configured. If it is unchanged, then
- // just execute the PAC thread. If it is changed then load
- // the new value
- if (mPACMan && mPACMan->IsPACURI(PACURI)) {
- // unchanged
- *usePACThread = true;
- return NS_OK;
- }
- ConfigureFromPAC(PACURI, false);
- return NS_OK;
- }
- nsAutoCString spec;
- nsAutoCString host;
- nsAutoCString scheme;
- int32_t port = -1;
- uri->GetAsciiSpec(spec);
- uri->GetAsciiHost(host);
- uri->GetScheme(scheme);
- uri->GetPort(&port);
- // now try the system proxy settings for this particular url
- if (NS_SUCCEEDED(mSystemProxySettings->
- GetProxyForURI(spec, scheme, host, port,
- pacString))) {
- ProcessPACString(pacString, 0, result);
- return NS_OK;
- }
- }
- // if proxies are enabled and this host:port combo is supposed to use a
- // proxy, check for a proxy.
- if (mProxyConfig == PROXYCONFIG_DIRECT ||
- (mProxyConfig == PROXYCONFIG_MANUAL &&
- !CanUseProxy(uri, info.defaultPort)))
- return NS_OK;
- // Proxy auto config magic...
- if (mProxyConfig == PROXYCONFIG_PAC || mProxyConfig == PROXYCONFIG_WPAD) {
- // Do not query PAC now.
- *usePACThread = true;
- return NS_OK;
- }
- // If we aren't in manual proxy configuration mode then we don't
- // want to honor any manual specific prefs that might be still set
- if (mProxyConfig != PROXYCONFIG_MANUAL)
- return NS_OK;
- // proxy info values for manual configuration mode
- const char *type = nullptr;
- const nsACString *host = nullptr;
- int32_t port = -1;
- uint32_t proxyFlags = 0;
- if ((flags & RESOLVE_PREFER_SOCKS_PROXY) &&
- !mSOCKSProxyTarget.IsEmpty() &&
- (IsHostLocalTarget(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
- host = &mSOCKSProxyTarget;
- if (mSOCKSProxyVersion == 4)
- type = kProxyType_SOCKS4;
- else
- type = kProxyType_SOCKS;
- port = mSOCKSProxyPort;
- if (mSOCKSProxyRemoteDNS)
- proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
- }
- else if ((flags & RESOLVE_PREFER_HTTPS_PROXY) &&
- !mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0) {
- host = &mHTTPSProxyHost;
- type = kProxyType_HTTP;
- port = mHTTPSProxyPort;
- }
- else if (!mHTTPProxyHost.IsEmpty() && mHTTPProxyPort > 0 &&
- ((flags & RESOLVE_IGNORE_URI_SCHEME) ||
- info.scheme.EqualsLiteral("http"))) {
- host = &mHTTPProxyHost;
- type = kProxyType_HTTP;
- port = mHTTPProxyPort;
- }
- else if (!mHTTPSProxyHost.IsEmpty() && mHTTPSProxyPort > 0 &&
- !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
- info.scheme.EqualsLiteral("https")) {
- host = &mHTTPSProxyHost;
- type = kProxyType_HTTP;
- port = mHTTPSProxyPort;
- }
- else if (!mFTPProxyHost.IsEmpty() && mFTPProxyPort > 0 &&
- !(flags & RESOLVE_IGNORE_URI_SCHEME) &&
- info.scheme.EqualsLiteral("ftp")) {
- host = &mFTPProxyHost;
- type = kProxyType_HTTP;
- port = mFTPProxyPort;
- }
- else if (!mSOCKSProxyTarget.IsEmpty() &&
- (IsHostLocalTarget(mSOCKSProxyTarget) || mSOCKSProxyPort > 0)) {
- host = &mSOCKSProxyTarget;
- if (mSOCKSProxyVersion == 4)
- type = kProxyType_SOCKS4;
- else
- type = kProxyType_SOCKS;
- port = mSOCKSProxyPort;
- if (mSOCKSProxyRemoteDNS)
- proxyFlags |= nsIProxyInfo::TRANSPARENT_PROXY_RESOLVES_HOST;
- }
- if (type) {
- rv = NewProxyInfo_Internal(type, *host, port,
- EmptyCString(), EmptyCString(),
- proxyFlags, UINT32_MAX, nullptr, flags,
- result);
- if (NS_FAILED(rv))
- return rv;
- }
- return NS_OK;
- }
- void
- nsProtocolProxyService::MaybeDisableDNSPrefetch(nsIProxyInfo *aProxy)
- {
- // Disable Prefetch in the DNS service if a proxy is in use.
- if (!aProxy)
- return;
- nsCOMPtr<nsProxyInfo> pi = do_QueryInterface(aProxy);
- if (!pi ||
- !pi->mType ||
- pi->mType == kProxyType_DIRECT)
- return;
- nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
- if (!dns)
- return;
- nsCOMPtr<nsPIDNSService> pdns = do_QueryInterface(dns);
- if (!pdns)
- return;
- // We lose the prefetch optimization for the life of the dns service.
- pdns->SetPrefetchEnabled(false);
- }
- void
- nsProtocolProxyService::ApplyFilters(nsIChannel *channel,
- const nsProtocolInfo &info,
- nsIProxyInfo **list)
- {
- if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY))
- return;
- // We prune the proxy list prior to invoking each filter. This may be
- // somewhat inefficient, but it seems like a good idea since we want each
- // filter to "see" a valid proxy list.
- nsCOMPtr<nsIProxyInfo> result;
- for (FilterLink *iter = mFilters; iter; iter = iter->next) {
- PruneProxyInfo(info, list);
- nsresult rv = NS_OK;
- if (iter->filter) {
- nsCOMPtr<nsIURI> uri;
- rv = GetProxyURI(channel, getter_AddRefs(uri));
- if (uri) {
- rv = iter->filter->ApplyFilter(this, uri, *list,
- getter_AddRefs(result));
- }
- } else if (iter->channelFilter) {
- rv = iter->channelFilter->ApplyFilter(this, channel, *list,
- getter_AddRefs(result));
- }
- if (NS_FAILED(rv))
- continue;
- result.swap(*list);
- }
- PruneProxyInfo(info, list);
- }
- void
- nsProtocolProxyService::PruneProxyInfo(const nsProtocolInfo &info,
- nsIProxyInfo **list)
- {
- if (!*list)
- return;
- nsProxyInfo *head = nullptr;
- CallQueryInterface(*list, &head);
- if (!head) {
- NS_NOTREACHED("nsIProxyInfo must QI to nsProxyInfo");
- return;
- }
- NS_RELEASE(*list);
- // Pruning of disabled proxies works like this:
- // - If all proxies are disabled, return the full list
- // - Otherwise, remove the disabled proxies.
- //
- // Pruning of disallowed proxies works like this:
- // - If the protocol handler disallows the proxy, then we disallow it.
- // Start by removing all disallowed proxies if required:
- if (!(info.flags & nsIProtocolHandler::ALLOWS_PROXY_HTTP)) {
- nsProxyInfo *last = nullptr, *iter = head;
- while (iter) {
- if ((iter->Type() == kProxyType_HTTP) ||
- (iter->Type() == kProxyType_HTTPS)) {
- // reject!
- if (last)
- last->mNext = iter->mNext;
- else
- head = iter->mNext;
- nsProxyInfo *next = iter->mNext;
- iter->mNext = nullptr;
- iter->Release();
- iter = next;
- } else {
- last = iter;
- iter = iter->mNext;
- }
- }
- if (!head)
- return;
- }
- // Now, scan to see if all remaining proxies are disabled. If so, then
- // we'll just bail and return them all. Otherwise, we'll go and prune the
- // disabled ones.
- bool allDisabled = true;
- nsProxyInfo *iter;
- for (iter = head; iter; iter = iter->mNext) {
- if (!IsProxyDisabled(iter)) {
- allDisabled = false;
- break;
- }
- }
- if (allDisabled)
- LOG(("All proxies are disabled, so trying all again"));
- else {
- // remove any disabled proxies.
- nsProxyInfo *last = nullptr;
- for (iter = head; iter; ) {
- if (IsProxyDisabled(iter)) {
- // reject!
- nsProxyInfo *reject = iter;
- iter = iter->mNext;
- if (last)
- last->mNext = iter;
- else
- head = iter;
- reject->mNext = nullptr;
- NS_RELEASE(reject);
- continue;
- }
- // since we are about to use this proxy, make sure it is not on
- // the disabled proxy list. we'll add it back to that list if
- // we have to (in GetFailoverForProxy).
- //
- // XXX(darin): It might be better to do this as a final pass.
- //
- EnableProxy(iter);
- last = iter;
- iter = iter->mNext;
- }
- }
- // if only DIRECT was specified then return no proxy info, and we're done.
- if (head && !head->mNext && head->mType == kProxyType_DIRECT)
- NS_RELEASE(head);
- *list = head; // Transfer ownership
- }
- } // namespace net
- } // namespace mozilla
|