Search code examples
firefoxfirefox-addonfirefox-addon-sdk

Identify http request / response by id


I am building an extension with Firefox's ADD ON SDK (v1.9) that will be able to read all HTTP requests / responses and calculate the time they took to load. This includes not only the main frame but any other loading file (sub frame, script, css, image, etc.).

So far, I am able to use the "observer-service" module to listen for:

  • "http-on-modify-request" when a HTTP request is created.
  • "http-on-examine-response" when a HTTP response is received
  • "http-on-examine-cached-response" when a HTTP response is received entirely from cache
  • "http-on-examine-merged-response" when a HTTP response is received partially from cache

My application follows the following sequence:

  1. A request is created and registered through the observer.
  2. I save the current time and mark it as start_time of the request load.
  3. A response for a request is received and registered through one of the observers.
  4. I save the current time and use the previously saved time to calculate load time of the request.

Problem: I am not able to link the start and end times of the load since I cannot find a request ID (or other unique value) that will tie the request with the response. I am currently using the URL of the request / response to tie them together but this is not correct since it will raise a "race condition" if two or more equal urls are loading at the same time. Google Chrome solves this issue by providing unique requestIds, but I have not been able to find a similar functionality on Firefox.


Solution

  • I am aware of two ways to recognize a channel that you receive in this observer. The "old" solution is to use nsIWritablePropertyBag interface to attach data to the channel:

    var {Ci} = require("chrome");
    var channelId = 0;
    
    ...
    
    // Attach channel ID to a channel
    if (channel instanceof Ci.nsIWritablePropertyBag)
      channel.setProperty("myExtension-channelId", ++channelId);
    
    ...
    
    // Read out channel ID for a channel
    if (channel instanceof Ci.nsIPropertyBag)
      console.log(channel.getProperty("myExtension-channelId"));
    

    The other solution would be using WeakMap API (only works properly starting with Firefox 13):

    var channelMap = new WeakMap();
    var channelId = 0;
    
    ...
    
    // Attach channel ID to a channel
    channelMap.set(channel, ++channelId);
    
    ...
    
    // Read out channel ID for a channel
    console.log(channelMap.get(channel));
    

    I'm not sure whether WeakMap is available in the context of Add-on SDK modules, you might have to "steal" it from a regular JavaScript module:

    var {Cu} = require("chrome");
    var {WeakMap} = Cu.import("resource://gre/modules/FileUtils.jsm", null);
    

    Obviously, in both cases you can attach more data to the channel than a simple number.