Commit 6277656d authored by Nigel Tao's avatar Nigel Tao

html, exp/html: escape ' and " as ' and ", since IE8 and

below do not support '.

This makes package html consistent with package text/template's
HTMLEscape function.

Fixes #3489.

R=rsc, mikesamuel, dsymonds
CC=golang-dev
https://golang.org/cl/5992071
parent 772e8ff4
...@@ -205,13 +205,15 @@ func escape(w writer, s string) error { ...@@ -205,13 +205,15 @@ func escape(w writer, s string) error {
case '&': case '&':
esc = "&" esc = "&"
case '\'': case '\'':
esc = "'" // "'" is shorter than "'" and apos was not in HTML until HTML5.
esc = "'"
case '<': case '<':
esc = "&lt;" esc = "&lt;"
case '>': case '>':
esc = "&gt;" esc = "&gt;"
case '"': case '"':
esc = "&quot;" // "&#34;" is shorter than "&quot;".
esc = "&#34;"
default: default:
panic("unrecognized escape character") panic("unrecognized escape character")
} }
...@@ -226,7 +228,7 @@ func escape(w writer, s string) error { ...@@ -226,7 +228,7 @@ func escape(w writer, s string) error {
} }
// EscapeString escapes special characters like "<" to become "&lt;". It // EscapeString escapes special characters like "<" to become "&lt;". It
// escapes only five such characters: amp, apos, lt, gt and quot. // escapes only five such characters: <, >, &, ' and ".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true. // always true.
func EscapeString(s string) string { func EscapeString(s string) string {
......
...@@ -98,7 +98,7 @@ func TestRenderer(t *testing.T) { ...@@ -98,7 +98,7 @@ func TestRenderer(t *testing.T) {
}, },
}, },
} }
want := `<html><head></head><body>0&lt;1<p id="A" foo="abc&quot;def">` + want := `<html><head></head><body>0&lt;1<p id="A" foo="abc&#34;def">` +
`2<b empty="">3</b><i backslash="\">&amp;4</i></p>` + `2<b empty="">3</b><i backslash="\">&amp;4</i></p>` +
`5<blockquote></blockquote><br/>6</body></html>` `5<blockquote></blockquote><br/>6</body></html>`
b := new(bytes.Buffer) b := new(bytes.Buffer)
......
...@@ -359,7 +359,7 @@ var tokenTests = []tokenTest{ ...@@ -359,7 +359,7 @@ var tokenTests = []tokenTest{
{ {
"tricky", "tricky",
"<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>", "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
`<p id="a&quot;B" foo="bar">$<em>$te&lt;&amp;;xt$</em>$</p>`, `<p id="a&#34;B" foo="bar">$<em>$te&lt;&amp;;xt$</em>$</p>`,
}, },
// A nonexistent entity. Tokenizing and converting back to a string should // A nonexistent entity. Tokenizing and converting back to a string should
// escape the "&" to become "&amp;". // escape the "&" to become "&amp;".
...@@ -421,7 +421,7 @@ var tokenTests = []tokenTest{ ...@@ -421,7 +421,7 @@ var tokenTests = []tokenTest{
{ {
"Double-quoted attribute value", "Double-quoted attribute value",
`<input value="I'm an attribute" FOO="BAR">`, `<input value="I'm an attribute" FOO="BAR">`,
`<input value="I&apos;m an attribute" foo="BAR">`, `<input value="I&#39;m an attribute" foo="BAR">`,
}, },
{ {
"Attribute name characters", "Attribute name characters",
...@@ -436,7 +436,7 @@ var tokenTests = []tokenTest{ ...@@ -436,7 +436,7 @@ var tokenTests = []tokenTest{
{ {
"Attributes with a solitary single quote", "Attributes with a solitary single quote",
`<p id=can't><p id=won't>`, `<p id=can't><p id=won't>`,
`<p id="can&apos;t">$<p id="won&apos;t">`, `<p id="can&#39;t">$<p id="won&#39;t">`,
}, },
} }
...@@ -545,10 +545,11 @@ func TestUnescapeEscape(t *testing.T) { ...@@ -545,10 +545,11 @@ func TestUnescapeEscape(t *testing.T) {
`"<&>"`, `"<&>"`,
`&quot;&lt;&amp;&gt;&quot;`, `&quot;&lt;&amp;&gt;&quot;`,
`3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`, `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
`The special characters are: <, >, &, ' and "`,
} }
for _, s := range ss { for _, s := range ss {
if s != UnescapeString(EscapeString(s)) { if got := UnescapeString(EscapeString(s)); got != s {
t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s) t.Errorf("got %q want %q", got, s)
} }
} }
} }
......
...@@ -210,13 +210,15 @@ func escape(w writer, s string) error { ...@@ -210,13 +210,15 @@ func escape(w writer, s string) error {
case '&': case '&':
esc = "&amp;" esc = "&amp;"
case '\'': case '\'':
esc = "&apos;" // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
esc = "&#39;"
case '<': case '<':
esc = "&lt;" esc = "&lt;"
case '>': case '>':
esc = "&gt;" esc = "&gt;"
case '"': case '"':
esc = "&quot;" // "&#34;" is shorter than "&quot;".
esc = "&#34;"
default: default:
panic("unrecognized escape character") panic("unrecognized escape character")
} }
...@@ -231,7 +233,7 @@ func escape(w writer, s string) error { ...@@ -231,7 +233,7 @@ func escape(w writer, s string) error {
} }
// EscapeString escapes special characters like "<" to become "&lt;". It // EscapeString escapes special characters like "<" to become "&lt;". It
// escapes only five such characters: amp, apos, lt, gt and quot. // escapes only five such characters: <, >, &, ' and ".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true. // always true.
func EscapeString(s string) string { func EscapeString(s string) string {
......
...@@ -785,8 +785,10 @@ var htmlReplacer = strings.NewReplacer( ...@@ -785,8 +785,10 @@ var htmlReplacer = strings.NewReplacer(
"&", "&amp;", "&", "&amp;",
"<", "&lt;", "<", "&lt;",
">", "&gt;", ">", "&gt;",
`"`, "&quot;", // "&#34;" is shorter than "&quot;".
"'", "&apos;", `"`, "&#34;",
// "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
"'", "&#39;",
) )
func htmlEscape(s string) string { func htmlEscape(s string) string {
......
...@@ -246,7 +246,7 @@ func not(arg interface{}) (truth bool) { ...@@ -246,7 +246,7 @@ func not(arg interface{}) (truth bool) {
var ( var (
htmlQuot = []byte("&#34;") // shorter than "&quot;" htmlQuot = []byte("&#34;") // shorter than "&quot;"
htmlApos = []byte("&#39;") // shorter than "&apos;" htmlApos = []byte("&#39;") // shorter than "&apos;" and apos was not in HTML until HTML5
htmlAmp = []byte("&amp;") htmlAmp = []byte("&amp;")
htmlLt = []byte("&lt;") htmlLt = []byte("&lt;")
htmlGt = []byte("&gt;") htmlGt = []byte("&gt;")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment