nsPACMan.cpp 21 KB

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