Imported Upstream version 1.0.0
[platform/upstream/nghttp2.git] / integration-tests / nghttpx_http1_test.go
1 package nghttp2
2
3 import (
4         "bufio"
5         "fmt"
6         "github.com/bradfitz/http2/hpack"
7         "io"
8         "net/http"
9         "syscall"
10         "testing"
11 )
12
13 // TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
14 func TestH1H1PlainGET(t *testing.T) {
15         st := newServerTester(nil, t, noopHandler)
16         defer st.Close()
17
18         res, err := st.http1(requestParam{
19                 name: "TestH1H1PlainGET",
20         })
21         if err != nil {
22                 t.Fatalf("Error st.http1() = %v", err)
23         }
24
25         want := 200
26         if got := res.status; got != want {
27                 t.Errorf("status = %v; want %v", got, want)
28         }
29 }
30
31 // TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
32 // Connetion: close request header field works.
33 func TestH1H1PlainGETClose(t *testing.T) {
34         st := newServerTester(nil, t, noopHandler)
35         defer st.Close()
36
37         res, err := st.http1(requestParam{
38                 name: "TestH1H1PlainGETClose",
39                 header: []hpack.HeaderField{
40                         pair("Connection", "close"),
41                 },
42         })
43         if err != nil {
44                 t.Fatalf("Error st.http1() = %v", err)
45         }
46
47         want := 200
48         if got := res.status; got != want {
49                 t.Errorf("status = %v; want %v", got, want)
50         }
51 }
52
53 // TestH1H1MultipleRequestCL tests that server rejects request which
54 // contains multiple Content-Length header fields.
55 func TestH1H1MultipleRequestCL(t *testing.T) {
56         st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
57                 t.Errorf("server should not forward bad request")
58         })
59         defer st.Close()
60
61         if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1
62 Host: %v
63 Test-Case: TestH1H1MultipleRequestCL
64 Content-Length: 0
65 Content-Length: 0
66
67 `, st.authority)); err != nil {
68                 t.Fatalf("Error io.WriteString() = %v", err)
69         }
70
71         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
72         if err != nil {
73                 t.Fatalf("Error http.ReadResponse() = %v", err)
74         }
75
76         want := 400
77         if got := resp.StatusCode; got != want {
78                 t.Errorf("status: %v; want %v", got, want)
79         }
80 }
81
82 // TestH1H1ConnectFailure tests that server handles the situation that
83 // connection attempt to HTTP/1 backend failed.
84 func TestH1H1ConnectFailure(t *testing.T) {
85         st := newServerTester(nil, t, noopHandler)
86         defer st.Close()
87
88         // shutdown backend server to simulate backend connect failure
89         st.ts.Close()
90
91         res, err := st.http1(requestParam{
92                 name: "TestH1H1ConnectFailure",
93         })
94         if err != nil {
95                 t.Fatalf("Error st.http1() = %v", err)
96         }
97         want := 503
98         if got := res.status; got != want {
99                 t.Errorf("status: %v; want %v", got, want)
100         }
101 }
102
103 // TestH1H1GracefulShutdown tests graceful shutdown.
104 func TestH1H1GracefulShutdown(t *testing.T) {
105         st := newServerTester(nil, t, noopHandler)
106         defer st.Close()
107
108         res, err := st.http1(requestParam{
109                 name: "TestH1H1GracefulShutdown-1",
110         })
111         if err != nil {
112                 t.Fatalf("Error st.http1() = %v", err)
113         }
114
115         if got, want := res.status, 200; got != want {
116                 t.Errorf("status: %v; want %v", got, want)
117         }
118
119         st.cmd.Process.Signal(syscall.SIGQUIT)
120
121         res, err = st.http1(requestParam{
122                 name: "TestH1H1GracefulShutdown-2",
123         })
124         if err != nil {
125                 t.Fatalf("Error st.http1() = %v", err)
126         }
127
128         if got, want := res.status, 200; got != want {
129                 t.Errorf("status: %v; want %v", got, want)
130         }
131
132         if got, want := res.connClose, true; got != want {
133                 t.Errorf("res.connClose: %v; want %v", got, want)
134         }
135
136         want := io.EOF
137         if _, err := st.conn.Read(nil); err == nil || err != want {
138                 t.Errorf("st.conn.Read(): %v; want %v", err, want)
139         }
140 }
141
142 // TestH1H1HostRewrite tests that server rewrites Host header field
143 func TestH1H1HostRewrite(t *testing.T) {
144         st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
145                 w.Header().Add("request-host", r.Host)
146         })
147         defer st.Close()
148
149         res, err := st.http1(requestParam{
150                 name: "TestH1H1HostRewrite",
151         })
152         if err != nil {
153                 t.Fatalf("Error st.http1() = %v", err)
154         }
155         if got, want := res.status, 200; got != want {
156                 t.Errorf("status: %v; want %v", got, want)
157         }
158         if got, want := res.header.Get("request-host"), st.backendHost; got != want {
159                 t.Errorf("request-host: %v; want %v", got, want)
160         }
161 }
162
163 // TestH1H1HTTP10 tests that server can accept HTTP/1.0 request
164 // without Host header field
165 func TestH1H1HTTP10(t *testing.T) {
166         st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
167                 w.Header().Add("request-host", r.Host)
168         })
169         defer st.Close()
170
171         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10\r\n\r\n"); err != nil {
172                 t.Fatalf("Error io.WriteString() = %v", err)
173         }
174
175         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
176         if err != nil {
177                 t.Fatalf("Error http.ReadResponse() = %v", err)
178         }
179
180         if got, want := resp.StatusCode, 200; got != want {
181                 t.Errorf("status: %v; want %v", got, want)
182         }
183         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
184                 t.Errorf("request-host: %v; want %v", got, want)
185         }
186 }
187
188 // TestH1H1HTTP10NoHostRewrite tests that server generates host header
189 // field using actual backend server even if --no-http-rewrite is
190 // used.
191 func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
192         st := newServerTester([]string{"--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
193                 w.Header().Add("request-host", r.Host)
194         })
195         defer st.Close()
196
197         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10NoHostRewrite\r\n\r\n"); err != nil {
198                 t.Fatalf("Error io.WriteString() = %v", err)
199         }
200
201         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
202         if err != nil {
203                 t.Fatalf("Error http.ReadResponse() = %v", err)
204         }
205
206         if got, want := resp.StatusCode, 200; got != want {
207                 t.Errorf("status: %v; want %v", got, want)
208         }
209         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
210                 t.Errorf("request-host: %v; want %v", got, want)
211         }
212 }
213
214 // TestH1H1RequestTrailer tests request trailer part is forwarded to
215 // backend.
216 func TestH1H1RequestTrailer(t *testing.T) {
217         st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
218                 buf := make([]byte, 4096)
219                 for {
220                         _, err := r.Body.Read(buf)
221                         if err == io.EOF {
222                                 break
223                         }
224                         if err != nil {
225                                 t.Fatalf("r.Body.Read() = %v", err)
226                         }
227                 }
228                 if got, want := r.Trailer.Get("foo"), "bar"; got != want {
229                         t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
230                 }
231         })
232         defer st.Close()
233
234         res, err := st.http1(requestParam{
235                 name: "TestH1H1RequestTrailer",
236                 body: []byte("1"),
237                 trailer: []hpack.HeaderField{
238                         pair("foo", "bar"),
239                 },
240         })
241         if err != nil {
242                 t.Fatalf("Error st.http1() = %v", err)
243         }
244         if got, want := res.status, 200; got != want {
245                 t.Errorf("res.status: %v; want %v", got, want)
246         }
247 }
248
249 // TestH1H1HeaderFieldBufferPath tests that request with request path
250 // larger than configured buffer size is rejected.
251 func TestH1H1HeaderFieldBufferPath(t *testing.T) {
252         // The value 100 is chosen so that sum of header fields bytes
253         // does not exceed it.  We use > 100 bytes URI to exceed this
254         // limit.
255         st := newServerTester([]string{"--header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
256                 t.Fatal("execution path should not be here")
257         })
258         defer st.Close()
259
260         res, err := st.http1(requestParam{
261                 name: "TestH1H1HeaderFieldBufferPath",
262                 path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
263         })
264         if err != nil {
265                 t.Fatalf("Error st.http1() = %v", err)
266         }
267         if got, want := res.status, 431; got != want {
268                 t.Errorf("status: %v; want %v", got, want)
269         }
270 }
271
272 // TestH1H1HeaderFieldBuffer tests that request with header fields
273 // larger than configured buffer size is rejected.
274 func TestH1H1HeaderFieldBuffer(t *testing.T) {
275         st := newServerTester([]string{"--header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
276                 t.Fatal("execution path should not be here")
277         })
278         defer st.Close()
279
280         res, err := st.http1(requestParam{
281                 name: "TestH1H1HeaderFieldBuffer",
282         })
283         if err != nil {
284                 t.Fatalf("Error st.http1() = %v", err)
285         }
286         if got, want := res.status, 431; got != want {
287                 t.Errorf("status: %v; want %v", got, want)
288         }
289 }
290
291 // TestH1H1HeaderFields tests that request with header fields more
292 // than configured number is rejected.
293 func TestH1H1HeaderFields(t *testing.T) {
294         st := newServerTester([]string{"--max-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
295                 t.Fatal("execution path should not be here")
296         })
297         defer st.Close()
298
299         res, err := st.http1(requestParam{
300                 name: "TestH1H1HeaderFields",
301                 header: []hpack.HeaderField{
302                         // Add extra header field to ensure that
303                         // header field limit exceeds
304                         pair("Connection", "close"),
305                 },
306         })
307         if err != nil {
308                 t.Fatalf("Error st.http1() = %v", err)
309         }
310         if got, want := res.status, 431; got != want {
311                 t.Errorf("status: %v; want %v", got, want)
312         }
313 }
314
315 // TestH1H2ConnectFailure tests that server handles the situation that
316 // connection attempt to HTTP/2 backend failed.
317 func TestH1H2ConnectFailure(t *testing.T) {
318         st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
319         defer st.Close()
320
321         // simulate backend connect attempt failure
322         st.ts.Close()
323
324         res, err := st.http1(requestParam{
325                 name: "TestH1H2ConnectFailure",
326         })
327         if err != nil {
328                 t.Fatalf("Error st.http1() = %v", err)
329         }
330         want := 503
331         if got := res.status; got != want {
332                 t.Errorf("status: %v; want %v", got, want)
333         }
334 }
335
336 // TestH1H2NoHost tests that server rejects request without Host
337 // header field for HTTP/2 backend.
338 func TestH1H2NoHost(t *testing.T) {
339         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
340                 t.Errorf("server should not forward bad request")
341         })
342         defer st.Close()
343
344         // without Host header field, we expect 400 response
345         if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
346                 t.Fatalf("Error io.WriteString() = %v", err)
347         }
348
349         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
350         if err != nil {
351                 t.Fatalf("Error http.ReadResponse() = %v", err)
352         }
353
354         want := 400
355         if got := resp.StatusCode; got != want {
356                 t.Errorf("status: %v; want %v", got, want)
357         }
358 }
359
360 // TestH1H2HTTP10 tests that server can accept HTTP/1.0 request
361 // without Host header field
362 func TestH1H2HTTP10(t *testing.T) {
363         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
364                 w.Header().Add("request-host", r.Host)
365         })
366         defer st.Close()
367
368         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10\r\n\r\n"); err != nil {
369                 t.Fatalf("Error io.WriteString() = %v", err)
370         }
371
372         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
373         if err != nil {
374                 t.Fatalf("Error http.ReadResponse() = %v", err)
375         }
376
377         if got, want := resp.StatusCode, 200; got != want {
378                 t.Errorf("status: %v; want %v", got, want)
379         }
380         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
381                 t.Errorf("request-host: %v; want %v", got, want)
382         }
383 }
384
385 // TestH1H2HTTP10NoHostRewrite tests that server generates host header
386 // field using actual backend server even if --no-http-rewrite is
387 // used.
388 func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
389         st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
390                 w.Header().Add("request-host", r.Host)
391         })
392         defer st.Close()
393
394         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
395                 t.Fatalf("Error io.WriteString() = %v", err)
396         }
397
398         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
399         if err != nil {
400                 t.Fatalf("Error http.ReadResponse() = %v", err)
401         }
402
403         if got, want := resp.StatusCode, 200; got != want {
404                 t.Errorf("status: %v; want %v", got, want)
405         }
406         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
407                 t.Errorf("request-host: %v; want %v", got, want)
408         }
409 }
410
411 // TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
412 // when forwarding to HTTP/2 backend link.  go-nghttp2 server
413 // concatenates crumbled Cookies automatically, so this test is not
414 // much effective now.
415 func TestH1H2CrumbleCookie(t *testing.T) {
416         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
417                 if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
418                         t.Errorf("Cookie: %v; want %v", got, want)
419                 }
420         })
421         defer st.Close()
422
423         res, err := st.http1(requestParam{
424                 name: "TestH1H2CrumbleCookie",
425                 header: []hpack.HeaderField{
426                         pair("Cookie", "alpha; bravo; charlie"),
427                 },
428         })
429         if err != nil {
430                 t.Fatalf("Error st.http1() = %v", err)
431         }
432         if got, want := res.status, 200; got != want {
433                 t.Errorf("status: %v; want %v", got, want)
434         }
435 }
436
437 // TestH1H2GenerateVia tests that server generates Via header field to and
438 // from backend server.
439 func TestH1H2GenerateVia(t *testing.T) {
440         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
441                 if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
442                         t.Errorf("Via: %v; want %v", got, want)
443                 }
444         })
445         defer st.Close()
446
447         res, err := st.http1(requestParam{
448                 name: "TestH1H2GenerateVia",
449         })
450         if err != nil {
451                 t.Fatalf("Error st.http1() = %v", err)
452         }
453         if got, want := res.header.Get("Via"), "2 nghttpx"; got != want {
454                 t.Errorf("Via: %v; want %v", got, want)
455         }
456 }
457
458 // TestH1H2AppendVia tests that server adds value to existing Via
459 // header field to and from backend server.
460 func TestH1H2AppendVia(t *testing.T) {
461         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
462                 if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
463                         t.Errorf("Via: %v; want %v", got, want)
464                 }
465                 w.Header().Add("Via", "bar")
466         })
467         defer st.Close()
468
469         res, err := st.http1(requestParam{
470                 name: "TestH1H2AppendVia",
471                 header: []hpack.HeaderField{
472                         pair("via", "foo"),
473                 },
474         })
475         if err != nil {
476                 t.Fatalf("Error st.http1() = %v", err)
477         }
478         if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want {
479                 t.Errorf("Via: %v; want %v", got, want)
480         }
481 }
482
483 // TestH1H2NoVia tests that server does not add value to existing Via
484 // header field to and from backend server.
485 func TestH1H2NoVia(t *testing.T) {
486         st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
487                 if got, want := r.Header.Get("Via"), "foo"; got != want {
488                         t.Errorf("Via: %v; want %v", got, want)
489                 }
490                 w.Header().Add("Via", "bar")
491         })
492         defer st.Close()
493
494         res, err := st.http1(requestParam{
495                 name: "TestH1H2NoVia",
496                 header: []hpack.HeaderField{
497                         pair("via", "foo"),
498                 },
499         })
500         if err != nil {
501                 t.Fatalf("Error st.http1() = %v", err)
502         }
503         if got, want := res.header.Get("Via"), "bar"; got != want {
504                 t.Errorf("Via: %v; want %v", got, want)
505         }
506 }