diff options
author | Colin Cross <ccross@android.com> | 2023-11-08 14:34:51 -0800 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2023-11-09 08:50:14 -0800 |
commit | 68a2d6d0813d288a1149f79a7223284fa2f5559f (patch) | |
tree | 143cca9a296a439937d2377dda45b0a02a58127b /src/html/template/escape_test.go | |
parent | 041649c429280aac67ca954c19cbbf0adc27312f (diff) | |
parent | ed817f1c4055a559a94afffecbb91c78e4f39942 (diff) | |
download | go-68a2d6d0813d288a1149f79a7223284fa2f5559f.tar.gz |
Merge tag 'upstream-go1.21.4'
Test: builds
Change-Id: I51ebec3387045e2d403ed4cb8d29e890930c802a
Diffstat (limited to 'src/html/template/escape_test.go')
-rw-r--r-- | src/html/template/escape_test.go | 138 |
1 files changed, 108 insertions, 30 deletions
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go index 12add077c3..8a4f62e92f 100644 --- a/src/html/template/escape_test.go +++ b/src/html/template/escape_test.go @@ -504,6 +504,31 @@ func TestEscape(t *testing.T) { "<script>var a \nd</script>", }, { + "JS HTML-like comments", + "<script>before <!-- beep\nbetween\nbefore-->boop\n</script>", + "<script>before \nbetween\nbefore\n</script>", + }, + { + "JS hashbang comment", + "<script>#! beep\n</script>", + "<script>\n</script>", + }, + { + "Special tags in <script> string literals", + `<script>var a = "asd < 123 <!-- 456 < fgh <script jkl < 789 </script"</script>`, + `<script>var a = "asd < 123 \x3C!-- 456 < fgh \x3Cscript jkl < 789 \x3C/script"</script>`, + }, + { + "Special tags in <script> string literals (mixed case)", + `<script>var a = "<!-- <ScripT </ScripT"</script>`, + `<script>var a = "\x3C!-- \x3CScripT \x3C/ScripT"</script>`, + }, + { + "Special tags in <script> regex literals (mixed case)", + `<script>var a = /<!-- <ScripT </ScripT/</script>`, + `<script>var a = /\x3C!-- \x3CScripT \x3C/ScripT/</script>`, + }, + { "CSS comments", "<style>p// paragraph\n" + `{border: 1px/* color */{{"#00f"}}}</style>`, @@ -678,38 +703,49 @@ func TestEscape(t *testing.T) { `<img srcset={{",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"}}>`, `<img srcset=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>`, }, + { + "unquoted empty attribute value (plaintext)", + "<p name={{.U}}>", + "<p name=ZgotmplZ>", + }, + { + "unquoted empty attribute value (url)", + "<p href={{.U}}>", + "<p href=ZgotmplZ>", + }, + { + "quoted empty attribute value", + "<p name=\"{{.U}}\">", + "<p name=\"\">", + }, } for _, test := range tests { - tmpl := New(test.name) - tmpl = Must(tmpl.Parse(test.input)) - // Check for bug 6459: Tree field was not set in Parse. - if tmpl.Tree != tmpl.text.Tree { - t.Errorf("%s: tree not set properly", test.name) - continue - } - b := new(strings.Builder) - if err := tmpl.Execute(b, data); err != nil { - t.Errorf("%s: template execution failed: %s", test.name, err) - continue - } - if w, g := test.output, b.String(); w != g { - t.Errorf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) - continue - } - b.Reset() - if err := tmpl.Execute(b, pdata); err != nil { - t.Errorf("%s: template execution failed for pointer: %s", test.name, err) - continue - } - if w, g := test.output, b.String(); w != g { - t.Errorf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) - continue - } - if tmpl.Tree != tmpl.text.Tree { - t.Errorf("%s: tree mismatch", test.name) - continue - } + t.Run(test.name, func(t *testing.T) { + tmpl := New(test.name) + tmpl = Must(tmpl.Parse(test.input)) + // Check for bug 6459: Tree field was not set in Parse. + if tmpl.Tree != tmpl.text.Tree { + t.Fatalf("%s: tree not set properly", test.name) + } + b := new(strings.Builder) + if err := tmpl.Execute(b, data); err != nil { + t.Fatalf("%s: template execution failed: %s", test.name, err) + } + if w, g := test.output, b.String(); w != g { + t.Fatalf("%s: escaped output: want\n\t%q\ngot\n\t%q", test.name, w, g) + } + b.Reset() + if err := tmpl.Execute(b, pdata); err != nil { + t.Fatalf("%s: template execution failed for pointer: %s", test.name, err) + } + if w, g := test.output, b.String(); w != g { + t.Fatalf("%s: escaped output for pointer: want\n\t%q\ngot\n\t%q", test.name, w, g) + } + if tmpl.Tree != tmpl.text.Tree { + t.Fatalf("%s: tree mismatch", test.name) + } + }) } } @@ -936,6 +972,10 @@ func TestErrors(t *testing.T) { "{{range .Items}}<a{{if .X}}{{end}}>{{if .X}}{{break}}{{end}}{{end}}", "", }, + { + "<script>var a = `${a+b}`</script>`", + "", + }, // Error cases. { "{{if .Cond}}<a{{end}}", @@ -1082,6 +1122,10 @@ func TestErrors(t *testing.T) { // html is allowed since it is the last command in the pipeline, but urlquery is not. `predefined escaper "urlquery" disallowed in template`, }, + { + "<script>var tmpl = `asd {{.}}`;</script>", + `{{.}} appears in a JS template literal`, + }, } for _, test := range tests { buf := new(bytes.Buffer) @@ -1304,6 +1348,10 @@ func TestEscapeText(t *testing.T) { context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript}, }, { + "<a onclick=\"`foo", + context{state: stateJSBqStr, delim: delimDoubleQuote, attr: attrScript}, + }, + { `<A ONCLICK="'`, context{state: stateJSSqStr, delim: delimDoubleQuote, attr: attrScript}, }, @@ -1500,8 +1548,38 @@ func TestEscapeText(t *testing.T) { context{state: stateJS, element: elementScript}, }, { + // <script and </script tags are escaped, so </script> should not + // cause us to exit the JS state. `<script>document.write("<script>alert(1)</script>");`, - context{state: stateText}, + context{state: stateJS, element: elementScript}, + }, + { + `<script>document.write("<script>`, + context{state: stateJSDqStr, element: elementScript}, + }, + { + `<script>document.write("<script>alert(1)</script>`, + context{state: stateJSDqStr, element: elementScript}, + }, + { + `<script>document.write("<script>alert(1)<!--`, + context{state: stateJSDqStr, element: elementScript}, + }, + { + `<script>document.write("<script>alert(1)</Script>");`, + context{state: stateJS, element: elementScript}, + }, + { + `<script>document.write("<!--");`, + context{state: stateJS, element: elementScript}, + }, + { + `<script>let a = /</script`, + context{state: stateJSRegexp, element: elementScript}, + }, + { + `<script>let a = /</script/`, + context{state: stateJS, element: elementScript, jsCtx: jsCtxDivOp}, }, { `<script type="text/template">`, |