src/html/template/context.go | 6 +++++- src/html/template/escape.go | 5 ++++- src/html/template/escape_test.go | 10 ++++++++++ src/html/template/state_string.go | 26 ++++++++++++++------------ src/html/template/transition.go | 80 ++++++++++++++++++++++++++++++++++------------------- diff --git a/src/html/template/context.go b/src/html/template/context.go index c28fb0c5ea8ef30ddbcb4ffec6d0bef34756ad76..e07a0c4a027d06fd1ae74241fc50bd70a287dddc 100644 --- a/src/html/template/context.go +++ b/src/html/template/context.go @@ -128,6 +128,10 @@ // stateJSBlockCmt occurs inside a JavaScript /* block comment */. stateJSBlockCmt // stateJSLineCmt occurs inside a JavaScript // line comment. stateJSLineCmt + // stateJSHTMLOpenCmt occurs inside a JavaScript HTML-like comment. + stateJSHTMLCloseCmt // stateCSS occurs inside a `, diff --git a/src/html/template/state_string.go b/src/html/template/state_string.go index 6fb1a6eeb0e746a4b2257bd6623ab96f28dc7f84..be7a9205111f238c6d86fabd40a750247251e96a 100644 --- a/src/html/template/state_string.go +++ b/src/html/template/state_string.go @@ -25,21 +25,23 @@ _ = x[stateJSBqStr-13] _ = x[stateJSRegexp-14] _ = x[stateJSBlockCmt-15] _ = x[stateJSLineCmt-16] - _ = x[stateCSS-17] - _ = x[stateCSSDqStr-18] - _ = x[stateCSSSqStr-19] - _ = x[stateCSSDqURL-20] - _ = x[stateCSSSqURL-21] - _ = x[stateCSSURL-22] - _ = x[stateCSSBlockCmt-23] - _ = x[stateCSSLineCmt-24] - _ = x[stateError-25] - _ = x[stateDead-26] + _ = x[stateJSHTMLOpenCmt-17] + _ = x[stateJSHTMLCloseCmt-18] + _ = x[stateCSS-19] + _ = x[stateCSSDqStr-20] + _ = x[stateCSSSqStr-21] + _ = x[stateCSSDqURL-22] + _ = x[stateCSSSqURL-23] + _ = x[stateCSSURL-24] + _ = x[stateCSSBlockCmt-25] + _ = x[stateCSSLineCmt-26] + _ = x[stateError-27] + _ = x[stateDead-28] } -const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" +const _state_name = "stateTextstateTagstateAttrNamestateAfterNamestateBeforeValuestateHTMLCmtstateRCDATAstateAttrstateURLstateSrcsetstateJSstateJSDqStrstateJSSqStrstateJSBqStrstateJSRegexpstateJSBlockCmtstateJSLineCmtstateJSHTMLOpenCmtstateJSHTMLCloseCmtstateCSSstateCSSDqStrstateCSSSqStrstateCSSDqURLstateCSSSqURLstateCSSURLstateCSSBlockCmtstateCSSLineCmtstateErrorstateDead" -var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 204, 217, 230, 243, 256, 267, 283, 298, 308, 317} +var _state_index = [...]uint16{0, 9, 17, 30, 44, 60, 72, 83, 92, 100, 111, 118, 130, 142, 154, 167, 182, 196, 214, 233, 241, 254, 267, 280, 293, 304, 320, 335, 345, 354} func (i state) String() string { if i >= state(len(_state_index)-1) { diff --git a/src/html/template/transition.go b/src/html/template/transition.go index 3b9fbfb68f536d1858863f6bc7dab8d90a92d69e..d8ff18abb08200a769f56b83af1311c7181fa13d 100644 --- a/src/html/template/transition.go +++ b/src/html/template/transition.go @@ -14,32 +14,34 @@ // A transition function takes a context and template text input, and returns // the updated context and the number of bytes consumed from the front of the // input. var transitionFunc = [...]func(context, []byte) (context, int){ - stateText: tText, - stateTag: tTag, - stateAttrName: tAttrName, - stateAfterName: tAfterName, - stateBeforeValue: tBeforeValue, - stateHTMLCmt: tHTMLCmt, - stateRCDATA: tSpecialTagEnd, - stateAttr: tAttr, - stateURL: tURL, - stateSrcset: tURL, - stateJS: tJS, - stateJSDqStr: tJSDelimited, - stateJSSqStr: tJSDelimited, - stateJSBqStr: tJSDelimited, - stateJSRegexp: tJSDelimited, - stateJSBlockCmt: tBlockCmt, - stateJSLineCmt: tLineCmt, - stateCSS: tCSS, - stateCSSDqStr: tCSSStr, - stateCSSSqStr: tCSSStr, - stateCSSDqURL: tCSSStr, - stateCSSSqURL: tCSSStr, - stateCSSURL: tCSSStr, - stateCSSBlockCmt: tBlockCmt, - stateCSSLineCmt: tLineCmt, - stateError: tError, + stateText: tText, + stateTag: tTag, + stateAttrName: tAttrName, + stateAfterName: tAfterName, + stateBeforeValue: tBeforeValue, + stateHTMLCmt: tHTMLCmt, + stateRCDATA: tSpecialTagEnd, + stateAttr: tAttr, + stateURL: tURL, + stateSrcset: tURL, + stateJS: tJS, + stateJSDqStr: tJSDelimited, + stateJSSqStr: tJSDelimited, + stateJSBqStr: tJSDelimited, + stateJSRegexp: tJSDelimited, + stateJSBlockCmt: tBlockCmt, + stateJSLineCmt: tLineCmt, + stateJSHTMLOpenCmt: tLineCmt, + stateJSHTMLCloseCmt: tLineCmt, + stateCSS: tCSS, + stateCSSDqStr: tCSSStr, + stateCSSSqStr: tCSSStr, + stateCSSDqURL: tCSSStr, + stateCSSSqURL: tCSSStr, + stateCSSURL: tCSSStr, + stateCSSBlockCmt: tBlockCmt, + stateCSSLineCmt: tLineCmt, + stateError: tError, } var commentStart = []byte("" + // as if it were actually prefixed with "//" and move on. + case '<': + if i+3 < len(s) && bytes.Equal(commentStart, s[i:i+4]) { + c.state, i = stateJSHTMLOpenCmt, i+3 + } + case '-': + if i+2 < len(s) && bytes.Equal(commentEnd, s[i:i+3]) { + c.state, i = stateJSHTMLCloseCmt, i+2 + } + // ECMAScript also supports "hashbang" comment lines, see Section 12.5. + case '#': + if i+1 < len(s) && s[i+1] == '!' { + c.state, i = stateJSLineCmt, i+1 } default: panic("unreachable") @@ -372,12 +394,12 @@ } return c, i + 2 } -// tLineCmt is the context transition function for //comment states. +// tLineCmt is the context transition function for //comment states, and the JS HTML-like comment state. func tLineCmt(c context, s []byte) (context, int) { var lineTerminators string var endState state switch c.state { - case stateJSLineCmt: + case stateJSLineCmt, stateJSHTMLOpenCmt, stateJSHTMLCloseCmt: lineTerminators, endState = "\n\r\u2028\u2029", stateJS case stateCSSLineCmt: lineTerminators, endState = "\n\f\r", stateCSS