Last active
December 15, 2015 21:39
-
-
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/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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