<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On 06.05.2009, at 17:31, Adam Barth wrote:</div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000"><br></font>WHY NOT toStaticHTML?<br><br>toStaticHTML addresses the same use cause by translating an untrusted<br>string to another string that lacks active HTML content. &nbsp;This API has<br>two issues:<br><br>1) The untrusted string -&gt; static string -&gt; HTML parser workflow<br>requires the browser to parse the string twice, introducing a<br>performance penalty and a security issue if the two parsing aren't<br>identical.<br></div></blockquote><div><br></div><div>That is based on assumptions that:</div><div>1. parsing is expensive enough to warrant API optimized for this particular case</div><div>2. browsers cannot optimize it otherwise</div><div>3. returned code will be ambiguous</div><div><br></div><div>In client-side scripts untrusted content comes from the network, which means that parsing time is going to be miniscule compared to time required to fetch the content (and to render it). My guess is that parsing itself is not a bottleneck.</div><div><br></div><div>Second, it _is_ possible to avoid reparsing without special API for this. toStaticHTML() may return subclass of String that contains reference to parsed DOM. Roughly something like this:</div><div><br></div><div>function toStaticHTML(html)</div><div>{</div><div>&nbsp;&nbsp; &nbsp;var cleanDOM = clean(parse(html))</div><div>&nbsp;&nbsp; &nbsp;return {</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;toString:function(){return unparse(cleanDOM)},&nbsp;</div><div>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;node:cleanDOM</div><div>&nbsp;&nbsp; &nbsp;}</div><div>}</div><div><br></div><div>which should make common case:</div><div><br></div><div>innerHTML = toStaticHTML(html) just as fast as innerStaticHTML = html;</div><div><br></div><div>toStaticHTML() enables other optimisations, e.g. filtered HTML can be saved for future use (in local storage) or string filtered once used in multiple places.</div><div><br></div><div>Alternatively there could be toStaticDOM() method that returns DOMDocumentFragment, avoiding reparsing issue entirely.</div><br><blockquote type="cite"><div>2) The API is difficult to future-proof because future versions of<br>HTML are likely to add new tags with active content (e.g., like the<br>&lt;video&gt; tag's event handlers). &nbsp;</div></blockquote><div><br></div><div>When support for new tag is added to a browser, it would also be added to its toStaticHTML()/innerStaticHTML, so evolution of HTML shouldn't be a problem either way. Browser doesn't need to worry about dangerous constructs it does not support.</div><div><br></div><div>Methods are easier to patch than properties in JavaScript, so if implementation of existing toStaticHTML() turned out to be insecure, the method could be easily replaced/patched on cilent-side, or applications could post-process output of toStaticHTML().</div><div>It's not that easy with a property.</div><div><br></div><div>I dislike APIs based on magic properties. Properties cannot take arguments and we'd have to create new property for every combination of arguments. If innerHTML was a method, instead of creating new property we could extend it to be innerHTML(html, static=true).&nbsp;</div><div><br></div><div>If more sophisticated filtering becomes&nbsp;needed&nbsp;in the future, we could have toStaticHTML(html, {preserve:['svg','rdf'], remove:'marquee'}), but it would be silly to create another innerStaticHTMLwithSVGandRDFbutWithoutMarquee property.</div><div><br></div></div><div> <div><div><div>--&nbsp;</div><div>regards,&nbsp;Kornel</div><div><br></div></div></div><br> </div><br></body></html>