>Форум Mozilla Россия http://forum.mozilla-russia.org/index.php >Разработка http://forum.mozilla-russia.org/viewforum.php?id=18 >безболезненный отлов заголовков http://forum.mozilla-russia.org/viewtopic.php?id=16020 |
Coordgun > 13-03-2007 18:39:13 |
Уважаемые, на вас вся надежда! Пишу расширение, которое должно отлавливать данные с определенным Content-Type(application/x-bittorrent). Думал сначала написать Content-Handler компонент, но не нашел никакой путной информации по нему, точнее нашел что-то похожее в коде FF, написал, компонент регистрируется, но не работает... В общем, с Content-Handler я не разобрался, потому начал делать через nsIURIContentListener. Тут до опреленного момента все было хорошо - на onStartURIOpen я отлавливал прямые ссылки на торренты, в isPreffered попадало остальное с нужным contentType. На большинстве сайтов это работало хорошо, но к примеру на torrents.ru этот метод не прокатил - там получилась ситуация, когда на onStartURIOpen пришла непрямая ссылка, а в isPreffered, равно как и в другие методы моего листенера мы больше так и не попали - вместо этого отработали этот запрос по схеме unknownContentType, то есть открылось окошко с предложением выполнить файл, либо сохранить его... В принципе этого можно было бы избежать, если тупо в onStartURIOpen проверять хидер полученного URI на предмет Content-Type, но вот как бы это сделать так, чтоб это не тормозило работу гуя - я не знаю, потому что банально через XMLHttpRequest в синхронном варианте сильно тормозит... Возможно, тут есть какое-то другое решение этой проблемы, но я его не знаю, потому ОЧЕНЬ рассчитываю на вашу помощь. Может быть уважаемые гуру подскажут мне как правильно решить данную задачу. Привожу код своего листенера с надеждой на вашу помощь Выделить код Код:var BTContentListener = { ListenedURI: null, mDownloader: null, QueryInterface: function(aIID) { if (aIID.equals(Components.interfaces.nsISupports) || aIID.equals(Components.interfaces.nsIURIContentListener) || aIID.equals(Components.interfaces.nsISupportsWeakReference)) return this; throw Components.results.NS_NOINTERFACE; }, get Downloader() {return this.mDownloader}, set Downloader(aDownloader) {return this.mDownloader = aDownloader}, onDownloadComplete: function() { //здесь делаем что-то со скачанным торрентом }, canHandleContent: function (contentType, isContentPreferred, desiredContentType) { alert("canHandleContent: " + contentType); if (contentType == "application/x-bittorrent") return true; else return false; }, doContent: function (contentType, isContentPreferred, request, contentHandler) { alert("doContent: " + contentType); dump(nsIURIToString(request.URI)+"\n"); return true; }, isPreferred: function (contentType, desiredContentType) { if (contentType == "application/x-bittorrent") { if (ListenedURI!=null) { this.mDownloader.onComplete = this.onDownloadComplete; this.mDownloader.download(ListenedURI.spec); } } return true; }, onStartURIOpen: function (URI) { ListenedURI = URI; //здесь тупо получаем Content-Type - решение на самом деле очень хреновое var http = false; var contentType = ""; try { http = new XMLHttpRequest(); } catch(e){ http = false; } if (http) { http.open("HEAD", ListenedURI.spec, false); http.send(null); if (http.status == 200) { contentType = http.getResponseHeader("Content-Type"); } } if ((torrentExt.test(URI.spec))||(torrentContentType.test(contentType))) { this.mDownloader.onComplete = this.onDownloadComplete; this.mDownloader.download(URI.spec); return true; } return false; } } function init() { var wnd = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIWebNavigation) .QueryInterface(Components.interfaces.nsIDocShell) .QueryInterface(Components.interfaces.nsIInterfaceRequestor) .getInterface(Components.interfaces.nsIURIContentListener); BTContentListener.Downloader = new asyncDownloader(); wnd.parentContentListener = BTContentListener; } window.addEventListener("load", init, true); |
Anton > 13-03-2007 22:30:40 |
может быть, эта ссылка: http://kb.mozillazine.org/Dev_:_Protocol_Handlers поможет ? |
Coordgun > 14-03-2007 09:59:48 |
Спасибо, Антон, но не поможет. Все же мне не нужен protocol handler. Я эту информацию перечитал, но это не то, что мне надо. Все-таки мне надо обрабатывать не протокол x-bittorrent:bla-bla-bla, а ловить контент с Content-Type = application/x-bittorrent. Мой случай - это компонент, реализующий интерфейс nsIContentHandler, который регистрируется как "@mozilla.org\uriloader\content-handler;1?type=application/x-bittorrent". Но вот как его правильно зарегистрировать - хз... Да, реализацию этого компонента писал на JS. Выделить код Код:/* components defined in this file */ const BITTORRENT_CONTENT_HANDLER_CONTRACTID = "@mozilla.org/uriloader/content-handler;1?type=application/x-bittorrent;"; const BITTORRENT_CONTENT_HANDLER_CID = Components.ID("{2E37E494-D09F-48FC-81AA-D0B37E8B0EEB}"); /* components used in this file */ const SIMPLEURI_CONTRACTID = "@mozilla.org/network/simple-uri;1"; /* interfaces used in this file */ const nsICategoryManager = Components.interfaces.nsICategoryManager; const nsIContentHandler = Components.interfaces.nsIContentHandler; const nsIURI = Components.interfaces.nsIURI; const nsIChannel = Components.interfaces.nsIChannel; const nsIRequest = Components.interfaces.nsIRequest; const nsIIOService = Components.interfaces.nsIIOService; const nsISupports = Components.interfaces.nsISupports; /* x-application-terminal content handler */ function BitTorrentContentHandler () {} BitTorrentContentHandler.prototype.QueryInterface = function (iid) { if (iid.equals(nsIContentHandler) || iid.equals(nsISupports)) return this; Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE; return null; } BitTorrentContentHandler.prototype.handleContent = function (aContentType, aWindowContext, aRequest) { var aChannel = aRequest.QueryInterface(Components.interfaces.nsIChannel); alert("BitTorrentContentHandler.handleContent (" + aContentType + ", " + aWindowContext + ", " + aChannel.URI.spec + ")\n"); } BitTorrentContentHandlerFactory = new Object(); BitTorrentContentHandlerFactory.createInstance = function (outer, iid) { if (outer != null) throw Components.results.NS_ERROR_NO_AGGREGATION; if (!iid.equals(nsIContentHandler) && !iid.equals(nsISupports)) throw Components.results.NS_ERROR_INVALID_ARG; return new BitTorrentContentHandler(); } var BTContentHandlerModule = new Object(); BTContentHandlerModule.registerSelf = function (compMgr, fileSpec, location, type) { debug("*** Registering application/x-bittorrent handler.\n"); compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar); compMgr.registerFactoryLocation(BITTORRENT_CONTENT_HANDLER_CID, "BitTorrent Content Handler", BITTORRENT_CONTENT_HANDLER_CONTRACTID, fileSpec, location, type); } BTContentHandlerModule.unregisterSelf = function(compMgr, fileSpec, location) { } BTContentHandlerModule.getClassObject = function (compMgr, cid, iid) { if (cid.equals(BITTORRENT_CONTENT_HANDLER_CID)) return BitTorrentContentHandlerFactory; if (!iid.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED; throw Components.results.NS_ERROR_NO_INTERFACE; } BTContentHandlerModule.canUnload = function(compMgr) { return true; } /* entrypoint */ function NSGetModule(compMgr, fileSpec) { return BTContentHandlerModule; } Эту реализацию я содрал из какого-то компонента из сорцов FF, оно вроде как даже регистрируется (в compreg.dat появляется соответсвующая запись), но вот алерта от handleContent я не получаю никогда. Да и вообще как-то я не пойму как проверить работоспособность компонента. Вполне возможно, что я где-то дико туплю, но тут прошу меня за это извинить - просто не хватает знаний, а работу делать надо... Если нетрудно, объясните где я не прав, и расскажите как сделать все правильно, если можно с примерами. Впрочем, может быть я чего-то не понимаю и мне нужен именно протокольный хэндлер, тогда можете ли вы мне рассказать поподробнее - почему именно он... |
Anton > 14-03-2007 15:44:25 |
прошу прощения, не разобрался в вопросе.
alert - это метод окна, а своего окна у компонента нет. надо либо определить метод, через который бы в компонент передавалось окно, либо, проще, записывать отладочные сообщения в консоль: Выделить код Код:var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService); consoleService.logStringMessage(text); |
Coordgun > 14-03-2007 17:56:00 |
Спасибо большое за консоль. Нашел в коде компонента еще один баг, а именно неверный CONTRACTID - в конце была лишняя точка с запятой. Убрал ее, но это как-то не помогло. Скажите, Антон, а вот если компонент именно реализует интерфейс, а не создает что-то свое собственное, необходимо ли наличие xpt файла? И еще один вопрос - я зарегистрировал обсервер на "http-on-examine-response". В принципе, мне этого наверное даже было бы достаточно для отлова моих торрентов, но есть один момент, который меня беспокоит. Дело в том, что при нажатии на линк функция observe вызывается от 10 до 30 раз. В этой функции я проверяю Content-Type того, что приехало и если это application/x-bittorrent, то говорю |
Anton > 14-03-2007 18:56:49 |
Я не особенно компетентен в этом вопросе, однако, судя по коду некоторых расширений, наличие xpt в данном случае необязательно.
Не знаю. Надо смотреть лог http-запросов, может быть FF делает повторные запросы, не получая ответ ? Тогда придётся строить http-on-modify-request. |