Добрый день.
Разрабатываю аддон к Firefox. Для его корректной работы требуется получить в строковую переменную оригинальный исходный код открытой страницы - не содержимое body как во многих примерах, а целиком - с doctype, head.
Нашел вот такую реализацию:

Выделить код

Код:

var cont = window.getBrowser().contentDocument;
var ser = new XMLSerializer();
var st = ser.serializeToString(cont);

На первый взгляд она работает правильно, но это не так. К примеру, если такому обработчику подсунуть заведомо некорректную страницу, в которой, допустим, нет <body> и <html>, он их создаст искусственно! И хотя эти тэги будут пустыми, получится, что оригинальная страница не соответствует результату. А одна из задач аддона получить код абсолютно такой как в оригинале.

Также мне посоветовали копать в сторону view-source. Я смотрел готовые реализации, но они не устраивают тем, что фактически мы запрашиваем страницу заново и при определенных условиях можно получить совсем не тот контент, что в ранее открытой странице

Как тут не подходит? Вроде бы, заново не запрашивается.

Infocatcher пишет

Как тут не подходит? Вроде бы, заново не запрашивается.

Спасибо за ответ и пример. Тем не менее вот этот участок кода

Выделить код

Код:

req.open("GET", "view-source:" + content.location.href, true);

как раз и делает запрос (хоть и через AJAX). Как я понимаю, браузер подставляет результат из кэша, т.е. фактически этот прием работает. Но вот есть две предположительных ситуации, в которых он будет давать сбой:
1. Страница не кэширована
2. Содержимое страницы поменялось скриптом, находящимся на этой же странице

Запрос-то будет уже по другой ссылке через протокол «view-source:» – точно так же как при вызове встроенной команды просмотра исходного кода.

В качестве альтернативы можно только обрабатывать загрузку всего подряд и сделать свой кэш для исходного кода всех страниц. А это как-то совсем не оптимально выходит.
Ну, или можно как-то получить доступ к кэшу этого view-source.

SergeyLisovskiy пишет

2. Содержимое страницы поменялось скриптом, находящимся на этой же странице

Я думаю, с этим ничего не сделать – скрипты работают с уже преобразованным внутренним представлением, куда уже добавились <html>, <body> и <tbody> у таблиц.

Infocatcher пишет

Запрос-то будет уже по другой ссылке через протокол «view-source:» – точно так же как при вызове встроенной команды просмотра исходного кода.

Вот мне не до конца понятен этот момент. С одной стороны «view-source:» при открытой странице с тем же адресом как-будто обращается к локальной копии (кэшу?) этой страницы. С другой - можно сразу зайти на нужную страницу через «view-source:». В этом случае браузер ее открывает заново

Infocatcher пишет

Я думаю, с этим ничего не сделать – скрипты работают с уже преобразованным внутренним представлением, куда уже добавились <html>, <body> и <tbody> у таблиц.

А вот инспектор кода же как-то работает с измененными данными. Значит в браузер встроен еще какой-то хитрый механизм, к которому нет доступа из аддонов...

SergeyLisovskiy пишет

А вот инспектор кода же как-то работает с измененными данными. Значит в браузер встроен еще какой-то хитрый механизм, к которому нет доступа из аддонов...

Ну так там и получится как раз вот это:

SergeyLisovskiy пишет

К примеру, если такому обработчику подсунуть заведомо некорректную страницу, в которой, допустим, нет <body> и <html>, он их создаст искусственно!

21-05-2013 10:23:49
В принципе, можно попробовать что-нибудь извлечь из
BrowserViewSourceOfDocument() -> gViewSourceUtils.viewSource() -> gViewSourceUtils.openInInternalViewer()
-> chrome://global/content/viewSource.js viewSource()

Выделить код

Код:

try {
        if (typeof(arg) == "object" && arg != null) {
          // Load the page using the page descriptor rather than the URL.
          // This allows the content to be fetched from the cache (if
          // possible) rather than the network...
          gPageLoader.loadPage(arg, gPageLoader.DISPLAY_AS_SOURCE);

          // The content was successfully loaded.
          loadFromURL = false;

          // Record the page load in the session history so <back> will work.
          var shEntrySource = arg.QueryInterface(Ci.nsISHEntry);
          var shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].createInstance(Ci.nsISHEntry);
          shEntry.setURI(makeURI(viewSrcUrl, null, null));
          shEntry.setTitle(viewSrcUrl);
          shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
          shEntry.cacheKey = shEntrySource.cacheKey;
          gBrowser.sessionHistory
                  .QueryInterface(Ci.nsISHistoryInternal)
                  .addEntry(shEntry, true);
        }
      } catch(ex) {
        // Ignore the failure.  The content will be loaded via the URL
        // that was supplied in arg[0].
      }

Infocatcher, спасибо, буду пробовать. Также стараюсь точно выяснить при каких условиях каждый механизм будет глючить