Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / dom / fetch / Fetch.h
blob9b9dccd1eeb45521a6470446934f52d619f2fa8a
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/Promise.h"
20 #include "mozilla/dom/FetchStreamReader.h"
21 #include "mozilla/dom/ReadableStream.h"
22 #include "mozilla/dom/ReadableStreamDefaultReaderBinding.h"
23 #include "mozilla/dom/RequestBinding.h"
24 #include "mozilla/dom/workerinternals/RuntimeService.h"
26 class nsIGlobalObject;
27 class nsIEventTarget;
29 namespace mozilla {
30 class ErrorResult;
32 namespace ipc {
33 class PrincipalInfo;
34 } // namespace ipc
36 namespace dom {
38 class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
39 class
40 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
41 class BlobImpl;
42 class InternalRequest;
43 class
44 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
46 class ReadableStreamDefaultReader;
47 class RequestOrUSVString;
48 class WorkerPrivate;
50 enum class CallerType : uint32_t;
52 already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
53 const RequestOrUSVString& aInput,
54 const RequestInit& aInit,
55 CallerType aCallerType,
56 ErrorResult& aRv);
58 nsresult UpdateRequestReferrer(nsIGlobalObject* aGlobal,
59 InternalRequest* aRequest);
61 namespace fetch {
62 using BodyInit =
63 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
64 using ResponseBodyInit =
65 BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
66 using OwningBodyInit =
67 OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
68 }; // namespace fetch
71 * Creates an nsIInputStream based on the fetch specifications 'extract a byte
72 * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
73 * Stores content type in out param aContentType.
75 nsresult ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
76 nsIInputStream** aStream,
77 nsCString& aContentType,
78 uint64_t& aContentLength);
81 * Non-owning version.
83 nsresult ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
84 nsIInputStream** aStream,
85 nsCString& aContentType,
86 uint64_t& aContentLength);
89 * Non-owning version. This method should go away when BodyInit will contain
90 * ReadableStream.
92 nsresult ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
93 nsIInputStream** aStream,
94 nsCString& aContentType,
95 uint64_t& aContentLength);
98 * FetchBody's body consumption uses nsIInputStreamPump to read from the
99 * underlying stream to a block of memory, which is then adopted by
100 * ContinueConsumeBody() and converted to the right type based on the JS
101 * function called.
103 * Use of the nsIInputStreamPump complicates things on the worker thread.
104 * The solution used here is similar to WebSockets.
105 * The difference is that we are only interested in completion and not data
106 * events, and nsIInputStreamPump can only deliver completion on the main
107 * thread.
109 * Before starting the pump on the main thread, we addref the FetchBody to keep
110 * it alive. Then we add a feature, to track the status of the worker.
112 * ContinueConsumeBody() is the function that cleans things up in both success
113 * and error conditions and so all callers call it with the appropriate status.
115 * Once the read is initiated on the main thread there are two possibilities.
117 * 1) Pump finishes before worker has finished Running.
118 * In this case we adopt the data and dispatch a runnable to the worker,
119 * which derefs FetchBody and removes the feature and resolves the Promise.
121 * 2) Pump still working while worker has stopped Running.
122 * The feature is Notify()ed and ContinueConsumeBody() is called with
123 * NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
124 * ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
125 * held by it) until pump->Cancel() is called. OnStreamComplete() will not
126 * do anything if the error code is NS_BINDING_ABORTED, so we don't have to
127 * worry about keeping anything alive.
129 * The pump is always released on the main thread.
132 class FetchBodyBase : public nsISupports {
133 public:
134 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
135 NS_DECL_CYCLE_COLLECTION_CLASS(FetchBodyBase)
137 protected:
138 virtual ~FetchBodyBase() = default;
140 RefPtr<ReadableStream> mReadableStreamBody;
143 template <class Derived>
144 class FetchBody : public FetchBodyBase, public AbortFollower {
145 public:
146 using FetchBodyBase::QueryInterface;
148 NS_INLINE_DECL_REFCOUNTING_INHERITED(FetchBody, FetchBodyBase)
150 bool BodyUsed() const;
152 already_AddRefed<Promise> ArrayBuffer(JSContext* aCx, ErrorResult& aRv) {
153 return ConsumeBody(aCx, BodyConsumer::CONSUME_ARRAYBUFFER, aRv);
156 already_AddRefed<Promise> Blob(JSContext* aCx, ErrorResult& aRv) {
157 return ConsumeBody(aCx, BodyConsumer::CONSUME_BLOB, aRv);
160 already_AddRefed<Promise> FormData(JSContext* aCx, ErrorResult& aRv) {
161 return ConsumeBody(aCx, BodyConsumer::CONSUME_FORMDATA, aRv);
164 already_AddRefed<Promise> Json(JSContext* aCx, ErrorResult& aRv) {
165 return ConsumeBody(aCx, BodyConsumer::CONSUME_JSON, aRv);
168 already_AddRefed<Promise> Text(JSContext* aCx, ErrorResult& aRv) {
169 return ConsumeBody(aCx, BodyConsumer::CONSUME_TEXT, aRv);
172 already_AddRefed<ReadableStream> GetBody(JSContext* aCx, ErrorResult& aRv);
173 void GetMimeType(nsACString& aMimeType, nsACString& aMixedCaseMimeType);
175 const nsACString& BodyBlobURISpec() const;
177 const nsAString& BodyLocalPath() const;
179 // If the body contains a ReadableStream body object, this method produces a
180 // tee() of it.
182 // This is marked as a script boundary minimize changes required for
183 // annotation while we work out how to correctly annotate this code.
184 // Tracked in Bug 1750650.
185 MOZ_CAN_RUN_SCRIPT_BOUNDARY
186 void MaybeTeeReadableStreamBody(JSContext* aCx, ReadableStream** aBodyOut,
187 FetchStreamReader** aStreamReader,
188 nsIInputStream** aInputStream,
189 ErrorResult& aRv);
191 // Utility public methods accessed by various runnables.
193 // This method _must_ be called in order to set the body as used. If the body
194 // is a ReadableStream, this method will start reading the stream.
195 // More in details, this method does:
196 // 1) It uses an internal flag to track if the body is used. This is tracked
197 // separately from the ReadableStream disturbed state due to purely native
198 // streams.
199 // 2) If there is a ReadableStream reflector for the native stream it is
200 // Locked.
201 // 3) If there is a JS ReadableStream then we begin pumping it into the native
202 // body stream. This effectively locks and disturbs the stream.
204 // Note that JSContext is used only if there is a ReadableStream (this can
205 // happen because the body is a ReadableStream or because attribute body has
206 // already been used by content). If something goes wrong using
207 // ReadableStream, errors will be reported via ErrorResult and not as JS
208 // exceptions in JSContext. This is done in order to have a centralized error
209 // reporting way.
211 // Exceptions generated when reading from the ReadableStream are directly sent
212 // to the Console.
213 void SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
215 virtual AbortSignalImpl* GetSignalImpl() const = 0;
217 virtual AbortSignalImpl* GetSignalImplToConsumeBody() const = 0;
219 // AbortFollower
220 void RunAbortAlgorithm() override;
222 already_AddRefed<Promise> ConsumeBody(JSContext* aCx,
223 BodyConsumer::ConsumeType aType,
224 ErrorResult& aRv);
226 protected:
227 nsCOMPtr<nsIGlobalObject> mOwner;
229 // This is the Reader used to retrieve data from the body. This needs to be
230 // traversed by subclasses.
231 RefPtr<FetchStreamReader> mFetchStreamReader;
233 explicit FetchBody(nsIGlobalObject* aOwner);
235 virtual ~FetchBody();
237 void SetReadableStreamBody(JSContext* aCx, ReadableStream* aBody);
239 private:
240 Derived* DerivedClass() const {
241 return static_cast<Derived*>(const_cast<FetchBody*>(this));
244 void LockStream(JSContext* aCx, ReadableStream* aStream, ErrorResult& aRv);
246 void AssertIsOnTargetThread() {
247 MOZ_ASSERT(NS_IsMainThread() == !GetCurrentThreadWorkerPrivate());
250 // Only ever set once, always on target thread.
251 bool mBodyUsed;
253 // The main-thread event target for runnable dispatching.
254 nsCOMPtr<nsISerialEventTarget> mMainThreadEventTarget;
257 class EmptyBody final : public FetchBody<EmptyBody> {
258 NS_DECL_ISUPPORTS_INHERITED
259 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(EmptyBody,
260 FetchBody<EmptyBody>)
262 public:
263 static already_AddRefed<EmptyBody> Create(
264 nsIGlobalObject* aGlobal, mozilla::ipc::PrincipalInfo* aPrincipalInfo,
265 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
266 const nsACString& aMixedCaseMimeType, ErrorResult& aRv);
268 nsIGlobalObject* GetParentObject() const { return mOwner; }
270 AbortSignalImpl* GetSignalImpl() const override { return mAbortSignalImpl; }
271 AbortSignalImpl* GetSignalImplToConsumeBody() const final { return nullptr; }
273 const UniquePtr<mozilla::ipc::PrincipalInfo>& GetPrincipalInfo() const {
274 return mPrincipalInfo;
277 void GetMimeType(nsACString& aMimeType, nsACString& aMixedCaseMimeType) {
278 aMimeType = mMimeType;
279 aMixedCaseMimeType = mMixedCaseMimeType;
282 void GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr);
284 using FetchBody::BodyBlobURISpec;
286 const nsACString& BodyBlobURISpec() const { return EmptyCString(); }
288 using FetchBody::BodyLocalPath;
290 const nsAString& BodyLocalPath() const { return EmptyString(); }
292 private:
293 EmptyBody(nsIGlobalObject* aGlobal,
294 mozilla::ipc::PrincipalInfo* aPrincipalInfo,
295 AbortSignalImpl* aAbortSignalImpl, const nsACString& aMimeType,
296 const nsACString& aMixedCaseMimeType,
297 already_AddRefed<nsIInputStream> aBodyStream);
299 ~EmptyBody();
301 UniquePtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
302 RefPtr<AbortSignalImpl> mAbortSignalImpl;
303 nsCString mMimeType;
304 nsCString mMixedCaseMimeType;
305 nsCOMPtr<nsIInputStream> mBodyStream;
307 } // namespace dom
308 } // namespace mozilla
310 #endif // mozilla_dom_Fetch_h