]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template/html: error out on ambiguous unquoted attributes
authorMike Samuel <mikesamuel@gmail.com>
Mon, 26 Sep 2011 07:42:38 +0000 (00:42 -0700)
committerMike Samuel <mikesamuel@gmail.com>
Mon, 26 Sep 2011 07:42:38 +0000 (00:42 -0700)
HTML parsers may differ on whether
<input id= onchange=f(             ends in id's or onchange's value,
<a class=`foo                      ends inside a value,
<input style=font:'Arial'          needs open-quote fixup.

Per
http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
this treats the error cases in 8.2.4.40 Attribute value (unquoted) state
as fatal errors.

\> U+0022 QUOTATION MARK (")
\> U+0027 APOSTROPHE (')
\> U+003C LESS-THAN SIGN (<)
\> U+003D EQUALS SIGN (=)
\> U+0060 GRAVE ACCENT (`)
        Parse error. Treat it as per the "anything else" entry below.

and emits ErrBadHTML.

R=nigeltao
CC=golang-dev
https://golang.org/cl/5085050

src/pkg/exp/template/html/escape.go
src/pkg/exp/template/html/escape_test.go

index 650a6acd288e82a15ff3545904b9f44c07455855..aa5427c09844888c18bf4f4be54a1cf89bc79b21 100644 (file)
@@ -626,6 +626,24 @@ func contextAfterText(c context, s []byte) (context, int) {
 
        i := bytes.IndexAny(s, delimEnds[c.delim])
        if i == -1 {
+               i = len(s)
+       }
+       if c.delim == delimSpaceOrTagEnd {
+               // http://www.w3.org/TR/html5/tokenization.html#attribute-value-unquoted-state
+               // lists the runes below as error characters.
+               // Error out because HTML parsers may differ on whether
+               // "<a id= onclick=f("     ends inside id's or onchange's value,
+               // "<a class=`foo "        ends inside a value,
+               // "<a style=font:'Arial'" needs open-quote fixup.
+               // IE treats '`' as a quotation character.
+               if j := bytes.IndexAny(s[:i], "\"'<=`"); j >= 0 {
+                       return context{
+                               state: stateError,
+                               err:   errorf(ErrBadHTML, 0, "%q in unquoted attr: %q", s[j:j+1], s[:i]),
+                       }, len(s)
+               }
+       }
+       if i == len(s) {
                // Remain inside the attribute.
                // Decode the value so non-HTML rules can easily handle
                //     <button onclick="alert(&quot;Hi!&quot;)">
index 1ce66c5fb19fd79f1ff134ee395028cd806d4ce2..a3dab4cc85e423182e972c2cba6cc93d46760e64 100644 (file)
@@ -884,6 +884,26 @@ func TestErrors(t *testing.T) {
                                `{{define "t"}}{{if .Tail}}{{template "t" .Tail}}{{end}}{{.Head}}",{{end}}`,
                        `: cannot compute output context for template t$htmltemplate_stateJS_elementScript`,
                },
+               {
+                       `<input type=button value=onclick=>`,
+                       `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+               },
+               {
+                       `<input type=button value= onclick=>`,
+                       `exp/template/html:z: "=" in unquoted attr: "onclick="`,
+               },
+               {
+                       `<input type=button value= 1+1=2>`,
+                       `exp/template/html:z: "=" in unquoted attr: "1+1=2"`,
+               },
+               {
+                       "<a class=`foo>",
+                       "exp/template/html:z: \"`\" in unquoted attr: \"`foo\"",
+               },
+               {
+                       `<a style=font:'Arial'>`,
+                       `exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`,
+               },
        }
 
        for _, test := range tests {