LCOV - code coverage report
Current view: top level - netwerk/cache2 - CacheFileInputStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 220 329 66.9 %
Date: 2017-07-14 16:53:18 Functions: 23 28 82.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13