Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/cache/ReadStream.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/ReadStream.h"
8
9
#include "mozilla/Unused.h"
10
#include "mozilla/dom/cache/CacheStreamControlChild.h"
11
#include "mozilla/dom/cache/CacheStreamControlParent.h"
12
#include "mozilla/dom/cache/CacheTypes.h"
13
#include "mozilla/ipc/IPCStreamUtils.h"
14
#include "mozilla/SnappyUncompressInputStream.h"
15
#include "nsIAsyncInputStream.h"
16
#include "nsStringStream.h"
17
#include "nsTArray.h"
18
19
namespace mozilla {
20
namespace dom {
21
namespace cache {
22
23
using mozilla::Unused;
24
using mozilla::ipc::AutoIPCStream;
25
using mozilla::ipc::IPCStream;
26
using mozilla::ipc::OptionalIPCStream;
27
28
// ----------------------------------------------------------------------------
29
30
// The inner stream class.  This is where all of the real work is done.  As
31
// an invariant Inner::Close() must be called before ~Inner().  This is
32
// guaranteed by our outer ReadStream class.
33
class ReadStream::Inner final : public ReadStream::Controllable
34
{
35
public:
36
  Inner(StreamControl* aControl, const nsID& aId,
37
        nsIInputStream* aStream);
38
39
  void
40
  Serialize(CacheReadStreamOrVoid* aReadStreamOut,
41
            nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
42
            ErrorResult& aRv);
43
44
  void
45
  Serialize(CacheReadStream* aReadStreamOut,
46
            nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
47
            ErrorResult& aRv);
48
49
  // ReadStream::Controllable methods
50
  virtual void
51
  CloseStream() override;
52
53
  virtual void
54
  CloseStreamWithoutReporting() override;
55
56
  virtual bool
57
  MatchId(const nsID& aId) const override;
58
59
  virtual bool
60
  HasEverBeenRead() const override;
61
62
  // Simulate nsIInputStream methods, but we don't actually inherit from it
63
  nsresult
64
  Close();
65
66
  nsresult
67
  Available(uint64_t *aNumAvailableOut);
68
69
  nsresult
70
  Read(char *aBuf, uint32_t aCount, uint32_t *aNumReadOut);
71
72
  nsresult
73
  ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount,
74
               uint32_t *aNumReadOut);
75
76
  nsresult
77
  IsNonBlocking(bool *aNonBlockingOut);
78
79
private:
80
  class NoteClosedRunnable;
81
  class ForgetRunnable;
82
83
  ~Inner();
84
85
  void
86
  NoteClosed();
87
88
  void
89
  Forget();
90
91
  void
92
  NoteClosedOnOwningThread();
93
94
  void
95
  ForgetOnOwningThread();
96
97
  nsIInputStream*
98
  EnsureStream();
99
100
  void
101
  AsyncOpenStreamOnOwningThread();
102
103
  void
104
  MaybeAbortAsyncOpenStream();
105
106
  void
107
  OpenStreamFailed();
108
109
  // Weak ref to the stream control actor.  The actor will always call either
110
  // CloseStream() or CloseStreamWithoutReporting() before it's destroyed.  The
111
  // weak ref is cleared in the resulting NoteClosedOnOwningThread() or
112
  // ForgetOnOwningThread() method call.
113
  StreamControl* mControl;
114
115
  const nsID mId;
116
  nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
117
118
  enum State
119
  {
120
    Open,
121
    Closed,
122
    NumStates
123
  };
124
  Atomic<State> mState;
125
  Atomic<bool> mHasEverBeenRead;
126
  bool mAsyncOpenStarted;
127
128
  // The wrapped stream objects may not be threadsafe.  We need to be able
129
  // to close a stream on our owning thread while an IO thread is simultaneously
130
  // reading the same stream.  Therefore, protect all access to these stream
131
  // objects with a mutex.
132
  Mutex mMutex;
133
  CondVar mCondVar;
134
  nsCOMPtr<nsIInputStream> mStream;
135
  nsCOMPtr<nsIInputStream> mSnappyStream;
136
137
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(cache::ReadStream::Inner, override)
138
};
139
140
// ----------------------------------------------------------------------------
141
142
// Runnable to notify actors that the ReadStream has closed.  This must
143
// be done on the thread associated with the PBackground actor.  Must be
144
// cancelable to execute on Worker threads (which can occur when the
145
// ReadStream is constructed on a child process Worker thread).
146
class ReadStream::Inner::NoteClosedRunnable final : public CancelableRunnable
147
{
148
public:
149
  explicit NoteClosedRunnable(ReadStream::Inner* aStream)
150
    : CancelableRunnable("dom::cache::ReadStream::Inner::NoteClosedRunnable")
151
    , mStream(aStream)
152
0
  { }
153
154
  NS_IMETHOD Run() override
155
0
  {
156
0
    mStream->NoteClosedOnOwningThread();
157
0
    mStream = nullptr;
158
0
    return NS_OK;
159
0
  }
160
161
  // Note, we must proceed with the Run() method since our actor will not
162
  // clean itself up until we note that the stream is closed.
163
  nsresult Cancel() override
164
0
  {
165
0
    Run();
166
0
    return NS_OK;
167
0
  }
168
169
private:
170
0
  ~NoteClosedRunnable() { }
171
172
  RefPtr<ReadStream::Inner> mStream;
173
};
174
175
// ----------------------------------------------------------------------------
176
177
// Runnable to clear actors without reporting that the ReadStream has
178
// closed.  Since this can trigger actor destruction, we need to do
179
// it on the thread associated with the PBackground actor.  Must be
180
// cancelable to execute on Worker threads (which can occur when the
181
// ReadStream is constructed on a child process Worker thread).
182
class ReadStream::Inner::ForgetRunnable final : public CancelableRunnable
183
{
184
public:
185
  explicit ForgetRunnable(ReadStream::Inner* aStream)
186
    : CancelableRunnable("dom::cache::ReadStream::Inner::ForgetRunnable")
187
    , mStream(aStream)
188
0
  { }
189
190
  NS_IMETHOD Run() override
191
0
  {
192
0
    mStream->ForgetOnOwningThread();
193
0
    mStream = nullptr;
194
0
    return NS_OK;
195
0
  }
196
197
  // Note, we must proceed with the Run() method so that we properly
198
  // call RemoveListener on the actor.
199
  nsresult Cancel() override
200
0
  {
201
0
    Run();
202
0
    return NS_OK;
203
0
  }
204
205
private:
206
0
  ~ForgetRunnable() { }
207
208
  RefPtr<ReadStream::Inner> mStream;
209
};
210
211
// ----------------------------------------------------------------------------
212
213
ReadStream::Inner::Inner(StreamControl* aControl, const nsID& aId,
214
                         nsIInputStream* aStream)
215
  : mControl(aControl)
216
  , mId(aId)
217
  , mOwningEventTarget(GetCurrentThreadSerialEventTarget())
218
  , mState(Open)
219
  , mHasEverBeenRead(false)
220
  , mAsyncOpenStarted(false)
221
  , mMutex("dom::cache::ReadStream")
222
  , mCondVar(mMutex, "dom::cache::ReadStream")
223
  , mStream(aStream)
224
  , mSnappyStream(aStream ? new SnappyUncompressInputStream(aStream) : nullptr)
225
0
{
226
0
  MOZ_DIAGNOSTIC_ASSERT(mControl);
227
0
  mControl->AddReadStream(this);
228
0
}
229
230
void
231
ReadStream::Inner::Serialize(CacheReadStreamOrVoid* aReadStreamOut,
232
                             nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
233
                             ErrorResult& aRv)
234
0
{
235
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
236
0
  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
237
0
  *aReadStreamOut = CacheReadStream();
238
0
  Serialize(&aReadStreamOut->get_CacheReadStream(), aStreamCleanupList, aRv);
239
0
}
240
241
void
242
ReadStream::Inner::Serialize(CacheReadStream* aReadStreamOut,
243
                             nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
244
                             ErrorResult& aRv)
245
0
{
246
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
247
0
  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
248
0
249
0
  if (mState != Open) {
250
0
    aRv.ThrowTypeError<MSG_CACHE_STREAM_CLOSED>();
251
0
    return;
252
0
  }
253
0
254
0
  MOZ_DIAGNOSTIC_ASSERT(mControl);
255
0
256
0
  aReadStreamOut->id() = mId;
257
0
  mControl->SerializeControl(aReadStreamOut);
258
0
259
0
  {
260
0
    MutexAutoLock lock(mMutex);
261
0
    mControl->SerializeStream(aReadStreamOut, mStream, aStreamCleanupList);
262
0
  }
263
0
264
0
  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut->stream().type() == OptionalIPCStream::Tvoid_t ||
265
0
                        aReadStreamOut->stream().get_IPCStream().type() ==
266
0
                        IPCStream::TInputStreamParamsWithFds);
267
0
268
0
  // We're passing ownership across the IPC barrier with the control, so
269
0
  // do not signal that the stream is closed here.
270
0
  Forget();
271
0
}
272
273
void
274
ReadStream::Inner::CloseStream()
275
0
{
276
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
277
0
  Close();
278
0
}
279
280
void
281
ReadStream::Inner::CloseStreamWithoutReporting()
282
0
{
283
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
284
0
  Forget();
285
0
}
286
287
bool
288
ReadStream::Inner::MatchId(const nsID& aId) const
289
0
{
290
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
291
0
  return mId.Equals(aId);
292
0
}
293
294
bool
295
ReadStream::Inner::HasEverBeenRead() const
296
0
{
297
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
298
0
  return mHasEverBeenRead;
299
0
}
300
301
nsresult
302
ReadStream::Inner::Close()
303
0
{
304
0
  // stream ops can happen on any thread
305
0
  nsresult rv = NS_OK;
306
0
  {
307
0
    MutexAutoLock lock(mMutex);
308
0
    if (mSnappyStream) {
309
0
      rv = mSnappyStream->Close();
310
0
    }
311
0
  }
312
0
  NoteClosed();
313
0
  return rv;
314
0
}
315
316
nsresult
317
ReadStream::Inner::Available(uint64_t* aNumAvailableOut)
318
0
{
319
0
  // stream ops can happen on any thread
320
0
  nsresult rv = NS_OK;
321
0
  {
322
0
    MutexAutoLock lock(mMutex);
323
0
    rv = EnsureStream()->Available(aNumAvailableOut);
324
0
  }
325
0
326
0
  if (NS_FAILED(rv)) {
327
0
    Close();
328
0
  }
329
0
330
0
  return rv;
331
0
}
332
333
nsresult
334
ReadStream::Inner::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
335
0
{
336
0
  // stream ops can happen on any thread
337
0
  MOZ_DIAGNOSTIC_ASSERT(aNumReadOut);
338
0
339
0
  nsresult rv = NS_OK;
340
0
  {
341
0
    MutexAutoLock lock(mMutex);
342
0
    rv = EnsureStream()->Read(aBuf, aCount, aNumReadOut);
343
0
  }
344
0
345
0
  if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) ||
346
0
      *aNumReadOut == 0) {
347
0
    Close();
348
0
  }
349
0
350
0
  mHasEverBeenRead = true;
351
0
352
0
  return rv;
353
0
}
354
355
nsresult
356
ReadStream::Inner::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
357
                                uint32_t aCount, uint32_t* aNumReadOut)
358
0
{
359
0
  // stream ops can happen on any thread
360
0
  MOZ_DIAGNOSTIC_ASSERT(aNumReadOut);
361
0
362
0
  if (aCount) {
363
0
    mHasEverBeenRead = true;
364
0
  }
365
0
366
0
367
0
  nsresult rv = NS_OK;
368
0
  {
369
0
    MutexAutoLock lock(mMutex);
370
0
    rv = EnsureStream()->ReadSegments(aWriter, aClosure, aCount, aNumReadOut);
371
0
  }
372
0
373
0
  if ((NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK &&
374
0
                        rv != NS_ERROR_NOT_IMPLEMENTED) || *aNumReadOut == 0) {
375
0
    Close();
376
0
  }
377
0
378
0
  // Verify bytes were actually read before marking as being ever read.  For
379
0
  // example, code can test if the stream supports ReadSegments() by calling
380
0
  // this method with a dummy callback which doesn't read anything.  We don't
381
0
  // want to trigger on that.
382
0
  if (*aNumReadOut) {
383
0
    mHasEverBeenRead = true;
384
0
  }
385
0
386
0
  return rv;
387
0
}
388
389
nsresult
390
ReadStream::Inner::IsNonBlocking(bool* aNonBlockingOut)
391
0
{
392
0
  // stream ops can happen on any thread
393
0
  MutexAutoLock lock(mMutex);
394
0
  if (mSnappyStream) {
395
0
    return mSnappyStream->IsNonBlocking(aNonBlockingOut);
396
0
  }
397
0
  *aNonBlockingOut = false;
398
0
  return NS_OK;
399
0
}
400
401
ReadStream::Inner::~Inner()
402
0
{
403
0
  // Any thread
404
0
  MOZ_DIAGNOSTIC_ASSERT(mState == Closed);
405
0
  MOZ_DIAGNOSTIC_ASSERT(!mControl);
406
0
}
407
408
void
409
ReadStream::Inner::NoteClosed()
410
0
{
411
0
  // Any thread
412
0
  if (mState == Closed) {
413
0
    return;
414
0
  }
415
0
416
0
  if (mOwningEventTarget->IsOnCurrentThread()) {
417
0
    NoteClosedOnOwningThread();
418
0
    return;
419
0
  }
420
0
421
0
  nsCOMPtr<nsIRunnable> runnable = new NoteClosedRunnable(this);
422
0
  MOZ_ALWAYS_SUCCEEDS(
423
0
    mOwningEventTarget->Dispatch(runnable.forget(), nsIThread::DISPATCH_NORMAL));
424
0
}
425
426
void
427
ReadStream::Inner::Forget()
428
0
{
429
0
  // Any thread
430
0
  if (mState == Closed) {
431
0
    return;
432
0
  }
433
0
434
0
  if (mOwningEventTarget->IsOnCurrentThread()) {
435
0
    ForgetOnOwningThread();
436
0
    return;
437
0
  }
438
0
439
0
  nsCOMPtr<nsIRunnable> runnable = new ForgetRunnable(this);
440
0
  MOZ_ALWAYS_SUCCEEDS(
441
0
    mOwningEventTarget->Dispatch(runnable.forget(), nsIThread::DISPATCH_NORMAL));
442
0
}
443
444
void
445
ReadStream::Inner::NoteClosedOnOwningThread()
446
0
{
447
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
448
0
449
0
  // Mark closed and do nothing if we were already closed
450
0
  if (!mState.compareExchange(Open, Closed)) {
451
0
    return;
452
0
  }
453
0
454
0
  MaybeAbortAsyncOpenStream();
455
0
456
0
  MOZ_DIAGNOSTIC_ASSERT(mControl);
457
0
  mControl->NoteClosed(this, mId);
458
0
  mControl = nullptr;
459
0
}
460
461
void
462
ReadStream::Inner::ForgetOnOwningThread()
463
0
{
464
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
465
0
466
0
  // Mark closed and do nothing if we were already closed
467
0
  if (!mState.compareExchange(Open, Closed)) {
468
0
    return;
469
0
  }
470
0
471
0
  MaybeAbortAsyncOpenStream();
472
0
473
0
  MOZ_DIAGNOSTIC_ASSERT(mControl);
474
0
  mControl->ForgetReadStream(this);
475
0
  mControl = nullptr;
476
0
}
477
478
nsIInputStream*
479
ReadStream::Inner::EnsureStream()
480
0
{
481
0
  mMutex.AssertCurrentThreadOwns();
482
0
483
0
  // We need to block the current thread while we open the stream.  We
484
0
  // cannot do this safely from the main owning thread since it would
485
0
  // trigger deadlock.  This should be ok, though, since a blocking
486
0
  // stream like this should never be read on the owning thread anyway.
487
0
  if (mOwningEventTarget->IsOnCurrentThread()) {
488
0
    MOZ_CRASH("Blocking read on the js/ipc owning thread!");
489
0
  }
490
0
491
0
  if (mSnappyStream) {
492
0
    return mSnappyStream;
493
0
  }
494
0
495
0
  nsCOMPtr<nsIRunnable> r =
496
0
    NewCancelableRunnableMethod("ReadStream::Inner::AsyncOpenStreamOnOwningThread",
497
0
                                this,
498
0
                                &ReadStream::Inner::AsyncOpenStreamOnOwningThread);
499
0
  nsresult rv = mOwningEventTarget->Dispatch(r.forget(),
500
0
                                             nsIThread::DISPATCH_NORMAL);
501
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
502
0
    OpenStreamFailed();
503
0
    return mSnappyStream;
504
0
  }
505
0
506
0
  mCondVar.Wait();
507
0
  MOZ_DIAGNOSTIC_ASSERT(mSnappyStream);
508
0
509
0
  return mSnappyStream;
510
0
}
511
512
void
513
ReadStream::Inner::AsyncOpenStreamOnOwningThread()
514
0
{
515
0
  MOZ_ASSERT(mOwningEventTarget->IsOnCurrentThread());
516
0
517
0
  if (!mControl || mState == Closed) {
518
0
    MutexAutoLock lock(mMutex);
519
0
    OpenStreamFailed();
520
0
    mCondVar.NotifyAll();
521
0
    return;
522
0
  }
523
0
524
0
  if (mAsyncOpenStarted) {
525
0
    return;
526
0
  }
527
0
  mAsyncOpenStarted = true;
528
0
529
0
  RefPtr<ReadStream::Inner> self = this;
530
0
  mControl->OpenStream(mId, [self](nsCOMPtr<nsIInputStream>&& aStream) {
531
0
    MutexAutoLock lock(self->mMutex);
532
0
    self->mAsyncOpenStarted = false;
533
0
    if (!self->mStream) {
534
0
      if (!aStream) {
535
0
        self->OpenStreamFailed();
536
0
      } else {
537
0
        self->mStream = std::move(aStream);
538
0
        self->mSnappyStream = new SnappyUncompressInputStream(self->mStream);
539
0
      }
540
0
    }
541
0
    self->mCondVar.NotifyAll();
542
0
  });
543
0
}
544
545
void
546
ReadStream::Inner::MaybeAbortAsyncOpenStream()
547
0
{
548
0
  if (!mAsyncOpenStarted) {
549
0
    return;
550
0
  }
551
0
552
0
  MutexAutoLock lock(mMutex);
553
0
  OpenStreamFailed();
554
0
  mCondVar.NotifyAll();
555
0
}
556
557
void
558
ReadStream::Inner::OpenStreamFailed()
559
0
{
560
0
  MOZ_DIAGNOSTIC_ASSERT(!mStream);
561
0
  MOZ_DIAGNOSTIC_ASSERT(!mSnappyStream);
562
0
  mMutex.AssertCurrentThreadOwns();
563
0
  Unused << NS_NewCStringInputStream(getter_AddRefs(mStream), EmptyCString());
564
0
  mSnappyStream = mStream;
565
0
  mStream->Close();
566
0
  NoteClosed();
567
0
}
568
569
// ----------------------------------------------------------------------------
570
571
NS_IMPL_ISUPPORTS(cache::ReadStream, nsIInputStream, ReadStream);
572
573
// static
574
already_AddRefed<ReadStream>
575
ReadStream::Create(const CacheReadStreamOrVoid& aReadStreamOrVoid)
576
0
{
577
0
  if (aReadStreamOrVoid.type() == CacheReadStreamOrVoid::Tvoid_t) {
578
0
    return nullptr;
579
0
  }
580
0
581
0
  return Create(aReadStreamOrVoid.get_CacheReadStream());
582
0
}
583
584
// static
585
already_AddRefed<ReadStream>
586
ReadStream::Create(const CacheReadStream& aReadStream)
587
0
{
588
0
  // The parameter may or may not be for a Cache created stream.  The way we
589
0
  // tell is by looking at the stream control actor.  If the actor exists,
590
0
  // then we know the Cache created it.
591
0
  if (!aReadStream.controlChild() && !aReadStream.controlParent()) {
592
0
    return nullptr;
593
0
  }
594
0
595
0
  MOZ_DIAGNOSTIC_ASSERT(aReadStream.stream().type() == OptionalIPCStream::Tvoid_t ||
596
0
                        aReadStream.stream().get_IPCStream().type() ==
597
0
                        IPCStream::TInputStreamParamsWithFds);
598
0
599
0
  // Control is guaranteed to survive this method as ActorDestroy() cannot
600
0
  // run on this thread until we complete.
601
0
  StreamControl* control;
602
0
  if (aReadStream.controlChild()) {
603
0
    auto actor = static_cast<CacheStreamControlChild*>(aReadStream.controlChild());
604
0
    control = actor;
605
0
  } else {
606
0
    auto actor = static_cast<CacheStreamControlParent*>(aReadStream.controlParent());
607
0
    control = actor;
608
0
  }
609
0
  MOZ_DIAGNOSTIC_ASSERT(control);
610
0
611
0
  nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aReadStream.stream());
612
0
613
0
  // Currently we expect all cache read streams to be blocking file streams.
614
0
#if defined(MOZ_DIAGNOSTIC_ASSERT_ENABLED)
615
0
  if (stream) {
616
0
    nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(stream);
617
0
    MOZ_DIAGNOSTIC_ASSERT(!asyncStream);
618
0
  }
619
0
#endif
620
0
621
0
  RefPtr<Inner> inner = new Inner(control, aReadStream.id(), stream);
622
0
  RefPtr<ReadStream> ref = new ReadStream(inner);
623
0
  return ref.forget();
624
0
}
625
626
// static
627
already_AddRefed<ReadStream>
628
ReadStream::Create(PCacheStreamControlParent* aControl, const nsID& aId,
629
                   nsIInputStream* aStream)
630
0
{
631
0
  MOZ_DIAGNOSTIC_ASSERT(aControl);
632
0
  auto actor = static_cast<CacheStreamControlParent*>(aControl);
633
0
  RefPtr<Inner> inner = new Inner(actor, aId, aStream);
634
0
  RefPtr<ReadStream> ref = new ReadStream(inner);
635
0
  return ref.forget();
636
0
}
637
638
void
639
ReadStream::Serialize(CacheReadStreamOrVoid* aReadStreamOut,
640
                      nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
641
                      ErrorResult& aRv)
642
0
{
643
0
  mInner->Serialize(aReadStreamOut, aStreamCleanupList, aRv);
644
0
}
645
646
void
647
ReadStream::Serialize(CacheReadStream* aReadStreamOut,
648
                      nsTArray<UniquePtr<AutoIPCStream>>& aStreamCleanupList,
649
                      ErrorResult& aRv)
650
0
{
651
0
  mInner->Serialize(aReadStreamOut, aStreamCleanupList, aRv);
652
0
}
653
654
ReadStream::ReadStream(ReadStream::Inner* aInner)
655
  : mInner(aInner)
656
0
{
657
0
  MOZ_DIAGNOSTIC_ASSERT(mInner);
658
0
}
659
660
ReadStream::~ReadStream()
661
0
{
662
0
  // Explicitly close the inner stream so that it does not have to
663
0
  // deal with implicitly closing at destruction time.
664
0
  mInner->Close();
665
0
}
666
667
NS_IMETHODIMP
668
ReadStream::Close()
669
0
{
670
0
  return mInner->Close();
671
0
}
672
673
NS_IMETHODIMP
674
ReadStream::Available(uint64_t* aNumAvailableOut)
675
0
{
676
0
  return mInner->Available(aNumAvailableOut);
677
0
}
678
679
NS_IMETHODIMP
680
ReadStream::Read(char* aBuf, uint32_t aCount, uint32_t* aNumReadOut)
681
0
{
682
0
  return mInner->Read(aBuf, aCount, aNumReadOut);
683
0
}
684
685
NS_IMETHODIMP
686
ReadStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
687
                         uint32_t aCount, uint32_t* aNumReadOut)
688
0
{
689
0
  return mInner->ReadSegments(aWriter, aClosure, aCount, aNumReadOut);
690
0
}
691
692
NS_IMETHODIMP
693
ReadStream::IsNonBlocking(bool* aNonBlockingOut)
694
0
{
695
0
  return mInner->IsNonBlocking(aNonBlockingOut);
696
0
}
697
698
} // namespace cache
699
} // namespace dom
700
} // namespace mozilla