1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package template
6
7import (
8	"testing"
9)
10
11func TestURLNormalizer(t *testing.T) {
12	tests := []struct {
13		url, want string
14	}{
15		{"", ""},
16		{
17			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
18			"http://example.com:80/foo/bar?q=foo%20&bar=x+y#frag",
19		},
20		{" ", "%20"},
21		{"%7c", "%7c"},
22		{"%7C", "%7C"},
23		{"%2", "%252"},
24		{"%", "%25"},
25		{"%z", "%25z"},
26		{"/foo|bar/%5c\u1234", "/foo%7cbar/%5c%e1%88%b4"},
27	}
28	for _, test := range tests {
29		if got := urlNormalizer(test.url); test.want != got {
30			t.Errorf("%q: want\n\t%q\nbut got\n\t%q", test.url, test.want, got)
31		}
32		if test.want != urlNormalizer(test.want) {
33			t.Errorf("not idempotent: %q", test.want)
34		}
35	}
36}
37
38func TestURLFilters(t *testing.T) {
39	input := ("\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f" +
40		"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
41		` !"#$%&'()*+,-./` +
42		`0123456789:;<=>?` +
43		`@ABCDEFGHIJKLMNO` +
44		`PQRSTUVWXYZ[\]^_` +
45		"`abcdefghijklmno" +
46		"pqrstuvwxyz{|}~\x7f" +
47		"\u00A0\u0100\u2028\u2029\ufeff\U0001D11E")
48
49	tests := []struct {
50		name    string
51		escaper func(...any) string
52		escaped string
53	}{
54		{
55			"urlEscaper",
56			urlEscaper,
57			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
58				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
59				"%20%21%22%23%24%25%26%27%28%29%2a%2b%2c-.%2f" +
60				"0123456789%3a%3b%3c%3d%3e%3f" +
61				"%40ABCDEFGHIJKLMNO" +
62				"PQRSTUVWXYZ%5b%5c%5d%5e_" +
63				"%60abcdefghijklmno" +
64				"pqrstuvwxyz%7b%7c%7d~%7f" +
65				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
66		},
67		{
68			"urlNormalizer",
69			urlNormalizer,
70			"%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f" +
71				"%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f" +
72				"%20!%22#$%25&%27%28%29*+,-./" +
73				"0123456789:;%3c=%3e?" +
74				"@ABCDEFGHIJKLMNO" +
75				"PQRSTUVWXYZ[%5c]%5e_" +
76				"%60abcdefghijklmno" +
77				"pqrstuvwxyz%7b%7c%7d~%7f" +
78				"%c2%a0%c4%80%e2%80%a8%e2%80%a9%ef%bb%bf%f0%9d%84%9e",
79		},
80	}
81
82	for _, test := range tests {
83		if s := test.escaper(input); s != test.escaped {
84			t.Errorf("%s: want\n\t%q\ngot\n\t%q", test.name, test.escaped, s)
85			continue
86		}
87	}
88}
89
90func TestSrcsetFilter(t *testing.T) {
91	tests := []struct {
92		name  string
93		input string
94		want  string
95	}{
96		{
97			"one ok",
98			"http://example.com/img.png",
99			"http://example.com/img.png",
100		},
101		{
102			"one ok with metadata",
103			" /img.png 200w",
104			" /img.png 200w",
105		},
106		{
107			"one bad",
108			"javascript:alert(1) 200w",
109			"#ZgotmplZ",
110		},
111		{
112			"two ok",
113			"foo.png, bar.png",
114			"foo.png, bar.png",
115		},
116		{
117			"left bad",
118			"javascript:alert(1), /foo.png",
119			"#ZgotmplZ, /foo.png",
120		},
121		{
122			"right bad",
123			"/bogus#, javascript:alert(1)",
124			"/bogus#,#ZgotmplZ",
125		},
126	}
127
128	for _, test := range tests {
129		if got := srcsetFilterAndEscaper(test.input); got != test.want {
130			t.Errorf("%s: srcsetFilterAndEscaper(%q) want %q != %q", test.name, test.input, test.want, got)
131		}
132	}
133}
134
135func BenchmarkURLEscaper(b *testing.B) {
136	for i := 0; i < b.N; i++ {
137		urlEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
138	}
139}
140
141func BenchmarkURLEscaperNoSpecials(b *testing.B) {
142	for i := 0; i < b.N; i++ {
143		urlEscaper("TheQuickBrownFoxJumpsOverTheLazyDog.")
144	}
145}
146
147func BenchmarkURLNormalizer(b *testing.B) {
148	for i := 0; i < b.N; i++ {
149		urlNormalizer("The quick brown fox jumps over the lazy dog.\n")
150	}
151}
152
153func BenchmarkURLNormalizerNoSpecials(b *testing.B) {
154	for i := 0; i < b.N; i++ {
155		urlNormalizer("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
156	}
157}
158
159func BenchmarkSrcsetFilter(b *testing.B) {
160	for i := 0; i < b.N; i++ {
161		srcsetFilterAndEscaper(" /foo/bar.png 200w, /baz/boo(1).png")
162	}
163}
164
165func BenchmarkSrcsetFilterNoSpecials(b *testing.B) {
166	for i := 0; i < b.N; i++ {
167		srcsetFilterAndEscaper("http://example.com:80/foo?q=bar%20&baz=x+y#frag")
168	}
169}
170