Bug 1828719 - Remove omnijar Gradle project from srcdir r=geckoview-reviewers,nalexan...
[gecko.git] / dom / fetch / Fetch.h
blob14be10289543bdeccd0f19da44ae0dce9f9bc4d1
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 "mozilla/Attributes.h"
11 #include "nsCOMPtr.h"
12 #include "nsError.h"
13 #include "nsProxyRelease.h"
14 #include "nsString.h"
16 #include "mozilla/DebugOnly.h"
17 #include "mozilla/dom/AbortSignal.h"
18 #include "mozilla/dom/BodyConsumer.h"
19 #include "mozilla/dom/BodyStream.h"
20 #include "mozilla/dom/Promise.h"
21 #include "mozilla/dom/FetchStreamReader.h"
22 #include "mozilla/dom/ReadableStream.h"
23 #include "mozilla/dom/ReadableStreamDefaultReaderBinding.h"
24 #include "mozilla/dom/RequestBinding.h"
25 #include "mozilla/dom/workerinternals/RuntimeService.h"
27 class nsIGlobalObject;
28 class nsIEventTarget;
30 namespace mozilla {
31 class ErrorResult;
33 namespace ipc {
34 class PrincipalInfo;
35 } // namespace ipc
37 namespace dom {
39 class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
40 class
41 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
42 class BlobImpl;
43 class InternalRequest;
44 class
45 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
47 class ReadableStreamDefaultReader;
48 class RequestOrUSVString;
49 class WorkerPrivate;
51 enum class CallerType : uint32_t;
53 already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
54 const RequestOrUSVString& aInput,
55 const RequestInit& aInit,
56 CallerType aCallerType,
57 ErrorResult& aRv);
59 nsresult UpdateRequestReferrer(nsIGlobalObject* aGlobal,
60 InternalRequest* aRequest);
62 namespace fetch {
63 using BodyInit =
64 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
65 using ResponseBodyInit =
66 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
67 using OwningBodyInit =
68 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
69 }; // namespace fetch
72 * Creates an nsIInputStream based on the fetch specifications 'extract a byte
73 * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
74 * Stores content type in out param aContentType.
76 nsresult ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
77 nsIInputStream** aStream,
78 nsCString& aContentType,
79 uint64_t& aContentLength);
82 * Non-owning version.
84 nsresult ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
85 nsIInputStream** aStream,
86 nsCString& aContentType,
87 uint64_t& aContentLength);
90 * Non-owning version. This method should go away when BodyInit will contain
91 * ReadableStream.
93 nsresult ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
94 nsIInputStream** aStream,
95 nsCString& aContentType,
96 uint64_t& aContentLength);
99 * FetchBody's body consumption uses nsIInputStreamPump to read from the
100 * underlying stream to a block of memory, which is then adopted by
101 * ContinueConsumeBody() and converted to the right type based on the JS
102 * function called.
104 * Use of the nsIInputStreamPump complicates things on the worker thread.
105 * The solution used here is similar to WebSockets.
106 * The difference is that we are only interested in completion and not data
107 * events, and nsIInputStreamPump can only deliver completion on the main
108 * thread.
110 * Before starting the pump on the main thread, we addref the FetchBody to keep
111 * it alive. Then we add a feature, to track the status of the worker.
113 * ContinueConsumeBody() is the function that cleans things up in both success
114 * and error conditions and so all callers call it with the appropriate status.
116 * Once the read is initiated on the main thread there are two possibilities.
118 * 1) Pump finishes before worker has finished Running.
119 * In this case we adopt the data and dispatch a runnable to the worker,
120 * which derefs FetchBody and removes the feature and resolves the Promise.
122 * 2) Pump still working while worker has stopped Running.
123 * The feature is Notify()ed and ContinueConsumeBody() is called with
124 * NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
125 * ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
126 * held by it) until pump->Cancel() is called. OnStreamComplete() will not
127 * do anything if the error code is NS_BINDING_ABORTED, so we don't have to
128 * worry about keeping anything alive.
130 * The pump is always released on the main thread.
132 template <class Derived>
133 class FetchBody : public BodyStreamHolder, public AbortFollower {
134 public:
135 using BodyStreamHolder::QueryInterface;
137 NS_INLINE_DECL_REFCOUNTING_INHERITED(FetchBody, BodyStreamHolder)
139 bool GetBodyUsed(ErrorResult& aRv) const;
141 // For use in assertions. On success, returns true if the body is used, false
142 // if not. On error, this sweeps the error under the rug and returns true.
143 bool CheckBodyUsed() const;
145 already_AddRefed<Promise> ArrayBuffer(JSContext* aCx, ErrorResult& aRv) {
146 return ConsumeBody(aCx, BodyConsumer::CONSUME_ARRAYBUFFER, aRv);
149 already_AddRefed<Promise> Blob(JSContext* aCx, ErrorResult& aRv) {
150 return ConsumeBody(aCx, BodyConsumer::CONSUME_BLOB, aRv);
153 already_AddRefed<Promise> FormData(JSContext* aCx, ErrorResult& aRv) {
154 return ConsumeBody(aCx, BodyConsumer::CONSUME_FORMDATA, aRv);
157 already_AddRefed<Promise> Json(JSContext* aCx, ErrorResult& aRv) {
158 return ConsumeBody(aCx, BodyConsumer::CONSUME_JSON, aRv);
161 already_AddRefed<Promise> Text(JSContext* aCx, ErrorResult& aRv) {
162 return ConsumeBody(aCx, BodyConsumer::CONSUME_TEXT, aRv);
165 already_AddRefed<ReadableStream> GetBody(JSContext* aCx, ErrorResult& aRv);
166 void GetMimeType(nsACString& aMimeType, nsACString& aMixedCaseMimeType);
168 const nsACString& BodyBlobURISpec() const;
170 const nsAString& BodyLocalPath() const;
172 // If the body contains a ReadableStream body object, this method produces a
173 // tee() of it.
175 // This is marked as a script boundary minimize changes required for
176 // annotation while we work out how to correctly annotate this code.
177 // Tracked in Bug 1750650.
178 MOZ_CAN_RUN_SCRIPT_BOUNDARY
179 void MaybeTeeReadableStreamBody(JSContext* aCx, ReadableStream** aBodyOut,
180 FetchStreamReader** aStreamReader,
181 nsIInputStream** aInputStream,
182 ErrorResult& aRv);
184 // Utility public methods accessed by various runnables.
186 // This method _must_ be called in order to set the body as used. If the body
187 // is a ReadableStream, this method will start reading the stream.
188 // More in details, this method does:
189 // 1) It uses an internal flag to track if the body is used. This is tracked
190 // separately from the ReadableStream disturbed state due to purely native
191 // streams.
192 // 2) If there is a ReadableStream reflector for the native stream it is
193 // Locked.
194 // 3) If there is a JS ReadableStream then we begin pumping it into the native
195 // body stream. This effectively locks and disturbs the stream.
197 // Note that JSContext is used only if there is a ReadableStream (this can
198 // happen because the body is a ReadableStream or because attribute body has
199 // already been used by content). If something goes wrong using
200 // ReadableStream, errors will be reported via ErrorResult and not as JS
201 // exceptions in JSContext. This is done in order to have a centralized error
202 // reporting way.
204 // Exceptions generated when reading from the ReadableStream are directly sent
205 // to the Console.
206 void SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
208 // BodyStreamHolder
209 void NullifyStream() override {
210 BodyStreamHolder::NullifyStream();
211 mReadableStreamReader = nullptr;
212 mFetchStreamReader = nullptr;
215 void MarkAsRead() override { mBodyUsed = true; }
217 virtual AbortSignalImpl* GetSignalImpl() const = 0;
219 virtual AbortSignalImpl* GetSignalImplToConsumeBody() const = 0;
221 // AbortFollower
222 void RunAbortAlgorithm() override;
224 already_AddRefed<Promise> ConsumeBody(JSContext* aCx,
225 BodyConsumer::ConsumeType aType,
226 ErrorResult& aRv);
228 protected:
229 nsCOMPtr<nsIGlobalObject> mOwner;
231 // This is the Reader used to retrieve data from the body. This needs to be
232 // traversed by subclasses.
233 RefPtr<ReadableStreamDefaultReader> mReadableStreamReader;
234 RefPtr<FetchStreamReader> mFetchStreamReader;
236 explicit FetchBody(nsIGlobalObject* aOwner);
238 virtual ~FetchBody();
240 void SetReadableStreamBody(JSContext* aCx, ReadableStream* aBody);
242 private:
243 Derived* DerivedClass() const {
244 return static_cast<Derived*>(const_cast<FetchBody*>(this));
247 void LockStream(JSContext* aCx, ReadableStream* aStream, ErrorResult& aRv);
249 void AssertIsOnTargetThread() {
250 MOZ_ASSERT(NS_IsMainThread() == !GetCurrentThreadWorkerPrivate());
253 // Only ever set once, always on target thread.
254 bool mBodyUsed;
256 // The main-thread event target for runnable dispatching.
257 nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
260 class EmptyBody final : public FetchBody<EmptyBody> {
261 NS_DECL_ISUPPORTS_INHERITED
262 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(EmptyBody,
263 FetchBody<EmptyBody>)
265 public:
266 static already_AddRefed<EmptyBody> Create(
267 nsIGlobalObject* aGlobal, mozilla::ipc::PrincipalInfo* aPrincipalInfo,
268 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
269 const nsACString& aMixedCaseMimeType, ErrorResult& aRv);
271 nsIGlobalObject* GetParentObject() const { return mOwner; }
273 AbortSignalImpl* GetSignalImpl() const override { return mAbortSignalImpl; }
274 AbortSignalImpl* GetSignalImplToConsumeBody() const final { return nullptr; }
276 const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const {
277 return mPrincipalInfo;
280 void GetMimeType(nsACString& aMimeType, nsACString& aMixedCaseMimeType) {
281 aMimeType = mMimeType;
282 aMixedCaseMimeType = mMixedCaseMimeType;
285 void GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr);
287 using FetchBody::BodyBlobURISpec;
289 const nsACString& BodyBlobURISpec() const { return EmptyCString(); }
291 using FetchBody::BodyLocalPath;
293 const nsAString& BodyLocalPath() const { return EmptyString(); }
295 private:
296 EmptyBody(nsIGlobalObject* aGlobal,
297 mozilla::ipc::PrincipalInfo* aPrincipalInfo,
298 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
299 const nsACString& aMixedCaseMimeType,
300 already_AddRefed<nsIInputStream> aBodyStream);
302 ~EmptyBody();
304 UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
305 RefPtr<AbortSignalImpl> mAbortSignalImpl;
306 nsCString mMimeType;
307 nsCString mMixedCaseMimeType;
308 nsCOMPtr<nsIInputStream> mBodyStream;
310 } // namespace dom
311 } // namespace mozilla
313 #endif // mozilla_dom_Fetch_h