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