Line data Source code
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/. */
6 :
7 : #ifndef mozilla_dom_Fetch_h
8 : #define mozilla_dom_Fetch_h
9 :
10 : #include "nsAutoPtr.h"
11 : #include "nsIStreamLoader.h"
12 :
13 : #include "nsCOMPtr.h"
14 : #include "nsError.h"
15 : #include "nsProxyRelease.h"
16 : #include "nsString.h"
17 :
18 : #include "mozilla/DebugOnly.h"
19 : #include "mozilla/ErrorResult.h"
20 : #include "mozilla/dom/Promise.h"
21 : #include "mozilla/dom/RequestBinding.h"
22 :
23 : class nsIGlobalObject;
24 : class nsIEventTarget;
25 :
26 : namespace mozilla {
27 : namespace dom {
28 :
29 : class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
30 : class BlobImpl;
31 : class InternalRequest;
32 : class OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
33 : class RequestOrUSVString;
34 : enum class CallerType : uint32_t;
35 :
36 : namespace workers {
37 : class WorkerPrivate;
38 : } // namespace workers
39 :
40 : already_AddRefed<Promise>
41 : FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
42 : const RequestInit& aInit, CallerType aCallerType,
43 : ErrorResult& aRv);
44 :
45 : nsresult
46 : UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
47 :
48 : namespace fetch {
49 : typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString BodyInit;
50 : typedef OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString OwningBodyInit;
51 : };
52 :
53 : /*
54 : * Creates an nsIInputStream based on the fetch specifications 'extract a byte
55 : * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
56 : * Stores content type in out param aContentType.
57 : */
58 : nsresult
59 : ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
60 : nsIInputStream** aStream,
61 : nsCString& aContentType,
62 : uint64_t& aContentLength);
63 :
64 : /*
65 : * Non-owning version.
66 : */
67 : nsresult
68 : ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
69 : nsIInputStream** aStream,
70 : nsCString& aContentType,
71 : uint64_t& aContentLength);
72 :
73 : template <class Derived> class FetchBodyConsumer;
74 :
75 : enum FetchConsumeType
76 : {
77 : CONSUME_ARRAYBUFFER,
78 : CONSUME_BLOB,
79 : CONSUME_FORMDATA,
80 : CONSUME_JSON,
81 : CONSUME_TEXT,
82 : };
83 :
84 : /*
85 : * FetchBody's body consumption uses nsIInputStreamPump to read from the
86 : * underlying stream to a block of memory, which is then adopted by
87 : * ContinueConsumeBody() and converted to the right type based on the JS
88 : * function called.
89 : *
90 : * Use of the nsIInputStreamPump complicates things on the worker thread.
91 : * The solution used here is similar to WebSockets.
92 : * The difference is that we are only interested in completion and not data
93 : * events, and nsIInputStreamPump can only deliver completion on the main thread.
94 : *
95 : * Before starting the pump on the main thread, we addref the FetchBody to keep
96 : * it alive. Then we add a feature, to track the status of the worker.
97 : *
98 : * ContinueConsumeBody() is the function that cleans things up in both success
99 : * and error conditions and so all callers call it with the appropriate status.
100 : *
101 : * Once the read is initiated on the main thread there are two possibilities.
102 : *
103 : * 1) Pump finishes before worker has finished Running.
104 : * In this case we adopt the data and dispatch a runnable to the worker,
105 : * which derefs FetchBody and removes the feature and resolves the Promise.
106 : *
107 : * 2) Pump still working while worker has stopped Running.
108 : * The feature is Notify()ed and ContinueConsumeBody() is called with
109 : * NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
110 : * ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
111 : * held by it) until pump->Cancel() is called. OnStreamComplete() will not
112 : * do anything if the error code is NS_BINDING_ABORTED, so we don't have to
113 : * worry about keeping anything alive.
114 : *
115 : * The pump is always released on the main thread.
116 : */
117 : template <class Derived>
118 : class FetchBody
119 : {
120 : public:
121 : friend class FetchBodyConsumer<Derived>;
122 :
123 : NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
124 :
125 : bool
126 2 : BodyUsed() const { return mBodyUsed; }
127 :
128 : already_AddRefed<Promise>
129 0 : ArrayBuffer(ErrorResult& aRv)
130 : {
131 0 : return ConsumeBody(CONSUME_ARRAYBUFFER, aRv);
132 : }
133 :
134 : already_AddRefed<Promise>
135 0 : Blob(ErrorResult& aRv)
136 : {
137 0 : return ConsumeBody(CONSUME_BLOB, aRv);
138 : }
139 :
140 : already_AddRefed<Promise>
141 0 : FormData(ErrorResult& aRv)
142 : {
143 0 : return ConsumeBody(CONSUME_FORMDATA, aRv);
144 : }
145 :
146 : already_AddRefed<Promise>
147 1 : Json(ErrorResult& aRv)
148 : {
149 1 : return ConsumeBody(CONSUME_JSON, aRv);
150 : }
151 :
152 : already_AddRefed<Promise>
153 0 : Text(ErrorResult& aRv)
154 : {
155 0 : return ConsumeBody(CONSUME_TEXT, aRv);
156 : }
157 :
158 : // Utility public methods accessed by various runnables.
159 :
160 : void
161 1 : SetBodyUsed()
162 : {
163 1 : mBodyUsed = true;
164 1 : }
165 :
166 : const nsCString&
167 0 : MimeType() const
168 : {
169 0 : return mMimeType;
170 : }
171 :
172 : protected:
173 : nsCOMPtr<nsIGlobalObject> mOwner;
174 :
175 : // Always set whenever the FetchBody is created on the worker thread.
176 : workers::WorkerPrivate* mWorkerPrivate;
177 :
178 : explicit FetchBody(nsIGlobalObject* aOwner);
179 :
180 : virtual ~FetchBody();
181 :
182 : void
183 : SetMimeType();
184 :
185 : private:
186 : Derived*
187 9 : DerivedClass() const
188 : {
189 9 : return static_cast<Derived*>(const_cast<FetchBody*>(this));
190 : }
191 :
192 : already_AddRefed<Promise>
193 : ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
194 :
195 : bool
196 : IsOnTargetThread()
197 : {
198 : return NS_IsMainThread() == !mWorkerPrivate;
199 : }
200 :
201 : void
202 : AssertIsOnTargetThread()
203 : {
204 : MOZ_ASSERT(IsOnTargetThread());
205 : }
206 :
207 : // Only ever set once, always on target thread.
208 : bool mBodyUsed;
209 : nsCString mMimeType;
210 :
211 : // The main-thread event target for runnable dispatching.
212 : nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
213 : };
214 :
215 : } // namespace dom
216 : } // namespace mozilla
217 :
218 : #endif // mozilla_dom_Fetch_h
|