Skip to content

Commit 9c7f7c1

Browse files
committed
fix
1 parent 145b583 commit 9c7f7c1

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

modules/templates/helper.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -294,17 +294,15 @@ func timeEstimateString(timeSec any) string {
294294
return util.TimeEstimateString(v)
295295
}
296296

297-
type QueryString string
298-
299-
func queryBuild(a ...any) QueryString {
297+
func queryBuild(a ...any) template.URL {
300298
var s string
301299
if len(a)%2 == 1 {
302300
if v, ok := a[0].(string); ok {
303301
if v == "" || (v[0] != '?' && v[0] != '&') {
304302
panic("queryBuild: invalid argument")
305303
}
306304
s = v
307-
} else if v, ok := a[0].(QueryString); ok {
305+
} else if v, ok := a[0].(template.URL); ok {
308306
s = string(v)
309307
} else {
310308
panic("queryBuild: invalid argument")
@@ -356,7 +354,7 @@ func queryBuild(a ...any) QueryString {
356354
if s != "" && s != "&" && s[len(s)-1] == '&' {
357355
s = s[:len(s)-1]
358356
}
359-
return QueryString(s)
357+
return template.URL(s)
360358
}
361359

362360
func panicIfDevOrTesting() {

modules/templates/helper_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11+
"code.gitea.io/gitea/modules/htmlutil"
1112
"code.gitea.io/gitea/modules/util"
1213

1314
"github.com/stretchr/testify/assert"
@@ -102,3 +103,37 @@ func TestTemplateTruthy(t *testing.T) {
102103
}
103104
assert.True(t, truthyCount != 0 && truthyCount != len(cases))
104105
}
106+
107+
func TestTemplateEscape(t *testing.T) {
108+
execTmpl := func(code string) string {
109+
tmpl := template.New("test")
110+
tmpl.Funcs(template.FuncMap{"QueryBuild": queryBuild, "HTMLFormat": htmlutil.HTMLFormat})
111+
template.Must(tmpl.Parse(code))
112+
w := &strings.Builder{}
113+
assert.NoError(t, tmpl.Execute(w, nil))
114+
return w.String()
115+
}
116+
117+
t.Run("Golang URL Escape", func(t *testing.T) {
118+
// Golang template considers "href", "*src*", "*uri", "*url*" (and more) ... as contentTypeURL and does auto-escaping
119+
actual := execTmpl(`<a href="?a={{"%"}}"></a>`)
120+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
121+
actual = execTmpl(`<a data-xxx-url="?a={{"%"}}"></a>`)
122+
assert.Equal(t, `<a data-xxx-url="?a=%25"></a>`, actual)
123+
})
124+
t.Run("Golang URL No-escape", func(t *testing.T) {
125+
// non-URL content isn't auto-escaped
126+
actual := execTmpl(`<a data-link="?a={{"%"}}"></a>`)
127+
assert.Equal(t, `<a data-link="?a=%"></a>`, actual)
128+
})
129+
t.Run("QueryBuild", func(t *testing.T) {
130+
actual := execTmpl(`<a href="{{QueryBuild "?" "a" "%"}}"></a>`)
131+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
132+
actual = execTmpl(`<a href="?{{QueryBuild "a" "%"}}"></a>`)
133+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
134+
})
135+
t.Run("HTMLFormat", func(t *testing.T) {
136+
actual := execTmpl("{{HTMLFormat `<a k=\"%s\">%s</a>` `\"` `<>`}}")
137+
assert.Equal(t, `<a k="&#34;">&lt;&gt;</a>`, actual)
138+
})
139+
}

0 commit comments

Comments
 (0)