Уважаемые, на вас вся надежда!

Пишу расширение, которое должно отлавливать данные с определенным Content-Type(application/x-bittorrent). Думал сначала написать Content-Handler компонент, но не нашел никакой путной информации по нему, точнее нашел что-то похожее в коде FF, написал, компонент регистрируется, но не работает... В общем, с Content-Handler я не разобрался, потому начал делать через nsIURIContentListener. Тут до опреленного момента все было хорошо - на onStartURIOpen я отлавливал прямые ссылки на торренты, в isPreffered попадало остальное с нужным contentType. На большинстве сайтов это работало хорошо, но к примеру на torrents.ru этот метод не прокатил - там получилась ситуация, когда на onStartURIOpen пришла непрямая ссылка, а в isPreffered, равно как и в другие методы моего листенера мы больше так и не попали - вместо этого отработали этот запрос по схеме unknownContentType, то есть открылось окошко с предложением выполнить файл, либо сохранить его... В принципе этого можно было бы избежать, если тупо в onStartURIOpen проверять хидер полученного URI на предмет Content-Type, но вот как бы это сделать так, чтоб это не тормозило работу гуя - я не знаю, потому что банально через XMLHttpRequest в синхронном варианте сильно тормозит... Возможно, тут есть какое-то другое решение этой проблемы, но я его не знаю, потому ОЧЕНЬ рассчитываю на вашу помощь. Может быть уважаемые гуру подскажут мне как правильно решить данную задачу.
Прошу не судить слишком строго, потому как мое знакомство Mozilla длится ровно две недели. :)

Привожу код своего листенера с надеждой на вашу помощь

Выделить код

Код:

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);

В общем, с Content-Handler я не разобрался

может быть, эта ссылка: http://kb.mozillazine.org/Dev_:_Protocol_Handlers поможет ?

Спасибо, Антон, но не поможет. Все же мне не нужен 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 я не получаю никогда. Да и вообще как-то я не пойму как проверить работоспособность компонента. Вполне возможно, что я где-то дико туплю, но тут прошу меня за это извинить - просто не хватает знаний, а работу делать надо... Если нетрудно, объясните где я не прав, и расскажите как сделать все правильно, если можно с примерами. Впрочем, может быть я чего-то не понимаю и мне нужен именно протокольный хэндлер, тогда можете ли вы мне рассказать поподробнее - почему именно он...

почему именно он...

прошу прощения, не разобрался в вопросе.

но вот алерта от handleContent я не получаю никогда

alert - это метод окна, а своего окна у компонента нет. надо либо определить метод, через который бы в компонент передавалось окно, либо, проще, записывать отладочные сообщения в консоль:

Выделить код

Код:

var consoleService = Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService);
consoleService.logStringMessage(text);

Спасибо большое за консоль. Нашел в коде компонента еще один баг, а именно неверный CONTRACTID - в конце была лишняя точка с запятой. Убрал ее, но это как-то не помогло. Скажите, Антон, а вот если компонент именно реализует интерфейс, а не создает что-то свое собственное, необходимо ли наличие xpt файла?

И еще один вопрос - я зарегистрировал обсервер на "http-on-examine-response". В принципе, мне этого наверное даже было бы достаточно для отлова моих торрентов, но есть один момент, который меня беспокоит. Дело в том, что при нажатии на линк функция observe вызывается от 10 до 30 раз. В этой функции я проверяю Content-Type того, что приехало и если это application/x-bittorrent, то говорю
cancel(Components.results.NS_ERROR_ABORT). Скажите, это нормальная ситуация, когда мы столько раз попадаем в observe с одного и того же линка и с одинми и теми же данными?

если компонент именно реализует интерфейс, а не создает что-то свое собственное, необходимо ли наличие xpt файла

Я не особенно компетентен в этом вопросе, однако, судя по коду некоторых расширений, наличие xpt в данном случае необязательно.

это нормальная ситуация, когда мы столько раз попадаем в observe с одного и того же линка и с одинми и теми же данными

Не знаю. Надо смотреть лог http-запросов, может быть FF делает повторные запросы, не получая ответ ? Тогда придётся строить http-on-modify-request.