WritableStream.h (9864B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_WritableStream_h 8 #define mozilla_dom_WritableStream_h 9 10 #include "js/TypeDecls.h" 11 #include "js/Value.h" 12 #include "mozilla/Attributes.h" 13 #include "mozilla/ErrorResult.h" 14 #include "mozilla/dom/BindingDeclarations.h" 15 #include "mozilla/dom/QueuingStrategyBinding.h" 16 #include "mozilla/dom/WritableStreamDefaultController.h" 17 #include "mozilla/dom/WritableStreamDefaultWriter.h" 18 #include "nsCycleCollectionParticipant.h" 19 #include "nsWrapperCache.h" 20 21 namespace mozilla::dom { 22 23 class Promise; 24 class WritableStreamDefaultController; 25 class WritableStreamDefaultWriter; 26 class UnderlyingSinkAlgorithmsBase; 27 class UniqueMessagePortId; 28 class MessagePort; 29 30 class WritableStream : public nsISupports, public nsWrapperCache { 31 public: 32 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 33 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WritableStream) 34 35 friend class ReadableStream; 36 37 protected: 38 virtual ~WritableStream(); 39 40 virtual void LastRelease() {} 41 42 // If one extends WritableStream with another cycle collectable class, 43 // calling HoldJSObjects and DropJSObjects should happen using 'this' of 44 // that extending class. And in that case Explicit should be passed to the 45 // constructor of WriteableStream so that it doesn't make those calls. 46 // See also https://bugzilla.mozilla.org/show_bug.cgi?id=1801214. 47 enum class HoldDropJSObjectsCaller { Implicit, Explicit }; 48 49 explicit WritableStream(const GlobalObject& aGlobal, 50 HoldDropJSObjectsCaller aHoldDropCaller); 51 explicit WritableStream(nsIGlobalObject* aGlobal, 52 HoldDropJSObjectsCaller aHoldDropCaller); 53 54 public: 55 // Slot Getter/Setters: 56 bool Backpressure() const { return mBackpressure; } 57 void SetBackpressure(bool aBackpressure) { mBackpressure = aBackpressure; } 58 59 Promise* GetCloseRequest() { return mCloseRequest; } 60 void SetCloseRequest(Promise* aRequest) { mCloseRequest = aRequest; } 61 62 MOZ_KNOWN_LIVE WritableStreamDefaultController* Controller() { 63 return mController; 64 } 65 void SetController(WritableStreamDefaultController& aController) { 66 MOZ_ASSERT(!mController); 67 mController = &aController; 68 } 69 70 Promise* GetInFlightWriteRequest() const { return mInFlightWriteRequest; } 71 72 Promise* GetPendingAbortRequestPromise() const { 73 return mPendingAbortRequestPromise; 74 } 75 76 void SetPendingAbortRequest(Promise* aPromise, JS::Handle<JS::Value> aReason, 77 bool aWasAlreadyErroring) { 78 mPendingAbortRequestPromise = aPromise; 79 mPendingAbortRequestReason = aReason; 80 mPendingAbortRequestWasAlreadyErroring = aWasAlreadyErroring; 81 } 82 83 WritableStreamDefaultWriter* GetWriter() const { return mWriter; } 84 void SetWriter(WritableStreamDefaultWriter* aWriter) { mWriter = aWriter; } 85 86 enum class WriterState { Writable, Closed, Erroring, Errored }; 87 88 WriterState State() const { return mState; } 89 void SetState(const WriterState& aState) { mState = aState; } 90 91 JS::Value StoredError() const { return mStoredError; } 92 void SetStoredError(JS::Handle<JS::Value> aStoredError) { 93 mStoredError = aStoredError; 94 } 95 96 void AppendWriteRequest(RefPtr<Promise>& aRequest) { 97 mWriteRequests.Push(RefPtr<Promise>(aRequest)); 98 } 99 100 // CreateWritableStream 101 MOZ_CAN_RUN_SCRIPT static already_AddRefed<WritableStream> CreateAbstract( 102 JSContext* aCx, nsIGlobalObject* aGlobal, 103 UnderlyingSinkAlgorithmsBase* aAlgorithms, double aHighWaterMark, 104 QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv); 105 106 // WritableStreamCloseQueuedOrInFlight 107 bool CloseQueuedOrInFlight() const { 108 return mCloseRequest || mInFlightCloseRequest; 109 } 110 111 // WritableStreamDealWithRejection 112 MOZ_CAN_RUN_SCRIPT void DealWithRejection(JSContext* aCx, 113 JS::Handle<JS::Value> aError, 114 ErrorResult& aRv); 115 116 // WritableStreamFinishErroring 117 MOZ_CAN_RUN_SCRIPT void FinishErroring(JSContext* aCx, ErrorResult& aRv); 118 119 // WritableStreamFinishInFlightClose 120 void FinishInFlightClose(); 121 122 // WritableStreamFinishInFlightCloseWithError 123 MOZ_CAN_RUN_SCRIPT void FinishInFlightCloseWithError( 124 JSContext* aCx, JS::Handle<JS::Value> aError, ErrorResult& aRv); 125 126 // WritableStreamFinishInFlightWrite 127 void FinishInFlightWrite(); 128 129 // WritableStreamFinishInFlightWriteWithError 130 MOZ_CAN_RUN_SCRIPT void FinishInFlightWriteWithError( 131 JSContext* aCX, JS::Handle<JS::Value> aError, ErrorResult& aR); 132 133 // WritableStreamHasOperationMarkedInFlight 134 bool HasOperationMarkedInFlight() const { 135 return mInFlightWriteRequest || mInFlightCloseRequest; 136 } 137 138 // WritableStreamMarkCloseRequestInFlight 139 void MarkCloseRequestInFlight(); 140 141 // WritableStreamMarkFirstWriteRequestInFlight 142 void MarkFirstWriteRequestInFlight(); 143 144 // WritableStreamRejectCloseAndClosedPromiseIfNeeded 145 void RejectCloseAndClosedPromiseIfNeeded(); 146 147 // WritableStreamStartErroring 148 MOZ_CAN_RUN_SCRIPT void StartErroring(JSContext* aCx, 149 JS::Handle<JS::Value> aReason, 150 ErrorResult& aRv); 151 152 // WritableStreamUpdateBackpressure 153 void UpdateBackpressure(bool aBackpressure); 154 155 // [Transferable] 156 // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-steps 157 MOZ_CAN_RUN_SCRIPT bool Transfer(JSContext* aCx, 158 UniqueMessagePortId& aPortId); 159 // https://html.spec.whatwg.org/multipage/structured-data.html#transfer-receiving-steps 160 MOZ_CAN_RUN_SCRIPT static already_AddRefed<WritableStream> 161 ReceiveTransferImpl(JSContext* aCx, nsIGlobalObject* aGlobal, 162 MessagePort& aPort); 163 MOZ_CAN_RUN_SCRIPT static bool ReceiveTransfer( 164 JSContext* aCx, nsIGlobalObject* aGlobal, MessagePort& aPort, 165 JS::MutableHandle<JSObject*> aReturnObject); 166 167 // Public functions to implement other specs 168 // https://streams.spec.whatwg.org/#other-specs-ws 169 170 // https://streams.spec.whatwg.org/#writablestream-set-up 171 protected: 172 // Sets up the WritableStream. Intended for subclasses. 173 void SetUpNative(JSContext* aCx, UnderlyingSinkAlgorithmsWrapper& aAlgorithms, 174 Maybe<double> aHighWaterMark, 175 QueuingStrategySize* aSizeAlgorithm, ErrorResult& aRv); 176 177 public: 178 // Creates and sets up a WritableStream. Use SetUpNative for this purpose in 179 // subclasses. 180 static already_AddRefed<WritableStream> CreateNative( 181 JSContext* aCx, nsIGlobalObject& aGlobal, 182 UnderlyingSinkAlgorithmsWrapper& aAlgorithms, 183 Maybe<double> aHighWaterMark, QueuingStrategySize* aSizeAlgorithm, 184 ErrorResult& aRv); 185 186 // The following definitions must only be used on WritableStream instances 187 // initialized via the above set up algorithm: 188 189 // https://streams.spec.whatwg.org/#writablestream-error 190 MOZ_CAN_RUN_SCRIPT void ErrorNative(JSContext* aCx, 191 JS::Handle<JS::Value> aError, 192 ErrorResult& aRv); 193 194 // IDL layer functions 195 196 nsIGlobalObject* GetParentObject() const { return mGlobal; } 197 198 JSObject* WrapObject(JSContext* aCx, 199 JS::Handle<JSObject*> aGivenProto) override; 200 201 // IDL methods 202 203 // TODO: Use MOZ_CAN_RUN_SCRIPT when IDL constructors can use it (bug 1749042) 204 MOZ_CAN_RUN_SCRIPT_BOUNDARY static already_AddRefed<WritableStream> 205 Constructor(const GlobalObject& aGlobal, 206 const Optional<JS::Handle<JSObject*>>& aUnderlyingSink, 207 const QueuingStrategy& aStrategy, ErrorResult& aRv); 208 209 bool Locked() const { return !!mWriter; } 210 211 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> Abort( 212 JSContext* cx, JS::Handle<JS::Value> aReason, ErrorResult& aRv); 213 214 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> Close(JSContext* aCx, 215 ErrorResult& aRv); 216 217 already_AddRefed<WritableStreamDefaultWriter> GetWriter(ErrorResult& aRv); 218 219 protected: 220 nsCOMPtr<nsIGlobalObject> mGlobal; 221 222 // Internal Slots: 223 private: 224 bool mBackpressure = false; 225 RefPtr<Promise> mCloseRequest; 226 RefPtr<WritableStreamDefaultController> mController; 227 RefPtr<Promise> mInFlightWriteRequest; 228 RefPtr<Promise> mInFlightCloseRequest; 229 230 // We inline all members of [[pendingAbortRequest]] in this class. 231 // The absence (i.e. undefined) of the [[pendingAbortRequest]] 232 // is indicated by mPendingAbortRequestPromise = nullptr. 233 RefPtr<Promise> mPendingAbortRequestPromise; 234 JS::Heap<JS::Value> mPendingAbortRequestReason; 235 bool mPendingAbortRequestWasAlreadyErroring = false; 236 237 WriterState mState = WriterState::Writable; 238 JS::Heap<JS::Value> mStoredError; 239 RefPtr<WritableStreamDefaultWriter> mWriter; 240 mozilla::Queue<RefPtr<Promise>> mWriteRequests; 241 242 HoldDropJSObjectsCaller mHoldDropCaller; 243 }; 244 245 namespace streams_abstract { 246 247 inline bool IsWritableStreamLocked(WritableStream* aStream) { 248 return aStream->Locked(); 249 } 250 251 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WritableStreamAbort( 252 JSContext* aCx, WritableStream* aStream, JS::Handle<JS::Value> aReason, 253 ErrorResult& aRv); 254 255 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> WritableStreamClose( 256 JSContext* aCx, WritableStream* aStream, ErrorResult& aRv); 257 258 already_AddRefed<Promise> WritableStreamAddWriteRequest( 259 WritableStream* aStream); 260 261 already_AddRefed<WritableStreamDefaultWriter> 262 AcquireWritableStreamDefaultWriter(WritableStream* aStream, ErrorResult& aRv); 263 264 } // namespace streams_abstract 265 266 } // namespace mozilla::dom 267 268 #endif // mozilla_dom_WritableStream_h