LCOV - code coverage report
Current view: top level - netwerk/base - nsPACMan.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 14 360 3.9 %
Date: 2017-07-14 16:53:18 Functions: 3 52 5.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       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 "nsPACMan.h"
       8             : #include "nsThreadUtils.h"
       9             : #include "nsIAuthPrompt.h"
      10             : #include "nsIPromptFactory.h"
      11             : #include "nsIHttpChannel.h"
      12             : #include "nsIPrefService.h"
      13             : #include "nsIPrefBranch.h"
      14             : #include "nsNetUtil.h"
      15             : #include "nsIAsyncVerifyRedirectCallback.h"
      16             : #include "nsISystemProxySettings.h"
      17             : #include "nsContentUtils.h"
      18             : #include "mozilla/Preferences.h"
      19             : 
      20             : //-----------------------------------------------------------------------------
      21             : 
      22             : namespace mozilla {
      23             : namespace net {
      24             : 
      25             : LazyLogModule gProxyLog("proxy");
      26             : 
      27             : #undef LOG
      28             : #define LOG(args) MOZ_LOG(gProxyLog, LogLevel::Debug, args)
      29             : 
      30             : // The PAC thread does evaluations of both PAC files and
      31             : // nsISystemProxySettings because they can both block the calling thread and we
      32             : // don't want that on the main thread
      33             : 
      34             : // Check to see if the underlying request was not an error page in the case of
      35             : // a HTTP request.  For other types of channels, just return true.
      36             : static bool
      37           0 : HttpRequestSucceeded(nsIStreamLoader *loader)
      38             : {
      39           0 :   nsCOMPtr<nsIRequest> request;
      40           0 :   loader->GetRequest(getter_AddRefs(request));
      41             : 
      42           0 :   bool result = true;  // default to assuming success
      43             : 
      44           0 :   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
      45           0 :   if (httpChannel) {
      46             :     // failsafe
      47           0 :     Unused << httpChannel->GetRequestSucceeded(&result);
      48             :   }
      49             : 
      50           0 :   return result;
      51             : }
      52             : 
      53             : // Read preference setting of extra JavaScript context heap size.
      54             : // PrefService tends to be run on main thread, where ProxyAutoConfig runs on
      55             : // ProxyResolution thread, so it's read here and passed to ProxyAutoConfig.
      56             : static uint32_t
      57           0 : GetExtraJSContextHeapSize()
      58             : {
      59           0 :   MOZ_ASSERT(NS_IsMainThread());
      60             : 
      61             :   static int32_t extraSize = -1;
      62             : 
      63           0 :   if (extraSize < 0) {
      64           0 :     nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
      65             :     int32_t value;
      66             : 
      67           0 :     if (prefs && NS_SUCCEEDED(prefs->GetIntPref(
      68             :         "network.proxy.autoconfig_extra_jscontext_heap_size", &value))) {
      69           0 :       LOG(("autoconfig_extra_jscontext_heap_size: %d\n", value));
      70             : 
      71           0 :       extraSize = value;
      72             :     }
      73             :   }
      74             : 
      75           0 :   return extraSize < 0 ? 0 : extraSize;
      76             : }
      77             : 
      78             : 
      79             : //-----------------------------------------------------------------------------
      80             : 
      81             : // The ExecuteCallback runnable is triggered by
      82             : // nsPACManCallback::OnQueryComplete on the Main thread when its completion is
      83             : // discovered on the pac thread
      84             : 
      85           0 : class ExecuteCallback final : public Runnable
      86             : {
      87             : public:
      88           0 :   ExecuteCallback(nsPACManCallback* aCallback, nsresult status)
      89           0 :     : Runnable("net::ExecuteCallback")
      90             :     , mCallback(aCallback)
      91           0 :     , mStatus(status)
      92             :   {
      93           0 :   }
      94             : 
      95           0 :   void SetPACString(const nsCString &pacString)
      96             :   {
      97           0 :     mPACString = pacString;
      98           0 :   }
      99             : 
     100           0 :   void SetPACURL(const nsCString &pacURL)
     101             :   {
     102           0 :     mPACURL = pacURL;
     103           0 :   }
     104             : 
     105           0 :   NS_IMETHOD Run() override
     106             :   {
     107           0 :     mCallback->OnQueryComplete(mStatus, mPACString, mPACURL);
     108           0 :     mCallback = nullptr;
     109           0 :     return NS_OK;
     110             :   }
     111             : 
     112             : private:
     113             :   RefPtr<nsPACManCallback> mCallback;
     114             :   nsresult                   mStatus;
     115             :   nsCString                  mPACString;
     116             :   nsCString                  mPACURL;
     117             : };
     118             : 
     119             : //-----------------------------------------------------------------------------
     120             : 
     121             : // The PAC thread must be deleted from the main thread, this class
     122             : // acts as a proxy to do that, as the PACMan is reference counted
     123             : // and might be destroyed on either thread
     124             : 
     125           0 : class ShutdownThread final : public Runnable
     126             : {
     127             : public:
     128           0 :   explicit ShutdownThread(nsIThread* thread)
     129           0 :     : Runnable("net::ShutdownThread")
     130           0 :     , mThread(thread)
     131             :   {
     132           0 :   }
     133             : 
     134           0 :   NS_IMETHOD Run() override
     135             :   {
     136           0 :     MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     137           0 :     mThread->Shutdown();
     138           0 :     return NS_OK;
     139             :   }
     140             : 
     141             : private:
     142             :   nsCOMPtr<nsIThread> mThread;
     143             : };
     144             : 
     145             : // Dispatch this to wait until the PAC thread shuts down.
     146             : 
     147           0 : class WaitForThreadShutdown final : public Runnable
     148             : {
     149             : public:
     150           0 :   explicit WaitForThreadShutdown(nsPACMan* aPACMan)
     151           0 :     : Runnable("net::WaitForThreadShutdown")
     152           0 :     , mPACMan(aPACMan)
     153             :   {
     154           0 :   }
     155             : 
     156           0 :   NS_IMETHOD Run() override
     157             :   {
     158           0 :     MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     159           0 :     if (mPACMan->mPACThread) {
     160           0 :       mPACMan->mPACThread->Shutdown();
     161           0 :       mPACMan->mPACThread = nullptr;
     162             :     }
     163           0 :     return NS_OK;
     164             :   }
     165             : 
     166             : private:
     167             :   RefPtr<nsPACMan> mPACMan;
     168             : };
     169             : 
     170             : //-----------------------------------------------------------------------------
     171             : 
     172             : // PACLoadComplete allows the PAC thread to tell the main thread that
     173             : // the javascript PAC file has been installed (perhaps unsuccessfully)
     174             : // and that there is no reason to queue executions anymore
     175             : 
     176           0 : class PACLoadComplete final : public Runnable
     177             : {
     178             : public:
     179           0 :   explicit PACLoadComplete(nsPACMan* aPACMan)
     180           0 :     : Runnable("net::PACLoadComplete")
     181           0 :     , mPACMan(aPACMan)
     182             :   {
     183           0 :   }
     184             : 
     185           0 :   NS_IMETHOD Run() override
     186             :   {
     187           0 :     MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     188           0 :     mPACMan->mLoader = nullptr;
     189           0 :     mPACMan->PostProcessPendingQ();
     190           0 :     return NS_OK;
     191             :   }
     192             : 
     193             : private:
     194             :     RefPtr<nsPACMan> mPACMan;
     195             : };
     196             : 
     197             : //-----------------------------------------------------------------------------
     198             : 
     199             : // ExecutePACThreadAction is used to proxy actions from the main
     200             : // thread onto the PAC thread. There are 3 options: process the queue,
     201             : // cancel the queue, and setup the javascript context with a new PAC file
     202             : 
     203           0 : class ExecutePACThreadAction final : public Runnable
     204             : {
     205             : public:
     206             :   // by default we just process the queue
     207           0 :   explicit ExecutePACThreadAction(nsPACMan* aPACMan)
     208           0 :     : Runnable("net::ExecutePACThreadAction")
     209             :     , mPACMan(aPACMan)
     210             :     , mCancel(false)
     211             :     , mCancelStatus(NS_OK)
     212             :     , mSetupPAC(false)
     213           0 :     , mExtraHeapSize(0)
     214           0 :   { }
     215             : 
     216           0 :   void CancelQueue (nsresult status)
     217             :   {
     218           0 :     mCancel = true;
     219           0 :     mCancelStatus = status;
     220           0 :   }
     221             : 
     222           0 :   void SetupPAC (const char *text,
     223             :                  uint32_t datalen,
     224             :                  nsCString &pacURI,
     225             :                  uint32_t extraHeapSize)
     226             :   {
     227           0 :     mSetupPAC = true;
     228           0 :     mSetupPACData.Assign(text, datalen);
     229           0 :     mSetupPACURI = pacURI;
     230           0 :     mExtraHeapSize = extraHeapSize;
     231           0 :   }
     232             : 
     233           0 :   NS_IMETHOD Run() override
     234             :   {
     235           0 :     MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
     236           0 :     if (mCancel) {
     237           0 :       mPACMan->CancelPendingQ(mCancelStatus);
     238           0 :       mCancel = false;
     239           0 :       return NS_OK;
     240             :     }
     241             : 
     242           0 :     if (mSetupPAC) {
     243           0 :       mSetupPAC = false;
     244             : 
     245           0 :       nsCOMPtr<nsIEventTarget> target = mPACMan->GetNeckoTarget();
     246           0 :       mPACMan->mPAC.Init(mSetupPACURI,
     247             :                          mSetupPACData,
     248           0 :                          mPACMan->mIncludePath,
     249             :                          mExtraHeapSize,
     250           0 :                          target);
     251             : 
     252           0 :       RefPtr<PACLoadComplete> runnable = new PACLoadComplete(mPACMan);
     253           0 :       mPACMan->Dispatch(runnable.forget());
     254           0 :       return NS_OK;
     255             :     }
     256             : 
     257           0 :     mPACMan->ProcessPendingQ();
     258           0 :     return NS_OK;
     259             :   }
     260             : 
     261             : private:
     262             :   RefPtr<nsPACMan> mPACMan;
     263             : 
     264             :   bool      mCancel;
     265             :   nsresult  mCancelStatus;
     266             : 
     267             :   bool                 mSetupPAC;
     268             :   uint32_t             mExtraHeapSize;
     269             :   nsCString            mSetupPACData;
     270             :   nsCString            mSetupPACURI;
     271             : };
     272             : 
     273             : //-----------------------------------------------------------------------------
     274             : 
     275           0 : PendingPACQuery::PendingPACQuery(nsPACMan* pacMan,
     276             :                                  nsIURI* uri,
     277             :                                  nsPACManCallback* callback,
     278           0 :                                  bool mainThreadResponse)
     279             :   : Runnable("net::PendingPACQuery")
     280             :   , mPACMan(pacMan)
     281             :   , mCallback(callback)
     282           0 :   , mOnMainThreadOnly(mainThreadResponse)
     283             : {
     284           0 :   uri->GetAsciiSpec(mSpec);
     285           0 :   uri->GetAsciiHost(mHost);
     286           0 :   uri->GetScheme(mScheme);
     287           0 :   uri->GetPort(&mPort);
     288           0 : }
     289             : 
     290             : void
     291           0 : PendingPACQuery::Complete(nsresult status, const nsCString &pacString)
     292             : {
     293           0 :   if (!mCallback)
     294           0 :     return;
     295           0 :   RefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, status);
     296           0 :   runnable->SetPACString(pacString);
     297           0 :   if (mOnMainThreadOnly)
     298           0 :     mPACMan->Dispatch(runnable.forget());
     299             :   else
     300           0 :     runnable->Run();
     301             : }
     302             : 
     303             : void
     304           0 : PendingPACQuery::UseAlternatePACFile(const nsCString &pacURL)
     305             : {
     306           0 :   if (!mCallback)
     307           0 :     return;
     308             : 
     309           0 :   RefPtr<ExecuteCallback> runnable = new ExecuteCallback(mCallback, NS_OK);
     310           0 :   runnable->SetPACURL(pacURL);
     311           0 :   if (mOnMainThreadOnly)
     312           0 :     mPACMan->Dispatch(runnable.forget());
     313             :   else
     314           0 :     runnable->Run();
     315             : }
     316             : 
     317             : NS_IMETHODIMP
     318           0 : PendingPACQuery::Run()
     319             : {
     320           0 :   MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
     321           0 :   mPACMan->PostQuery(this);
     322           0 :   return NS_OK;
     323             : }
     324             : 
     325             : //-----------------------------------------------------------------------------
     326             : 
     327             : static bool sThreadLocalSetup = false;
     328             : static uint32_t sThreadLocalIndex = 0xdeadbeef; // out of range
     329             : 
     330             : static const char *kPACIncludePath =
     331             :   "network.proxy.autoconfig_url.include_path";
     332             : 
     333           1 : nsPACMan::nsPACMan(nsIEventTarget *mainThreadEventTarget)
     334             :   : NeckoTargetHolder(mainThreadEventTarget)
     335             :   , mLoadPending(false)
     336             :   , mShutdown(false)
     337             :   , mLoadFailureCount(0)
     338           1 :   , mInProgress(false)
     339             : {
     340           1 :   MOZ_ASSERT(NS_IsMainThread(), "pacman must be created on main thread");
     341           1 :   if (!sThreadLocalSetup){
     342           1 :     sThreadLocalSetup = true;
     343           1 :     PR_NewThreadPrivateIndex(&sThreadLocalIndex, nullptr);
     344             :   }
     345           1 :   mPAC.SetThreadLocalIndex(sThreadLocalIndex);
     346           1 :   mIncludePath = Preferences::GetBool(kPACIncludePath, false);
     347           1 : }
     348             : 
     349           0 : nsPACMan::~nsPACMan()
     350             : {
     351           0 :   if (mPACThread) {
     352           0 :     if (NS_IsMainThread()) {
     353           0 :       mPACThread->Shutdown();
     354             :     }
     355             :     else {
     356           0 :       RefPtr<ShutdownThread> runnable = new ShutdownThread(mPACThread);
     357           0 :       Dispatch(runnable.forget());
     358             :     }
     359             :   }
     360             : 
     361           0 :   NS_ASSERTION(mLoader == nullptr, "pac man not shutdown properly");
     362           0 :   NS_ASSERTION(mPendingQ.isEmpty(), "pac man not shutdown properly");
     363           0 : }
     364             : 
     365             : void
     366           0 : nsPACMan::Shutdown()
     367             : {
     368           0 :   MOZ_ASSERT(NS_IsMainThread(), "pacman must be shutdown on main thread");
     369           0 :   if (mShutdown) {
     370           0 :     return;
     371             :   }
     372           0 :   mShutdown = true;
     373           0 :   CancelExistingLoad();
     374           0 :   PostCancelPendingQ(NS_ERROR_ABORT);
     375             : 
     376           0 :   RefPtr<WaitForThreadShutdown> runnable = new WaitForThreadShutdown(this);
     377           0 :   Dispatch(runnable.forget());
     378             : }
     379             : 
     380             : nsresult
     381           0 : nsPACMan::AsyncGetProxyForURI(nsIURI *uri,
     382             :                               nsPACManCallback *callback,
     383             :                               bool mainThreadResponse)
     384             : {
     385           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     386           0 :   if (mShutdown)
     387           0 :     return NS_ERROR_NOT_AVAILABLE;
     388             : 
     389             :   // Maybe Reload PAC
     390           0 :   if (!mPACURISpec.IsEmpty() && !mScheduledReload.IsNull() &&
     391           0 :       TimeStamp::Now() > mScheduledReload) {
     392           0 :     LOG(("nsPACMan::AsyncGetProxyForURI reload as scheduled\n"));
     393             : 
     394           0 :     LoadPACFromURI(EmptyCString());
     395             :   }
     396             : 
     397             :   RefPtr<PendingPACQuery> query =
     398           0 :     new PendingPACQuery(this, uri, callback, mainThreadResponse);
     399             : 
     400           0 :   if (IsPACURI(uri)) {
     401             :     // deal with this directly instead of queueing it
     402           0 :     query->Complete(NS_OK, EmptyCString());
     403           0 :     return NS_OK;
     404             :   }
     405             : 
     406           0 :   return mPACThread->Dispatch(query, nsIEventTarget::DISPATCH_NORMAL);
     407             : }
     408             : 
     409             : nsresult
     410           0 : nsPACMan::PostQuery(PendingPACQuery *query)
     411             : {
     412           0 :   MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
     413             : 
     414           0 :   if (mShutdown) {
     415           0 :     query->Complete(NS_ERROR_NOT_AVAILABLE, EmptyCString());
     416           0 :     return NS_OK;
     417             :   }
     418             : 
     419             :   // add a reference to the query while it is in the pending list
     420           0 :   RefPtr<PendingPACQuery> addref(query);
     421           0 :   mPendingQ.insertBack(addref.forget().take());
     422           0 :   ProcessPendingQ();
     423           0 :   return NS_OK;
     424             : }
     425             : 
     426             : nsresult
     427           0 : nsPACMan::LoadPACFromURI(const nsCString &spec)
     428             : {
     429           0 :   NS_ENSURE_STATE(!mShutdown);
     430           0 :   NS_ENSURE_ARG(!spec.IsEmpty() || !mPACURISpec.IsEmpty());
     431             : 
     432             :   nsCOMPtr<nsIStreamLoader> loader =
     433           0 :       do_CreateInstance(NS_STREAMLOADER_CONTRACTID);
     434           0 :   NS_ENSURE_STATE(loader);
     435             : 
     436           0 :   LOG(("nsPACMan::LoadPACFromURI %s\n", spec.get()));
     437             :   // Since we might get called from nsProtocolProxyService::Init, we need to
     438             :   // post an event back to the main thread before we try to use the IO service.
     439             :   //
     440             :   // But, we need to flag ourselves as loading, so that we queue up any PAC
     441             :   // queries the enter between now and when we actually load the PAC file.
     442             : 
     443           0 :   if (!mLoadPending) {
     444             :     nsCOMPtr<nsIRunnable> runnable =
     445           0 :       NewRunnableMethod("nsPACMan::StartLoading", this, &nsPACMan::StartLoading);
     446           0 :     nsresult rv = NS_IsMainThread()
     447           0 :       ? Dispatch(runnable.forget())
     448           0 :       : GetCurrentThreadEventTarget()->Dispatch(runnable.forget());
     449           0 :     if (NS_FAILED(rv))
     450           0 :       return rv;
     451           0 :     mLoadPending = true;
     452             :   }
     453             : 
     454           0 :   CancelExistingLoad();
     455             : 
     456           0 :   mLoader = loader;
     457           0 :   if (!spec.IsEmpty()) {
     458           0 :     mPACURISpec = spec;
     459           0 :     mPACURIRedirectSpec.Truncate();
     460           0 :     mNormalPACURISpec.Truncate(); // set at load time
     461           0 :     mLoadFailureCount = 0;  // reset
     462             :   }
     463             : 
     464             :   // reset to Null
     465           0 :   mScheduledReload = TimeStamp();
     466           0 :   return NS_OK;
     467             : }
     468             : 
     469             : void
     470           0 : nsPACMan::StartLoading()
     471             : {
     472           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     473           0 :   mLoadPending = false;
     474             : 
     475             :   // CancelExistingLoad was called...
     476           0 :   if (!mLoader) {
     477           0 :     PostCancelPendingQ(NS_ERROR_ABORT);
     478           0 :     return;
     479             :   }
     480             : 
     481           0 :   if (NS_SUCCEEDED(mLoader->Init(this, nullptr))) {
     482             :     // Always hit the origin server when loading PAC.
     483           0 :     nsCOMPtr<nsIIOService> ios = do_GetIOService();
     484           0 :     if (ios) {
     485           0 :       nsCOMPtr<nsIChannel> channel;
     486           0 :       nsCOMPtr<nsIURI> pacURI;
     487           0 :       NS_NewURI(getter_AddRefs(pacURI), mPACURISpec);
     488             : 
     489             :       // NOTE: This results in GetProxyForURI being called
     490           0 :       if (pacURI) {
     491           0 :         nsresult rv = pacURI->GetSpec(mNormalPACURISpec);
     492           0 :         MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
     493           0 :         NS_NewChannel(getter_AddRefs(channel),
     494             :                       pacURI,
     495             :                       nsContentUtils::GetSystemPrincipal(),
     496             :                       nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     497             :                       nsIContentPolicy::TYPE_OTHER,
     498             :                       nullptr, // aLoadGroup
     499             :                       nullptr, // aCallbacks
     500             :                       nsIRequest::LOAD_NORMAL,
     501           0 :                       ios);
     502             :       }
     503             :       else {
     504           0 :         LOG(("nsPACMan::StartLoading Failed pacspec uri conversion %s\n",
     505             :              mPACURISpec.get()));
     506             :       }
     507             : 
     508           0 :       if (channel) {
     509           0 :         channel->SetLoadFlags(nsIRequest::LOAD_BYPASS_CACHE);
     510           0 :         channel->SetNotificationCallbacks(this);
     511           0 :         if (NS_SUCCEEDED(channel->AsyncOpen2(mLoader)))
     512           0 :           return;
     513             :       }
     514             :     }
     515             :   }
     516             : 
     517           0 :   CancelExistingLoad();
     518           0 :   PostCancelPendingQ(NS_ERROR_UNEXPECTED);
     519             : }
     520             : 
     521             : 
     522             : void
     523           0 : nsPACMan::OnLoadFailure()
     524             : {
     525           0 :   int32_t minInterval = 5;    // 5 seconds
     526           0 :   int32_t maxInterval = 300;  // 5 minutes
     527             : 
     528           0 :   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
     529           0 :   if (prefs) {
     530           0 :     prefs->GetIntPref("network.proxy.autoconfig_retry_interval_min",
     531           0 :                       &minInterval);
     532           0 :     prefs->GetIntPref("network.proxy.autoconfig_retry_interval_max",
     533           0 :                       &maxInterval);
     534             :   }
     535             : 
     536           0 :   int32_t interval = minInterval << mLoadFailureCount++;  // seconds
     537           0 :   if (!interval || interval > maxInterval)
     538           0 :     interval = maxInterval;
     539             : 
     540           0 :   mScheduledReload = TimeStamp::Now() + TimeDuration::FromSeconds(interval);
     541             : 
     542           0 :   LOG(("OnLoadFailure: retry in %d seconds (%d fails)\n",
     543             :        interval, mLoadFailureCount));
     544             : 
     545             :   // while we wait for the retry queued members should try direct
     546             :   // even if that means fast failure.
     547           0 :   PostCancelPendingQ(NS_ERROR_NOT_AVAILABLE);
     548           0 : }
     549             : 
     550             : void
     551           0 : nsPACMan::CancelExistingLoad()
     552             : {
     553           0 :   if (mLoader) {
     554           0 :     nsCOMPtr<nsIRequest> request;
     555           0 :     mLoader->GetRequest(getter_AddRefs(request));
     556           0 :     if (request)
     557           0 :       request->Cancel(NS_ERROR_ABORT);
     558           0 :     mLoader = nullptr;
     559             :   }
     560           0 : }
     561             : 
     562             : void
     563           0 : nsPACMan::PostProcessPendingQ()
     564             : {
     565           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     566             :   RefPtr<ExecutePACThreadAction> pending =
     567           0 :     new ExecutePACThreadAction(this);
     568           0 :   if (mPACThread)
     569           0 :     mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL);
     570           0 : }
     571             : 
     572             : void
     573           0 : nsPACMan::PostCancelPendingQ(nsresult status)
     574             : {
     575           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     576             :   RefPtr<ExecutePACThreadAction> pending =
     577           0 :     new ExecutePACThreadAction(this);
     578           0 :   pending->CancelQueue(status);
     579           0 :   if (mPACThread)
     580           0 :     mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL);
     581           0 : }
     582             : 
     583             : void
     584           0 : nsPACMan::CancelPendingQ(nsresult status)
     585             : {
     586           0 :   MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
     587           0 :   RefPtr<PendingPACQuery> query;
     588             : 
     589           0 :   while (!mPendingQ.isEmpty()) {
     590           0 :     query = dont_AddRef(mPendingQ.popLast());
     591           0 :     query->Complete(status, EmptyCString());
     592             :   }
     593             : 
     594           0 :   if (mShutdown)
     595           0 :     mPAC.Shutdown();
     596           0 : }
     597             : 
     598             : void
     599           0 : nsPACMan::ProcessPendingQ()
     600             : {
     601           0 :   MOZ_ASSERT(!NS_IsMainThread(), "wrong thread");
     602           0 :   while (ProcessPending());
     603             : 
     604           0 :   if (mShutdown) {
     605           0 :     mPAC.Shutdown();
     606             :   } else {
     607             :     // do GC while the thread has nothing pending
     608           0 :     mPAC.GC();
     609             :   }
     610           0 : }
     611             : 
     612             : // returns true if progress was made by shortening the queue
     613             : bool
     614           0 : nsPACMan::ProcessPending()
     615             : {
     616           0 :   if (mPendingQ.isEmpty())
     617           0 :     return false;
     618             : 
     619             :   // queue during normal load, but if we are retrying a failed load then
     620             :   // fast fail the queries
     621           0 :   if (mInProgress || (IsLoading() && !mLoadFailureCount))
     622           0 :     return false;
     623             : 
     624           0 :   RefPtr<PendingPACQuery> query(dont_AddRef(mPendingQ.popFirst()));
     625             : 
     626           0 :   if (mShutdown || IsLoading()) {
     627           0 :     query->Complete(NS_ERROR_NOT_AVAILABLE, EmptyCString());
     628           0 :     return true;
     629             :   }
     630             : 
     631           0 :   nsAutoCString pacString;
     632           0 :   bool completed = false;
     633           0 :   mInProgress = true;
     634           0 :   nsAutoCString PACURI;
     635             : 
     636             :   // first we need to consider the system proxy changing the pac url
     637           0 :   if (mSystemProxySettings &&
     638           0 :       NS_SUCCEEDED(mSystemProxySettings->GetPACURI(PACURI)) &&
     639           0 :       !PACURI.IsEmpty() &&
     640           0 :       !PACURI.Equals(mPACURISpec)) {
     641           0 :     query->UseAlternatePACFile(PACURI);
     642           0 :     LOG(("Use PAC from system settings: %s\n", PACURI.get()));
     643           0 :     completed = true;
     644             :   }
     645             : 
     646             :   // now try the system proxy settings for this particular url if
     647             :   // PAC was not specified
     648           0 :   if (!completed && mSystemProxySettings && PACURI.IsEmpty() &&
     649           0 :       NS_SUCCEEDED(mSystemProxySettings->
     650             :                    GetProxyForURI(query->mSpec, query->mScheme,
     651             :                                   query->mHost, query->mPort,
     652             :                                   pacString))) {
     653           0 :     LOG(("Use proxy from system settings: %s\n", pacString.get()));
     654           0 :     query->Complete(NS_OK, pacString);
     655           0 :     completed = true;
     656             :   }
     657             : 
     658             :   // the systemproxysettings didn't complete the resolution. try via PAC
     659           0 :   if (!completed) {
     660           0 :     nsresult status = mPAC.GetProxyForURI(query->mSpec, query->mHost,
     661           0 :                                           pacString);
     662           0 :     LOG(("Use proxy from PAC: %s\n", pacString.get()));
     663           0 :     query->Complete(status, pacString);
     664             :   }
     665             : 
     666           0 :   mInProgress = false;
     667           0 :   return true;
     668             : }
     669             : 
     670           1 : NS_IMPL_ISUPPORTS(nsPACMan, nsIStreamLoaderObserver,
     671             :                   nsIInterfaceRequestor, nsIChannelEventSink)
     672             : 
     673             : NS_IMETHODIMP
     674           0 : nsPACMan::OnStreamComplete(nsIStreamLoader *loader,
     675             :                            nsISupports *context,
     676             :                            nsresult status,
     677             :                            uint32_t dataLen,
     678             :                            const uint8_t *data)
     679             : {
     680           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     681           0 :   if (mLoader != loader) {
     682             :     // If this happens, then it means that LoadPACFromURI was called more
     683             :     // than once before the initial call completed.  In this case, status
     684             :     // should be NS_ERROR_ABORT, and if so, then we know that we can and
     685             :     // should delay any processing.
     686           0 :     LOG(("OnStreamComplete: called more than once\n"));
     687           0 :     if (status == NS_ERROR_ABORT)
     688           0 :       return NS_OK;
     689             :   }
     690             : 
     691           0 :   LOG(("OnStreamComplete: entry\n"));
     692             : 
     693           0 :   if (NS_SUCCEEDED(status) && HttpRequestSucceeded(loader)) {
     694             :     // Get the URI spec used to load this PAC script.
     695           0 :     nsAutoCString pacURI;
     696             :     {
     697           0 :       nsCOMPtr<nsIRequest> request;
     698           0 :       loader->GetRequest(getter_AddRefs(request));
     699           0 :       nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
     700           0 :       if (channel) {
     701           0 :         nsCOMPtr<nsIURI> uri;
     702           0 :         channel->GetURI(getter_AddRefs(uri));
     703           0 :         if (uri)
     704           0 :           uri->GetAsciiSpec(pacURI);
     705             :       }
     706             :     }
     707             : 
     708             :     // We assume that the PAC text is ASCII (or ISO-Latin-1).  We've had this
     709             :     // assumption forever, and some real-world PAC scripts actually have some
     710             :     // non-ASCII text in comment blocks (see bug 296163).
     711           0 :     const char *text = (const char *) data;
     712             : 
     713             :     // we have succeeded in loading the pac file using a bunch of interfaces that
     714             :     // are main thread only, unfortunately we have to initialize the instance of
     715             :     // the PAC evaluator (NS_PROXYAUTOCONFIG_CONTRACTID) on the pac thread, because
     716             :     // that is where it will be used.
     717             : 
     718             :     RefPtr<ExecutePACThreadAction> pending =
     719           0 :       new ExecutePACThreadAction(this);
     720           0 :     pending->SetupPAC(text, dataLen, pacURI, GetExtraJSContextHeapSize());
     721           0 :     if (mPACThread)
     722           0 :       mPACThread->Dispatch(pending, nsIEventTarget::DISPATCH_NORMAL);
     723             : 
     724           0 :     LOG(("OnStreamComplete: process the PAC contents\n"));
     725             : 
     726             :     // Even if the PAC file could not be parsed, we did succeed in loading the
     727             :     // data for it.
     728           0 :     mLoadFailureCount = 0;
     729             :   } else {
     730             :     // We were unable to load the PAC file (presumably because of a network
     731             :     // failure).  Try again a little later.
     732           0 :     LOG(("OnStreamComplete: unable to load PAC, retry later\n"));
     733           0 :     OnLoadFailure();
     734             :   }
     735             : 
     736           0 :   if (NS_SUCCEEDED(status))
     737           0 :     PostProcessPendingQ();
     738             :   else
     739           0 :     PostCancelPendingQ(status);
     740             : 
     741           0 :   return NS_OK;
     742             : }
     743             : 
     744             : NS_IMETHODIMP
     745           0 : nsPACMan::GetInterface(const nsIID &iid, void **result)
     746             : {
     747             :   // In case loading the PAC file requires authentication.
     748           0 :   if (iid.Equals(NS_GET_IID(nsIAuthPrompt))) {
     749           0 :     nsCOMPtr<nsIPromptFactory> promptFac = do_GetService("@mozilla.org/prompter;1");
     750           0 :     NS_ENSURE_TRUE(promptFac, NS_ERROR_FAILURE);
     751           0 :     return promptFac->GetPrompt(nullptr, iid, reinterpret_cast<void**>(result));
     752             :   }
     753             : 
     754             :   // In case loading the PAC file results in a redirect.
     755           0 :   if (iid.Equals(NS_GET_IID(nsIChannelEventSink))) {
     756           0 :     NS_ADDREF_THIS();
     757           0 :     *result = static_cast<nsIChannelEventSink *>(this);
     758           0 :     return NS_OK;
     759             :   }
     760             : 
     761           0 :   return NS_ERROR_NO_INTERFACE;
     762             : }
     763             : 
     764             : NS_IMETHODIMP
     765           0 : nsPACMan::AsyncOnChannelRedirect(nsIChannel *oldChannel, nsIChannel *newChannel,
     766             :                                  uint32_t flags,
     767             :                                  nsIAsyncVerifyRedirectCallback *callback)
     768             : {
     769           0 :   MOZ_ASSERT(NS_IsMainThread(), "wrong thread");
     770             : 
     771           0 :   nsresult rv = NS_OK;
     772           0 :   nsCOMPtr<nsIURI> pacURI;
     773           0 :   if (NS_FAILED((rv = newChannel->GetURI(getter_AddRefs(pacURI)))))
     774           0 :       return rv;
     775             : 
     776           0 :   rv = pacURI->GetSpec(mPACURIRedirectSpec);
     777           0 :   if (NS_FAILED(rv))
     778           0 :       return rv;
     779             : 
     780           0 :   LOG(("nsPACMan redirect from original %s to redirected %s\n",
     781             :        mPACURISpec.get(), mPACURIRedirectSpec.get()));
     782             : 
     783             :   // do not update mPACURISpec - that needs to stay as the
     784             :   // configured URI so that we can determine when the config changes.
     785             :   // However do track the most recent URI in the redirect change
     786             :   // as mPACURIRedirectSpec so that URI can be allowed to bypass
     787             :   // the proxy and actually fetch the pac file.
     788             : 
     789           0 :   callback->OnRedirectVerifyCallback(NS_OK);
     790           0 :   return NS_OK;
     791             : }
     792             : 
     793             : nsresult
     794           1 : nsPACMan::Init(nsISystemProxySettings *systemProxySettings)
     795             : {
     796           1 :   mSystemProxySettings = systemProxySettings;
     797             : 
     798             :   nsresult rv =
     799           1 :     NS_NewNamedThread("ProxyResolution", getter_AddRefs(mPACThread));
     800             : 
     801           1 :   return rv;
     802             : }
     803             : 
     804             : } // namespace net
     805             : } // namespace mozilla

Generated by: LCOV version 1.13