LCOV - code coverage report
Current view: top level - netwerk/base - nsProtocolProxyService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 315 1054 29.9 %
Date: 2017-07-14 16:53:18 Functions: 30 73 41.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13