/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */ /** * The multiplex stream concatenates a list of input streams into a single * stream. */ #ifndef _nsMultiplexInputStream_h_ #define _nsMultiplexInputStream_h_ #include "nsIBufferedStreams.h" #include "nsICloneableInputStream.h" #include "nsIMultiplexInputStream.h" #include "nsISeekableStream.h" #include "nsCOMPtr.h" #include "nsIIPCSerializableInputStream.h" #include "mozilla/ipc/InputStreamUtils.h" #include "nsIAsyncInputStream.h" #include "nsIInputStreamLength.h" #include "nsNetUtil.h" #include "nsStreamUtils.h" #define NS_MULTIPLEXINPUTSTREAM_CONTRACTID \ "@mozilla.org/io/multiplex-input-stream;1" #define NS_MULTIPLEXINPUTSTREAM_CID \ {/* 565e3a2c-1dd2-11b2-8da1-b4cef17e568d */ \ 0x565e3a2c, \ 0x1dd2, \ 0x11b2, \ {0x8d, 0xa1, 0xb4, 0xce, 0xf1, 0x7e, 0x56, 0x8d}} extern nsresult nsMultiplexInputStreamConstructor(REFNSIID aIID, void** aResult); namespace mozilla { class nsMultiplexInputStream final : public nsIMultiplexInputStream, public nsISeekableStream, public nsIIPCSerializableInputStream, public nsICloneableInputStream, public nsIAsyncInputStream, public nsIInputStreamCallback, public nsIInputStreamLength, public nsIAsyncInputStreamLength { public: nsMultiplexInputStream(); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINPUTSTREAM NS_DECL_NSIMULTIPLEXINPUTSTREAM NS_DECL_NSISEEKABLESTREAM NS_DECL_NSITELLABLESTREAM NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM NS_DECL_NSICLONEABLEINPUTSTREAM NS_DECL_NSIASYNCINPUTSTREAM NS_DECL_NSIINPUTSTREAMCALLBACK NS_DECL_NSIINPUTSTREAMLENGTH NS_DECL_NSIASYNCINPUTSTREAMLENGTH // This is used for nsIAsyncInputStream::AsyncWait void AsyncWaitCompleted(); // This is used for nsIAsyncInputStreamLength::AsyncLengthWait void AsyncWaitCompleted(int64_t aLength, const MutexAutoLock& aProofOfLock) MOZ_REQUIRES(mLock); struct StreamData { nsresult Initialize(nsIInputStream* aOriginalStream) { mCurrentPos = 0; mOriginalStream = aOriginalStream; mBufferedStream = aOriginalStream; if (!NS_InputStreamIsBuffered(mBufferedStream)) { nsCOMPtr bufferedStream; nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), mBufferedStream.forget(), 4096); NS_ENSURE_SUCCESS(rv, rv); mBufferedStream = bufferedStream; } mAsyncStream = do_QueryInterface(mBufferedStream); mSeekableStream = do_QueryInterface(mBufferedStream); return NS_OK; } nsCOMPtr mOriginalStream; // Equal to mOriginalStream or a wrap around the original stream to make it // buffered. nsCOMPtr mBufferedStream; // This can be null. nsCOMPtr mAsyncStream; // This can be null. nsCOMPtr mSeekableStream; uint64_t mCurrentPos; }; Mutex& GetLock() MOZ_RETURN_CAPABILITY(mLock) { return mLock; } private: ~nsMultiplexInputStream() = default; void NextStream() MOZ_REQUIRES(mLock) { ++mCurrentStream; mStartedReadingCurrent = false; } nsresult AsyncWaitInternal(); // This method updates mSeekableStreams, mTellableStreams, // mIPCSerializableStreams and mCloneableStreams values. void UpdateQIMap(StreamData& aStream) MOZ_REQUIRES(mLock); struct MOZ_STACK_CLASS ReadSegmentsState { nsCOMPtr mThisStream; uint32_t mOffset; nsWriteSegmentFun mWriter; void* mClosure; bool mDone; }; void SerializedComplexityInternal(uint32_t aMaxSize, uint32_t* aSizeUsed, uint32_t* aPipes, uint32_t* aTransferables, bool* aSerializeAsPipe); static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure, const char* aFromRawSegment, uint32_t aToOffset, uint32_t aCount, uint32_t* aWriteCount); bool IsSeekable() const; bool IsIPCSerializable() const; bool IsCloneable() const; bool IsAsyncInputStream() const; bool IsInputStreamLength() const; bool IsAsyncInputStreamLength() const; Mutex mLock; // Protects access to all data members. nsTArray mStreams MOZ_GUARDED_BY(mLock); uint32_t mCurrentStream MOZ_GUARDED_BY(mLock); bool mStartedReadingCurrent MOZ_GUARDED_BY(mLock); nsresult mStatus MOZ_GUARDED_BY(mLock); nsCOMPtr mAsyncWaitCallback MOZ_GUARDED_BY(mLock); uint32_t mAsyncWaitFlags MOZ_GUARDED_BY(mLock); uint32_t mAsyncWaitRequestedCount MOZ_GUARDED_BY(mLock); nsCOMPtr mAsyncWaitEventTarget MOZ_GUARDED_BY(mLock); nsCOMPtr mAsyncWaitLengthCallback MOZ_GUARDED_BY(mLock); class AsyncWaitLengthHelper; RefPtr mAsyncWaitLengthHelper MOZ_GUARDED_BY(mLock); uint32_t mSeekableStreams MOZ_GUARDED_BY(mLock); uint32_t mIPCSerializableStreams MOZ_GUARDED_BY(mLock); uint32_t mCloneableStreams MOZ_GUARDED_BY(mLock); // These are Atomics so that we can check them in QueryInterface without // taking a lock (to look at mStreams.Length() and the numbers above) // With no streams added yet, all of these are possible Atomic mIsSeekableStream{true}; Atomic mIsIPCSerializableStream{true}; Atomic mIsCloneableStream{true}; Atomic mIsAsyncInputStream{false}; Atomic mIsInputStreamLength{false}; Atomic mIsAsyncInputStreamLength{false}; }; } // namespace mozilla #endif // _nsMultiplexInputStream_h_