Coverage Report

Created: 2018-09-25 14:53

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