Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/reporting/./../../../dom/reporting/ReportDeliver.cpp
Warning:line 180, column 12
Value stored to 'rv' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_dom_reporting0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/reporting -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/reporting -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/dom/reporting -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dom/reporting -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_dom_reporting0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "mozilla/dom/ReportDeliver.h"
6
7#include <algorithm>
8
9#include "mozilla/JSONStringWriteFuncs.h"
10#include "mozilla/StaticPrefs_dom.h"
11#include "mozilla/dom/Document.h"
12#include "mozilla/dom/Fetch.h"
13#include "mozilla/dom/Navigator.h"
14#include "mozilla/dom/Promise.h"
15#include "mozilla/dom/ReportBody.h"
16#include "mozilla/dom/Request.h"
17#include "mozilla/dom/RequestBinding.h"
18#include "mozilla/dom/Response.h"
19#include "mozilla/dom/RootedDictionary.h"
20#include "mozilla/ipc/BackgroundChild.h"
21#include "mozilla/ipc/PBackgroundChild.h"
22#include "mozilla/ipc/PBackgroundSharedTypes.h"
23#include "nsGlobalWindowInner.h"
24#include "nsIGlobalObject.h"
25#include "nsIXPConnect.h"
26#include "nsNetUtil.h"
27#include "nsStringStream.h"
28
29namespace mozilla::dom {
30
31namespace {
32
33StaticRefPtr<ReportDeliver> gReportDeliver;
34
35// This is the same value as the default value of
36// dom.min_timeout_value, so it's not that random.
37constexpr double gMinReportAgeInMs = 4.0;
38
39class ReportFetchHandler final : public PromiseNativeHandler {
40 public:
41 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
42
43 explicit ReportFetchHandler(
44 const nsTArray<ReportDeliver::ReportData>& aReportData)
45 : mReports(aReportData.Clone()) {}
46
47 void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
48 ErrorResult& aRv) override {
49 if (!gReportDeliver) {
50 return;
51 }
52
53 if (NS_WARN_IF(!aValue.isObject())NS_warn_if_impl(!aValue.isObject(), "!aValue.isObject()", "./../../../dom/reporting/ReportDeliver.cpp"
, 53)
) {
54 return;
55 }
56
57 JS::Rooted<JSObject*> obj(aCx, &aValue.toObject());
58 MOZ_ASSERT(obj)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(obj)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(obj))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("obj", "./../../../dom/reporting/ReportDeliver.cpp"
, 58); AnnotateMozCrashReason("MOZ_ASSERT" "(" "obj" ")"); do
{ MOZ_CrashSequence(__null, 58); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
59
60 {
61 Response* response = nullptr;
62 if (NS_WARN_IF(NS_FAILED(UNWRAP_OBJECT(Response, &obj, response)))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(mozilla
::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts<
mozilla::dom::prototypes::id::Response, mozilla::dom::Response_Binding
::NativeType>(&obj, response))), 0))), "NS_FAILED(UNWRAP_OBJECT(Response, &obj, response))"
, "./../../../dom/reporting/ReportDeliver.cpp", 62)
) {
63 return;
64 }
65
66 if (response->Status() == 410) {
67 if (XRE_IsContentProcess()) {
68 for (const auto& report : mReports) {
69 gReportDeliver->EndpointRespondedWithRemove(report.mGlobalKey,
70 report.mGroupName);
71 }
72 } else {
73 // Crash Reports will end up here, because they're not sent from with
74 // a content process. The endpoints used for crash reporting and NEL
75 // are parsed using the ReportingHeader::ReportingFromChannel, since
76 // these two variants of Reporting API strictly should run in the
77 // parent process
78 for (const auto& report : mReports) {
79 ReportingHeader::RemoveEndpoint(
80 report.mGroupName, report.mEndpointURL, report.mPrincipal);
81 }
82 }
83 }
84 }
85 }
86
87 void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
88 ErrorResult& aRv) override {
89 if (gReportDeliver) {
90 for (auto& report : mReports) {
91 ++report.mFailures;
92 gReportDeliver->EnqueueReport(report);
93 }
94 }
95 }
96
97 private:
98 ~ReportFetchHandler() = default;
99
100 nsTArray<ReportDeliver::ReportData> mReports;
101};
102
103NS_IMPL_ISUPPORTS0(ReportFetchHandler)MozExternalRefCountType ReportFetchHandler::AddRef(void) { static_assert
(!std::is_destructible_v<ReportFetchHandler>, "Reference-counted class "
"ReportFetchHandler" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 103
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ReportFetchHandler" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("ReportFetchHandler" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"ReportFetchHandler\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/reporting/ReportDeliver.cpp", 103); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"ReportFetchHandler\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 103); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("ReportFetchHandler"
" not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef
((this), (count), ("ReportFetchHandler"), (uint32_t)(sizeof(*
this))); return count; } MozExternalRefCountType ReportFetchHandler
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 103); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 103
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ReportFetchHandler" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("ReportFetchHandler" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"ReportFetchHandler\" != nullptr" " (" "Must specify a name"
")", "./../../../dom/reporting/ReportDeliver.cpp", 103); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"ReportFetchHandler\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 103); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("ReportFetchHandler"
" not thread-safe"); const char* const nametmp = "ReportFetchHandler"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult ReportFetchHandler::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/reporting/ReportDeliver.cpp"
, 103); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<ReportFetchHandler, nsISupports>, int32_t
( reinterpret_cast<char*>(static_cast<nsISupports*>
((ReportFetchHandler*)0x1000)) - reinterpret_cast<char*>
((ReportFetchHandler*)0x1000))}, { nullptr, 0 } } ; static_assert
(std::size(table) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
104
105class ReportJSONWriter final : public JSONWriter {
106 public:
107 explicit ReportJSONWriter(JSONStringWriteFunc<nsAutoCString>& aOutput)
108 : JSONWriter(aOutput) {}
109
110 void JSONProperty(const Span<const char>& aProperty,
111 const Span<const char>& aJSON) {
112 Separator();
113 PropertyNameAndColon(aProperty);
114 mWriter.Write(aJSON);
115 }
116};
117
118void SendReports(nsTArray<ReportDeliver::ReportData>& aReports,
119 const nsCString& aEndPointUrl, nsIPrincipal* aPrincipal) {
120 if (NS_WARN_IF(aReports.IsEmpty())NS_warn_if_impl(aReports.IsEmpty(), "aReports.IsEmpty()", "./../../../dom/reporting/ReportDeliver.cpp"
, 120)
) {
121 return;
122 }
123
124 nsIXPConnect* xpc = nsContentUtils::XPConnect();
125 MOZ_ASSERT(xpc, "This should never be null!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(xpc)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(xpc))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("xpc" " (" "This should never be null!"
")", "./../../../dom/reporting/ReportDeliver.cpp", 125); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "xpc" ") (" "This should never be null!" ")"
); do { MOZ_CrashSequence(__null, 125); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
126
127 nsCOMPtr<nsIGlobalObject> globalObject;
128 {
129 AutoJSAPI jsapi;
130 jsapi.Init();
131
132 JSContext* cx = jsapi.cx();
133 JS::Rooted<JSObject*> sandbox(cx);
134 nsresult rv = xpc->CreateSandbox(cx, aPrincipal, sandbox.address());
135 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/reporting/ReportDeliver.cpp"
, 135)
) {
136 return;
137 }
138
139 // The JSContext is not in a realm, so CreateSandbox returned an unwrapped
140 // global.
141 MOZ_ASSERT(JS_IsGlobalObject(sandbox))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(JS_IsGlobalObject(sandbox))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(JS_IsGlobalObject(sandbox)))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("JS_IsGlobalObject(sandbox)"
, "./../../../dom/reporting/ReportDeliver.cpp", 141); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "JS_IsGlobalObject(sandbox)" ")"); do { MOZ_CrashSequence
(__null, 141); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
142
143 globalObject = xpc::NativeGlobal(sandbox);
144 }
145
146 if (NS_WARN_IF(!globalObject)NS_warn_if_impl(!globalObject, "!globalObject", "./../../../dom/reporting/ReportDeliver.cpp"
, 146)
) {
147 return;
148 }
149
150 // The body
151 JSONStringWriteFunc<nsAutoCString> body;
152 ReportJSONWriter w(body);
153
154 uint64_t associatedBrowsingContextId = aReports[0].mAssociatedBrowsingContext;
155
156 w.StartArrayElement();
157 for (const auto& report : aReports) {
158 MOZ_ASSERT(report.mPrincipal == aPrincipal)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(report.mPrincipal == aPrincipal)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(report.mPrincipal == aPrincipal
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"report.mPrincipal == aPrincipal", "./../../../dom/reporting/ReportDeliver.cpp"
, 158); AnnotateMozCrashReason("MOZ_ASSERT" "(" "report.mPrincipal == aPrincipal"
")"); do { MOZ_CrashSequence(__null, 158); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
159 MOZ_ASSERT(report.mEndpointURL == aEndPointUrl)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(report.mEndpointURL == aEndPointUrl)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(report.mEndpointURL == aEndPointUrl
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"report.mEndpointURL == aEndPointUrl", "./../../../dom/reporting/ReportDeliver.cpp"
, 159); AnnotateMozCrashReason("MOZ_ASSERT" "(" "report.mEndpointURL == aEndPointUrl"
")"); do { MOZ_CrashSequence(__null, 159); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
160 w.StartObjectElement();
161 // It looks like in rare cases, TimeStamp::Now() may be the same
162 // as report.mCreationTime, so we introduce a constant number to
163 // make sure "age" is always not 0.
164 w.IntProperty(
165 "age",
166 std::max((TimeStamp::Now() - report.mCreationTime).ToMilliseconds(),
167 gMinReportAgeInMs));
168 w.StringProperty("type", NS_ConvertUTF16toUTF8(report.mType));
169 w.StringProperty("url", NS_ConvertUTF16toUTF8(report.mURL));
170 w.StringProperty("user_agent", NS_ConvertUTF16toUTF8(report.mUserAgent));
171 w.JSONProperty(MakeStringSpan("body"),
172 Span<const char>(report.mReportBodyJSON.Data(),
173 report.mReportBodyJSON.Length()));
174 w.EndObject();
175 }
176 w.EndArray();
177
178 // The body as stream
179 nsCOMPtr<nsIInputStream> streamBody;
180 nsresult rv =
Value stored to 'rv' during its initialization is never read
181 NS_NewCStringInputStream(getter_AddRefs(streamBody), body.StringCRef());
182
183 // Headers
184 IgnoredErrorResult error;
185 RefPtr<InternalHeaders> internalHeaders =
186 new InternalHeaders(HeadersGuardEnum::Request);
187 internalHeaders->Set("Content-Type"_ns, "application/reports+json"_ns, error);
188 if (NS_WARN_IF(error.Failed())NS_warn_if_impl(error.Failed(), "error.Failed()", "./../../../dom/reporting/ReportDeliver.cpp"
, 188)
) {
189 return;
190 }
191
192 // URL and fragments
193 nsCOMPtr<nsIURI> uri;
194 rv = NS_NewURI(getter_AddRefs(uri), aEndPointUrl);
195 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/reporting/ReportDeliver.cpp"
, 195)
) {
196 return;
197 }
198
199 nsCOMPtr<nsIURI> uriClone;
200 rv = NS_GetURIWithoutRef(uri, getter_AddRefs(uriClone));
201 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/reporting/ReportDeliver.cpp"
, 201)
) {
202 return;
203 }
204
205 nsAutoCString uriFragment;
206 rv = uri->GetRef(uriFragment);
207 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../dom/reporting/ReportDeliver.cpp"
, 207)
) {
208 return;
209 }
210
211 auto internalRequest =
212 MakeSafeRefPtr<InternalRequest>(WrapNotNull(uriClone.get()), uriFragment);
213
214 internalRequest->SetMethod("POST"_ns);
215 internalRequest->SetBody(streamBody, body.StringCRef().Length());
216 internalRequest->SetHeaders(internalHeaders);
217 internalRequest->SetSkipServiceWorker();
218 // TODO: internalRequest->SetContentPolicyType(TYPE_REPORT);
219 internalRequest->SetMode(RequestMode::Cors);
220 internalRequest->SetCredentialsMode(RequestCredentials::Same_origin);
221 internalRequest->SetUnsafeRequest();
222
223 if (aReports[0].mCookieJarSettings) {
224 internalRequest->SetCookieJarSettings(aReports[0].mCookieJarSettings);
225 }
226 internalRequest->SetAssociatedBrowsingContextID(associatedBrowsingContextId);
227
228 RefPtr<Request> request =
229 new Request(globalObject, std::move(internalRequest), nullptr);
230
231 RequestOrUTF8String fetchInput;
232 fetchInput.SetAsRequest() = request;
233
234 RootedDictionary<RequestInit> requestInit(RootingCx());
235 RefPtr<Promise> promise = FetchRequest(globalObject, fetchInput, requestInit,
236 CallerType::NonSystem, error);
237 if (error.Failed()) {
238 if (gReportDeliver) {
239 for (auto& report : aReports) {
240 ++report.mFailures;
241 gReportDeliver->EnqueueReport(report);
242 }
243 }
244 return;
245 }
246
247 RefPtr<ReportFetchHandler> handler = new ReportFetchHandler(aReports);
248 promise->AppendNativeHandler(handler);
249}
250
251} // namespace
252
253/* static */
254void ReportDeliver::AttemptDelivery(nsIGlobalObject* aGlobal,
255 const nsAString& aType,
256 const nsAString& aGroupName,
257 const nsAString& aURL, ReportBody* aBody,
258 uint64_t aAssociatedBrowsingContextId) {
259 MOZ_ASSERT(aGlobal && aBody)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGlobal && aBody)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGlobal && aBody))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("aGlobal && aBody"
, "./../../../dom/reporting/ReportDeliver.cpp", 259); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "aGlobal && aBody" ")"); do { MOZ_CrashSequence
(__null, 259); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
260
261 if (NS_WARN_IF(!gReportDeliver)NS_warn_if_impl(!gReportDeliver, "!gReportDeliver", "./../../../dom/reporting/ReportDeliver.cpp"
, 261)
) {
262 return;
263 }
264
265 nsCOMPtr<nsIPrincipal> principal = aGlobal->PrincipalOrNull();
266 if (NS_WARN_IF(!principal)NS_warn_if_impl(!principal, "!principal", "./../../../dom/reporting/ReportDeliver.cpp"
, 266)
) {
267 return;
268 }
269
270 // We have to serialize aBody here because the thread we're sending
271 // this to, sometimes isn't not the owner, which doesn't work for RefPtr.
272 JSONStringWriteFunc<nsAutoCString> reportBodyJSON;
273 ReportJSONWriter w(reportBodyJSON);
274
275 w.Start();
276 aBody->ToJSON(w);
277 w.End();
278
279 RefPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
280 "ReportDeliver::AttemptDelivery",
281 [aGlobalKey = reinterpret_cast<uintptr_t>(aGlobal),
282 type = nsString{aType}, group = nsString{aGroupName},
283 reportUrl = nsString{aURL},
284 reportBody = std::move(reportBodyJSON).StringRRef(), principal,
285 browsingContextId = aAssociatedBrowsingContextId]() mutable {
286 ReportData data;
287
288 // https://w3c.github.io/reporting/#report-delivery
289 // 2.1 If there exists an endpoint (endpoint) in context’s endpoints
290 // list whose name is report’s destination:
291 // 2.1.1 Append report to
292 // endpoint map’s list of reports for endpoint.
293 nsIURI* endpointURI =
294 gReportDeliver->GetEndpointURLFor(aGlobalKey, group);
295 if (!endpointURI) {
296 return;
297 }
298 endpointURI->GetSpec(data.mEndpointURL);
299
300 data.mType = std::move(type);
301 data.mGroupName = std::move(group);
302 data.mURL = std::move(reportUrl);
303 data.mCreationTime = TimeStamp::Now();
304 data.mReportBodyJSON = std::move(reportBody);
305 data.mPrincipal = std::move(principal);
306 data.mFailures = 0;
307 data.mAssociatedBrowsingContext = browsingContextId;
308 gReportDeliver->SetGlobalAndUserAgentData(data, aGlobalKey);
309 ReportDeliver::Fetch(data);
310 });
311
312 if (!NS_IsMainThread()) {
313 NS_DispatchToMainThread(runnable.forget());
314 } else {
315 runnable->Run();
316 }
317}
318
319void ReportDeliver::SetGlobalAndUserAgentData(
320 ReportDeliver::ReportData& aReportData, uintptr_t aGlobalKey) {
321 // Will be null for workers
322 aReportData.mGlobalKey = aGlobalKey;
323 if (auto reportingGlobal = mGlobalsEndpointLists.Lookup(aGlobalKey)) {
324 aReportData.mUserAgent = reportingGlobal->mUserAgentData;
325 aReportData.mCookieJarSettings = reportingGlobal->mCookieJarSettings;
326 }
327}
328
329void ReportDeliver::ScheduleFetch() {
330 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 330); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 330); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
331 if (mPendingDelivery) {
332 return;
333 }
334
335 mPendingDelivery = true;
336 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
337 "ReportDeliver::CallNotify",
338 [self = RefPtr<ReportDeliver>{gReportDeliver}]() { self->Notify(); });
339
340 NS_DispatchToCurrentThreadQueue(
341 runnable.forget(), StaticPrefs::dom_reporting_delivering_timeout() * 1000,
342 EventQueuePriority::Idle);
343}
344
345void ReportDeliver::EnqueueReport(const ReportData& aReportData) {
346 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 346); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 346); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
347 // If this is failed report, and queue is full, don't remove potentially
348 // non-tried reports, instead discard this one.
349 if ((aReportData.mFailures > 0 &&
350 mReportQueue.Length() >
351 StaticPrefs::dom_reporting_delivering_maxReports()) ||
352 aReportData.mFailures >=
353 StaticPrefs::dom_reporting_delivering_maxFailures()) {
354 return;
355 }
356
357 if (NS_WARN_IF(!mReportQueue.AppendElement(aReportData, fallible))NS_warn_if_impl(!mReportQueue.AppendElement(aReportData, fallible
), "!mReportQueue.AppendElement(aReportData, fallible)", "./../../../dom/reporting/ReportDeliver.cpp"
, 357)
) {
358 return;
359 }
360
361 while (mReportQueue.Length() >
362 StaticPrefs::dom_reporting_delivering_maxReports()) {
363 mReportQueue.RemoveElementAt(0);
364 }
365
366 ScheduleFetch();
367}
368
369void ReportDeliver::Initialize() {
370 if (!gReportDeliver) {
371 RefPtr<ReportDeliver> rd = new ReportDeliver();
372
373 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
374 if (NS_WARN_IF(!obs)NS_warn_if_impl(!obs, "!obs", "./../../../dom/reporting/ReportDeliver.cpp"
, 374)
) {
375 return;
376 }
377
378 obs->AddObserver(rd, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown", false);
379 gReportDeliver = rd;
380 }
381}
382
383/* static */
384void ReportDeliver::WorkerInitializeReportingEndpoints(
385 uintptr_t aGlobalKey, nsIURI* aResourceURI, nsCString aHeaderContents,
386 bool aShouldResistFingerprinting,
387 nsICookieJarSettings* aCookieJarSettings) {
388 MOZ_ASSERT(!NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 388); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "!NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 388); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
389 if (NS_WARN_IF(!aResourceURI)NS_warn_if_impl(!aResourceURI, "!aResourceURI", "./../../../dom/reporting/ReportDeliver.cpp"
, 389)
|| aHeaderContents.IsEmpty() ||
390 aHeaderContents.IsVoid()) {
391 return;
392 }
393
394 NS_DispatchToMainThread(NS_NewRunnableFunction(
395 "ReportDeliver::DispatchInitializeReportingEndpoints",
396 [aGlobalKey, uri = RefPtr{aResourceURI},
397 header = std::move(aHeaderContents), aShouldResistFingerprinting,
398 cookieJarSettings = nsCOMPtr{aCookieJarSettings}]() mutable {
399 EndpointsList list;
400 ReportingHeader::ParseReportingEndpointsHeader(
401 header, uri,
402 [&list](const nsAString& aEndpointName,
403 nsCOMPtr<nsIURI> aEndpointURL) {
404 list.mData.EmplaceBack(ReportingHeader::Endpoint::Create(
405 aEndpointURL.forget(), aEndpointName));
406 });
407
408 nsString userAgent;
409 mozilla::dom::Navigator::GetUserAgent(
410 nullptr, nullptr, Some(aShouldResistFingerprinting), userAgent);
411
412 gReportDeliver->mGlobalsEndpointLists.InsertOrUpdate(
413 aGlobalKey,
414 GlobalReportingData{std::move(userAgent), std::move(list),
415 cookieJarSettings});
416 }));
417}
418
419/** static */
420void ReportDeliver::WindowInitializeReportingEndpoints(
421 nsIGlobalObject* aGlobal, mozilla::dom::EndpointsList aEndpointList) {
422 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 422); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 422); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
423
424 nsString userAgentData;
425 if (aEndpointList.mData.IsEmpty()) {
426 return;
427 }
428
429 nsPIDOMWindowInner* win = aGlobal->GetAsInnerWindow();
430 RefPtr<Document> doc;
431 if (win) {
432 doc = win->GetExtantDoc();
433 }
434
435 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
436 if (doc) {
437 cookieJarSettings = doc->CookieJarSettings();
438 }
439
440 (void)mozilla::dom::Navigator::GetUserAgent(
441 win, doc,
442 mozilla::Some(
443 aGlobal->ShouldResistFingerprinting(RFPTarget::NavigatorUserAgent)),
444 userAgentData);
445 gReportDeliver->mGlobalsEndpointLists.InsertOrUpdate(
446 reinterpret_cast<uintptr_t>(aGlobal),
447 GlobalReportingData{std::move(userAgentData), std::move(aEndpointList),
448 std::move(cookieJarSettings)});
449}
450
451nsIURI* ReportDeliver::GetEndpointURLFor(uintptr_t aGlobalKey,
452 const nsAString& aGroupName) {
453 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 453); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 453); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
454 auto reportingGlobal = mGlobalsEndpointLists.Lookup(aGlobalKey);
455 if (!reportingGlobal) {
456 return nullptr;
457 }
458
459 if (ReportingHeader::Endpoint* endpoint =
460 reportingGlobal->mEndpoints.GetEndpointWithName(aGroupName)) {
461 return endpoint->mUrl;
462 }
463 return nullptr;
464}
465
466void ReportDeliver::EndpointRespondedWithRemove(
467 uint64_t aGlobalKey, const nsAString& aEndpointName) {
468 auto reportingGlobal = mGlobalsEndpointLists.Lookup(aGlobalKey);
469 if (!reportingGlobal) {
470 return;
471 }
472 reportingGlobal->mEndpoints.RemoveEndpoint(aEndpointName);
473}
474
475/* static */
476void ReportDeliver::RemoveGlobalEndpoints(uintptr_t aGlobalKey) {
477 if (NS_IsMainThread()) {
478 if (gReportDeliver) {
479 gReportDeliver->mGlobalsEndpointLists.Remove(aGlobalKey);
480 }
481 } else {
482 NS_DispatchToMainThread(NS_NewRunnableFunction(
483 "ReportDeliver::RemoveGlobalEndpoints", [aGlobalKey]() {
484 if (gReportDeliver) {
485 gReportDeliver->mGlobalsEndpointLists.Remove(aGlobalKey);
486 }
487 }));
488 }
489}
490
491/* static */
492void ReportDeliver::Fetch(const ReportData& aReportData) {
493 if (aReportData.mFailures >
494 StaticPrefs::dom_reporting_delivering_maxFailures()) {
495 return;
496 }
497
498 gReportDeliver->EnqueueReport(aReportData);
499}
500
501void ReportDeliver::Notify() {
502 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../dom/reporting/ReportDeliver.cpp", 502); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 502); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
503 mPendingDelivery = false;
504 nsTArray<ReportData> reports = std::move(mReportQueue);
505 // group reports by endpoint and nsIPrincipal
506 std::map<std::pair<nsCString, nsCOMPtr<nsIPrincipal>>, nsTArray<ReportData>>
507 reportsByPrincipal;
508 for (ReportData& report : reports) {
509 auto already_seen =
510 reportsByPrincipal.find({report.mEndpointURL, report.mPrincipal});
511 if (already_seen == reportsByPrincipal.end()) {
512 reportsByPrincipal.emplace(
513 std::make_pair(report.mEndpointURL, report.mPrincipal),
514 nsTArray<ReportData>({report}));
515 } else {
516 already_seen->second.AppendElement(report);
517 }
518 }
519
520 for (auto& iter : reportsByPrincipal) {
521 std::pair<nsCString, nsCOMPtr<nsIPrincipal>> key = iter.first;
522 nsTArray<ReportData>& value = iter.second;
523 nsCString url = key.first;
524 nsCOMPtr<nsIPrincipal> principal = key.second;
525 nsAutoCString u(url);
526 SendReports(value, url, principal);
527 }
528}
529
530NS_IMETHODIMPnsresult
531ReportDeliver::GetName(nsACString& aName) {
532 aName.AssignLiteral("ReportDeliver");
533 return NS_OK;
534}
535
536NS_IMETHODIMPnsresult
537ReportDeliver::Observe(nsISupports* aSubject, const char* aTopic,
538 const char16_t* aData) {
539 MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!strcmp(aTopic, "xpcom-shutdown"))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!strcmp(aTopic, "xpcom-shutdown"
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!strcmp(aTopic, \"xpcom-shutdown\")", "./../../../dom/reporting/ReportDeliver.cpp"
, 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!strcmp(aTopic, \"xpcom-shutdown\")"
")"); do { MOZ_CrashSequence(__null, 539); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
540
541 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
542 if (NS_WARN_IF(!obs)NS_warn_if_impl(!obs, "!obs", "./../../../dom/reporting/ReportDeliver.cpp"
, 542)
) {
543 return NS_OK;
544 }
545
546 obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID"xpcom-shutdown");
547
548 gReportDeliver = nullptr;
549 return NS_OK;
550}
551
552ReportDeliver::ReportDeliver() = default;
553
554ReportDeliver::~ReportDeliver() = default;
555
556NS_INTERFACE_MAP_BEGIN(ReportDeliver)nsresult ReportDeliver::QueryInterface(const nsIID& aIID,
void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../dom/reporting/ReportDeliver.cpp"
, 556); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface
;
557 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsISupports>)) foundInterface = static_cast
<nsISupports*>(static_cast<nsIObserver*>(this)); else
558 NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsIObserver>)) foundInterface = static_cast
<nsIObserver*>(this); else
559 NS_INTERFACE_MAP_ENTRY(nsINamed)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t
<decltype(*this)>, nsINamed>)) foundInterface = static_cast
<nsINamed*>(this); else
560NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do
{ static_assert( mozilla::detail::AssertionConditionType<
decltype(!aIID.Equals((nsISupports::kIID)))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::kIID
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!aIID.Equals((nsISupports::kIID))", "./../../../dom/reporting/ReportDeliver.cpp"
, 560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::kIID))"
")"); do { MOZ_CrashSequence(__null, 560); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE
; } else { (foundInterface)->AddRef(); status = NS_OK; } *
aInstancePtr = foundInterface; return status; }
561
562NS_IMPL_ADDREF(ReportDeliver)MozExternalRefCountType ReportDeliver::AddRef(void) { static_assert
(!std::is_destructible_v<ReportDeliver>, "Reference-counted class "
"ReportDeliver" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 562); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 562
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ReportDeliver" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("ReportDeliver" != nullptr))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"ReportDeliver\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 562); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ReportDeliver\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 562); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("ReportDeliver" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("ReportDeliver"), (uint32_t)
(sizeof(*this))); return count; }
563NS_IMPL_RELEASE(ReportDeliver)MozExternalRefCountType ReportDeliver::Release(void) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 563); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 563
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("ReportDeliver" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("ReportDeliver" != nullptr))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"ReportDeliver\" != nullptr"
" (" "Must specify a name" ")", "./../../../dom/reporting/ReportDeliver.cpp"
, 563); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"ReportDeliver\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 563); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("ReportDeliver" " not thread-safe"); const char* const nametmp
= "ReportDeliver"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; }
564
565} // namespace mozilla::dom