admin管理员组

文章数量:1327823

I am trying to develop a Firefox extension that drops every HTTP request to a certain site and returns a fake response. No request should get through to the original web server, but I want to be able to create a custom response. I tried to intercept the "http-on-modify-request" message, but cancelling the request doesn't seem to work, as I cannot simulate a real response afterwards. Similarly, using an nsITraceableStream instance, I don't seem to be able to really cancel the request. I am out of ideas, can somebody help?

I am trying to develop a Firefox extension that drops every HTTP request to a certain site and returns a fake response. No request should get through to the original web server, but I want to be able to create a custom response. I tried to intercept the "http-on-modify-request" message, but cancelling the request doesn't seem to work, as I cannot simulate a real response afterwards. Similarly, using an nsITraceableStream instance, I don't seem to be able to really cancel the request. I am out of ideas, can somebody help?

Share Improve this question edited Aug 15, 2014 at 22:21 Niklas B. asked Aug 28, 2011 at 17:25 Niklas B.Niklas B. 95.4k18 gold badges199 silver badges226 bronze badges 7
  • What is this extension supposed to be used for? – Amir Raminfar Commented Aug 28, 2011 at 17:31
  • Maybe you want to have a look how LeechBlock blocks the requests: addons.mozilla/en-US/firefox/addon/leechblock – Felix Kling Commented Aug 28, 2011 at 17:52
  • @Felix: I know how to block requests, but if I do it the usual way (reacting to the "http-on-modify-request" message), I can not fake a response. – Niklas B. Commented Aug 28, 2011 at 18:24
  • @Amir: We (an IT security pany I work for) want to use it for demonstration purposes to show how easy it is to manipulate SSL-secured connections when you have access to the client side (browser). – Niklas B. Commented Aug 28, 2011 at 18:37
  • 1 @Niklas: Why not just use the Fiddler (www.fiddler2.) AutoResponder to do this? You can then do your demo in ALL browsers. – EricLaw Commented Aug 29, 2011 at 0:13
 |  Show 2 more ments

1 Answer 1

Reset to default 9

The answer below has been superseded as of Firefox 21, now the nsIHttpChannel.redirectTo() method does the job nicely. You can redirect to a data: URI, something like this will work:

Components.utils.import("resource://gre/modules/Services.jsm");
const Ci = Components.interfaces;

[...]

onModifyRequest: function(channel)
{
  if (channel instanceof Ci.nsIHttpChannel && shouldRedirect(channel.URI.spec))
  {
    let redirectURL = "data:text/html," + encodeURIComponent("<html>Hi there!</html>");
    channel.redirectTo(Services.io.newURI(redirectURI, null, null));
  }
}

Original answer (outdated)

Each channel has its associated stream listener that gets notified when data is received. All you need to do to fake a response is to get this listener and feed it with wrong data. And nsITraceableChannel is in fact the way to do it. You need to replace the channel's usual listener by your own that won't do anything, after that you can cancel the channel without the listener being notified about it. And then you trigger the listener and give it your own data. Something like this:

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const Cc = Components.classes;
const Ci = Components.interfaces;

[...]

onModifyRequest: function(channel)
{
  if (channel instanceof Ci.nsIHttpChannel && channel instanceof Ci.nsITraceableChannel)
  {
    // Our own listener for the channel
    var fakeListener = {
      QueryInterface: XPCOMUtils.generateQI([Ci.nsIStreamListener,
                        Ci.nsIRequestObserver, Ci.nsIRunnable]),
      oldListener: null,
      run: function()
      {
        // Replace old listener by our fake listener
        this.oldListener = channel.setNewListener(this);

        // Now we can cancel the channel, listener old won't notice
        //channel.cancel(Components.results.NS_BINDING_ABORTED);
      },
      onDataAvailable: function(){},
      onStartRequest: function(){},
      onStopRequest: function(request, context, status)
      {
        // Call old listener with our data and set "response" headers
        var stream = Cc["@mozilla/io/string-input-stream;1"]
                       .createInstance(Ci.nsIStringInputStream);
        stream.setData("<html>Hi there!</html>", -1);
        this.oldListener.onStartRequest(channel, context);
        channel.setResponseHeader("Refresh", "5; url=http://google./", false);
        this.oldListener.onDataAvailable(channel, context, stream, 0, stream.available());
        this.oldListener.onStopRequest(channel, context, Components.results.NS_OK);
      }
    }

    // We cannot replace the listener right now, see
    // https://bugzilla.mozilla/show_bug.cgi?id=646370.
    // Do it asynchronously instead.
    var threadManager = Cc["@mozilla/thread-manager;1"]
                          .getService(Ci.nsIThreadManager);
    threadManager.currentThread.dispatch(fakeListener, Ci.nsIEventTarget.DISPATCH_NORMAL);
  }
}

The problem with this code is still that the page shows up blank if the channel is canceled (so I mented that line) - it seems that the listener still looks at the channel and notices that it is canceled.

本文标签: javascriptFirefox extension Cancel requests and emit fake responsesStack Overflow