Skip to content

Instantly share code, notes, and snippets.

@Infocatcher
Last active December 15, 2015 21:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Infocatcher/5327631 to your computer and use it in GitHub Desktop.
Save Infocatcher/5327631 to your computer and use it in GitHub Desktop.
Получение свойств файла по ссылке, пример для статьи на habrahabr.ru Getting file's properties by it's URL, example for article on habrahabr.ru http://habrahabr.ru/post/175745/
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