Я пытаюсь разработать расширение Firefox, которое отбрасывает каждый HTTP-запрос на определенный сайт и возвращает поддельный ответ. Ни один запрос не должен проходить к исходному веб-серверу, но я хочу иметь возможность создать собственный ответ. Я попытался перехватить сообщение «http-on-modify-request», но отмена запроса, похоже, не работает, так как впоследствии я не могу смоделировать реальный ответ. Точно так же, используя экземпляр nsITraceableStream, я не могу действительно отменить запрос. У меня нет идей, может кто-нибудь помочь?
Расширение Firefox: отменяйте запросы и отправляйте поддельные ответы
Ответы (1)
Ответ ниже был заменен с Firefox 21, теперь метод nsIHttpChannel.redirectTo() прекрасно справляется со своей задачей. Вы можете перенаправить на data: URI, что-то вроде этого будет работать:
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));
}
}
Исходный ответ (устаревший)
С каждым каналом связан прослушиватель потока, который получает уведомление при получении данных. Все, что вам нужно сделать, чтобы подделать ответ, — это получить этот слушатель и передать ему неправильные данные. И nsITraceableChannel на самом деле является способом сделать это. Вам нужно заменить обычный слушатель канала на свой, который ничего не сделает, после этого вы можете закрыть канал, не уведомляя об этом слушателя. Затем вы запускаете прослушиватель и передаете ему свои данные. Что-то вроде этого:
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.org/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.com/", 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.org/show_bug.cgi?id=646370.
// Do it asynchronously instead.
var threadManager = Cc["@mozilla.org/thread-manager;1"]
.getService(Ci.nsIThreadManager);
threadManager.currentThread.dispatch(fakeListener, Ci.nsIEventTarget.DISPATCH_NORMAL);
}
}
Проблема с этим кодом по-прежнему заключается в том, что страница отображается пустой, если канал отменен (поэтому я прокомментировал эту строку) - кажется, что слушатель все еще смотрит на канал и замечает, что он отменен.
oldListener.onStartRequest(channel, oldContext);
Я попробую FiFo 3.5 сейчас, чтобы быть уверенным. На самом деле я использовал очень похожий подход с нулевым прослушивателем, но в onExamineResponse, где я, похоже, не смог отменить запрос и установить какие-либо заголовки ответа.
- person Niklas B.; 29.08.2011
oldContext
не был установлен в этот момент, поэтому вы вызываете его с неправильным контекстом - я предполагаю, что канал отменяется асинхронно, что означает, что onStopRequest
вызывается слишком поздно. Перемещение всего кода, имитирующего запрос (onStartRequest
и Ко.), в onStopRequest
вашего поддельного слушателя, должно исправить это.
- person Wladimir Palant; 29.08.2011
alert("Registering fake listener...")
. Редактировать: поддельный прослушиватель даже не вызывается, когда я не отменяю запрос.
- person Niklas B.; 29.08.2011
alert()
в сетевом коде - плохая идея и может не работать по какой-то причине (он создает модальный диалог). Вы должны использовать Components.utils.reportError()
или window.dump()
, которые дают более надежные результаты.
- person Wladimir Palant; 29.08.2011
Components.utils.reportError()
с теми же результатами. Кажется, что setNewListener
вообще не будет иметь никакого эффекта... возможно ли, что это работает только в ответ на http-on-examine-response
? Весь пример кода, который я видел до сих пор, включающий setNewListener
, на самом деле вызывает его в onExamineResponse
.
- person Niklas B.; 29.08.2011
TRACE
, который не влияет на серверную сторону Затем я могу манипулировать телом ответа в onExmineResponse
, но кажется, что я не могу вызвать setResponseHeader
(выдает NS_ERROR_ILLEGAL_VALUE
)
- person Niklas B.; 29.08.2011
channel.contentType
.
- person Niklas B.; 29.08.2011
Content-Type
, вероятно, потому, что на данный момент он уже есть в канале. Однако можно установить и другие заголовки.
- person Wladimir Palant; 29.08.2011
setResponseHeader
, например, с "Set-Cookie"
или "Refresh"
не вызывает исключения, но Firefox, похоже, не учитывает заголовки, установленные таким образом. Он не обновляется и не устанавливает куки, по крайней мере, для меня. Если это для вас, можете ли вы сказать мне, какую версию Firefox вы используете? Я использую 6.0 на Linux x86_64. Редактировать: Я также очень хочу поблагодарить вас за время, которое вы потратили на эту проблему!
- person Niklas B.; 29.08.2011
Refresh
в Firefox 9.0a1, он работает (однако эта версия Firefox блокирует перенаправление). Возможно, вы захотите изменить третий параметр с setResponseHeader
(aMerge
) на true
, это определенно необходимо, если присутствуют другие заголовки файлов cookie.
- person Wladimir Palant; 29.08.2011
Set-Cookie
(или попробовать другие настройки этого кода).
- person Wladimir Palant; 29.08.2011
onStartRequest
. Что касается ошибки 646370 - я не думаю, что это проблема. , обходной путь работает просто отлично.
- person Wladimir Palant; 29.08.2011
onStopRequest()
— это замыкание, определенное внутри функции onModifyRequest()
, совершенно нормально использовать переменную channel
из внешней функции (она даже требуется для метода run()
). Но может у вас другая установка.
- person Wladimir Palant; 29.08.2011
onStartRequest
.
- person Niklas B.; 29.08.2011
onStopRequest
не был таким же, как тот, к которому вы привязали своего слушателя. Я должен отредактировать свой код, чтобы учесть этот случай.
- person Wladimir Palant; 29.08.2011