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(1),
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
, &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(GetEnumString(mRequestMode
));
629 autoCancel
.SetCancelMessage("BadOpaqueInterceptionRequestModeWithURL"_ns
,
630 mRequestURL
, modeString
);
634 if (mRequestRedirectMode
!= RequestRedirect::Manual
&&
635 response
->Type() == ResponseType::Opaqueredirect
) {
636 autoCancel
.SetCancelMessage("BadOpaqueRedirectInterceptionWithURL"_ns
,
641 if (mRequestRedirectMode
!= RequestRedirect::Follow
&&
642 response
->Redirected()) {
643 autoCancel
.SetCancelMessage("BadRedirectModeInterceptionWithURL"_ns
,
648 if (NS_WARN_IF(response
->BodyUsed())) {
649 autoCancel
.SetCancelMessage("InterceptedUsedResponseWithURL"_ns
,
654 SafeRefPtr
<InternalResponse
> ir
= response
->GetInternalResponse();
655 if (NS_WARN_IF(!ir
)) {
659 // An extra safety check to make sure our invariant that opaque and cors
660 // responses always have a URL does not break.
661 if (NS_WARN_IF((response
->Type() == ResponseType::Opaque
||
662 response
->Type() == ResponseType::Cors
) &&
663 ir
->GetUnfilteredURL().IsEmpty())) {
664 MOZ_DIAGNOSTIC_ASSERT(false, "Cors or opaque Response without a URL");
668 if (mRequestMode
== RequestMode::Same_origin
&&
669 response
->Type() == ResponseType::Cors
) {
670 Telemetry::ScalarAdd(Telemetry::ScalarID::SW_CORS_RES_FOR_SO_REQ_COUNT
, 1);
672 // XXXtt: Will have a pref to enable the quirk response in bug 1419684.
673 // The variadic template provided by StringArrayAppender requires exactly
675 NS_ConvertUTF8toUTF16
responseURL(ir
->GetUnfilteredURL());
676 autoCancel
.SetCancelMessage("CorsResponseForSameOriginRequest"_ns
,
677 mRequestURL
, responseURL
);
681 // Propagate the URL to the content if the request mode is not "navigate".
682 // Note that, we only reflect the final URL if the response.redirected is
683 // false. We propagate all the URLs if the response.redirected is true.
684 nsCString responseURL
;
685 if (mRequestMode
!= RequestMode::Navigate
) {
686 responseURL
= ir
->GetUnfilteredURL();
688 // Similar to how we apply the request fragment to redirects automatically
689 // we also want to apply it automatically when propagating the response
690 // URL from a service worker interception. Currently response.url strips
691 // the fragment, so this will never conflict with an existing fragment
692 // on the response. In the future we will have to check for a response
693 // fragment and avoid overriding in that case.
694 if (!mRequestFragment
.IsEmpty() && !responseURL
.IsEmpty()) {
695 MOZ_ASSERT(!responseURL
.Contains('#'));
696 responseURL
.Append("#"_ns
);
697 responseURL
.Append(mRequestFragment
);
701 UniquePtr
<RespondWithClosure
> closure(new RespondWithClosure(
702 mInterceptedChannel
, mRegistration
, mRequestURL
, mRespondWithScriptSpec
,
703 mRespondWithLineNumber
, mRespondWithColumnNumber
));
705 nsCOMPtr
<nsIRunnable
> startRunnable
= new StartResponse(
706 mInterceptedChannel
, ir
.clonePtr(), worker
->GetChannelInfo(), mScriptSpec
,
707 responseURL
, std::move(closure
));
709 nsCOMPtr
<nsIInputStream
> body
;
710 ir
->GetUnfilteredBody(getter_AddRefs(body
));
711 // Errors and redirects may not have a body.
714 response
->SetBodyUsed(aCx
, error
);
715 error
.WouldReportJSException();
716 if (NS_WARN_IF(error
.Failed())) {
717 autoCancel
.SetCancelErrorResult(aCx
, error
);
722 MOZ_ALWAYS_SUCCEEDS(worker
->DispatchToMainThread(startRunnable
.forget()));
724 MOZ_ASSERT(!closure
);
726 mRequestWasHandled
= true;
729 void RespondWithHandler::RejectedCallback(JSContext
* aCx
,
730 JS::Handle
<JS::Value
> aValue
,
732 nsCString sourceSpec
= mRespondWithScriptSpec
;
733 uint32_t line
= mRespondWithLineNumber
;
734 uint32_t column
= mRespondWithColumnNumber
;
735 nsString valueString
;
737 nsContentUtils::ExtractErrorValues(aCx
, aValue
, sourceSpec
, &line
, &column
,
740 ::AsyncLog(mInterceptedChannel
, sourceSpec
, line
, column
,
741 "InterceptionRejectedResponseWithURL"_ns
, mRequestURL
,
744 CancelRequest(NS_ERROR_INTERCEPTION_FAILED
);
747 void RespondWithHandler::CancelRequest(nsresult aStatus
) {
748 nsCOMPtr
<nsIRunnable
> runnable
=
749 new CancelChannelRunnable(mInterceptedChannel
, mRegistration
, aStatus
);
750 // Note, this may run off the worker thread during worker termination.
751 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
753 MOZ_ALWAYS_SUCCEEDS(worker
->DispatchToMainThread(runnable
.forget()));
755 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable
.forget()));
757 mRequestWasHandled
= true;
762 void FetchEvent::RespondWith(JSContext
* aCx
, Promise
& aArg
, ErrorResult
& aRv
) {
763 if (!GetDispatchFlag() || mWaitToRespond
) {
764 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
768 // Record where respondWith() was called in the script so we can include the
769 // information in any error reporting. We should be guaranteed not to get
770 // a file:// string here because service workers require http/https.
774 nsJSUtils::GetCallingLocation(aCx
, spec
, &line
, &column
);
776 SafeRefPtr
<InternalRequest
> ir
= mRequest
->GetInternalRequest();
778 nsAutoCString requestURL
;
779 ir
->GetURL(requestURL
);
781 StopImmediatePropagation();
782 mWaitToRespond
= true;
785 RefPtr
<RespondWithHandler
> handler
= new RespondWithHandler(
786 mChannel
, mRegistration
, mRequest
->Mode(), ir
->IsClientRequest(),
787 mRequest
->Redirect(), mScriptSpec
, NS_ConvertUTF8toUTF16(requestURL
),
788 ir
->GetFragment(), spec
, line
, column
);
790 aArg
.AppendNativeHandler(handler
);
791 // mRespondWithHandler can be nullptr for self-dispatched FetchEvent.
792 } else if (mRespondWithHandler
) {
793 mRespondWithHandler
->RespondWithCalledAt(spec
, line
, column
);
794 aArg
.AppendNativeHandler(mRespondWithHandler
);
795 mRespondWithHandler
= nullptr;
798 if (!WaitOnPromise(aArg
)) {
799 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
803 void FetchEvent::PreventDefault(JSContext
* aCx
, CallerType aCallerType
) {
805 MOZ_ASSERT(aCallerType
!= CallerType::System
,
806 "Since when do we support system-principal service workers?");
808 if (mPreventDefaultScriptSpec
.IsEmpty()) {
809 // Note when the FetchEvent might have been canceled by script, but don't
810 // actually log the location until we are sure it matters. This is
811 // determined in ServiceWorkerPrivate.cpp. We only remember the first
812 // call to preventDefault() as its the most likely to have actually canceled
814 nsJSUtils::GetCallingLocation(aCx
, mPreventDefaultScriptSpec
,
815 &mPreventDefaultLineNumber
,
816 &mPreventDefaultColumnNumber
);
819 Event::PreventDefault(aCx
, aCallerType
);
822 void FetchEvent::ReportCanceled() {
823 MOZ_ASSERT(!mPreventDefaultScriptSpec
.IsEmpty());
825 SafeRefPtr
<InternalRequest
> ir
= mRequest
->GetInternalRequest();
829 // The variadic template provided by StringArrayAppender requires exactly
831 NS_ConvertUTF8toUTF16
requestURL(url
);
832 // nsString requestURL;
833 // CopyUTF8toUTF16(url, requestURL);
836 ::AsyncLog(mChannel
.get(), mPreventDefaultScriptSpec
,
837 mPreventDefaultLineNumber
, mPreventDefaultColumnNumber
,
838 "InterceptionCanceledWithURL"_ns
, requestURL
);
839 // mRespondWithHandler could be nullptr for self-dispatched FetchEvent.
840 } else if (mRespondWithHandler
) {
841 mRespondWithHandler
->ReportCanceled(mPreventDefaultScriptSpec
,
842 mPreventDefaultLineNumber
,
843 mPreventDefaultColumnNumber
);
844 mRespondWithHandler
= nullptr;
850 class WaitUntilHandler final
: public PromiseNativeHandler
{
851 WorkerPrivate
* mWorkerPrivate
;
852 const nsCString mScope
;
853 nsString mSourceSpec
;
856 nsString mRejectValue
;
858 ~WaitUntilHandler() = default;
861 NS_DECL_THREADSAFE_ISUPPORTS
863 WaitUntilHandler(WorkerPrivate
* aWorkerPrivate
, JSContext
* aCx
)
864 : mWorkerPrivate(aWorkerPrivate
),
865 mScope(mWorkerPrivate
->ServiceWorkerScope()),
868 mWorkerPrivate
->AssertIsOnWorkerThread();
870 // Save the location of the waitUntil() call itself as a fallback
871 // in case the rejection value does not contain any location info.
872 nsJSUtils::GetCallingLocation(aCx
, mSourceSpec
, &mLine
, &mColumn
);
875 void ResolvedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValu
,
876 ErrorResult
& aRve
) override
{
877 // do nothing, we are only here to report errors
880 void RejectedCallback(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
881 ErrorResult
& aRv
) override
{
882 mWorkerPrivate
->AssertIsOnWorkerThread();
887 nsContentUtils::ExtractErrorValues(aCx
, aValue
, spec
, &line
, &column
,
890 // only use the extracted location if we found one
891 if (!spec
.IsEmpty()) {
897 MOZ_ALWAYS_SUCCEEDS(mWorkerPrivate
->DispatchToMainThread(
898 NewRunnableMethod("WaitUntilHandler::ReportOnMainThread", this,
899 &WaitUntilHandler::ReportOnMainThread
)));
902 void ReportOnMainThread() {
903 MOZ_ASSERT(NS_IsMainThread());
904 RefPtr
<ServiceWorkerManager
> swm
= ServiceWorkerManager::GetInstance();
910 // TODO: Make the error message a localized string. (bug 1222720)
912 message
.AppendLiteral(
913 "Service worker event waitUntil() was passed a "
914 "promise that rejected with '");
915 message
.Append(mRejectValue
);
916 message
.AppendLiteral("'.");
918 // Note, there is a corner case where this won't report to the window
919 // that triggered the error. Consider a navigation fetch event that
920 // rejects waitUntil() without holding respondWith() open. In this case
921 // there is no controlling document yet, the window did call .register()
922 // because there is no documeny yet, and the navigation is no longer
923 // being intercepted.
925 swm
->ReportToAllClients(mScope
, message
, mSourceSpec
, u
""_ns
, mLine
,
926 mColumn
, nsIScriptError::errorFlag
);
930 NS_IMPL_ISUPPORTS0(WaitUntilHandler
)
932 } // anonymous namespace
934 ExtendableEvent::ExtensionsHandler::~ExtensionsHandler() {
935 MOZ_ASSERT(!mExtendableEvent
);
938 bool ExtendableEvent::ExtensionsHandler::GetDispatchFlag() const {
939 // mExtendableEvent should set itself as nullptr in its destructor, and we
940 // can't be dispatching an event that doesn't exist, so this should work for
941 // as long as it's not needed to determine whether the event is still alive,
942 // which seems unlikely.
943 if (!mExtendableEvent
) {
947 return mExtendableEvent
->GetDispatchFlag();
950 void ExtendableEvent::ExtensionsHandler::SetExtendableEvent(
951 const ExtendableEvent
* const aExtendableEvent
) {
952 mExtendableEvent
= aExtendableEvent
;
955 NS_IMPL_ADDREF_INHERITED(FetchEvent
, ExtendableEvent
)
956 NS_IMPL_RELEASE_INHERITED(FetchEvent
, ExtendableEvent
)
958 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FetchEvent
)
959 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent
)
961 NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent
, ExtendableEvent
, mRequest
,
962 mHandled
, mPreloadResponse
)
964 ExtendableEvent::ExtendableEvent(EventTarget
* aOwner
)
965 : Event(aOwner
, nullptr, nullptr) {}
967 bool ExtendableEvent::WaitOnPromise(Promise
& aPromise
) {
968 if (!mExtensionsHandler
) {
971 return mExtensionsHandler
->WaitOnPromise(aPromise
);
974 void ExtendableEvent::SetKeepAliveHandler(
975 ExtensionsHandler
* aExtensionsHandler
) {
976 MOZ_ASSERT(!mExtensionsHandler
);
977 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
979 worker
->AssertIsOnWorkerThread();
980 mExtensionsHandler
= aExtensionsHandler
;
981 mExtensionsHandler
->SetExtendableEvent(this);
984 void ExtendableEvent::WaitUntil(JSContext
* aCx
, Promise
& aPromise
,
986 MOZ_ASSERT(!NS_IsMainThread());
988 if (!WaitOnPromise(aPromise
)) {
989 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
993 // Append our handler to each waitUntil promise separately so we
994 // can record the location in script where waitUntil was called.
995 RefPtr
<WaitUntilHandler
> handler
=
996 new WaitUntilHandler(GetCurrentThreadWorkerPrivate(), aCx
);
997 aPromise
.AppendNativeHandler(handler
);
1000 NS_IMPL_ADDREF_INHERITED(ExtendableEvent
, Event
)
1001 NS_IMPL_RELEASE_INHERITED(ExtendableEvent
, Event
)
1003 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtendableEvent
)
1004 NS_INTERFACE_MAP_END_INHERITING(Event
)
1007 nsresult
ExtractBytesFromUSVString(const nsAString
& aStr
,
1008 nsTArray
<uint8_t>& aBytes
) {
1009 MOZ_ASSERT(aBytes
.IsEmpty());
1010 auto encoder
= UTF_8_ENCODING
->NewEncoder();
1011 CheckedInt
<size_t> needed
=
1012 encoder
->MaxBufferLengthFromUTF16WithoutReplacement(aStr
.Length());
1013 if (NS_WARN_IF(!needed
.isValid() ||
1014 !aBytes
.SetLength(needed
.value(), fallible
))) {
1015 return NS_ERROR_OUT_OF_MEMORY
;
1020 // Do not use structured binding lest deal with [-Werror=unused-variable]
1021 std::tie(result
, read
, written
) =
1022 encoder
->EncodeFromUTF16WithoutReplacement(aStr
, aBytes
, true);
1023 MOZ_ASSERT(result
== kInputEmpty
);
1024 MOZ_ASSERT(read
== aStr
.Length());
1025 aBytes
.TruncateLength(written
);
1029 nsresult
ExtractBytesFromData(
1030 const OwningArrayBufferViewOrArrayBufferOrUSVString
& aDataInit
,
1031 nsTArray
<uint8_t>& aBytes
) {
1032 MOZ_ASSERT(aBytes
.IsEmpty());
1033 Maybe
<bool> result
= AppendTypedArrayDataTo(aDataInit
, aBytes
);
1034 if (result
.isSome()) {
1035 return NS_WARN_IF(!result
.value()) ? NS_ERROR_OUT_OF_MEMORY
: NS_OK
;
1037 if (aDataInit
.IsUSVString()) {
1038 return ExtractBytesFromUSVString(aDataInit
.GetAsUSVString(), aBytes
);
1040 MOZ_ASSERT_UNREACHABLE("Unexpected push message data");
1041 return NS_ERROR_FAILURE
;
1045 PushMessageData::PushMessageData(nsIGlobalObject
* aOwner
,
1046 nsTArray
<uint8_t>&& aBytes
)
1047 : mOwner(aOwner
), mBytes(std::move(aBytes
)) {}
1049 PushMessageData::~PushMessageData() = default;
1051 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushMessageData
, mOwner
)
1053 NS_IMPL_CYCLE_COLLECTING_ADDREF(PushMessageData
)
1054 NS_IMPL_CYCLE_COLLECTING_RELEASE(PushMessageData
)
1056 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushMessageData
)
1057 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1058 NS_INTERFACE_MAP_ENTRY(nsISupports
)
1059 NS_INTERFACE_MAP_END
1061 JSObject
* PushMessageData::WrapObject(JSContext
* aCx
,
1062 JS::Handle
<JSObject
*> aGivenProto
) {
1063 return mozilla::dom::PushMessageData_Binding::Wrap(aCx
, this, aGivenProto
);
1066 void PushMessageData::Json(JSContext
* cx
, JS::MutableHandle
<JS::Value
> aRetval
,
1068 if (NS_FAILED(EnsureDecodedText())) {
1069 aRv
.Throw(NS_ERROR_DOM_UNKNOWN_ERR
);
1072 BodyUtil::ConsumeJson(cx
, aRetval
, mDecodedText
, aRv
);
1075 void PushMessageData::Text(nsAString
& aData
) {
1076 if (NS_SUCCEEDED(EnsureDecodedText())) {
1077 aData
= mDecodedText
;
1081 void PushMessageData::ArrayBuffer(JSContext
* cx
,
1082 JS::MutableHandle
<JSObject
*> aRetval
,
1084 uint8_t* data
= GetContentsCopy();
1086 UniquePtr
<uint8_t[], JS::FreePolicy
> dataPtr(data
);
1087 BodyUtil::ConsumeArrayBuffer(cx
, aRetval
, mBytes
.Length(),
1088 std::move(dataPtr
), aRv
);
1092 already_AddRefed
<mozilla::dom::Blob
> PushMessageData::Blob(ErrorResult
& aRv
) {
1093 uint8_t* data
= GetContentsCopy();
1095 RefPtr
<mozilla::dom::Blob
> blob
=
1096 BodyUtil::ConsumeBlob(mOwner
, u
""_ns
, mBytes
.Length(), data
, aRv
);
1098 return blob
.forget();
1104 nsresult
PushMessageData::EnsureDecodedText() {
1105 if (mBytes
.IsEmpty() || !mDecodedText
.IsEmpty()) {
1108 nsresult rv
= BodyUtil::ConsumeText(
1109 mBytes
.Length(), reinterpret_cast<uint8_t*>(mBytes
.Elements()),
1111 if (NS_WARN_IF(NS_FAILED(rv
))) {
1112 mDecodedText
.Truncate();
1118 uint8_t* PushMessageData::GetContentsCopy() {
1119 uint32_t length
= mBytes
.Length();
1120 void* data
= malloc(length
);
1124 memcpy(data
, mBytes
.Elements(), length
);
1125 return reinterpret_cast<uint8_t*>(data
);
1128 PushEvent::PushEvent(EventTarget
* aOwner
) : ExtendableEvent(aOwner
) {}
1130 already_AddRefed
<PushEvent
> PushEvent::Constructor(
1131 mozilla::dom::EventTarget
* aOwner
, const nsAString
& aType
,
1132 const PushEventInit
& aOptions
, ErrorResult
& aRv
) {
1133 RefPtr
<PushEvent
> e
= new PushEvent(aOwner
);
1134 bool trusted
= e
->Init(aOwner
);
1135 e
->InitEvent(aType
, aOptions
.mBubbles
, aOptions
.mCancelable
);
1136 e
->SetTrusted(trusted
);
1137 e
->SetComposed(aOptions
.mComposed
);
1138 if (aOptions
.mData
.WasPassed()) {
1139 nsTArray
<uint8_t> bytes
;
1140 nsresult rv
= ExtractBytesFromData(aOptions
.mData
.Value(), bytes
);
1141 if (NS_FAILED(rv
)) {
1145 e
->mData
= new PushMessageData(aOwner
->GetOwnerGlobal(), std::move(bytes
));
1150 NS_IMPL_ADDREF_INHERITED(PushEvent
, ExtendableEvent
)
1151 NS_IMPL_RELEASE_INHERITED(PushEvent
, ExtendableEvent
)
1153 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushEvent
)
1154 NS_INTERFACE_MAP_END_INHERITING(ExtendableEvent
)
1156 NS_IMPL_CYCLE_COLLECTION_INHERITED(PushEvent
, ExtendableEvent
, mData
)
1158 JSObject
* PushEvent::WrapObjectInternal(JSContext
* aCx
,
1159 JS::Handle
<JSObject
*> aGivenProto
) {
1160 return mozilla::dom::PushEvent_Binding::Wrap(aCx
, this, aGivenProto
);
1163 ExtendableMessageEvent::ExtendableMessageEvent(EventTarget
* aOwner
)
1164 : ExtendableEvent(aOwner
), mData(JS::UndefinedValue()) {
1165 mozilla::HoldJSObjects(this);
1168 ExtendableMessageEvent::~ExtendableMessageEvent() { DropJSObjects(this); }
1170 void ExtendableMessageEvent::GetData(JSContext
* aCx
,
1171 JS::MutableHandle
<JS::Value
> aData
,
1174 if (!JS_WrapValue(aCx
, aData
)) {
1175 aRv
.Throw(NS_ERROR_FAILURE
);
1179 void ExtendableMessageEvent::GetSource(
1180 Nullable
<OwningClientOrServiceWorkerOrMessagePort
>& aValue
) const {
1182 aValue
.SetValue().SetAsClient() = mClient
;
1183 } else if (mServiceWorker
) {
1184 aValue
.SetValue().SetAsServiceWorker() = mServiceWorker
;
1185 } else if (mMessagePort
) {
1186 aValue
.SetValue().SetAsMessagePort() = mMessagePort
;
1188 // nullptr source is possible for manually constructed event
1194 already_AddRefed
<ExtendableMessageEvent
> ExtendableMessageEvent::Constructor(
1195 const GlobalObject
& aGlobal
, const nsAString
& aType
,
1196 const ExtendableMessageEventInit
& aOptions
) {
1197 nsCOMPtr
<EventTarget
> t
= do_QueryInterface(aGlobal
.GetAsSupports());
1198 return Constructor(t
, aType
, aOptions
);
1202 already_AddRefed
<ExtendableMessageEvent
> ExtendableMessageEvent::Constructor(
1203 mozilla::dom::EventTarget
* aEventTarget
, const nsAString
& aType
,
1204 const ExtendableMessageEventInit
& aOptions
) {
1205 RefPtr
<ExtendableMessageEvent
> event
=
1206 new ExtendableMessageEvent(aEventTarget
);
1208 event
->InitEvent(aType
, aOptions
.mBubbles
, aOptions
.mCancelable
);
1209 bool trusted
= event
->Init(aEventTarget
);
1210 event
->SetTrusted(trusted
);
1212 event
->mData
= aOptions
.mData
;
1213 event
->mOrigin
= aOptions
.mOrigin
;
1214 event
->mLastEventId
= aOptions
.mLastEventId
;
1216 if (!aOptions
.mSource
.IsNull()) {
1217 if (aOptions
.mSource
.Value().IsClient()) {
1218 event
->mClient
= aOptions
.mSource
.Value().GetAsClient();
1219 } else if (aOptions
.mSource
.Value().IsServiceWorker()) {
1220 event
->mServiceWorker
= aOptions
.mSource
.Value().GetAsServiceWorker();
1221 } else if (aOptions
.mSource
.Value().IsMessagePort()) {
1222 event
->mMessagePort
= aOptions
.mSource
.Value().GetAsMessagePort();
1226 event
->mPorts
.AppendElements(aOptions
.mPorts
);
1227 return event
.forget();
1230 void ExtendableMessageEvent::GetPorts(nsTArray
<RefPtr
<MessagePort
>>& aPorts
) {
1231 aPorts
= mPorts
.Clone();
1234 NS_IMPL_CYCLE_COLLECTION_CLASS(ExtendableMessageEvent
)
1236 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1237 tmp
->mData
.setUndefined();
1238 NS_IMPL_CYCLE_COLLECTION_UNLINK(mClient
)
1239 NS_IMPL_CYCLE_COLLECTION_UNLINK(mServiceWorker
)
1240 NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagePort
)
1241 NS_IMPL_CYCLE_COLLECTION_UNLINK(mPorts
)
1242 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1244 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1245 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClient
)
1246 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorker
)
1247 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessagePort
)
1248 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPorts
)
1249 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1251 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ExtendableMessageEvent
, Event
)
1252 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mData
)
1253 NS_IMPL_CYCLE_COLLECTION_TRACE_END
1255 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ExtendableMessageEvent
)
1256 NS_INTERFACE_MAP_END_INHERITING(Event
)
1258 NS_IMPL_ADDREF_INHERITED(ExtendableMessageEvent
, Event
)
1259 NS_IMPL_RELEASE_INHERITED(ExtendableMessageEvent
, Event
)
1261 } // namespace mozilla::dom