Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/io/SlicedInputStream.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 "SlicedInputStream.h"
8
#include "mozilla/ipc/InputStreamUtils.h"
9
#include "mozilla/CheckedInt.h"
10
#include "mozilla/ScopeExit.h"
11
#include "nsISeekableStream.h"
12
#include "nsStreamUtils.h"
13
14
namespace mozilla {
15
16
using namespace ipc;
17
18
NS_IMPL_ADDREF(SlicedInputStream);
19
NS_IMPL_RELEASE(SlicedInputStream);
20
21
0
NS_INTERFACE_MAP_BEGIN(SlicedInputStream)
22
0
  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
23
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
24
0
                                     mWeakCloneableInputStream || !mInputStream)
25
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
26
0
                                     mWeakIPCSerializableInputStream || !mInputStream)
27
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream,
28
0
                                     mWeakSeekableInputStream || !mInputStream)
29
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
30
0
                                     mWeakAsyncInputStream || !mInputStream)
31
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
32
0
                                     mWeakAsyncInputStream || !mInputStream)
33
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLength,
34
0
                                     mWeakInputStreamLength || !mInputStream)
35
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStreamLength,
36
0
                                     mWeakAsyncInputStreamLength || !mInputStream)
37
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLengthCallback,
38
0
                                     mWeakAsyncInputStreamLength || !mInputStream)
39
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
40
0
NS_INTERFACE_MAP_END
41
42
SlicedInputStream::SlicedInputStream(already_AddRefed<nsIInputStream> aInputStream,
43
                                     uint64_t aStart, uint64_t aLength)
44
  : mWeakCloneableInputStream(nullptr)
45
  , mWeakIPCSerializableInputStream(nullptr)
46
  , mWeakSeekableInputStream(nullptr)
47
  , mWeakAsyncInputStream(nullptr)
48
  , mWeakInputStreamLength(nullptr)
49
  , mWeakAsyncInputStreamLength(nullptr)
50
  , mStart(aStart)
51
  , mLength(aLength)
52
  , mCurPos(0)
53
  , mClosed(false)
54
  , mAsyncWaitFlags(0)
55
  , mAsyncWaitRequestedCount(0)
56
  , mMutex("SlicedInputStream::mMutex")
57
0
{
58
0
  nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
59
0
  SetSourceStream(inputStream.forget());
60
0
}
61
62
SlicedInputStream::SlicedInputStream()
63
  : mWeakCloneableInputStream(nullptr)
64
  , mWeakIPCSerializableInputStream(nullptr)
65
  , mWeakSeekableInputStream(nullptr)
66
  , mWeakAsyncInputStream(nullptr)
67
  , mStart(0)
68
  , mLength(0)
69
  , mCurPos(0)
70
  , mClosed(false)
71
  , mAsyncWaitFlags(0)
72
  , mAsyncWaitRequestedCount(0)
73
  , mMutex("SlicedInputStream::mMutex")
74
0
{}
75
76
SlicedInputStream::~SlicedInputStream()
77
0
{}
78
79
void
80
SlicedInputStream::SetSourceStream(already_AddRefed<nsIInputStream> aInputStream)
81
0
{
82
0
  MOZ_ASSERT(!mInputStream);
83
0
84
0
  mInputStream = std::move(aInputStream);
85
0
86
0
  nsCOMPtr<nsICloneableInputStream> cloneableStream =
87
0
    do_QueryInterface(mInputStream);
88
0
  if (cloneableStream && SameCOMIdentity(mInputStream, cloneableStream)) {
89
0
    mWeakCloneableInputStream = cloneableStream;
90
0
  }
91
0
92
0
  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
93
0
    do_QueryInterface(mInputStream);
94
0
  if (serializableStream &&
95
0
      SameCOMIdentity(mInputStream, serializableStream)) {
96
0
    mWeakIPCSerializableInputStream = serializableStream;
97
0
  }
98
0
99
0
  nsCOMPtr<nsISeekableStream> seekableStream =
100
0
    do_QueryInterface(mInputStream);
101
0
  if (seekableStream && SameCOMIdentity(mInputStream, seekableStream)) {
102
0
    mWeakSeekableInputStream = seekableStream;
103
0
  }
104
0
105
0
  nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
106
0
    do_QueryInterface(mInputStream);
107
0
  if (asyncInputStream && SameCOMIdentity(mInputStream, asyncInputStream)) {
108
0
    mWeakAsyncInputStream = asyncInputStream;
109
0
  }
110
0
111
0
  nsCOMPtr<nsIInputStreamLength> streamLength = do_QueryInterface(mInputStream);
112
0
  if (streamLength &&
113
0
      SameCOMIdentity(mInputStream, streamLength)) {
114
0
    mWeakInputStreamLength = streamLength;
115
0
  }
116
0
117
0
  nsCOMPtr<nsIAsyncInputStreamLength> asyncStreamLength =
118
0
    do_QueryInterface(mInputStream);
119
0
  if (asyncStreamLength &&
120
0
      SameCOMIdentity(mInputStream, asyncStreamLength)) {
121
0
    mWeakAsyncInputStreamLength = asyncStreamLength;
122
0
  }
123
0
}
124
125
uint64_t
126
SlicedInputStream::AdjustRange(uint64_t aRange)
127
0
{
128
0
  CheckedUint64 range(aRange);
129
0
  range += mCurPos;
130
0
131
0
  // Let's remove extra length from the end.
132
0
  if (range.isValid() && range.value() > mStart + mLength) {
133
0
    aRange -= XPCOM_MIN((uint64_t)aRange, range.value() - (mStart + mLength));
134
0
  }
135
0
136
0
  // Let's remove extra length from the begin.
137
0
  if (mCurPos < mStart) {
138
0
    aRange -= XPCOM_MIN((uint64_t)aRange, mStart - mCurPos);
139
0
  }
140
0
141
0
  return aRange;
142
0
}
143
144
// nsIInputStream interface
145
146
NS_IMETHODIMP
147
SlicedInputStream::Close()
148
0
{
149
0
  NS_ENSURE_STATE(mInputStream);
150
0
151
0
  mClosed = true;
152
0
  return mInputStream->Close();
153
0
}
154
155
NS_IMETHODIMP
156
SlicedInputStream::Available(uint64_t* aLength)
157
0
{
158
0
  NS_ENSURE_STATE(mInputStream);
159
0
160
0
  if (mClosed) {
161
0
    return NS_BASE_STREAM_CLOSED;
162
0
  }
163
0
164
0
  nsresult rv = mInputStream->Available(aLength);
165
0
  if (rv == NS_BASE_STREAM_CLOSED) {
166
0
    mClosed = true;
167
0
    return rv;
168
0
  }
169
0
170
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
171
0
    return rv;
172
0
  }
173
0
174
0
  *aLength = AdjustRange(*aLength);
175
0
  return NS_OK;
176
0
}
177
178
NS_IMETHODIMP
179
SlicedInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount)
180
0
{
181
0
  *aReadCount = 0;
182
0
183
0
  if (mClosed) {
184
0
    return NS_OK;
185
0
  }
186
0
187
0
  if (mCurPos < mStart) {
188
0
    nsCOMPtr<nsISeekableStream> seekableStream =
189
0
      do_QueryInterface(mInputStream);
190
0
    if (seekableStream) {
191
0
      nsresult rv = seekableStream->Seek(nsISeekableStream::NS_SEEK_SET,
192
0
                                         mStart);
193
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
194
0
        return rv;
195
0
      }
196
0
197
0
      mCurPos = mStart;
198
0
    } else {
199
0
      char buf[4096];
200
0
      while (mCurPos < mStart) {
201
0
        uint32_t bytesRead;
202
0
        uint64_t bufCount = XPCOM_MIN(mStart - mCurPos, (uint64_t)sizeof(buf));
203
0
        nsresult rv = mInputStream->Read(buf, bufCount, &bytesRead);
204
0
        if (NS_SUCCEEDED(rv) && bytesRead == 0) {
205
0
          mClosed = true;
206
0
          return rv;
207
0
        }
208
0
209
0
        if (NS_WARN_IF(NS_FAILED(rv))) {
210
0
          return rv;
211
0
        }
212
0
213
0
         mCurPos += bytesRead;
214
0
      }
215
0
    }
216
0
  }
217
0
218
0
  // Let's reduce aCount in case it's too big.
219
0
  if (mCurPos + aCount > mStart + mLength) {
220
0
    aCount = mStart + mLength - mCurPos;
221
0
  }
222
0
223
0
  // Nothing else to read.
224
0
  if (!aCount) {
225
0
    return NS_OK;
226
0
  }
227
0
228
0
  nsresult rv = mInputStream->Read(aBuffer, aCount, aReadCount);
229
0
  if (NS_SUCCEEDED(rv) && *aReadCount == 0) {
230
0
    mClosed = true;
231
0
    return rv;
232
0
  }
233
0
234
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
235
0
    return rv;
236
0
  }
237
0
238
0
  mCurPos += *aReadCount;
239
0
  return NS_OK;
240
0
}
241
242
NS_IMETHODIMP
243
SlicedInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
244
                                uint32_t aCount, uint32_t *aResult)
245
0
{
246
0
  return NS_ERROR_NOT_IMPLEMENTED;
247
0
}
248
249
NS_IMETHODIMP
250
SlicedInputStream::IsNonBlocking(bool* aNonBlocking)
251
0
{
252
0
  NS_ENSURE_STATE(mInputStream);
253
0
  return mInputStream->IsNonBlocking(aNonBlocking);
254
0
}
255
256
// nsICloneableInputStream interface
257
258
NS_IMETHODIMP
259
SlicedInputStream::GetCloneable(bool* aCloneable)
260
0
{
261
0
  NS_ENSURE_STATE(mInputStream);
262
0
  NS_ENSURE_STATE(mWeakCloneableInputStream);
263
0
264
0
  *aCloneable = true;
265
0
  return NS_OK;
266
0
}
267
268
NS_IMETHODIMP
269
SlicedInputStream::Clone(nsIInputStream** aResult)
270
0
{
271
0
  NS_ENSURE_STATE(mInputStream);
272
0
  NS_ENSURE_STATE(mWeakCloneableInputStream);
273
0
274
0
  nsCOMPtr<nsIInputStream> clonedStream;
275
0
  nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
276
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
277
0
    return rv;
278
0
  }
279
0
280
0
  nsCOMPtr<nsIInputStream> sis =
281
0
    new SlicedInputStream(clonedStream.forget(), mStart, mLength);
282
0
283
0
  sis.forget(aResult);
284
0
  return NS_OK;
285
0
}
286
287
// nsIAsyncInputStream interface
288
289
NS_IMETHODIMP
290
SlicedInputStream::CloseWithStatus(nsresult aStatus)
291
0
{
292
0
  NS_ENSURE_STATE(mInputStream);
293
0
  NS_ENSURE_STATE(mWeakAsyncInputStream);
294
0
295
0
  mClosed = true;
296
0
  return mWeakAsyncInputStream->CloseWithStatus(aStatus);
297
0
}
298
299
NS_IMETHODIMP
300
SlicedInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
301
                             uint32_t aFlags,
302
                             uint32_t aRequestedCount,
303
                             nsIEventTarget* aEventTarget)
304
0
{
305
0
  NS_ENSURE_STATE(mInputStream);
306
0
  NS_ENSURE_STATE(mWeakAsyncInputStream);
307
0
308
0
  nsCOMPtr<nsIInputStreamCallback> callback = aCallback ? this : nullptr;
309
0
310
0
  uint32_t flags = aFlags;
311
0
  uint32_t requestedCount = aRequestedCount;
312
0
313
0
  {
314
0
    MutexAutoLock lock(mMutex);
315
0
316
0
    if (mAsyncWaitCallback && aCallback) {
317
0
      return NS_ERROR_FAILURE;
318
0
    }
319
0
320
0
    mAsyncWaitCallback = aCallback;
321
0
322
0
    // If we haven't started retrieving data, let's see if we can seek.
323
0
    // If we cannot seek, we will do consecutive reads.
324
0
    if (mCurPos < mStart && mWeakSeekableInputStream) {
325
0
      nsresult rv =
326
0
        mWeakSeekableInputStream->Seek(nsISeekableStream::NS_SEEK_SET, mStart);
327
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
328
0
        return rv;
329
0
      }
330
0
331
0
      mCurPos = mStart;
332
0
    }
333
0
334
0
    mAsyncWaitFlags = aFlags;
335
0
    mAsyncWaitRequestedCount = aRequestedCount;
336
0
    mAsyncWaitEventTarget = aEventTarget;
337
0
338
0
    // If we are not at the right position, let's do an asyncWait just internal.
339
0
    if (mCurPos < mStart) {
340
0
      flags = 0;
341
0
      requestedCount = mStart - mCurPos;
342
0
    }
343
0
  }
344
0
345
0
  return mWeakAsyncInputStream->AsyncWait(callback, flags, requestedCount,
346
0
                                          aEventTarget);
347
0
}
348
349
// nsIInputStreamCallback
350
351
NS_IMETHODIMP
352
SlicedInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream)
353
0
{
354
0
  MOZ_ASSERT(mInputStream);
355
0
  MOZ_ASSERT(mWeakAsyncInputStream);
356
0
  MOZ_ASSERT(mWeakAsyncInputStream == aStream);
357
0
358
0
  nsCOMPtr<nsIInputStreamCallback> callback;
359
0
  uint32_t asyncWaitFlags = 0;
360
0
  uint32_t asyncWaitRequestedCount = 0;
361
0
  nsCOMPtr<nsIEventTarget> asyncWaitEventTarget;
362
0
363
0
  {
364
0
    MutexAutoLock lock(mMutex);
365
0
366
0
    // We have been canceled in the meanwhile.
367
0
    if (!mAsyncWaitCallback) {
368
0
      return NS_OK;
369
0
    }
370
0
371
0
    auto raii = MakeScopeExit([&] {
372
0
      mMutex.AssertCurrentThreadOwns();
373
0
      mAsyncWaitCallback = nullptr;
374
0
      mAsyncWaitEventTarget = nullptr;
375
0
    });
376
0
377
0
    asyncWaitFlags = mAsyncWaitFlags;
378
0
    asyncWaitRequestedCount = mAsyncWaitRequestedCount;
379
0
    asyncWaitEventTarget = mAsyncWaitEventTarget;
380
0
381
0
    // If at the end of this locked block, the callback is not null, it will be
382
0
    // executed, otherwise, we are going to exec another AsyncWait().
383
0
    callback = mAsyncWaitCallback;
384
0
385
0
    if (mCurPos < mStart) {
386
0
      char buf[4096];
387
0
      nsresult rv = NS_OK;
388
0
      while (mCurPos < mStart) {
389
0
        uint32_t bytesRead;
390
0
        uint64_t bufCount = XPCOM_MIN(mStart - mCurPos, (uint64_t)sizeof(buf));
391
0
        rv = mInputStream->Read(buf, bufCount, &bytesRead);
392
0
        if (NS_SUCCEEDED(rv) && bytesRead == 0) {
393
0
          mClosed = true;
394
0
          break;
395
0
        }
396
0
397
0
        if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
398
0
          asyncWaitFlags = 0;
399
0
          asyncWaitRequestedCount = mStart - mCurPos;
400
0
          // Here we want to exec another AsyncWait().
401
0
          callback = nullptr;
402
0
          break;
403
0
        }
404
0
405
0
        if (NS_WARN_IF(NS_FAILED(rv))) {
406
0
          break;
407
0
        }
408
0
409
0
        mCurPos += bytesRead;
410
0
      }
411
0
412
0
      // Now we are ready to do the 'real' asyncWait.
413
0
      if (mCurPos >= mStart) {
414
0
        // We don't want to nullify the callback now, because it will be needed
415
0
        // at the next ::OnInputStreamReady.
416
0
        raii.release();
417
0
        callback = nullptr;
418
0
      }
419
0
    }
420
0
  }
421
0
422
0
  if (callback) {
423
0
    return callback->OnInputStreamReady(this);
424
0
  }
425
0
426
0
  return mWeakAsyncInputStream->AsyncWait(this, asyncWaitFlags,
427
0
                                          asyncWaitRequestedCount,
428
0
                                          asyncWaitEventTarget);
429
0
}
430
431
// nsIIPCSerializableInputStream
432
433
void
434
SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
435
                             FileDescriptorArray& aFileDescriptors)
436
0
{
437
0
  MOZ_ASSERT(mInputStream);
438
0
  MOZ_ASSERT(mWeakIPCSerializableInputStream);
439
0
440
0
  SlicedInputStreamParams params;
441
0
  InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
442
0
                                          aFileDescriptors);
443
0
  params.start() = mStart;
444
0
  params.length() = mLength;
445
0
  params.curPos() = mCurPos;
446
0
  params.closed() = mClosed;
447
0
448
0
  aParams = params;
449
0
}
450
451
bool
452
SlicedInputStream::Deserialize(const mozilla::ipc::InputStreamParams& aParams,
453
                               const FileDescriptorArray& aFileDescriptors)
454
0
{
455
0
  MOZ_ASSERT(!mInputStream);
456
0
  MOZ_ASSERT(!mWeakIPCSerializableInputStream);
457
0
458
0
  if (aParams.type() !=
459
0
      InputStreamParams::TSlicedInputStreamParams) {
460
0
    NS_ERROR("Received unknown parameters from the other process!");
461
0
    return false;
462
0
  }
463
0
464
0
  const SlicedInputStreamParams& params =
465
0
    aParams.get_SlicedInputStreamParams();
466
0
467
0
  nsCOMPtr<nsIInputStream> stream =
468
0
    InputStreamHelper::DeserializeInputStream(params.stream(),
469
0
                                              aFileDescriptors);
470
0
  if (!stream) {
471
0
    NS_WARNING("Deserialize failed!");
472
0
    return false;
473
0
  }
474
0
475
0
  SetSourceStream(stream.forget());
476
0
477
0
  mStart = params.start();
478
0
  mLength = params.length();
479
0
  mCurPos = params.curPos();
480
0
  mClosed = params.closed();
481
0
482
0
  return true;
483
0
}
484
485
mozilla::Maybe<uint64_t>
486
SlicedInputStream::ExpectedSerializedLength()
487
0
{
488
0
  if (!mInputStream || !mWeakIPCSerializableInputStream) {
489
0
    return mozilla::Nothing();
490
0
  }
491
0
492
0
  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
493
0
}
494
495
// nsISeekableStream
496
497
NS_IMETHODIMP
498
SlicedInputStream::Seek(int32_t aWhence, int64_t aOffset)
499
0
{
500
0
  NS_ENSURE_STATE(mInputStream);
501
0
  NS_ENSURE_STATE(mWeakSeekableInputStream);
502
0
503
0
  int64_t offset;
504
0
  nsresult rv;
505
0
506
0
  switch (aWhence) {
507
0
    case NS_SEEK_SET:
508
0
      offset = mStart + aOffset;
509
0
      break;
510
0
    case NS_SEEK_CUR:
511
0
      // mCurPos could be lower than mStart if the reading has not started yet.
512
0
      offset = XPCOM_MAX(mStart, mCurPos) + aOffset;
513
0
      break;
514
0
    case NS_SEEK_END: {
515
0
      uint64_t available;
516
0
      rv = mInputStream->Available(&available);
517
0
      if (rv == NS_BASE_STREAM_CLOSED) {
518
0
        mClosed = true;
519
0
        return rv;
520
0
      }
521
0
522
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
523
0
        return rv;
524
0
      }
525
0
526
0
      offset = XPCOM_MIN(mStart + mLength, available) + aOffset;
527
0
      break;
528
0
    }
529
0
    default:
530
0
      return NS_ERROR_ILLEGAL_VALUE;
531
0
  }
532
0
533
0
  if (offset < (int64_t)mStart || offset > (int64_t)(mStart + mLength)) {
534
0
    return NS_ERROR_INVALID_ARG;
535
0
  }
536
0
537
0
  rv = mWeakSeekableInputStream->Seek(NS_SEEK_SET, offset);
538
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
539
0
    return rv;
540
0
  }
541
0
542
0
  mCurPos = offset;
543
0
  return NS_OK;
544
0
}
545
546
NS_IMETHODIMP
547
SlicedInputStream::Tell(int64_t *aResult)
548
0
{
549
0
  NS_ENSURE_STATE(mInputStream);
550
0
  NS_ENSURE_STATE(mWeakSeekableInputStream);
551
0
552
0
  int64_t tell = 0;
553
0
554
0
  nsresult rv = mWeakSeekableInputStream->Tell(&tell);
555
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
556
0
    return rv;
557
0
  }
558
0
559
0
  if (tell < (int64_t)mStart) {
560
0
    *aResult = 0;
561
0
    return NS_OK;
562
0
  }
563
0
564
0
  *aResult = tell - mStart;
565
0
  if (*aResult > (int64_t)mLength) {
566
0
    *aResult = mLength;
567
0
  }
568
0
569
0
  return NS_OK;
570
0
}
571
572
NS_IMETHODIMP
573
SlicedInputStream::SetEOF()
574
0
{
575
0
  NS_ENSURE_STATE(mInputStream);
576
0
  NS_ENSURE_STATE(mWeakSeekableInputStream);
577
0
578
0
  mClosed = true;
579
0
  return mWeakSeekableInputStream->SetEOF();
580
0
}
581
582
// nsIInputStreamLength
583
584
NS_IMETHODIMP
585
SlicedInputStream::Length(int64_t* aLength)
586
0
{
587
0
  NS_ENSURE_STATE(mInputStream);
588
0
  NS_ENSURE_STATE(mWeakInputStreamLength);
589
0
590
0
  nsresult rv = mWeakInputStreamLength->Length(aLength);
591
0
  if (rv == NS_BASE_STREAM_CLOSED) {
592
0
    mClosed = true;
593
0
    return rv;
594
0
  }
595
0
596
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
597
0
    return rv;
598
0
  }
599
0
600
0
  if (*aLength == -1) {
601
0
    return NS_OK;
602
0
  }
603
0
604
0
  *aLength = (int64_t)AdjustRange((uint64_t)*aLength);
605
0
  return NS_OK;
606
0
}
607
608
// nsIAsyncInputStreamLength
609
610
NS_IMETHODIMP
611
SlicedInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
612
                                   nsIEventTarget* aEventTarget)
613
0
{
614
0
  NS_ENSURE_STATE(mInputStream);
615
0
  NS_ENSURE_STATE(mWeakAsyncInputStreamLength);
616
0
617
0
  nsCOMPtr<nsIInputStreamLengthCallback> callback = aCallback ? this : nullptr;
618
0
  {
619
0
    MutexAutoLock lock(mMutex);
620
0
    mAsyncWaitLengthCallback = aCallback;
621
0
  }
622
0
623
0
  return mWeakAsyncInputStreamLength->AsyncLengthWait(callback, aEventTarget);
624
0
}
625
626
// nsIInputStreamLengthCallback
627
628
NS_IMETHODIMP
629
SlicedInputStream::OnInputStreamLengthReady(nsIAsyncInputStreamLength* aStream,
630
                                            int64_t aLength)
631
0
{
632
0
  MOZ_ASSERT(mInputStream);
633
0
  MOZ_ASSERT(mWeakAsyncInputStreamLength);
634
0
  MOZ_ASSERT(mWeakAsyncInputStreamLength == aStream);
635
0
636
0
  nsCOMPtr<nsIInputStreamLengthCallback> callback;
637
0
  {
638
0
      MutexAutoLock lock(mMutex);
639
0
640
0
    // We have been canceled in the meanwhile.
641
0
    if (!mAsyncWaitLengthCallback) {
642
0
      return NS_OK;
643
0
    }
644
0
645
0
    callback.swap(mAsyncWaitLengthCallback);
646
0
  }
647
0
648
0
  if (aLength != -1) {
649
0
    aLength = (int64_t)AdjustRange((uint64_t)aLength);
650
0
  }
651
0
652
0
  MOZ_ASSERT(callback);
653
0
  return callback->OnInputStreamLengthReady(this, aLength);
654
0
}
655
656
} // namespace mozilla