Создайте Дополнение Firefox, чтобы Наблюдать и изменить запросы XHR и reponses

Обновление: Я предполагаю, что предмет дал неправильное понятие, что я ищу существующее дополнение. Это - пользовательская проблема, и я НЕ хочу существующего решения.
Я хочу ЗАПИСАТЬ (или более соответственно, изменить и существующий) Дополнение.

Вот мое требование:

  • Я хочу, чтобы мое дополнение работало на конкретный сайт только
  • Данные на страницах кодируются с помощью 2 путей хеш
  • Много информации загружается запросами XHR и иногда отображается в анимированных пузырях и т.д.
  • Текущая версия моего дополнения анализирует страницу через выражения XPath, декодирует данные и заменяет их

  • Проблема входит с теми bubblified полями, которые отображены на событии mouseOver

  • Таким образом я понял, что это могла бы быть хорошая идея создать мост XHR, который мог слушать все данные и декодировать/кодировать на лету
  • После нескольких поисков я столкнулся с nsITraceableInterface[1][2][3]

Просто требуемый, чтобы знать, нахожусь ли я на корректном пути. Если "да", то любезно обеспечивают любые дополнительные указатели и предложения, которые могут быть соответствующими; и если "Нет", то.. хорошо, помогите с корректными указателями :)

Спасибо,
Bipin.

[1]. https://developer.mozilla.org/en/NsITraceableChannel
[2]. http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
[3]. http://www.ashita.org/howto-xhr-listening-by-a-firefox-addon/

6
задан Jumper 25 August 2011 в 11:43
поделиться

3 ответа

nsITraceableChannel - это действительно путь сюда. Посты в блоге Яна Одварко (softwareishard.com) и меня (ashita.org) показывают, как это сделать. Вы также можете захотеть посмотреть http://www.ashita.org/implementing-an-xpcom-firefox-interface-and-creating-observers/, но на самом деле это не обязательно делать в XPCOM компоненте.

Шагами в основном являются:

  1. Создание объектного прототипа, реализующего nsITraceableChannel; и создание наблюдателя для прослушивания http-on-modify-запроса и http-on-exame-ответа
  2. регистрация наблюдателя
  3. регистрация наблюдателя, прослушивающего два типа запроса, добавляет наш объект nsITraceableChannel в цепочку слушателей и удостовериться, что наш объект nsITC знает, кто следующий в цепочке
  4. nsITC обеспечивает три обратных вызова, и каждый из них будет вызван на соответствующем этапе: onStartRequest, onDataAvailable и onStopRequest
  5. in each of the callback above, наш объект nsITC должен передать данные следующему элементу цепочки

Ниже приведен реальный код из написанного мною дополнения для конкретного сайта, который ведет себя очень похоже на ваш, из того, что я могу сказать.

function TracingListener() {
    //this.receivedData = [];
}

TracingListener.prototype =
{
    originalListener: null,
    receivedData: null,   // array for incoming data.

    onDataAvailable: function(request, context, inputStream, offset, count)
    {
        var binaryInputStream = CCIN("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
        var storageStream = CCIN("@mozilla.org/storagestream;1", "nsIStorageStream");
        binaryInputStream.setInputStream(inputStream);
        storageStream.init(8192, count, null);

        var binaryOutputStream = CCIN("@mozilla.org/binaryoutputstream;1",
                "nsIBinaryOutputStream");

        binaryOutputStream.setOutputStream(storageStream.getOutputStream(0));

        // Copy received data as they come.
        var data = binaryInputStream.readBytes(count);
        //var data = inputStream.readBytes(count);

        this.receivedData.push(data);

        binaryOutputStream.writeBytes(data, count);
        this.originalListener.onDataAvailable(request, context,storageStream.newInputStream(0), offset, count);
    },

    onStartRequest: function(request, context) {
        this.receivedData = [];
        this.originalListener.onStartRequest(request, context);
    },

    onStopRequest: function(request, context, statusCode)
    {
        try 
        {
            request.QueryInterface(Ci.nsIHttpChannel);

            if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) 
            {

                var data = null;
                if (request.requestMethod.toLowerCase() == "post") 
                {
                    var postText = this.readPostTextFromRequest(request, context);
                    if (postText) 
                        data = ((String)(postText)).parseQuery();

                }
                var date = Date.parse(request.getResponseHeader("Date"));
                var responseSource = this.receivedData.join('');

                //fix leading spaces bug
                responseSource = responseSource.replace(/^\s+(\S[\s\S]+)/, "$1");

                piratequesting.ProcessRawResponse(request.originalURI.spec, responseSource, date, data);
            }
        } 
        catch (e) 
        {
            dumpError(e);
        }
        this.originalListener.onStopRequest(request, context, statusCode);
    },

    QueryInterface: function (aIID) {
        if (aIID.equals(Ci.nsIStreamListener) ||
            aIID.equals(Ci.nsISupports)) {
            return this;
        }
        throw Components.results.NS_NOINTERFACE;
    },
    readPostTextFromRequest : function(request, context) {
        try
        {
            var is = request.QueryInterface(Ci.nsIUploadChannel).uploadStream;
            if (is)
            {
                var ss = is.QueryInterface(Ci.nsISeekableStream);
                var prevOffset;
                if (ss)
                {
                    prevOffset = ss.tell();
                    ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
                }

                // Read data from the stream..
                var charset = "UTF-8";
                var text = this.readFromStream(is, charset, true);

                // Seek locks the file so, seek to the beginning only if necko hasn't read it yet,
                // since necko doesn't seek to 0 before reading (at lest not till 459384 is fixed).
                if (ss && prevOffset == 0) 
                    ss.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);

                return text;
            }
            else {
                dump("Failed to Query Interface for upload stream.\n");
            }
        }
        catch(exc)
        {
            dumpError(exc);
        }

        return null;
    },
    readFromStream : function(stream, charset, noClose) {

        var sis = CCSV("@mozilla.org/binaryinputstream;1", "nsIBinaryInputStream");
        sis.setInputStream(stream);

        var segments = [];
        for (var count = stream.available(); count; count = stream.available())
            segments.push(sis.readBytes(count));

        if (!noClose)
            sis.close();

        var text = segments.join("");
        return text;
    }

}


hRO = {

    observe: function(request, aTopic, aData){
        try {
            if (typeof Cc == "undefined") {
                var Cc = Components.classes;
            }
            if (typeof Ci == "undefined") {
                var Ci = Components.interfaces;
            }
            if (aTopic == "http-on-examine-response") {
                request.QueryInterface(Ci.nsIHttpChannel);

                if (request.originalURI && piratequesting.baseURL == request.originalURI.prePath && request.originalURI.path.indexOf("/index.php?ajax=") == 0) {
                    var newListener = new TracingListener();
                    request.QueryInterface(Ci.nsITraceableChannel);
                    newListener.originalListener = request.setNewListener(newListener);
                }
            } 
        } catch (e) {
            dump("\nhRO error: \n\tMessage: " + e.message + "\n\tFile: " + e.fileName + "  line: " + e.lineNumber + "\n");
        }
    },

    QueryInterface: function(aIID){
        if (typeof Cc == "undefined") {
            var Cc = Components.classes;
        }
        if (typeof Ci == "undefined") {
            var Ci = Components.interfaces;
        }
        if (aIID.equals(Ci.nsIObserver) ||
        aIID.equals(Ci.nsISupports)) {
            return this;
        }

        throw Components.results.NS_NOINTERFACE;

    },
};


var observerService = Cc["@mozilla.org/observer-service;1"]
    .getService(Ci.nsIObserverService);

observerService.addObserver(hRO,
    "http-on-examine-response", false);

В приведенном выше коде, originalListener - это слушатель, которого мы вставляем раньше в цепочку. Очень важно, чтобы вы сохраняли эту информацию при создании Tracing Listener и передавали данные во всех трех обратных вызовах. В противном случае ничего не будет работать (страницы даже не загружаются. Сам Firefox последний в цепочке).

Замечание: в коде выше есть некоторые функции, которые являются частью пиратской надстройки, например: parseQuery() и dumpError()

8
ответ дан 16 December 2019 в 21:39
поделиться
0
ответ дан 16 December 2019 в 21:39
поделиться

Вы можете попробовать сделать сценарий Greasemonkey и перезаписывать XMLHTTPREQUEST.
Код будет выглядеть что-то вроде:

function request () {
};
request.prototype.open = function (type, path, block) {
 GM_xmlhttpRequest({
  method: type,
  url: path,
  onload: function (response) {
   // some code here
  }
 });
};
unsafeWindow.XMLHttpRequest = request;

также обратите внимание, что вы можете превратить GM Script в аддона для Firefox

0
ответ дан 16 December 2019 в 21:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: