Backed out 2 changesets (bug 1908320) for causing wr failures on align-items-baseline...
[gecko.git] / dom / streams / UnderlyingSourceCallbackHelpers.h
blobe35e1dc59fbc0cf37321d8e5fd26511c81117d30
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/. */
7 #ifndef mozilla_dom_UnderlyingSourceCallbackHelpers_h
8 #define mozilla_dom_UnderlyingSourceCallbackHelpers_h
10 #include "mozilla/DOMEventTargetHelper.h"
11 #include "mozilla/HoldDropJSObjects.h"
12 #include "mozilla/dom/Promise.h"
13 #include "mozilla/dom/UnderlyingSourceBinding.h"
14 #include "mozilla/WeakPtr.h"
15 #include "nsIAsyncInputStream.h"
16 #include "nsISupports.h"
17 #include "nsISupportsImpl.h"
19 /* Since the streams specification has native descriptions of some callbacks
20 * (i.e. described in prose, rather than provided by user code), we need to be
21 * able to pass around native callbacks. To handle this, we define polymorphic
22 * classes That cover the difference between native callback and user-provided.
24 * The Streams specification wants us to invoke these callbacks, run through
25 * WebIDL as if they were methods. So we have to preserve the underlying object
26 * to use as the This value on invocation.
28 enum class nsresult : uint32_t;
30 namespace mozilla::dom {
32 class StrongWorkerRef;
33 class BodyStreamHolder;
34 class ReadableStreamController;
35 class ReadableStream;
37 class UnderlyingSourceAlgorithmsBase : public nsISupports {
38 public:
39 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
40 NS_DECL_CYCLE_COLLECTION_CLASS(UnderlyingSourceAlgorithmsBase)
42 MOZ_CAN_RUN_SCRIPT virtual void StartCallback(
43 JSContext* aCx, ReadableStreamController& aController,
44 JS::MutableHandle<JS::Value> aRetVal, ErrorResult& aRv) = 0;
46 // A promise-returning algorithm that pulls data from the underlying byte
47 // source
48 MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> PullCallback(
49 JSContext* aCx, ReadableStreamController& aController,
50 ErrorResult& aRv) = 0;
52 // A promise-returning algorithm, taking one argument (the cancel reason),
53 // which communicates a requested cancelation to the underlying byte source
54 MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> CancelCallback(
55 JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
56 ErrorResult& aRv) = 0;
58 // Implement this when you need to release underlying resources immediately
59 // from closed(canceled)/errored streams, without waiting for GC.
60 virtual void ReleaseObjects() {}
62 // Can be used to read chunks directly via nsIInputStream to skip JS-related
63 // overhead, if this readable stream is a wrapper of a native stream.
64 // Currently used by Fetch helper functions e.g. new Response(stream).text()
65 virtual nsIInputStream* MaybeGetInputStreamIfUnread() { return nullptr; }
67 // https://streams.spec.whatwg.org/#other-specs-rs-create
68 // By "native" we mean "instances initialized via the above set up or set up
69 // with byte reading support algorithms (not, e.g., on web-developer-created
70 // instances)"
71 virtual bool IsNative() { return true; }
73 protected:
74 virtual ~UnderlyingSourceAlgorithmsBase() = default;
77 class UnderlyingSourceAlgorithms final : public UnderlyingSourceAlgorithmsBase {
78 public:
79 NS_DECL_ISUPPORTS_INHERITED
80 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(
81 UnderlyingSourceAlgorithms, UnderlyingSourceAlgorithmsBase)
83 UnderlyingSourceAlgorithms(nsIGlobalObject* aGlobal,
84 JS::Handle<JSObject*> aUnderlyingSource,
85 UnderlyingSource& aUnderlyingSourceDict)
86 : mGlobal(aGlobal), mUnderlyingSource(aUnderlyingSource) {
87 // Step 6. (implicit Step 2.)
88 if (aUnderlyingSourceDict.mStart.WasPassed()) {
89 mStartCallback = aUnderlyingSourceDict.mStart.Value();
92 // Step 7. (implicit Step 3.)
93 if (aUnderlyingSourceDict.mPull.WasPassed()) {
94 mPullCallback = aUnderlyingSourceDict.mPull.Value();
97 // Step 8. (implicit Step 4.)
98 if (aUnderlyingSourceDict.mCancel.WasPassed()) {
99 mCancelCallback = aUnderlyingSourceDict.mCancel.Value();
102 mozilla::HoldJSObjects(this);
105 MOZ_CAN_RUN_SCRIPT void StartCallback(JSContext* aCx,
106 ReadableStreamController& aController,
107 JS::MutableHandle<JS::Value> aRetVal,
108 ErrorResult& aRv) override;
110 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PullCallback(
111 JSContext* aCx, ReadableStreamController& aController,
112 ErrorResult& aRv) override;
114 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CancelCallback(
115 JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
116 ErrorResult& aRv) override;
118 bool IsNative() override { return false; }
120 protected:
121 ~UnderlyingSourceAlgorithms() override { mozilla::DropJSObjects(this); };
123 private:
124 // Virtually const, but are cycle collected
125 nsCOMPtr<nsIGlobalObject> mGlobal;
126 JS::Heap<JSObject*> mUnderlyingSource;
127 MOZ_KNOWN_LIVE RefPtr<UnderlyingSourceStartCallback> mStartCallback;
128 MOZ_KNOWN_LIVE RefPtr<UnderlyingSourcePullCallback> mPullCallback;
129 MOZ_KNOWN_LIVE RefPtr<UnderlyingSourceCancelCallback> mCancelCallback;
132 // https://streams.spec.whatwg.org/#readablestream-set-up
133 // https://streams.spec.whatwg.org/#readablestream-set-up-with-byte-reading-support
134 // Wrappers defined by the "Set up" methods in the spec. This helps you just
135 // return nullptr when an error occurred as this wrapper converts it to a
136 // rejected promise.
137 // Note that StartCallback is only for JS consumers to access
138 // the controller, and thus is no-op here since native consumers can call
139 // `EnqueueNative()` etc. without direct controller access.
140 class UnderlyingSourceAlgorithmsWrapper
141 : public UnderlyingSourceAlgorithmsBase {
142 void StartCallback(JSContext*, ReadableStreamController&,
143 JS::MutableHandle<JS::Value> aRetVal, ErrorResult&) final;
145 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> PullCallback(
146 JSContext* aCx, ReadableStreamController& aController,
147 ErrorResult& aRv) final;
149 MOZ_CAN_RUN_SCRIPT already_AddRefed<Promise> CancelCallback(
150 JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
151 ErrorResult& aRv) final;
153 MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> PullCallbackImpl(
154 JSContext* aCx, ReadableStreamController& aController, ErrorResult& aRv) {
155 // pullAlgorithm is optional, return null by default
156 return nullptr;
159 MOZ_CAN_RUN_SCRIPT virtual already_AddRefed<Promise> CancelCallbackImpl(
160 JSContext* aCx, const Optional<JS::Handle<JS::Value>>& aReason,
161 ErrorResult& aRv) {
162 // cancelAlgorithm is optional, return null by default
163 return nullptr;
167 class InputToReadableStreamAlgorithms;
169 // This class exists to isolate InputToReadableStreamAlgorithms from the
170 // nsIAsyncInputStream. If we call AsyncWait(this,...), it holds a
171 // reference to 'this' which can't be cc'd, and we can leak the stream,
172 // causing a Worker to assert with globalScopeAlive. By isolating
173 // ourselves from the inputstream, we can safely be CC'd if needed and
174 // will inform the inputstream to shut down.
175 class InputStreamHolder final : public nsIInputStreamCallback,
176 public GlobalTeardownObserver {
177 public:
178 NS_DECL_THREADSAFE_ISUPPORTS
179 NS_DECL_NSIINPUTSTREAMCALLBACK
181 InputStreamHolder(nsIGlobalObject* aGlobal,
182 InputToReadableStreamAlgorithms* aCallback,
183 nsIAsyncInputStream* aInput);
185 void Init(JSContext* aCx);
187 void DisconnectFromOwner() override;
189 // Used by global teardown
190 void Shutdown();
192 // These just proxy the calls to the nsIAsyncInputStream
193 nsresult AsyncWait(uint32_t aFlags, uint32_t aRequestedCount,
194 nsIEventTarget* aEventTarget);
195 nsresult Available(uint64_t* aSize) { return mInput->Available(aSize); }
196 nsresult Read(char* aBuffer, uint32_t aLength, uint32_t* aWritten) {
197 return mInput->Read(aBuffer, aLength, aWritten);
199 nsresult CloseWithStatus(nsresult aStatus) {
200 return mInput->CloseWithStatus(aStatus);
203 nsIAsyncInputStream* GetInputStream() { return mInput; }
205 private:
206 ~InputStreamHolder();
208 // WeakPtr to avoid cycles
209 WeakPtr<InputToReadableStreamAlgorithms> mCallback;
210 // To ensure the worker sticks around
211 RefPtr<StrongWorkerRef> mAsyncWaitWorkerRef;
212 RefPtr<StrongWorkerRef> mWorkerRef;
213 nsCOMPtr<nsIAsyncInputStream> mInput;
215 // To ensure the underlying source sticks around during an ongoing read
216 // operation. mAlgorithms is not cycle collected on purpose, and this holder
217 // is responsible to keep the underlying source algorithms until
218 // nsIAsyncInputStream responds.
220 // This is done because otherwise the whole stream objects may be cycle
221 // collected, including the promises created from read(), as our JS engine may
222 // throw unsettled promises away for optimization. See bug 1849860.
223 RefPtr<InputToReadableStreamAlgorithms> mAsyncWaitAlgorithms;
226 // Using this class means you are also passing the lifetime control of your
227 // nsIAsyncInputStream, as it will be closed when this class tears down.
228 class InputToReadableStreamAlgorithms final
229 : public UnderlyingSourceAlgorithmsWrapper,
230 public nsIInputStreamCallback,
231 public SupportsWeakPtr {
232 NS_DECL_ISUPPORTS_INHERITED
233 NS_DECL_NSIINPUTSTREAMCALLBACK
234 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(InputToReadableStreamAlgorithms,
235 UnderlyingSourceAlgorithmsWrapper)
237 InputToReadableStreamAlgorithms(JSContext* aCx, nsIAsyncInputStream* aInput,
238 ReadableStream* aStream);
240 // Streams algorithms
242 already_AddRefed<Promise> PullCallbackImpl(
243 JSContext* aCx, ReadableStreamController& aController,
244 ErrorResult& aRv) override;
246 void ReleaseObjects() override;
248 nsIInputStream* MaybeGetInputStreamIfUnread() override;
250 private:
251 ~InputToReadableStreamAlgorithms() {
252 if (mInput) {
253 mInput->Shutdown();
257 MOZ_CAN_RUN_SCRIPT_BOUNDARY void CloseAndReleaseObjects(
258 JSContext* aCx, ReadableStream* aStream);
260 void WriteIntoReadRequestBuffer(JSContext* aCx, ReadableStream* aStream,
261 JS::Handle<JSObject*> aBuffer,
262 uint32_t aLength, uint32_t* aByteWritten,
263 ErrorResult& aRv);
265 // https://streams.spec.whatwg.org/#readablestream-pull-from-bytes
266 // (Uses InputStreamHolder for the "byte sequence" in the spec)
267 MOZ_CAN_RUN_SCRIPT void PullFromInputStream(JSContext* aCx,
268 uint64_t aAvailable,
269 ErrorResult& aRv);
271 void ErrorPropagation(JSContext* aCx, ReadableStream* aStream,
272 nsresult aError);
274 // Common methods
276 bool IsClosed() { return !mInput; }
278 nsCOMPtr<nsIEventTarget> mOwningEventTarget;
280 // This promise is created by PullCallback and resolved when
281 // OnInputStreamReady succeeds. No need to try hard to settle it though, see
282 // also ReleaseObjects() for the reason.
283 RefPtr<Promise> mPullPromise;
285 RefPtr<InputStreamHolder> mInput;
287 // mStream never changes after construction and before CC
288 MOZ_KNOWN_LIVE RefPtr<ReadableStream> mStream;
291 class NonAsyncInputToReadableStreamAlgorithms
292 : public UnderlyingSourceAlgorithmsWrapper {
293 public:
294 NS_DECL_ISUPPORTS_INHERITED
295 NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(
296 NonAsyncInputToReadableStreamAlgorithms,
297 UnderlyingSourceAlgorithmsWrapper)
299 explicit NonAsyncInputToReadableStreamAlgorithms(nsIInputStream& aInput)
300 : mInput(&aInput) {}
302 already_AddRefed<Promise> PullCallbackImpl(
303 JSContext* aCx, ReadableStreamController& aController,
304 ErrorResult& aRv) override;
306 void ReleaseObjects() override {
307 if (RefPtr<InputToReadableStreamAlgorithms> algorithms =
308 mAsyncAlgorithms.forget()) {
309 algorithms->ReleaseObjects();
311 if (nsCOMPtr<nsIInputStream> input = mInput.forget()) {
312 input->Close();
316 nsIInputStream* MaybeGetInputStreamIfUnread() override {
317 MOZ_ASSERT(mInput, "Should be only called on non-disturbed streams");
318 return mInput;
321 private:
322 ~NonAsyncInputToReadableStreamAlgorithms() = default;
324 nsCOMPtr<nsIInputStream> mInput;
325 RefPtr<InputToReadableStreamAlgorithms> mAsyncAlgorithms;
328 } // namespace mozilla::dom
330 #endif