tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c5fef7ff2b99bd5b0d3d45ecdccfda55392e5249
parent c02551c18397b5ffdff734590188b1e5c7c35963
Author: Freya LaLuna <freyalaluna@outlook.com>
Date:   Sat,  3 Jan 2026 20:00:41 +0000

Bug 1955682 - C++ platform implementation of generate_test_report command r=webidl,smaug

This is the platform implementation for the WebDriver extension command outlined in Part 7.1 of the Reporting API spec: https://w3c.github.io/reporting/#generate-test-report-command
This command simulates the generation of a report for the purpose of testing, which is observed by any registered Reporting Observers and sent off to a specified endpoint.

Differential Revision: https://phabricator.services.mozilla.com/D250373

Diffstat:
Mdom/base/nsIGlobalObject.cpp | 1+
Mdom/reporting/CSPViolationReportBody.cpp | 4++--
Adom/reporting/TestReportBody.cpp | 36++++++++++++++++++++++++++++++++++++
Adom/reporting/TestReportBody.h | 36++++++++++++++++++++++++++++++++++++
Adom/reporting/TestReportGenerator.cpp | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adom/reporting/TestReportGenerator.h | 24++++++++++++++++++++++++
Mdom/reporting/moz.build | 4++++
Mdom/reporting/tests/browser.toml | 2++
Adom/reporting/tests/browser_reportGeneration.js | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdom/webidl/Reporting.webidl | 20++++++++++++++++++++
10 files changed, 247 insertions(+), 2 deletions(-)

diff --git a/dom/base/nsIGlobalObject.cpp b/dom/base/nsIGlobalObject.cpp @@ -11,6 +11,7 @@ #include "mozilla/GlobalFreezeObserver.h" #include "mozilla/GlobalTeardownObserver.h" #include "mozilla/Result.h" +#include "mozilla/StaticPrefs_dom.h" #include "mozilla/StorageAccess.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/BlobURLProtocolHandler.h" diff --git a/dom/reporting/CSPViolationReportBody.cpp b/dom/reporting/CSPViolationReportBody.cpp @@ -35,11 +35,11 @@ JSObject* CSPViolationReportBody::WrapObject( } void CSPViolationReportBody::GetBlockedURL(nsAString& aURL) const { - aURL = mDocumentURL; + aURL = mBlockedURL; } void CSPViolationReportBody::GetDocumentURL(nsAString& aURL) const { - aURL = mBlockedURL; + aURL = mDocumentURL; } void CSPViolationReportBody::GetReferrer(nsAString& aReferrer) const { diff --git a/dom/reporting/TestReportBody.cpp b/dom/reporting/TestReportBody.cpp @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TestReportBody.h" + +#include "mozilla/JSONWriter.h" +#include "mozilla/dom/ReportingBinding.h" + +namespace mozilla::dom { + +TestReportBody::TestReportBody(nsIGlobalObject* aGlobal, + const nsString& aMessage) + : ReportBody(aGlobal), mMessage(aMessage) {} + +JSObject* TestReportBody::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return TestReportBody_Binding::Wrap(aCx, this, aGivenProto); +} + +TestReportBody::~TestReportBody() = default; + +void TestReportBody::GetMessage(nsAString& aMessage) const { + aMessage = mMessage; +} + +void TestReportBody::ToJSON(JSONWriter& aJSONWriter) const { + if (mMessage.IsEmpty()) { + aJSONWriter.NullProperty("message"); + } else { + aJSONWriter.StringProperty("message", NS_ConvertUTF16toUTF8(mMessage)); + } +} +} // namespace mozilla::dom diff --git a/dom/reporting/TestReportBody.h b/dom/reporting/TestReportBody.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_TestReportBody_h +#define mozilla_dom_TestReportBody_h + +#include "mozilla/dom/Nullable.h" +#include "mozilla/dom/ReportBody.h" +#include "mozilla/dom/SecurityPolicyViolationEvent.h" + +namespace mozilla::dom { + +class TestReportBody final : public ReportBody { + public: + TestReportBody(nsIGlobalObject* aGlobal, const nsString& aBody); + + JSObject* WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) override; + + void GetMessage(nsAString& aMessage) const; + + protected: + void ToJSON(JSONWriter& aJSONWriter) const override; + + private: + ~TestReportBody(); + + const nsString mMessage; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_TestReportBody_h diff --git a/dom/reporting/TestReportGenerator.cpp b/dom/reporting/TestReportGenerator.cpp @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/dom/TestReportGenerator.h" + +#include "mozilla/dom/ReportingBinding.h" +#include "mozilla/dom/ReportingUtils.h" +#include "mozilla/dom/TestReportBody.h" + +namespace mozilla::dom { + +/* static */ +already_AddRefed<Promise> TestReportGenerator::GenerateReport( + const GlobalObject& aGlobal, const GenerateTestReportParameters& aParams, + ErrorResult& aRv) { + nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); + MOZ_ASSERT(global); + + RefPtr<Promise> promise = Promise::Create(global, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + MOZ_ASSERT(promise); + + nsString messageBody = aParams.mMessage; + if (messageBody.IsEmpty()) { + promise->MaybeRejectWithNotSupportedError( + "Report must have a message string"); + return promise.forget(); + } + + nsString reportGroup = aParams.mGroup; + + nsPIDOMWindowInner* window = global->GetAsInnerWindow(); + if (NS_WARN_IF(!window)) { + promise->MaybeRejectWithNotSupportedError( + "Failed to convert global object to window"); + return promise.forget(); + } + + RefPtr<TestReportBody> reportBody = new TestReportBody(global, messageBody); + + nsCOMPtr<nsIURI> docURI = window->GetDocumentURI(); + nsAutoCString spec; + if (!docURI || NS_FAILED(docURI->GetSpec(spec))) { + promise->MaybeRejectWithNotSupportedError( + "Failed to retrieve active document's URI from window"); + return promise.forget(); + } + + NS_ConvertUTF8toUTF16 docURIString(spec); + + ReportingUtils::Report(global, nsGkAtoms::test, reportGroup, docURIString, + reportBody); + + AutoJSAPI jsapi; + if (!jsapi.Init(global)) { + promise->MaybeRejectWithNotSupportedError( + "Failed to initialize JS context"); + return promise.forget(); + } + + promise->MaybeResolveWithUndefined(); + return promise.forget(); +} + +} // namespace mozilla::dom diff --git a/dom/reporting/TestReportGenerator.h b/dom/reporting/TestReportGenerator.h @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_TestReportGenerator_h +#define mozilla_dom_TestReportGenerator_h + +#include "mozilla/dom/Promise.h" + +namespace mozilla::dom { + +struct GenerateTestReportParameters; + +class TestReportGenerator { + public: + static already_AddRefed<Promise> GenerateReport( + const GlobalObject& aGlobal, const GenerateTestReportParameters& aParams, + ErrorResult& aRv); +}; +} // namespace mozilla::dom + +#endif // mozilla_dom_TestReportGenerator_h diff --git a/dom/reporting/moz.build b/dom/reporting/moz.build @@ -18,6 +18,8 @@ EXPORTS.mozilla.dom = [ "ReportingObserver.h", "ReportingUtils.h", "TestingDeprecatedInterface.h", + "TestReportBody.h", + "TestReportGenerator.h", ] UNIFIED_SOURCES += [ @@ -34,6 +36,8 @@ UNIFIED_SOURCES += [ "ReportingObserver.cpp", "ReportingUtils.cpp", "TestingDeprecatedInterface.cpp", + "TestReportBody.cpp", + "TestReportGenerator.cpp", ] IPDL_SOURCES += [ diff --git a/dom/reporting/tests/browser.toml b/dom/reporting/tests/browser.toml @@ -5,3 +5,5 @@ support-files = [ ] ["browser_cleanup.js"] + +["browser_reportGeneration.js"] diff --git a/dom/reporting/tests/browser_reportGeneration.js b/dom/reporting/tests/browser_reportGeneration.js @@ -0,0 +1,52 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.reporting.enabled", true], + ["dom.reporting.header.enabled", true], + ["dom.reporting.testing.enabled", true], + ], + }); +}); + +add_task(async function () { + let o = new ReportingObserver(() => {}); + o.observe(); + + await window.TestReportGenerator.generateReport({ + message: "test", + group: "test", + }); + + let r = o.takeRecords(); + is(r.length, 1, "Report delivery was observed"); + is(r[0].body.message, "test", "Message is correct"); + + await window.TestReportGenerator.generateReport({ message: "test" }); + + r = o.takeRecords(); + is(r.length, 1, "Report delivery was observed when no group was provided"); + + await Assert.rejects( + window.TestReportGenerator.generateReport(), + /TypeError/, + "generateReport emits a TypeError when message isn't provided" + ); +}); + +// test serialization of message as null property +add_task(async function () { + let o = new ReportingObserver(() => {}); + o.observe(); + + await window.TestReportGenerator.generateReport({ + message: null, + group: "test", + }); + + let r = o.takeRecords(); + is(r.length, 1, "Report delivery was observed"); + is(r[0].body.message, "null", "Message is correct"); +}); diff --git a/dom/webidl/Reporting.webidl b/dom/webidl/Reporting.webidl @@ -7,6 +7,8 @@ * https://w3c.github.io/reporting/#interface-reporting-observer */ +interface nsISupports; + [Pref="dom.reporting.enabled", Exposed=(Window,Worker)] interface ReportBody { @@ -112,3 +114,21 @@ dictionary ReportingEndpoint { // This is an unsigned long. any weight; }; + +dictionary GenerateTestReportParameters +{ + required DOMString message; + DOMString group = "default"; +}; + +[ChromeOnly, Pref="dom.reporting.enabled", Exposed=Window] +namespace TestReportGenerator { + [Throws] + Promise<undefined> generateReport(GenerateTestReportParameters params); +}; + +[LegacyNoInterfaceObject, Exposed=Window] +interface TestReportBody : ReportBody { + [Default] object toJSON(); + readonly attribute DOMString message; +};