Запрос перенаправления (nsiHttpChannel?) В расширениях Firefox
Я пробовал это уже давно, и никаких хороших результатов не было.
var myObserver = {
observe: function(subject, topic, data)
{
if (topic == "http-on-examine-response")
{
// implement later
}
else if(topic == "http-on-modify-request")
{
// implement later
}
},
QueryInterface : function (id)
{
if (id.equals(Components.interfaces["nsIObserver"]) ||
id.equals(Components.interfaces["nsISupports"]))
{
return this;
}
throw Components.results.NS_NOINTERFACE;
}
};
var obs = new Service("observer-service", "ObserverService");
obs.addObserver(myObserver, "http-on-modify-request", false);
В принципе, на http-on-modify-request
, я знаю, как исследовать URI, выяснить, какое окно (если есть) связано с ним, и множество других вещей. Я не могу понять, как перенаправить запрос, который, как я знаю, возможен отсюда, потому что я могу получить nsIHttpChannel до того, как любой запрос будет отправлен.
Кто-нибудь знает, что делать?:/Я пробовал пару недель вкл./Выкл., И не получил нигде.
Ответы
Ответ 1
Мы можем сделать это, переопределив nsiHttpChannel
новым, делая это немного сложно, но, к счастью, надстройка https-everywhere
реализует это, чтобы принудительно установить https-соединение.
https-everywhere
доступен исходный код here
Большая часть кода, необходимого для этого, находится в файлах
[IO Util.js
]
[ChannelReplacement.js
]
Мы можем работать только с вышеуказанными файлами, если у нас есть основные переменные, такие как Cc, Ci, и определена функция xpcom_generateQI
.
var httpRequestObserver =
{
observe: function(subject, topic, data) {
if (topic == "http-on-modify-request") {
var httpChannel = subject.QueryInterface(Components.interfaces.nsIHttpChannel);
var requestURL = subject.URI.spec;
if(isToBeReplaced(requestURL)) {
var newURL = getURL(requestURL);
ChannelReplacement.runWhenPending(subject, function() {
var cr = new ChannelReplacement(subject, ch);
cr.replace(true,null);
cr.open();
});
}
}
},
get observerService() {
return Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
},
register: function() {
this.observerService.addObserver(this, "http-on-modify-request", false);
},
unregister: function() {
this.observerService.removeObserver(this, "http-on-modify-request");
}
};
httpRequestObserver.register();
В коде заменить запрос не перенаправляется.
Хотя я достаточно хорошо проверил приведенный выше код, я не уверен в его реализации. Пока я могу разобрать, он копирует все атрибуты запрашиваемого канала и устанавливает их на переопределяемый канал. После чего какой-то выход, запрошенный исходным запросом, подается с использованием нового канала.
P.S. Я видел сообщение SO, в котором был предложен этот подход.
Ответ 2
У меня создается впечатление, что вы не можете сделать это на этом уровне - я пробовал различные методы внешне "обманывать" код, который требует создания nsIHttpChannel (пример в конце сообщения).
Я бы рекомендовал, если вы хотите перенаправить, обратитесь в окно владельца канала (что работает 99% времени) и попросите его перенаправить. Я знаю, что это не будет вести себя одинаково, но поскольку я точно не знаю, почему вы это делаете, это будет внешне (для пользователя), похоже, делает то же самое, что и вы.
Вот основы того, что я пытался:
if(aTopic == "http-on-examine-response") {
var request = aSubject.QueryInterface(Components.interfaces.nsIHttpChannel);
if(!request.URI.spec.match("^http://www.apple.com/")) {
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var ch = ios.newChannel("http://www.apple.com/", null, null);
var listener = {
QueryInterface : XPCOMUtils.generateQI([Ci.nsIChannelEventSink]),
onDataAvailable: function() {},
onStopRequest: function() {},
onStartRequest: function() {}
};
ch.asyncOpen(listener,null);
var eventSink = request.notificationCallbacks.getInterface(Ci.nsIChannelEventSink);
eventSink.asyncOnChannelRedirect(request,ch,Ci.nsIChannelEventSink.REDIRECT_INTERNAL,function() {});
}
Ответ 3
Я сделал это следующим образом: stop nsIHttpChannel
on "http-on-modify-request"
событие, получить объект браузера для текущего окна, вызвать browser.loadURI
.
var utils = require("sdk/window/utils");
function needsRedirect(url) {
// to be implemented
return true;
}
function generateNewUrl(url) {
// to be implemented
return "http://www.example.com/";
}
Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService)
.addObserver({
observe: function(subject, topic, data) {
var channel = subject.QueryInterface(Ci.nsIHttpChannel);
var url = channel.originalURI.spec;
if (needsRedirect(url)) {
//stop
channel.cancel(Cr.NS_BINDING_ABORTED);
//redirect
var gBrowser = utils.getMostRecentBrowserWindow().gBrowser;
var domWin = channel.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
var browser = gBrowser.getBrowserForDocument(domWin.top.document);
browser.loadURI(generateNewUrl(url));
}
}
}, "http-on-modify-request", false);
Ответ 4
Во время тестирования чего-то я создал сжатую версию (см. этот смысл) логики замены канала, упомянутой в других ответах.
Общая идея состоит в том, чтобы передать все критические свойства на новый канал, удалить обратные вызовы из старого канала, чтобы манипуляции не прерывали загрузку страницы, а затем закрывали старый канал.
С некоторыми изменениями можно изменить URI страницы для загрузки документов или оставить его как есть.
Предупреждение: это был просто быстрый взлом, чтобы загрузить несколько страниц, я не тестировал его в глубину, и он, вероятно, сломается для некоторых случаев. Я подозреваю, что есть причины, по которым HTTPS Everywhere является более сложным.