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