/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* 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/. */ #ifndef mozilla_dom_ReadableStream_h #define mozilla_dom_ReadableStream_h #include "js/TypeDecls.h" #include "js/Value.h" #include "mozilla/Attributes.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/IterableIterator.h" #include "mozilla/dom/QueuingStrategyBinding.h" #include "mozilla/dom/ReadableStreamController.h" #include "mozilla/dom/ReadableStreamDefaultController.h" #include "mozilla/dom/UnderlyingSourceCallbackHelpers.h" #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" namespace mozilla::dom { class Promise; class ReadableStreamDefaultReader; class ReadableStreamGenericReader; struct ReadableStreamGetReaderOptions; struct ReadableStreamIteratorOptions; struct ReadIntoRequest; class WritableStream; struct ReadableWritablePair; struct StreamPipeOptions; using ReadableStreamReader = ReadableStreamDefaultReaderOrReadableStreamBYOBReader; using OwningReadableStreamReader = OwningReadableStreamDefaultReaderOrReadableStreamBYOBReader; class NativeUnderlyingSource; class BodyStreamHolder; class UniqueMessagePortId; class MessagePort; class ReadableStream : public nsISupports, public nsWrapperCache { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ReadableStream) friend class WritableStream; protected: virtual ~ReadableStream(); nsCOMPtr mGlobal; // If one extends ReadableStream with another cycle collectable class, // calling HoldJSObjects and DropJSObjects should happen using 'this' of // that extending class. And in that case Explicit should be passed to the // constructor of ReadableStream so that it doesn't make those calls. // See also https://bugzilla.mozilla.org/show_bug.cgi?id=1801214. enum class HoldDropJSObjectsCaller { Implicit, Explicit }; explicit ReadableStream(const GlobalObject& aGlobal, HoldDropJSObjectsCaller aHoldDropCaller); explicit ReadableStream(nsIGlobalObject* aGlobal, HoldDropJSObjectsCaller aHoldDropCaller); public: // Abstract algorithms MOZ_CAN_RUN_SCRIPT static already_AddRefed CreateAbstract( JSContext* aCx, nsIGlobalObject* aGlobal, UnderlyingSourceAlgorithmsBase* aAlgorithms, mozilla::Maybe aHighWaterMark, QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT static already_AddRefed CreateByteAbstract( JSContext* aCx, nsIGlobalObject* aGlobal, UnderlyingSourceAlgorithmsBase* aAlgorithms, ErrorResult& aRv); // Slot Getter/Setters: MOZ_KNOWN_LIVE ReadableStreamController* Controller() { return mController; } ReadableStreamDefaultController* DefaultController() { MOZ_ASSERT(mController && mController->IsDefault()); return mController->AsDefault(); } void SetController(ReadableStreamController& aController) { MOZ_ASSERT(!mController); mController = &aController; } bool Disturbed() const { return mDisturbed; } void SetDisturbed(bool aDisturbed) { mDisturbed = aDisturbed; } ReadableStreamGenericReader* GetReader() { return mReader; } void SetReader(ReadableStreamGenericReader* aReader); ReadableStreamDefaultReader* GetDefaultReader(); enum class ReaderState { Readable, Closed, Errored }; ReaderState State() const { return mState; } void SetState(const ReaderState& aState) { mState = aState; } JS::Value StoredError() const { return mStoredError; } void SetStoredError(JS::Handle aStoredError) { mStoredError = aStoredError; } nsIInputStream* MaybeGetInputStreamIfUnread() { MOZ_ASSERT(!Disturbed()); if (UnderlyingSourceAlgorithmsBase* algorithms = Controller()->GetAlgorithms()) { return algorithms->MaybeGetInputStreamIfUnread(); } return nullptr; } // [Transferable] // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps MOZ_CAN_RUN_SCRIPT bool Transfer(JSContext* aCx, UniqueMessagePortId& aPortId); MOZ_CAN_RUN_SCRIPT static already_AddRefed ReceiveTransferImpl(JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort); // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps MOZ_CAN_RUN_SCRIPT static bool ReceiveTransfer( JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort, JS::MutableHandle aReturnObject); // Public functions to implement other specs // https://streams.spec.whatwg.org/#other-specs-rs // https://streams.spec.whatwg.org/#readablestream-set-up static already_AddRefed CreateNative( JSContext* aCx, nsIGlobalObject* aGlobal, UnderlyingSourceAlgorithmsWrapper& aAlgorithms, mozilla::Maybe aHighWaterMark, QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv); // https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support protected: // Sets up the ReadableStream with byte reading support. Intended for // subclasses. void SetUpByteNative(JSContext* aCx, UnderlyingSourceAlgorithmsWrapper& aAlgorithms, mozilla::Maybe aHighWaterMark, ErrorResult& aRv); public: // Creates and sets up a ReadableStream with byte reading support. Use // SetUpByteNative for this purpose in subclasses. static already_AddRefed CreateByteNative( JSContext* aCx, nsIGlobalObject* aGlobal, UnderlyingSourceAlgorithmsWrapper& aAlgorithms, mozilla::Maybe aHighWaterMark, ErrorResult& aRv); // The following algorithms must only be used on ReadableStream instances // initialized via the above set up or set up with byte reading support // algorithms (not, e.g., on web-developer-created instances): // https://streams.spec.whatwg.org/#readablestream-close MOZ_CAN_RUN_SCRIPT void CloseNative(JSContext* aCx, ErrorResult& aRv); // https://streams.spec.whatwg.org/#readablestream-error void ErrorNative(JSContext* aCx, JS::Handle aError, ErrorResult& aRv); // https://streams.spec.whatwg.org/#readablestream-enqueue MOZ_CAN_RUN_SCRIPT void EnqueueNative(JSContext* aCx, JS::Handle aChunk, ErrorResult& aRv); // The following algorithms can be used on arbitrary ReadableStream instances, // including ones that are created by web developers. They can all fail in // various operation-specific ways, and these failures should be handled by // the calling specification. // https://streams.spec.whatwg.org/#readablestream-get-a-reader already_AddRefed GetReader( ErrorResult& aRv); // IDL layer functions nsIGlobalObject* GetParentObject() const { return mGlobal; } JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; // IDL methods // TODO: Use MOZ_CAN_RUN_SCRIPT when IDL constructors can use it (bug 1749042) MOZ_CAN_RUN_SCRIPT_BOUNDARY static already_AddRefed Constructor(const GlobalObject& aGlobal, const Optional>& aUnderlyingSource, const QueuingStrategy& aStrategy, ErrorResult& aRv); bool Locked() const; MOZ_CAN_RUN_SCRIPT already_AddRefed Cancel( JSContext* cx, JS::Handle aReason, ErrorResult& aRv); void GetReader(const ReadableStreamGetReaderOptions& aOptions, OwningReadableStreamReader& resultReader, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT already_AddRefed PipeThrough( const ReadableWritablePair& aTransform, const StreamPipeOptions& aOptions, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT already_AddRefed PipeTo( WritableStream& aDestination, const StreamPipeOptions& aOptions, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void Tee(JSContext* aCx, nsTArray>& aResult, ErrorResult& aRv); struct IteratorData { void Traverse(nsCycleCollectionTraversalCallback& cb); void Unlink(); RefPtr mReader; bool mPreventCancel; }; using Iterator = AsyncIterableIterator; void InitAsyncIteratorData(IteratorData& aData, Iterator::IteratorType aType, const ReadableStreamIteratorOptions& aOptions, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT already_AddRefed GetNextIterationResult( Iterator* aIterator, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT already_AddRefed IteratorReturn( JSContext* aCx, Iterator* aIterator, JS::Handle aValue, ErrorResult& aRv); // Internal Slots: private: RefPtr mController; bool mDisturbed = false; RefPtr mReader; ReaderState mState = ReaderState::Readable; JS::Heap mStoredError; HoldDropJSObjectsCaller mHoldDropCaller; }; namespace streams_abstract { bool IsReadableStreamLocked(ReadableStream* aStream); double ReadableStreamGetNumReadRequests(ReadableStream* aStream); void ReadableStreamError(JSContext* aCx, ReadableStream* aStream, JS::Handle aValue, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void ReadableStreamClose(JSContext* aCx, ReadableStream* aStream, ErrorResult& aRv); MOZ_CAN_RUN_SCRIPT void ReadableStreamFulfillReadRequest( JSContext* aCx, ReadableStream* aStream, JS::Handle aChunk, bool done, ErrorResult& aRv); void ReadableStreamAddReadRequest(ReadableStream* aStream, ReadRequest* aReadRequest); void ReadableStreamAddReadIntoRequest(ReadableStream* aStream, ReadIntoRequest* aReadIntoRequest); MOZ_CAN_RUN_SCRIPT already_AddRefed ReadableStreamCancel( JSContext* aCx, ReadableStream* aStream, JS::Handle aError, ErrorResult& aRv); already_AddRefed AcquireReadableStreamDefaultReader(ReadableStream* aStream, ErrorResult& aRv); bool ReadableStreamHasBYOBReader(ReadableStream* aStream); bool ReadableStreamHasDefaultReader(ReadableStream* aStream); } // namespace streams_abstract } // namespace mozilla::dom #endif // mozilla_dom_ReadableStream_h