channel-event-sink.js (2858B)
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 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { ComponentUtils } = ChromeUtils.importESModule( 8 "resource://gre/modules/ComponentUtils.sys.mjs", 9 { global: "contextual" } 10 ); 11 12 /** 13 * THIS is a nsIChannelEventSink implementation that monitors channel redirects and 14 * informs the registered "collectors" about the old and new channels. 15 */ 16 const SINK_CLASS_DESCRIPTION = "NetworkMonitor Channel Event Sink"; 17 const SINK_CLASS_ID = Components.ID("{e89fa076-c845-48a8-8c45-2604729eba1d}"); 18 const SINK_CONTRACT_ID = "@mozilla.org/network/monitor/channeleventsink;1"; 19 const SINK_CATEGORY_NAME = "net-channel-event-sinks"; 20 21 class ChannelEventSink { 22 constructor() { 23 this.wrappedJSObject = this; 24 this.collectors = new Set(); 25 } 26 27 QueryInterface = ChromeUtils.generateQI(["nsIChannelEventSink"]); 28 29 registerCollector(collector) { 30 this.collectors.add(collector); 31 } 32 33 unregisterCollector(collector) { 34 this.collectors.delete(collector); 35 36 if (this.collectors.size == 0) { 37 ChannelEventSinkFactory.unregister(); 38 } 39 } 40 41 // eslint-disable-next-line no-shadow 42 asyncOnChannelRedirect(oldChannel, newChannel, flags, callback) { 43 for (const collector of this.collectors) { 44 try { 45 collector.onChannelRedirect(oldChannel, newChannel, flags); 46 } catch (ex) { 47 console.error( 48 "ChannelEventSink collector's 'onChannelRedirect' threw an exception", 49 ex 50 ); 51 } 52 } 53 callback.onRedirectVerifyCallback(Cr.NS_OK); 54 } 55 } 56 57 const ChannelEventSinkFactory = 58 ComponentUtils.generateSingletonFactory(ChannelEventSink); 59 60 ChannelEventSinkFactory.register = function () { 61 const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); 62 if (registrar.isCIDRegistered(SINK_CLASS_ID)) { 63 return; 64 } 65 66 registrar.registerFactory( 67 SINK_CLASS_ID, 68 SINK_CLASS_DESCRIPTION, 69 SINK_CONTRACT_ID, 70 ChannelEventSinkFactory 71 ); 72 73 Services.catMan.addCategoryEntry( 74 SINK_CATEGORY_NAME, 75 SINK_CONTRACT_ID, 76 SINK_CONTRACT_ID, 77 false, 78 true 79 ); 80 }; 81 82 ChannelEventSinkFactory.unregister = function () { 83 const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); 84 registrar.unregisterFactory(SINK_CLASS_ID, ChannelEventSinkFactory); 85 86 Services.catMan.deleteCategoryEntry( 87 SINK_CATEGORY_NAME, 88 SINK_CONTRACT_ID, 89 false 90 ); 91 }; 92 93 ChannelEventSinkFactory.getService = function () { 94 // Make sure the ChannelEventSink service is registered before accessing it 95 ChannelEventSinkFactory.register(); 96 97 return Cc[SINK_CONTRACT_ID].getService(Ci.nsIChannelEventSink) 98 .wrappedJSObject; 99 }; 100 exports.ChannelEventSinkFactory = ChannelEventSinkFactory;