Commit 918c8230 authored by Nodir Turakulov's avatar Nodir Turakulov Committed by Rob Pike

html/template: preserve attr in stateBeforeValue

Context: #12149. The problem there is that contents of
<script type="text/template"> are treated as JS, and thus // is treated
as regexp.

Preserve context.attr while we are in the attribute, in particular in
stateBeforeValue, so we have attr when reading attr value.

Next CL will actually fix the bug.

Change-Id: I99add2237b0885ecdcc08b4f7c25d0af99173e53
Reviewed-on: https://go-review.googlesource.com/14335Reviewed-by: default avatarRob Pike <r@golang.org>
parent 65994500
...@@ -310,7 +310,8 @@ func (e element) String() string { ...@@ -310,7 +310,8 @@ func (e element) String() string {
return fmt.Sprintf("illegal element %d", int(e)) return fmt.Sprintf("illegal element %d", int(e))
} }
// attr identifies the most recent HTML attribute when inside a start tag. // attr identifies the current HTML attribute when inside the attribute,
// that is, starting from stateAttrName until stateTag/stateText (exclusive).
type attr uint8 type attr uint8
const ( const (
......
...@@ -1054,7 +1054,7 @@ func TestEscapeText(t *testing.T) { ...@@ -1054,7 +1054,7 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a href=x`, `<a href=x`,
context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href=x `, `<a href=x `,
...@@ -1070,7 +1070,7 @@ func TestEscapeText(t *testing.T) { ...@@ -1070,7 +1070,7 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a href ='`, `<a href ='`,
context{state: stateURL, delim: delimSingleQuote}, context{state: stateURL, delim: delimSingleQuote, attr: attrURL},
}, },
{ {
`<a href=''`, `<a href=''`,
...@@ -1078,7 +1078,7 @@ func TestEscapeText(t *testing.T) { ...@@ -1078,7 +1078,7 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a href= "`, `<a href= "`,
context{state: stateURL, delim: delimDoubleQuote}, context{state: stateURL, delim: delimDoubleQuote, attr: attrURL},
}, },
{ {
`<a href=""`, `<a href=""`,
...@@ -1090,35 +1090,35 @@ func TestEscapeText(t *testing.T) { ...@@ -1090,35 +1090,35 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a HREF='http:`, `<a HREF='http:`,
context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a Href='/`, `<a Href='/`,
context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href='"`, `<a href='"`,
context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href="'`, `<a href="'`,
context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href='&apos;`, `<a href='&apos;`,
context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSingleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href="&quot;`, `<a href="&quot;`,
context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href="&#34;`, `<a href="&#34;`,
context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<a href=&quot;`, `<a href=&quot;`,
context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery}, context{state: stateURL, delim: delimSpaceOrTagEnd, urlPart: urlPartPreQuery, attr: attrURL},
}, },
{ {
`<img alt="1">`, `<img alt="1">`,
...@@ -1138,83 +1138,83 @@ func TestEscapeText(t *testing.T) { ...@@ -1138,83 +1138,83 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a onclick="`, `<a onclick="`,
context{state: stateJS, delim: delimDoubleQuote}, context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="//foo`, `<a onclick="//foo`,
context{state: stateJSLineCmt, delim: delimDoubleQuote}, context{state: stateJSLineCmt, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
"<a onclick='//\n", "<a onclick='//\n",
context{state: stateJS, delim: delimSingleQuote}, context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
}, },
{ {
"<a onclick='//\r\n", "<a onclick='//\r\n",
context{state: stateJS, delim: delimSingleQuote}, context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
}, },
{ {
"<a onclick='//\u2028", "<a onclick='//\u2028",
context{state: stateJS, delim: delimSingleQuote}, context{state: stateJS, delim: delimSingleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/*`, `<a onclick="/*`,
context{state: stateJSBlockCmt, delim: delimDoubleQuote}, context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/*/`, `<a onclick="/*/`,
context{state: stateJSBlockCmt, delim: delimDoubleQuote}, context{state: stateJSBlockCmt, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/**/`, `<a onclick="/**/`,
context{state: stateJS, delim: delimDoubleQuote}, context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onkeypress="&quot;`, `<a onkeypress="&quot;`,
context{state: stateJSDqStr, delim: delimDoubleQuote}, context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick='&quot;foo&quot;`, `<a onclick='&quot;foo&quot;`,
context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimSingleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<a onclick=&#39;foo&#39;`, `<a onclick=&#39;foo&#39;`,
context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimSpaceOrTagEnd, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<a onclick=&#39;foo`, `<a onclick=&#39;foo`,
context{state: stateJSSqStr, delim: delimSpaceOrTagEnd}, context{state: stateJSSqStr, delim: delimSpaceOrTagEnd, attr: attrScript},
}, },
{ {
`<a onclick="&quot;foo'`, `<a onclick="&quot;foo'`,
context{state: stateJSDqStr, delim: delimDoubleQuote}, context{state: stateJSDqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="'foo&quot;`, `<a onclick="'foo&quot;`,
context{state: stateJSSqStr, delim: delimDoubleQuote}, context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<A ONCLICK="'`, `<A ONCLICK="'`,
context{state: stateJSSqStr, delim: delimDoubleQuote}, context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/`, `<a onclick="/`,
context{state: stateJSRegexp, delim: delimDoubleQuote}, context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="'foo'`, `<a onclick="'foo'`,
context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<a onclick="'foo\'`, `<a onclick="'foo\'`,
context{state: stateJSSqStr, delim: delimDoubleQuote}, context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="'foo\'`, `<a onclick="'foo\'`,
context{state: stateJSSqStr, delim: delimDoubleQuote}, context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/foo/`, `<a onclick="/foo/`,
context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<script>/foo/ /=`, `<script>/foo/ /=`,
...@@ -1222,111 +1222,111 @@ func TestEscapeText(t *testing.T) { ...@@ -1222,111 +1222,111 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a onclick="1 /foo`, `<a onclick="1 /foo`,
context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<a onclick="1 /*c*/ /foo`, `<a onclick="1 /*c*/ /foo`,
context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<a onclick="/foo[/]`, `<a onclick="/foo[/]`,
context{state: stateJSRegexp, delim: delimDoubleQuote}, context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/foo\/`, `<a onclick="/foo\/`,
context{state: stateJSRegexp, delim: delimDoubleQuote}, context{state: stateJSRegexp, delim: delimDoubleQuote, attr: attrScript},
}, },
{ {
`<a onclick="/foo/`, `<a onclick="/foo/`,
context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp}, context{state: stateJS, delim: delimDoubleQuote, jsCtx: jsCtxDivOp, attr: attrScript},
}, },
{ {
`<input checked style="`, `<input checked style="`,
context{state: stateCSS, delim: delimDoubleQuote}, context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="//`, `<a style="//`,
context{state: stateCSSLineCmt, delim: delimDoubleQuote}, context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="//</script>`, `<a style="//</script>`,
context{state: stateCSSLineCmt, delim: delimDoubleQuote}, context{state: stateCSSLineCmt, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
"<a style='//\n", "<a style='//\n",
context{state: stateCSS, delim: delimSingleQuote}, context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
}, },
{ {
"<a style='//\r", "<a style='//\r",
context{state: stateCSS, delim: delimSingleQuote}, context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
}, },
{ {
`<a style="/*`, `<a style="/*`,
context{state: stateCSSBlockCmt, delim: delimDoubleQuote}, context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="/*/`, `<a style="/*/`,
context{state: stateCSSBlockCmt, delim: delimDoubleQuote}, context{state: stateCSSBlockCmt, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="/**/`, `<a style="/**/`,
context{state: stateCSS, delim: delimDoubleQuote}, context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: '`, `<a style="background: '`,
context{state: stateCSSSqStr, delim: delimDoubleQuote}, context{state: stateCSSSqStr, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: &quot;`, `<a style="background: &quot;`,
context{state: stateCSSDqStr, delim: delimDoubleQuote}, context{state: stateCSSDqStr, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: '/foo?img=`, `<a style="background: '/foo?img=`,
context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag}, context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
}, },
{ {
`<a style="background: '/`, `<a style="background: '/`,
context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSSqStr, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url(&#x22;/`, `<a style="background: url(&#x22;/`,
context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSDqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url('/`, `<a style="background: url('/`,
context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url('/)`, `<a style="background: url('/)`,
context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url('/ `, `<a style="background: url('/ `,
context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSSqURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url(/`, `<a style="background: url(/`,
context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery}, context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartPreQuery, attr: attrStyle},
}, },
{ {
`<a style="background: url( `, `<a style="background: url( `,
context{state: stateCSSURL, delim: delimDoubleQuote}, context{state: stateCSSURL, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: url( /image?name=`, `<a style="background: url( /image?name=`,
context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag}, context{state: stateCSSURL, delim: delimDoubleQuote, urlPart: urlPartQueryOrFrag, attr: attrStyle},
}, },
{ {
`<a style="background: url(x)`, `<a style="background: url(x)`,
context{state: stateCSS, delim: delimDoubleQuote}, context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: url('x'`, `<a style="background: url('x'`,
context{state: stateCSS, delim: delimDoubleQuote}, context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<a style="background: url( x `, `<a style="background: url( x `,
context{state: stateCSS, delim: delimDoubleQuote}, context{state: stateCSS, delim: delimDoubleQuote, attr: attrStyle},
}, },
{ {
`<!-- foo`, `<!-- foo`,
...@@ -1466,7 +1466,7 @@ func TestEscapeText(t *testing.T) { ...@@ -1466,7 +1466,7 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<a svg:style='`, `<a svg:style='`,
context{state: stateCSS, delim: delimSingleQuote}, context{state: stateCSS, delim: delimSingleQuote, attr: attrStyle},
}, },
{ {
`<svg:font-face`, `<svg:font-face`,
...@@ -1474,7 +1474,11 @@ func TestEscapeText(t *testing.T) { ...@@ -1474,7 +1474,11 @@ func TestEscapeText(t *testing.T) {
}, },
{ {
`<svg:a svg:onclick="`, `<svg:a svg:onclick="`,
context{state: stateJS, delim: delimDoubleQuote}, context{state: stateJS, delim: delimDoubleQuote, attr: attrScript},
},
{
`<svg:a svg:onclick="x()">`,
context{},
}, },
} }
......
...@@ -169,7 +169,7 @@ func tBeforeValue(c context, s []byte) (context, int) { ...@@ -169,7 +169,7 @@ func tBeforeValue(c context, s []byte) (context, int) {
case '"': case '"':
delim, i = delimDoubleQuote, i+1 delim, i = delimDoubleQuote, i+1
} }
c.state, c.delim, c.attr = attrStartStates[c.attr], delim, attrNone c.state, c.delim = attrStartStates[c.attr], delim
return c, i return c, i
} }
......
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