tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CacheFileInputStream.cpp (19571B)


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