Files
palemoon27/netwerk/cache2/CacheFileInputStream.cpp
T
roytam1 4b8580917e import changes from `dev' branch of rmottola/Arctic-Fox:
- some pref. cleanup (21e17660e7)
- add some font names and aliases (cb38962246)
- remove unused dom.max_child_script_run_time (d214b353d4)
- align strange layout.css.scroll-snap.enabled overwrite (f2562a5cc1)
- reshuffle some preferences, remove unused (41f586186b)
- more reshuffle and cleanup of preferences (0208aa32a3)
- Bug 1168891 Part 1 - Refine two functions related to caret positioning. r=mats (86d718d60e)
- Bug 1168891 Part 2 - Allow one caret to be dragged across the other caret. r=mats (9276eb7728)
- part of Bug 1252802 - Web page scrolls when dragging caret in editable, r=snorp (31dade8b77)
- Bug 1235508 - Re-implement fast Phone number selection on long-press, r=TYLin (59b6371d17)
- Bug 1249201 Part 1 - Add "scroll" reason to CaretStateChangedEvent. r=smaug (b92ff6cbfc)
- Bug 1249201 Part 2 - Show carets continuously when panning or zooming. r=mats,sebastian (ca5c51c479)
- Bug 1245246: Add null check for mDocViewerPrint in nsPrintEngine::FirePrintingErrorEvent. r=roc (e9d5b49a3f)
- Bug 1025267 - Make some -moz- prefixed pseudo-classes chrome-only. r=bz (238f7a85d4)
- Bug 1259889 Part 1 - Add @supports -moz-bool-pref for internal-only style sheets. r=heycam (d716a7b884)
- Bug 1237633 - Part 1: Percentages are not allowed in a <source-size-value>. r=jdm (52ccffbf86)
- Bug 1081362 - Change nsStyleBasicShape pointer to an nsRefPtr, to avoid leak in unexpected case. r=dholbert (2a5cb8ffdd)
- Bug 1264317 - Make the basic shape clip-path clipping use nsCSSValue::Array instead of nsCSSValueList. r=dholbert (7aaf39f2d7)
- Bug 1247150 - Consistently use StyleSheetHandle::RefPtr* for outparams in nsLayoutStylesheetCache. r=dholbert (ddc85f29f8)
- Bug 1251848: Check StyleSheetHandles for being null-flavored before derefing them, in assertions within nsLayoutStylesheetCache::InvalidateSheet. r=bholley (edb3924075)
- Bug 1245260 - Add crashtest; r=hiro (6347e37750)
- Bug 460209 - Add crashtest. (97b4786de2)
- Bug 474377 - Add crashtest. (516b4e8164)
- Bug 1264396 - Don't allow animation of 'display' property; r=heycam (6e94bcb26a)
- missing bit of  759568 - Part 1 (fc954f075b)
- part of Bug 1037483 replace microdata with microformats (4ff01e11d6)
- Bug 1245334 - Make PromiseMessage.jsm ids more meaningful. r=baku (913ac1b9a5)
- Bug 1094201 - Implement an Integration.jsm module for low-overhead registration of overrides. r=mak (9982624b90)
- Bug 1167663 - Mark nsCSSKeyframeStyleDeclaration/nsCSSPageStyleDeclaration::mRule as MOZ_NON_OWNING_REF. r=dbaron (6d4e9751a1)
- Bug 1244992 - Avoid double-counting in various refcounted types related to nsCSSValue. r=heycam. (c830949dd9)
- Bug 1262646 - Change the outparams passed to nsStyleUtil::AppendEscapedCSSString from nsString to nsAutoString. r=dholbert (2b0caadf9d)
- Bug 1247336 - De-dupe changes in ActiveLayerTracker before treating property as animated. r=roc (c44ed5aee6)
- space fix (5e79d245ea)
- Bug 1266288 - Track changes to all margin properties for scroll-linked effects. r=mstange (fed6994e4d)
- Bug 1259641 - Do not force reflow for all tabs when size mode changed. r=smaug (70847cc6d2)
- Bug 1261265 - Fix nsStyleContext::MoveTo flag assertions to allow mismatch on parents if bit is set on child. r=dholbert (3e6b08372e)
- Bug 1264837 Part 43 - Remove SVGFEUnstyledLeafFrameBase. r=dholbert (bb55feda77)
- Remove mention of old SVG text pref in comment; no bug. (DONTBUILD) (3a618aca18)
- Bug 752638, part 1 - Move SVGTextFrame::SetupContextPaint to nsSVGUtils. r=heycam (c125c2903f)
- Bug 1258843 - Don't build SVG display items if their visibility is hidden. r=dholbert (150c3b0059)
- Bug 1258650. Properly use aExtraMasksTransform when combining masks. r=Bas,a=kwierso (ba5ea1928b)
- Bug 1263789 - Stop nsSVGMaskFrameNEON.h from polluting the global namespace. r=dholbert (e2c8544d35)
- Bug 1162418 - Try to find a suitable non-zero dimension to use when containing block's inline-size depends on an SVG element which is specified as a percentage of its container. r=jwatt (3eab79c8a4)
- Bug 1250143. Account for border/padding on outer <svg> elements in GeometryUtils. r=mats (f307820b75)
- Bug 1243623. Don't skip unregistering a table part if we have a split table. r=mats (35bb0821c1)
- Bug 1203417. Propagate error result from PaintTableFrame. r=seth (866e47b3e4)
- Bug 1209780. Propagate the use of MOZ_MUST_USE DrawResult in nsTablePainter. r=seth (851618d06c)
- var-const (29d5e9f859)
- Bug 1209780. Propagate the use of MOZ_MUST_USE DrawResult in nsTreeBodyFrame::PaintText. r=seth (1ce563ea18)
- Bug 1203626 - remove the unused argument from nsTreeBodyFrame::GetTwistyRect. r=mattwoodrow (03293f52b5)
- Bug 1218041, part 1: Give nsTreeBodyFrame::PaintImage a fallback codepath for painting SVG images with no explicit height or width. r=seth (b6fd3a39f7)
- Bug 1218041, part 2: add reftests for <treecell> SVG-image rendering. (no review) (90231e0bfa)
- Bug 1224736: When image size lookup fails in nsTreeBodyFrame::PaintImage, only fall back to use the full destRect if we've got a VectorImage. r=tn (dd7d7667ca)
- Bug 1156108 - Make nsTreeColumns::mFirstColumn an nsRefPtr; r=roc (f6888480bc)
- Bug 1255069 - use UniquePtr for storage in nsTreeContentView; r=dholbert (598256735f)
- Bug 1181560 - ensure previous menus get closed when opening new ones, r=Enn (2c88f3452a)
- Bug 1192655 - Make menubar not react to events when it is not visible. r=enn (2bbcbc81a2)
- Bug 1197913 - Keep the last hovered item highlighted after moving the cursor outside the <select> drop-down list on Windows. r=neil (abd3240473)
- Bug 1228029 - Fix the usage of gtest assertion macros in TestJobScheduler.cpp. r=kats (0fcc9aa6fe)
- Bug 1244234 - Simplify joining jobs with the gfx job scheduler. r=jrmuizel (f4b6bbf418)
- Bug 1239288 - Add a shutdown test to the gfx job scheduler. r=jrmuizel (fd2432d108)
- Bug 1239288 - Fix a race in the win32 job scheduler's shutdown. r=jrmuizel (4e509b4bf3)
- Bug 1241161 - make Matrix4x4::ProjectTo2D normalize out perpective where possible. r=mattwoodrow (5a68e396a3)
- bits of  Bug 1135138 - Remove UNICODE from DEFINES (1eb51a0a79)
- Bug 1249640: Part 4 Android to use new blocking. r=snorp (855e5c0dda)
- Bug 1234875 - Remove alwaysAcceptSessionCookies pref. r=mak (8bed323449)
- Bug 1247912 - convert left side expression to int64_t when assigning to mCookiesLifetimeSec in order to avoid overflow. r=jdm (0cedb68c83)
- code and comment style (9215d74a8f)
- code and comment style (1d4cda31af)
- Bug 1219928 - Skip misspelled words in style blocks. r=enndeakin. (91dd0bcedf)
- Bug 1236968 - autodial telemetry r=mayhemer (3844b9c19e)
- Bug 1254310 - Add a hidden pref to temporarily disable Safe Browsing on given hostnames. r=gcp (4955fc88f8)
- Bug 772528 - Remove nsFileInputStream::Seek() from nsPartialFileInputStream::Init(). r=baku (15db900fb5)
- Bug 1150921 - Add telemetry for response codes to SafeBrowsing requests. r=francois f=bsmedberg (215d50e4ad)
- Bug 1164518 - Better logging of completions. r=gcp (95b4fe3731)
- Bug 1172688 - Add telemetry for when gethash calls timeout. r=francois, r=bsmedberg (b94a2b38a7)
- Bug 1266184 - Implement nsIMIMEInputStream.data getter. r=mcmanus (8c9159c030)
- Bug 1239955 - Let DNSService rely on IOService::Offline, r=bagder (336f161d21)
- Bug 1260407 - added logging for proxy/pac to aid debugging, r=mcmanus (a179275ca6)
- Bug 1259089 - Set TCP socket to non-blocking in sts again, just to be sure. r=mcmanus (bf0656bf07)
- Bug 1256473 - Cast values to avoid C4838 on VS2015; r=mayhemer (d4b138dba8)
- Bug 1260764 - Creation of PollableEvent needs a lock r=dragana a=kwierso (01c9d5e477)
- Bug 652186 - Implement URL Standard's backslash replacement r=mcmanus (6485fa7e8c)
- Bug 1042347 - %2e entered in URL bar not normalized leading to denormalized request r=mcmanus (3fc1ff92cd)
- Bug 377052 - nsBaseURLParser::ParseURL doesn't handle spaces embedded in the scheme properly r=mcmanus (1f54055b9d)
- fix editor format (444d6a62c4)
- Bug 1154124 - Prevent recursion when calling HTTP cache entry's callbacks. r=michal (7bdfbf603d)
- Bug 1247644 - Don't do any I/O on doomed and unused HTTP cache entries, r=michal (7668d29a36)
2024-08-07 16:47:10 +08:00

639 lines
15 KiB
C++

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CacheLog.h"
#include "CacheFileInputStream.h"
#include "CacheFile.h"
#include "nsStreamUtils.h"
#include "nsThreadUtils.h"
#include <algorithm>
namespace mozilla {
namespace net {
NS_IMPL_ADDREF(CacheFileInputStream)
NS_IMETHODIMP_(MozExternalRefCountType)
CacheFileInputStream::Release()
{
NS_PRECONDITION(0 != mRefCnt, "dup release");
nsrefcnt count = --mRefCnt;
NS_LOG_RELEASE(this, count, "CacheFileInputStream");
if (0 == count) {
mRefCnt = 1;
delete (this);
return 0;
}
if (count == 1) {
mFile->RemoveInput(this, mStatus);
}
return count;
}
NS_INTERFACE_MAP_BEGIN(CacheFileInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY(mozilla::net::CacheFileChunkListener)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END_THREADSAFE
CacheFileInputStream::CacheFileInputStream(CacheFile *aFile, nsISupports *aEntry)
: mFile(aFile)
, mPos(0)
, mClosed(false)
, mStatus(NS_OK)
, mWaitingForUpdate(false)
, mListeningForChunk(-1)
, mCallbackFlags(0)
, mCacheEntryHandle(aEntry)
{
LOG(("CacheFileInputStream::CacheFileInputStream() [this=%p]", this));
MOZ_COUNT_CTOR(CacheFileInputStream);
}
CacheFileInputStream::~CacheFileInputStream()
{
LOG(("CacheFileInputStream::~CacheFileInputStream() [this=%p]", this));
MOZ_COUNT_DTOR(CacheFileInputStream);
}
// nsIInputStream
NS_IMETHODIMP
CacheFileInputStream::Close()
{
LOG(("CacheFileInputStream::Close() [this=%p]", this));
return CloseWithStatus(NS_OK);
}
NS_IMETHODIMP
CacheFileInputStream::Available(uint64_t *_retval)
{
CacheFileAutoLock lock(mFile);
if (mClosed) {
LOG(("CacheFileInputStream::Available() - Stream is closed. [this=%p, "
"status=0x%08x]", this, mStatus));
return NS_FAILED(mStatus) ? mStatus : NS_BASE_STREAM_CLOSED;
}
EnsureCorrectChunk(false);
if (NS_FAILED(mStatus))
return mStatus;
*_retval = 0;
if (mChunk) {
int64_t canRead = mFile->BytesFromChunk(mChunk->Index());
canRead -= (mPos % kChunkSize);
if (canRead > 0)
*_retval = canRead;
else if (canRead == 0 && !mFile->mOutput)
return NS_BASE_STREAM_CLOSED;
}
LOG(("CacheFileInputStream::Available() [this=%p, retval=%lld]",
this, *_retval));
return NS_OK;
}
NS_IMETHODIMP
CacheFileInputStream::Read(char *aBuf, uint32_t aCount, uint32_t *_retval)
{
LOG(("CacheFileInputStream::Read() [this=%p, count=%d]", this, aCount));
return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, _retval);
}
NS_IMETHODIMP
CacheFileInputStream::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
uint32_t aCount, uint32_t *_retval)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::ReadSegments() [this=%p, count=%d]",
this, aCount));
nsresult rv;
*_retval = 0;
if (mClosed) {
LOG(("CacheFileInputStream::ReadSegments() - Stream is closed. [this=%p, "
"status=0x%08x]", this, mStatus));
if NS_FAILED(mStatus)
return mStatus;
return NS_OK;
}
EnsureCorrectChunk(false);
while (true) {
if (NS_FAILED(mStatus))
return mStatus;
if (!mChunk) {
if (mListeningForChunk == -1) {
return NS_OK;
}
else {
return NS_BASE_STREAM_WOULD_BLOCK;
}
}
int64_t canRead;
const char *buf;
CanRead(&canRead, &buf);
if (NS_FAILED(mStatus)) {
return mStatus;
}
if (canRead < 0) {
// file was truncated ???
MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
rv = NS_OK;
} else if (canRead > 0) {
uint32_t toRead = std::min(static_cast<uint32_t>(canRead), aCount);
uint32_t read;
rv = aWriter(this, aClosure, buf, *_retval, toRead, &read);
if (NS_SUCCEEDED(rv)) {
MOZ_ASSERT(read <= toRead,
"writer should not write more than we asked it to write");
*_retval += read;
mPos += read;
aCount -= read;
// The last chunk is released after the caller closes this stream.
EnsureCorrectChunk(false);
if (mChunk && aCount) {
// We have the next chunk! Go on.
continue;
}
}
rv = NS_OK;
} else {
if (mFile->mOutput)
rv = NS_BASE_STREAM_WOULD_BLOCK;
else {
rv = NS_OK;
}
}
break;
}
LOG(("CacheFileInputStream::ReadSegments() [this=%p, rv=0x%08x, retval=%d]",
this, rv, *_retval));
return rv;
}
NS_IMETHODIMP
CacheFileInputStream::IsNonBlocking(bool *_retval)
{
*_retval = true;
return NS_OK;
}
// nsIAsyncInputStream
NS_IMETHODIMP
CacheFileInputStream::CloseWithStatus(nsresult aStatus)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::CloseWithStatus() [this=%p, aStatus=0x%08x]",
this, aStatus));
return CloseWithStatusLocked(aStatus);
}
nsresult
CacheFileInputStream::CloseWithStatusLocked(nsresult aStatus)
{
LOG(("CacheFileInputStream::CloseWithStatusLocked() [this=%p, "
"aStatus=0x%08x]", this, aStatus));
if (mClosed) {
MOZ_ASSERT(!mCallback);
return NS_OK;
}
mClosed = true;
mStatus = NS_FAILED(aStatus) ? aStatus : NS_BASE_STREAM_CLOSED;
if (mChunk) {
ReleaseChunk();
}
// TODO propagate error from input stream to other streams ???
MaybeNotifyListener();
mFile->ReleaseOutsideLock(mCacheEntryHandle.forget());
return NS_OK;
}
NS_IMETHODIMP
CacheFileInputStream::AsyncWait(nsIInputStreamCallback *aCallback,
uint32_t aFlags,
uint32_t aRequestedCount,
nsIEventTarget *aEventTarget)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::AsyncWait() [this=%p, callback=%p, flags=%d, "
"requestedCount=%d, eventTarget=%p]", this, aCallback, aFlags,
aRequestedCount, aEventTarget));
mCallback = aCallback;
mCallbackFlags = aFlags;
mCallbackTarget = aEventTarget;
if (!mCallback) {
if (mWaitingForUpdate) {
mChunk->CancelWait(this);
mWaitingForUpdate = false;
}
return NS_OK;
}
if (mClosed) {
NotifyListener();
return NS_OK;
}
EnsureCorrectChunk(false);
MaybeNotifyListener();
return NS_OK;
}
// nsISeekableStream
NS_IMETHODIMP
CacheFileInputStream::Seek(int32_t whence, int64_t offset)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::Seek() [this=%p, whence=%d, offset=%lld]",
this, whence, offset));
if (mClosed) {
LOG(("CacheFileInputStream::Seek() - Stream is closed. [this=%p]", this));
return NS_BASE_STREAM_CLOSED;
}
int64_t newPos = offset;
switch (whence) {
case NS_SEEK_SET:
break;
case NS_SEEK_CUR:
newPos += mPos;
break;
case NS_SEEK_END:
newPos += mFile->mDataSize;
break;
default:
NS_ERROR("invalid whence");
return NS_ERROR_INVALID_ARG;
}
mPos = newPos;
EnsureCorrectChunk(false);
LOG(("CacheFileInputStream::Seek() [this=%p, pos=%lld]", this, mPos));
return NS_OK;
}
NS_IMETHODIMP
CacheFileInputStream::Tell(int64_t *_retval)
{
CacheFileAutoLock lock(mFile);
if (mClosed) {
LOG(("CacheFileInputStream::Tell() - Stream is closed. [this=%p]", this));
return NS_BASE_STREAM_CLOSED;
}
*_retval = mPos;
LOG(("CacheFileInputStream::Tell() [this=%p, retval=%lld]", this, *_retval));
return NS_OK;
}
NS_IMETHODIMP
CacheFileInputStream::SetEOF()
{
MOZ_ASSERT(false, "Don't call SetEOF on cache input stream");
return NS_ERROR_NOT_IMPLEMENTED;
}
// CacheFileChunkListener
nsresult
CacheFileInputStream::OnChunkRead(nsresult aResult, CacheFileChunk *aChunk)
{
MOZ_CRASH("CacheFileInputStream::OnChunkRead should not be called!");
return NS_ERROR_UNEXPECTED;
}
nsresult
CacheFileInputStream::OnChunkWritten(nsresult aResult, CacheFileChunk *aChunk)
{
MOZ_CRASH("CacheFileInputStream::OnChunkWritten should not be called!");
return NS_ERROR_UNEXPECTED;
}
nsresult
CacheFileInputStream::OnChunkAvailable(nsresult aResult, uint32_t aChunkIdx,
CacheFileChunk *aChunk)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::OnChunkAvailable() [this=%p, result=0x%08x, "
"idx=%d, chunk=%p]", this, aResult, aChunkIdx, aChunk));
MOZ_ASSERT(mListeningForChunk != -1);
if (mListeningForChunk != static_cast<int64_t>(aChunkIdx)) {
// This is not a chunk that we're waiting for
LOG(("CacheFileInputStream::OnChunkAvailable() - Notification is for a "
"different chunk. [this=%p, listeningForChunk=%lld]",
this, mListeningForChunk));
return NS_OK;
}
MOZ_ASSERT(!mChunk);
MOZ_ASSERT(!mWaitingForUpdate);
mListeningForChunk = -1;
if (mClosed) {
MOZ_ASSERT(!mCallback);
LOG(("CacheFileInputStream::OnChunkAvailable() - Stream is closed, "
"ignoring notification. [this=%p]", this));
return NS_OK;
}
if (NS_SUCCEEDED(aResult)) {
mChunk = aChunk;
} else if (aResult != NS_ERROR_NOT_AVAILABLE) {
// Close the stream with error. The consumer will receive this error later
// in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
// differently since it is returned when the requested chunk is not
// available and there is no writer that could create it, i.e. it means that
// we've reached the end of the file.
CloseWithStatusLocked(aResult);
return NS_OK;
}
MaybeNotifyListener();
return NS_OK;
}
nsresult
CacheFileInputStream::OnChunkUpdated(CacheFileChunk *aChunk)
{
CacheFileAutoLock lock(mFile);
LOG(("CacheFileInputStream::OnChunkUpdated() [this=%p, idx=%d]",
this, aChunk->Index()));
if (!mWaitingForUpdate) {
LOG(("CacheFileInputStream::OnChunkUpdated() - Ignoring notification since "
"mWaitingforUpdate == false. [this=%p]", this));
return NS_OK;
}
else {
mWaitingForUpdate = false;
}
MOZ_ASSERT(mChunk == aChunk);
MaybeNotifyListener();
return NS_OK;
}
void
CacheFileInputStream::ReleaseChunk()
{
mFile->AssertOwnsLock();
LOG(("CacheFileInputStream::ReleaseChunk() [this=%p, idx=%d]",
this, mChunk->Index()));
if (mWaitingForUpdate) {
LOG(("CacheFileInputStream::ReleaseChunk() - Canceling waiting for update. "
"[this=%p]", this));
mChunk->CancelWait(this);
mWaitingForUpdate = false;
}
mFile->ReleaseOutsideLock(mChunk.forget());
}
void
CacheFileInputStream::EnsureCorrectChunk(bool aReleaseOnly)
{
mFile->AssertOwnsLock();
LOG(("CacheFileInputStream::EnsureCorrectChunk() [this=%p, releaseOnly=%d]",
this, aReleaseOnly));
nsresult rv;
uint32_t chunkIdx = mPos / kChunkSize;
if (mChunk) {
if (mChunk->Index() == chunkIdx) {
// we have a correct chunk
LOG(("CacheFileInputStream::EnsureCorrectChunk() - Have correct chunk "
"[this=%p, idx=%d]", this, chunkIdx));
return;
}
else {
ReleaseChunk();
}
}
MOZ_ASSERT(!mWaitingForUpdate);
if (aReleaseOnly)
return;
if (mListeningForChunk == static_cast<int64_t>(chunkIdx)) {
// We're already waiting for this chunk
LOG(("CacheFileInputStream::EnsureCorrectChunk() - Already listening for "
"chunk %lld [this=%p]", mListeningForChunk, this));
return;
}
rv = mFile->GetChunkLocked(chunkIdx, CacheFile::READER, this,
getter_AddRefs(mChunk));
if (NS_FAILED(rv)) {
LOG(("CacheFileInputStream::EnsureCorrectChunk() - GetChunkLocked failed. "
"[this=%p, idx=%d, rv=0x%08x]", this, chunkIdx, rv));
if (rv != NS_ERROR_NOT_AVAILABLE) {
// Close the stream with error. The consumer will receive this error later
// in Read(), Available() etc. We need to handle NS_ERROR_NOT_AVAILABLE
// differently since it is returned when the requested chunk is not
// available and there is no writer that could create it, i.e. it means
// that we've reached the end of the file.
CloseWithStatusLocked(rv);
return;
}
} else if (!mChunk) {
mListeningForChunk = static_cast<int64_t>(chunkIdx);
}
MaybeNotifyListener();
}
void
CacheFileInputStream::CanRead(int64_t *aCanRead, const char **aBuf)
{
mFile->AssertOwnsLock();
MOZ_ASSERT(mChunk);
MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
uint32_t chunkOffset = mPos - (mPos / kChunkSize) * kChunkSize;
*aCanRead = mChunk->DataSize() - chunkOffset;
if (*aCanRead > 0) {
*aBuf = mChunk->BufForReading() + chunkOffset;
} else {
*aBuf = nullptr;
if (NS_FAILED(mChunk->GetStatus())) {
CloseWithStatusLocked(mChunk->GetStatus());
}
}
LOG(("CacheFileInputStream::CanRead() [this=%p, canRead=%lld]",
this, *aCanRead));
}
void
CacheFileInputStream::NotifyListener()
{
mFile->AssertOwnsLock();
LOG(("CacheFileInputStream::NotifyListener() [this=%p]", this));
MOZ_ASSERT(mCallback);
if (!mCallbackTarget) {
mCallbackTarget = CacheFileIOManager::IOTarget();
if (!mCallbackTarget) {
LOG(("CacheFileInputStream::NotifyListener() - Cannot get Cache I/O "
"thread! Using main thread for callback."));
mCallbackTarget = do_GetMainThread();
}
}
nsCOMPtr<nsIInputStreamCallback> asyncCallback =
NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget);
mCallback = nullptr;
mCallbackTarget = nullptr;
asyncCallback->OnInputStreamReady(this);
}
void
CacheFileInputStream::MaybeNotifyListener()
{
mFile->AssertOwnsLock();
LOG(("CacheFileInputStream::MaybeNotifyListener() [this=%p, mCallback=%p, "
"mClosed=%d, mStatus=0x%08x, mChunk=%p, mListeningForChunk=%lld, "
"mWaitingForUpdate=%d]", this, mCallback.get(), mClosed, mStatus,
mChunk.get(), mListeningForChunk, mWaitingForUpdate));
if (!mCallback)
return;
if (mClosed || NS_FAILED(mStatus)) {
NotifyListener();
return;
}
if (!mChunk) {
if (mListeningForChunk == -1) {
// EOF, should we notify even if mCallbackFlags == WAIT_CLOSURE_ONLY ??
NotifyListener();
}
return;
}
MOZ_ASSERT(mPos / kChunkSize == mChunk->Index());
if (mWaitingForUpdate)
return;
int64_t canRead;
const char *buf;
CanRead(&canRead, &buf);
if (NS_FAILED(mStatus)) {
// CanRead() called CloseWithStatusLocked() which called
// MaybeNotifyListener() so the listener was already notified. Stop here.
MOZ_ASSERT(!mCallback);
return;
}
if (canRead > 0) {
if (!(mCallbackFlags & WAIT_CLOSURE_ONLY))
NotifyListener();
}
else if (canRead == 0) {
if (!mFile->mOutput) {
// EOF
NotifyListener();
}
else {
mChunk->WaitForUpdate(this);
mWaitingForUpdate = true;
}
}
else {
// Output have set EOF before mPos?
MOZ_ASSERT(false, "SetEOF is currenty not implemented?!");
NotifyListener();
}
}
// Memory reporting
size_t
CacheFileInputStream::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
{
// Everything the stream keeps a reference to is already reported somewhere else.
// mFile reports itself.
// mChunk reported as part of CacheFile.
// mCallback is usually CacheFile or a class that is reported elsewhere.
return mallocSizeOf(this);
}
} // namespace net
} // namespace mozilla