Source file
src/net/http/server_test.go
1
2
3
4
5
6
7 package http
8
9 import (
10 "fmt"
11 "net/url"
12 "regexp"
13 "testing"
14 "time"
15 )
16
17 func TestServerTLSHandshakeTimeout(t *testing.T) {
18 tests := []struct {
19 s *Server
20 want time.Duration
21 }{
22 {
23 s: &Server{},
24 want: 0,
25 },
26 {
27 s: &Server{
28 ReadTimeout: -1,
29 },
30 want: 0,
31 },
32 {
33 s: &Server{
34 ReadTimeout: 5 * time.Second,
35 },
36 want: 5 * time.Second,
37 },
38 {
39 s: &Server{
40 ReadTimeout: 5 * time.Second,
41 WriteTimeout: -1,
42 },
43 want: 5 * time.Second,
44 },
45 {
46 s: &Server{
47 ReadTimeout: 5 * time.Second,
48 WriteTimeout: 4 * time.Second,
49 },
50 want: 4 * time.Second,
51 },
52 {
53 s: &Server{
54 ReadTimeout: 5 * time.Second,
55 ReadHeaderTimeout: 2 * time.Second,
56 WriteTimeout: 4 * time.Second,
57 },
58 want: 2 * time.Second,
59 },
60 }
61 for i, tt := range tests {
62 got := tt.s.tlsHandshakeTimeout()
63 if got != tt.want {
64 t.Errorf("%d. got %v; want %v", i, got, tt.want)
65 }
66 }
67 }
68
69 type handler struct{ i int }
70
71 func (handler) ServeHTTP(ResponseWriter, *Request) {}
72
73 func TestFindHandler(t *testing.T) {
74 mux := NewServeMux()
75 for _, ph := range []struct {
76 pat string
77 h Handler
78 }{
79 {"/", &handler{1}},
80 {"/foo/", &handler{2}},
81 {"/foo", &handler{3}},
82 {"/bar/", &handler{4}},
83 {"//foo", &handler{5}},
84 } {
85 mux.Handle(ph.pat, ph.h)
86 }
87
88 for _, test := range []struct {
89 method string
90 path string
91 wantHandler string
92 }{
93 {"GET", "/", "&http.handler{i:1}"},
94 {"GET", "//", `&http.redirectHandler{url:"/", code:301}`},
95 {"GET", "/foo/../bar/./..//baz", `&http.redirectHandler{url:"/baz", code:301}`},
96 {"GET", "/foo", "&http.handler{i:3}"},
97 {"GET", "/foo/x", "&http.handler{i:2}"},
98 {"GET", "/bar/x", "&http.handler{i:4}"},
99 {"GET", "/bar", `&http.redirectHandler{url:"/bar/", code:301}`},
100 {"CONNECT", "/", "&http.handler{i:1}"},
101 {"CONNECT", "//", "&http.handler{i:1}"},
102 {"CONNECT", "//foo", "&http.handler{i:5}"},
103 {"CONNECT", "/foo/../bar/./..//baz", "&http.handler{i:2}"},
104 {"CONNECT", "/foo", "&http.handler{i:3}"},
105 {"CONNECT", "/foo/x", "&http.handler{i:2}"},
106 {"CONNECT", "/bar/x", "&http.handler{i:4}"},
107 {"CONNECT", "/bar", `&http.redirectHandler{url:"/bar/", code:301}`},
108 } {
109 var r Request
110 r.Method = test.method
111 r.Host = "example.com"
112 r.URL = &url.URL{Path: test.path}
113 gotH, _, _, _ := mux.findHandler(&r)
114 got := fmt.Sprintf("%#v", gotH)
115 if got != test.wantHandler {
116 t.Errorf("%s %q: got %q, want %q", test.method, test.path, got, test.wantHandler)
117 }
118 }
119 }
120
121 func TestEmptyServeMux(t *testing.T) {
122
123
124 mux := NewServeMux()
125 var r Request
126 r.Method = "GET"
127 r.Host = "example.com"
128 r.URL = &url.URL{Path: "/"}
129 _, p := mux.Handler(&r)
130 if p != "" {
131 t.Errorf(`got %q, want ""`, p)
132 }
133 }
134
135 func TestRegisterErr(t *testing.T) {
136 mux := NewServeMux()
137 h := &handler{}
138 mux.Handle("/a", h)
139
140 for _, test := range []struct {
141 pattern string
142 handler Handler
143 wantRegexp string
144 }{
145 {"", h, "invalid pattern"},
146 {"/", nil, "nil handler"},
147 {"/", HandlerFunc(nil), "nil handler"},
148 {"/{x", h, `parsing "/\{x": at offset 1: bad wildcard segment`},
149 {"/a", h, `conflicts with pattern.* \(registered at .*/server_test.go:\d+`},
150 } {
151 t.Run(fmt.Sprintf("%s:%#v", test.pattern, test.handler), func(t *testing.T) {
152 err := mux.registerErr(test.pattern, test.handler)
153 if err == nil {
154 t.Fatal("got nil error")
155 }
156 re := regexp.MustCompile(test.wantRegexp)
157 if g := err.Error(); !re.MatchString(g) {
158 t.Errorf("\ngot %q\nwant string matching %q", g, test.wantRegexp)
159 }
160 })
161 }
162 }
163
164 func TestExactMatch(t *testing.T) {
165 for _, test := range []struct {
166 pattern string
167 path string
168 want bool
169 }{
170 {"", "/a", false},
171 {"/", "/a", false},
172 {"/a", "/a", true},
173 {"/a/{x...}", "/a/b", false},
174 {"/a/{x}", "/a/b", true},
175 {"/a/b/", "/a/b/", true},
176 {"/a/b/{$}", "/a/b/", true},
177 {"/a/", "/a/b/", false},
178 } {
179 var n *routingNode
180 if test.pattern != "" {
181 pat := mustParsePattern(t, test.pattern)
182 n = &routingNode{pattern: pat}
183 }
184 got := exactMatch(n, test.path)
185 if got != test.want {
186 t.Errorf("%q, %s: got %t, want %t", test.pattern, test.path, got, test.want)
187 }
188 }
189 }
190
191 func TestEscapedPathsAndPatterns(t *testing.T) {
192 matches := []struct {
193 pattern string
194 paths []string
195 paths121 []string
196 }{
197 {
198 "/a",
199 []string{"/a", "/%61"},
200 []string{"/a", "/%61"},
201 },
202 {
203 "/%62",
204 []string{"/b", "/%62"},
205 []string{"/%2562"},
206 },
207 {
208 "/%7B/%7D",
209 []string{"/{/}", "/%7b/}", "/{/%7d", "/%7B/%7D"},
210 []string{"/%257B/%257D"},
211 },
212 {
213 "/%x",
214 []string{"/%25x"},
215 []string{"/%25x"},
216 },
217 }
218
219 run := func(t *testing.T, test121 bool) {
220 defer func(u bool) { use121 = u }(use121)
221 use121 = test121
222
223 mux := NewServeMux()
224 for _, m := range matches {
225 mux.HandleFunc(m.pattern, func(w ResponseWriter, r *Request) {})
226 }
227
228 for _, m := range matches {
229 paths := m.paths
230 if use121 {
231 paths = m.paths121
232 }
233 for _, p := range paths {
234 u, err := url.ParseRequestURI(p)
235 if err != nil {
236 t.Fatal(err)
237 }
238 req := &Request{
239 URL: u,
240 }
241 _, gotPattern := mux.Handler(req)
242 if g, w := gotPattern, m.pattern; g != w {
243 t.Errorf("%s: pattern: got %q, want %q", p, g, w)
244 }
245 }
246 }
247 }
248
249 t.Run("latest", func(t *testing.T) { run(t, false) })
250 t.Run("1.21", func(t *testing.T) { run(t, true) })
251 }
252
253 func TestCleanPath(t *testing.T) {
254 for _, test := range []struct {
255 in, want string
256 }{
257 {"//", "/"},
258 {"/x", "/x"},
259 {"//x", "/x"},
260 {"x//", "/x/"},
261 {"a//b/////c", "/a/b/c"},
262 {"/foo/../bar/./..//baz", "/baz"},
263 } {
264 got := cleanPath(test.in)
265 if got != test.want {
266 t.Errorf("%s: got %q, want %q", test.in, got, test.want)
267 }
268 }
269 }
270
271 func BenchmarkServerMatch(b *testing.B) {
272 fn := func(w ResponseWriter, r *Request) {
273 fmt.Fprintf(w, "OK")
274 }
275 mux := NewServeMux()
276 mux.HandleFunc("/", fn)
277 mux.HandleFunc("/index", fn)
278 mux.HandleFunc("/home", fn)
279 mux.HandleFunc("/about", fn)
280 mux.HandleFunc("/contact", fn)
281 mux.HandleFunc("/robots.txt", fn)
282 mux.HandleFunc("/products/", fn)
283 mux.HandleFunc("/products/1", fn)
284 mux.HandleFunc("/products/2", fn)
285 mux.HandleFunc("/products/3", fn)
286 mux.HandleFunc("/products/3/image.jpg", fn)
287 mux.HandleFunc("/admin", fn)
288 mux.HandleFunc("/admin/products/", fn)
289 mux.HandleFunc("/admin/products/create", fn)
290 mux.HandleFunc("/admin/products/update", fn)
291 mux.HandleFunc("/admin/products/delete", fn)
292
293 paths := []string{"/", "/notfound", "/admin/", "/admin/foo", "/contact", "/products",
294 "/products/", "/products/3/image.jpg"}
295 b.StartTimer()
296 for i := 0; i < b.N; i++ {
297 r, err := NewRequest("GET", "http://example.com/"+paths[i%len(paths)], nil)
298 if err != nil {
299 b.Fatal(err)
300 }
301 if h, p, _, _ := mux.findHandler(r); h != nil && p == "" {
302 b.Error("impossible")
303 }
304 }
305 b.StopTimer()
306 }
307
View as plain text