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