#firefox-addon #xul
#firefox-дополнение #xul
Вопрос:
У меня есть этот javascript, который извлекает html-часть с сервера. Я могу вернуть html в предупреждающем сообщении, и это правильный код.
ajax: function(url){
var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onreadystatechange = function() {
if (request.readyState == 4) {
// only if "OK"
if (request.status == 200) {
var popup = document.getElementById("ajax"); // a <menupopup> element
var txt = request.responseText;
alert(txt);
popup.appendChild(txt);
} else {
alert("There was a problem retrieving the XML data:n"
request.statusText);
}
}
};
request.open("GET", url, true);
request.send(null);
}
xul / html, возвращенный с сервера:
<menuitem>
<html:h2><html:a href="http://google.com">Google</html:a></html:h2>
<html:p><html:table><html:tr><html:td>xxxx</html:td></html:tr></html:table></html:p>
</menuitem>
<menuitem>
<html:h2><html:a href="http://yahoo.com">Yahoo</html:a></html:h2>
<html:p><html:table><html:tr><html:td>yyyy</html:td></html:tr></html:table></html:p>
</menuitem>
Моя страница xul:
… еще немного кода
<menu class="menu" label="test">
<menupopup id="ajax" width="450" height="700" onpopupshowing="myextension.ajax('http://www.myserver.com/phpscript.php'>
</menupopup>
</menu>
Теперь, если я прикреплю html непосредственно к menupopup с идентификатором ajax, он будет работать так, как ожидалось. Когда я прикрепляю его с помощью appendChild, это не так. Я знаю, что не могу использовать appendChild, но, похоже, в XUL нет эквивалента innerHTML. У меня нет контроля над xul / html, возвращаемым с сервера, поэтому я не могу использовать методы DOM для добавления содержимого и обхода html.
Я пытался использовать HTMLParser https://developer.mozilla.org/en/Code_snippets/HTML_to_DOM чтобы преобразовать его в объект DOM, но это, похоже, не работает, я полагаю, потому что это сокращает <menuitem>
тег.
Есть идеи, как прикрепить HTML к menupopup, чтобы я мог отображать их как menuitems.
Хорошо, я попробовал подход iframe:
ajax: function(url){
var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onreadystatechange = function() {
if (request.readyState == 4) {
// only if "OK"
if (request.status == 200) {
var frame = document.getElementById("frame");
frame.setAttribute("src", "data:text/html," encodeURIComponent(request.responseText));
} else {
alert("There was a problem retrieving the XML data:n" request.statusText);
}
}
};
request.open("GET", url, true);
request.send(null);
}
с
<iframe id="frame" type="content" src="" />
Похоже, это не работает. Однако, если я выполняю оповещение о encodeURIComponent (request.responseText), оно правильно закодировано. Еще больше, если я напрямую добавлю его в iframe следующим образом:
<iframe type="content" src="data:text/html,
Hello everyone
"/>
это не работает, потому что для отображения html он должен находиться внутри тегов, но html содержит много разных элементов, каждый из которых должен быть в своем собственном теге. Простое добавление в html не работает.
Комментарии:
1. Если вы управляете сервером, возможно, было бы лучше, если бы вызов AJAX возвращал некоторый JSON с данными, которые вы хотите отобразить, а затем создавал структуры XUL / HTML на стороне клиента, используя методы DOM или XBL.
2. Я не могу этого сделать. На самом деле я получаю RSS-канал, который содержит некоторый HTML в описании. Я уже анализирую RSS-канал, чтобы извлечь из него часть HMTL. Но сложно разобрать html, а также я не знаю, что в нем будет. Поэтому я предпочитаю использовать html как есть.
3. Извините, я не заметил, что вы уже сказали, что не можете управлять сервером.
Ответ №1:
Сначала правильный ответ, который на самом деле не то, что вы ищете, но который важно опустить:
Не добавляйте / внедряйте / какой бы то ни было удаленно полученный HTML или javascript-код в области кода XUL или chrome!
Подобные вещи всегда являются уязвимостью в системе безопасности. JS является исполняемым, и HTML также может содержать исполняемые биты (например, javascript: протокол). Любой введенный код будет выполняться с полными правами браузера, что соответствует привилегиям пользователя операционной системы (которые в Windows XP соответствуют привилегиям администратора).
Вам нужно либо экранировать html, либо разобрать его и оставить только защищенные биты.
Вы не можете доверять удаленному коду, даже если он исходит с ваших собственных серверов:
- Человек посередине атакует (http)
- Взломанный сервер
- Грубый администратор сервера (надеюсь, не вы ;))
Кстати: добавление / внедрение / любого удаленно извлеченного кода или HTML в chrome space приведет к отклонению затронутых версий вашего дополнения на addons.mozilla.org по причине, указанной выше.
Теперь технически правильный ответ, но не используйте с удаленно извлеченным и очищенным HTML:
- Вам нужно убедиться, что будет использоваться правильное пространство имен HTML (
xmlns:html="http://www.w3.org/1999/xhtml"
) - На самом деле вы не можете
appendElement()
вводить текст, а только реальные элементы DOM. Следовательно, вы должны предварительно проанализировать любой текст в DOM. Проще всего с допустимым XML (DOMParser); возможно для содержимого tag soup через скрытый iframe. - Вы должны
adoptNode
использовать любые элементы из разных доменов - Затем добавляйте элементы один за другим (каждый элемент меню и поддерево).
Комментарии:
1. Проблема в том, что rss-канал содержит html-часть, которую трудно разобрать на отдельные элементы с помощью javascript (это PITA). Итак, я ищу более простой способ его добавления.
Ответ №2:
Ваш код действительно является уязвимостью системы безопасности, вы никогда не должны делать это подобным образом. Однако существует относительно простой способ сделать это безопасно (важно: это при условии, что ваш XUL не запущен в области содержимого браузера). Вы помещаете iframe в свой menupopup:
<menu class="menu" label="test">
<menupopup id="ajax" onpopupshowing="myextension.ajax('http://www.myserver.com/phpscript.php'>
<menuitem>
<iframe id="frame" type="content" width="450" height="700"></iframe>
</menuitem>
</menupopup>
</menu>
Затем вы можете загрузить свои данные в этот фрейм, используя data: URL. Важной частью здесь является type=»content», это создает границу безопасности между вашим кодом (chrome) и загруженным вами кодом (content). Вот почему важно, чтобы ваш документ XUL не находился в области содержимого браузера — тогда вы уже находитесь на стороне «содержимого» границы безопасности, вы не можете установить другую.
На самом деле помещение данных во фрейм работает следующим образом:
var frame = document.getElementById("frame"); // <iframe> element
var txt = request.responseText;
frame.setAttribute("src", "data:text/html;charset=utf-8," encodeURIComponent(txt));
Для получения дополнительной информации см. https://developer.mozilla.org/En/Displaying_web_content_in_an_extension_without_security_issues (эта статья была написана специально для чтения RSS).
Комментарии:
1. Я пытался использовать очень простую htmlстраницу: <html> <body> <p> Всем привет</p> </body> </html>, но она не отображается в iframe. Когда я добавляю это напрямую, вот так <iframe id=»frame» type = «content» src=»data: text / html,% 3Cp>hello% 3C / p>% 3C / html>»/> это действительно работает, но когда я использую frame.setAttribute, происходит сбой.
2. Похоже, что тег menuitem необходим для отображения html с помощью menupopup