将HTML附加到XUL(Firefox扩展)

时间:2011-06-02 10:09:10

标签: firefox-addon xul

我有这个从服务器获取html部分的javascript。我能够在警告消息中返回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直接附加到带有id ajax的menupopup,它会按预期工作。当我使用appendChild附加它时,它没有。我知道我不能使用appendChild但是在XUL中似乎没有相当于innerHTML的东西。我无法控制从服务器返回的xul / html,因此我无法使用DOM方法添加内容并绕过html。

我尝试使用HTMLParser https://developer.mozilla.org/en/Code_snippets/HTML_to_DOM将其转换为DOM对象,但这似乎不起作用,我相信因为它会删除<menuitem>标记。

有关如何将HTML附加到menupopup的任何想法,以便我可以将它们显示为菜单项。

好的我尝试了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,%3Chtml%3E%0A%3Cbody%3E%0A%3Cp%3EHello%20everyone%3C%2Fp%3E%0A%09%3C%2Fbody%3E%0A%3C%2Fhtml%3E%0A%0A"/>

它不起作用,因为要显示它需要在标签内的html,但html包含许多不同的项目,每个项目都应该在它们自己的标签中。简单地添加到html是行不通的。

2 个答案:

答案 0 :(得分:3)

首先是正确答案,这不是你想要的,但重要的是省略:

请勿将远程检索的HTML或javascript代码附加/注入/放入XUL或Chrome代码范围内!

这样的东西总是一个安全漏洞。 JS是可执行的,HTML也可以包含可执行位(例如javascript:protocol)。任何注入的代码都将以完全浏览器权限运行,这转换为操作系统用户权限(在Windows XP上转换为管理员权限)。

你需要转义html,或解析它,只留下安全位。

您无法信任远程代码,即使它来自您自己的服务器:

  • 中间人攻击(http)
  • 受损服务器
  • 粗服务器管理员(不是你,希望;))

顺便说一句:将上传/注入/任何远程检索的代码或HTML放入chrome空间将导致在addons.mozilla.org上拒绝受影响的加载项版本,原因如上所述。

现在是技术上正确的答案,但不要使用远程检索和清理的HTML:

  1. 您需要确保使用正确的HTML命名空间(xmlns:html="http://www.w3.org/1999/xhtml"
  2. 您实际上不能appendElement()文本,而只能是真正的DOM元素。因此,您必须先将任何文本解析为DOM。使用有效的XML(DOMParser)最简单;可以通过隐藏的iframe标记汤的东西。
  3. 您应adoptNode来自不同DOM的任何元素
  4. 逐个追加元素(每个menuitem和子树)。

答案 1 :(得分:1)

您的代码确实是一个安全漏洞,您永远不应该这样做。然而,有一种相对简单的方法可以安全地执行它(重要的是:假设您的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)和您加载的代码(内容)之间创建一个安全边界。这就是为什么你的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阅读器编写)。