• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package nghttp2
2
3import (
4	"bufio"
5	"bytes"
6	"encoding/json"
7	"fmt"
8	"golang.org/x/net/http2/hpack"
9	"golang.org/x/net/websocket"
10	"io"
11	"net/http"
12	"regexp"
13	"syscall"
14	"testing"
15	"time"
16)
17
18// TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
19func TestH1H1PlainGET(t *testing.T) {
20	st := newServerTester(nil, t, noopHandler)
21	defer st.Close()
22
23	res, err := st.http1(requestParam{
24		name: "TestH1H1PlainGET",
25	})
26	if err != nil {
27		t.Fatalf("Error st.http1() = %v", err)
28	}
29
30	want := 200
31	if got := res.status; got != want {
32		t.Errorf("status = %v; want %v", got, want)
33	}
34}
35
36// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
37// Connetion: close request header field works.
38func TestH1H1PlainGETClose(t *testing.T) {
39	st := newServerTester(nil, t, noopHandler)
40	defer st.Close()
41
42	res, err := st.http1(requestParam{
43		name: "TestH1H1PlainGETClose",
44		header: []hpack.HeaderField{
45			pair("Connection", "close"),
46		},
47	})
48	if err != nil {
49		t.Fatalf("Error st.http1() = %v", err)
50	}
51
52	want := 200
53	if got := res.status; got != want {
54		t.Errorf("status = %v; want %v", got, want)
55	}
56}
57
58// TestH1H1InvalidMethod tests that server rejects invalid method with
59// 501 status code
60func TestH1H1InvalidMethod(t *testing.T) {
61	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
62		t.Errorf("server should not forward this request")
63	})
64	defer st.Close()
65
66	res, err := st.http1(requestParam{
67		name:   "TestH1H1InvalidMethod",
68		method: "get",
69	})
70	if err != nil {
71		t.Fatalf("Error st.http1() = %v", err)
72	}
73
74	if got, want := res.status, 501; got != want {
75		t.Errorf("status = %v; want %v", got, want)
76	}
77}
78
79// TestH1H1MultipleRequestCL tests that server rejects request which
80// contains multiple Content-Length header fields.
81func TestH1H1MultipleRequestCL(t *testing.T) {
82	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
83		t.Errorf("server should not forward bad request")
84	})
85	defer st.Close()
86
87	if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1
88Host: %v
89Test-Case: TestH1H1MultipleRequestCL
90Content-Length: 0
91Content-Length: 0
92
93`, st.authority)); err != nil {
94		t.Fatalf("Error io.WriteString() = %v", err)
95	}
96
97	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
98	if err != nil {
99		t.Fatalf("Error http.ReadResponse() = %v", err)
100	}
101
102	want := 400
103	if got := resp.StatusCode; got != want {
104		t.Errorf("status: %v; want %v", got, want)
105	}
106}
107
108// // TestH1H1ConnectFailure tests that server handles the situation that
109// // connection attempt to HTTP/1 backend failed.
110// func TestH1H1ConnectFailure(t *testing.T) {
111// 	st := newServerTester(nil, t, noopHandler)
112// 	defer st.Close()
113
114// 	// shutdown backend server to simulate backend connect failure
115// 	st.ts.Close()
116
117// 	res, err := st.http1(requestParam{
118// 		name: "TestH1H1ConnectFailure",
119// 	})
120// 	if err != nil {
121// 		t.Fatalf("Error st.http1() = %v", err)
122// 	}
123// 	want := 503
124// 	if got := res.status; got != want {
125// 		t.Errorf("status: %v; want %v", got, want)
126// 	}
127// }
128
129// TestH1H1AffinityCookie tests that affinity cookie is sent back in
130// cleartext http.
131func TestH1H1AffinityCookie(t *testing.T) {
132	st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
133	defer st.Close()
134
135	res, err := st.http1(requestParam{
136		name: "TestH1H1AffinityCookie",
137	})
138	if err != nil {
139		t.Fatalf("Error st.http1() = %v", err)
140	}
141
142	if got, want := res.status, 200; got != want {
143		t.Errorf("status = %v; want %v", got, want)
144	}
145
146	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
147	validCookie := regexp.MustCompile(pattern)
148	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
149		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
150	}
151}
152
153// TestH1H1AffinityCookieTLS tests that affinity cookie is sent back
154// in https.
155func TestH1H1AffinityCookieTLS(t *testing.T) {
156	st := newServerTesterTLS([]string{"--alpn-h1", "--affinity-cookie"}, t, noopHandler)
157	defer st.Close()
158
159	res, err := st.http1(requestParam{
160		name: "TestH1H1AffinityCookieTLS",
161	})
162	if err != nil {
163		t.Fatalf("Error st.http1() = %v", err)
164	}
165
166	if got, want := res.status, 200; got != want {
167		t.Errorf("status = %v; want %v", got, want)
168	}
169
170	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
171	validCookie := regexp.MustCompile(pattern)
172	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
173		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
174	}
175}
176
177// TestH1H1GracefulShutdown tests graceful shutdown.
178func TestH1H1GracefulShutdown(t *testing.T) {
179	st := newServerTester(nil, t, noopHandler)
180	defer st.Close()
181
182	res, err := st.http1(requestParam{
183		name: "TestH1H1GracefulShutdown-1",
184	})
185	if err != nil {
186		t.Fatalf("Error st.http1() = %v", err)
187	}
188
189	if got, want := res.status, 200; got != want {
190		t.Errorf("status: %v; want %v", got, want)
191	}
192
193	st.cmd.Process.Signal(syscall.SIGQUIT)
194	time.Sleep(150 * time.Millisecond)
195
196	res, err = st.http1(requestParam{
197		name: "TestH1H1GracefulShutdown-2",
198	})
199	if err != nil {
200		t.Fatalf("Error st.http1() = %v", err)
201	}
202
203	if got, want := res.status, 200; got != want {
204		t.Errorf("status: %v; want %v", got, want)
205	}
206
207	if got, want := res.connClose, true; got != want {
208		t.Errorf("res.connClose: %v; want %v", got, want)
209	}
210
211	want := io.EOF
212	b := make([]byte, 256)
213	if _, err := st.conn.Read(b); err == nil || err != want {
214		t.Errorf("st.conn.Read(): %v; want %v", err, want)
215	}
216}
217
218// TestH1H1HostRewrite tests that server rewrites Host header field
219func TestH1H1HostRewrite(t *testing.T) {
220	st := newServerTester([]string{"--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
221		w.Header().Add("request-host", r.Host)
222	})
223	defer st.Close()
224
225	res, err := st.http1(requestParam{
226		name: "TestH1H1HostRewrite",
227	})
228	if err != nil {
229		t.Fatalf("Error st.http1() = %v", err)
230	}
231	if got, want := res.status, 200; got != want {
232		t.Errorf("status: %v; want %v", got, want)
233	}
234	if got, want := res.header.Get("request-host"), st.backendHost; got != want {
235		t.Errorf("request-host: %v; want %v", got, want)
236	}
237}
238
239// TestH1H1BadHost tests that server rejects request including bad
240// characters in host header field.
241func TestH1H1BadHost(t *testing.T) {
242	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
243		t.Errorf("server should not forward this request")
244	})
245	defer st.Close()
246
247	if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H1HBadHost\r\nHost: foo\"bar\r\n\r\n"); err != nil {
248		t.Fatalf("Error io.WriteString() = %v", err)
249	}
250	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
251	if err != nil {
252		t.Fatalf("Error http.ReadResponse() = %v", err)
253	}
254	if got, want := resp.StatusCode, 400; got != want {
255		t.Errorf("status: %v; want %v", got, want)
256	}
257}
258
259// TestH1H1BadAuthority tests that server rejects request including
260// bad characters in authority component of requset URI.
261func TestH1H1BadAuthority(t *testing.T) {
262	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
263		t.Errorf("server should not forward this request")
264	})
265	defer st.Close()
266
267	if _, err := io.WriteString(st.conn, "GET http://foo\"bar/ HTTP/1.1\r\nTest-Case: TestH1H1HBadAuthority\r\nHost: foobar\r\n\r\n"); err != nil {
268		t.Fatalf("Error io.WriteString() = %v", err)
269	}
270	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
271	if err != nil {
272		t.Fatalf("Error http.ReadResponse() = %v", err)
273	}
274	if got, want := resp.StatusCode, 400; got != want {
275		t.Errorf("status: %v; want %v", got, want)
276	}
277}
278
279// TestH1H1BadScheme tests that server rejects request including
280// bad characters in scheme component of requset URI.
281func TestH1H1BadScheme(t *testing.T) {
282	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
283		t.Errorf("server should not forward this request")
284	})
285	defer st.Close()
286
287	if _, err := io.WriteString(st.conn, "GET http*://example.com/ HTTP/1.1\r\nTest-Case: TestH1H1HBadScheme\r\nHost: example.com\r\n\r\n"); err != nil {
288		t.Fatalf("Error io.WriteString() = %v", err)
289	}
290	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
291	if err != nil {
292		t.Fatalf("Error http.ReadResponse() = %v", err)
293	}
294	if got, want := resp.StatusCode, 400; got != want {
295		t.Errorf("status: %v; want %v", got, want)
296	}
297}
298
299// TestH1H1HTTP10 tests that server can accept HTTP/1.0 request
300// without Host header field
301func TestH1H1HTTP10(t *testing.T) {
302	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
303		w.Header().Add("request-host", r.Host)
304	})
305	defer st.Close()
306
307	if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10\r\n\r\n"); err != nil {
308		t.Fatalf("Error io.WriteString() = %v", err)
309	}
310
311	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
312	if err != nil {
313		t.Fatalf("Error http.ReadResponse() = %v", err)
314	}
315
316	if got, want := resp.StatusCode, 200; got != want {
317		t.Errorf("status: %v; want %v", got, want)
318	}
319	if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
320		t.Errorf("request-host: %v; want %v", got, want)
321	}
322}
323
324// TestH1H1HTTP10NoHostRewrite tests that server generates host header
325// field using actual backend server even if --no-http-rewrite is
326// used.
327func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
328	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
329		w.Header().Add("request-host", r.Host)
330	})
331	defer st.Close()
332
333	if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10NoHostRewrite\r\n\r\n"); err != nil {
334		t.Fatalf("Error io.WriteString() = %v", err)
335	}
336
337	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
338	if err != nil {
339		t.Fatalf("Error http.ReadResponse() = %v", err)
340	}
341
342	if got, want := resp.StatusCode, 200; got != want {
343		t.Errorf("status: %v; want %v", got, want)
344	}
345	if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
346		t.Errorf("request-host: %v; want %v", got, want)
347	}
348}
349
350// TestH1H1RequestTrailer tests request trailer part is forwarded to
351// backend.
352func TestH1H1RequestTrailer(t *testing.T) {
353	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
354		buf := make([]byte, 4096)
355		for {
356			_, err := r.Body.Read(buf)
357			if err == io.EOF {
358				break
359			}
360			if err != nil {
361				t.Fatalf("r.Body.Read() = %v", err)
362			}
363		}
364		if got, want := r.Trailer.Get("foo"), "bar"; got != want {
365			t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
366		}
367	})
368	defer st.Close()
369
370	res, err := st.http1(requestParam{
371		name: "TestH1H1RequestTrailer",
372		body: []byte("1"),
373		trailer: []hpack.HeaderField{
374			pair("foo", "bar"),
375		},
376	})
377	if err != nil {
378		t.Fatalf("Error st.http1() = %v", err)
379	}
380	if got, want := res.status, 200; got != want {
381		t.Errorf("res.status: %v; want %v", got, want)
382	}
383}
384
385// TestH1H1HeaderFieldBufferPath tests that request with request path
386// larger than configured buffer size is rejected.
387func TestH1H1HeaderFieldBufferPath(t *testing.T) {
388	// The value 100 is chosen so that sum of header fields bytes
389	// does not exceed it.  We use > 100 bytes URI to exceed this
390	// limit.
391	st := newServerTester([]string{"--request-header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
392		t.Fatal("execution path should not be here")
393	})
394	defer st.Close()
395
396	res, err := st.http1(requestParam{
397		name: "TestH1H1HeaderFieldBufferPath",
398		path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
399	})
400	if err != nil {
401		t.Fatalf("Error st.http1() = %v", err)
402	}
403	if got, want := res.status, 431; got != want {
404		t.Errorf("status: %v; want %v", got, want)
405	}
406}
407
408// TestH1H1HeaderFieldBuffer tests that request with header fields
409// larger than configured buffer size is rejected.
410func TestH1H1HeaderFieldBuffer(t *testing.T) {
411	st := newServerTester([]string{"--request-header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
412		t.Fatal("execution path should not be here")
413	})
414	defer st.Close()
415
416	res, err := st.http1(requestParam{
417		name: "TestH1H1HeaderFieldBuffer",
418	})
419	if err != nil {
420		t.Fatalf("Error st.http1() = %v", err)
421	}
422	if got, want := res.status, 431; got != want {
423		t.Errorf("status: %v; want %v", got, want)
424	}
425}
426
427// TestH1H1HeaderFields tests that request with header fields more
428// than configured number is rejected.
429func TestH1H1HeaderFields(t *testing.T) {
430	st := newServerTester([]string{"--max-request-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
431		t.Fatal("execution path should not be here")
432	})
433	defer st.Close()
434
435	res, err := st.http1(requestParam{
436		name: "TestH1H1HeaderFields",
437		header: []hpack.HeaderField{
438			// Add extra header field to ensure that
439			// header field limit exceeds
440			pair("Connection", "close"),
441		},
442	})
443	if err != nil {
444		t.Fatalf("Error st.http1() = %v", err)
445	}
446	if got, want := res.status, 431; got != want {
447		t.Errorf("status: %v; want %v", got, want)
448	}
449}
450
451// TestH1H1Websocket tests that HTTP Upgrade to WebSocket works.
452func TestH1H1Websocket(t *testing.T) {
453	st := newServerTesterHandler(nil, t, websocket.Handler(func(ws *websocket.Conn) {
454		io.Copy(ws, ws)
455	}))
456	defer st.Close()
457
458	content := []byte("hello world")
459	res, err := st.websocket(requestParam{
460		name: "TestH1H1Websocket",
461		body: content,
462	})
463	if err != nil {
464		t.Fatalf("Error st.websocket() = %v", err)
465	}
466	if got, want := res.body, content; !bytes.Equal(got, want) {
467		t.Errorf("echo: %q; want %q", got, want)
468	}
469}
470
471// TestH1H1ReqPhaseSetHeader tests mruby request phase hook
472// modifies request header fields.
473func TestH1H1ReqPhaseSetHeader(t *testing.T) {
474	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-set-header.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
475		if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
476			t.Errorf("User-Agent = %v; want %v", got, want)
477		}
478	})
479	defer st.Close()
480
481	res, err := st.http1(requestParam{
482		name: "TestH1H1ReqPhaseSetHeader",
483	})
484	if err != nil {
485		t.Fatalf("Error st.http1() = %v", err)
486	}
487
488	if got, want := res.status, 200; got != want {
489		t.Errorf("status = %v; want %v", got, want)
490	}
491}
492
493// TestH1H1ReqPhaseReturn tests mruby request phase hook returns
494// custom response.
495func TestH1H1ReqPhaseReturn(t *testing.T) {
496	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
497		t.Fatalf("request should not be forwarded")
498	})
499	defer st.Close()
500
501	res, err := st.http1(requestParam{
502		name: "TestH1H1ReqPhaseReturn",
503	})
504	if err != nil {
505		t.Fatalf("Error st.http1() = %v", err)
506	}
507
508	if got, want := res.status, 404; got != want {
509		t.Errorf("status = %v; want %v", got, want)
510	}
511
512	hdtests := []struct {
513		k, v string
514	}{
515		{"content-length", "20"},
516		{"from", "mruby"},
517	}
518	for _, tt := range hdtests {
519		if got, want := res.header.Get(tt.k), tt.v; got != want {
520			t.Errorf("%v = %v; want %v", tt.k, got, want)
521		}
522	}
523
524	if got, want := string(res.body), "Hello World from req"; got != want {
525		t.Errorf("body = %v; want %v", got, want)
526	}
527}
528
529// TestH1H1RespPhaseSetHeader tests mruby response phase hook modifies
530// response header fields.
531func TestH1H1RespPhaseSetHeader(t *testing.T) {
532	st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler)
533	defer st.Close()
534
535	res, err := st.http1(requestParam{
536		name: "TestH1H1RespPhaseSetHeader",
537	})
538	if err != nil {
539		t.Fatalf("Error st.http1() = %v", err)
540	}
541
542	if got, want := res.status, 200; got != want {
543		t.Errorf("status = %v; want %v", got, want)
544	}
545
546	if got, want := res.header.Get("alpha"), "bravo"; got != want {
547		t.Errorf("alpha = %v; want %v", got, want)
548	}
549}
550
551// TestH1H1RespPhaseReturn tests mruby response phase hook returns
552// custom response.
553func TestH1H1RespPhaseReturn(t *testing.T) {
554	st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
555	defer st.Close()
556
557	res, err := st.http1(requestParam{
558		name: "TestH1H1RespPhaseReturn",
559	})
560	if err != nil {
561		t.Fatalf("Error st.http1() = %v", err)
562	}
563
564	if got, want := res.status, 404; got != want {
565		t.Errorf("status = %v; want %v", got, want)
566	}
567
568	hdtests := []struct {
569		k, v string
570	}{
571		{"content-length", "21"},
572		{"from", "mruby"},
573	}
574	for _, tt := range hdtests {
575		if got, want := res.header.Get(tt.k), tt.v; got != want {
576			t.Errorf("%v = %v; want %v", tt.k, got, want)
577		}
578	}
579
580	if got, want := string(res.body), "Hello World from resp"; got != want {
581		t.Errorf("body = %v; want %v", got, want)
582	}
583}
584
585// TestH1H1HTTPSRedirect tests that the request to the backend which
586// requires TLS is redirected to https URI.
587func TestH1H1HTTPSRedirect(t *testing.T) {
588	st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler)
589	defer st.Close()
590
591	res, err := st.http1(requestParam{
592		name: "TestH1H1HTTPSRedirect",
593	})
594	if err != nil {
595		t.Fatalf("Error st.http1() = %v", err)
596	}
597
598	if got, want := res.status, 308; got != want {
599		t.Errorf("status = %v; want %v", got, want)
600	}
601	if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
602		t.Errorf("location: %v; want %v", got, want)
603	}
604}
605
606// TestH1H1HTTPSRedirectPort tests that the request to the backend
607// which requires TLS is redirected to https URI with given port.
608func TestH1H1HTTPSRedirectPort(t *testing.T) {
609	st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler)
610	defer st.Close()
611
612	res, err := st.http1(requestParam{
613		path: "/foo?bar",
614		name: "TestH1H1HTTPSRedirectPort",
615	})
616	if err != nil {
617		t.Fatalf("Error st.http1() = %v", err)
618	}
619
620	if got, want := res.status, 308; got != want {
621		t.Errorf("status = %v; want %v", got, want)
622	}
623	if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
624		t.Errorf("location: %v; want %v", got, want)
625	}
626}
627
628// TestH1H1POSTRequests tests that server can handle 2 requests with
629// request body.
630func TestH1H1POSTRequests(t *testing.T) {
631	st := newServerTester(nil, t, noopHandler)
632	defer st.Close()
633
634	res, err := st.http1(requestParam{
635		name: "TestH1H1POSTRequestsNo1",
636		body: make([]byte, 1),
637	})
638	if err != nil {
639		t.Fatalf("Error st.http1() = %v", err)
640	}
641	if got, want := res.status, 200; got != want {
642		t.Errorf("res.status: %v; want %v", got, want)
643	}
644
645	res, err = st.http1(requestParam{
646		name: "TestH1H1POSTRequestsNo2",
647		body: make([]byte, 65536),
648	})
649	if err != nil {
650		t.Fatalf("Error st.http1() = %v", err)
651	}
652	if got, want := res.status, 200; got != want {
653		t.Errorf("res.status: %v; want %v", got, want)
654	}
655}
656
657// // TestH1H2ConnectFailure tests that server handles the situation that
658// // connection attempt to HTTP/2 backend failed.
659// func TestH1H2ConnectFailure(t *testing.T) {
660// 	st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
661// 	defer st.Close()
662
663// 	// simulate backend connect attempt failure
664// 	st.ts.Close()
665
666// 	res, err := st.http1(requestParam{
667// 		name: "TestH1H2ConnectFailure",
668// 	})
669// 	if err != nil {
670// 		t.Fatalf("Error st.http1() = %v", err)
671// 	}
672// 	want := 503
673// 	if got := res.status; got != want {
674// 		t.Errorf("status: %v; want %v", got, want)
675// 	}
676// }
677
678// TestH1H2NoHost tests that server rejects request without Host
679// header field for HTTP/2 backend.
680func TestH1H2NoHost(t *testing.T) {
681	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
682		t.Errorf("server should not forward bad request")
683	})
684	defer st.Close()
685
686	// without Host header field, we expect 400 response
687	if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
688		t.Fatalf("Error io.WriteString() = %v", err)
689	}
690
691	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
692	if err != nil {
693		t.Fatalf("Error http.ReadResponse() = %v", err)
694	}
695
696	want := 400
697	if got := resp.StatusCode; got != want {
698		t.Errorf("status: %v; want %v", got, want)
699	}
700}
701
702// TestH1H2HTTP10 tests that server can accept HTTP/1.0 request
703// without Host header field
704func TestH1H2HTTP10(t *testing.T) {
705	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
706		w.Header().Add("request-host", r.Host)
707	})
708	defer st.Close()
709
710	if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10\r\n\r\n"); err != nil {
711		t.Fatalf("Error io.WriteString() = %v", err)
712	}
713
714	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
715	if err != nil {
716		t.Fatalf("Error http.ReadResponse() = %v", err)
717	}
718
719	if got, want := resp.StatusCode, 200; got != want {
720		t.Errorf("status: %v; want %v", got, want)
721	}
722	if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
723		t.Errorf("request-host: %v; want %v", got, want)
724	}
725}
726
727// TestH1H2HTTP10NoHostRewrite tests that server generates host header
728// field using actual backend server even if --no-http-rewrite is
729// used.
730func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
731	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
732		w.Header().Add("request-host", r.Host)
733	})
734	defer st.Close()
735
736	if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
737		t.Fatalf("Error io.WriteString() = %v", err)
738	}
739
740	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
741	if err != nil {
742		t.Fatalf("Error http.ReadResponse() = %v", err)
743	}
744
745	if got, want := resp.StatusCode, 200; got != want {
746		t.Errorf("status: %v; want %v", got, want)
747	}
748	if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
749		t.Errorf("request-host: %v; want %v", got, want)
750	}
751}
752
753// TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
754// when forwarding to HTTP/2 backend link.  go-nghttp2 server
755// concatenates crumbled Cookies automatically, so this test is not
756// much effective now.
757func TestH1H2CrumbleCookie(t *testing.T) {
758	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
759		if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
760			t.Errorf("Cookie: %v; want %v", got, want)
761		}
762	})
763	defer st.Close()
764
765	res, err := st.http1(requestParam{
766		name: "TestH1H2CrumbleCookie",
767		header: []hpack.HeaderField{
768			pair("Cookie", "alpha; bravo; charlie"),
769		},
770	})
771	if err != nil {
772		t.Fatalf("Error st.http1() = %v", err)
773	}
774	if got, want := res.status, 200; got != want {
775		t.Errorf("status: %v; want %v", got, want)
776	}
777}
778
779// TestH1H2GenerateVia tests that server generates Via header field to and
780// from backend server.
781func TestH1H2GenerateVia(t *testing.T) {
782	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
783		if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
784			t.Errorf("Via: %v; want %v", got, want)
785		}
786	})
787	defer st.Close()
788
789	res, err := st.http1(requestParam{
790		name: "TestH1H2GenerateVia",
791	})
792	if err != nil {
793		t.Fatalf("Error st.http1() = %v", err)
794	}
795	if got, want := res.header.Get("Via"), "2 nghttpx"; got != want {
796		t.Errorf("Via: %v; want %v", got, want)
797	}
798}
799
800// TestH1H2AppendVia tests that server adds value to existing Via
801// header field to and from backend server.
802func TestH1H2AppendVia(t *testing.T) {
803	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
804		if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
805			t.Errorf("Via: %v; want %v", got, want)
806		}
807		w.Header().Add("Via", "bar")
808	})
809	defer st.Close()
810
811	res, err := st.http1(requestParam{
812		name: "TestH1H2AppendVia",
813		header: []hpack.HeaderField{
814			pair("via", "foo"),
815		},
816	})
817	if err != nil {
818		t.Fatalf("Error st.http1() = %v", err)
819	}
820	if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want {
821		t.Errorf("Via: %v; want %v", got, want)
822	}
823}
824
825// TestH1H2NoVia tests that server does not add value to existing Via
826// header field to and from backend server.
827func TestH1H2NoVia(t *testing.T) {
828	st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
829		if got, want := r.Header.Get("Via"), "foo"; got != want {
830			t.Errorf("Via: %v; want %v", got, want)
831		}
832		w.Header().Add("Via", "bar")
833	})
834	defer st.Close()
835
836	res, err := st.http1(requestParam{
837		name: "TestH1H2NoVia",
838		header: []hpack.HeaderField{
839			pair("via", "foo"),
840		},
841	})
842	if err != nil {
843		t.Fatalf("Error st.http1() = %v", err)
844	}
845	if got, want := res.header.Get("Via"), "bar"; got != want {
846		t.Errorf("Via: %v; want %v", got, want)
847	}
848}
849
850// TestH1H2ReqPhaseReturn tests mruby request phase hook returns
851// custom response.
852func TestH1H2ReqPhaseReturn(t *testing.T) {
853	st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
854		t.Fatalf("request should not be forwarded")
855	})
856	defer st.Close()
857
858	res, err := st.http1(requestParam{
859		name: "TestH1H2ReqPhaseReturn",
860	})
861	if err != nil {
862		t.Fatalf("Error st.http1() = %v", err)
863	}
864
865	if got, want := res.status, 404; got != want {
866		t.Errorf("status = %v; want %v", got, want)
867	}
868
869	hdtests := []struct {
870		k, v string
871	}{
872		{"content-length", "20"},
873		{"from", "mruby"},
874	}
875	for _, tt := range hdtests {
876		if got, want := res.header.Get(tt.k), tt.v; got != want {
877			t.Errorf("%v = %v; want %v", tt.k, got, want)
878		}
879	}
880
881	if got, want := string(res.body), "Hello World from req"; got != want {
882		t.Errorf("body = %v; want %v", got, want)
883	}
884}
885
886// TestH1H2RespPhaseReturn tests mruby response phase hook returns
887// custom response.
888func TestH1H2RespPhaseReturn(t *testing.T) {
889	st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
890	defer st.Close()
891
892	res, err := st.http1(requestParam{
893		name: "TestH1H2RespPhaseReturn",
894	})
895	if err != nil {
896		t.Fatalf("Error st.http1() = %v", err)
897	}
898
899	if got, want := res.status, 404; got != want {
900		t.Errorf("status = %v; want %v", got, want)
901	}
902
903	hdtests := []struct {
904		k, v string
905	}{
906		{"content-length", "21"},
907		{"from", "mruby"},
908	}
909	for _, tt := range hdtests {
910		if got, want := res.header.Get(tt.k), tt.v; got != want {
911			t.Errorf("%v = %v; want %v", tt.k, got, want)
912		}
913	}
914
915	if got, want := string(res.body), "Hello World from resp"; got != want {
916		t.Errorf("body = %v; want %v", got, want)
917	}
918}
919
920// TestH1H2TE tests that "te: trailers" header is forwarded to HTTP/2
921// backend server by stripping other encodings.
922func TestH1H2TE(t *testing.T) {
923	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
924		if got, want := r.Header.Get("te"), "trailers"; got != want {
925			t.Errorf("te: %v; want %v", got, want)
926		}
927	})
928	defer st.Close()
929
930	res, err := st.http1(requestParam{
931		name: "TestH1H2TE",
932		header: []hpack.HeaderField{
933			pair("te", "foo,trailers,bar"),
934		},
935	})
936	if err != nil {
937		t.Fatalf("Error st.http1() = %v", err)
938	}
939	if got, want := res.status, 200; got != want {
940		t.Errorf("status: %v; want %v", got, want)
941	}
942}
943
944// TestH1APIBackendconfig exercise backendconfig API endpoint routine
945// for successful case.
946func TestH1APIBackendconfig(t *testing.T) {
947	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
948		t.Fatalf("request should not be forwarded")
949	}, 3010)
950	defer st.Close()
951
952	res, err := st.http1(requestParam{
953		name:   "TestH1APIBackendconfig",
954		path:   "/api/v1beta1/backendconfig",
955		method: "PUT",
956		body: []byte(`# comment
957backend=127.0.0.1,3011
958
959`),
960	})
961	if err != nil {
962		t.Fatalf("Error st.http1() = %v", err)
963	}
964	if got, want := res.status, 200; got != want {
965		t.Errorf("res.status: %v; want %v", got, want)
966	}
967
968	var apiResp APIResponse
969	err = json.Unmarshal(res.body, &apiResp)
970	if err != nil {
971		t.Fatalf("Error unmarshaling API response: %v", err)
972	}
973	if got, want := apiResp.Status, "Success"; got != want {
974		t.Errorf("apiResp.Status: %v; want %v", got, want)
975	}
976	if got, want := apiResp.Code, 200; got != want {
977		t.Errorf("apiResp.Status: %v; want %v", got, want)
978	}
979}
980
981// TestH1APIBackendconfigQuery exercise backendconfig API endpoint
982// routine with query.
983func TestH1APIBackendconfigQuery(t *testing.T) {
984	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
985		t.Fatalf("request should not be forwarded")
986	}, 3010)
987	defer st.Close()
988
989	res, err := st.http1(requestParam{
990		name:   "TestH1APIBackendconfigQuery",
991		path:   "/api/v1beta1/backendconfig?foo=bar",
992		method: "PUT",
993		body: []byte(`# comment
994backend=127.0.0.1,3011
995
996`),
997	})
998	if err != nil {
999		t.Fatalf("Error st.http1() = %v", err)
1000	}
1001	if got, want := res.status, 200; got != want {
1002		t.Errorf("res.status: %v; want %v", got, want)
1003	}
1004
1005	var apiResp APIResponse
1006	err = json.Unmarshal(res.body, &apiResp)
1007	if err != nil {
1008		t.Fatalf("Error unmarshaling API response: %v", err)
1009	}
1010	if got, want := apiResp.Status, "Success"; got != want {
1011		t.Errorf("apiResp.Status: %v; want %v", got, want)
1012	}
1013	if got, want := apiResp.Code, 200; got != want {
1014		t.Errorf("apiResp.Status: %v; want %v", got, want)
1015	}
1016}
1017
1018// TestH1APIBackendconfigBadMethod exercise backendconfig API endpoint
1019// routine with bad method.
1020func TestH1APIBackendconfigBadMethod(t *testing.T) {
1021	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1022		t.Fatalf("request should not be forwarded")
1023	}, 3010)
1024	defer st.Close()
1025
1026	res, err := st.http1(requestParam{
1027		name:   "TestH1APIBackendconfigBadMethod",
1028		path:   "/api/v1beta1/backendconfig",
1029		method: "GET",
1030		body: []byte(`# comment
1031backend=127.0.0.1,3011
1032
1033`),
1034	})
1035	if err != nil {
1036		t.Fatalf("Error st.http1() = %v", err)
1037	}
1038	if got, want := res.status, 405; got != want {
1039		t.Errorf("res.status: %v; want %v", got, want)
1040	}
1041
1042	var apiResp APIResponse
1043	err = json.Unmarshal(res.body, &apiResp)
1044	if err != nil {
1045		t.Fatalf("Error unmarshaling API response: %v", err)
1046	}
1047	if got, want := apiResp.Status, "Failure"; got != want {
1048		t.Errorf("apiResp.Status: %v; want %v", got, want)
1049	}
1050	if got, want := apiResp.Code, 405; got != want {
1051		t.Errorf("apiResp.Status: %v; want %v", got, want)
1052	}
1053}
1054
1055// TestH1APIConfigrevision tests configrevision API.
1056func TestH1APIConfigrevision(t *testing.T) {
1057	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1058		t.Fatalf("request should not be forwarded")
1059	}, 3010)
1060	defer st.Close()
1061
1062	res, err := st.http1(requestParam{
1063		name:   "TestH1APIConfigrevision",
1064		path:   "/api/v1beta1/configrevision",
1065		method: "GET",
1066	})
1067	if err != nil {
1068		t.Fatalf("Error st.http1() = %v", err)
1069	}
1070	if got, want := res.status, 200; got != want {
1071		t.Errorf("res.status: %v; want = %v", got, want)
1072	}
1073
1074	var apiResp APIResponse
1075	d := json.NewDecoder(bytes.NewBuffer(res.body))
1076	d.UseNumber()
1077	err = d.Decode(&apiResp)
1078	if err != nil {
1079		t.Fatalf("Error unmarshalling API response: %v", err)
1080	}
1081	if got, want := apiResp.Status, "Success"; got != want {
1082		t.Errorf("apiResp.Status: %v; want %v", got, want)
1083	}
1084	if got, want := apiResp.Code, 200; got != want {
1085		t.Errorf("apiResp.Status: %v; want %v", got, want)
1086	}
1087	if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want {
1088		t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want)
1089	}
1090}
1091
1092// TestH1APINotFound exercise backendconfig API endpoint routine when
1093// API endpoint is not found.
1094func TestH1APINotFound(t *testing.T) {
1095	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1096		t.Fatalf("request should not be forwarded")
1097	}, 3010)
1098	defer st.Close()
1099
1100	res, err := st.http1(requestParam{
1101		name:   "TestH1APINotFound",
1102		path:   "/api/notfound",
1103		method: "GET",
1104		body: []byte(`# comment
1105backend=127.0.0.1,3011
1106
1107`),
1108	})
1109	if err != nil {
1110		t.Fatalf("Error st.http1() = %v", err)
1111	}
1112	if got, want := res.status, 404; got != want {
1113		t.Errorf("res.status: %v; want %v", got, want)
1114	}
1115
1116	var apiResp APIResponse
1117	err = json.Unmarshal(res.body, &apiResp)
1118	if err != nil {
1119		t.Fatalf("Error unmarshaling API response: %v", err)
1120	}
1121	if got, want := apiResp.Status, "Failure"; got != want {
1122		t.Errorf("apiResp.Status: %v; want %v", got, want)
1123	}
1124	if got, want := apiResp.Code, 404; got != want {
1125		t.Errorf("apiResp.Status: %v; want %v", got, want)
1126	}
1127}
1128
1129// TestH1Healthmon tests health monitor endpoint.
1130func TestH1Healthmon(t *testing.T) {
1131	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3011;healthmon;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1132		t.Fatalf("request should not be forwarded")
1133	}, 3011)
1134	defer st.Close()
1135
1136	res, err := st.http1(requestParam{
1137		name: "TestH1Healthmon",
1138		path: "/alpha/bravo",
1139	})
1140	if err != nil {
1141		t.Fatalf("Error st.http1() = %v", err)
1142	}
1143	if got, want := res.status, 200; got != want {
1144		t.Errorf("res.status: %v; want %v", got, want)
1145	}
1146}
1147
1148// TestH1ResponseBeforeRequestEnd tests the situation where response
1149// ends before request body finishes.
1150func TestH1ResponseBeforeRequestEnd(t *testing.T) {
1151	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
1152		t.Fatal("request should not be forwarded")
1153	})
1154	defer st.Close()
1155
1156	if _, err := io.WriteString(st.conn, fmt.Sprintf(`POST / HTTP/1.1
1157Host: %v
1158Test-Case: TestH1ResponseBeforeRequestEnd
1159Content-Length: 1000000
1160
1161`, st.authority)); err != nil {
1162		t.Fatalf("Error io.WriteString() = %v", err)
1163	}
1164
1165	resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
1166	if err != nil {
1167		t.Fatalf("Error http.ReadResponse() = %v", err)
1168	}
1169
1170	if got, want := resp.StatusCode, 404; got != want {
1171		t.Errorf("status: %v; want %v", got, want)
1172	}
1173}
1174