nsBaseChannel.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "nsBaseChannel.h"
  6. #include "nsContentUtils.h"
  7. #include "nsURLHelper.h"
  8. #include "nsNetCID.h"
  9. #include "nsMimeTypes.h"
  10. #include "nsIContentSniffer.h"
  11. #include "nsIScriptSecurityManager.h"
  12. #include "nsMimeTypes.h"
  13. #include "nsIHttpEventSink.h"
  14. #include "nsIHttpChannel.h"
  15. #include "nsIChannelEventSink.h"
  16. #include "nsIStreamConverterService.h"
  17. #include "nsChannelClassifier.h"
  18. #include "nsAsyncRedirectVerifyHelper.h"
  19. #include "nsProxyRelease.h"
  20. #include "nsXULAppAPI.h"
  21. #include "nsContentSecurityManager.h"
  22. #include "mozilla/LoadInfo.h"
  23. #include "nsServiceManagerUtils.h"
  24. using namespace mozilla;
  25. using namespace mozilla::net;
  26. // This class is used to suspend a request across a function scope.
  27. class ScopedRequestSuspender {
  28. public:
  29. explicit ScopedRequestSuspender(nsIRequest *request)
  30. : mRequest(request) {
  31. if (mRequest && NS_FAILED(mRequest->Suspend())) {
  32. NS_WARNING("Couldn't suspend pump");
  33. mRequest = nullptr;
  34. }
  35. }
  36. ~ScopedRequestSuspender() {
  37. if (mRequest)
  38. mRequest->Resume();
  39. }
  40. private:
  41. nsIRequest *mRequest;
  42. };
  43. // Used to suspend data events from mPump within a function scope. This is
  44. // usually needed when a function makes callbacks that could process events.
  45. #define SUSPEND_PUMP_FOR_SCOPE() \
  46. ScopedRequestSuspender pump_suspender__(mPump)
  47. //-----------------------------------------------------------------------------
  48. // nsBaseChannel
  49. nsBaseChannel::nsBaseChannel()
  50. : mLoadFlags(LOAD_NORMAL)
  51. , mQueriedProgressSink(true)
  52. , mSynthProgressEvents(false)
  53. , mAllowThreadRetargeting(true)
  54. , mWaitingOnAsyncRedirect(false)
  55. , mStatus(NS_OK)
  56. , mContentDispositionHint(UINT32_MAX)
  57. , mContentLength(-1)
  58. , mWasOpened(false)
  59. {
  60. mContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
  61. }
  62. nsBaseChannel::~nsBaseChannel()
  63. {
  64. NS_ReleaseOnMainThread(mLoadInfo.forget());
  65. }
  66. nsresult
  67. nsBaseChannel::Redirect(nsIChannel *newChannel, uint32_t redirectFlags,
  68. bool openNewChannel)
  69. {
  70. SUSPEND_PUMP_FOR_SCOPE();
  71. // Transfer properties
  72. newChannel->SetLoadGroup(mLoadGroup);
  73. newChannel->SetNotificationCallbacks(mCallbacks);
  74. newChannel->SetLoadFlags(mLoadFlags | LOAD_REPLACE);
  75. // make a copy of the loadinfo, append to the redirectchain
  76. // and set it on the new channel
  77. if (mLoadInfo) {
  78. nsSecurityFlags secFlags = mLoadInfo->GetSecurityFlags() &
  79. ~nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
  80. nsCOMPtr<nsILoadInfo> newLoadInfo =
  81. static_cast<LoadInfo*>(mLoadInfo.get())->CloneWithNewSecFlags(secFlags);
  82. nsCOMPtr<nsIPrincipal> uriPrincipal;
  83. nsIScriptSecurityManager *sm = nsContentUtils::GetSecurityManager();
  84. sm->GetChannelURIPrincipal(this, getter_AddRefs(uriPrincipal));
  85. bool isInternalRedirect =
  86. (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
  87. nsIChannelEventSink::REDIRECT_STS_UPGRADE));
  88. newLoadInfo->AppendRedirectedPrincipal(uriPrincipal, isInternalRedirect);
  89. newChannel->SetLoadInfo(newLoadInfo);
  90. }
  91. else {
  92. // the newChannel was created with a dummy loadInfo, we should clear
  93. // it in case the original channel does not have a loadInfo
  94. newChannel->SetLoadInfo(nullptr);
  95. }
  96. // Preserve the privacy bit if it has been overridden
  97. if (mPrivateBrowsingOverriden) {
  98. nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
  99. do_QueryInterface(newChannel);
  100. if (newPBChannel) {
  101. newPBChannel->SetPrivate(mPrivateBrowsing);
  102. }
  103. }
  104. nsCOMPtr<nsIWritablePropertyBag> bag = ::do_QueryInterface(newChannel);
  105. if (bag) {
  106. for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
  107. bag->SetProperty(iter.Key(), iter.UserData());
  108. }
  109. }
  110. // Notify consumer, giving chance to cancel redirect. For backwards compat,
  111. // we support nsIHttpEventSink if we are an HTTP channel and if this is not
  112. // an internal redirect.
  113. RefPtr<nsAsyncRedirectVerifyHelper> redirectCallbackHelper =
  114. new nsAsyncRedirectVerifyHelper();
  115. bool checkRedirectSynchronously = !openNewChannel;
  116. mRedirectChannel = newChannel;
  117. mRedirectFlags = redirectFlags;
  118. mOpenRedirectChannel = openNewChannel;
  119. nsresult rv = redirectCallbackHelper->Init(this, newChannel, redirectFlags,
  120. checkRedirectSynchronously);
  121. if (NS_FAILED(rv))
  122. return rv;
  123. if (checkRedirectSynchronously && NS_FAILED(mStatus))
  124. return mStatus;
  125. return NS_OK;
  126. }
  127. nsresult
  128. nsBaseChannel::ContinueRedirect()
  129. {
  130. // Backwards compat for non-internal redirects from a HTTP channel.
  131. // XXX Is our http channel implementation going to derive from nsBaseChannel?
  132. // If not, this code can be removed.
  133. if (!(mRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
  134. nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface();
  135. if (httpChannel) {
  136. nsCOMPtr<nsIHttpEventSink> httpEventSink;
  137. GetCallback(httpEventSink);
  138. if (httpEventSink) {
  139. nsresult rv = httpEventSink->OnRedirect(httpChannel, mRedirectChannel);
  140. if (NS_FAILED(rv)) {
  141. return rv;
  142. }
  143. }
  144. }
  145. }
  146. // Make sure to do this _after_ making all the OnChannelRedirect calls
  147. mRedirectChannel->SetOriginalURI(OriginalURI());
  148. // If we fail to open the new channel, then we want to leave this channel
  149. // unaffected, so we defer tearing down our channel until we have succeeded
  150. // with the redirect.
  151. if (mOpenRedirectChannel) {
  152. nsresult rv = NS_OK;
  153. if (mLoadInfo && mLoadInfo->GetEnforceSecurity()) {
  154. MOZ_ASSERT(!mListenerContext, "mListenerContext should be null!");
  155. rv = mRedirectChannel->AsyncOpen2(mListener);
  156. }
  157. else {
  158. rv = mRedirectChannel->AsyncOpen(mListener, mListenerContext);
  159. }
  160. NS_ENSURE_SUCCESS(rv, rv);
  161. }
  162. mRedirectChannel = nullptr;
  163. // close down this channel
  164. Cancel(NS_BINDING_REDIRECTED);
  165. ChannelDone();
  166. return NS_OK;
  167. }
  168. bool
  169. nsBaseChannel::HasContentTypeHint() const
  170. {
  171. NS_ASSERTION(!Pending(), "HasContentTypeHint called too late");
  172. return !mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE);
  173. }
  174. nsresult
  175. nsBaseChannel::PushStreamConverter(const char *fromType,
  176. const char *toType,
  177. bool invalidatesContentLength,
  178. nsIStreamListener **result)
  179. {
  180. NS_ASSERTION(mListener, "no listener");
  181. nsresult rv;
  182. nsCOMPtr<nsIStreamConverterService> scs =
  183. do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv);
  184. if (NS_FAILED(rv))
  185. return rv;
  186. nsCOMPtr<nsIStreamListener> converter;
  187. rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext,
  188. getter_AddRefs(converter));
  189. if (NS_SUCCEEDED(rv)) {
  190. mListener = converter;
  191. if (invalidatesContentLength)
  192. mContentLength = -1;
  193. if (result) {
  194. *result = nullptr;
  195. converter.swap(*result);
  196. }
  197. }
  198. return rv;
  199. }
  200. nsresult
  201. nsBaseChannel::BeginPumpingData()
  202. {
  203. nsCOMPtr<nsIInputStream> stream;
  204. nsCOMPtr<nsIChannel> channel;
  205. nsresult rv = OpenContentStream(true, getter_AddRefs(stream),
  206. getter_AddRefs(channel));
  207. if (NS_FAILED(rv))
  208. return rv;
  209. NS_ASSERTION(!stream || !channel, "Got both a channel and a stream?");
  210. if (channel) {
  211. rv = NS_DispatchToCurrentThread(new RedirectRunnable(this, channel));
  212. if (NS_SUCCEEDED(rv))
  213. mWaitingOnAsyncRedirect = true;
  214. return rv;
  215. }
  216. // By assigning mPump, we flag this channel as pending (see Pending). It's
  217. // important that the pending flag is set when we call into the stream (the
  218. // call to AsyncRead results in the stream's AsyncWait method being called)
  219. // and especially when we call into the loadgroup. Our caller takes care to
  220. // release mPump if we return an error.
  221. rv = nsInputStreamPump::Create(getter_AddRefs(mPump), stream, -1, -1, 0, 0,
  222. true);
  223. if (NS_SUCCEEDED(rv))
  224. rv = mPump->AsyncRead(this, nullptr);
  225. return rv;
  226. }
  227. void
  228. nsBaseChannel::HandleAsyncRedirect(nsIChannel* newChannel)
  229. {
  230. NS_ASSERTION(!mPump, "Shouldn't have gotten here");
  231. nsresult rv = mStatus;
  232. if (NS_SUCCEEDED(mStatus)) {
  233. rv = Redirect(newChannel,
  234. nsIChannelEventSink::REDIRECT_TEMPORARY,
  235. true);
  236. if (NS_SUCCEEDED(rv)) {
  237. // OnRedirectVerifyCallback will be called asynchronously
  238. return;
  239. }
  240. }
  241. ContinueHandleAsyncRedirect(rv);
  242. }
  243. void
  244. nsBaseChannel::ContinueHandleAsyncRedirect(nsresult result)
  245. {
  246. mWaitingOnAsyncRedirect = false;
  247. if (NS_FAILED(result))
  248. Cancel(result);
  249. if (NS_FAILED(result) && mListener) {
  250. // Notify our consumer ourselves
  251. mListener->OnStartRequest(this, mListenerContext);
  252. mListener->OnStopRequest(this, mListenerContext, mStatus);
  253. ChannelDone();
  254. }
  255. if (mLoadGroup)
  256. mLoadGroup->RemoveRequest(this, nullptr, mStatus);
  257. // Drop notification callbacks to prevent cycles.
  258. mCallbacks = nullptr;
  259. CallbacksChanged();
  260. }
  261. void
  262. nsBaseChannel::ClassifyURI()
  263. {
  264. // For channels created in the child process, delegate to the parent to
  265. // classify URIs.
  266. if (!XRE_IsParentProcess()) {
  267. return;
  268. }
  269. if (mLoadFlags & LOAD_CLASSIFY_URI) {
  270. RefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
  271. if (classifier) {
  272. classifier->Start(this);
  273. } else {
  274. Cancel(NS_ERROR_OUT_OF_MEMORY);
  275. }
  276. }
  277. }
  278. //-----------------------------------------------------------------------------
  279. // nsBaseChannel::nsISupports
  280. NS_IMPL_ISUPPORTS_INHERITED(nsBaseChannel,
  281. nsHashPropertyBag,
  282. nsIRequest,
  283. nsIChannel,
  284. nsIThreadRetargetableRequest,
  285. nsIInterfaceRequestor,
  286. nsITransportEventSink,
  287. nsIRequestObserver,
  288. nsIStreamListener,
  289. nsIThreadRetargetableStreamListener,
  290. nsIAsyncVerifyRedirectCallback,
  291. nsIPrivateBrowsingChannel)
  292. //-----------------------------------------------------------------------------
  293. // nsBaseChannel::nsIRequest
  294. NS_IMETHODIMP
  295. nsBaseChannel::GetName(nsACString &result)
  296. {
  297. if (!mURI) {
  298. result.Truncate();
  299. return NS_OK;
  300. }
  301. return mURI->GetSpec(result);
  302. }
  303. NS_IMETHODIMP
  304. nsBaseChannel::IsPending(bool *result)
  305. {
  306. *result = Pending();
  307. return NS_OK;
  308. }
  309. NS_IMETHODIMP
  310. nsBaseChannel::GetStatus(nsresult *status)
  311. {
  312. if (mPump && NS_SUCCEEDED(mStatus)) {
  313. mPump->GetStatus(status);
  314. } else {
  315. *status = mStatus;
  316. }
  317. return NS_OK;
  318. }
  319. NS_IMETHODIMP
  320. nsBaseChannel::Cancel(nsresult status)
  321. {
  322. // Ignore redundant cancelation
  323. if (NS_FAILED(mStatus))
  324. return NS_OK;
  325. mStatus = status;
  326. if (mPump)
  327. mPump->Cancel(status);
  328. return NS_OK;
  329. }
  330. NS_IMETHODIMP
  331. nsBaseChannel::Suspend()
  332. {
  333. NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
  334. return mPump->Suspend();
  335. }
  336. NS_IMETHODIMP
  337. nsBaseChannel::Resume()
  338. {
  339. NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
  340. return mPump->Resume();
  341. }
  342. NS_IMETHODIMP
  343. nsBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
  344. {
  345. *aLoadFlags = mLoadFlags;
  346. return NS_OK;
  347. }
  348. NS_IMETHODIMP
  349. nsBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
  350. {
  351. mLoadFlags = aLoadFlags;
  352. return NS_OK;
  353. }
  354. NS_IMETHODIMP
  355. nsBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
  356. {
  357. NS_IF_ADDREF(*aLoadGroup = mLoadGroup);
  358. return NS_OK;
  359. }
  360. NS_IMETHODIMP
  361. nsBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
  362. {
  363. if (!CanSetLoadGroup(aLoadGroup)) {
  364. return NS_ERROR_FAILURE;
  365. }
  366. mLoadGroup = aLoadGroup;
  367. CallbacksChanged();
  368. UpdatePrivateBrowsing();
  369. return NS_OK;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // nsBaseChannel::nsIChannel
  373. NS_IMETHODIMP
  374. nsBaseChannel::GetOriginalURI(nsIURI **aURI)
  375. {
  376. *aURI = OriginalURI();
  377. NS_ADDREF(*aURI);
  378. return NS_OK;
  379. }
  380. NS_IMETHODIMP
  381. nsBaseChannel::SetOriginalURI(nsIURI *aURI)
  382. {
  383. NS_ENSURE_ARG_POINTER(aURI);
  384. mOriginalURI = aURI;
  385. return NS_OK;
  386. }
  387. NS_IMETHODIMP
  388. nsBaseChannel::GetURI(nsIURI **aURI)
  389. {
  390. NS_IF_ADDREF(*aURI = mURI);
  391. return NS_OK;
  392. }
  393. NS_IMETHODIMP
  394. nsBaseChannel::GetOwner(nsISupports **aOwner)
  395. {
  396. NS_IF_ADDREF(*aOwner = mOwner);
  397. return NS_OK;
  398. }
  399. NS_IMETHODIMP
  400. nsBaseChannel::SetOwner(nsISupports *aOwner)
  401. {
  402. mOwner = aOwner;
  403. return NS_OK;
  404. }
  405. NS_IMETHODIMP
  406. nsBaseChannel::SetLoadInfo(nsILoadInfo* aLoadInfo)
  407. {
  408. mLoadInfo = aLoadInfo;
  409. return NS_OK;
  410. }
  411. NS_IMETHODIMP
  412. nsBaseChannel::GetLoadInfo(nsILoadInfo** aLoadInfo)
  413. {
  414. NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
  415. return NS_OK;
  416. }
  417. NS_IMETHODIMP
  418. nsBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
  419. {
  420. NS_IF_ADDREF(*aCallbacks = mCallbacks);
  421. return NS_OK;
  422. }
  423. NS_IMETHODIMP
  424. nsBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
  425. {
  426. if (!CanSetCallbacks(aCallbacks)) {
  427. return NS_ERROR_FAILURE;
  428. }
  429. mCallbacks = aCallbacks;
  430. CallbacksChanged();
  431. UpdatePrivateBrowsing();
  432. return NS_OK;
  433. }
  434. NS_IMETHODIMP
  435. nsBaseChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
  436. {
  437. NS_IF_ADDREF(*aSecurityInfo = mSecurityInfo);
  438. return NS_OK;
  439. }
  440. NS_IMETHODIMP
  441. nsBaseChannel::GetContentType(nsACString &aContentType)
  442. {
  443. aContentType = mContentType;
  444. return NS_OK;
  445. }
  446. NS_IMETHODIMP
  447. nsBaseChannel::SetContentType(const nsACString &aContentType)
  448. {
  449. // mContentCharset is unchanged if not parsed
  450. bool dummy;
  451. net_ParseContentType(aContentType, mContentType, mContentCharset, &dummy);
  452. return NS_OK;
  453. }
  454. NS_IMETHODIMP
  455. nsBaseChannel::GetContentCharset(nsACString &aContentCharset)
  456. {
  457. aContentCharset = mContentCharset;
  458. return NS_OK;
  459. }
  460. NS_IMETHODIMP
  461. nsBaseChannel::SetContentCharset(const nsACString &aContentCharset)
  462. {
  463. mContentCharset = aContentCharset;
  464. return NS_OK;
  465. }
  466. NS_IMETHODIMP
  467. nsBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
  468. {
  469. // preserve old behavior, fail unless explicitly set.
  470. if (mContentDispositionHint == UINT32_MAX) {
  471. return NS_ERROR_NOT_AVAILABLE;
  472. }
  473. *aContentDisposition = mContentDispositionHint;
  474. return NS_OK;
  475. }
  476. NS_IMETHODIMP
  477. nsBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
  478. {
  479. mContentDispositionHint = aContentDisposition;
  480. return NS_OK;
  481. }
  482. NS_IMETHODIMP
  483. nsBaseChannel::GetContentDispositionFilename(nsAString &aContentDispositionFilename)
  484. {
  485. if (!mContentDispositionFilename) {
  486. return NS_ERROR_NOT_AVAILABLE;
  487. }
  488. aContentDispositionFilename = *mContentDispositionFilename;
  489. return NS_OK;
  490. }
  491. NS_IMETHODIMP
  492. nsBaseChannel::SetContentDispositionFilename(const nsAString &aContentDispositionFilename)
  493. {
  494. mContentDispositionFilename = new nsString(aContentDispositionFilename);
  495. // For safety reasons ensure the filename doesn't contain null characters and
  496. // replace them with underscores. We may later pass the extension to system
  497. // MIME APIs that expect null terminated strings.
  498. mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
  499. return NS_OK;
  500. }
  501. NS_IMETHODIMP
  502. nsBaseChannel::GetContentDispositionHeader(nsACString &aContentDispositionHeader)
  503. {
  504. return NS_ERROR_NOT_AVAILABLE;
  505. }
  506. NS_IMETHODIMP
  507. nsBaseChannel::GetContentLength(int64_t *aContentLength)
  508. {
  509. *aContentLength = mContentLength;
  510. return NS_OK;
  511. }
  512. NS_IMETHODIMP
  513. nsBaseChannel::SetContentLength(int64_t aContentLength)
  514. {
  515. mContentLength = aContentLength;
  516. return NS_OK;
  517. }
  518. NS_IMETHODIMP
  519. nsBaseChannel::Open(nsIInputStream **result)
  520. {
  521. NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
  522. NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
  523. NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
  524. nsCOMPtr<nsIChannel> chan;
  525. nsresult rv = OpenContentStream(false, result, getter_AddRefs(chan));
  526. NS_ASSERTION(!chan || !*result, "Got both a channel and a stream?");
  527. if (NS_SUCCEEDED(rv) && chan) {
  528. rv = Redirect(chan, nsIChannelEventSink::REDIRECT_INTERNAL, false);
  529. if (NS_FAILED(rv))
  530. return rv;
  531. rv = chan->Open(result);
  532. } else if (rv == NS_ERROR_NOT_IMPLEMENTED)
  533. return NS_ImplementChannelOpen(this, result);
  534. if (NS_SUCCEEDED(rv)) {
  535. mWasOpened = true;
  536. ClassifyURI();
  537. }
  538. return rv;
  539. }
  540. NS_IMETHODIMP
  541. nsBaseChannel::Open2(nsIInputStream** aStream)
  542. {
  543. nsCOMPtr<nsIStreamListener> listener;
  544. nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
  545. NS_ENSURE_SUCCESS(rv, rv);
  546. return Open(aStream);
  547. }
  548. NS_IMETHODIMP
  549. nsBaseChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *ctxt)
  550. {
  551. MOZ_ASSERT(!mLoadInfo ||
  552. mLoadInfo->GetSecurityMode() == 0 ||
  553. mLoadInfo->GetInitialSecurityCheckDone() ||
  554. (mLoadInfo->GetSecurityMode() == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
  555. nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal())),
  556. "security flags in loadInfo but asyncOpen2() not called");
  557. NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_INITIALIZED);
  558. NS_ENSURE_TRUE(!mPump, NS_ERROR_IN_PROGRESS);
  559. NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
  560. NS_ENSURE_ARG(listener);
  561. // Skip checking for chrome:// sub-resources.
  562. nsAutoCString scheme;
  563. mURI->GetScheme(scheme);
  564. if (!scheme.EqualsLiteral("file")) {
  565. NS_CompareLoadInfoAndLoadContext(this);
  566. }
  567. // Ensure that this is an allowed port before proceeding.
  568. nsresult rv = NS_CheckPortSafety(mURI);
  569. if (NS_FAILED(rv)) {
  570. mCallbacks = nullptr;
  571. return rv;
  572. }
  573. // Store the listener and context early so that OpenContentStream and the
  574. // stream's AsyncWait method (called by AsyncRead) can have access to them
  575. // via PushStreamConverter and the StreamListener methods. However, since
  576. // this typically introduces a reference cycle between this and the listener,
  577. // we need to be sure to break the reference if this method does not succeed.
  578. mListener = listener;
  579. mListenerContext = ctxt;
  580. // This method assigns mPump as a side-effect. We need to clear mPump if
  581. // this method fails.
  582. rv = BeginPumpingData();
  583. if (NS_FAILED(rv)) {
  584. mPump = nullptr;
  585. ChannelDone();
  586. mCallbacks = nullptr;
  587. return rv;
  588. }
  589. // At this point, we are going to return success no matter what.
  590. mWasOpened = true;
  591. SUSPEND_PUMP_FOR_SCOPE();
  592. if (mLoadGroup)
  593. mLoadGroup->AddRequest(this, nullptr);
  594. ClassifyURI();
  595. return NS_OK;
  596. }
  597. NS_IMETHODIMP
  598. nsBaseChannel::AsyncOpen2(nsIStreamListener *aListener)
  599. {
  600. nsCOMPtr<nsIStreamListener> listener = aListener;
  601. nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
  602. NS_ENSURE_SUCCESS(rv, rv);
  603. return AsyncOpen(listener, nullptr);
  604. }
  605. //-----------------------------------------------------------------------------
  606. // nsBaseChannel::nsITransportEventSink
  607. NS_IMETHODIMP
  608. nsBaseChannel::OnTransportStatus(nsITransport *transport, nsresult status,
  609. int64_t progress, int64_t progressMax)
  610. {
  611. // In some cases, we may wish to suppress transport-layer status events.
  612. if (!mPump || NS_FAILED(mStatus)) {
  613. return NS_OK;
  614. }
  615. SUSPEND_PUMP_FOR_SCOPE();
  616. // Lazily fetch mProgressSink
  617. if (!mProgressSink) {
  618. if (mQueriedProgressSink) {
  619. return NS_OK;
  620. }
  621. GetCallback(mProgressSink);
  622. mQueriedProgressSink = true;
  623. if (!mProgressSink) {
  624. return NS_OK;
  625. }
  626. }
  627. if (!HasLoadFlag(LOAD_BACKGROUND)) {
  628. nsAutoString statusArg;
  629. if (GetStatusArg(status, statusArg)) {
  630. mProgressSink->OnStatus(this, mListenerContext, status, statusArg.get());
  631. }
  632. }
  633. if (progress) {
  634. mProgressSink->OnProgress(this, mListenerContext, progress, progressMax);
  635. }
  636. return NS_OK;
  637. }
  638. //-----------------------------------------------------------------------------
  639. // nsBaseChannel::nsIInterfaceRequestor
  640. NS_IMETHODIMP
  641. nsBaseChannel::GetInterface(const nsIID &iid, void **result)
  642. {
  643. NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup, iid, result);
  644. return *result ? NS_OK : NS_ERROR_NO_INTERFACE;
  645. }
  646. //-----------------------------------------------------------------------------
  647. // nsBaseChannel::nsIRequestObserver
  648. static void
  649. CallTypeSniffers(void *aClosure, const uint8_t *aData, uint32_t aCount)
  650. {
  651. nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
  652. nsAutoCString newType;
  653. NS_SniffContent(NS_CONTENT_SNIFFER_CATEGORY, chan, aData, aCount, newType);
  654. if (!newType.IsEmpty()) {
  655. chan->SetContentType(newType);
  656. }
  657. }
  658. static void
  659. CallUnknownTypeSniffer(void *aClosure, const uint8_t *aData, uint32_t aCount)
  660. {
  661. nsIChannel *chan = static_cast<nsIChannel*>(aClosure);
  662. nsCOMPtr<nsIContentSniffer> sniffer =
  663. do_CreateInstance(NS_GENERIC_CONTENT_SNIFFER);
  664. if (!sniffer)
  665. return;
  666. nsAutoCString detected;
  667. nsresult rv = sniffer->GetMIMETypeFromContent(chan, aData, aCount, detected);
  668. if (NS_SUCCEEDED(rv))
  669. chan->SetContentType(detected);
  670. }
  671. NS_IMETHODIMP
  672. nsBaseChannel::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
  673. {
  674. MOZ_ASSERT(request == mPump);
  675. // If our content type is unknown, use the content type
  676. // sniffer. If the sniffer is not available for some reason, then we just keep
  677. // going as-is.
  678. if (NS_SUCCEEDED(mStatus) &&
  679. mContentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE)) {
  680. mPump->PeekStream(CallUnknownTypeSniffer, static_cast<nsIChannel*>(this));
  681. }
  682. // Now, the general type sniffers. Skip this if we have none.
  683. if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS)
  684. mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
  685. SUSPEND_PUMP_FOR_SCOPE();
  686. if (mListener) // null in case of redirect
  687. return mListener->OnStartRequest(this, mListenerContext);
  688. return NS_OK;
  689. }
  690. NS_IMETHODIMP
  691. nsBaseChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt,
  692. nsresult status)
  693. {
  694. // If both mStatus and status are failure codes, we keep mStatus as-is since
  695. // that is consistent with our GetStatus and Cancel methods.
  696. if (NS_SUCCEEDED(mStatus))
  697. mStatus = status;
  698. // Cause Pending to return false.
  699. mPump = nullptr;
  700. if (mListener) // null in case of redirect
  701. mListener->OnStopRequest(this, mListenerContext, mStatus);
  702. ChannelDone();
  703. // No need to suspend pump in this scope since we will not be receiving
  704. // any more events from it.
  705. if (mLoadGroup)
  706. mLoadGroup->RemoveRequest(this, nullptr, mStatus);
  707. // Drop notification callbacks to prevent cycles.
  708. mCallbacks = nullptr;
  709. CallbacksChanged();
  710. return NS_OK;
  711. }
  712. //-----------------------------------------------------------------------------
  713. // nsBaseChannel::nsIStreamListener
  714. NS_IMETHODIMP
  715. nsBaseChannel::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
  716. nsIInputStream *stream, uint64_t offset,
  717. uint32_t count)
  718. {
  719. SUSPEND_PUMP_FOR_SCOPE();
  720. nsresult rv = mListener->OnDataAvailable(this, mListenerContext, stream,
  721. offset, count);
  722. if (mSynthProgressEvents && NS_SUCCEEDED(rv)) {
  723. int64_t prog = offset + count;
  724. if (NS_IsMainThread()) {
  725. OnTransportStatus(nullptr, NS_NET_STATUS_READING, prog, mContentLength);
  726. } else {
  727. class OnTransportStatusAsyncEvent : public mozilla::Runnable
  728. {
  729. RefPtr<nsBaseChannel> mChannel;
  730. int64_t mProgress;
  731. int64_t mContentLength;
  732. public:
  733. OnTransportStatusAsyncEvent(nsBaseChannel* aChannel,
  734. int64_t aProgress,
  735. int64_t aContentLength)
  736. : mChannel(aChannel),
  737. mProgress(aProgress),
  738. mContentLength(aContentLength)
  739. { }
  740. NS_IMETHOD Run() override
  741. {
  742. return mChannel->OnTransportStatus(nullptr, NS_NET_STATUS_READING,
  743. mProgress, mContentLength);
  744. }
  745. };
  746. nsCOMPtr<nsIRunnable> runnable =
  747. new OnTransportStatusAsyncEvent(this, prog, mContentLength);
  748. NS_DispatchToMainThread(runnable);
  749. }
  750. }
  751. return rv;
  752. }
  753. NS_IMETHODIMP
  754. nsBaseChannel::OnRedirectVerifyCallback(nsresult result)
  755. {
  756. if (NS_SUCCEEDED(result))
  757. result = ContinueRedirect();
  758. if (NS_FAILED(result) && !mWaitingOnAsyncRedirect) {
  759. if (NS_SUCCEEDED(mStatus))
  760. mStatus = result;
  761. return NS_OK;
  762. }
  763. if (mWaitingOnAsyncRedirect)
  764. ContinueHandleAsyncRedirect(result);
  765. return NS_OK;
  766. }
  767. NS_IMETHODIMP
  768. nsBaseChannel::RetargetDeliveryTo(nsIEventTarget* aEventTarget)
  769. {
  770. MOZ_ASSERT(NS_IsMainThread());
  771. NS_ENSURE_TRUE(mPump, NS_ERROR_NOT_INITIALIZED);
  772. if (!mAllowThreadRetargeting) {
  773. return NS_ERROR_NOT_IMPLEMENTED;
  774. }
  775. return mPump->RetargetDeliveryTo(aEventTarget);
  776. }
  777. NS_IMETHODIMP
  778. nsBaseChannel::CheckListenerChain()
  779. {
  780. MOZ_ASSERT(NS_IsMainThread());
  781. if (!mAllowThreadRetargeting) {
  782. return NS_ERROR_NOT_IMPLEMENTED;
  783. }
  784. nsCOMPtr<nsIThreadRetargetableStreamListener> listener =
  785. do_QueryInterface(mListener);
  786. if (!listener) {
  787. return NS_ERROR_NO_INTERFACE;
  788. }
  789. return listener->CheckListenerChain();
  790. }