nsIProtocolHandler и nsIURI: относительные URL в самостоятельно создаваемом протоколе - PullRequest
1 голос
/ 14 февраля 2012

У меня есть простая реализация пользовательского протокола.Говорят, что метод newURI принимает 3 аргумента (spec, charset & baseURI) и "если протокол не имеет понятия относительных URI, третий параметр игнорируется" .

Итак, я открываю страницу, подобную этой tada: // domain / samplepage, в которой XML начинается с этого:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Product SYSTEM "product.dtd">

Но я не вижу ни одного запроса относительно product.dtd в моем протоколе (newURI не являетсядаже звонил).Я скучаю по чему-то в моей реализации?Кстати: сама страница открывается правильно, но нет запроса к DTD-файлу.

const
    Cc = Components.classes,
    Ci = Components.interfaces,
    Cr = Components.results,
    Cu = Components.utils,
    nsIProtocolHandler = Ci.nsIProtocolHandler;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");

function TadaProtocol() {
}

TadaProtocol.prototype = {
    scheme: "tada",
    protocolFlags: nsIProtocolHandler.URI_DANGEROUS_TO_LOAD,

    newURI: function(aSpec, aOriginCharset, aBaseURI) {
        let uri = Cc["@mozilla.org/network/simple-uri;1"].createInstance(Ci.nsIURI);
        uri.spec = (aBaseURI === null)
            ? aSpec
            : aBaseURI.resolve(aSpec);

        return uri;
    },

    newChannel: function(aURI) {
        let
            ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService),
            uri = ioService.newURI("chrome://my-extension/content/about/product.xml", null, null);

        return ioService.newChannelFromURI(uri);
    },

    classDescription: "Sample Protocol Handler",
    contractID: "@mozilla.org/network/protocol;1?name=tada",
    classID: Components.ID('{1BC90DA3-5450-4FAF-B6FF-F110BB73A5EB}'),
    QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler])
}

let NSGetFactory = XPCOMUtils.generateNSGetFactory([TadaProtocol]);

Ответы [ 3 ]

1 голос
/ 15 февраля 2012

Как отметил Борис в своем ответе, ваша реализация протокола не устанавливает свойство nsIChannel.originalURI, поэтому URL-адреса будут разрешаться относительно URL-адреса chrome:, а не относительно вашего tada: URL-адреса.Однако есть еще одна проблема с вашим кодом: в Firefox загрузка внешних DTD работает только с URL-адресами chrome:, эта проверка жестко закодирована.Существует ограниченное количество поддерживаемых DTD, которые отображаются на локальные файлы (различные типы документов HTML), но это все - Gecko не поддерживает случайные URL-адреса в <!DOCTYPE>.Вы можете увидеть текущую логику в исходном коде .Соответствующая ошибка - ошибка 22942 , которая не будет исправлена.

1 голос
/ 16 февраля 2012

Борис и Владимир, спасибо!

Через некоторое время у меня есть решение.Проблема заключалась в том, что DTD-файл не мог быть загружен из моего специально созданного протокола.Идея состояла в том, чтобы использовать Proxy API для переопределения метода schegrams (), который был вызван в методе newURI nsIProtocolHandler.

Так что теперь у меня есть этот фрагмент кода в методе newURI:

let standardUrl = Cc["@mozilla.org/network/standard-url;1"].createInstance(Ci.nsIStandardURL);
standardUrl.init(standardUrl.URLTYPE_STANDARD, -1, spec, charset, baseURI);
standardUrl.QueryInterface(Ci.nsIURL);

return Proxy.create(proxyHandlerMaker(standardUrl));

proxyHandlerMaker просто реализует Proxy API и переопределяет необходимый метод circuitIs () .Это решило проблему, и теперь все запросы поступают в newChannel, где мы можем их обработать.


Важные примечания:

  1. Запрос к DTD приходит к методу newURI () и выполняетне приходят в новый канал ().Это поведение по умолчанию.Это происходит потому, что метод scheIs ("chrome") вызывается для объекта, который был возвращен методом newURI ().Этот метод должен возвращать «true» для DTD-запросов, если вы хотите, чтобы запрос достиг метода newChannel ().
  2. Метод newChannel () вызывается с объектом {nsIURI}, который не совпадает как объект, который был возвращен методом newURI.
  3. Если вы хотите обрабатывать оба протокола : страница и протокол: // домен / страница URL-адреса по вашему протоколу, вам следуетиспользуйте оба {nsIURI} и {nsIStandardURL} objects
  4. Вы можете передать созданный {nsIStandardUrl} -объект (standardUrl в приведенном выше фрагменте) в качестве второго аргумента Proxy.create ()функция.Это заставит ваш baseURI (3-ий аргумент в newURI) пройти проверку " baseURI instanceof nsIStandardUrl ".Метод SchemeIs () этого прокси-объекта также будет возвращать true для запросов DTD-файлов.Но, к сожалению, запросы не доходят до метода newChannel ().Это может быть хорошим решением проблемы DTD, но я не могу решить эту проблему.
1 голос
/ 14 февраля 2012

Канал, который вы возвращаете из newChannel, имеет URI chrome://, который вы передали newChannelFromURI в качестве URI.Так что это URI, который страница имеет в качестве своего URI и в качестве базового URI.Таким образом, загрузка DTD происходит непосредственно из "chrome: //my-extension/content/about/product.dtd".

Что вы, вероятно, хотите сделать, - это установить aURI в качестве originalURI на канале, из которого вы возвращаетесьnewChannel.

...