将 HTML 附加到 XUL(Firefox 扩展)

Appending HTML to XUL (Firefox extension)

我有这个从服务器获取 html 部分的 javascript。我能够在警报消息中返回 html,它是正确的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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:\
" +
                            request.statusText);
                }
            }
        };
        request.open("GET", url, true);
        request.send(null);
}

服务器返回的xul/html:

1
2
3
4
5
6
7
8
     <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页面:

...更多代码

1
2
3
4
<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 的菜单弹出窗口,它会按预期工作。当我使用 appendChild 附加它时,它没有。我知道我不能使用 appendChild 但在 XUL 中似乎没有与 innerHTML 等效的东西。我无法控制从服务器返回的 xul/html,因此我无法使用 DOM 方法添加内容并绕过 html。

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

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

好的,我尝试了 iframe 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        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:\
" + request.statusText);
                    }
                }
            };
            request.open("GET", url, true);
            request.send(null);
    }

1
&lt;iframe id="frame" type="content" src="" />

这似乎不起作用。但是,如果我对 encodeURIComponent(request.responseText) 发出警报,它就会正确编码。甚至如果我像这样直接将它添加到 iframe 中:

1
&lt;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 是行不通的。


首先是正确答案,这不是您真正要寻找的,但重要的是要省略:

不要将远程检索到的 HTML 或 javascript 代码附加/注入/任何内容到 XUL 或 chrome 代码范围!

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

您需要对 html 进行转义,或者对其进行解析并只保留安全位。

你不能信任远程代码,即使它来自你自己的服务器:

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

顺便说一句:由于上述原因,将远程检索到的代码或 HTML 添加/注入/任何远程检索到的代码或 HTML 将导致 addons.mozilla.org 上受影响的插件版本被拒绝。

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

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

  • 你的代码确实是一个安全漏洞,你不应该那样做。然而,有一种相对简单的方法可以安全地执行此操作(重要:这是假设您的 XUL 没有在浏览器的内容区域中运行)。您将 iframe 放入 menupopup:

    1
    2
    3
    4
    5
    6
    7
    <menu class="menu" label="test">
        <menupopup id="ajax" onpopupshowing="myextension.ajax('http://www.myserver.com/phpscript.php'>
            <menuitem>
                &lt;iframe id="frame" type="content" width="450" height="700">&lt;/iframex&gt;
            </menuitem>
        </menupopup>
    </menu>

    然后您可以使用 data: URL 将数据加载到该框架中。这里的重要部分是 type="content" 这里,这会在您的代码 (chrome) 和您加载的代码 (content) 之间创建一个安全边界。这就是为什么您的 XUL 文档不在浏览器的内容区域中很重要的原因 - 那么您已经在安全边界的"内容"一侧,您无法建立另一个。

    实际上将数据放入框架是这样的:

    1
    2
    3
    var frame = document.getElementById("frame"); // &lt;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 阅读器编写)。