tor-browser

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

network.sys.mjs (5757B)


      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 import { WindowGlobalBiDiModule } from "chrome://remote/content/webdriver-bidi/modules/WindowGlobalBiDiModule.sys.mjs";
      6 
      7 const lazy = {};
      8 
      9 ChromeUtils.defineESModuleGetters(lazy, {
     10  BeforeStopRequestListener:
     11    "chrome://remote/content/shared/listeners/BeforeStopRequestListener.sys.mjs",
     12  CachedResourceListener:
     13    "chrome://remote/content/shared/listeners/CachedResourceListener.sys.mjs",
     14  DataChannelListener:
     15    "chrome://remote/content/shared/listeners/DataChannelListener.sys.mjs",
     16  NetworkRequest: "chrome://remote/content/shared/NetworkRequest.sys.mjs",
     17  NetworkResponse: "chrome://remote/content/shared/NetworkResponse.sys.mjs",
     18 });
     19 
     20 class NetworkModule extends WindowGlobalBiDiModule {
     21  #beforeStopRequestListener;
     22  #cachedResourceListener;
     23  #dataChannelListener;
     24  #subscribedEvents;
     25 
     26  constructor(messageHandler) {
     27    super(messageHandler);
     28 
     29    this.#beforeStopRequestListener = new lazy.BeforeStopRequestListener(
     30      this.messageHandler.context
     31    );
     32    this.#beforeStopRequestListener.on(
     33      "beforeStopRequest",
     34      this.#onBeforeStopRequest
     35    );
     36 
     37    this.#cachedResourceListener = new lazy.CachedResourceListener(
     38      this.messageHandler.context
     39    );
     40    this.#cachedResourceListener.on(
     41      "cached-resource-sent",
     42      this.#onCachedResourceSent
     43    );
     44 
     45    this.#dataChannelListener = new lazy.DataChannelListener(
     46      this.messageHandler.context
     47    );
     48    this.#dataChannelListener.on(
     49      "data-channel-opened",
     50      this.#onDataChannelOpened
     51    );
     52 
     53    // Set of event names which have active subscriptions.
     54    this.#subscribedEvents = new Set();
     55  }
     56 
     57  destroy() {
     58    this.#beforeStopRequestListener.destroy();
     59    this.#cachedResourceListener.destroy();
     60    this.#dataChannelListener.destroy();
     61    this.#subscribedEvents = null;
     62  }
     63 
     64  #emitWindowGlobalNetworkResource(channel, request, response) {
     65    this.messageHandler.emitEvent("network._windowGlobalNetworkResource", {
     66      channelId: channel.channelId,
     67      context: this.messageHandler.context,
     68      request: request.toJSON(),
     69      response: response.toJSON(),
     70    });
     71  }
     72 
     73  #onBeforeStopRequest = (event, data) => {
     74    this.messageHandler.emitEvent("network._beforeStopRequest", {
     75      channelId: data.channel.channelId,
     76      contextId: this.messageHandler.contextId,
     77      decodedBodySize: data.decodedBodySize,
     78    });
     79  };
     80 
     81  #onCachedResourceSent = (event, data) => {
     82    const request = new lazy.NetworkRequest(data.channel, {
     83      eventRecord: this,
     84      navigationManager: null,
     85    });
     86    const response = new lazy.NetworkResponse(data.channel, {
     87      fromCache: true,
     88      fromServiceWorker: false,
     89      isCachedResource: true,
     90    });
     91 
     92    this.#emitWindowGlobalNetworkResource(data.channel, request, response);
     93  };
     94 
     95  #onDataChannelOpened = (event, data) => {
     96    const request = new lazy.NetworkRequest(data.channel, {
     97      eventRecord: this,
     98      navigationManager: null,
     99    });
    100    const response = new lazy.NetworkResponse(data.channel, {
    101      fromCache: false,
    102      fromServiceWorker: false,
    103      isCachedResource: false,
    104    });
    105 
    106    this.#emitWindowGlobalNetworkResource(data.channel, request, response);
    107  };
    108 
    109  #startListening() {
    110    if (this.#subscribedEvents.size == 0) {
    111      this.#beforeStopRequestListener.startListening();
    112      this.#cachedResourceListener.startListening();
    113      this.#dataChannelListener.startListening();
    114    }
    115  }
    116 
    117  #stopListening() {
    118    if (this.#subscribedEvents.size == 0) {
    119      this.#beforeStopRequestListener.stopListening();
    120      this.#cachedResourceListener.stopListening();
    121      this.#dataChannelListener.stopListening();
    122    }
    123  }
    124 
    125  #subscribeEvent(event) {
    126    switch (event) {
    127      case "network.beforeRequestSent":
    128        this.#startListening();
    129        this.#subscribedEvents.add("network.beforeRequestSent");
    130        break;
    131      case "network.responseStarted":
    132        this.#startListening();
    133        this.#subscribedEvents.add("network.responseStarted");
    134        break;
    135      case "network.responseCompleted":
    136        this.#startListening();
    137        this.#subscribedEvents.add("network.responseCompleted");
    138        break;
    139    }
    140  }
    141 
    142  #unsubscribeEvent(event) {
    143    switch (event) {
    144      case "network.beforeRequestSent":
    145        this.#subscribedEvents.delete("network.beforeRequestSent");
    146        break;
    147      case "network.responseStarted":
    148        this.#subscribedEvents.delete("network.responseStarted");
    149        break;
    150      case "network.responseCompleted":
    151        this.#subscribedEvents.delete("network.responseCompleted");
    152        break;
    153    }
    154 
    155    this.#stopListening();
    156  }
    157 
    158  /**
    159   * Internal commands
    160   */
    161 
    162  _applySessionData(params) {
    163    // TODO: Bug 1775231. Move this logic to a shared module or an abstract
    164    // class.
    165    const { category } = params;
    166    if (category === "event") {
    167      const filteredSessionData = params.sessionData.filter(item =>
    168        this.messageHandler.matchesContext(item.contextDescriptor)
    169      );
    170      for (const event of this.#subscribedEvents.values()) {
    171        const hasSessionItem = filteredSessionData.some(
    172          item => item.value === event
    173        );
    174        // If there are no session items for this context, we should unsubscribe from the event.
    175        if (!hasSessionItem) {
    176          this.#unsubscribeEvent(event);
    177        }
    178      }
    179 
    180      // Subscribe to all events, which have an item in SessionData.
    181      for (const { value } of filteredSessionData) {
    182        this.#subscribeEvent(value);
    183      }
    184    }
    185  }
    186 }
    187 
    188 export const network = NetworkModule;