Cache.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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 "mozilla/dom/cache/Cache.h"
  6. #include "mozilla/dom/Headers.h"
  7. #include "mozilla/dom/InternalResponse.h"
  8. #include "mozilla/dom/Promise.h"
  9. #include "mozilla/dom/PromiseNativeHandler.h"
  10. #include "mozilla/dom/Response.h"
  11. #include "mozilla/dom/WorkerPrivate.h"
  12. #include "mozilla/dom/CacheBinding.h"
  13. #include "mozilla/dom/cache/AutoUtils.h"
  14. #include "mozilla/dom/cache/CacheChild.h"
  15. #include "mozilla/dom/cache/CacheWorkerHolder.h"
  16. #include "mozilla/dom/cache/ReadStream.h"
  17. #include "mozilla/ErrorResult.h"
  18. #include "mozilla/Preferences.h"
  19. #include "mozilla/Unused.h"
  20. #include "nsIGlobalObject.h"
  21. namespace mozilla {
  22. namespace dom {
  23. namespace cache {
  24. using mozilla::dom::workers::GetCurrentThreadWorkerPrivate;
  25. using mozilla::dom::workers::WorkerPrivate;
  26. using mozilla::ipc::PBackgroundChild;
  27. namespace {
  28. bool
  29. IsValidPutRequestURL(const nsAString& aUrl, ErrorResult& aRv)
  30. {
  31. bool validScheme = false;
  32. // make a copy because ProcessURL strips the fragmet
  33. NS_ConvertUTF16toUTF8 url(aUrl);
  34. TypeUtils::ProcessURL(url, &validScheme, nullptr, nullptr, aRv);
  35. if (aRv.Failed()) {
  36. return false;
  37. }
  38. if (!validScheme) {
  39. aRv.ThrowTypeError<MSG_INVALID_URL_SCHEME>(NS_LITERAL_STRING("Request"),
  40. aUrl);
  41. return false;
  42. }
  43. return true;
  44. }
  45. static bool
  46. IsValidPutRequestMethod(const Request& aRequest, ErrorResult& aRv)
  47. {
  48. nsAutoCString method;
  49. aRequest.GetMethod(method);
  50. if (!method.LowerCaseEqualsLiteral("get")) {
  51. NS_ConvertASCIItoUTF16 label(method);
  52. aRv.ThrowTypeError<MSG_INVALID_REQUEST_METHOD>(label);
  53. return false;
  54. }
  55. return true;
  56. }
  57. static bool
  58. IsValidPutRequestMethod(const RequestOrUSVString& aRequest, ErrorResult& aRv)
  59. {
  60. // If the provided request is a string URL, then it will default to
  61. // a valid http method automatically.
  62. if (!aRequest.IsRequest()) {
  63. return true;
  64. }
  65. return IsValidPutRequestMethod(aRequest.GetAsRequest(), aRv);
  66. }
  67. } // namespace
  68. // Helper class to wait for Add()/AddAll() fetch requests to complete and
  69. // then perform a PutAll() with the responses. This class holds a WorkerHolder
  70. // to keep the Worker thread alive. This is mainly to ensure that Add/AddAll
  71. // act the same as other Cache operations that directly create a CacheOpChild
  72. // actor.
  73. class Cache::FetchHandler final : public PromiseNativeHandler
  74. {
  75. public:
  76. FetchHandler(CacheWorkerHolder* aWorkerHolder, Cache* aCache,
  77. nsTArray<RefPtr<Request>>&& aRequestList, Promise* aPromise)
  78. : mWorkerHolder(aWorkerHolder)
  79. , mCache(aCache)
  80. , mRequestList(Move(aRequestList))
  81. , mPromise(aPromise)
  82. {
  83. MOZ_ASSERT_IF(!NS_IsMainThread(), mWorkerHolder);
  84. MOZ_DIAGNOSTIC_ASSERT(mCache);
  85. MOZ_DIAGNOSTIC_ASSERT(mPromise);
  86. }
  87. virtual void
  88. ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  89. {
  90. NS_ASSERT_OWNINGTHREAD(FetchHandler);
  91. // Stop holding the worker alive when we leave this method.
  92. RefPtr<CacheWorkerHolder> workerHolder;
  93. workerHolder.swap(mWorkerHolder);
  94. // Promise::All() passed an array of fetch() Promises should give us
  95. // an Array of Response objects. The following code unwraps these
  96. // JS values back to an nsTArray<RefPtr<Response>>.
  97. AutoTArray<RefPtr<Response>, 256> responseList;
  98. responseList.SetCapacity(mRequestList.Length());
  99. bool isArray;
  100. if (NS_WARN_IF(!JS_IsArrayObject(aCx, aValue, &isArray) || !isArray)) {
  101. Fail();
  102. return;
  103. }
  104. JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
  105. uint32_t length;
  106. if (NS_WARN_IF(!JS_GetArrayLength(aCx, obj, &length))) {
  107. Fail();
  108. return;
  109. }
  110. for (uint32_t i = 0; i < length; ++i) {
  111. JS::Rooted<JS::Value> value(aCx);
  112. if (NS_WARN_IF(!JS_GetElement(aCx, obj, i, &value))) {
  113. Fail();
  114. return;
  115. }
  116. if (NS_WARN_IF(!value.isObject())) {
  117. Fail();
  118. return;
  119. }
  120. JS::Rooted<JSObject*> responseObj(aCx, &value.toObject());
  121. RefPtr<Response> response;
  122. nsresult rv = UNWRAP_OBJECT(Response, responseObj, response);
  123. if (NS_WARN_IF(NS_FAILED(rv))) {
  124. Fail();
  125. return;
  126. }
  127. if (NS_WARN_IF(response->Type() == ResponseType::Error)) {
  128. Fail();
  129. return;
  130. }
  131. // Do not allow the convenience methods .add()/.addAll() to store failed
  132. // responses. A consequence of this is that these methods cannot be
  133. // used to store opaque or opaqueredirect responses since they always
  134. // expose a 0 status value.
  135. if (!response->Ok()) {
  136. uint32_t t = static_cast<uint32_t>(response->Type());
  137. NS_ConvertASCIItoUTF16 type(ResponseTypeValues::strings[t].value,
  138. ResponseTypeValues::strings[t].length);
  139. nsAutoString status;
  140. status.AppendInt(response->Status());
  141. nsAutoString url;
  142. mRequestList[i]->GetUrl(url);
  143. ErrorResult rv;
  144. rv.ThrowTypeError<MSG_CACHE_ADD_FAILED_RESPONSE>(type, status, url);
  145. // TODO: abort the fetch requests we have running (bug 1157434)
  146. mPromise->MaybeReject(rv);
  147. return;
  148. }
  149. responseList.AppendElement(Move(response));
  150. }
  151. MOZ_DIAGNOSTIC_ASSERT(mRequestList.Length() == responseList.Length());
  152. // Now store the unwrapped Response list in the Cache.
  153. ErrorResult result;
  154. RefPtr<Promise> put = mCache->PutAll(mRequestList, responseList, result);
  155. if (NS_WARN_IF(result.Failed())) {
  156. // TODO: abort the fetch requests we have running (bug 1157434)
  157. mPromise->MaybeReject(result);
  158. return;
  159. }
  160. // Chain the Cache::Put() promise to the original promise returned to
  161. // the content script.
  162. mPromise->MaybeResolve(put);
  163. }
  164. virtual void
  165. RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override
  166. {
  167. NS_ASSERT_OWNINGTHREAD(FetchHandler);
  168. Fail();
  169. }
  170. private:
  171. ~FetchHandler()
  172. {
  173. }
  174. void
  175. Fail()
  176. {
  177. ErrorResult rv;
  178. rv.ThrowTypeError<MSG_FETCH_FAILED>();
  179. mPromise->MaybeReject(rv);
  180. }
  181. RefPtr<CacheWorkerHolder> mWorkerHolder;
  182. RefPtr<Cache> mCache;
  183. nsTArray<RefPtr<Request>> mRequestList;
  184. RefPtr<Promise> mPromise;
  185. NS_DECL_ISUPPORTS
  186. };
  187. NS_IMPL_ISUPPORTS0(Cache::FetchHandler)
  188. NS_IMPL_CYCLE_COLLECTING_ADDREF(mozilla::dom::cache::Cache);
  189. NS_IMPL_CYCLE_COLLECTING_RELEASE(mozilla::dom::cache::Cache);
  190. NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(mozilla::dom::cache::Cache, mGlobal);
  191. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Cache)
  192. NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  193. NS_INTERFACE_MAP_ENTRY(nsISupports)
  194. NS_INTERFACE_MAP_END
  195. Cache::Cache(nsIGlobalObject* aGlobal, CacheChild* aActor)
  196. : mGlobal(aGlobal)
  197. , mActor(aActor)
  198. {
  199. MOZ_DIAGNOSTIC_ASSERT(mGlobal);
  200. MOZ_DIAGNOSTIC_ASSERT(mActor);
  201. mActor->SetListener(this);
  202. }
  203. already_AddRefed<Promise>
  204. Cache::Match(const RequestOrUSVString& aRequest,
  205. const CacheQueryOptions& aOptions, ErrorResult& aRv)
  206. {
  207. if (NS_WARN_IF(!mActor)) {
  208. aRv.Throw(NS_ERROR_UNEXPECTED);
  209. return nullptr;
  210. }
  211. CacheChild::AutoLock actorLock(mActor);
  212. RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
  213. if (NS_WARN_IF(aRv.Failed())) {
  214. return nullptr;
  215. }
  216. CacheQueryParams params;
  217. ToCacheQueryParams(params, aOptions);
  218. AutoChildOpArgs args(this, CacheMatchArgs(CacheRequest(), params), 1);
  219. args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
  220. if (NS_WARN_IF(aRv.Failed())) {
  221. return nullptr;
  222. }
  223. return ExecuteOp(args, aRv);
  224. }
  225. already_AddRefed<Promise>
  226. Cache::MatchAll(const Optional<RequestOrUSVString>& aRequest,
  227. const CacheQueryOptions& aOptions, ErrorResult& aRv)
  228. {
  229. if (NS_WARN_IF(!mActor)) {
  230. aRv.Throw(NS_ERROR_UNEXPECTED);
  231. return nullptr;
  232. }
  233. CacheChild::AutoLock actorLock(mActor);
  234. CacheQueryParams params;
  235. ToCacheQueryParams(params, aOptions);
  236. AutoChildOpArgs args(this, CacheMatchAllArgs(void_t(), params), 1);
  237. if (aRequest.WasPassed()) {
  238. RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
  239. IgnoreBody, aRv);
  240. if (aRv.Failed()) {
  241. return nullptr;
  242. }
  243. args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
  244. if (aRv.Failed()) {
  245. return nullptr;
  246. }
  247. }
  248. return ExecuteOp(args, aRv);
  249. }
  250. already_AddRefed<Promise>
  251. Cache::Add(JSContext* aContext, const RequestOrUSVString& aRequest,
  252. ErrorResult& aRv)
  253. {
  254. if (NS_WARN_IF(!mActor)) {
  255. aRv.Throw(NS_ERROR_UNEXPECTED);
  256. return nullptr;
  257. }
  258. CacheChild::AutoLock actorLock(mActor);
  259. if (!IsValidPutRequestMethod(aRequest, aRv)) {
  260. return nullptr;
  261. }
  262. GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
  263. MOZ_DIAGNOSTIC_ASSERT(!global.Failed());
  264. nsTArray<RefPtr<Request>> requestList(1);
  265. RefPtr<Request> request = Request::Constructor(global, aRequest,
  266. RequestInit(), aRv);
  267. if (NS_WARN_IF(aRv.Failed())) {
  268. return nullptr;
  269. }
  270. nsAutoString url;
  271. request->GetUrl(url);
  272. if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
  273. return nullptr;
  274. }
  275. requestList.AppendElement(Move(request));
  276. return AddAll(global, Move(requestList), aRv);
  277. }
  278. already_AddRefed<Promise>
  279. Cache::AddAll(JSContext* aContext,
  280. const Sequence<OwningRequestOrUSVString>& aRequestList,
  281. ErrorResult& aRv)
  282. {
  283. if (NS_WARN_IF(!mActor)) {
  284. aRv.Throw(NS_ERROR_UNEXPECTED);
  285. return nullptr;
  286. }
  287. CacheChild::AutoLock actorLock(mActor);
  288. GlobalObject global(aContext, mGlobal->GetGlobalJSObject());
  289. MOZ_DIAGNOSTIC_ASSERT(!global.Failed());
  290. nsTArray<RefPtr<Request>> requestList(aRequestList.Length());
  291. for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
  292. RequestOrUSVString requestOrString;
  293. if (aRequestList[i].IsRequest()) {
  294. requestOrString.SetAsRequest() = aRequestList[i].GetAsRequest();
  295. if (NS_WARN_IF(!IsValidPutRequestMethod(requestOrString.GetAsRequest(),
  296. aRv))) {
  297. return nullptr;
  298. }
  299. } else {
  300. requestOrString.SetAsUSVString().Rebind(
  301. aRequestList[i].GetAsUSVString().Data(),
  302. aRequestList[i].GetAsUSVString().Length());
  303. }
  304. RefPtr<Request> request = Request::Constructor(global, requestOrString,
  305. RequestInit(), aRv);
  306. if (NS_WARN_IF(aRv.Failed())) {
  307. return nullptr;
  308. }
  309. nsAutoString url;
  310. request->GetUrl(url);
  311. if (NS_WARN_IF(!IsValidPutRequestURL(url, aRv))) {
  312. return nullptr;
  313. }
  314. requestList.AppendElement(Move(request));
  315. }
  316. return AddAll(global, Move(requestList), aRv);
  317. }
  318. already_AddRefed<Promise>
  319. Cache::Put(const RequestOrUSVString& aRequest, Response& aResponse,
  320. ErrorResult& aRv)
  321. {
  322. if (NS_WARN_IF(!mActor)) {
  323. aRv.Throw(NS_ERROR_UNEXPECTED);
  324. return nullptr;
  325. }
  326. CacheChild::AutoLock actorLock(mActor);
  327. if (NS_WARN_IF(!IsValidPutRequestMethod(aRequest, aRv))) {
  328. return nullptr;
  329. }
  330. RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, ReadBody, aRv);
  331. if (NS_WARN_IF(aRv.Failed())) {
  332. return nullptr;
  333. }
  334. AutoChildOpArgs args(this, CachePutAllArgs(), 1);
  335. args.Add(ir, ReadBody, TypeErrorOnInvalidScheme,
  336. aResponse, aRv);
  337. if (NS_WARN_IF(aRv.Failed())) {
  338. return nullptr;
  339. }
  340. return ExecuteOp(args, aRv);
  341. }
  342. already_AddRefed<Promise>
  343. Cache::Delete(const RequestOrUSVString& aRequest,
  344. const CacheQueryOptions& aOptions, ErrorResult& aRv)
  345. {
  346. if (NS_WARN_IF(!mActor)) {
  347. aRv.Throw(NS_ERROR_UNEXPECTED);
  348. return nullptr;
  349. }
  350. CacheChild::AutoLock actorLock(mActor);
  351. RefPtr<InternalRequest> ir = ToInternalRequest(aRequest, IgnoreBody, aRv);
  352. if (NS_WARN_IF(aRv.Failed())) {
  353. return nullptr;
  354. }
  355. CacheQueryParams params;
  356. ToCacheQueryParams(params, aOptions);
  357. AutoChildOpArgs args(this, CacheDeleteArgs(CacheRequest(), params), 1);
  358. args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
  359. if (NS_WARN_IF(aRv.Failed())) {
  360. return nullptr;
  361. }
  362. return ExecuteOp(args, aRv);
  363. }
  364. already_AddRefed<Promise>
  365. Cache::Keys(const Optional<RequestOrUSVString>& aRequest,
  366. const CacheQueryOptions& aOptions, ErrorResult& aRv)
  367. {
  368. if (NS_WARN_IF(!mActor)) {
  369. aRv.Throw(NS_ERROR_UNEXPECTED);
  370. return nullptr;
  371. }
  372. CacheChild::AutoLock actorLock(mActor);
  373. CacheQueryParams params;
  374. ToCacheQueryParams(params, aOptions);
  375. AutoChildOpArgs args(this, CacheKeysArgs(void_t(), params), 1);
  376. if (aRequest.WasPassed()) {
  377. RefPtr<InternalRequest> ir = ToInternalRequest(aRequest.Value(),
  378. IgnoreBody, aRv);
  379. if (NS_WARN_IF(aRv.Failed())) {
  380. return nullptr;
  381. }
  382. args.Add(ir, IgnoreBody, IgnoreInvalidScheme, aRv);
  383. if (NS_WARN_IF(aRv.Failed())) {
  384. return nullptr;
  385. }
  386. }
  387. return ExecuteOp(args, aRv);
  388. }
  389. // static
  390. bool
  391. Cache::PrefEnabled(JSContext* aCx, JSObject* aObj)
  392. {
  393. using mozilla::dom::workers::WorkerPrivate;
  394. using mozilla::dom::workers::GetWorkerPrivateFromContext;
  395. // If we're on the main thread, then check the pref directly.
  396. if (NS_IsMainThread()) {
  397. bool enabled = false;
  398. Preferences::GetBool("dom.caches.enabled", &enabled);
  399. return enabled;
  400. }
  401. // Otherwise check the pref via the work private helper
  402. WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
  403. if (!workerPrivate) {
  404. return false;
  405. }
  406. return workerPrivate->DOMCachesEnabled();
  407. }
  408. nsISupports*
  409. Cache::GetParentObject() const
  410. {
  411. return mGlobal;
  412. }
  413. JSObject*
  414. Cache::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aGivenProto)
  415. {
  416. return CacheBinding::Wrap(aContext, this, aGivenProto);
  417. }
  418. void
  419. Cache::DestroyInternal(CacheChild* aActor)
  420. {
  421. MOZ_DIAGNOSTIC_ASSERT(mActor);
  422. MOZ_DIAGNOSTIC_ASSERT(mActor == aActor);
  423. mActor->ClearListener();
  424. mActor = nullptr;
  425. }
  426. nsIGlobalObject*
  427. Cache::GetGlobalObject() const
  428. {
  429. return mGlobal;
  430. }
  431. #ifdef DEBUG
  432. void
  433. Cache::AssertOwningThread() const
  434. {
  435. NS_ASSERT_OWNINGTHREAD(Cache);
  436. }
  437. #endif
  438. PBackgroundChild*
  439. Cache::GetIPCManager()
  440. {
  441. NS_ASSERT_OWNINGTHREAD(Cache);
  442. MOZ_DIAGNOSTIC_ASSERT(mActor);
  443. return mActor->Manager();
  444. }
  445. Cache::~Cache()
  446. {
  447. NS_ASSERT_OWNINGTHREAD(Cache);
  448. if (mActor) {
  449. mActor->StartDestroyFromListener();
  450. // DestroyInternal() is called synchronously by StartDestroyFromListener().
  451. // So we should have already cleared the mActor.
  452. MOZ_DIAGNOSTIC_ASSERT(!mActor);
  453. }
  454. }
  455. already_AddRefed<Promise>
  456. Cache::ExecuteOp(AutoChildOpArgs& aOpArgs, ErrorResult& aRv)
  457. {
  458. MOZ_DIAGNOSTIC_ASSERT(mActor);
  459. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  460. if (NS_WARN_IF(!promise)) {
  461. return nullptr;
  462. }
  463. mActor->ExecuteOp(mGlobal, promise, this, aOpArgs.SendAsOpArgs());
  464. return promise.forget();
  465. }
  466. already_AddRefed<Promise>
  467. Cache::AddAll(const GlobalObject& aGlobal,
  468. nsTArray<RefPtr<Request>>&& aRequestList, ErrorResult& aRv)
  469. {
  470. MOZ_DIAGNOSTIC_ASSERT(mActor);
  471. // If there is no work to do, then resolve immediately
  472. if (aRequestList.IsEmpty()) {
  473. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  474. if (NS_WARN_IF(!promise)) {
  475. return nullptr;
  476. }
  477. promise->MaybeResolveWithUndefined();
  478. return promise.forget();
  479. }
  480. AutoTArray<RefPtr<Promise>, 256> fetchList;
  481. fetchList.SetCapacity(aRequestList.Length());
  482. // Begin fetching each request in parallel. For now, if an error occurs just
  483. // abandon our previous fetch calls. In theory we could cancel them in the
  484. // future once fetch supports it.
  485. for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
  486. RequestOrUSVString requestOrString;
  487. requestOrString.SetAsRequest() = aRequestList[i];
  488. RefPtr<Promise> fetch = FetchRequest(mGlobal, requestOrString,
  489. RequestInit(), aRv);
  490. if (NS_WARN_IF(aRv.Failed())) {
  491. return nullptr;
  492. }
  493. fetchList.AppendElement(Move(fetch));
  494. }
  495. RefPtr<Promise> promise = Promise::Create(mGlobal, aRv);
  496. if (NS_WARN_IF(aRv.Failed())) {
  497. return nullptr;
  498. }
  499. RefPtr<FetchHandler> handler =
  500. new FetchHandler(mActor->GetWorkerHolder(), this,
  501. Move(aRequestList), promise);
  502. RefPtr<Promise> fetchPromise = Promise::All(aGlobal.Context(), fetchList, aRv);
  503. if (NS_WARN_IF(aRv.Failed())) {
  504. return nullptr;
  505. }
  506. fetchPromise->AppendNativeHandler(handler);
  507. return promise.forget();
  508. }
  509. already_AddRefed<Promise>
  510. Cache::PutAll(const nsTArray<RefPtr<Request>>& aRequestList,
  511. const nsTArray<RefPtr<Response>>& aResponseList,
  512. ErrorResult& aRv)
  513. {
  514. MOZ_DIAGNOSTIC_ASSERT(aRequestList.Length() == aResponseList.Length());
  515. if (NS_WARN_IF(!mActor)) {
  516. aRv.Throw(NS_ERROR_UNEXPECTED);
  517. return nullptr;
  518. }
  519. CacheChild::AutoLock actorLock(mActor);
  520. AutoChildOpArgs args(this, CachePutAllArgs(), aRequestList.Length());
  521. for (uint32_t i = 0; i < aRequestList.Length(); ++i) {
  522. RefPtr<InternalRequest> ir = aRequestList[i]->GetInternalRequest();
  523. args.Add(ir, ReadBody, TypeErrorOnInvalidScheme, *aResponseList[i], aRv);
  524. if (NS_WARN_IF(aRv.Failed())) {
  525. return nullptr;
  526. }
  527. }
  528. return ExecuteOp(args, aRv);
  529. }
  530. } // namespace cache
  531. } // namespace dom
  532. } // namespace mozilla