/src/mozilla-central/dom/fetch/FetchConsumer.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | #include "Fetch.h" |
8 | | #include "FetchConsumer.h" |
9 | | |
10 | | #include "mozilla/dom/BlobBinding.h" |
11 | | #include "mozilla/dom/File.h" |
12 | | #include "mozilla/dom/FileBinding.h" |
13 | | #include "mozilla/dom/FileCreatorHelper.h" |
14 | | #include "mozilla/dom/PromiseNativeHandler.h" |
15 | | #include "mozilla/dom/WorkerCommon.h" |
16 | | #include "mozilla/dom/WorkerPrivate.h" |
17 | | #include "mozilla/dom/WorkerRef.h" |
18 | | #include "mozilla/dom/WorkerRunnable.h" |
19 | | #include "mozilla/dom/WorkerScope.h" |
20 | | #include "mozilla/ipc/PBackgroundSharedTypes.h" |
21 | | #include "nsIInputStreamPump.h" |
22 | | #include "nsIThreadRetargetableRequest.h" |
23 | | #include "nsProxyRelease.h" |
24 | | |
25 | | // Undefine the macro of CreateFile to avoid FileCreatorHelper#CreateFile being |
26 | | // replaced by FileCreatorHelper#CreateFileW. |
27 | | #ifdef CreateFile |
28 | | #undef CreateFile |
29 | | #endif |
30 | | |
31 | | namespace mozilla { |
32 | | namespace dom { |
33 | | |
34 | | namespace { |
35 | | |
36 | | template <class Derived> |
37 | | class BeginConsumeBodyRunnable final : public Runnable |
38 | | { |
39 | | public: |
40 | | BeginConsumeBodyRunnable(FetchBodyConsumer<Derived>* aConsumer, |
41 | | ThreadSafeWorkerRef* aWorkerRef) |
42 | | : Runnable("BeginConsumeBodyRunnable") |
43 | | , mFetchBodyConsumer(aConsumer) |
44 | | , mWorkerRef(aWorkerRef) |
45 | 0 | { } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::BeginConsumeBodyRunnable<mozilla::dom::Request>::BeginConsumeBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::ThreadSafeWorkerRef*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::BeginConsumeBodyRunnable<mozilla::dom::Response>::BeginConsumeBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::ThreadSafeWorkerRef*) |
46 | | |
47 | | NS_IMETHOD |
48 | | Run() override |
49 | 0 | { |
50 | 0 | mFetchBodyConsumer->BeginConsumeBodyMainThread(mWorkerRef); |
51 | 0 | return NS_OK; |
52 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::BeginConsumeBodyRunnable<mozilla::dom::Request>::Run() Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::BeginConsumeBodyRunnable<mozilla::dom::Response>::Run() |
53 | | |
54 | | private: |
55 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
56 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
57 | | }; |
58 | | |
59 | | /* |
60 | | * Called on successfully reading the complete stream. |
61 | | */ |
62 | | template <class Derived> |
63 | | class ContinueConsumeBodyRunnable final : public MainThreadWorkerRunnable |
64 | | { |
65 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
66 | | nsresult mStatus; |
67 | | uint32_t mLength; |
68 | | uint8_t* mResult; |
69 | | |
70 | | public: |
71 | | ContinueConsumeBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer, |
72 | | WorkerPrivate* aWorkerPrivate, |
73 | | nsresult aStatus, uint32_t aLength, |
74 | | uint8_t* aResult) |
75 | | : MainThreadWorkerRunnable(aWorkerPrivate) |
76 | | , mFetchBodyConsumer(aFetchBodyConsumer) |
77 | | , mStatus(aStatus) |
78 | | , mLength(aLength) |
79 | | , mResult(aResult) |
80 | 0 | { |
81 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
82 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBodyRunnable<mozilla::dom::Request>::ContinueConsumeBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::WorkerPrivate*, nsresult, unsigned int, unsigned char*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBodyRunnable<mozilla::dom::Response>::ContinueConsumeBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::WorkerPrivate*, nsresult, unsigned int, unsigned char*) |
83 | | |
84 | | bool |
85 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
86 | 0 | { |
87 | 0 | mFetchBodyConsumer->ContinueConsumeBody(mStatus, mLength, mResult); |
88 | 0 | return true; |
89 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBodyRunnable<mozilla::dom::Request>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBodyRunnable<mozilla::dom::Response>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) |
90 | | }; |
91 | | |
92 | | // ControlRunnable used to complete the releasing of resources on the worker |
93 | | // thread when already shutting down. |
94 | | template <class Derived> |
95 | | class AbortConsumeBodyControlRunnable final : public MainThreadWorkerControlRunnable |
96 | | { |
97 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
98 | | |
99 | | public: |
100 | | AbortConsumeBodyControlRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer, |
101 | | WorkerPrivate* aWorkerPrivate) |
102 | | : MainThreadWorkerControlRunnable(aWorkerPrivate) |
103 | | , mFetchBodyConsumer(aFetchBodyConsumer) |
104 | 0 | { |
105 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
106 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBodyControlRunnable<mozilla::dom::Request>::AbortConsumeBodyControlRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBodyControlRunnable<mozilla::dom::Response>::AbortConsumeBodyControlRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::WorkerPrivate*) |
107 | | |
108 | | bool |
109 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
110 | 0 | { |
111 | 0 | mFetchBodyConsumer->ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr, |
112 | 0 | true /* shutting down */); |
113 | 0 | return true; |
114 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBodyControlRunnable<mozilla::dom::Request>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBodyControlRunnable<mozilla::dom::Response>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) |
115 | | }; |
116 | | |
117 | | /* |
118 | | * In case of failure to create a stream pump or dispatch stream completion to |
119 | | * worker, ensure we cleanup properly. Thread agnostic. |
120 | | */ |
121 | | template <class Derived> |
122 | | class MOZ_STACK_CLASS AutoFailConsumeBody final |
123 | | { |
124 | | public: |
125 | | AutoFailConsumeBody(FetchBodyConsumer<Derived>* aBodyConsumer, |
126 | | ThreadSafeWorkerRef* aWorkerRef) |
127 | | : mBodyConsumer(aBodyConsumer) |
128 | | , mWorkerRef(aWorkerRef) |
129 | 0 | {} Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Request>::AutoFailConsumeBody(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::ThreadSafeWorkerRef*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Response>::AutoFailConsumeBody(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::ThreadSafeWorkerRef*) |
130 | | |
131 | | ~AutoFailConsumeBody() |
132 | 0 | { |
133 | 0 | AssertIsOnMainThread(); |
134 | 0 |
|
135 | 0 | if (!mBodyConsumer) { |
136 | 0 | return; |
137 | 0 | } |
138 | 0 | |
139 | 0 | // Web Worker |
140 | 0 | if (mWorkerRef) { |
141 | 0 | RefPtr<AbortConsumeBodyControlRunnable<Derived>> r = |
142 | 0 | new AbortConsumeBodyControlRunnable<Derived>(mBodyConsumer, |
143 | 0 | mWorkerRef->Private()); |
144 | 0 | if (!r->Dispatch()) { |
145 | 0 | MOZ_CRASH("We are going to leak"); |
146 | 0 | } |
147 | 0 | return; |
148 | 0 | } |
149 | 0 | |
150 | 0 | // Main-thread |
151 | 0 | mBodyConsumer->ContinueConsumeBody(NS_ERROR_FAILURE, 0, nullptr); |
152 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Request>::~AutoFailConsumeBody() Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Response>::~AutoFailConsumeBody() |
153 | | |
154 | | void |
155 | | DontFail() |
156 | 0 | { |
157 | 0 | mBodyConsumer = nullptr; |
158 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Request>::DontFail() Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AutoFailConsumeBody<mozilla::dom::Response>::DontFail() |
159 | | |
160 | | private: |
161 | | RefPtr<FetchBodyConsumer<Derived>> mBodyConsumer; |
162 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
163 | | }; |
164 | | |
165 | | /* |
166 | | * Called on successfully reading the complete stream for Blob. |
167 | | */ |
168 | | template <class Derived> |
169 | | class ContinueConsumeBlobBodyRunnable final : public MainThreadWorkerRunnable |
170 | | { |
171 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
172 | | RefPtr<BlobImpl> mBlobImpl; |
173 | | |
174 | | public: |
175 | | ContinueConsumeBlobBodyRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer, |
176 | | WorkerPrivate* aWorkerPrivate, |
177 | | BlobImpl* aBlobImpl) |
178 | | : MainThreadWorkerRunnable(aWorkerPrivate) |
179 | | , mFetchBodyConsumer(aFetchBodyConsumer) |
180 | | , mBlobImpl(aBlobImpl) |
181 | 0 | { |
182 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
183 | 0 | MOZ_ASSERT(mBlobImpl); |
184 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBlobBodyRunnable<mozilla::dom::Request>::ContinueConsumeBlobBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::WorkerPrivate*, mozilla::dom::BlobImpl*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBlobBodyRunnable<mozilla::dom::Response>::ContinueConsumeBlobBodyRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::WorkerPrivate*, mozilla::dom::BlobImpl*) |
185 | | |
186 | | bool |
187 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
188 | 0 | { |
189 | 0 | mFetchBodyConsumer->ContinueConsumeBlobBody(mBlobImpl); |
190 | 0 | return true; |
191 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBlobBodyRunnable<mozilla::dom::Request>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ContinueConsumeBlobBodyRunnable<mozilla::dom::Response>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) |
192 | | }; |
193 | | |
194 | | // ControlRunnable used to complete the releasing of resources on the worker |
195 | | // thread when already shutting down. |
196 | | template <class Derived> |
197 | | class AbortConsumeBlobBodyControlRunnable final |
198 | | : public MainThreadWorkerControlRunnable |
199 | | { |
200 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
201 | | |
202 | | public: |
203 | | AbortConsumeBlobBodyControlRunnable(FetchBodyConsumer<Derived>* aFetchBodyConsumer, |
204 | | WorkerPrivate* aWorkerPrivate) |
205 | | : MainThreadWorkerControlRunnable(aWorkerPrivate) |
206 | | , mFetchBodyConsumer(aFetchBodyConsumer) |
207 | 0 | { |
208 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
209 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBlobBodyControlRunnable<mozilla::dom::Request>::AbortConsumeBlobBodyControlRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBlobBodyControlRunnable<mozilla::dom::Response>::AbortConsumeBlobBodyControlRunnable(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::WorkerPrivate*) |
210 | | |
211 | | bool |
212 | | WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override |
213 | 0 | { |
214 | 0 | mFetchBodyConsumer->ContinueConsumeBlobBody(nullptr, |
215 | 0 | true /* shutting down */); |
216 | 0 | return true; |
217 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBlobBodyControlRunnable<mozilla::dom::Request>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::AbortConsumeBlobBodyControlRunnable<mozilla::dom::Response>::WorkerRun(JSContext*, mozilla::dom::WorkerPrivate*) |
218 | | }; |
219 | | |
220 | | template <class Derived> |
221 | | class ConsumeBodyDoneObserver final : public nsIStreamLoaderObserver |
222 | | , public MutableBlobStorageCallback |
223 | | { |
224 | | public: |
225 | | NS_DECL_THREADSAFE_ISUPPORTS |
226 | | |
227 | | ConsumeBodyDoneObserver(FetchBodyConsumer<Derived>* aFetchBodyConsumer, |
228 | | ThreadSafeWorkerRef* aWorkerRef) |
229 | | : mFetchBodyConsumer(aFetchBodyConsumer) |
230 | | , mWorkerRef(aWorkerRef) |
231 | 0 | { } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Request>::ConsumeBodyDoneObserver(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*, mozilla::dom::ThreadSafeWorkerRef*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Response>::ConsumeBodyDoneObserver(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*, mozilla::dom::ThreadSafeWorkerRef*) |
232 | | |
233 | | NS_IMETHOD |
234 | | OnStreamComplete(nsIStreamLoader* aLoader, |
235 | | nsISupports* aCtxt, |
236 | | nsresult aStatus, |
237 | | uint32_t aResultLength, |
238 | | const uint8_t* aResult) override |
239 | 0 | { |
240 | 0 | MOZ_ASSERT(NS_IsMainThread()); |
241 | 0 |
|
242 | 0 | // The loading is completed. Let's nullify the pump before continuing the |
243 | 0 | // consuming of the body. |
244 | 0 | mFetchBodyConsumer->NullifyConsumeBodyPump(); |
245 | 0 |
|
246 | 0 | uint8_t* nonconstResult = const_cast<uint8_t*>(aResult); |
247 | 0 |
|
248 | 0 | // Main-thread. |
249 | 0 | if (!mWorkerRef) { |
250 | 0 | mFetchBodyConsumer->ContinueConsumeBody(aStatus, aResultLength, |
251 | 0 | nonconstResult); |
252 | 0 | // FetchBody is responsible for data. |
253 | 0 | return NS_SUCCESS_ADOPTED_DATA; |
254 | 0 | } |
255 | 0 | |
256 | 0 | // Web Worker. |
257 | 0 | { |
258 | 0 | RefPtr<ContinueConsumeBodyRunnable<Derived>> r = |
259 | 0 | new ContinueConsumeBodyRunnable<Derived>(mFetchBodyConsumer, |
260 | 0 | mWorkerRef->Private(), |
261 | 0 | aStatus, |
262 | 0 | aResultLength, |
263 | 0 | nonconstResult); |
264 | 0 | if (r->Dispatch()) { |
265 | 0 | // FetchBody is responsible for data. |
266 | 0 | return NS_SUCCESS_ADOPTED_DATA; |
267 | 0 | } |
268 | 0 | } |
269 | 0 | |
270 | 0 | // The worker is shutting down. Let's use a control runnable to complete the |
271 | 0 | // shutting down procedure. |
272 | 0 | |
273 | 0 | RefPtr<AbortConsumeBodyControlRunnable<Derived>> r = |
274 | 0 | new AbortConsumeBodyControlRunnable<Derived>(mFetchBodyConsumer, |
275 | 0 | mWorkerRef->Private()); |
276 | 0 | if (NS_WARN_IF(!r->Dispatch())) { |
277 | 0 | return NS_ERROR_FAILURE; |
278 | 0 | } |
279 | 0 | |
280 | 0 | // We haven't taken ownership of the data. |
281 | 0 | return NS_OK; |
282 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Request>::OnStreamComplete(nsIStreamLoader*, nsISupports*, nsresult, unsigned int, unsigned char const*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Response>::OnStreamComplete(nsIStreamLoader*, nsISupports*, nsresult, unsigned int, unsigned char const*) |
283 | | |
284 | | virtual void BlobStoreCompleted(MutableBlobStorage* aBlobStorage, |
285 | | Blob* aBlob, |
286 | | nsresult aRv) override |
287 | 0 | { |
288 | 0 | // On error. |
289 | 0 | if (NS_FAILED(aRv)) { |
290 | 0 | OnStreamComplete(nullptr, nullptr, aRv, 0, nullptr); |
291 | 0 | return; |
292 | 0 | } |
293 | 0 | |
294 | 0 | // The loading is completed. Let's nullify the pump before continuing the |
295 | 0 | // consuming of the body. |
296 | 0 | mFetchBodyConsumer->NullifyConsumeBodyPump(); |
297 | 0 |
|
298 | 0 | mFetchBodyConsumer->OnBlobResult(aBlob, mWorkerRef); |
299 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Request>::BlobStoreCompleted(mozilla::dom::MutableBlobStorage*, mozilla::dom::Blob*, nsresult) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Response>::BlobStoreCompleted(mozilla::dom::MutableBlobStorage*, mozilla::dom::Blob*, nsresult) |
300 | | |
301 | | private: |
302 | 0 | ~ConsumeBodyDoneObserver() = default; Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Request>::~ConsumeBodyDoneObserver() Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Response>::~ConsumeBodyDoneObserver() |
303 | | |
304 | | RefPtr<FetchBodyConsumer<Derived>> mFetchBodyConsumer; |
305 | | RefPtr<ThreadSafeWorkerRef> mWorkerRef; |
306 | | }; |
307 | | |
308 | | template <class Derived> |
309 | | NS_IMPL_ADDREF(ConsumeBodyDoneObserver<Derived>) |
310 | | template <class Derived> |
311 | | NS_IMPL_RELEASE(ConsumeBodyDoneObserver<Derived>) |
312 | | template <class Derived> |
313 | 0 | NS_INTERFACE_MAP_BEGIN(ConsumeBodyDoneObserver<Derived>) |
314 | 0 | NS_INTERFACE_MAP_ENTRY(nsIStreamLoaderObserver) |
315 | 0 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamLoaderObserver) |
316 | 0 | NS_INTERFACE_MAP_END Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Request>::QueryInterface(nsID const&, void**) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::ConsumeBodyDoneObserver<mozilla::dom::Response>::QueryInterface(nsID const&, void**) |
317 | | |
318 | | } // anonymous |
319 | | |
320 | | template <class Derived> |
321 | | /* static */ already_AddRefed<Promise> |
322 | | FetchBodyConsumer<Derived>::Create(nsIGlobalObject* aGlobal, |
323 | | nsIEventTarget* aMainThreadEventTarget, |
324 | | FetchBody<Derived>* aBody, |
325 | | AbortSignalImpl* aSignalImpl, |
326 | | FetchConsumeType aType, |
327 | | ErrorResult& aRv) |
328 | 0 | { |
329 | 0 | MOZ_ASSERT(aBody); |
330 | 0 | MOZ_ASSERT(aMainThreadEventTarget); |
331 | 0 |
|
332 | 0 | nsCOMPtr<nsIInputStream> bodyStream; |
333 | 0 | aBody->DerivedClass()->GetBody(getter_AddRefs(bodyStream)); |
334 | 0 | if (!bodyStream) { |
335 | 0 | aRv = NS_NewCStringInputStream(getter_AddRefs(bodyStream), EmptyCString()); |
336 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
337 | 0 | return nullptr; |
338 | 0 | } |
339 | 0 | } |
340 | 0 | |
341 | 0 | RefPtr<Promise> promise = Promise::Create(aGlobal, aRv); |
342 | 0 | if (aRv.Failed()) { |
343 | 0 | return nullptr; |
344 | 0 | } |
345 | 0 | |
346 | 0 | RefPtr<FetchBodyConsumer<Derived>> consumer = |
347 | 0 | new FetchBodyConsumer<Derived>(aMainThreadEventTarget, aGlobal, |
348 | 0 | aBody, bodyStream, promise, |
349 | 0 | aType); |
350 | 0 |
|
351 | 0 | RefPtr<ThreadSafeWorkerRef> workerRef; |
352 | 0 |
|
353 | 0 | if (!NS_IsMainThread()) { |
354 | 0 | WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); |
355 | 0 | MOZ_ASSERT(workerPrivate); |
356 | 0 |
|
357 | 0 | RefPtr<StrongWorkerRef> strongWorkerRef = |
358 | 0 | StrongWorkerRef::Create(workerPrivate, "FetchBodyConsumer", |
359 | 0 | [consumer]() { |
360 | 0 | consumer->ShutDownMainThreadConsuming(); |
361 | 0 | }); Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::Create(nsIGlobalObject*, nsIEventTarget*, mozilla::dom::FetchBody<mozilla::dom::Request>*, mozilla::dom::AbortSignalImpl*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&)::{lambda()#1}::operator()() const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::Create(nsIGlobalObject*, nsIEventTarget*, mozilla::dom::FetchBody<mozilla::dom::Response>*, mozilla::dom::AbortSignalImpl*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&)::{lambda()#1}::operator()() const |
362 | 0 | if (NS_WARN_IF(!strongWorkerRef)) { |
363 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
364 | 0 | return nullptr; |
365 | 0 | } |
366 | 0 | |
367 | 0 | workerRef = new ThreadSafeWorkerRef(strongWorkerRef); |
368 | 0 | } else { |
369 | 0 | nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); |
370 | 0 | if (NS_WARN_IF(!os)) { |
371 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
372 | 0 | return nullptr; |
373 | 0 | } |
374 | 0 | |
375 | 0 | aRv = os->AddObserver(consumer, DOM_WINDOW_DESTROYED_TOPIC, true); |
376 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
377 | 0 | return nullptr; |
378 | 0 | } |
379 | 0 | |
380 | 0 | aRv = os->AddObserver(consumer, DOM_WINDOW_FROZEN_TOPIC, true); |
381 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
382 | 0 | return nullptr; |
383 | 0 | } |
384 | 0 | } |
385 | 0 | |
386 | 0 | nsCOMPtr<nsIRunnable> r = |
387 | 0 | new BeginConsumeBodyRunnable<Derived>(consumer, workerRef); |
388 | 0 | aRv = aMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); |
389 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
390 | 0 | return nullptr; |
391 | 0 | } |
392 | 0 | |
393 | 0 | if (aSignalImpl) { |
394 | 0 | consumer->Follow(aSignalImpl); |
395 | 0 | } |
396 | 0 |
|
397 | 0 | return promise.forget(); |
398 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::Create(nsIGlobalObject*, nsIEventTarget*, mozilla::dom::FetchBody<mozilla::dom::Request>*, mozilla::dom::AbortSignalImpl*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::Create(nsIGlobalObject*, nsIEventTarget*, mozilla::dom::FetchBody<mozilla::dom::Response>*, mozilla::dom::AbortSignalImpl*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&) |
399 | | |
400 | | template <class Derived> |
401 | | void |
402 | | FetchBodyConsumer<Derived>::ReleaseObject() |
403 | 0 | { |
404 | 0 | AssertIsOnTargetThread(); |
405 | 0 |
|
406 | 0 | if (NS_IsMainThread()) { |
407 | 0 | nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); |
408 | 0 | if (os) { |
409 | 0 | os->RemoveObserver(this, DOM_WINDOW_DESTROYED_TOPIC); |
410 | 0 | os->RemoveObserver(this, DOM_WINDOW_FROZEN_TOPIC); |
411 | 0 | } |
412 | 0 | } |
413 | 0 |
|
414 | 0 | mGlobal = nullptr; |
415 | 0 |
|
416 | | #ifdef DEBUG |
417 | | mBody = nullptr; |
418 | | #endif |
419 | |
|
420 | 0 | Unfollow(); |
421 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ReleaseObject() Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ReleaseObject() |
422 | | |
423 | | template <class Derived> |
424 | | FetchBodyConsumer<Derived>::FetchBodyConsumer(nsIEventTarget* aMainThreadEventTarget, |
425 | | nsIGlobalObject* aGlobalObject, |
426 | | FetchBody<Derived>* aBody, |
427 | | nsIInputStream* aBodyStream, |
428 | | Promise* aPromise, |
429 | | FetchConsumeType aType) |
430 | | : mTargetThread(NS_GetCurrentThread()) |
431 | | , mMainThreadEventTarget(aMainThreadEventTarget) |
432 | | #ifdef DEBUG |
433 | | , mBody(aBody) |
434 | | #endif |
435 | | , mBodyStream(aBodyStream) |
436 | | , mBlobStorageType(MutableBlobStorage::eOnlyInMemory) |
437 | | , mBodyLocalPath(aBody ? aBody->BodyLocalPath() : VoidString()) |
438 | | , mGlobal(aGlobalObject) |
439 | | , mConsumeType(aType) |
440 | | , mConsumePromise(aPromise) |
441 | | , mBodyConsumed(false) |
442 | | , mShuttingDown(false) |
443 | 0 | { |
444 | 0 | MOZ_ASSERT(aMainThreadEventTarget); |
445 | 0 | MOZ_ASSERT(aBody); |
446 | 0 | MOZ_ASSERT(aBodyStream); |
447 | 0 | MOZ_ASSERT(aPromise); |
448 | 0 |
|
449 | 0 | const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo = |
450 | 0 | aBody->DerivedClass()->GetPrincipalInfo(); |
451 | 0 | // We support temporary file for blobs only if the principal is known and |
452 | 0 | // it's system or content not in private Browsing. |
453 | 0 | if (principalInfo && |
454 | 0 | (principalInfo->type() == mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo || |
455 | 0 | (principalInfo->type() == mozilla::ipc::PrincipalInfo::TContentPrincipalInfo && |
456 | 0 | principalInfo->get_ContentPrincipalInfo().attrs().mPrivateBrowsingId == 0))) { |
457 | 0 | mBlobStorageType = MutableBlobStorage::eCouldBeInTemporaryFile; |
458 | 0 | } |
459 | 0 |
|
460 | 0 | mBodyMimeType = aBody->MimeType(); |
461 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::FetchBodyConsumer(nsIEventTarget*, nsIGlobalObject*, mozilla::dom::FetchBody<mozilla::dom::Request>*, nsIInputStream*, mozilla::dom::Promise*, mozilla::dom::FetchConsumeType) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::FetchBodyConsumer(nsIEventTarget*, nsIGlobalObject*, mozilla::dom::FetchBody<mozilla::dom::Response>*, nsIInputStream*, mozilla::dom::Promise*, mozilla::dom::FetchConsumeType) |
462 | | |
463 | | template <class Derived> |
464 | | FetchBodyConsumer<Derived>::~FetchBodyConsumer() |
465 | 0 | { |
466 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::~FetchBodyConsumer() Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::~FetchBodyConsumer() |
467 | | |
468 | | template <class Derived> |
469 | | void |
470 | | FetchBodyConsumer<Derived>::AssertIsOnTargetThread() const |
471 | 0 | { |
472 | 0 | MOZ_ASSERT(NS_GetCurrentThread() == mTargetThread); |
473 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::AssertIsOnTargetThread() const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::AssertIsOnTargetThread() const |
474 | | |
475 | | namespace { |
476 | | |
477 | | template <class Derived> |
478 | | class FileCreationHandler final : public PromiseNativeHandler |
479 | | { |
480 | | public: |
481 | | NS_DECL_THREADSAFE_ISUPPORTS |
482 | | |
483 | | static void |
484 | | Create(Promise* aPromise, FetchBodyConsumer<Derived>* aConsumer) |
485 | 0 | { |
486 | 0 | AssertIsOnMainThread(); |
487 | 0 | MOZ_ASSERT(aPromise); |
488 | 0 |
|
489 | 0 | RefPtr<FileCreationHandler> handler = new FileCreationHandler<Derived>(aConsumer); |
490 | 0 | aPromise->AppendNativeHandler(handler); |
491 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::Create(mozilla::dom::Promise*, mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::Create(mozilla::dom::Promise*, mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*) |
492 | | |
493 | | void |
494 | | ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override |
495 | 0 | { |
496 | 0 | AssertIsOnMainThread(); |
497 | 0 |
|
498 | 0 | if (NS_WARN_IF(!aValue.isObject())) { |
499 | 0 | mConsumer->OnBlobResult(nullptr); |
500 | 0 | return; |
501 | 0 | } |
502 | 0 | |
503 | 0 | RefPtr<Blob> blob; |
504 | 0 | if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Blob, &aValue.toObject(), blob)))) { |
505 | 0 | mConsumer->OnBlobResult(nullptr); |
506 | 0 | return; |
507 | 0 | } |
508 | 0 | |
509 | 0 | mConsumer->OnBlobResult(blob); |
510 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::ResolvedCallback(JSContext*, JS::Handle<JS::Value>) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::ResolvedCallback(JSContext*, JS::Handle<JS::Value>) |
511 | | |
512 | | void |
513 | | RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override |
514 | 0 | { |
515 | 0 | AssertIsOnMainThread(); |
516 | 0 |
|
517 | 0 | mConsumer->OnBlobResult(nullptr); |
518 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::RejectedCallback(JSContext*, JS::Handle<JS::Value>) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::RejectedCallback(JSContext*, JS::Handle<JS::Value>) |
519 | | |
520 | | private: |
521 | | explicit FileCreationHandler<Derived>(FetchBodyConsumer<Derived>* aConsumer) |
522 | | : mConsumer(aConsumer) |
523 | 0 | { |
524 | 0 | AssertIsOnMainThread(); |
525 | 0 | MOZ_ASSERT(aConsumer); |
526 | 0 | } Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::FileCreationHandler(mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>*) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::FileCreationHandler(mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>*) |
527 | | |
528 | 0 | ~FileCreationHandler() = default; Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::~FileCreationHandler() Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::~FileCreationHandler() |
529 | | |
530 | | RefPtr<FetchBodyConsumer<Derived>> mConsumer; |
531 | | }; |
532 | | |
533 | | template <class Derived> |
534 | | NS_IMPL_ADDREF(FileCreationHandler<Derived>) |
535 | | template <class Derived> |
536 | | NS_IMPL_RELEASE(FileCreationHandler<Derived>) |
537 | | template <class Derived> |
538 | 0 | NS_INTERFACE_MAP_BEGIN(FileCreationHandler<Derived>) |
539 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
540 | 0 | NS_INTERFACE_MAP_END Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Request>::QueryInterface(nsID const&, void**) Unexecuted instantiation: Unified_cpp_dom_fetch0.cpp:mozilla::dom::(anonymous namespace)::FileCreationHandler<mozilla::dom::Response>::QueryInterface(nsID const&, void**) |
541 | | |
542 | | } // namespace |
543 | | |
544 | | template <class Derived> |
545 | | nsresult |
546 | | FetchBodyConsumer<Derived>::GetBodyLocalFile(nsIFile** aFile) const |
547 | 0 | { |
548 | 0 | AssertIsOnMainThread(); |
549 | 0 |
|
550 | 0 | if (!mBodyLocalPath.Length()) { |
551 | 0 | return NS_OK; |
552 | 0 | } |
553 | 0 | |
554 | 0 | nsresult rv; |
555 | 0 | nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1", &rv); |
556 | 0 | if (NS_FAILED(rv)) { |
557 | 0 | return rv; |
558 | 0 | } |
559 | 0 | |
560 | 0 | rv = file->InitWithPath(mBodyLocalPath); |
561 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
562 | 0 |
|
563 | 0 | bool exists; |
564 | 0 | rv = file->Exists(&exists); |
565 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
566 | 0 | if (!exists) { |
567 | 0 | return NS_ERROR_FILE_NOT_FOUND; |
568 | 0 | } |
569 | 0 | |
570 | 0 | bool isDir; |
571 | 0 | rv = file->IsDirectory(&isDir); |
572 | 0 | NS_ENSURE_SUCCESS(rv, rv); |
573 | 0 | if (isDir) { |
574 | 0 | return NS_ERROR_FILE_IS_DIRECTORY; |
575 | 0 | } |
576 | 0 | |
577 | 0 | file.forget(aFile); |
578 | 0 | return NS_OK; |
579 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::GetBodyLocalFile(nsIFile**) const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::GetBodyLocalFile(nsIFile**) const |
580 | | |
581 | | /* |
582 | | * BeginConsumeBodyMainThread() will automatically reject the consume promise |
583 | | * and clean up on any failures, so there is no need for callers to do so, |
584 | | * reflected in a lack of error return code. |
585 | | */ |
586 | | template <class Derived> |
587 | | void |
588 | | FetchBodyConsumer<Derived>::BeginConsumeBodyMainThread(ThreadSafeWorkerRef* aWorkerRef) |
589 | 0 | { |
590 | 0 | AssertIsOnMainThread(); |
591 | 0 |
|
592 | 0 | AutoFailConsumeBody<Derived> autoReject(this, aWorkerRef); |
593 | 0 |
|
594 | 0 | if (mShuttingDown) { |
595 | 0 | // We haven't started yet, but we have been terminated. AutoFailConsumeBody |
596 | 0 | // will dispatch a runnable to release resources. |
597 | 0 | return; |
598 | 0 | } |
599 | 0 | |
600 | 0 | // If we're trying to consume a blob, and the request was for a local |
601 | 0 | // file, then generate and return a File blob. |
602 | 0 | if (mConsumeType == CONSUME_BLOB) { |
603 | 0 | nsCOMPtr<nsIFile> file; |
604 | 0 | nsresult rv = GetBodyLocalFile(getter_AddRefs(file)); |
605 | 0 | if (!NS_WARN_IF(NS_FAILED(rv)) && file) { |
606 | 0 | ChromeFilePropertyBag bag; |
607 | 0 | bag.mType = NS_ConvertUTF8toUTF16(mBodyMimeType); |
608 | 0 |
|
609 | 0 | ErrorResult error; |
610 | 0 | RefPtr<Promise> promise = |
611 | 0 | FileCreatorHelper::CreateFile(mGlobal, file, bag, true, error); |
612 | 0 | if (NS_WARN_IF(error.Failed())) { |
613 | 0 | return; |
614 | 0 | } |
615 | 0 | |
616 | 0 | FileCreationHandler<Derived>::Create(promise, this); |
617 | 0 | autoReject.DontFail(); |
618 | 0 | return; |
619 | 0 | } |
620 | 0 | } |
621 | 0 |
|
622 | 0 | nsCOMPtr<nsIInputStreamPump> pump; |
623 | 0 | nsresult rv = NS_NewInputStreamPump(getter_AddRefs(pump), |
624 | 0 | mBodyStream.forget(), 0, 0, false, |
625 | 0 | mMainThreadEventTarget); |
626 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
627 | 0 | return; |
628 | 0 | } |
629 | 0 | |
630 | 0 | RefPtr<ConsumeBodyDoneObserver<Derived>> p = |
631 | 0 | new ConsumeBodyDoneObserver<Derived>(this, aWorkerRef); |
632 | 0 |
|
633 | 0 | nsCOMPtr<nsIStreamListener> listener; |
634 | 0 | if (mConsumeType == CONSUME_BLOB) { |
635 | 0 | listener = new MutableBlobStreamListener(mBlobStorageType, nullptr, |
636 | 0 | mBodyMimeType, p, |
637 | 0 | mMainThreadEventTarget); |
638 | 0 | } else { |
639 | 0 | nsCOMPtr<nsIStreamLoader> loader; |
640 | 0 | rv = NS_NewStreamLoader(getter_AddRefs(loader), p); |
641 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
642 | 0 | return; |
643 | 0 | } |
644 | 0 | |
645 | 0 | listener = loader; |
646 | 0 | } |
647 | 0 |
|
648 | 0 | rv = pump->AsyncRead(listener, nullptr); |
649 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
650 | 0 | return; |
651 | 0 | } |
652 | 0 | |
653 | 0 | // Now that everything succeeded, we can assign the pump to a pointer that |
654 | 0 | // stays alive for the lifetime of the FetchConsumer. |
655 | 0 | mConsumeBodyPump = pump; |
656 | 0 |
|
657 | 0 | // It is ok for retargeting to fail and reads to happen on the main thread. |
658 | 0 | autoReject.DontFail(); |
659 | 0 |
|
660 | 0 | // Try to retarget, otherwise fall back to main thread. |
661 | 0 | nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(pump); |
662 | 0 | if (rr) { |
663 | 0 | nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
664 | 0 | rv = rr->RetargetDeliveryTo(sts); |
665 | 0 | if (NS_FAILED(rv)) { |
666 | 0 | NS_WARNING("Retargeting failed"); |
667 | 0 | } |
668 | 0 | } |
669 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::BeginConsumeBodyMainThread(mozilla::dom::ThreadSafeWorkerRef*) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::BeginConsumeBodyMainThread(mozilla::dom::ThreadSafeWorkerRef*) |
670 | | |
671 | | /* |
672 | | * OnBlobResult() is called when a blob body is ready to be consumed (when its |
673 | | * network transfer completes in BeginConsumeBodyRunnable or its local File has |
674 | | * been wrapped by FileCreationHandler). The blob is sent to the target thread |
675 | | * and ContinueConsumeBody is called. |
676 | | */ |
677 | | template <class Derived> |
678 | | void |
679 | | FetchBodyConsumer<Derived>::OnBlobResult(Blob* aBlob, ThreadSafeWorkerRef* aWorkerRef) |
680 | 0 | { |
681 | 0 | MOZ_ASSERT(aBlob); |
682 | 0 |
|
683 | 0 | // Main-thread. |
684 | 0 | if (!aWorkerRef) { |
685 | 0 | ContinueConsumeBlobBody(aBlob->Impl()); |
686 | 0 | return; |
687 | 0 | } |
688 | 0 | |
689 | 0 | // Web Worker. |
690 | 0 | { |
691 | 0 | RefPtr<ContinueConsumeBlobBodyRunnable<Derived>> r = |
692 | 0 | new ContinueConsumeBlobBodyRunnable<Derived>(this, aWorkerRef->Private(), |
693 | 0 | aBlob->Impl()); |
694 | 0 |
|
695 | 0 | if (r->Dispatch()) { |
696 | 0 | return; |
697 | 0 | } |
698 | 0 | } |
699 | 0 | |
700 | 0 | // The worker is shutting down. Let's use a control runnable to complete the |
701 | 0 | // shutting down procedure. |
702 | 0 | |
703 | 0 | RefPtr<AbortConsumeBlobBodyControlRunnable<Derived>> r = |
704 | 0 | new AbortConsumeBlobBodyControlRunnable<Derived>(this, |
705 | 0 | aWorkerRef->Private()); |
706 | 0 |
|
707 | 0 | Unused << NS_WARN_IF(!r->Dispatch()); |
708 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::OnBlobResult(mozilla::dom::Blob*, mozilla::dom::ThreadSafeWorkerRef*) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::OnBlobResult(mozilla::dom::Blob*, mozilla::dom::ThreadSafeWorkerRef*) |
709 | | |
710 | | /* |
711 | | * ContinueConsumeBody() is to be called on the target thread whenever the |
712 | | * final result of the fetch is known. The fetch promise is resolved or |
713 | | * rejected based on whether the fetch succeeded, and the body can be |
714 | | * converted into the expected type of JS object. |
715 | | */ |
716 | | template <class Derived> |
717 | | void |
718 | | FetchBodyConsumer<Derived>::ContinueConsumeBody(nsresult aStatus, |
719 | | uint32_t aResultLength, |
720 | | uint8_t* aResult, |
721 | | bool aShuttingDown) |
722 | 0 | { |
723 | 0 | AssertIsOnTargetThread(); |
724 | 0 |
|
725 | 0 | // This makes sure that we free the data correctly. |
726 | 0 | auto autoFree = mozilla::MakeScopeExit([&] { |
727 | 0 | free(aResult); |
728 | 0 | }); Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool)::{lambda()#1}::operator()() const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool)::{lambda()#1}::operator()() const |
729 | 0 |
|
730 | 0 | if (mBodyConsumed) { |
731 | 0 | return; |
732 | 0 | } |
733 | 0 | mBodyConsumed = true; |
734 | 0 |
|
735 | 0 | // Just a precaution to ensure ContinueConsumeBody is not called out of |
736 | 0 | // sync with a body read. |
737 | 0 | MOZ_ASSERT(mBody->BodyUsed()); |
738 | 0 |
|
739 | 0 | MOZ_ASSERT(mConsumePromise); |
740 | 0 | RefPtr<Promise> localPromise = mConsumePromise.forget(); |
741 | 0 |
|
742 | 0 | RefPtr<FetchBodyConsumer<Derived>> self = this; |
743 | 0 | auto autoReleaseObject = mozilla::MakeScopeExit([self] { |
744 | 0 | self->ReleaseObject(); |
745 | 0 | }); Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool)::{lambda()#2}::operator()() const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool)::{lambda()#2}::operator()() const |
746 | 0 |
|
747 | 0 | if (aShuttingDown) { |
748 | 0 | // If shutting down, we don't want to resolve any promise. |
749 | 0 | return; |
750 | 0 | } |
751 | 0 | |
752 | 0 | if (NS_WARN_IF(NS_FAILED(aStatus))) { |
753 | 0 | localPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); |
754 | 0 | } |
755 | 0 |
|
756 | 0 | // Don't warn here since we warned above. |
757 | 0 | if (NS_FAILED(aStatus)) { |
758 | 0 | return; |
759 | 0 | } |
760 | 0 | |
761 | 0 | // Finish successfully consuming body according to type. |
762 | 0 | MOZ_ASSERT(aResult); |
763 | 0 |
|
764 | 0 | AutoJSAPI jsapi; |
765 | 0 | if (!jsapi.Init(mGlobal)) { |
766 | 0 | localPromise->MaybeReject(NS_ERROR_UNEXPECTED); |
767 | 0 | return; |
768 | 0 | } |
769 | 0 | |
770 | 0 | JSContext* cx = jsapi.cx(); |
771 | 0 | ErrorResult error; |
772 | 0 |
|
773 | 0 | switch (mConsumeType) { |
774 | 0 | case CONSUME_ARRAYBUFFER: { |
775 | 0 | JS::Rooted<JSObject*> arrayBuffer(cx); |
776 | 0 | BodyUtil::ConsumeArrayBuffer(cx, &arrayBuffer, aResultLength, aResult, |
777 | 0 | error); |
778 | 0 |
|
779 | 0 | if (!error.Failed()) { |
780 | 0 | JS::Rooted<JS::Value> val(cx); |
781 | 0 | val.setObjectOrNull(arrayBuffer); |
782 | 0 |
|
783 | 0 | localPromise->MaybeResolve(cx, val); |
784 | 0 | // ArrayBuffer takes over ownership. |
785 | 0 | aResult = nullptr; |
786 | 0 | } |
787 | 0 | break; |
788 | 0 | } |
789 | 0 | case CONSUME_BLOB: { |
790 | 0 | MOZ_CRASH("This should not happen."); |
791 | 0 | break; |
792 | 0 | } |
793 | 0 | case CONSUME_FORMDATA: { |
794 | 0 | nsCString data; |
795 | 0 | data.Adopt(reinterpret_cast<char*>(aResult), aResultLength); |
796 | 0 | aResult = nullptr; |
797 | 0 |
|
798 | 0 | RefPtr<dom::FormData> fd = |
799 | 0 | BodyUtil::ConsumeFormData(mGlobal, mBodyMimeType, data, error); |
800 | 0 | if (!error.Failed()) { |
801 | 0 | localPromise->MaybeResolve(fd); |
802 | 0 | } |
803 | 0 | break; |
804 | 0 | } |
805 | 0 | case CONSUME_TEXT: |
806 | 0 | // fall through handles early exit. |
807 | 0 | case CONSUME_JSON: { |
808 | 0 | nsString decoded; |
809 | 0 | if (NS_SUCCEEDED(BodyUtil::ConsumeText(aResultLength, aResult, decoded))) { |
810 | 0 | if (mConsumeType == CONSUME_TEXT) { |
811 | 0 | localPromise->MaybeResolve(decoded); |
812 | 0 | } else { |
813 | 0 | JS::Rooted<JS::Value> json(cx); |
814 | 0 | BodyUtil::ConsumeJson(cx, &json, decoded, error); |
815 | 0 | if (!error.Failed()) { |
816 | 0 | localPromise->MaybeResolve(cx, json); |
817 | 0 | } |
818 | 0 | } |
819 | 0 | }; |
820 | 0 | break; |
821 | 0 | } |
822 | 0 | default: |
823 | 0 | MOZ_ASSERT_UNREACHABLE("Unexpected consume body type"); |
824 | 0 | } |
825 | 0 |
|
826 | 0 | error.WouldReportJSException(); |
827 | 0 | if (error.Failed()) { |
828 | 0 | localPromise->MaybeReject(error); |
829 | 0 | } |
830 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ContinueConsumeBody(nsresult, unsigned int, unsigned char*, bool) |
831 | | |
832 | | template <class Derived> |
833 | | void |
834 | | FetchBodyConsumer<Derived>::ContinueConsumeBlobBody(BlobImpl* aBlobImpl, |
835 | | bool aShuttingDown) |
836 | 0 | { |
837 | 0 | AssertIsOnTargetThread(); |
838 | 0 | MOZ_ASSERT(mConsumeType == CONSUME_BLOB); |
839 | 0 |
|
840 | 0 | if (mBodyConsumed) { |
841 | 0 | return; |
842 | 0 | } |
843 | 0 | mBodyConsumed = true; |
844 | 0 |
|
845 | 0 | // Just a precaution to ensure ContinueConsumeBody is not called out of |
846 | 0 | // sync with a body read. |
847 | 0 | MOZ_ASSERT(mBody->BodyUsed()); |
848 | 0 |
|
849 | 0 | MOZ_ASSERT(mConsumePromise); |
850 | 0 | RefPtr<Promise> localPromise = mConsumePromise.forget(); |
851 | 0 |
|
852 | 0 | if (!aShuttingDown) { |
853 | 0 | RefPtr<dom::Blob> blob = dom::Blob::Create(mGlobal, aBlobImpl); |
854 | 0 | MOZ_ASSERT(blob); |
855 | 0 |
|
856 | 0 | localPromise->MaybeResolve(blob); |
857 | 0 | } |
858 | 0 |
|
859 | 0 | ReleaseObject(); |
860 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ContinueConsumeBlobBody(mozilla::dom::BlobImpl*, bool) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ContinueConsumeBlobBody(mozilla::dom::BlobImpl*, bool) |
861 | | |
862 | | template <class Derived> |
863 | | void |
864 | | FetchBodyConsumer<Derived>::ShutDownMainThreadConsuming() |
865 | 0 | { |
866 | 0 | if (!NS_IsMainThread()) { |
867 | 0 | RefPtr<FetchBodyConsumer<Derived>> self = this; |
868 | 0 |
|
869 | 0 | nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction( |
870 | 0 | "FetchBodyConsumer::ShutDownMainThreadConsuming", |
871 | 0 | [self] () { self->ShutDownMainThreadConsuming(); }); Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ShutDownMainThreadConsuming()::{lambda()#1}::operator()() const Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ShutDownMainThreadConsuming()::{lambda()#1}::operator()() const |
872 | 0 |
|
873 | 0 | mMainThreadEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL); |
874 | 0 | return; |
875 | 0 | } |
876 | 0 |
|
877 | 0 | // We need this because maybe, mConsumeBodyPump has not been created yet. We |
878 | 0 | // must be sure that we don't try to do it. |
879 | 0 | mShuttingDown = true; |
880 | 0 |
|
881 | 0 | if (mConsumeBodyPump) { |
882 | 0 | mConsumeBodyPump->Cancel(NS_BINDING_ABORTED); |
883 | 0 | mConsumeBodyPump = nullptr; |
884 | 0 | } |
885 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::ShutDownMainThreadConsuming() Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::ShutDownMainThreadConsuming() |
886 | | |
887 | | template <class Derived> |
888 | | NS_IMETHODIMP |
889 | | FetchBodyConsumer<Derived>::Observe(nsISupports* aSubject, |
890 | | const char* aTopic, |
891 | | const char16_t* aData) |
892 | 0 | { |
893 | 0 | AssertIsOnMainThread(); |
894 | 0 |
|
895 | 0 | MOZ_ASSERT((strcmp(aTopic, DOM_WINDOW_FROZEN_TOPIC) == 0) || |
896 | 0 | (strcmp(aTopic, DOM_WINDOW_DESTROYED_TOPIC) == 0)); |
897 | 0 |
|
898 | 0 | nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mGlobal); |
899 | 0 | if (SameCOMIdentity(aSubject, window)) { |
900 | 0 | ContinueConsumeBody(NS_BINDING_ABORTED, 0, nullptr); |
901 | 0 | } |
902 | 0 |
|
903 | 0 | return NS_OK; |
904 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::Observe(nsISupports*, char const*, char16_t const*) Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::Observe(nsISupports*, char const*, char16_t const*) |
905 | | |
906 | | template <class Derived> |
907 | | void |
908 | | FetchBodyConsumer<Derived>::Abort() |
909 | 0 | { |
910 | 0 | AssertIsOnTargetThread(); |
911 | 0 | ShutDownMainThreadConsuming(); |
912 | 0 | ContinueConsumeBody(NS_ERROR_DOM_ABORT_ERR, 0, nullptr); |
913 | 0 | } Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Request>::Abort() Unexecuted instantiation: mozilla::dom::FetchBodyConsumer<mozilla::dom::Response>::Abort() |
914 | | |
915 | | template <class Derived> |
916 | | NS_IMPL_ADDREF(FetchBodyConsumer<Derived>) |
917 | | |
918 | | template <class Derived> |
919 | | NS_IMPL_RELEASE(FetchBodyConsumer<Derived>) |
920 | | |
921 | | template <class Derived> |
922 | | NS_IMPL_QUERY_INTERFACE(FetchBodyConsumer<Derived>, |
923 | | nsIObserver, |
924 | | nsISupportsWeakReference) |
925 | | |
926 | | } // namespace dom |
927 | | } // namespace mozilla |