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 #include "ServiceWorkerEvents.h"
11 #include "ServiceWorker.h"
12 #include "ServiceWorkerManager.h"
13 #include "js/Conversions.h"
14 #include "js/Exception.h" // JS::ExceptionStack, JS::StealPendingExceptionStack
15 #include "js/TypeDecls.h"
16 #include "mozilla/Encoding.h"
17 #include "mozilla/ErrorResult.h"
18 #include "mozilla/HoldDropJSObjects.h"
19 #include "mozilla/LoadInfo.h"
20 #include "mozilla/Preferences.h"
21 #include "mozilla/dom/BodyUtil.h"
22 #include "mozilla/dom/Client.h"
23 #include "mozilla/dom/EventBinding.h"
24 #include "mozilla/dom/FetchEventBinding.h"
25 #include "mozilla/dom/MessagePort.h"
26 #include "mozilla/dom/PromiseNativeHandler.h"
27 #include "mozilla/dom/PushEventBinding.h"
28 #include "mozilla/dom/PushMessageDataBinding.h"
29 #include "mozilla/dom/PushUtil.h"
30 #include "mozilla/dom/Request.h"
31 #include "mozilla/dom/Response.h"
32 #include "mozilla/dom/ServiceWorkerOp.h"
33 #include "mozilla/dom/TypedArray.h"
34 #include "mozilla/dom/WorkerPrivate.h"
35 #include "mozilla/dom/WorkerScope.h"
36 #include "mozilla/net/NeckoChannelParams.h"
37 #include "mozilla/Telemetry.h"
38 #include "nsComponentManagerUtils.h"
39 #include "nsContentPolicyUtils.h"
40 #include "nsContentUtils.h"
41 #include "nsIConsoleReportCollector.h"
42 #include "nsINetworkInterceptController.h"
43 #include "nsIScriptError.h"
45 #include "nsNetUtil.h"
46 #include "nsQueryObject.h"
47 #include "nsSerializationHelper.h"
48 #include "nsServiceManagerUtils.h"
49 #include "nsStreamUtils.h"
50 #include "xpcpublic.h"
52 using namespace mozilla
;
53 using namespace mozilla::dom
;
57 void AsyncLog(nsIInterceptedChannel
* aInterceptedChannel
,
58 const nsACString
& aRespondWithScriptSpec
,
59 uint32_t aRespondWithLineNumber
,
60 uint32_t aRespondWithColumnNumber
, const nsACString
& aMessageName
,
61 const nsTArray
<nsString
>& aParams
) {
62 MOZ_ASSERT(aInterceptedChannel
);
63 nsCOMPtr
<nsIConsoleReportCollector
> reporter
=
64 aInterceptedChannel
->GetConsoleReportCollector();
66 reporter
->AddConsoleReport(nsIScriptError::errorFlag
,
67 "Service Worker Interception"_ns
,
68 nsContentUtils::eDOM_PROPERTIES
,
69 aRespondWithScriptSpec
, aRespondWithLineNumber
,
70 aRespondWithColumnNumber
, aMessageName
, aParams
);
74 template <typename
... Params
>
75 void AsyncLog(nsIInterceptedChannel
* aInterceptedChannel
,
76 const nsACString
& aRespondWithScriptSpec
,
77 uint32_t aRespondWithLineNumber
,
78 uint32_t aRespondWithColumnNumber
,
79 // We have to list one explicit string so that calls with an
80 // nsTArray of params won't end up in here.
81 const nsACString
& aMessageName
, const nsAString
& aFirstParam
,
82 Params
&&... aParams
) {
83 nsTArray
<nsString
> paramsList(sizeof...(Params
) + 1);
84 StringArrayAppender::Append(paramsList
, sizeof...(Params
) + 1, aFirstParam
,
85 std::forward
<Params
>(aParams
)...);
86 AsyncLog(aInterceptedChannel
, aRespondWithScriptSpec
, aRespondWithLineNumber
,
87 aRespondWithColumnNumber
, aMessageName
, paramsList
);
90 } // anonymous namespace
92 namespace mozilla::dom
{
94 CancelChannelRunnable::CancelChannelRunnable(
95 nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
,
96 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
>& aRegistration
,
98 : Runnable("dom::CancelChannelRunnable"),
100 mRegistration(aRegistration
),
104 CancelChannelRunnable::Run() {
105 MOZ_ASSERT(NS_IsMainThread());
107 mChannel
->CancelInterception(mStatus
);
108 mRegistration
->MaybeScheduleUpdate();
112 FetchEvent::FetchEvent(EventTarget
* aOwner
)
113 : ExtendableEvent(aOwner
),
114 mPreventDefaultLineNumber(0),
115 mPreventDefaultColumnNumber(0),
116 mWaitToRespond(false) {}
118 FetchEvent::~FetchEvent() = default;
120 void FetchEvent::PostInit(
121 nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
,
122 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
>& aRegistration
,
123 const nsACString
& aScriptSpec
) {
125 mRegistration
= aRegistration
;
126 mScriptSpec
.Assign(aScriptSpec
);
129 void FetchEvent::PostInit(const nsACString
& aScriptSpec
,
130 RefPtr
<FetchEventOp
> aRespondWithHandler
) {
131 MOZ_ASSERT(aRespondWithHandler
);
133 mScriptSpec
.Assign(aScriptSpec
);
134 mRespondWithHandler
= std::move(aRespondWithHandler
);
138 already_AddRefed
<FetchEvent
> FetchEvent::Constructor(
139 const GlobalObject
& aGlobal
, const nsAString
& aType
,
140 const FetchEventInit
& aOptions
) {
141 RefPtr
<EventTarget
> owner
= do_QueryObject(aGlobal
.GetAsSupports());
143 RefPtr
<FetchEvent
> e
= new FetchEvent(owner
);
144 bool trusted
= e
->Init(owner
);
145 e
->InitEvent(aType
, aOptions
.mBubbles
, aOptions
.mCancelable
);
146 e
->SetTrusted(trusted
);
147 e
->SetComposed(aOptions
.mComposed
);
148 e
->mRequest
= aOptions
.mRequest
;
149 e
->mClientId
= aOptions
.mClientId
;
150 e
->mResultingClientId
= aOptions
.mResultingClientId
;
151 RefPtr
<nsIGlobalObject
> global
= do_QueryObject(aGlobal
.GetAsSupports());
154 e
->mHandled
= Promise::Create(global
, rv
);
156 rv
.SuppressException();
159 e
->mPreloadResponse
= Promise::Create(global
, rv
);
161 rv
.SuppressException();
169 struct RespondWithClosure
{
170 nsMainThreadPtrHandle
<nsIInterceptedChannel
> mInterceptedChannel
;
171 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
> mRegistration
;
172 const nsString mRequestURL
;
173 const nsCString mRespondWithScriptSpec
;
174 const uint32_t mRespondWithLineNumber
;
175 const uint32_t mRespondWithColumnNumber
;
178 nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
,
179 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
>& aRegistration
,
180 const nsAString
& aRequestURL
, const nsACString
& aRespondWithScriptSpec
,
181 uint32_t aRespondWithLineNumber
, uint32_t aRespondWithColumnNumber
)
182 : mInterceptedChannel(aChannel
),
183 mRegistration(aRegistration
),
184 mRequestURL(aRequestURL
),
185 mRespondWithScriptSpec(aRespondWithScriptSpec
),
186 mRespondWithLineNumber(aRespondWithLineNumber
),
187 mRespondWithColumnNumber(aRespondWithColumnNumber
) {}
190 class FinishResponse final
: public Runnable
{
191 nsMainThreadPtrHandle
<nsIInterceptedChannel
> mChannel
;
194 explicit FinishResponse(
195 nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
)
196 : Runnable("dom::FinishResponse"), mChannel(aChannel
) {}
200 MOZ_ASSERT(NS_IsMainThread());
202 nsresult rv
= mChannel
->FinishSynthesizedResponse();
203 if (NS_WARN_IF(NS_FAILED(rv
))) {
204 mChannel
->CancelInterception(NS_ERROR_INTERCEPTION_FAILED
);
212 class BodyCopyHandle final
: public nsIInterceptedBodyCallback
{
213 UniquePtr
<RespondWithClosure
> mClosure
;
215 ~BodyCopyHandle() = default;
218 NS_DECL_THREADSAFE_ISUPPORTS
220 explicit BodyCopyHandle(UniquePtr
<RespondWithClosure
>&& aClosure
)
221 : mClosure(std::move(aClosure
)) {}
224 BodyComplete(nsresult aRv
) override
{
225 MOZ_ASSERT(NS_IsMainThread());
227 nsCOMPtr
<nsIRunnable
> event
;
228 if (NS_WARN_IF(NS_FAILED(aRv
))) {
230 mClosure
->mInterceptedChannel
, mClosure
->mRespondWithScriptSpec
,
231 mClosure
->mRespondWithLineNumber
, mClosure
->mRespondWithColumnNumber
,
232 "InterceptionFailedWithURL"_ns
, mClosure
->mRequestURL
);
233 event
= new CancelChannelRunnable(mClosure
->mInterceptedChannel
,
234 mClosure
->mRegistration
,
235 NS_ERROR_INTERCEPTION_FAILED
);
237 event
= new FinishResponse(mClosure
->mInterceptedChannel
);
248 NS_IMPL_ISUPPORTS(BodyCopyHandle
, nsIInterceptedBodyCallback
)
250 class StartResponse final
: public Runnable
{
251 nsMainThreadPtrHandle
<nsIInterceptedChannel
> mChannel
;
252 SafeRefPtr
<InternalResponse
> mInternalResponse
;
253 ChannelInfo mWorkerChannelInfo
;
254 const nsCString mScriptSpec
;
255 const nsCString mResponseURLSpec
;
256 UniquePtr
<RespondWithClosure
> mClosure
;
259 StartResponse(nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
,
260 SafeRefPtr
<InternalResponse
> aInternalResponse
,
261 const ChannelInfo
& aWorkerChannelInfo
,
262 const nsACString
& aScriptSpec
,
263 const nsACString
& aResponseURLSpec
,
264 UniquePtr
<RespondWithClosure
>&& aClosure
)
265 : Runnable("dom::StartResponse"),
267 mInternalResponse(std::move(aInternalResponse
)),
268 mWorkerChannelInfo(aWorkerChannelInfo
),
269 mScriptSpec(aScriptSpec
),
270 mResponseURLSpec(aResponseURLSpec
),
271 mClosure(std::move(aClosure
)) {}
275 MOZ_ASSERT(NS_IsMainThread());
277 nsCOMPtr
<nsIChannel
> underlyingChannel
;
278 nsresult rv
= mChannel
->GetChannel(getter_AddRefs(underlyingChannel
));
279 NS_ENSURE_SUCCESS(rv
, rv
);
280 NS_ENSURE_TRUE(underlyingChannel
, NS_ERROR_UNEXPECTED
);
281 nsCOMPtr
<nsILoadInfo
> loadInfo
= underlyingChannel
->LoadInfo();
283 if (!CSPPermitsResponse(loadInfo
)) {
284 mChannel
->CancelInterception(NS_ERROR_CONTENT_BLOCKED
);
288 ChannelInfo channelInfo
;
289 if (mInternalResponse
->GetChannelInfo().IsInitialized()) {
290 channelInfo
= mInternalResponse
->GetChannelInfo();
292 // We are dealing with a synthesized response here, so fall back to the
293 // channel info for the worker script.
294 channelInfo
= mWorkerChannelInfo
;
296 rv
= mChannel
->SetChannelInfo(&channelInfo
);
297 if (NS_WARN_IF(NS_FAILED(rv
))) {
298 mChannel
->CancelInterception(NS_ERROR_INTERCEPTION_FAILED
);
302 rv
= mChannel
->SynthesizeStatus(
303 mInternalResponse
->GetUnfilteredStatus(),
304 mInternalResponse
->GetUnfilteredStatusText());
305 if (NS_WARN_IF(NS_FAILED(rv
))) {
306 mChannel
->CancelInterception(NS_ERROR_INTERCEPTION_FAILED
);
310 AutoTArray
<InternalHeaders::Entry
, 5> entries
;
311 mInternalResponse
->UnfilteredHeaders()->GetEntries(entries
);
312 for (uint32_t i
= 0; i
< entries
.Length(); ++i
) {
313 mChannel
->SynthesizeHeader(entries
[i
].mName
, entries
[i
].mValue
);
316 auto castLoadInfo
= static_cast<mozilla::net::LoadInfo
*>(loadInfo
.get());
317 castLoadInfo
->SynthesizeServiceWorkerTainting(
318 mInternalResponse
->GetTainting());
320 // Get the preferred alternative data type of outter channel
321 nsAutoCString
preferredAltDataType(""_ns
);
322 nsCOMPtr
<nsICacheInfoChannel
> outerChannel
=
323 do_QueryInterface(underlyingChannel
);
325 !outerChannel
->PreferredAlternativeDataTypes().IsEmpty()) {
326 // TODO: handle multiple types properly.
327 preferredAltDataType
.Assign(
328 outerChannel
->PreferredAlternativeDataTypes()[0].type());
331 // Get the alternative data type saved in the InternalResponse
332 nsAutoCString altDataType
;
333 nsCOMPtr
<nsICacheInfoChannel
> cacheInfoChannel
=
334 mInternalResponse
->TakeCacheInfoChannel().get();
335 if (cacheInfoChannel
) {
336 cacheInfoChannel
->GetAlternativeDataType(altDataType
);
339 nsCOMPtr
<nsIInputStream
> body
;
340 if (preferredAltDataType
.Equals(altDataType
)) {
341 body
= mInternalResponse
->TakeAlternativeBody();
344 mInternalResponse
->GetUnfilteredBody(getter_AddRefs(body
));
346 Telemetry::ScalarAdd(Telemetry::ScalarID::SW_ALTERNATIVE_BODY_USED_COUNT
,
350 RefPtr
<BodyCopyHandle
> copyHandle
;
351 copyHandle
= new BodyCopyHandle(std::move(mClosure
));
353 rv
= mChannel
->StartSynthesizedResponse(body
, copyHandle
, cacheInfoChannel
,
355 mInternalResponse
->IsRedirected());
356 if (NS_WARN_IF(NS_FAILED(rv
))) {
357 mChannel
->CancelInterception(NS_ERROR_INTERCEPTION_FAILED
);
361 nsCOMPtr
<nsIObserverService
> obsService
= services::GetObserverService();
363 obsService
->NotifyObservers(
364 underlyingChannel
, "service-worker-synthesized-response", nullptr);
370 bool CSPPermitsResponse(nsILoadInfo
* aLoadInfo
) {
371 MOZ_ASSERT(NS_IsMainThread());
372 MOZ_ASSERT(aLoadInfo
);
374 nsCOMPtr
<nsIURI
> uri
;
375 nsCString url
= mInternalResponse
->GetUnfilteredURL();
377 // Synthetic response. The buck stops at the worker script.
380 rv
= NS_NewURI(getter_AddRefs(uri
), url
);
381 NS_ENSURE_SUCCESS(rv
, false);
382 int16_t decision
= nsIContentPolicy::ACCEPT
;
383 rv
= NS_CheckContentLoadPolicy(uri
, aLoadInfo
, ""_ns
, &decision
);
384 NS_ENSURE_SUCCESS(rv
, false);
385 return decision
== nsIContentPolicy::ACCEPT
;
389 class RespondWithHandler final
: public PromiseNativeHandler
{
390 nsMainThreadPtrHandle
<nsIInterceptedChannel
> mInterceptedChannel
;
391 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
> mRegistration
;
392 const RequestMode mRequestMode
;
393 const RequestRedirect mRequestRedirectMode
;
395 const bool mIsClientRequest
;
397 const nsCString mScriptSpec
;
398 const nsString mRequestURL
;
399 const nsCString mRequestFragment
;
400 const nsCString mRespondWithScriptSpec
;
401 const uint32_t mRespondWithLineNumber
;
402 const uint32_t mRespondWithColumnNumber
;
403 bool mRequestWasHandled
;
409 nsMainThreadPtrHandle
<nsIInterceptedChannel
>& aChannel
,
410 nsMainThreadPtrHandle
<ServiceWorkerRegistrationInfo
>& aRegistration
,
411 RequestMode aRequestMode
, bool aIsClientRequest
,
412 RequestRedirect aRedirectMode
, const nsACString
& aScriptSpec
,
413 const nsAString
& aRequestURL
, const nsACString
& aRequestFragment
,
414 const nsACString
& aRespondWithScriptSpec
, uint32_t aRespondWithLineNumber
,
415 uint32_t aRespondWithColumnNumber
)
416 : mInterceptedChannel(aChannel
),
417 mRegistration(aRegistration
),
418 mRequestMode(aRequestMode
),
419 mRequestRedirectMode(aRedirectMode
)
422 mIsClientRequest(aIsClientRequest
)
425 mScriptSpec(aScriptSpec
),
426 mRequestURL(aRequestURL
),
427 mRequestFragment(aRequestFragment
),
428 mRespondWithScriptSpec(aRespondWithScriptSpec
),
429 mRespondWithLineNumber(aRespondWithLineNumber
),
430 mRespondWithColumnNumber(aRespondWithColumnNumber
),
431 mRequestWasHandled(false) {
434 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
435 ErrorResult
& aRv
) override
;
437 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
438 ErrorResult
& aRv
) override
;
440 void CancelRequest(nsresult aStatus
);
442 void AsyncLog(const nsACString
& aMessageName
,
443 const nsTArray
<nsString
>& aParams
) {
444 ::AsyncLog(mInterceptedChannel
, mRespondWithScriptSpec
,
445 mRespondWithLineNumber
, mRespondWithColumnNumber
, aMessageName
,
449 void AsyncLog(const nsACString
& aSourceSpec
, uint32_t aLine
, uint32_t aColumn
,
450 const nsACString
& aMessageName
,
451 const nsTArray
<nsString
>& aParams
) {
452 ::AsyncLog(mInterceptedChannel
, aSourceSpec
, aLine
, aColumn
, aMessageName
,
457 ~RespondWithHandler() {
458 if (!mRequestWasHandled
) {
459 ::AsyncLog(mInterceptedChannel
, mRespondWithScriptSpec
,
460 mRespondWithLineNumber
, mRespondWithColumnNumber
,
461 "InterceptionFailedWithURL"_ns
, mRequestURL
);
462 CancelRequest(NS_ERROR_INTERCEPTION_FAILED
);
467 class MOZ_STACK_CLASS AutoCancel
{
468 RefPtr
<RespondWithHandler
> mOwner
;
469 nsCString mSourceSpec
;
472 nsCString mMessageName
;
473 nsTArray
<nsString
> mParams
;
476 AutoCancel(RespondWithHandler
* aOwner
, const nsString
& aRequestURL
)
480 mMessageName("InterceptionFailedWithURL"_ns
) {
481 mParams
.AppendElement(aRequestURL
);
486 if (mSourceSpec
.IsEmpty()) {
487 mOwner
->AsyncLog(mMessageName
, mParams
);
489 mOwner
->AsyncLog(mSourceSpec
, mLine
, mColumn
, mMessageName
, mParams
);
491 mOwner
->CancelRequest(NS_ERROR_INTERCEPTION_FAILED
);
495 // This function steals the error message from a ErrorResult.
496 void SetCancelErrorResult(JSContext
* aCx
, ErrorResult
& aRv
) {
497 MOZ_DIAGNOSTIC_ASSERT(aRv
.Failed());
498 MOZ_DIAGNOSTIC_ASSERT(!JS_IsExceptionPending(aCx
));
500 // Storing the error as exception in the JSContext.
501 if (!aRv
.MaybeSetPendingException(aCx
)) {
505 MOZ_ASSERT(!aRv
.Failed());
507 // Let's take the pending exception.
508 JS::ExceptionStack
exnStack(aCx
);
509 if (!JS::StealPendingExceptionStack(aCx
, &exnStack
)) {
513 // Converting the exception in a JS::ErrorReportBuilder.
514 JS::ErrorReportBuilder
report(aCx
);
515 if (!report
.init(aCx
, exnStack
, JS::ErrorReportBuilder::WithSideEffects
)) {
516 JS_ClearPendingException(aCx
);
521 MOZ_ASSERT(mMessageName
.EqualsLiteral("InterceptionFailedWithURL"));
522 MOZ_ASSERT(mParams
.Length() == 1);
524 // Let's store the error message here.
525 mMessageName
.Assign(report
.toStringResult().c_str());
529 template <typename
... Params
>
530 void SetCancelMessage(const nsACString
& aMessageName
, Params
&&... aParams
) {
532 MOZ_ASSERT(mMessageName
.EqualsLiteral("InterceptionFailedWithURL"));
533 MOZ_ASSERT(mParams
.Length() == 1);
534 mMessageName
= aMessageName
;
536 StringArrayAppender::Append(mParams
, sizeof...(Params
),
537 std::forward
<Params
>(aParams
)...);
540 template <typename
... Params
>
541 void SetCancelMessageAndLocation(const nsACString
& aSourceSpec
,
542 uint32_t aLine
, uint32_t aColumn
,
543 const nsACString
& aMessageName
,
544 Params
&&... aParams
) {
546 MOZ_ASSERT(mMessageName
.EqualsLiteral("InterceptionFailedWithURL"));
547 MOZ_ASSERT(mParams
.Length() == 1);
549 mSourceSpec
= aSourceSpec
;
553 mMessageName
= aMessageName
;
555 StringArrayAppender::Append(mParams
, sizeof...(Params
),
556 std::forward
<Params
>(aParams
)...);
559 void Reset() { mOwner
= nullptr; }
562 NS_IMPL_ISUPPORTS0(RespondWithHandler
)
564 void RespondWithHandler::ResolvedCallback(JSContext
* aCx
,
565 JS::Handle
<JS::Value
> aValue
,
567 AutoCancel
autoCancel(this, mRequestURL
);
569 if (!aValue
.isObject()) {
571 "FetchEvent::RespondWith was passed a promise resolved to a non-Object "
574 nsCString sourceSpec
;
577 nsString valueString
;
578 nsContentUtils::ExtractErrorValues(aCx
, aValue
, sourceSpec
, &line
, &column
,
581 autoCancel
.SetCancelMessageAndLocation(sourceSpec
, line
, column
,
582 "InterceptedNonResponseWithURL"_ns
,
583 mRequestURL
, valueString
);
587 RefPtr
<Response
> response
;
588 nsresult rv
= UNWRAP_OBJECT(Response
, &aValue
.toObject(), response
);
590 nsCString sourceSpec
;
593 nsString valueString
;
594 nsContentUtils::ExtractErrorValues(aCx
, aValue
, sourceSpec
, &line
, &column
,
597 autoCancel
.SetCancelMessageAndLocation(sourceSpec
, line
, column
,
598 "InterceptedNonResponseWithURL"_ns
,
599 mRequestURL
, valueString
);
603 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
605 worker
->AssertIsOnWorkerThread();
607 // Section "HTTP Fetch", step 3.3:
608 // If one of the following conditions is true, return a network error:
609 // * response's type is "error".
610 // * request's mode is not "no-cors" and response's type is "opaque".
611 // * request's redirect mode is not "manual" and response's type is
613 // * request's redirect mode is not "follow" and response's url list
614 // has more than one item.
616 if (response
->Type() == ResponseType::Error
) {
617 autoCancel
.SetCancelMessage("InterceptedErrorResponseWithURL"_ns
,
622 MOZ_ASSERT_IF(mIsClientRequest
, mRequestMode
== RequestMode::Same_origin
||
623 mRequestMode
== RequestMode::Navigate
);
625 if (response
->Type() == ResponseType::Opaque
&&
626 mRequestMode
!= RequestMode::No_cors
) {
627 NS_ConvertASCIItoUTF16
modeString(
628 RequestModeValues::GetString(mRequestMode
));
630 autoCancel
.SetCancelMessage("BadOpaqueInterceptionRequestModeWithURL"_ns
,
631 mRequestURL
, modeString
);
635 if (mRequestRedirectMode
!= RequestRedirect::Manual
&&
636 response
->Type() == ResponseType::Opaqueredirect
) {
637 autoCancel
.SetCancelMessage("BadOpaqueRedirectInterceptionWithURL"_ns
,
642 if (mRequestRedirectMode
!= RequestRedirect::Follow
&&
643 response
->Redirected()) {
644 autoCancel
.SetCancelMessage("BadRedirectModeInterceptionWithURL"_ns
,
649 if (NS_WARN_IF(response
->BodyUsed())) {
650 autoCancel
.SetCancelMessage("InterceptedUsedResponseWithURL"_ns
,
655 SafeRefPtr
<InternalResponse
> ir
= response
->GetInternalResponse();
656 if (NS_WARN_IF(!ir
)) {
660 // An extra safety check to make sure our invariant that opaque and cors
661 // responses always have a URL does not break.
662 if (NS_WARN_IF((response
->Type() == ResponseType::Opaque
||
663 response
->Type() == ResponseType::Cors
) &&
664 ir
->GetUnfilteredURL().IsEmpty())) {
665 MOZ_DIAGNOSTIC_ASSERT(false, "Cors or opaque Response without a URL");
669 if (mRequestMode
== RequestMode::Same_origin
&&
670 response
->Type() == ResponseType::Cors
) {
671 Telemetry::ScalarAdd(Telemetry::ScalarID::SW_CORS_RES_FOR_SO_REQ_COUNT
, 1);
673 // XXXtt: Will have a pref to enable the quirk response in bug 1419684.
674 // The variadic template provided by StringArrayAppender requires exactly
676 NS_ConvertUTF8toUTF16
responseURL(ir
->GetUnfilteredURL());
677 autoCancel
.SetCancelMessage("CorsResponseForSameOriginRequest"_ns
,
678 mRequestURL
, responseURL
);
682 // Propagate the URL to the content if the request mode is not "navigate".
683 // Note that, we only reflect the final URL if the response.redirected is
684 // false. We propagate all the URLs if the response.redirected is true.
685 nsCString responseURL
;
686 if (mRequestMode
!= RequestMode::Navigate
) {
687 responseURL
= ir
->GetUnfilteredURL();
689 // Similar to how we apply the request fragment to redirects automatically
690 // we also want to apply it automatically when propagating the response
691 // URL from a service worker interception. Currently response.url strips
692 // the fragment, so this will never conflict with an existing fragment
693 // on the response. In the future we will have to check for a response
694 // fragment and avoid overriding in that case.
695 if (!mRequestFragment
.IsEmpty() && !responseURL
.IsEmpty()) {
696 MOZ_ASSERT(!responseURL
.Contains('#'));
697 responseURL
.Append("#"_ns
);
698 responseURL
.Append(mRequestFragment
);
702 UniquePtr
<RespondWithClosure
> closure(new RespondWithClosure(
703 mInterceptedChannel
, mRegistration
, mRequestURL
, mRespondWithScriptSpec
,
704 mRespondWithLineNumber
, mRespondWithColumnNumber
));
706 nsCOMPtr
<nsIRunnable
> startRunnable
= new StartResponse(
707 mInterceptedChannel
, ir
.clonePtr(), worker
->GetChannelInfo(), mScriptSpec
,
708 responseURL
, std::move(closure
));
710 nsCOMPtr
<nsIInputStream
> body
;
711 ir
->GetUnfilteredBody(getter_AddRefs(body
));
712 // Errors and redirects may not have a body.
715 response
->SetBodyUsed(aCx
, error
);
716 error
.WouldReportJSException();
717 if (NS_WARN_IF(error
.Failed())) {
718 autoCancel
.SetCancelErrorResult(aCx
, error
);
723 MOZ_ALWAYS_SUCCEEDS(worker
->DispatchToMainThread(startRunnable
.forget()));
725 MOZ_ASSERT(!closure
);
727 mRequestWasHandled
= true;
730 void RespondWithHandler::RejectedCallback(JSContext
* aCx
,
731 JS::Handle
<JS::Value
> aValue
,
733 nsCString sourceSpec
= mRespondWithScriptSpec
;
734 uint32_t line
= mRespondWithLineNumber
;
735 uint32_t column
= mRespondWithColumnNumber
;
736 nsString valueString
;
738 nsContentUtils::ExtractErrorValues(aCx
, aValue
, sourceSpec
, &line
, &column
,
741 ::AsyncLog(mInterceptedChannel
, sourceSpec
, line
, column
,
742 "InterceptionRejectedResponseWithURL"_ns
, mRequestURL
,
745 CancelRequest(NS_ERROR_INTERCEPTION_FAILED
);
748 void RespondWithHandler::CancelRequest(nsresult aStatus
) {
749 nsCOMPtr
<nsIRunnable
> runnable
=
750 new CancelChannelRunnable(mInterceptedChannel
, mRegistration
, aStatus
);
751 // Note, this may run off the worker thread during worker termination.
752 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
754 MOZ_ALWAYS_SUCCEEDS(worker
->DispatchToMainThread(runnable
.forget()));
756 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
.forget()));
758 mRequestWasHandled
= true;
763 void FetchEvent::RespondWith(JSContext
* aCx
, Promise
& aArg
, ErrorResult
& aRv
) {
764 if (!GetDispatchFlag() || mWaitToRespond
) {
765 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
769 // Record where respondWith() was called in the script so we can include the
770 // information in any error reporting. We should be guaranteed not to get
771 // a file:// string here because service workers require http/https.
775 nsJSUtils::GetCallingLocation(aCx
, spec
, &line
, &column
);
777 SafeRefPtr
<InternalRequest
> ir
= mRequest
->GetInternalRequest();
779 nsAutoCString requestURL
;
780 ir
->GetURL(requestURL
);
782 StopImmediatePropagation();
783 mWaitToRespond
= true;
786 RefPtr
<RespondWithHandler
> handler
= new RespondWithHandler(
787 mChannel
, mRegistration
, mRequest
->Mode(), ir
->IsClientRequest(),
788 mRequest
->Redirect(), mScriptSpec
, NS_ConvertUTF8toUTF16(requestURL
),
789 ir
->GetFragment(), spec
, line
, column
);
791 aArg
.AppendNativeHandler(handler
);
792 // mRespondWithHandler can be nullptr for self-dispatched FetchEvent.
793 } else if (mRespondWithHandler
) {
794 mRespondWithHandler
->RespondWithCalledAt(spec
, line
, column
);
795 aArg
.AppendNativeHandler(mRespondWithHandler
);
796 mRespondWithHandler
= nullptr;
799 if (!WaitOnPromise(aArg
)) {
800 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
804 void FetchEvent::PreventDefault(JSContext
* aCx
, CallerType aCallerType
) {
806 MOZ_ASSERT(aCallerType
!= CallerType::System
,
807 "Since when do we support system-principal service workers?");
809 if (mPreventDefaultScriptSpec
.IsEmpty()) {
810 // Note when the FetchEvent might have been canceled by script, but don't
811 // actually log the location until we are sure it matters. This is
812 // determined in ServiceWorkerPrivate.cpp. We only remember the first
813 // call to preventDefault() as its the most likely to have actually canceled
815 nsJSUtils::GetCallingLocation(aCx
, mPreventDefaultScriptSpec
,
816 &mPreventDefaultLineNumber
,
817 &mPreventDefaultColumnNumber
);
820 Event::PreventDefault(aCx
, aCallerType
);
823 void FetchEvent::ReportCanceled() {
824 MOZ_ASSERT(!mPreventDefaultScriptSpec
.IsEmpty());
826 SafeRefPtr
<InternalRequest
> ir
= mRequest
->GetInternalRequest();
830 // The variadic template provided by StringArrayAppender requires exactly
832 NS_ConvertUTF8toUTF16
requestURL(url
);
833 // nsString requestURL;
834 // CopyUTF8toUTF16(url, requestURL);
837 ::AsyncLog(mChannel
.get(), mPreventDefaultScriptSpec
,
838 mPreventDefaultLineNumber
, mPreventDefaultColumnNumber
,
839 "InterceptionCanceledWithURL"_ns
, requestURL
);
840 // mRespondWithHandler could be nullptr for self-dispatched FetchEvent.
841 } else if (mRespondWithHandler
) {
842 mRespondWithHandler
->ReportCanceled(mPreventDefaultScriptSpec
,
843 mPreventDefaultLineNumber
,
844 mPreventDefaultColumnNumber
);
845 mRespondWithHandler
= nullptr;
851 class WaitUntilHandler final
: public PromiseNativeHandler
{
852 WorkerPrivate
* mWorkerPrivate
;
853 const nsCString mScope
;
854 nsString mSourceSpec
;
857 nsString mRejectValue
;
859 ~WaitUntilHandler() = default;
862 NS_DECL_THREADSAFE_ISUPPORTS
864 WaitUntilHandler(WorkerPrivate
* aWorkerPrivate
, JSContext
* aCx
)
865 : mWorkerPrivate(aWorkerPrivate
),
866 mScope(mWorkerPrivate
->ServiceWorkerScope()),
869 mWorkerPrivate
->AssertIsOnWorkerThread();
871 // Save the location of the waitUntil() call itself as a fallback
872 // in case the rejection value does not contain any location info.
873 nsJSUtils::GetCallingLocation(aCx
, mSourceSpec
, &mLine
, &mColumn
);
876 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValu
,
877 ErrorResult
& aRve
) override
{
878 // do nothing, we are only here to report errors
881 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
882 ErrorResult
& aRv
) override
{
883 mWorkerPrivate
->AssertIsOnWorkerThread();
888 nsContentUtils::ExtractErrorValues(aCx
, aValue
, spec
, &line
, &column
,
891 // only use the extracted location if we found one
892 if (!spec
.IsEmpty()) {
898 MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate
->DispatchToMainThread(
899 NewRunnableMethod("WaitUntilHandler::ReportOnMainThread", this,
900 &WaitUntilHandler::ReportOnMainThread
)));
903 void ReportOnMainThread() {
904 MOZ_ASSERT(NS_IsMainThread());
905 RefPtr
<ServiceWorkerManager
> swm
= ServiceWorkerManager::GetInstance();
911 // TODO: Make the error message a localized string. (bug 1222720)
913 message
.AppendLiteral(
914 "Service worker event waitUntil() was passed a "
915 "promise that rejected with '");
916 message
.Append(mRejectValue
);
917 message
.AppendLiteral("'.");
919 // Note, there is a corner case where this won't report to the window
920 // that triggered the error. Consider a navigation fetch event that
921 // rejects waitUntil() without holding respondWith() open. In this case
922 // there is no controlling document yet, the window did call .register()
923 // because there is no documeny yet, and the navigation is no longer
924 // being intercepted.
926 swm
->ReportToAllClients(mScope
, message
, mSourceSpec
, u
""_ns
, mLine
,
927 mColumn
, nsIScriptError::errorFlag
);
931 NS_IMPL_ISUPPORTS0(WaitUntilHandler
)
933 } // anonymous namespace
935 ExtendableEvent::ExtensionsHandler::~ExtensionsHandler() {
936 MOZ_ASSERT(!mExtendableEvent
);
939 bool ExtendableEvent::ExtensionsHandler::GetDispatchFlag() const {
940 // mExtendableEvent should set itself as nullptr in its destructor, and we
941 // can't be dispatching an event that doesn't exist, so this should work for
942 // as long as it's not needed to determine whether the event is still alive,
943 // which seems unlikely.
944 if (!mExtendableEvent
) {
948 return mExtendableEvent
->GetDispatchFlag();
951 void ExtendableEvent::ExtensionsHandler::SetExtendableEvent(
952 const ExtendableEvent
* const aExtendableEvent
) {
953 mExtendableEvent
= aExtendableEvent
;
956 NS_IMPL_ADDREF_INHERITED(FetchEvent
, ExtendableEvent
)
957 NS_IMPL_RELEASE_INHERITED(FetchEvent
, ExtendableEvent
)
959 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchEvent
)
960 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent
)
962 NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent
, ExtendableEvent
, mRequest
,
963 mHandled
, mPreloadResponse
)
965 ExtendableEvent::ExtendableEvent(EventTarget
* aOwner
)
966 : Event(aOwner
, nullptr, nullptr) {}
968 bool ExtendableEvent::WaitOnPromise(Promise
& aPromise
) {
969 if (!mExtensionsHandler
) {
972 return mExtensionsHandler
->WaitOnPromise(aPromise
);
975 void ExtendableEvent::SetKeepAliveHandler(
976 ExtensionsHandler
* aExtensionsHandler
) {
977 MOZ_ASSERT(!mExtensionsHandler
);
978 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
980 worker
->AssertIsOnWorkerThread();
981 mExtensionsHandler
= aExtensionsHandler
;
982 mExtensionsHandler
->SetExtendableEvent(this);
985 void ExtendableEvent::WaitUntil(JSContext
* aCx
, Promise
& aPromise
,
987 MOZ_ASSERT(!NS_IsMainThread());
989 if (!WaitOnPromise(aPromise
)) {
990 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
994 // Append our handler to each waitUntil promise separately so we
995 // can record the location in script where waitUntil was called.
996 RefPtr
<WaitUntilHandler
> handler
=
997 new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx
);
998 aPromise
.AppendNativeHandler(handler
);
1001 NS_IMPL_ADDREF_INHERITED(ExtendableEvent
, Event
)
1002 NS_IMPL_RELEASE_INHERITED(ExtendableEvent
, Event
)
1004 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtendableEvent
)
1005 NS_INTERFACE_MAP_END_INHERITING(Event
)
1008 nsresult
ExtractBytesFromUSVString(const nsAString
& aStr
,
1009 nsTArray
<uint8_t>& aBytes
) {
1010 MOZ_ASSERT(aBytes
.IsEmpty());
1011 auto encoder
= UTF_8_ENCODING
->NewEncoder();
1012 CheckedInt
<size_t> needed
=
1013 encoder
->MaxBufferLengthFromUTF16WithoutReplacement(aStr
.Length());
1014 if (NS_WARN_IF(!needed
.isValid() ||
1015 !aBytes
.SetLength(needed
.value(), fallible
))) {
1016 return NS_ERROR_OUT_OF_MEMORY
;
1021 // Do not use structured binding lest deal with [-Werror=unused-variable]
1022 std::tie(result
, read
, written
) =
1023 encoder
->EncodeFromUTF16WithoutReplacement(aStr
, aBytes
, true);
1024 MOZ_ASSERT(result
== kInputEmpty
);
1025 MOZ_ASSERT(read
== aStr
.Length());
1026 aBytes
.TruncateLength(written
);
1030 nsresult
ExtractBytesFromData(
1031 const OwningArrayBufferViewOrArrayBufferOrUSVString
& aDataInit
,
1032 nsTArray
<uint8_t>& aBytes
) {
1033 MOZ_ASSERT(aBytes
.IsEmpty());
1034 Maybe
<bool> result
= AppendTypedArrayDataTo(aDataInit
, aBytes
);
1035 if (result
.isSome()) {
1036 return NS_WARN_IF(!result
.value()) ? NS_ERROR_OUT_OF_MEMORY
: NS_OK
;
1038 if (aDataInit
.IsUSVString()) {
1039 return ExtractBytesFromUSVString(aDataInit
.GetAsUSVString(), aBytes
);
1041 MOZ_ASSERT_UNREACHABLE("Unexpected push message data");
1042 return NS_ERROR_FAILURE
;
1046 PushMessageData::PushMessageData(nsIGlobalObject
* aOwner
,
1047 nsTArray
<uint8_t>&& aBytes
)
1048 : mOwner(aOwner
), mBytes(std::move(aBytes
)) {}
1050 PushMessageData::~PushMessageData() = default;
1052 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushMessageData
, mOwner
)
1054 NS_IMPL_CYCLE_COLLECTING_ADDREF(PushMessageData
)
1055 NS_IMPL_CYCLE_COLLECTING_RELEASE(PushMessageData
)
1057 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushMessageData
)
1058 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1059 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1060 NS_INTERFACE_MAP_END
1062 JSObject
* PushMessageData::WrapObject(JSContext
* aCx
,
1063 JS::Handle
<JSObject
*> aGivenProto
) {
1064 return mozilla::dom::PushMessageData_Binding::Wrap(aCx
, this, aGivenProto
);
1067 void PushMessageData::Json(JSContext
* cx
, JS::MutableHandle
<JS::Value
> aRetval
,
1069 if (NS_FAILED(EnsureDecodedText())) {
1070 aRv
.Throw(NS_ERROR_DOM_UNKNOWN_ERR
);
1073 BodyUtil::ConsumeJson(cx
, aRetval
, mDecodedText
, aRv
);
1076 void PushMessageData::Text(nsAString
& aData
) {
1077 if (NS_SUCCEEDED(EnsureDecodedText())) {
1078 aData
= mDecodedText
;
1082 void PushMessageData::ArrayBuffer(JSContext
* cx
,
1083 JS::MutableHandle
<JSObject
*> aRetval
,
1085 uint8_t* data
= GetContentsCopy();
1087 UniquePtr
<uint8_t[], JS::FreePolicy
> dataPtr(data
);
1088 BodyUtil::ConsumeArrayBuffer(cx
, aRetval
, mBytes
.Length(),
1089 std::move(dataPtr
), aRv
);
1093 already_AddRefed
<mozilla::dom::Blob
> PushMessageData::Blob(ErrorResult
& aRv
) {
1094 uint8_t* data
= GetContentsCopy();
1096 RefPtr
<mozilla::dom::Blob
> blob
=
1097 BodyUtil::ConsumeBlob(mOwner
, u
""_ns
, mBytes
.Length(), data
, aRv
);
1099 return blob
.forget();
1105 nsresult
PushMessageData::EnsureDecodedText() {
1106 if (mBytes
.IsEmpty() || !mDecodedText
.IsEmpty()) {
1109 nsresult rv
= BodyUtil::ConsumeText(
1110 mBytes
.Length(), reinterpret_cast<uint8_t*>(mBytes
.Elements()),
1112 if (NS_WARN_IF(NS_FAILED(rv
))) {
1113 mDecodedText
.Truncate();
1119 uint8_t* PushMessageData::GetContentsCopy() {
1120 uint32_t length
= mBytes
.Length();
1121 void* data
= malloc(length
);
1125 memcpy(data
, mBytes
.Elements(), length
);
1126 return reinterpret_cast<uint8_t*>(data
);
1129 PushEvent::PushEvent(EventTarget
* aOwner
) : ExtendableEvent(aOwner
) {}
1131 already_AddRefed
<PushEvent
> PushEvent::Constructor(
1132 mozilla::dom::EventTarget
* aOwner
, const nsAString
& aType
,
1133 const PushEventInit
& aOptions
, ErrorResult
& aRv
) {
1134 RefPtr
<PushEvent
> e
= new PushEvent(aOwner
);
1135 bool trusted
= e
->Init(aOwner
);
1136 e
->InitEvent(aType
, aOptions
.mBubbles
, aOptions
.mCancelable
);
1137 e
->SetTrusted(trusted
);
1138 e
->SetComposed(aOptions
.mComposed
);
1139 if (aOptions
.mData
.WasPassed()) {
1140 nsTArray
<uint8_t> bytes
;
1141 nsresult rv
= ExtractBytesFromData(aOptions
.mData
.Value(), bytes
);
1142 if (NS_FAILED(rv
)) {
1146 e
->mData
= new PushMessageData(aOwner
->GetOwnerGlobal(), std::move(bytes
));
1151 NS_IMPL_ADDREF_INHERITED(PushEvent
, ExtendableEvent
)
1152 NS_IMPL_RELEASE_INHERITED(PushEvent
, ExtendableEvent
)
1154 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushEvent
)
1155 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent
)
1157 NS_IMPL_CYCLE_COLLECTION_INHERITED(PushEvent
, ExtendableEvent
, mData
)
1159 JSObject
* PushEvent::WrapObjectInternal(JSContext
* aCx
,
1160 JS::Handle
<JSObject
*> aGivenProto
) {
1161 return mozilla::dom::PushEvent_Binding::Wrap(aCx
, this, aGivenProto
);
1164 ExtendableMessageEvent::ExtendableMessageEvent(EventTarget
* aOwner
)
1165 : ExtendableEvent(aOwner
), mData(JS::UndefinedValue()) {
1166 mozilla::HoldJSObjects(this);
1169 ExtendableMessageEvent::~ExtendableMessageEvent() { DropJSObjects(this); }
1171 void ExtendableMessageEvent::GetData(JSContext
* aCx
,
1172 JS::MutableHandle
<JS::Value
> aData
,
1175 if (!JS_WrapValue(aCx
, aData
)) {
1176 aRv
.Throw(NS_ERROR_FAILURE
);
1180 void ExtendableMessageEvent::GetSource(
1181 Nullable
<OwningClientOrServiceWorkerOrMessagePort
>& aValue
) const {
1183 aValue
.SetValue().SetAsClient() = mClient
;
1184 } else if (mServiceWorker
) {
1185 aValue
.SetValue().SetAsServiceWorker() = mServiceWorker
;
1186 } else if (mMessagePort
) {
1187 aValue
.SetValue().SetAsMessagePort() = mMessagePort
;
1189 // nullptr source is possible for manually constructed event
1195 already_AddRefed
<ExtendableMessageEvent
> ExtendableMessageEvent::Constructor(
1196 const GlobalObject
& aGlobal
, const nsAString
& aType
,
1197 const ExtendableMessageEventInit
& aOptions
) {
1198 nsCOMPtr
<EventTarget
> t
= do_QueryInterface(aGlobal
.GetAsSupports());
1199 return Constructor(t
, aType
, aOptions
);
1203 already_AddRefed
<ExtendableMessageEvent
> ExtendableMessageEvent::Constructor(
1204 mozilla::dom::EventTarget
* aEventTarget
, const nsAString
& aType
,
1205 const ExtendableMessageEventInit
& aOptions
) {
1206 RefPtr
<ExtendableMessageEvent
> event
=
1207 new ExtendableMessageEvent(aEventTarget
);
1209 event
->InitEvent(aType
, aOptions
.mBubbles
, aOptions
.mCancelable
);
1210 bool trusted
= event
->Init(aEventTarget
);
1211 event
->SetTrusted(trusted
);
1213 event
->mData
= aOptions
.mData
;
1214 event
->mOrigin
= aOptions
.mOrigin
;
1215 event
->mLastEventId
= aOptions
.mLastEventId
;
1217 if (!aOptions
.mSource
.IsNull()) {
1218 if (aOptions
.mSource
.Value().IsClient()) {
1219 event
->mClient
= aOptions
.mSource
.Value().GetAsClient();
1220 } else if (aOptions
.mSource
.Value().IsServiceWorker()) {
1221 event
->mServiceWorker
= aOptions
.mSource
.Value().GetAsServiceWorker();
1222 } else if (aOptions
.mSource
.Value().IsMessagePort()) {
1223 event
->mMessagePort
= aOptions
.mSource
.Value().GetAsMessagePort();
1227 event
->mPorts
.AppendElements(aOptions
.mPorts
);
1228 return event
.forget();
1231 void ExtendableMessageEvent::GetPorts(nsTArray
<RefPtr
<MessagePort
>>& aPorts
) {
1232 aPorts
= mPorts
.Clone();
1235 NS_IMPL_CYCLE_COLLECTION_CLASS(ExtendableMessageEvent
)
1237 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1238 tmp
->mData
.setUndefined();
1239 NS_IMPL_CYCLE_COLLECTION_UNLINK(mClient
)
1240 NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker
)
1241 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort
)
1242 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts
)
1243 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1245 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1246 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClient
)
1247 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker
)
1248 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort
)
1249 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts
)
1250 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1252 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1253 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData
)
1254 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1256 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtendableMessageEvent
)
1257 NS_INTERFACE_MAP_END_INHERITING(Event
)
1259 NS_IMPL_ADDREF_INHERITED(ExtendableMessageEvent
, Event
)
1260 NS_IMPL_RELEASE_INHERITED(ExtendableMessageEvent
, Event
)
1262 } // namespace mozilla::dom