summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/network-monitor/channel-event-sink.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/network-monitor/channel-event-sink.js')
-rw-r--r--devtools/server/actors/network-monitor/channel-event-sink.js99
1 files changed, 99 insertions, 0 deletions
diff --git a/devtools/server/actors/network-monitor/channel-event-sink.js b/devtools/server/actors/network-monitor/channel-event-sink.js
new file mode 100644
index 0000000000..8ff00302f9
--- /dev/null
+++ b/devtools/server/actors/network-monitor/channel-event-sink.js
@@ -0,0 +1,99 @@
+/* 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/. */
+
+"use strict";
+
+const { ComponentUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/ComponentUtils.sys.mjs"
+);
+
+/**
+ * This is a nsIChannelEventSink implementation that monitors channel redirects and
+ * informs the registered "collectors" about the old and new channels.
+ */
+const SINK_CLASS_DESCRIPTION = "NetworkMonitor Channel Event Sink";
+const SINK_CLASS_ID = Components.ID("{e89fa076-c845-48a8-8c45-2604729eba1d}");
+const SINK_CONTRACT_ID = "@mozilla.org/network/monitor/channeleventsink;1";
+const SINK_CATEGORY_NAME = "net-channel-event-sinks";
+
+class ChannelEventSink {
+ constructor() {
+ this.wrappedJSObject = this;
+ this.collectors = new Set();
+ }
+
+ QueryInterface = ChromeUtils.generateQI(["nsIChannelEventSink"]);
+
+ registerCollector(collector) {
+ this.collectors.add(collector);
+ }
+
+ unregisterCollector(collector) {
+ this.collectors.delete(collector);
+
+ if (this.collectors.size == 0) {
+ ChannelEventSinkFactory.unregister();
+ }
+ }
+
+ // eslint-disable-next-line no-shadow
+ asyncOnChannelRedirect(oldChannel, newChannel, flags, callback) {
+ for (const collector of this.collectors) {
+ try {
+ collector.onChannelRedirect(oldChannel, newChannel, flags);
+ } catch (ex) {
+ console.error(
+ "ChannelEventSink collector's 'onChannelRedirect' threw an exception",
+ ex
+ );
+ }
+ }
+ callback.onRedirectVerifyCallback(Cr.NS_OK);
+ }
+}
+
+const ChannelEventSinkFactory =
+ ComponentUtils.generateSingletonFactory(ChannelEventSink);
+
+ChannelEventSinkFactory.register = function () {
+ const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ if (registrar.isCIDRegistered(SINK_CLASS_ID)) {
+ return;
+ }
+
+ registrar.registerFactory(
+ SINK_CLASS_ID,
+ SINK_CLASS_DESCRIPTION,
+ SINK_CONTRACT_ID,
+ ChannelEventSinkFactory
+ );
+
+ Services.catMan.addCategoryEntry(
+ SINK_CATEGORY_NAME,
+ SINK_CONTRACT_ID,
+ SINK_CONTRACT_ID,
+ false,
+ true
+ );
+};
+
+ChannelEventSinkFactory.unregister = function () {
+ const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+ registrar.unregisterFactory(SINK_CLASS_ID, ChannelEventSinkFactory);
+
+ Services.catMan.deleteCategoryEntry(
+ SINK_CATEGORY_NAME,
+ SINK_CONTRACT_ID,
+ false
+ );
+};
+
+ChannelEventSinkFactory.getService = function () {
+ // Make sure the ChannelEventSink service is registered before accessing it
+ ChannelEventSinkFactory.register();
+
+ return Cc[SINK_CONTRACT_ID].getService(Ci.nsIChannelEventSink)
+ .wrappedJSObject;
+};
+exports.ChannelEventSinkFactory = ChannelEventSinkFactory;