Bug 1733673 [wpt PR 31066] - Annotate CSS Transforms WPT reftests as fuzzy where...
[gecko.git] / dom / fetch / Fetch.h
blob585be4df17d7e9fadb9fe8cdf59fbe01680b9f12
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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_Fetch_h
8 #define mozilla_dom_Fetch_h
10 #include "nsCOMPtr.h"
11 #include "nsError.h"
12 #include "nsProxyRelease.h"
13 #include "nsString.h"
15 #include "mozilla/DebugOnly.h"
16 #include "mozilla/dom/AbortSignal.h"
17 #include "mozilla/dom/BodyConsumer.h"
18 #include "mozilla/dom/BodyStream.h"
19 #include "mozilla/dom/Promise.h"
20 #include "mozilla/dom/FetchStreamReader.h"
21 #include "mozilla/dom/RequestBinding.h"
23 class nsIGlobalObject;
24 class nsIEventTarget;
26 namespace mozilla {
27 class ErrorResult;
29 namespace ipc {
30 class PrincipalInfo;
31 } // namespace ipc
33 namespace dom {
35 class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
36 class
37 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
38 class BlobImpl;
39 class InternalRequest;
40 class
41 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
42 class ReadableStream;
43 class RequestOrUSVString;
44 class WorkerPrivate;
46 enum class CallerType : uint32_t;
48 already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
49 const RequestOrUSVString& aInput,
50 const RequestInit& aInit,
51 CallerType aCallerType,
52 ErrorResult& aRv);
54 nsresult UpdateRequestReferrer(nsIGlobalObject* aGlobal,
55 InternalRequest* aRequest);
57 namespace fetch {
58 using BodyInit =
59 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
60 using ResponseBodyInit =
61 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
62 using OwningBodyInit =
63 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
64 }; // namespace fetch
67 * Creates an nsIInputStream based on the fetch specifications 'extract a byte
68 * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
69 * Stores content type in out param aContentType.
71 nsresult ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
72 nsIInputStream** aStream,
73 nsCString& aContentType,
74 uint64_t& aContentLength);
77 * Non-owning version.
79 nsresult ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
80 nsIInputStream** aStream,
81 nsCString& aContentType,
82 uint64_t& aContentLength);
85 * Non-owning version. This method should go away when BodyInit will contain
86 * ReadableStream.
88 nsresult ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
89 nsIInputStream** aStream,
90 nsCString& aContentType,
91 uint64_t& aContentLength);
94 * FetchBody's body consumption uses nsIInputStreamPump to read from the
95 * underlying stream to a block of memory, which is then adopted by
96 * ContinueConsumeBody() and converted to the right type based on the JS
97 * function called.
99 * Use of the nsIInputStreamPump complicates things on the worker thread.
100 * The solution used here is similar to WebSockets.
101 * The difference is that we are only interested in completion and not data
102 * events, and nsIInputStreamPump can only deliver completion on the main
103 * thread.
105 * Before starting the pump on the main thread, we addref the FetchBody to keep
106 * it alive. Then we add a feature, to track the status of the worker.
108 * ContinueConsumeBody() is the function that cleans things up in both success
109 * and error conditions and so all callers call it with the appropriate status.
111 * Once the read is initiated on the main thread there are two possibilities.
113 * 1) Pump finishes before worker has finished Running.
114 * In this case we adopt the data and dispatch a runnable to the worker,
115 * which derefs FetchBody and removes the feature and resolves the Promise.
117 * 2) Pump still working while worker has stopped Running.
118 * The feature is Notify()ed and ContinueConsumeBody() is called with
119 * NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
120 * ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
121 * held by it) until pump->Cancel() is called. OnStreamComplete() will not
122 * do anything if the error code is NS_BINDING_ABORTED, so we don't have to
123 * worry about keeping anything alive.
125 * The pump is always released on the main thread.
127 template <class Derived>
128 class FetchBody : public BodyStreamHolder, public AbortFollower {
129 public:
130 using BodyStreamHolder::QueryInterface;
132 NS_INLINE_DECL_REFCOUNTING_INHERITED(FetchBody, BodyStreamHolder)
134 bool GetBodyUsed(ErrorResult& aRv) const;
136 // For use in assertions. On success, returns true if the body is used, false
137 // if not. On error, this sweeps the error under the rug and returns true.
138 bool CheckBodyUsed() const;
140 already_AddRefed<Promise> ArrayBuffer(JSContext* aCx, ErrorResult& aRv) {
141 return ConsumeBody(aCx, BodyConsumer::CONSUME_ARRAYBUFFER, aRv);
144 already_AddRefed<Promise> Blob(JSContext* aCx, ErrorResult& aRv) {
145 return ConsumeBody(aCx, BodyConsumer::CONSUME_BLOB, aRv);
148 already_AddRefed<Promise> FormData(JSContext* aCx, ErrorResult& aRv) {
149 return ConsumeBody(aCx, BodyConsumer::CONSUME_FORMDATA, aRv);
152 already_AddRefed<Promise> Json(JSContext* aCx, ErrorResult& aRv) {
153 return ConsumeBody(aCx, BodyConsumer::CONSUME_JSON, aRv);
156 already_AddRefed<Promise> Text(JSContext* aCx, ErrorResult& aRv) {
157 return ConsumeBody(aCx, BodyConsumer::CONSUME_TEXT, aRv);
160 #ifdef MOZ_DOM_STREAMS
161 already_AddRefed<ReadableStream> GetBody(ErrorResult& aRv) {
162 MOZ_CRASH("MOZ_DOM_STREAMS:NYI");
164 #else
165 void GetBody(JSContext* aCx, JS::MutableHandle<JSObject*> aBodyOut,
166 ErrorResult& aRv);
167 #endif
168 void GetMimeType(nsACString& aMimeType);
170 const nsACString& BodyBlobURISpec() const;
172 const nsAString& BodyLocalPath() const;
174 // If the body contains a ReadableStream body object, this method produces a
175 // tee() of it.
176 void MaybeTeeReadableStreamBody(JSContext* aCx,
177 JS::MutableHandle<JSObject*> aBodyOut,
178 FetchStreamReader** aStreamReader,
179 nsIInputStream** aInputStream,
180 ErrorResult& aRv);
182 // Utility public methods accessed by various runnables.
184 // This method _must_ be called in order to set the body as used. If the body
185 // is a ReadableStream, this method will start reading the stream.
186 // More in details, this method does:
187 // 1) It uses an internal flag to track if the body is used. This is tracked
188 // separately from the ReadableStream disturbed state due to purely native
189 // streams.
190 // 2) If there is a ReadableStream reflector for the native stream it is
191 // Locked.
192 // 3) If there is a JS ReadableStream then we begin pumping it into the native
193 // body stream. This effectively locks and disturbs the stream.
195 // Note that JSContext is used only if there is a ReadableStream (this can
196 // happen because the body is a ReadableStream or because attribute body has
197 // already been used by content). If something goes wrong using
198 // ReadableStream, errors will be reported via ErrorResult and not as JS
199 // exceptions in JSContext. This is done in order to have a centralized error
200 // reporting way.
202 // Exceptions generated when reading from the ReadableStream are directly sent
203 // to the Console.
204 void SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
206 // BodyStreamHolder
207 void NullifyStream() override {
208 mReadableStreamBody = nullptr;
209 mReadableStreamReader = nullptr;
210 mFetchStreamReader = nullptr;
213 void SetReadableStreamBody(JSObject* aBody) override {
214 mReadableStreamBody = aBody;
217 JSObject* GetReadableStreamBody() override { return mReadableStreamBody; }
219 void MarkAsRead() override { mBodyUsed = true; }
221 virtual AbortSignalImpl* GetSignalImpl() const = 0;
223 // AbortFollower
224 void RunAbortAlgorithm() override;
226 already_AddRefed<Promise> ConsumeBody(JSContext* aCx,
227 BodyConsumer::ConsumeType aType,
228 ErrorResult& aRv);
230 protected:
231 nsCOMPtr<nsIGlobalObject> mOwner;
233 // Always set whenever the FetchBody is created on the worker thread.
234 WorkerPrivate* mWorkerPrivate;
236 // This is the ReadableStream exposed to content. It's underlying source is a
237 // BodyStream object.
238 JS::Heap<JSObject*> mReadableStreamBody;
240 // This is the Reader used to retrieve data from the body.
241 JS::Heap<JSObject*> mReadableStreamReader;
242 RefPtr<FetchStreamReader> mFetchStreamReader;
244 explicit FetchBody(nsIGlobalObject* aOwner);
246 virtual ~FetchBody();
248 void SetReadableStreamBody(JSContext* aCx, JSObject* aBody);
250 private:
251 Derived* DerivedClass() const {
252 return static_cast<Derived*>(const_cast<FetchBody*>(this));
255 void LockStream(JSContext* aCx, JS::HandleObject aStream, ErrorResult& aRv);
257 bool IsOnTargetThread() { return NS_IsMainThread() == !mWorkerPrivate; }
259 void AssertIsOnTargetThread() { MOZ_ASSERT(IsOnTargetThread()); }
261 // Only ever set once, always on target thread.
262 bool mBodyUsed;
264 // The main-thread event target for runnable dispatching.
265 nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
268 class EmptyBody final : public FetchBody<EmptyBody> {
269 NS_DECL_ISUPPORTS_INHERITED
270 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(EmptyBody,
271 FetchBody<EmptyBody>)
273 public:
274 static already_AddRefed<EmptyBody> Create(
275 nsIGlobalObject* aGlobal, mozilla::ipc::PrincipalInfo* aPrincipalInfo,
276 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
277 ErrorResult& aRv);
279 nsIGlobalObject* GetParentObject() const { return mOwner; }
281 AbortSignalImpl* GetSignalImpl() const override { return mAbortSignalImpl; }
283 const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const {
284 return mPrincipalInfo;
287 void GetMimeType(nsACString& aMimeType) { aMimeType = mMimeType; }
289 void GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr);
291 using FetchBody::BodyBlobURISpec;
293 const nsACString& BodyBlobURISpec() const { return EmptyCString(); }
295 using FetchBody::BodyLocalPath;
297 const nsAString& BodyLocalPath() const { return EmptyString(); }
299 private:
300 EmptyBody(nsIGlobalObject* aGlobal,
301 mozilla::ipc::PrincipalInfo* aPrincipalInfo,
302 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
303 already_AddRefed<nsIInputStream> aBodyStream);
305 ~EmptyBody();
307 UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
308 RefPtr<AbortSignalImpl> mAbortSignalImpl;
309 nsCString mMimeType;
310 nsCOMPtr<nsIInputStream> mBodyStream;
312 } // namespace dom
313 } // namespace mozilla
315 #endif // mozilla_dom_Fetch_h