/* 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/. */ const lazy = {}; ChromeUtils.defineESModuleGetters(lazy, { EventEmitter: "resource://gre/modules/EventEmitter.sys.mjs", NetworkUtils: "resource://devtools/shared/network-observer/NetworkUtils.sys.mjs", }); const OBSERVER_TOPIC_BEFORE_STOP_REQUEST = "http-on-before-stop-request"; /** * The BeforeStopRequestListener can be used to listen for * http-on-before-stop-request notifications emitted right before a network * channel is stopped. At this point the response should be completely decoded * and the channel decodedBodySize property should have the expected value. * This notification needs to be monitored in content processes, because * decodedBodySize is always set to 0 in the parent process. * * Example: * ``` * const listener = new BeforeStopRequestListener(); * listener.on("beforeStopRequest", onBeforeStopRequest); * listener.startListening(); * * const onBeforeStopRequest = (eventName, data = {}) => { * const { channel, decodedBodySize } = data; * ... * }; * ``` * * @fires message * The BeforeStopRequestListener emits "beforeStopRequest" events with the * following object as payload: * - {nsIHttpChannel} channel * The channel for which the observer notification was emitted. * - {number} decodedBodySize * The decoded body size for the channel. */ export class BeforeStopRequestListener { #context; #listening; /** * Create a new BeforeStopRequestListener instance. * * @param {BrowsingContext} context * The browsing context to filter the events for. */ constructor(context) { lazy.EventEmitter.decorate(this); this.#context = context; this.#listening = false; } destroy() { this.stopListening(); } observe(subject, topic) { switch (topic) { case OBSERVER_TOPIC_BEFORE_STOP_REQUEST: { const channel = subject.QueryInterface(Ci.nsIHttpChannel); const id = lazy.NetworkUtils.getChannelBrowsingContextID(channel); // Send the event only if the notification comes for the observed // context. if (id === this.#context.id) { this.emit("beforeStopRequest", { channel, decodedBodySize: channel.decodedBodySize, }); } break; } } } startListening() { if (this.#listening) { return; } Services.obs.addObserver(this, OBSERVER_TOPIC_BEFORE_STOP_REQUEST); this.#listening = true; } stopListening() { if (!this.#listening) { return; } Services.obs.removeObserver(this, OBSERVER_TOPIC_BEFORE_STOP_REQUEST); this.#listening = false; } }