aboutsummaryrefslogtreecommitdiff
path: root/src/html/template/escape_test.go
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-11-08 14:34:51 -0800
committerColin Cross <ccross@android.com>2023-11-09 08:50:14 -0800
commit68a2d6d0813d288a1149f79a7223284fa2f5559f (patch)
tree143cca9a296a439937d2377dda45b0a02a58127b /src/html/template/escape_test.go
parent041649c429280aac67ca954c19cbbf0adc27312f (diff)
parented817f1c4055a559a94afffecbb91c78e4f39942 (diff)
downloadgo-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.go138
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">`,