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:307}`},
95 {"GET", "/foo/../bar/./..//baz", `&http.redirectHandler{url:"/baz", code:307}`},
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:307}`},
100 {"CONNECT", "", "(http.HandlerFunc)(.*)"},
101 {"CONNECT", "/", "&http.handler{i:1}"},
102 {"CONNECT", "//", "&http.handler{i:1}"},
103 {"CONNECT", "//foo", "&http.handler{i:5}"},
104 {"CONNECT", "/foo/../bar/./..//baz", "&http.handler{i:2}"},
105 {"CONNECT", "/foo", "&http.handler{i:3}"},
106 {"CONNECT", "/foo/x", "&http.handler{i:2}"},
107 {"CONNECT", "/bar/x", "&http.handler{i:4}"},
108 {"CONNECT", "/bar", `&http.redirectHandler{url:"/bar/", code:307}`},
109 } {
110 var r Request
111 r.Method = test.method
112 r.Host = "example.com"
113 r.URL = &url.URL{Path: test.path}
114 gotH, _, _, _ := mux.findHandler(&r)
115 got := fmt.Sprintf("%#v", gotH)
116 if !regexp.MustCompile(test.wantHandler).MatchString(got) {
117 t.Errorf("%s %q: got %q, want %q", test.method, test.path, got, test.wantHandler)
118 }
119 }
120 }
121
122 func TestEmptyServeMux(t *testing.T) {
123
124
125 mux := NewServeMux()
126 var r Request
127 r.Method = "GET"
128 r.Host = "example.com"
129 r.URL = &url.URL{Path: "/"}
130 _, p := mux.Handler(&r)
131 if p != "" {
132 t.Errorf(`got %q, want ""`, p)
133 }
134 }
135
136 func TestRegisterErr(t *testing.T) {
137 mux := NewServeMux()
138 h := &handler{}
139 mux.Handle("/a", h)
140
141 for _, test := range []struct {
142 pattern string
143 handler Handler
144 wantRegexp string
145 }{
146 {"", h, "invalid pattern"},
147 {"/", nil, "nil handler"},
148 {"/", HandlerFunc(nil), "nil handler"},
149 {"/{x", h, `parsing "/\{x": at offset 1: bad wildcard segment`},
150 {"/a", h, `conflicts with pattern.* \(registered at .*/server_test.go:\d+`},
151 } {
152 t.Run(fmt.Sprintf("%s:%#v", test.pattern, test.handler), func(t *testing.T) {
153 err := mux.registerErr(test.pattern, test.handler)
154 if err == nil {
155 t.Fatal("got nil error")
156 }
157 re := regexp.MustCompile(test.wantRegexp)
158 if g := err.Error(); !re.MatchString(g) {
159 t.Errorf("\ngot %q\nwant string matching %q", g, test.wantRegexp)
160 }
161 })
162 }
163 }
164
165 func TestExactMatch(t *testing.T) {
166 for _, test := range []struct {
167 pattern string
168 path string
169 want bool
170 }{
171 {"", "/a", false},
172 {"/", "/a", false},
173 {"/a", "/a", true},
174 {"/a/{x...}", "/a/b", false},
175 {"/a/{x}", "/a/b", true},
176 {"/a/b/", "/a/b/", true},
177 {"/a/b/{$}", "/a/b/", true},
178 {"/a/", "/a/b/", false},
179 } {
180 var n *routingNode
181 if test.pattern != "" {
182 pat := mustParsePattern(t, test.pattern)
183 n = &routingNode{pattern: pat}
184 }
185 got := exactMatch(n, test.path)
186 if got != test.want {
187 t.Errorf("%q, %s: got %t, want %t", test.pattern, test.path, got, test.want)
188 }
189 }
190 }
191
192 func TestEscapedPathsAndPatterns(t *testing.T) {
193 matches := []struct {
194 pattern string
195 paths []string
196 paths121 []string
197 }{
198 {
199 "/a",
200 []string{"/a", "/%61"},
201 []string{"/a", "/%61"},
202 },
203 {
204 "/%62",
205 []string{"/b", "/%62"},
206 []string{"/%2562"},
207 },
208 {
209 "/%7B/%7D",
210 []string{"/{/}", "/%7b/}", "/{/%7d", "/%7B/%7D"},
211 []string{"/%257B/%257D"},
212 },
213 {
214 "/%x",
215 []string{"/%25x"},
216 []string{"/%25x"},
217 },
218 }
219
220 run := func(t *testing.T, test121 bool) {
221 defer func(u bool) { use121 = u }(use121)
222 use121 = test121
223
224 mux := NewServeMux()
225 for _, m := range matches {
226 mux.HandleFunc(m.pattern, func(w ResponseWriter, r *Request) {})
227 }
228
229 for _, m := range matches {
230 paths := m.paths
231 if use121 {
232 paths = m.paths121
233 }
234 for _, p := range paths {
235 u, err := url.ParseRequestURI(p)
236 if err != nil {
237 t.Fatal(err)
238 }
239 req := &Request{
240 URL: u,
241 }
242 _, gotPattern := mux.Handler(req)
243 if g, w := gotPattern, m.pattern; g != w {
244 t.Errorf("%s: pattern: got %q, want %q", p, g, w)
245 }
246 }
247 }
248 }
249
250 t.Run("latest", func(t *testing.T) { run(t, false) })
251 t.Run("1.21", func(t *testing.T) { run(t, true) })
252 }
253
254 func TestCleanPath(t *testing.T) {
255 for _, test := range []struct {
256 in, want string
257 }{
258 {"//", "/"},
259 {"/x", "/x"},
260 {"//x", "/x"},
261 {"x//", "/x/"},
262 {"a//b/////c", "/a/b/c"},
263 {"/foo/../bar/./..//baz", "/baz"},
264 } {
265 got := cleanPath(test.in)
266 if got != test.want {
267 t.Errorf("%s: got %q, want %q", test.in, got, test.want)
268 }
269 }
270 }
271
272 func BenchmarkServerMatch(b *testing.B) {
273 fn := func(w ResponseWriter, r *Request) {
274 fmt.Fprintf(w, "OK")
275 }
276 mux := NewServeMux()
277 mux.HandleFunc("/", fn)
278 mux.HandleFunc("/index", fn)
279 mux.HandleFunc("/home", fn)
280 mux.HandleFunc("/about", fn)
281 mux.HandleFunc("/contact", fn)
282 mux.HandleFunc("/robots.txt", fn)
283 mux.HandleFunc("/products/", fn)
284 mux.HandleFunc("/products/1", fn)
285 mux.HandleFunc("/products/2", fn)
286 mux.HandleFunc("/products/3", fn)
287 mux.HandleFunc("/products/3/image.jpg", fn)
288 mux.HandleFunc("/admin", fn)
289 mux.HandleFunc("/admin/products/", fn)
290 mux.HandleFunc("/admin/products/create", fn)
291 mux.HandleFunc("/admin/products/update", fn)
292 mux.HandleFunc("/admin/products/delete", fn)
293
294 paths := []string{"/", "/notfound", "/admin/", "/admin/foo", "/contact", "/products",
295 "/products/", "/products/3/image.jpg"}
296 b.StartTimer()
297 for i := 0; i < b.N; i++ {
298 r, err := NewRequest("GET", "http://example.com/"+paths[i%len(paths)], nil)
299 if err != nil {
300 b.Fatal(err)
301 }
302 if h, p, _, _ := mux.findHandler(r); h != nil && p == "" {
303 b.Error("impossible")
304 }
305 }
306 b.StopTimer()
307 }
308
View as plain text