]> Cypherpunks repositories - gostls13.git/commitdiff
exp/template/html: fix infinite loop in escapeText on bad input
authorMike Samuel <mikesamuel@gmail.com>
Mon, 26 Sep 2011 07:56:49 +0000 (00:56 -0700)
committerMike Samuel <mikesamuel@gmail.com>
Mon, 26 Sep 2011 07:56:49 +0000 (00:56 -0700)
The template
    "<a="
caused an infinite loop in escape text.

The change to tTag fixes that and the change to escape.go causes
escapeText to panic on any infinite loop that does not involve
a state cycle.

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

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

index aa5427c09844888c18bf4f4be54a1cf89bc79b21..5ea819fc50a752b895009a10cb2e884aaadc2970 100644 (file)
@@ -598,6 +598,9 @@ func (e *escaper) escapeText(c context, n *parse.TextNode) context {
                        b.Write(s[written:cs])
                        written = i1
                }
+               if i == i1 && c.state == c1.state {
+                       panic(fmt.Sprintf("infinite loop from %v to %v on %q..%q", c, c1, s[:i], s[i:]))
+               }
                c, i = c1, i1
        }
 
index a3dab4cc85e423182e972c2cba6cc93d46760e64..da3c0119615784674740ef2d2839f6819c9d8b04 100644 (file)
@@ -904,6 +904,10 @@ func TestErrors(t *testing.T) {
                        `<a style=font:'Arial'>`,
                        `exp/template/html:z: "'" in unquoted attr: "font:'Arial'"`,
                },
+               {
+                       `<a=foo>`,
+                       `: expected space, attr name, or end of tag, but got "=foo>"`,
+               },
        }
 
        for _, test := range tests {
index 15548043b69a393fc24b1b112b85520f6893bbe2..b8e02b239c91e8b6e50af2de4ad1c393f4335955 100644 (file)
@@ -100,26 +100,30 @@ func tTag(c context, s []byte) (context, int) {
                return context{state: stateError, err: err}, len(s)
        }
        state, attr := stateTag, attrNone
-       if i != j {
-               canonAttrName := strings.ToLower(string(s[i:j]))
-               switch attrType[canonAttrName] {
-               case contentTypeURL:
-                       attr = attrURL
-               case contentTypeCSS:
-                       attr = attrStyle
-               case contentTypeJS:
+       if i == j {
+               return context{
+                       state: stateError,
+                       err:   errorf(ErrBadHTML, 0, "expected space, attr name, or end of tag, but got %q", s[i:]),
+               }, len(s)
+       }
+       canonAttrName := strings.ToLower(string(s[i:j]))
+       switch attrType[canonAttrName] {
+       case contentTypeURL:
+               attr = attrURL
+       case contentTypeCSS:
+               attr = attrStyle
+       case contentTypeJS:
+               attr = attrScript
+       default:
+               if strings.HasPrefix(canonAttrName, "on") {
                        attr = attrScript
-               default:
-                       if strings.HasPrefix(canonAttrName, "on") {
-                               attr = attrScript
-                       }
-               }
-               if j == len(s) {
-                       state = stateAttrName
-               } else {
-                       state = stateAfterName
                }
        }
+       if j == len(s) {
+               state = stateAttrName
+       } else {
+               state = stateAfterName
+       }
        return context{state: state, element: c.element, attr: attr}, j
 }