diff --git a/dom/file/ipc/IPCBlobInputStream.cpp b/dom/file/ipc/IPCBlobInputStream.cpp index 384c2660298f..668f801eec6e 100644 --- a/dom/file/ipc/IPCBlobInputStream.cpp +++ b/dom/file/ipc/IPCBlobInputStream.cpp @@ -431,16 +431,26 @@ IPCBlobInputStream::AsyncWait(nsIInputStreamCallback* aCallback, break; } - // Stream is closed. + case eClosed: + [[fallthrough]]; default: MOZ_ASSERT(mState == eClosed); - return NS_BASE_STREAM_CLOSED; + if (mInputStreamCallback && aCallback) { + return NS_ERROR_FAILURE; + } + break; } } - MOZ_ASSERT(asyncRemoteStream); - return asyncRemoteStream->AsyncWait(aCallback ? this : nullptr, 0, 0, - aEventTarget); + if (asyncRemoteStream) { + return asyncRemoteStream->AsyncWait(aCallback ? this : nullptr, 0, 0, + aEventTarget); + } + + // if asyncRemoteStream is nullptr here, that probably means the stream has + // been closed and the callback can be executed immediately + InputStreamCallbackRunnable::Execute(aCallback, aEventTarget, this); + return NS_OK; } void IPCBlobInputStream::StreamReady( @@ -803,38 +813,6 @@ IPCBlobInputStream::Length(int64_t* aLength) { return NS_BASE_STREAM_WOULD_BLOCK; } -// nsIAsyncInputStreamLength - -NS_IMETHODIMP -IPCBlobInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback, - nsIEventTarget* aEventTarget) { - MutexAutoLock lock(mMutex); - - if (mState == eClosed) { - return NS_BASE_STREAM_CLOSED; - } - - if (mConsumed) { - return NS_ERROR_NOT_AVAILABLE; - } - - // If we have the callback, we must have the event target. - if (NS_WARN_IF(!!aCallback != !!aEventTarget)) { - return NS_ERROR_FAILURE; - } - - MOZ_ASSERT(mActor); - - mLengthCallback = aCallback; - mLengthCallbackEventTarget = aEventTarget; - - if (aCallback) { - mActor->LengthNeeded(this, aEventTarget); - } - - return NS_OK; -} - namespace { class InputStreamLengthCallbackRunnable final : public CancelableRunnable { @@ -879,6 +857,39 @@ class InputStreamLengthCallbackRunnable final : public CancelableRunnable { } // namespace +// nsIAsyncInputStreamLength + +NS_IMETHODIMP +IPCBlobInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback, + nsIEventTarget* aEventTarget) { + // If we have the callback, we must have the event target. + if (NS_WARN_IF(!!aCallback != !!aEventTarget)) { + return NS_ERROR_FAILURE; + } + + { + MutexAutoLock lock(mMutex); + + mLengthCallback = aCallback; + mLengthCallbackEventTarget = aEventTarget; + + if (mState != eClosed && !mConsumed) { + MOZ_ASSERT(mActor); + + if (aCallback) { + mActor->LengthNeeded(this, aEventTarget); + } + + return NS_OK; + } + } + + // If execution has reached here, it means the stream is either closed or + // consumed, and therefore the callback can be executed immediately + InputStreamLengthCallbackRunnable::Execute(aCallback, aEventTarget, this, -1); + return NS_OK; +} + void IPCBlobInputStream::LengthReady(int64_t aLength) { nsCOMPtr lengthCallback; nsCOMPtr lengthCallbackEventTarget; @@ -886,19 +897,20 @@ void IPCBlobInputStream::LengthReady(int64_t aLength) { { MutexAutoLock lock(mMutex); - // We have been closed in the meantime. + // Stream has been closed in the meantime. Callback can be executed + // immediately if (mState == eClosed || mConsumed) { - return; - } + aLength = -1; + } else { + if (mStart > 0) { + aLength -= mStart; + } - if (mStart > 0) { - aLength -= mStart; - } - - if (mLength < mActor->Size()) { - // If the remote stream must be sliced, we must return here the correct - // value. - aLength = XPCOM_MIN(aLength, (int64_t)mLength); + if (mLength < mActor->Size()) { + // If the remote stream must be sliced, we must return here the correct + // value. + aLength = XPCOM_MIN(aLength, (int64_t)mLength); + } } lengthCallback.swap(mLengthCallback);