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 : #include "Fetch.h"
8 : #include "FetchConsumer.h"
9 :
10 : #include "nsIDocument.h"
11 : #include "nsIGlobalObject.h"
12 : #include "nsIStreamLoader.h"
13 : #include "nsIThreadRetargetableRequest.h"
14 :
15 : #include "nsCharSeparatedTokenizer.h"
16 : #include "nsDOMString.h"
17 : #include "nsJSUtils.h"
18 : #include "nsNetUtil.h"
19 : #include "nsReadableUtils.h"
20 : #include "nsStreamUtils.h"
21 : #include "nsStringStream.h"
22 : #include "nsProxyRelease.h"
23 :
24 : #include "mozilla/ErrorResult.h"
25 : #include "mozilla/dom/BindingDeclarations.h"
26 : #include "mozilla/dom/BodyUtil.h"
27 : #include "mozilla/dom/Exceptions.h"
28 : #include "mozilla/dom/FetchDriver.h"
29 : #include "mozilla/dom/File.h"
30 : #include "mozilla/dom/FormData.h"
31 : #include "mozilla/dom/Headers.h"
32 : #include "mozilla/dom/MutableBlobStreamListener.h"
33 : #include "mozilla/dom/Promise.h"
34 : #include "mozilla/dom/PromiseWorkerProxy.h"
35 : #include "mozilla/dom/Request.h"
36 : #include "mozilla/dom/Response.h"
37 : #include "mozilla/dom/ScriptSettings.h"
38 : #include "mozilla/dom/URLSearchParams.h"
39 : #include "mozilla/dom/workers/ServiceWorkerManager.h"
40 : #include "mozilla/Telemetry.h"
41 :
42 : #include "BodyExtractor.h"
43 : #include "FetchObserver.h"
44 : #include "InternalRequest.h"
45 : #include "InternalResponse.h"
46 :
47 : #include "WorkerPrivate.h"
48 : #include "WorkerRunnable.h"
49 : #include "WorkerScope.h"
50 : #include "Workers.h"
51 :
52 : namespace mozilla {
53 : namespace dom {
54 :
55 : using namespace workers;
56 :
57 : // This class helps the proxying of FetchSignal changes cross threads.
58 : class FetchSignalProxy final : public FetchSignal::Follower
59 : {
60 : // This is created and released on the main-thread.
61 : RefPtr<FetchSignal> mSignalMainThread;
62 :
63 : // The main-thread event target for runnable dispatching.
64 : nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
65 :
66 : // This value is used only for the creation of FetchSignal on the
67 : // main-thread. They are not updated.
68 : const bool mAborted;
69 :
70 : // This runnable propagates changes from the FetchSignal on workers to the
71 : // FetchSignal on main-thread.
72 0 : class FetchSignalProxyRunnable final : public Runnable
73 : {
74 : RefPtr<FetchSignalProxy> mProxy;
75 :
76 : public:
77 0 : explicit FetchSignalProxyRunnable(FetchSignalProxy* aProxy)
78 0 : : Runnable("dom::FetchSignalProxy::FetchSignalProxyRunnable")
79 0 : , mProxy(aProxy)
80 0 : {}
81 :
82 : NS_IMETHOD
83 0 : Run() override
84 : {
85 0 : MOZ_ASSERT(NS_IsMainThread());
86 0 : FetchSignal* signal = mProxy->GetOrCreateSignalForMainThread();
87 0 : signal->Abort();
88 0 : return NS_OK;
89 : }
90 : };
91 :
92 : public:
93 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FetchSignalProxy)
94 :
95 0 : FetchSignalProxy(FetchSignal* aSignal, nsIEventTarget* aMainThreadEventTarget)
96 0 : : mMainThreadEventTarget(aMainThreadEventTarget)
97 0 : , mAborted(aSignal->Aborted())
98 : {
99 0 : MOZ_ASSERT(mMainThreadEventTarget);
100 0 : Follow(aSignal);
101 0 : }
102 :
103 : void
104 0 : Aborted() override
105 : {
106 : RefPtr<FetchSignalProxyRunnable> runnable =
107 0 : new FetchSignalProxyRunnable(this);
108 0 : mMainThreadEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
109 0 : }
110 :
111 : FetchSignal*
112 0 : GetOrCreateSignalForMainThread()
113 : {
114 0 : MOZ_ASSERT(NS_IsMainThread());
115 0 : if (!mSignalMainThread) {
116 0 : mSignalMainThread = new FetchSignal(mAborted);
117 : }
118 0 : return mSignalMainThread;
119 : }
120 :
121 : void
122 0 : Shutdown()
123 : {
124 0 : Unfollow();
125 0 : }
126 :
127 : private:
128 0 : ~FetchSignalProxy()
129 0 : {
130 0 : NS_ProxyRelease(
131 : "FetchSignalProxy::mSignalMainThread",
132 0 : mMainThreadEventTarget, mSignalMainThread.forget());
133 0 : }
134 : };
135 :
136 : class WorkerFetchResolver final : public FetchDriverObserver
137 : {
138 : friend class MainThreadFetchRunnable;
139 : friend class WorkerDataAvailableRunnable;
140 : friend class WorkerFetchResponseEndBase;
141 : friend class WorkerFetchResponseEndRunnable;
142 : friend class WorkerFetchResponseRunnable;
143 :
144 : RefPtr<PromiseWorkerProxy> mPromiseProxy;
145 : RefPtr<FetchSignalProxy> mSignalProxy;
146 : RefPtr<FetchObserver> mFetchObserver;
147 :
148 : public:
149 : // Returns null if worker is shutting down.
150 : static already_AddRefed<WorkerFetchResolver>
151 0 : Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise,
152 : FetchSignal* aSignal, FetchObserver* aObserver)
153 : {
154 0 : MOZ_ASSERT(aWorkerPrivate);
155 0 : aWorkerPrivate->AssertIsOnWorkerThread();
156 : RefPtr<PromiseWorkerProxy> proxy =
157 0 : PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
158 0 : if (!proxy) {
159 0 : return nullptr;
160 : }
161 :
162 0 : RefPtr<FetchSignalProxy> signalProxy;
163 0 : if (aSignal) {
164 : signalProxy =
165 0 : new FetchSignalProxy(aSignal, aWorkerPrivate->MainThreadEventTarget());
166 : }
167 :
168 : RefPtr<WorkerFetchResolver> r =
169 0 : new WorkerFetchResolver(proxy, signalProxy, aObserver);
170 0 : return r.forget();
171 : }
172 :
173 : FetchSignal*
174 0 : GetFetchSignal()
175 : {
176 0 : MOZ_ASSERT(NS_IsMainThread());
177 :
178 0 : if (!mSignalProxy) {
179 0 : return nullptr;
180 : }
181 :
182 0 : return mSignalProxy->GetOrCreateSignalForMainThread();
183 : }
184 :
185 : void
186 : OnResponseAvailableInternal(InternalResponse* aResponse) override;
187 :
188 : void
189 : OnResponseEnd(FetchDriverObserver::EndReason eReason) override;
190 :
191 : void
192 : OnDataAvailable() override;
193 :
194 : private:
195 0 : WorkerFetchResolver(PromiseWorkerProxy* aProxy,
196 : FetchSignalProxy* aSignalProxy,
197 : FetchObserver* aObserver)
198 0 : : mPromiseProxy(aProxy)
199 : , mSignalProxy(aSignalProxy)
200 0 : , mFetchObserver(aObserver)
201 : {
202 0 : MOZ_ASSERT(!NS_IsMainThread());
203 0 : MOZ_ASSERT(mPromiseProxy);
204 0 : }
205 :
206 0 : ~WorkerFetchResolver()
207 0 : {}
208 :
209 : virtual void
210 : FlushConsoleReport() override;
211 : };
212 :
213 : class MainThreadFetchResolver final : public FetchDriverObserver
214 : {
215 : RefPtr<Promise> mPromise;
216 : RefPtr<Response> mResponse;
217 : RefPtr<FetchObserver> mFetchObserver;
218 :
219 : nsCOMPtr<nsILoadGroup> mLoadGroup;
220 :
221 : NS_DECL_OWNINGTHREAD
222 : public:
223 1 : MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver)
224 1 : : mPromise(aPromise)
225 1 : , mFetchObserver(aObserver)
226 1 : {}
227 :
228 : void
229 : OnResponseAvailableInternal(InternalResponse* aResponse) override;
230 :
231 1 : void SetLoadGroup(nsILoadGroup* aLoadGroup)
232 : {
233 1 : mLoadGroup = aLoadGroup;
234 1 : }
235 :
236 : void
237 1 : OnResponseEnd(FetchDriverObserver::EndReason aReason) override
238 : {
239 1 : if (aReason == eAborted) {
240 0 : mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
241 : }
242 :
243 1 : mFetchObserver = nullptr;
244 :
245 1 : FlushConsoleReport();
246 1 : }
247 :
248 : void
249 : OnDataAvailable() override;
250 :
251 : private:
252 : ~MainThreadFetchResolver();
253 :
254 1 : void FlushConsoleReport() override
255 : {
256 1 : mReporter->FlushConsoleReports(mLoadGroup);
257 1 : }
258 : };
259 :
260 0 : class MainThreadFetchRunnable : public Runnable
261 : {
262 : RefPtr<WorkerFetchResolver> mResolver;
263 : RefPtr<InternalRequest> mRequest;
264 :
265 : public:
266 0 : MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
267 : InternalRequest* aRequest)
268 0 : : Runnable("dom::MainThreadFetchRunnable")
269 : , mResolver(aResolver)
270 0 : , mRequest(aRequest)
271 : {
272 0 : MOZ_ASSERT(mResolver);
273 0 : }
274 :
275 : NS_IMETHOD
276 0 : Run() override
277 : {
278 0 : AssertIsOnMainThread();
279 0 : RefPtr<FetchDriver> fetch;
280 0 : RefPtr<PromiseWorkerProxy> proxy = mResolver->mPromiseProxy;
281 :
282 : {
283 : // Acquire the proxy mutex while getting data from the WorkerPrivate...
284 0 : MutexAutoLock lock(proxy->Lock());
285 0 : if (proxy->CleanedUp()) {
286 0 : NS_WARNING("Aborting Fetch because worker already shut down");
287 0 : return NS_OK;
288 : }
289 :
290 0 : WorkerPrivate* workerPrivate = proxy->GetWorkerPrivate();
291 0 : MOZ_ASSERT(workerPrivate);
292 0 : nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
293 0 : MOZ_ASSERT(principal);
294 0 : nsCOMPtr<nsILoadGroup> loadGroup = workerPrivate->GetLoadGroup();
295 0 : MOZ_ASSERT(loadGroup);
296 : // We don't track if a worker is spawned from a tracking script for now,
297 : // so pass false as the last argument to FetchDriver().
298 : fetch = new FetchDriver(mRequest, principal, loadGroup,
299 0 : workerPrivate->MainThreadEventTarget(), false);
300 0 : nsAutoCString spec;
301 0 : if (proxy->GetWorkerPrivate()->GetBaseURI()) {
302 0 : proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
303 : }
304 0 : fetch->SetWorkerScript(spec);
305 : }
306 :
307 0 : RefPtr<FetchSignal> signal = mResolver->GetFetchSignal();
308 :
309 : // ...but release it before calling Fetch, because mResolver's callback can
310 : // be called synchronously and they want the mutex, too.
311 0 : return fetch->Fetch(signal, mResolver);
312 : }
313 : };
314 :
315 : already_AddRefed<Promise>
316 1 : FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
317 : const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv)
318 : {
319 2 : RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
320 1 : if (NS_WARN_IF(aRv.Failed())) {
321 0 : return nullptr;
322 : }
323 :
324 1 : MOZ_ASSERT(aGlobal);
325 :
326 : // Double check that we have chrome privileges if the Request's content
327 : // policy type has been overridden.
328 1 : MOZ_ASSERT_IF(aInput.IsRequest() &&
329 : aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
330 : aCallerType == CallerType::System);
331 :
332 2 : AutoJSAPI jsapi;
333 1 : if (!jsapi.Init(aGlobal)) {
334 0 : aRv.Throw(NS_ERROR_NOT_AVAILABLE);
335 0 : return nullptr;
336 : }
337 :
338 1 : JSContext* cx = jsapi.cx();
339 2 : JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
340 2 : GlobalObject global(cx, jsGlobal);
341 :
342 2 : RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
343 1 : if (NS_WARN_IF(aRv.Failed())) {
344 0 : return nullptr;
345 : }
346 :
347 2 : RefPtr<InternalRequest> r = request->GetInternalRequest();
348 :
349 2 : RefPtr<FetchSignal> signal;
350 1 : if (aInit.mSignal.WasPassed()) {
351 0 : signal = &aInit.mSignal.Value();
352 : // Let's FetchDriver to deal with an already aborted signal.
353 : }
354 :
355 2 : RefPtr<FetchObserver> observer;
356 1 : if (aInit.mObserve.WasPassed()) {
357 0 : observer = new FetchObserver(aGlobal, signal);
358 0 : aInit.mObserve.Value().HandleEvent(*observer);
359 : }
360 :
361 1 : if (NS_IsMainThread()) {
362 2 : nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
363 2 : nsCOMPtr<nsIDocument> doc;
364 2 : nsCOMPtr<nsILoadGroup> loadGroup;
365 : nsIPrincipal* principal;
366 1 : bool isTrackingFetch = false;
367 1 : if (window) {
368 0 : doc = window->GetExtantDoc();
369 0 : if (!doc) {
370 0 : aRv.Throw(NS_ERROR_FAILURE);
371 0 : return nullptr;
372 : }
373 0 : principal = doc->NodePrincipal();
374 0 : loadGroup = doc->GetDocumentLoadGroup();
375 :
376 0 : nsAutoCString fileNameString;
377 0 : if (nsJSUtils::GetCallingLocation(cx, fileNameString)) {
378 0 : isTrackingFetch = doc->IsScriptTracking(fileNameString);
379 : }
380 : } else {
381 1 : principal = aGlobal->PrincipalOrNull();
382 1 : if (NS_WARN_IF(!principal)) {
383 0 : aRv.Throw(NS_ERROR_FAILURE);
384 0 : return nullptr;
385 : }
386 1 : nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
387 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
388 0 : aRv.Throw(rv);
389 0 : return nullptr;
390 : }
391 : }
392 :
393 1 : Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
394 :
395 : RefPtr<MainThreadFetchResolver> resolver =
396 3 : new MainThreadFetchResolver(p, observer);
397 : RefPtr<FetchDriver> fetch =
398 : new FetchDriver(r, principal, loadGroup,
399 3 : aGlobal->EventTargetFor(TaskCategory::Other), isTrackingFetch);
400 1 : fetch->SetDocument(doc);
401 1 : resolver->SetLoadGroup(loadGroup);
402 1 : aRv = fetch->Fetch(signal, resolver);
403 1 : if (NS_WARN_IF(aRv.Failed())) {
404 0 : return nullptr;
405 : }
406 : } else {
407 0 : WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
408 0 : MOZ_ASSERT(worker);
409 :
410 0 : Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
411 :
412 0 : if (worker->IsServiceWorker()) {
413 0 : r->SetSkipServiceWorker();
414 : }
415 :
416 : RefPtr<WorkerFetchResolver> resolver =
417 0 : WorkerFetchResolver::Create(worker, p, signal, observer);
418 0 : if (!resolver) {
419 0 : NS_WARNING("Could not add WorkerFetchResolver workerHolder to worker");
420 0 : aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
421 0 : return nullptr;
422 : }
423 :
424 : RefPtr<MainThreadFetchRunnable> run =
425 0 : new MainThreadFetchRunnable(resolver, r);
426 0 : worker->DispatchToMainThread(run.forget());
427 : }
428 :
429 1 : return p.forget();
430 : }
431 :
432 : void
433 1 : MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
434 : {
435 1 : NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
436 1 : AssertIsOnMainThread();
437 :
438 1 : if (aResponse->Type() != ResponseType::Error) {
439 1 : if (mFetchObserver) {
440 0 : mFetchObserver->SetState(FetchState::Complete);
441 : }
442 :
443 2 : nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
444 2 : mResponse = new Response(go, aResponse);
445 1 : mPromise->MaybeResolve(mResponse);
446 : } else {
447 0 : if (mFetchObserver) {
448 0 : mFetchObserver->SetState(FetchState::Errored);
449 : }
450 :
451 0 : ErrorResult result;
452 0 : result.ThrowTypeError<MSG_FETCH_FAILED>();
453 0 : mPromise->MaybeReject(result);
454 : }
455 1 : }
456 :
457 : void
458 1 : MainThreadFetchResolver::OnDataAvailable()
459 : {
460 1 : NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
461 1 : AssertIsOnMainThread();
462 :
463 1 : if (!mFetchObserver) {
464 1 : return;
465 : }
466 :
467 0 : if (mFetchObserver->State() == FetchState::Requesting) {
468 0 : mFetchObserver->SetState(FetchState::Responding);
469 : }
470 : }
471 :
472 3 : MainThreadFetchResolver::~MainThreadFetchResolver()
473 : {
474 1 : NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
475 3 : }
476 :
477 0 : class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable
478 : {
479 : RefPtr<WorkerFetchResolver> mResolver;
480 : // Passed from main thread to worker thread after being initialized.
481 : RefPtr<InternalResponse> mInternalResponse;
482 : public:
483 0 : WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
484 : WorkerFetchResolver* aResolver,
485 : InternalResponse* aResponse)
486 0 : : MainThreadWorkerRunnable(aWorkerPrivate)
487 : , mResolver(aResolver)
488 0 : , mInternalResponse(aResponse)
489 : {
490 0 : MOZ_ASSERT(mResolver);
491 0 : }
492 :
493 : bool
494 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
495 : {
496 0 : MOZ_ASSERT(aWorkerPrivate);
497 0 : aWorkerPrivate->AssertIsOnWorkerThread();
498 :
499 0 : RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
500 :
501 0 : if (mInternalResponse->Type() != ResponseType::Error) {
502 0 : if (mResolver->mFetchObserver) {
503 0 : mResolver->mFetchObserver->SetState(FetchState::Complete);
504 : }
505 :
506 0 : RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
507 0 : RefPtr<Response> response = new Response(global, mInternalResponse);
508 0 : promise->MaybeResolve(response);
509 : } else {
510 0 : if (mResolver->mFetchObserver) {
511 0 : mResolver->mFetchObserver->SetState(FetchState::Errored);
512 : }
513 :
514 0 : ErrorResult result;
515 0 : result.ThrowTypeError<MSG_FETCH_FAILED>();
516 0 : promise->MaybeReject(result);
517 : }
518 0 : return true;
519 : }
520 : };
521 :
522 0 : class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable
523 : {
524 : RefPtr<WorkerFetchResolver> mResolver;
525 : public:
526 0 : WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
527 : WorkerFetchResolver* aResolver)
528 0 : : MainThreadWorkerRunnable(aWorkerPrivate)
529 0 : , mResolver(aResolver)
530 : {
531 0 : }
532 :
533 : bool
534 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
535 : {
536 0 : MOZ_ASSERT(aWorkerPrivate);
537 0 : aWorkerPrivate->AssertIsOnWorkerThread();
538 :
539 0 : if (mResolver->mFetchObserver &&
540 0 : mResolver->mFetchObserver->State() == FetchState::Requesting) {
541 0 : mResolver->mFetchObserver->SetState(FetchState::Responding);
542 : }
543 :
544 0 : return true;
545 : }
546 : };
547 :
548 0 : class WorkerFetchResponseEndBase
549 : {
550 : protected:
551 : RefPtr<WorkerFetchResolver> mResolver;
552 :
553 : public:
554 0 : explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
555 0 : : mResolver(aResolver)
556 : {
557 0 : MOZ_ASSERT(aResolver);
558 0 : }
559 :
560 : void
561 0 : WorkerRunInternal(WorkerPrivate* aWorkerPrivate)
562 : {
563 0 : MOZ_ASSERT(aWorkerPrivate);
564 0 : aWorkerPrivate->AssertIsOnWorkerThread();
565 :
566 0 : mResolver->mPromiseProxy->CleanUp();
567 :
568 0 : mResolver->mFetchObserver = nullptr;
569 :
570 0 : if (mResolver->mSignalProxy) {
571 0 : mResolver->mSignalProxy->Shutdown();
572 0 : mResolver->mSignalProxy = nullptr;
573 : }
574 0 : }
575 : };
576 :
577 0 : class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable
578 : , public WorkerFetchResponseEndBase
579 : {
580 : FetchDriverObserver::EndReason mReason;
581 :
582 : public:
583 0 : WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
584 : WorkerFetchResolver* aResolver,
585 : FetchDriverObserver::EndReason aReason)
586 0 : : MainThreadWorkerRunnable(aWorkerPrivate)
587 : , WorkerFetchResponseEndBase(aResolver)
588 0 : , mReason(aReason)
589 : {
590 0 : }
591 :
592 : bool
593 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
594 : {
595 0 : if (mReason == FetchDriverObserver::eAborted) {
596 0 : RefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
597 0 : promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
598 : }
599 :
600 0 : WorkerRunInternal(aWorkerPrivate);
601 0 : return true;
602 : }
603 :
604 : nsresult
605 0 : Cancel() override
606 : {
607 : // Execute Run anyway to make sure we cleanup our promise proxy to avoid
608 : // leaking the worker thread
609 0 : Run();
610 0 : return WorkerRunnable::Cancel();
611 : }
612 : };
613 :
614 0 : class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerControlRunnable
615 : , public WorkerFetchResponseEndBase
616 : {
617 : public:
618 0 : WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
619 : WorkerFetchResolver* aResolver)
620 0 : : MainThreadWorkerControlRunnable(aWorkerPrivate)
621 0 : , WorkerFetchResponseEndBase(aResolver)
622 : {
623 0 : }
624 :
625 : bool
626 0 : WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
627 : {
628 0 : WorkerRunInternal(aWorkerPrivate);
629 0 : return true;
630 : }
631 :
632 : // Control runnable cancel already calls Run().
633 : };
634 :
635 : void
636 0 : WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
637 : {
638 0 : AssertIsOnMainThread();
639 :
640 0 : MutexAutoLock lock(mPromiseProxy->Lock());
641 0 : if (mPromiseProxy->CleanedUp()) {
642 0 : return;
643 : }
644 :
645 : RefPtr<WorkerFetchResponseRunnable> r =
646 0 : new WorkerFetchResponseRunnable(mPromiseProxy->GetWorkerPrivate(), this,
647 0 : aResponse);
648 :
649 0 : if (!r->Dispatch()) {
650 0 : NS_WARNING("Could not dispatch fetch response");
651 : }
652 : }
653 :
654 : void
655 0 : WorkerFetchResolver::OnDataAvailable()
656 : {
657 0 : AssertIsOnMainThread();
658 :
659 0 : MutexAutoLock lock(mPromiseProxy->Lock());
660 0 : if (mPromiseProxy->CleanedUp()) {
661 0 : return;
662 : }
663 :
664 : RefPtr<WorkerDataAvailableRunnable> r =
665 0 : new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
666 0 : Unused << r->Dispatch();
667 : }
668 :
669 : void
670 0 : WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason)
671 : {
672 0 : AssertIsOnMainThread();
673 0 : MutexAutoLock lock(mPromiseProxy->Lock());
674 0 : if (mPromiseProxy->CleanedUp()) {
675 0 : return;
676 : }
677 :
678 0 : FlushConsoleReport();
679 :
680 : RefPtr<WorkerFetchResponseEndRunnable> r =
681 0 : new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(),
682 0 : this, aReason);
683 :
684 0 : if (!r->Dispatch()) {
685 : RefPtr<WorkerFetchResponseEndControlRunnable> cr =
686 0 : new WorkerFetchResponseEndControlRunnable(mPromiseProxy->GetWorkerPrivate(),
687 0 : this);
688 : // This can fail if the worker thread is canceled or killed causing
689 : // the PromiseWorkerProxy to give up its WorkerHolder immediately,
690 : // allowing the worker thread to become Dead.
691 0 : if (!cr->Dispatch()) {
692 0 : NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
693 : }
694 : }
695 : }
696 :
697 : void
698 0 : WorkerFetchResolver::FlushConsoleReport()
699 : {
700 0 : AssertIsOnMainThread();
701 0 : MOZ_ASSERT(mPromiseProxy);
702 :
703 0 : if(!mReporter) {
704 0 : return;
705 : }
706 :
707 0 : workers::WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
708 0 : if (!worker) {
709 0 : mReporter->FlushReportsToConsole(0);
710 0 : return;
711 : }
712 :
713 0 : if (worker->IsServiceWorker()) {
714 : // Flush to service worker
715 0 : RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
716 0 : if (!swm) {
717 0 : mReporter->FlushReportsToConsole(0);
718 0 : return;
719 : }
720 :
721 0 : swm->FlushReportsToAllClients(worker->ServiceWorkerScope(), mReporter);
722 0 : return;
723 : }
724 :
725 0 : if (worker->IsSharedWorker()) {
726 : // Flush to shared worker
727 0 : worker->FlushReportsToSharedWorkers(mReporter);
728 0 : return;
729 : }
730 :
731 : // Flush to dedicated worker
732 0 : mReporter->FlushConsoleReports(worker->GetLoadGroup());
733 : }
734 :
735 : nsresult
736 0 : ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
737 : nsIInputStream** aStream,
738 : nsCString& aContentTypeWithCharset,
739 : uint64_t& aContentLength)
740 : {
741 0 : MOZ_ASSERT(aStream);
742 0 : nsAutoCString charset;
743 0 : aContentTypeWithCharset.SetIsVoid(true);
744 :
745 0 : if (aBodyInit.IsArrayBuffer()) {
746 0 : BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
747 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
748 0 : charset);
749 : }
750 :
751 0 : if (aBodyInit.IsArrayBufferView()) {
752 0 : BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
753 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
754 0 : charset);
755 : }
756 :
757 0 : if (aBodyInit.IsBlob()) {
758 0 : Blob& blob = aBodyInit.GetAsBlob();
759 0 : BodyExtractor<nsIXHRSendable> body(&blob);
760 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
761 0 : charset);
762 : }
763 :
764 0 : if (aBodyInit.IsFormData()) {
765 0 : FormData& formData = aBodyInit.GetAsFormData();
766 0 : BodyExtractor<nsIXHRSendable> body(&formData);
767 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
768 0 : charset);
769 : }
770 :
771 0 : if (aBodyInit.IsUSVString()) {
772 0 : BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
773 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
774 0 : charset);
775 : }
776 :
777 0 : if (aBodyInit.IsURLSearchParams()) {
778 0 : URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
779 0 : BodyExtractor<nsIXHRSendable> body(&usp);
780 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
781 0 : charset);
782 : }
783 :
784 0 : NS_NOTREACHED("Should never reach here");
785 0 : return NS_ERROR_FAILURE;
786 : }
787 :
788 : nsresult
789 0 : ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
790 : nsIInputStream** aStream,
791 : nsCString& aContentTypeWithCharset,
792 : uint64_t& aContentLength)
793 : {
794 0 : MOZ_ASSERT(aStream);
795 0 : MOZ_ASSERT(!*aStream);
796 :
797 0 : nsAutoCString charset;
798 0 : aContentTypeWithCharset.SetIsVoid(true);
799 :
800 0 : if (aBodyInit.IsArrayBuffer()) {
801 0 : BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
802 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
803 0 : charset);
804 : }
805 :
806 0 : if (aBodyInit.IsArrayBufferView()) {
807 0 : BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
808 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
809 0 : charset);
810 : }
811 :
812 0 : if (aBodyInit.IsBlob()) {
813 0 : BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsBlob());
814 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
815 0 : charset);
816 : }
817 :
818 0 : if (aBodyInit.IsFormData()) {
819 0 : BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsFormData());
820 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
821 0 : charset);
822 : }
823 :
824 0 : if (aBodyInit.IsUSVString()) {
825 0 : BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
826 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
827 0 : charset);
828 : }
829 :
830 0 : if (aBodyInit.IsURLSearchParams()) {
831 0 : BodyExtractor<nsIXHRSendable> body(&aBodyInit.GetAsURLSearchParams());
832 0 : return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
833 0 : charset);
834 : }
835 :
836 0 : NS_NOTREACHED("Should never reach here");
837 0 : return NS_ERROR_FAILURE;
838 : }
839 :
840 : template <class Derived>
841 2 : FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
842 : : mOwner(aOwner)
843 : , mWorkerPrivate(nullptr)
844 2 : , mBodyUsed(false)
845 : {
846 2 : MOZ_ASSERT(aOwner);
847 :
848 2 : if (!NS_IsMainThread()) {
849 0 : mWorkerPrivate = GetCurrentThreadWorkerPrivate();
850 0 : MOZ_ASSERT(mWorkerPrivate);
851 0 : mMainThreadEventTarget = mWorkerPrivate->MainThreadEventTarget();
852 : } else {
853 2 : mMainThreadEventTarget = aOwner->EventTargetFor(TaskCategory::Other);
854 : }
855 :
856 2 : MOZ_ASSERT(mMainThreadEventTarget);
857 2 : }
858 :
859 : template
860 : FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
861 :
862 : template
863 : FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
864 :
865 : template <class Derived>
866 1 : FetchBody<Derived>::~FetchBody()
867 : {
868 1 : }
869 :
870 : template <class Derived>
871 : already_AddRefed<Promise>
872 1 : FetchBody<Derived>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv)
873 : {
874 1 : if (BodyUsed()) {
875 0 : aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
876 0 : return nullptr;
877 : }
878 :
879 1 : SetBodyUsed();
880 :
881 : RefPtr<Promise> promise =
882 : FetchBodyConsumer<Derived>::Create(DerivedClass()->GetParentObject(),
883 : mMainThreadEventTarget, this, aType,
884 2 : aRv);
885 1 : if (NS_WARN_IF(aRv.Failed())) {
886 0 : return nullptr;
887 : }
888 :
889 1 : return promise.forget();
890 : }
891 :
892 : template
893 : already_AddRefed<Promise>
894 : FetchBody<Request>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
895 :
896 : template
897 : already_AddRefed<Promise>
898 : FetchBody<Response>::ConsumeBody(FetchConsumeType aType, ErrorResult& aRv);
899 :
900 : template <class Derived>
901 : void
902 3 : FetchBody<Derived>::SetMimeType()
903 : {
904 : // Extract mime type.
905 6 : ErrorResult result;
906 6 : nsCString contentTypeValues;
907 3 : MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
908 3 : DerivedClass()->GetInternalHeaders()->Get(NS_LITERAL_CSTRING("Content-Type"),
909 : contentTypeValues, result);
910 3 : MOZ_ALWAYS_TRUE(!result.Failed());
911 :
912 : // HTTP ABNF states Content-Type may have only one value.
913 : // This is from the "parse a header value" of the fetch spec.
914 3 : if (!contentTypeValues.IsVoid() && contentTypeValues.Find(",") == -1) {
915 1 : mMimeType = contentTypeValues;
916 1 : ToLowerCase(mMimeType);
917 : }
918 3 : }
919 :
920 : template
921 : void
922 : FetchBody<Request>::SetMimeType();
923 :
924 : template
925 : void
926 : FetchBody<Response>::SetMimeType();
927 :
928 : } // namespace dom
929 : } // namespace mozilla
|