1
2
3
4
5 package template
6
7 import (
8 "testing"
9 )
10
11 func 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
38 func 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
90 func 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
135 func 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
141 func BenchmarkURLEscaperNoSpecials(b *testing.B) {
142 for i := 0; i < b.N; i++ {
143 urlEscaper("TheQuickBrownFoxJumpsOverTheLazyDog.")
144 }
145 }
146
147 func 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
153 func 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
159 func 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
165 func 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
View as plain text