Skip to content

Instantly share code, notes, and snippets.

@plugn
Forked from Infocatcher/request.js
Created April 8, 2013 07:27
Show Gist options
  • Save plugn/5334895 to your computer and use it in GitHub Desktop.
Save plugn/5334895 to your computer and use it in GitHub Desktop.
var uriString = "https://addons.mozilla.org/firefox/downloads/latest/413716/addon-413716-latest.xpi";
var referer = "https://addons.mozilla.org/";
var private = false; // Отсылать запрос в приватном режиме
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var uri = ios.newURI(uriString, null, null);
var scheme = uri.scheme && uri.scheme.toLowerCase();
var channel = scheme == "about" && "nsIAboutModule" in Components.interfaces
// Небольшое колдунство для about: ссылок
? Components.classes["@mozilla.org/network/protocol/about;1?what=" + uri.path.replace(/[?&#].*$/, "")]
.getService(Components.interfaces.nsIAboutModule)
.newChannel(uri)
: ios.newChannelFromURI(uri);
if(
private
&& "nsIPrivateBrowsingChannel" in Components.interfaces
&& channel instanceof Components.interfaces.nsIPrivateBrowsingChannel
&& "setPrivate" in channel
)
channel.setPrivate(true);
var observer = {
// nsIRequestObserver (nsIStreamListener наследует этот интерфейс)
onStartRequest: function(aRequest, aContext) {
if(aRequest instanceof Components.interfaces.nsIHttpChannel)
aRequest.visitResponseHeaders(this);
else {
if("contentType" in channel)
data.push("Тип содержимого: " + channel.contentType);
if("contentLength" in channel)
data.push("Размер файла: " + channel.contentLength);
if("responseStatus" in channel && "responseStatusText" in channel)
data.push("Статус: " + channel.responseStatus + " " + channel.responseStatusText);
if("lastModifiedTime" in aRequest && aRequest.lastModifiedTime) { // Firefox 4
var t = aRequest.lastModifiedTime;
data.push("Последнее изменение: " + new Date(t > 1e14 ? t/1000 : t).toLocaleString());
}
}
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
if(aRequest instanceof Components.interfaces.nsIChannel && aRequest.URI)
data.push("Прямая ссылка: " + aRequest.URI.spec);
this.done();
},
// nsIStreamListener
onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
// Кажется, что-то пошло не так, не нужно нам данные получать, отменяем
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
},
// nsIHttpHeaderVisitor
visitHeader: function(aHeader, aValue) {
headers.push(aHeader + ": " + aValue);
switch(aHeader) {
// Тут можно как-то красиво форматировать данные
case "Content-Length": data.push("Размер файла: " + aValue); break;
case "Content-Type": data.push("Тип содержимого: " + aValue); break;
case "Last-Modified": data.push("Последнее изменение: " + new Date(aValue).toLocaleString());
}
},
// nsIInterfaceRequestor
getInterface: function(iid) {
if(iid.equals(Components.interfaces.nsIChannelEventSink))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
// nsIChannelEventSink
onChannelRedirect: function(oldChannel, newChannel, flags) { // Gecko < 2
this.onRedirect.apply(this, arguments);
},
asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) {
// Надо обязательно разрешить перенаправление, иначе запрос будет прерван!
callback.onRedirectVerifyCallback(Components.results.NS_OK);
this.onRedirect.apply(this, arguments);
},
onRedirect: function(oldChannel, newChannel, flags) {
if(!redirects.length) // Это самое первое перенаправление
redirects.push(oldChannel.URI.spec);
// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIChannelEventSink#Constants
var ces = Components.interfaces.nsIChannelEventSink;
var types = [];
if(flags & ces.REDIRECT_TEMPORARY)
types.push("временное");
if(flags & ces.REDIRECT_PERMANENT)
types.push("постоянное");
if(flags & ces.REDIRECT_INTERNAL)
types.push("внутреннее");
redirects.push("=> (" + types.join(", ") + ") " + newChannel.URI.spec);
},
done: function() {
alert(
data.join("\n")
+ "\n\nПеренаправления:\n" + redirects.join("\n")
+ "\n\nЗаголовки:\n" + headers.join("\n")
);
}
};
channel.notificationCallbacks = observer; // Для отслеживания перенаправлений
// => observer.getInterface() => observer.asyncOnChannelRedirect()
var data = []; // Для примера будем просто собирать результаты в массив
var headers = []; // Еще один массив, для заголовков
var redirects = []; // Массив для данных о перенаправлениях
if(channel instanceof Components.interfaces.nsIHttpChannel) {
// Проверка на instanceof неявно делает
// channel.QueryInterface(Components.interfaces.nsIHttpChannel),
// но не генерирует ошибок в случае отсутствия поддержки запрашиваемого интерфейса
channel.requestMethod = "HEAD"; // HEAD-запрос
channel.setRequestHeader("Referer", referer, false);
channel.visitRequestHeaders(observer);
headers.push(""); // Отделим заголовки запроса от заголовков ответа
}
// Следующая строка выглядит странно, но nsIFTPChannel нам еще пригодится
channel instanceof Components.interfaces.nsIFTPChannel;
channel.asyncOpen(observer, null);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment