tizen 2.4 release
[external/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 // TestH1H2ConnectFailure tests that server handles the situation that
215 // connection attempt to HTTP/2 backend failed.
216 func TestH1H2ConnectFailure(t *testing.T) {
217         st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
218         defer st.Close()
219
220         // simulate backend connect attempt failure
221         st.ts.Close()
222
223         res, err := st.http1(requestParam{
224                 name: "TestH1H2ConnectFailure",
225         })
226         if err != nil {
227                 t.Fatalf("Error st.http1() = %v", err)
228         }
229         want := 503
230         if got := res.status; got != want {
231                 t.Errorf("status: %v; want %v", got, want)
232         }
233 }
234
235 // TestH1H2NoHost tests that server rejects request without Host
236 // header field for HTTP/2 backend.
237 func TestH1H2NoHost(t *testing.T) {
238         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
239                 t.Errorf("server should not forward bad request")
240         })
241         defer st.Close()
242
243         // without Host header field, we expect 400 response
244         if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
245                 t.Fatalf("Error io.WriteString() = %v", err)
246         }
247
248         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
249         if err != nil {
250                 t.Fatalf("Error http.ReadResponse() = %v", err)
251         }
252
253         want := 400
254         if got := resp.StatusCode; got != want {
255                 t.Errorf("status: %v; want %v", got, want)
256         }
257 }
258
259 // TestH1H2HTTP10 tests that server can accept HTTP/1.0 request
260 // without Host header field
261 func TestH1H2HTTP10(t *testing.T) {
262         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
263                 w.Header().Add("request-host", r.Host)
264         })
265         defer st.Close()
266
267         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10\r\n\r\n"); err != nil {
268                 t.Fatalf("Error io.WriteString() = %v", err)
269         }
270
271         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
272         if err != nil {
273                 t.Fatalf("Error http.ReadResponse() = %v", err)
274         }
275
276         if got, want := resp.StatusCode, 200; got != want {
277                 t.Errorf("status: %v; want %v", got, want)
278         }
279         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
280                 t.Errorf("request-host: %v; want %v", got, want)
281         }
282 }
283
284 // TestH1H2HTTP10NoHostRewrite tests that server generates host header
285 // field using actual backend server even if --no-http-rewrite is
286 // used.
287 func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
288         st := newServerTester([]string{"--http2-bridge", "--no-host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
289                 w.Header().Add("request-host", r.Host)
290         })
291         defer st.Close()
292
293         if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
294                 t.Fatalf("Error io.WriteString() = %v", err)
295         }
296
297         resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
298         if err != nil {
299                 t.Fatalf("Error http.ReadResponse() = %v", err)
300         }
301
302         if got, want := resp.StatusCode, 200; got != want {
303                 t.Errorf("status: %v; want %v", got, want)
304         }
305         if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
306                 t.Errorf("request-host: %v; want %v", got, want)
307         }
308 }
309
310 // TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
311 // when forwarding to HTTP/2 backend link.  go-nghttp2 server
312 // concatenates crumbled Cookies automatically, so this test is not
313 // much effective now.
314 func TestH1H2CrumbleCookie(t *testing.T) {
315         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
316                 if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
317                         t.Errorf("Cookie: %v; want %v", got, want)
318                 }
319         })
320         defer st.Close()
321
322         res, err := st.http1(requestParam{
323                 name: "TestH1H2CrumbleCookie",
324                 header: []hpack.HeaderField{
325                         pair("Cookie", "alpha; bravo; charlie"),
326                 },
327         })
328         if err != nil {
329                 t.Fatalf("Error st.http1() = %v", err)
330         }
331         if got, want := res.status, 200; got != want {
332                 t.Errorf("status: %v; want %v", got, want)
333         }
334 }
335
336 // TestH1H2GenerateVia tests that server generates Via header field to and
337 // from backend server.
338 func TestH1H2GenerateVia(t *testing.T) {
339         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
340                 if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
341                         t.Errorf("Via: %v; want %v", got, want)
342                 }
343         })
344         defer st.Close()
345
346         res, err := st.http1(requestParam{
347                 name: "TestH1H2GenerateVia",
348         })
349         if err != nil {
350                 t.Fatalf("Error st.http1() = %v", err)
351         }
352         if got, want := res.header.Get("Via"), "2.0 nghttpx"; got != want {
353                 t.Errorf("Via: %v; want %v", got, want)
354         }
355 }
356
357 // TestH1H2AppendVia tests that server adds value to existing Via
358 // header field to and from backend server.
359 func TestH1H2AppendVia(t *testing.T) {
360         st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
361                 if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
362                         t.Errorf("Via: %v; want %v", got, want)
363                 }
364                 w.Header().Add("Via", "bar")
365         })
366         defer st.Close()
367
368         res, err := st.http1(requestParam{
369                 name: "TestH1H2AppendVia",
370                 header: []hpack.HeaderField{
371                         pair("via", "foo"),
372                 },
373         })
374         if err != nil {
375                 t.Fatalf("Error st.http1() = %v", err)
376         }
377         if got, want := res.header.Get("Via"), "bar, 2.0 nghttpx"; got != want {
378                 t.Errorf("Via: %v; want %v", got, want)
379         }
380 }
381
382 // TestH1H2NoVia tests that server does not add value to existing Via
383 // header field to and from backend server.
384 func TestH1H2NoVia(t *testing.T) {
385         st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
386                 if got, want := r.Header.Get("Via"), "foo"; got != want {
387                         t.Errorf("Via: %v; want %v", got, want)
388                 }
389                 w.Header().Add("Via", "bar")
390         })
391         defer st.Close()
392
393         res, err := st.http1(requestParam{
394                 name: "TestH1H2NoVia",
395                 header: []hpack.HeaderField{
396                         pair("via", "foo"),
397                 },
398         })
399         if err != nil {
400                 t.Fatalf("Error st.http1() = %v", err)
401         }
402         if got, want := res.header.Get("Via"), "bar"; got != want {
403                 t.Errorf("Via: %v; want %v", got, want)
404         }
405 }