FetchConsumer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714
  1. /* -*- Mode: C++; tab-width: 8; 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 "Fetch.h"
  6. #include "FetchConsumer.h"
  7. #include "nsIInputStreamPump.h"
  8. #include "nsProxyRelease.h"
  9. #include "WorkerPrivate.h"
  10. #include "WorkerRunnable.h"
  11. #include "WorkerScope.h"
  12. #include "Workers.h"
  13. namespace mozilla {
  14. namespace dom {
  15. using namespace workers;
  16. namespace {
  17. template <class Derived>
  18. class FetchBodyWorkerHolder final : public workers::WorkerHolder
  19. {
  20. RefPtr<FetchBodyConsumer<Derived>> mConsumer;
  21. bool mWasNotified;
  22. public:
  23. explicit FetchBodyWorkerHolder(FetchBodyConsumer<Derived>* aConsumer)
  24. : mConsumer(aConsumer)
  25. , mWasNotified(false)
  26. {
  27. MOZ_ASSERT(aConsumer);
  28. }
  29. ~FetchBodyWorkerHolder() = default;
  30. bool Notify(workers::Status aStatus) override
  31. {
  32. MOZ_ASSERT(aStatus > workers::Running);
  33. if (!mWasNotified) {
  34. mWasNotified = true;
  35. mConsumer->ShutDownMainThreadConsuming();
  36. }
  37. return true;
  38. }
  39. };
  40. template <class Derived>
  41. class BeginConsumeBodyRunnable final : public Runnable
  42. {
  43. RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
  44. public:
  45. explicit BeginConsumeBodyRunnable(FetchBodyConsumer<Derived>* aConsumer)
  46. : mFetchBodyConsumer(aConsumer)
  47. { }
  48. NS_IMETHOD
  49. Run() override
  50. {
  51. mFetchBodyConsumer->BeginConsumeBodyMainThread();
  52. return NS_OK;
  53. }
  54. };
  55. /*
  56. * Called on successfully reading the complete stream.
  57. */
  58. template <class Derived>
  59. class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable
  60. {
  61. RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
  62. nsresult mStatus;
  63. uint32_t mLength;
  64. uint8_t* mResult;
  65. public:
  66. ContinueConsumeBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
  67. nsresult aStatus, uint32_t aLength,
  68. uint8_t* aResult)
  69. : MainThreadWorkerRunnable(aFetchBodyConsumer->GetWorkerPrivate())
  70. , mFetchBodyConsumer(aFetchBodyConsumer)
  71. , mStatus(aStatus)
  72. , mLength(aLength)
  73. , mResult(aResult)
  74. {
  75. MOZ_ASSERT(NS_IsMainThread());
  76. }
  77. bool
  78. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  79. {
  80. mFetchBodyConsumer->ContinueConsumeBody(mStatus, mLength, mResult);
  81. return true;
  82. }
  83. };
  84. template <class Derived>
  85. class FailConsumeBodyWorkerRunnable : public MainThreadWorkerControlRunnable
  86. {
  87. RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
  88. public:
  89. explicit FailConsumeBodyWorkerRunnable(FetchBodyConsumer<Derived>* aBodyConsumer)
  90. : MainThreadWorkerControlRunnable(aBodyConsumer->GetWorkerPrivate())
  91. , mBodyConsumer(aBodyConsumer)
  92. {
  93. AssertIsOnMainThread();
  94. }
  95. bool
  96. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  97. {
  98. mBodyConsumer->ContinueConsumeBody(NS_ERROR_FAILURE, 0, nullptr);
  99. return true;
  100. }
  101. };
  102. /*
  103. * In case of failure to create a stream pump or dispatch stream completion to
  104. * worker, ensure we cleanup properly. Thread agnostic.
  105. */
  106. template <class Derived>
  107. class MOZ_STACK_CLASS AutoFailConsumeBody final
  108. {
  109. RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer;
  110. public:
  111. explicit AutoFailConsumeBody(FetchBodyConsumer<Derived>* aBodyConsumer)
  112. : mBodyConsumer(aBodyConsumer)
  113. {}
  114. ~AutoFailConsumeBody()
  115. {
  116. AssertIsOnMainThread();
  117. if (mBodyConsumer) {
  118. if (mBodyConsumer->GetWorkerPrivate()) {
  119. RefPtr<FailConsumeBodyWorkerRunnable<Derived>> r =
  120. new FailConsumeBodyWorkerRunnable<Derived>(mBodyConsumer);
  121. if (!r->Dispatch()) {
  122. MOZ_CRASH("We are going to leak");
  123. }
  124. } else {
  125. mBodyConsumer->ContinueConsumeBody(NS_ERROR_FAILURE, 0, nullptr);
  126. }
  127. }
  128. }
  129. void
  130. DontFail()
  131. {
  132. mBodyConsumer = nullptr;
  133. }
  134. };
  135. /*
  136. * Called on successfully reading the complete stream for Blob.
  137. */
  138. template <class Derived>
  139. class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable
  140. {
  141. RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
  142. RefPtr<BlobImpl> mBlobImpl;
  143. public:
  144. ContinueConsumeBlobBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer,
  145. BlobImpl* aBlobImpl)
  146. : MainThreadWorkerRunnable(aFetchBodyConsumer->GetWorkerPrivate())
  147. , mFetchBodyConsumer(aFetchBodyConsumer)
  148. , mBlobImpl(aBlobImpl)
  149. {
  150. MOZ_ASSERT(NS_IsMainThread());
  151. MOZ_ASSERT(mBlobImpl);
  152. }
  153. bool
  154. WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
  155. {
  156. mFetchBodyConsumer->ContinueConsumeBlobBody(mBlobImpl);
  157. return true;
  158. }
  159. };
  160. template <class Derived>
  161. class ConsumeBodyDoneObserver : public nsIStreamLoaderObserver
  162. , public MutableBlobStorageCallback
  163. {
  164. RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer;
  165. public:
  166. NS_DECL_THREADSAFE_ISUPPORTS
  167. explicit ConsumeBodyDoneObserver(FetchBodyConsumer<Derived>* aFetchBodyConsumer)
  168. : mFetchBodyConsumer(aFetchBodyConsumer)
  169. { }
  170. NS_IMETHOD
  171. OnStreamComplete(nsIStreamLoader* aLoader,
  172. nsISupports* aCtxt,
  173. nsresult aStatus,
  174. uint32_t aResultLength,
  175. const uint8_t* aResult) override
  176. {
  177. MOZ_ASSERT(NS_IsMainThread());
  178. // The loading is completed. Let's nullify the pump before continuing the
  179. // consuming of the body.
  180. mFetchBodyConsumer->NullifyConsumeBodyPump();
  181. uint8_t* nonconstResult = const_cast<uint8_t*>(aResult);
  182. if (mFetchBodyConsumer->GetWorkerPrivate()) {
  183. RefPtr<ContinueConsumeBodyRunnable<Derived>> r =
  184. new ContinueConsumeBodyRunnable<Derived>(mFetchBodyConsumer,
  185. aStatus,
  186. aResultLength,
  187. nonconstResult);
  188. if (!r->Dispatch()) {
  189. NS_WARNING("Could not dispatch ConsumeBodyRunnable");
  190. // Return failure so that aResult is freed.
  191. return NS_ERROR_FAILURE;
  192. }
  193. } else {
  194. mFetchBodyConsumer->ContinueConsumeBody(aStatus, aResultLength,
  195. nonconstResult);
  196. }
  197. // FetchBody is responsible for data.
  198. return NS_SUCCESS_ADOPTED_DATA;
  199. }
  200. virtual void BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
  201. Blob* aBlob,
  202. nsresult aRv) override
  203. {
  204. // On error.
  205. if (NS_FAILED(aRv)) {
  206. OnStreamComplete(nullptr, nullptr, aRv, 0, nullptr);
  207. return;
  208. }
  209. // The loading is completed. Let's nullify the pump before continuing the
  210. // consuming of the body.
  211. mFetchBodyConsumer->NullifyConsumeBodyPump();
  212. MOZ_ASSERT(aBlob);
  213. if (mFetchBodyConsumer->GetWorkerPrivate()) {
  214. RefPtr<ContinueConsumeBlobBodyRunnable<Derived>> r =
  215. new ContinueConsumeBlobBodyRunnable<Derived>(mFetchBodyConsumer,
  216. aBlob->Impl());
  217. if (!r->Dispatch()) {
  218. NS_WARNING("Could not dispatch ConsumeBlobBodyRunnable");
  219. return;
  220. }
  221. } else {
  222. mFetchBodyConsumer->ContinueConsumeBlobBody(aBlob->Impl());
  223. }
  224. }
  225. private:
  226. virtual ~ConsumeBodyDoneObserver()
  227. { }
  228. };
  229. template <class Derived>
  230. NS_IMPL_ADDREF(ConsumeBodyDoneObserver<Derived>)
  231. template <class Derived>
  232. NS_IMPL_RELEASE(ConsumeBodyDoneObserver<Derived>)
  233. template <class Derived>
  234. NS_INTERFACE_MAP_BEGIN(ConsumeBodyDoneObserver<Derived>)
  235. NS_INTERFACE_MAP_ENTRY(nsIStreamLoaderObserver)
  236. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamLoaderObserver)
  237. NS_INTERFACE_MAP_END
  238. } // anonymous
  239. template <class Derived>
  240. /* static */ already_AddRefed<Promise>
  241. FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal,
  242. FetchBody<Derived>* aBody,
  243. AbortSignal* aSignal,
  244. FetchConsumeType aType,
  245. ErrorResult& aRv)
  246. {
  247. MOZ_ASSERT(aBody);
  248. nsCOMPtr<nsIInputStream> bodyStream;
  249. aBody->DerivedClass()->GetBody(getter_AddRefs(bodyStream));
  250. if (!bodyStream) {
  251. aRv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), EmptyCString());
  252. if (NS_WARN_IF(aRv.Failed())) {
  253. return nullptr;
  254. }
  255. }
  256. RefPtr<Promise> promise = Promise::Create(aGlobal, aRv);
  257. if (aRv.Failed()) {
  258. return nullptr;
  259. }
  260. WorkerPrivate* workerPrivate = nullptr;
  261. if (!NS_IsMainThread()) {
  262. workerPrivate = GetCurrentThreadWorkerPrivate();
  263. MOZ_ASSERT(workerPrivate);
  264. }
  265. RefPtr<FetchBodyConsumer<Derived>> consumer =
  266. new FetchBodyConsumer<Derived>(aGlobal, workerPrivate, aBody, bodyStream,
  267. promise, aType);
  268. if (!NS_IsMainThread()) {
  269. MOZ_ASSERT(workerPrivate);
  270. if (NS_WARN_IF(!consumer->RegisterWorkerHolder())) {
  271. aRv.Throw(NS_ERROR_FAILURE);
  272. return nullptr;
  273. }
  274. } else {
  275. nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  276. if (NS_WARN_IF(!os)) {
  277. aRv.Throw(NS_ERROR_FAILURE);
  278. return nullptr;
  279. }
  280. aRv = os->AddObserver(consumer, DOM_WINDOW_DESTROYED_TOPIC, true);
  281. if (NS_WARN_IF(aRv.Failed())) {
  282. return nullptr;
  283. }
  284. aRv = os->AddObserver(consumer, DOM_WINDOW_FROZEN_TOPIC, true);
  285. if (NS_WARN_IF(aRv.Failed())) {
  286. return nullptr;
  287. }
  288. }
  289. nsCOMPtr<nsIRunnable> r = new BeginConsumeBodyRunnable<Derived>(consumer);
  290. aRv = NS_DispatchToMainThread(r.forget());
  291. if (NS_WARN_IF(aRv.Failed())) {
  292. return nullptr;
  293. }
  294. if (aSignal) {
  295. consumer->Follow(aSignal);
  296. }
  297. return promise.forget();
  298. }
  299. template <class Derived>
  300. void
  301. FetchBodyConsumer<Derived>::ReleaseObject()
  302. {
  303. AssertIsOnTargetThread();
  304. if (NS_IsMainThread()) {
  305. nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
  306. if (os) {
  307. os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC);
  308. os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC);
  309. }
  310. }
  311. mGlobal = nullptr;
  312. mWorkerHolder = nullptr;
  313. #ifdef DEBUG
  314. mBody = nullptr;
  315. #endif
  316. Unfollow();
  317. }
  318. template <class Derived>
  319. FetchBodyConsumer<Derived>::FetchBodyConsumer(nsIGlobalObject* aGlobalObject,
  320. WorkerPrivate* aWorkerPrivate,
  321. FetchBody<Derived>* aBody,
  322. nsIInputStream* aBodyStream,
  323. Promise* aPromise,
  324. FetchConsumeType aType)
  325. : mTargetThread(NS_GetCurrentThread())
  326. #ifdef DEBUG
  327. , mBody(aBody)
  328. #endif
  329. , mBodyStream(aBodyStream)
  330. , mBlobStorageType(MutableBlobStorage::eOnlyInMemory)
  331. , mGlobal(aGlobalObject)
  332. , mWorkerPrivate(aWorkerPrivate)
  333. , mConsumeType(aType)
  334. , mConsumePromise(aPromise)
  335. , mBodyConsumed(false)
  336. , mShuttingDown(false)
  337. {
  338. MOZ_ASSERT(aBody);
  339. MOZ_ASSERT(aBodyStream);
  340. MOZ_ASSERT(aPromise);
  341. const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo =
  342. aBody->DerivedClass()->GetPrincipalInfo();
  343. // We support temporary file for blobs only if the principal is known and
  344. // it's system or content not in private Browsing.
  345. if (principalInfo &&
  346. (principalInfo->type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo ||
  347. (principalInfo->type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
  348. principalInfo->get_ContentPrincipalInfo().attrs().mPrivateBrowsingId == 0))) {
  349. mBlobStorageType = MutableBlobStorage::eCouldBeInTemporaryFile;
  350. }
  351. mBodyMimeType = aBody->MimeType();
  352. }
  353. template <class Derived>
  354. FetchBodyConsumer<Derived>::~FetchBodyConsumer()
  355. {
  356. }
  357. template <class Derived>
  358. void
  359. FetchBodyConsumer<Derived>::AssertIsOnTargetThread() const
  360. {
  361. MOZ_ASSERT(NS_GetCurrentThread() == mTargetThread);
  362. }
  363. template <class Derived>
  364. bool
  365. FetchBodyConsumer<Derived>::RegisterWorkerHolder()
  366. {
  367. MOZ_ASSERT(mWorkerPrivate);
  368. mWorkerPrivate->AssertIsOnWorkerThread();
  369. MOZ_ASSERT(!mWorkerHolder);
  370. mWorkerHolder.reset(new FetchBodyWorkerHolder<Derived>(this));
  371. if (!mWorkerHolder->HoldWorker(mWorkerPrivate, Closing)) {
  372. NS_WARNING("Failed to add workerHolder");
  373. mWorkerHolder = nullptr;
  374. return false;
  375. }
  376. return true;
  377. }
  378. /*
  379. * BeginConsumeBodyMainThread() will automatically reject the consume promise
  380. * and clean up on any failures, so there is no need for callers to do so,
  381. * reflected in a lack of error return code.
  382. */
  383. template <class Derived>
  384. void
  385. FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread()
  386. {
  387. AssertIsOnMainThread();
  388. AutoFailConsumeBody<Derived> autoReject(this);
  389. if (mShuttingDown) {
  390. // We haven't started yet, but we have been terminated. AutoFailConsumeBody
  391. // will dispatch a runnable to release resources.
  392. return;
  393. }
  394. nsCOMPtr<nsIInputStreamPump> pump;
  395. nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump),
  396. mBodyStream, -1, -1, 0, 0, false);
  397. if (NS_WARN_IF(NS_FAILED(rv))) {
  398. return;
  399. }
  400. RefPtr<ConsumeBodyDoneObserver<Derived>> p =
  401. new ConsumeBodyDoneObserver<Derived>(this);
  402. nsCOMPtr<nsIStreamListener> listener;
  403. if (mConsumeType == CONSUME_BLOB) {
  404. listener = new MutableBlobStreamListener(mBlobStorageType, nullptr,
  405. mBodyMimeType, p);
  406. } else {
  407. nsCOMPtr<nsIStreamLoader> loader;
  408. rv = NS_NewStreamLoader(getter_AddRefs(loader), p);
  409. if (NS_WARN_IF(NS_FAILED(rv))) {
  410. return;
  411. }
  412. listener = loader;
  413. }
  414. rv = pump->AsyncRead(listener, nullptr);
  415. if (NS_WARN_IF(NS_FAILED(rv))) {
  416. return;
  417. }
  418. // Now that everything succeeded, we can assign the pump to a pointer that
  419. // stays alive for the lifetime of the FetchConsumer.
  420. mConsumeBodyPump = pump;
  421. // It is ok for retargeting to fail and reads to happen on the main thread.
  422. autoReject.DontFail();
  423. // Try to retarget, otherwise fall back to main thread.
  424. nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump);
  425. if (rr) {
  426. nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
  427. rv = rr->RetargetDeliveryTo(sts);
  428. if (NS_WARN_IF(NS_FAILED(rv))) {
  429. NS_WARNING("Retargeting failed");
  430. }
  431. }
  432. }
  433. template <class Derived>
  434. void
  435. FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus,
  436. uint32_t aResultLength,
  437. uint8_t* aResult)
  438. {
  439. AssertIsOnTargetThread();
  440. if (mBodyConsumed) {
  441. return;
  442. }
  443. mBodyConsumed = true;
  444. // Just a precaution to ensure ContinueConsumeBody is not called out of
  445. // sync with a body read.
  446. MOZ_ASSERT(mBody->BodyUsed());
  447. auto autoFree = mozilla::MakeScopeExit([&] {
  448. free(aResult);
  449. });
  450. MOZ_ASSERT(mConsumePromise);
  451. RefPtr<Promise> localPromise = mConsumePromise.forget();
  452. RefPtr<FetchBodyConsumer<Derived>> self = this;
  453. auto autoReleaseObject = mozilla::MakeScopeExit([&] {
  454. self->ReleaseObject();
  455. });
  456. if (NS_WARN_IF(NS_FAILED(aStatus))) {
  457. localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
  458. }
  459. // Don't warn here since we warned above.
  460. if (NS_FAILED(aStatus)) {
  461. return;
  462. }
  463. // Finish successfully consuming body according to type.
  464. MOZ_ASSERT(aResult);
  465. AutoJSAPI jsapi;
  466. if (!jsapi.Init(mGlobal)) {
  467. localPromise->MaybeReject(NS_ERROR_UNEXPECTED);
  468. return;
  469. }
  470. JSContext* cx = jsapi.cx();
  471. ErrorResult error;
  472. switch (mConsumeType) {
  473. case CONSUME_ARRAYBUFFER: {
  474. JS::Rooted<JSObject*> arrayBuffer(cx);
  475. BodyUtil::ConsumeArrayBuffer(cx, &arrayBuffer, aResultLength, aResult,
  476. error);
  477. if (!error.Failed()) {
  478. JS::Rooted<JS::Value> val(cx);
  479. val.setObjectOrNull(arrayBuffer);
  480. localPromise->MaybeResolve(cx, val);
  481. // ArrayBuffer takes over ownership.
  482. aResult = nullptr;
  483. }
  484. break;
  485. }
  486. case CONSUME_BLOB: {
  487. MOZ_CRASH("This should not happen.");
  488. break;
  489. }
  490. case CONSUME_FORMDATA: {
  491. nsCString data;
  492. data.Adopt(reinterpret_cast<char*>(aResult), aResultLength);
  493. aResult = nullptr;
  494. RefPtr<dom::FormData> fd =
  495. BodyUtil::ConsumeFormData(mGlobal, mBodyMimeType, data, error);
  496. if (!error.Failed()) {
  497. localPromise->MaybeResolve(fd);
  498. }
  499. break;
  500. }
  501. case CONSUME_TEXT:
  502. // fall through handles early exit.
  503. case CONSUME_JSON: {
  504. nsString decoded;
  505. if (NS_SUCCEEDED(BodyUtil::ConsumeText(aResultLength, aResult, decoded))) {
  506. if (mConsumeType == CONSUME_TEXT) {
  507. localPromise->MaybeResolve(decoded);
  508. } else {
  509. JS::Rooted<JS::Value> json(cx);
  510. BodyUtil::ConsumeJson(cx, &json, decoded, error);
  511. if (!error.Failed()) {
  512. localPromise->MaybeResolve(cx, json);
  513. }
  514. }
  515. };
  516. break;
  517. }
  518. default:
  519. NS_NOTREACHED("Unexpected consume body type");
  520. }
  521. error.WouldReportJSException();
  522. if (error.Failed()) {
  523. localPromise->MaybeReject(error);
  524. }
  525. }
  526. template <class Derived>
  527. void
  528. FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl)
  529. {
  530. AssertIsOnTargetThread();
  531. MOZ_ASSERT(mConsumeType == CONSUME_BLOB);
  532. if (mBodyConsumed) {
  533. return;
  534. }
  535. mBodyConsumed = true;
  536. // Just a precaution to ensure ContinueConsumeBody is not called out of
  537. // sync with a body read.
  538. MOZ_ASSERT(mBody->BodyUsed());
  539. MOZ_ASSERT(mConsumePromise);
  540. RefPtr<Promise> localPromise = mConsumePromise.forget();
  541. RefPtr<dom::Blob> blob = dom::Blob::Create(mGlobal, aBlobImpl);
  542. MOZ_ASSERT(blob);
  543. localPromise->MaybeResolve(blob);
  544. ReleaseObject();
  545. }
  546. template <class Derived>
  547. void
  548. FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming()
  549. {
  550. if (!NS_IsMainThread()) {
  551. RefPtr<FetchBodyConsumer<Derived>> self = this;
  552. nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
  553. [self] () { self->ShutDownMainThreadConsuming(); });
  554. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r.forget()));
  555. return;
  556. }
  557. // We need this because maybe, mConsumeBodyPump has not been created yet. We
  558. // must be sure that we don't try to do it.
  559. mShuttingDown = true;
  560. if (mConsumeBodyPump) {
  561. mConsumeBodyPump->Cancel(NS_BINDING_ABORTED);
  562. mConsumeBodyPump = nullptr;
  563. }
  564. }
  565. template <class Derived>
  566. NS_IMETHODIMP
  567. FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject,
  568. const char* aTopic,
  569. const char16_t* aData)
  570. {
  571. AssertIsOnMainThread();
  572. MOZ_ASSERT((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) ||
  573. (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0));
  574. nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal);
  575. if (SameCOMIdentity(aSubject, window)) {
  576. ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr);
  577. }
  578. return NS_OK;
  579. }
  580. template <class Derived>
  581. void
  582. FetchBodyConsumer<Derived>::Aborted()
  583. {
  584. AssertIsOnTargetThread();
  585. ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr);
  586. }
  587. template <class Derived>
  588. NS_IMPL_ADDREF(FetchBodyConsumer<Derived>)
  589. template <class Derived>
  590. NS_IMPL_RELEASE(FetchBodyConsumer<Derived>)
  591. template <class Derived>
  592. NS_IMPL_QUERY_INTERFACE(FetchBodyConsumer<Derived>,
  593. nsIObserver,
  594. nsISupportsWeakReference)
  595. } // namespace dom
  596. } // namespace mozilla