Skip to content

Commit 8cc2e94

Browse files
committed
chore: add unit test and benchmark to URL function
1 parent 6365f94 commit 8cc2e94

File tree

4 files changed

+78
-20
lines changed

4 files changed

+78
-20
lines changed

.version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.2.648
1+
0.2.655

runtime.go

-19
Original file line numberDiff line numberDiff line change
@@ -461,25 +461,6 @@ func SanitizeCSS[T ~string](property string, value T) SafeCSS {
461461
return SafeCSS(p + ":" + v + ";")
462462
}
463463

464-
// Hyperlink sanitization.
465-
466-
// FailedSanitizationURL is returned if a URL fails sanitization checks.
467-
const FailedSanitizationURL = SafeURL("about:invalid#TemplFailedSanitizationURL")
468-
469-
// URL sanitizes the input string s and returns a SafeURL.
470-
func URL(s string) SafeURL {
471-
if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
472-
protocol := s[:i]
473-
if !strings.EqualFold(protocol, "http") && !strings.EqualFold(protocol, "https") && !strings.EqualFold(protocol, "mailto") && !strings.EqualFold(protocol, "tel") && !strings.EqualFold(protocol, "ftp") && !strings.EqualFold(protocol, "ftps") {
474-
return FailedSanitizationURL
475-
}
476-
}
477-
return SafeURL(s)
478-
}
479-
480-
// SafeURL is a URL that has been sanitized.
481-
type SafeURL string
482-
483464
// Attributes is an alias to map[string]any made for spread attributes.
484465
type Attributes map[string]any
485466

url.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package templ
2+
3+
import "strings"
4+
5+
// FailedSanitizationURL is returned if a URL fails sanitization checks.
6+
const FailedSanitizationURL = SafeURL("about:invalid#TemplFailedSanitizationURL")
7+
8+
// URL sanitizes the input string s and returns a SafeURL.
9+
func URL(s string) SafeURL {
10+
if i := strings.IndexRune(s, ':'); i >= 0 && !strings.ContainsRune(s[:i], '/') {
11+
protocol := s[:i]
12+
if !strings.EqualFold(protocol, "http") && !strings.EqualFold(protocol, "https") && !strings.EqualFold(protocol, "mailto") && !strings.EqualFold(protocol, "tel") && !strings.EqualFold(protocol, "ftp") && !strings.EqualFold(protocol, "ftps") {
13+
return FailedSanitizationURL
14+
}
15+
}
16+
return SafeURL(s)
17+
}
18+
19+
// SafeURL is a URL that has been sanitized.
20+
type SafeURL string

url_test.go

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package templ
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
type urlTest struct {
9+
url string
10+
expectSanitized bool
11+
}
12+
13+
var urlTests = []urlTest{
14+
{"//example.com", false},
15+
{"/", false},
16+
{"/index", false},
17+
{"http://example.com", false},
18+
{"https://example.com", false},
19+
{"mailto:[email protected]", false},
20+
{"tel:+1234567890", false},
21+
{"ftp://example.com", false},
22+
{"ftps://example.com", false},
23+
{"irc://example.com", true},
24+
{"bitcoin://example.com", true},
25+
}
26+
27+
func testURL(t *testing.T, url string, expectSanitized bool) {
28+
u := URL(url)
29+
wasSanitized := u == FailedSanitizationURL
30+
if expectSanitized != wasSanitized {
31+
t.Errorf("expected sanitized=%v, got %v", expectSanitized, wasSanitized)
32+
}
33+
}
34+
35+
func TestURL(t *testing.T) {
36+
for _, test := range urlTests {
37+
t.Run(test.url, func(t *testing.T) {
38+
testURL(t, test.url, test.expectSanitized)
39+
})
40+
test.url = strings.ToUpper(test.url)
41+
t.Run(strings.ToUpper(test.url), func(t *testing.T) {
42+
testURL(t, test.url, test.expectSanitized)
43+
})
44+
}
45+
}
46+
47+
func BenchmarkURL(b *testing.B) {
48+
for i := 0; i < b.N; i++ {
49+
for _, test := range urlTests {
50+
u := URL(test.url)
51+
wasSanitized := u == FailedSanitizationURL
52+
if test.expectSanitized != wasSanitized {
53+
b.Errorf("expected sanitized=%v, got %v", test.expectSanitized, wasSanitized)
54+
}
55+
}
56+
}
57+
}

0 commit comments

Comments
 (0)