Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/cache2/CacheFileInputStream.cpp
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "CacheLog.h"
6
#include "CacheFileInputStream.h"
7
8
#include "CacheFile.h"
9
#include "nsStreamUtils.h"
10
#include "nsThreadUtils.h"
11
#include <algorithm>
12
13
namespace mozilla {
14
namespace net {
15
16
NS_IMPL_ADDREF(CacheFileInputStream)
17
NS_IMETHODIMP_(MozExternalRefCountType)
18
CacheFileInputStream::Release()
19
0
{
20
0
  MOZ_ASSERT(0 != mRefCnt, "dup release");
21
0
  nsrefcnt count = --mRefCnt;
22
0
  NS_LOG_RELEASE(this, count, "CacheFileInputStream");
23
0
24
0
  if (0 == count) {
25
0
    mRefCnt = 1;
26
0
    delete (this);
27
0
    return 0;
28
0
  }
29
0
30
0
  if (count == 1) {
31
0
    mFile->RemoveInput(this, mStatus);
32
0
  }
33
0
34
0
  return count;
35
0
}
36
37
0
NS_INTERFACE_MAP_BEGIN(CacheFileInputStream)
38
0
  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
39
0
  NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
40
0
  NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
41
0
  NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener)
42
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
43
0
NS_INTERFACE_MAP_END
44
45
CacheFileInputStream::CacheFileInputStream(CacheFile *aFile,
46
                                           nsISupports *aEntry,
47
                                           bool aAlternativeData)
48
  : mFile(aFile)
49
  , mPos(0)
50
  , mStatus(NS_OK)
51
  , mClosed(false)
52
  , mInReadSegments(false)
53
  , mWaitingForUpdate(false)
54
  , mAlternativeData(aAlternativeData)
55
  , mListeningForChunk(-1)
56
  , mCallbackFlags(0)
57
  , mCacheEntryHandle(aEntry)
58
0
{
59
0
  LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this));
60
0
61
0
  if (mAlternativeData) {
62
0
    mPos = mFile->mAltDataOffset;
63
0
  }
64
0
}
65
66
CacheFileInputStream::~CacheFileInputStream()
67
0
{
68
0
  LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this));
69
0
  MOZ_ASSERT(!mInReadSegments);
70
0
}
71
72
// nsIInputStream
73
NS_IMETHODIMP
74
CacheFileInputStream::Close()
75
0
{
76
0
  LOG(("CacheFileInputStream::Close() [this=%p]", this));
77
0
  return CloseWithStatus(NS_OK);
78
0
}
79
80
NS_IMETHODIMP
81
CacheFileInputStream::Available(uint64_t *_retval)
82
0
{
83
0
  CacheFileAutoLock lock(mFile);
84
0
85
0
  if (mClosed) {
86
0
    LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, "
87
0
         "status=0x%08" PRIx32 "]", this, static_cast<uint32_t>(mStatus)));
88
0
    return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED;
89
0
  }
90
0
91
0
  EnsureCorrectChunk(false);
92
0
  if (NS_FAILED(mStatus)) {
93
0
    LOG(("CacheFileInputStream::Available() - EnsureCorrectChunk failed. "
94
0
         "[this=%p, status=0x%08" PRIx32 "]", this, static_cast<uint32_t>(mStatus)));
95
0
    return mStatus;
96
0
  }
97
0
98
0
  nsresult rv = NS_OK;
99
0
  *_retval = 0;
100
0
101
0
  if (mChunk) {
102
0
    int64_t canRead = mFile->BytesFromChunk(mChunk->Index(), mAlternativeData);
103
0
    canRead -= (mPos % kChunkSize);
104
0
105
0
    if (canRead > 0) {
106
0
      *_retval = canRead;
107
0
    } else if (canRead == 0 && !mFile->OutputStreamExists(mAlternativeData)) {
108
0
      rv = NS_BASE_STREAM_CLOSED;
109
0
    }
110
0
  }
111
0
112
0
  LOG(("CacheFileInputStream::Available() [this=%p, retval=%" PRIu64 ", rv=0x%08" PRIx32 "]",
113
0
       this, *_retval, static_cast<uint32_t>(rv)));
114
0
115
0
  return rv;
116
0
}
117
118
NS_IMETHODIMP
119
CacheFileInputStream::Read(char *aBuf, uint32_t aCount, uint32_t *_retval)
120
0
{
121
0
  LOG(("CacheFileInputStream::Read() [this=%p, count=%d]", this, aCount));
122
0
  return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
123
0
}
124
125
NS_IMETHODIMP
126
CacheFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
127
                                   uint32_t aCount, uint32_t *_retval)
128
0
{
129
0
  CacheFileAutoLock lock(mFile);
130
0
131
0
  LOG(("CacheFileInputStream::ReadSegments() [this=%p, count=%d]",
132
0
       this, aCount));
133
0
134
0
  nsresult rv = NS_OK;
135
0
136
0
  *_retval = 0;
137
0
138
0
  if (mInReadSegments) {
139
0
    LOG(("CacheFileInputStream::ReadSegments() - Cannot be called while the "
140
0
         "stream is in ReadSegments!"));
141
0
    return NS_ERROR_UNEXPECTED;
142
0
  }
143
0
144
0
  if (mClosed) {
145
0
    LOG(("CacheFileInputStream::ReadSegments() - Stream is closed. [this=%p, "
146
0
         "status=0x%08" PRIx32 "]", this, static_cast<uint32_t>(mStatus)));
147
0
148
0
    if (NS_FAILED(mStatus)) {
149
0
      return mStatus;
150
0
    }
151
0
152
0
    return NS_OK;
153
0
  }
154
0
155
0
  if (aCount == 0) {
156
0
    return NS_OK;
157
0
  }
158
0
159
0
  EnsureCorrectChunk(false);
160
0
161
0
  while (true) {
162
0
    if (NS_FAILED(mStatus))
163
0
      return mStatus;
164
0
165
0
    if (!mChunk) {
166
0
      if (mListeningForChunk == -1) {
167
0
        return NS_OK;
168
0
      }
169
0
      return NS_BASE_STREAM_WOULD_BLOCK;
170
0
    }
171
0
172
0
    CacheFileChunkReadHandle hnd = mChunk->GetReadHandle();
173
0
    int64_t canRead = CanRead(&hnd);
174
0
    if (NS_FAILED(mStatus)) {
175
0
      return mStatus;
176
0
    }
177
0
178
0
    if (canRead < 0) {
179
0
      // file was truncated ???
180
0
      MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
181
0
      rv = NS_OK;
182
0
    } else if (canRead > 0) {
183
0
      uint32_t toRead = std::min(static_cast<uint32_t>(canRead), aCount);
184
0
      uint32_t read;
185
0
      const char *buf = hnd.Buf() + (mPos - hnd.Offset());
186
0
187
0
      mInReadSegments = true;
188
0
      lock.Unlock();
189
0
190
0
      rv = aWriter(this, aClosure, buf, *_retval, toRead, &read);
191
0
192
0
      lock.Lock();
193
0
      mInReadSegments = false;
194
0
195
0
      if (NS_SUCCEEDED(rv)) {
196
0
        MOZ_ASSERT(read <= toRead,
197
0
                   "writer should not write more than we asked it to write");
198
0
199
0
        *_retval += read;
200
0
        mPos += read;
201
0
        aCount -= read;
202
0
203
0
        if (!mClosed) {
204
0
          // The last chunk is released after the caller closes this stream.
205
0
          EnsureCorrectChunk(false);
206
0
207
0
          if (mChunk && aCount) {
208
0
            // Check whether there is more data available to read.
209
0
            continue;
210
0
          }
211
0
        }
212
0
      }
213
0
214
0
      if (mClosed) {
215
0
        // The stream was closed from aWriter, do the cleanup.
216
0
        CleanUp();
217
0
      }
218
0
219
0
      rv = NS_OK;
220
0
    } else {
221
0
      if (*_retval == 0 && mFile->OutputStreamExists(mAlternativeData)) {
222
0
        rv = NS_BASE_STREAM_WOULD_BLOCK;
223
0
      } else {
224
0
        rv = NS_OK;
225
0
      }
226
0
    }
227
0
228
0
    break;
229
0
  }
230
0
231
0
  LOG(("CacheFileInputStream::ReadSegments() [this=%p, rv=0x%08" PRIx32 ", retval=%d]",
232
0
       this, static_cast<uint32_t>(rv), *_retval));
233
0
234
0
  return rv;
235
0
}
236
237
NS_IMETHODIMP
238
CacheFileInputStream::IsNonBlocking(bool *_retval)
239
0
{
240
0
  *_retval = true;
241
0
  return NS_OK;
242
0
}
243
244
// nsIAsyncInputStream
245
NS_IMETHODIMP
246
CacheFileInputStream::CloseWithStatus(nsresult aStatus)
247
0
{
248
0
  CacheFileAutoLock lock(mFile);
249
0
250
0
  LOG(("CacheFileInputStream::CloseWithStatus() [this=%p, aStatus=0x%08" PRIx32 "]",
251
0
       this, static_cast<uint32_t>(aStatus)));
252
0
253
0
  return CloseWithStatusLocked(aStatus);
254
0
}
255
256
nsresult
257
CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus)
258
0
{
259
0
  LOG(("CacheFileInputStream::CloseWithStatusLocked() [this=%p, "
260
0
       "aStatus=0x%08" PRIx32 "]", this, static_cast<uint32_t>(aStatus)));
261
0
262
0
  if (mClosed) {
263
0
    // We notify listener and null out mCallback immediately after closing
264
0
    // the stream. If we're in ReadSegments we postpone notification until we
265
0
    // step out from ReadSegments. So if the stream is already closed the
266
0
    // following assertion must be true.
267
0
    MOZ_ASSERT(!mCallback || mInReadSegments);
268
0
269
0
    return NS_OK;
270
0
  }
271
0
272
0
  mClosed = true;
273
0
  mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
274
0
275
0
  if (!mInReadSegments) {
276
0
    CleanUp();
277
0
  }
278
0
279
0
  return NS_OK;
280
0
}
281
282
void
283
CacheFileInputStream::CleanUp()
284
0
{
285
0
  MOZ_ASSERT(!mInReadSegments);
286
0
  MOZ_ASSERT(mClosed);
287
0
288
0
  if (mChunk) {
289
0
    ReleaseChunk();
290
0
  }
291
0
292
0
  // TODO propagate error from input stream to other streams ???
293
0
294
0
  MaybeNotifyListener();
295
0
296
0
  mFile->ReleaseOutsideLock(mCacheEntryHandle.forget());
297
0
}
298
299
NS_IMETHODIMP
300
CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback,
301
                                uint32_t aFlags,
302
                                uint32_t aRequestedCount,
303
                                nsIEventTarget *aEventTarget)
304
0
{
305
0
  CacheFileAutoLock lock(mFile);
306
0
307
0
  LOG(("CacheFileInputStream::AsyncWait() [this=%p, callback=%p, flags=%d, "
308
0
       "requestedCount=%d, eventTarget=%p]", this, aCallback, aFlags,
309
0
       aRequestedCount, aEventTarget));
310
0
311
0
  if (mInReadSegments) {
312
0
    LOG(("CacheFileInputStream::AsyncWait() - Cannot be called while the stream"
313
0
         " is in ReadSegments!"));
314
0
    MOZ_ASSERT(false, "Unexpected call. If it's a valid usage implement it. "
315
0
               "Otherwise fix the caller.");
316
0
    return NS_ERROR_UNEXPECTED;
317
0
  }
318
0
319
0
  mCallback = aCallback;
320
0
  mCallbackFlags = aFlags;
321
0
  mCallbackTarget = aEventTarget;
322
0
323
0
  if (!mCallback) {
324
0
    if (mWaitingForUpdate) {
325
0
      mChunk->CancelWait(this);
326
0
      mWaitingForUpdate = false;
327
0
    }
328
0
    return NS_OK;
329
0
  }
330
0
331
0
  if (mClosed) {
332
0
    NotifyListener();
333
0
    return NS_OK;
334
0
  }
335
0
336
0
  EnsureCorrectChunk(false);
337
0
338
0
  MaybeNotifyListener();
339
0
340
0
  return NS_OK;
341
0
}
342
343
// nsISeekableStream
344
NS_IMETHODIMP
345
CacheFileInputStream::Seek(int32_t whence, int64_t offset)
346
0
{
347
0
  CacheFileAutoLock lock(mFile);
348
0
349
0
  LOG(("CacheFileInputStream::Seek() [this=%p, whence=%d, offset=%" PRId64 "]",
350
0
       this, whence, offset));
351
0
352
0
  if (mInReadSegments) {
353
0
    LOG(("CacheFileInputStream::Seek() - Cannot be called while the stream is "
354
0
         "in ReadSegments!"));
355
0
    return NS_ERROR_UNEXPECTED;
356
0
  }
357
0
358
0
  if (mClosed) {
359
0
    LOG(("CacheFileInputStream::Seek() - Stream is closed. [this=%p]", this));
360
0
    return NS_BASE_STREAM_CLOSED;
361
0
  }
362
0
363
0
  int64_t newPos = offset;
364
0
  switch (whence) {
365
0
    case NS_SEEK_SET:
366
0
      if (mAlternativeData) {
367
0
        newPos += mFile->mAltDataOffset;
368
0
      }
369
0
      break;
370
0
    case NS_SEEK_CUR:
371
0
      newPos += mPos;
372
0
      break;
373
0
    case NS_SEEK_END:
374
0
      if (mAlternativeData) {
375
0
        newPos += mFile->mDataSize;
376
0
      } else {
377
0
        newPos += mFile->mAltDataOffset;
378
0
      }
379
0
      break;
380
0
    default:
381
0
      NS_ERROR("invalid whence");
382
0
      return NS_ERROR_INVALID_ARG;
383
0
  }
384
0
  mPos = newPos;
385
0
  EnsureCorrectChunk(false);
386
0
387
0
  LOG(("CacheFileInputStream::Seek() [this=%p, pos=%" PRId64 "]", this, mPos));
388
0
  return NS_OK;
389
0
}
390
391
NS_IMETHODIMP
392
CacheFileInputStream::Tell(int64_t *_retval)
393
0
{
394
0
  CacheFileAutoLock lock(mFile);
395
0
396
0
  if (mClosed) {
397
0
    LOG(("CacheFileInputStream::Tell() - Stream is closed. [this=%p]", this));
398
0
    return NS_BASE_STREAM_CLOSED;
399
0
  }
400
0
401
0
  *_retval = mPos;
402
0
403
0
  if (mAlternativeData) {
404
0
    *_retval -= mFile->mAltDataOffset;
405
0
  }
406
0
407
0
  LOG(("CacheFileInputStream::Tell() [this=%p, retval=%" PRId64 "]", this, *_retval));
408
0
  return NS_OK;
409
0
}
410
411
NS_IMETHODIMP
412
CacheFileInputStream::SetEOF()
413
0
{
414
0
  MOZ_ASSERT(false, "Don't call SetEOF on cache input stream");
415
0
  return NS_ERROR_NOT_IMPLEMENTED;
416
0
}
417
418
// CacheFileChunkListener
419
nsresult
420
CacheFileInputStream::OnChunkRead(nsresult aResult, CacheFileChunk *aChunk)
421
0
{
422
0
  MOZ_CRASH("CacheFileInputStream::OnChunkRead should not be called!");
423
0
  return NS_ERROR_UNEXPECTED;
424
0
}
425
426
nsresult
427
CacheFileInputStream::OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk)
428
0
{
429
0
  MOZ_CRASH("CacheFileInputStream::OnChunkWritten should not be called!");
430
0
  return NS_ERROR_UNEXPECTED;
431
0
}
432
433
nsresult
434
CacheFileInputStream::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
435
                                       CacheFileChunk *aChunk)
436
0
{
437
0
  CacheFileAutoLock lock(mFile);
438
0
439
0
  LOG(("CacheFileInputStream::OnChunkAvailable() [this=%p, result=0x%08" PRIx32 ", "
440
0
       "idx=%d, chunk=%p]", this, static_cast<uint32_t>(aResult), aChunkIdx, aChunk));
441
0
442
0
  MOZ_ASSERT(mListeningForChunk != -1);
443
0
444
0
  if (mListeningForChunk != static_cast<int64_t>(aChunkIdx)) {
445
0
    // This is not a chunk that we're waiting for
446
0
    LOG(("CacheFileInputStream::OnChunkAvailable() - Notification is for a "
447
0
         "different chunk. [this=%p, listeningForChunk=%" PRId64 "]",
448
0
         this, mListeningForChunk));
449
0
450
0
    return NS_OK;
451
0
  }
452
0
453
0
  MOZ_ASSERT(!mChunk);
454
0
  MOZ_ASSERT(!mWaitingForUpdate);
455
0
  MOZ_ASSERT(!mInReadSegments);
456
0
  mListeningForChunk = -1;
457
0
458
0
  if (mClosed) {
459
0
    MOZ_ASSERT(!mCallback);
460
0
461
0
    LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, "
462
0
         "ignoring notification. [this=%p]", this));
463
0
464
0
    return NS_OK;
465
0
  }
466
0
467
0
  if (NS_SUCCEEDED(aResult)) {
468
0
    mChunk = aChunk;
469
0
  } else if (aResult != NS_ERROR_NOT_AVAILABLE) {
470
0
    // Close the stream with error. The consumer will receive this error later
471
0
    // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
472
0
    // differently since it is returned when the requested chunk is not
473
0
    // available and there is no writer that could create it, i.e. it means that
474
0
    // we've reached the end of the file.
475
0
    CloseWithStatusLocked(aResult);
476
0
477
0
    return NS_OK;
478
0
  }
479
0
480
0
  MaybeNotifyListener();
481
0
482
0
  return NS_OK;
483
0
}
484
485
nsresult
486
CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk)
487
0
{
488
0
  CacheFileAutoLock lock(mFile);
489
0
490
0
  LOG(("CacheFileInputStream::OnChunkUpdated() [this=%p, idx=%d]",
491
0
       this, aChunk->Index()));
492
0
493
0
  if (!mWaitingForUpdate) {
494
0
    LOG(("CacheFileInputStream::OnChunkUpdated() - Ignoring notification since "
495
0
         "mWaitingforUpdate == false. [this=%p]", this));
496
0
497
0
    return NS_OK;
498
0
  }
499
0
500
0
  mWaitingForUpdate = false;
501
0
502
0
  MOZ_ASSERT(mChunk == aChunk);
503
0
504
0
  MaybeNotifyListener();
505
0
506
0
  return NS_OK;
507
0
}
508
509
void
510
CacheFileInputStream::ReleaseChunk()
511
0
{
512
0
  mFile->AssertOwnsLock();
513
0
514
0
  LOG(("CacheFileInputStream::ReleaseChunk() [this=%p, idx=%d]",
515
0
       this, mChunk->Index()));
516
0
517
0
  MOZ_ASSERT(!mInReadSegments);
518
0
519
0
  if (mWaitingForUpdate) {
520
0
    LOG(("CacheFileInputStream::ReleaseChunk() - Canceling waiting for update. "
521
0
         "[this=%p]", this));
522
0
523
0
    mChunk->CancelWait(this);
524
0
    mWaitingForUpdate = false;
525
0
  }
526
0
527
0
  mFile->ReleaseOutsideLock(mChunk.forget());
528
0
}
529
530
void
531
CacheFileInputStream::EnsureCorrectChunk(bool aReleaseOnly)
532
0
{
533
0
  mFile->AssertOwnsLock();
534
0
535
0
  LOG(("CacheFileInputStream::EnsureCorrectChunk() [this=%p, releaseOnly=%d]",
536
0
       this, aReleaseOnly));
537
0
538
0
  nsresult rv;
539
0
540
0
  uint32_t chunkIdx = mPos / kChunkSize;
541
0
542
0
  if (mInReadSegments) {
543
0
    // We must have correct chunk
544
0
    MOZ_ASSERT(mChunk);
545
0
    MOZ_ASSERT(mChunk->Index() == chunkIdx);
546
0
    return;
547
0
  }
548
0
549
0
  if (mChunk) {
550
0
    if (mChunk->Index() == chunkIdx) {
551
0
      // we have a correct chunk
552
0
      LOG(("CacheFileInputStream::EnsureCorrectChunk() - Have correct chunk "
553
0
           "[this=%p, idx=%d]", this, chunkIdx));
554
0
555
0
      return;
556
0
    }
557
0
    ReleaseChunk();
558
0
  }
559
0
560
0
  MOZ_ASSERT(!mWaitingForUpdate);
561
0
562
0
  if (aReleaseOnly)
563
0
    return;
564
0
565
0
  if (mListeningForChunk == static_cast<int64_t>(chunkIdx)) {
566
0
    // We're already waiting for this chunk
567
0
    LOG(("CacheFileInputStream::EnsureCorrectChunk() - Already listening for "
568
0
         "chunk %" PRId64 " [this=%p]", mListeningForChunk, this));
569
0
570
0
    return;
571
0
  }
572
0
573
0
  rv = mFile->GetChunkLocked(chunkIdx, CacheFile::READER, this,
574
0
                             getter_AddRefs(mChunk));
575
0
  if (NS_FAILED(rv)) {
576
0
    LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. "
577
0
         "[this=%p, idx=%d, rv=0x%08" PRIx32 "]", this, chunkIdx,
578
0
         static_cast<uint32_t>(rv)));
579
0
    if (rv != NS_ERROR_NOT_AVAILABLE) {
580
0
      // Close the stream with error. The consumer will receive this error later
581
0
      // in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
582
0
      // differently since it is returned when the requested chunk is not
583
0
      // available and there is no writer that could create it, i.e. it means
584
0
      // that we've reached the end of the file.
585
0
      CloseWithStatusLocked(rv);
586
0
587
0
      return;
588
0
    }
589
0
  } else if (!mChunk) {
590
0
    mListeningForChunk = static_cast<int64_t>(chunkIdx);
591
0
  }
592
0
593
0
  MaybeNotifyListener();
594
0
}
595
596
int64_t
597
CacheFileInputStream::CanRead(CacheFileChunkReadHandle *aHandle)
598
0
{
599
0
  mFile->AssertOwnsLock();
600
0
601
0
  MOZ_ASSERT(mChunk);
602
0
  MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
603
0
604
0
  int64_t retval = aHandle->Offset() + aHandle->DataSize();
605
0
606
0
  if (!mAlternativeData && mFile->mAltDataOffset != -1 &&
607
0
      mFile->mAltDataOffset < retval) {
608
0
    retval = mFile->mAltDataOffset;
609
0
  }
610
0
611
0
  retval -= mPos;
612
0
  if (retval <= 0 && NS_FAILED(mChunk->GetStatus())) {
613
0
    CloseWithStatusLocked(mChunk->GetStatus());
614
0
  }
615
0
616
0
  LOG(("CacheFileInputStream::CanRead() [this=%p, canRead=%" PRId64 "]",
617
0
       this, retval));
618
0
619
0
  return retval;
620
0
}
621
622
void
623
CacheFileInputStream::NotifyListener()
624
0
{
625
0
  mFile->AssertOwnsLock();
626
0
627
0
  LOG(("CacheFileInputStream::NotifyListener() [this=%p]", this));
628
0
629
0
  MOZ_ASSERT(mCallback);
630
0
  MOZ_ASSERT(!mInReadSegments);
631
0
632
0
  if (!mCallbackTarget) {
633
0
    mCallbackTarget = CacheFileIOManager::IOTarget();
634
0
    if (!mCallbackTarget) {
635
0
      LOG(("CacheFileInputStream::NotifyListener() - Cannot get Cache I/O "
636
0
           "thread! Using main thread for callback."));
637
0
      mCallbackTarget = GetMainThreadEventTarget();
638
0
    }
639
0
  }
640
0
641
0
  nsCOMPtr<nsIInputStreamCallback> asyncCallback =
642
0
    NS_NewInputStreamReadyEvent("CacheFileInputStream::NotifyListener",
643
0
                                mCallback, mCallbackTarget);
644
0
645
0
  mCallback = nullptr;
646
0
  mCallbackTarget = nullptr;
647
0
648
0
  asyncCallback->OnInputStreamReady(this);
649
0
}
650
651
void
652
CacheFileInputStream::MaybeNotifyListener()
653
0
{
654
0
  mFile->AssertOwnsLock();
655
0
656
0
  LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, "
657
0
       "mClosed=%d, mStatus=0x%08" PRIx32 ", mChunk=%p, mListeningForChunk=%" PRId64 ", "
658
0
       "mWaitingForUpdate=%d]", this, mCallback.get(), mClosed,
659
0
       static_cast<uint32_t>(mStatus), mChunk.get(), mListeningForChunk,
660
0
       mWaitingForUpdate));
661
0
662
0
  MOZ_ASSERT(!mInReadSegments);
663
0
664
0
  if (!mCallback)
665
0
    return;
666
0
667
0
  if (mClosed || NS_FAILED(mStatus)) {
668
0
    NotifyListener();
669
0
    return;
670
0
  }
671
0
672
0
  if (!mChunk) {
673
0
    if (mListeningForChunk == -1) {
674
0
      // EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ??
675
0
      NotifyListener();
676
0
    }
677
0
    return;
678
0
  }
679
0
680
0
  MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
681
0
682
0
  if (mWaitingForUpdate)
683
0
    return;
684
0
685
0
  CacheFileChunkReadHandle hnd = mChunk->GetReadHandle();
686
0
  int64_t canRead = CanRead(&hnd);
687
0
  if (NS_FAILED(mStatus)) {
688
0
    // CanRead() called CloseWithStatusLocked() which called
689
0
    // MaybeNotifyListener() so the listener was already notified. Stop here.
690
0
    MOZ_ASSERT(!mCallback);
691
0
    return;
692
0
  }
693
0
694
0
  if (canRead > 0) {
695
0
    if (!(mCallbackFlags & WAIT_CLOSURE_ONLY))
696
0
      NotifyListener();
697
0
  }
698
0
  else if (canRead == 0) {
699
0
    if (!mFile->OutputStreamExists(mAlternativeData)) {
700
0
      // EOF
701
0
      NotifyListener();
702
0
    }
703
0
    else {
704
0
      mChunk->WaitForUpdate(this);
705
0
      mWaitingForUpdate = true;
706
0
    }
707
0
  }
708
0
  else {
709
0
    // Output have set EOF before mPos?
710
0
    MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
711
0
    NotifyListener();
712
0
  }
713
0
}
714
715
// Memory reporting
716
717
size_t
718
CacheFileInputStream::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
719
0
{
720
0
  // Everything the stream keeps a reference to is already reported somewhere else.
721
0
  // mFile reports itself.
722
0
  // mChunk reported as part of CacheFile.
723
0
  // mCallback is usually CacheFile or a class that is reported elsewhere.
724
0
  return mallocSizeOf(this);
725
0
}
726
727
} // namespace net
728
} // namespace mozilla