• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package nghttp2
2
3import (
4	"bytes"
5	"crypto/tls"
6	"encoding/json"
7	"errors"
8	"fmt"
9	"io"
10	"net"
11	"net/http"
12	"regexp"
13	"strings"
14	"syscall"
15	"testing"
16	"time"
17
18	"golang.org/x/net/http2"
19	"golang.org/x/net/http2/hpack"
20)
21
22// TestH2H1PlainGET tests whether simple HTTP/2 GET request works.
23func TestH2H1PlainGET(t *testing.T) {
24	st := newServerTester(t, options{})
25	defer st.Close()
26
27	res, err := st.http2(requestParam{
28		name: "TestH2H1PlainGET",
29	})
30	if err != nil {
31		t.Fatalf("Error st.http2() = %v", err)
32	}
33
34	if got, want := res.status, http.StatusOK; got != want {
35		t.Errorf("status = %v; want %v", got, want)
36	}
37}
38
39// TestH2H1AddXfp tests that server appends :scheme to the existing
40// x-forwarded-proto header field.
41func TestH2H1AddXfp(t *testing.T) {
42	opts := options{
43		args: []string{"--no-strip-incoming-x-forwarded-proto"},
44		handler: func(_ http.ResponseWriter, r *http.Request) {
45			xfp := r.Header.Get("X-Forwarded-Proto")
46			if got, want := xfp, "foo, http"; got != want {
47				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
48			}
49		},
50	}
51
52	st := newServerTester(t, opts)
53	defer st.Close()
54
55	res, err := st.http2(requestParam{
56		name: "TestH2H1AddXfp",
57		header: []hpack.HeaderField{
58			pair("x-forwarded-proto", "foo"),
59		},
60	})
61	if err != nil {
62		t.Fatalf("Error st.http2() = %v", err)
63	}
64
65	if got, want := res.status, http.StatusOK; got != want {
66		t.Errorf("status = %v; want %v", got, want)
67	}
68}
69
70// TestH2H1NoAddXfp tests that server does not append :scheme to the
71// existing x-forwarded-proto header field.
72func TestH2H1NoAddXfp(t *testing.T) {
73	opts := options{
74		args: []string{
75			"--no-add-x-forwarded-proto",
76			"--no-strip-incoming-x-forwarded-proto",
77		},
78		handler: func(_ http.ResponseWriter, r *http.Request) {
79			xfp := r.Header.Get("X-Forwarded-Proto")
80			if got, want := xfp, "foo"; got != want {
81				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
82			}
83		},
84	}
85
86	st := newServerTester(t, opts)
87	defer st.Close()
88
89	res, err := st.http2(requestParam{
90		name: "TestH2H1NoAddXfp",
91		header: []hpack.HeaderField{
92			pair("x-forwarded-proto", "foo"),
93		},
94	})
95	if err != nil {
96		t.Fatalf("Error st.http2() = %v", err)
97	}
98
99	if got, want := res.status, http.StatusOK; got != want {
100		t.Errorf("status = %v; want %v", got, want)
101	}
102}
103
104// TestH2H1StripXfp tests that server strips incoming
105// x-forwarded-proto header field.
106func TestH2H1StripXfp(t *testing.T) {
107	opts := options{
108		handler: func(_ http.ResponseWriter, r *http.Request) {
109			xfp := r.Header.Get("X-Forwarded-Proto")
110			if got, want := xfp, "http"; got != want {
111				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
112			}
113		},
114	}
115
116	st := newServerTester(t, opts)
117	defer st.Close()
118
119	res, err := st.http2(requestParam{
120		name: "TestH2H1StripXfp",
121		header: []hpack.HeaderField{
122			pair("x-forwarded-proto", "foo"),
123		},
124	})
125	if err != nil {
126		t.Fatalf("Error st.http2() = %v", err)
127	}
128
129	if got, want := res.status, http.StatusOK; got != want {
130		t.Errorf("status = %v; want %v", got, want)
131	}
132}
133
134// TestH2H1StripNoAddXfp tests that server strips incoming
135// x-forwarded-proto header field, and does not add another.
136func TestH2H1StripNoAddXfp(t *testing.T) {
137	opts := options{
138		args: []string{"--no-add-x-forwarded-proto"},
139		handler: func(_ http.ResponseWriter, r *http.Request) {
140			if got, found := r.Header["X-Forwarded-Proto"]; found {
141				t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
142			}
143		},
144	}
145
146	st := newServerTester(t, opts)
147	defer st.Close()
148
149	res, err := st.http2(requestParam{
150		name: "TestH2H1StripNoAddXfp",
151		header: []hpack.HeaderField{
152			pair("x-forwarded-proto", "foo"),
153		},
154	})
155	if err != nil {
156		t.Fatalf("Error st.http2() = %v", err)
157	}
158
159	if got, want := res.status, http.StatusOK; got != want {
160		t.Errorf("status = %v; want %v", got, want)
161	}
162}
163
164// TestH2H1AddXff tests that server generates X-Forwarded-For header
165// field when forwarding request to backend.
166func TestH2H1AddXff(t *testing.T) {
167	opts := options{
168		args: []string{"--add-x-forwarded-for"},
169		handler: func(_ http.ResponseWriter, r *http.Request) {
170			xff := r.Header.Get("X-Forwarded-For")
171			want := "127.0.0.1"
172			if xff != want {
173				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
174			}
175		},
176	}
177
178	st := newServerTester(t, opts)
179	defer st.Close()
180
181	res, err := st.http2(requestParam{
182		name: "TestH2H1AddXff",
183	})
184	if err != nil {
185		t.Fatalf("Error st.http2() = %v", err)
186	}
187
188	if got, want := res.status, http.StatusOK; got != want {
189		t.Errorf("status = %v; want %v", got, want)
190	}
191}
192
193// TestH2H1AddXff2 tests that server appends X-Forwarded-For header
194// field to existing one when forwarding request to backend.
195func TestH2H1AddXff2(t *testing.T) {
196	opts := options{
197		args: []string{"--add-x-forwarded-for"},
198		handler: func(_ http.ResponseWriter, r *http.Request) {
199			xff := r.Header.Get("X-Forwarded-For")
200			want := "host, 127.0.0.1"
201			if xff != want {
202				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
203			}
204		},
205	}
206
207	st := newServerTester(t, opts)
208	defer st.Close()
209
210	res, err := st.http2(requestParam{
211		name: "TestH2H1AddXff2",
212		header: []hpack.HeaderField{
213			pair("x-forwarded-for", "host"),
214		},
215	})
216	if err != nil {
217		t.Fatalf("Error st.http2() = %v", err)
218	}
219
220	if got, want := res.status, http.StatusOK; got != want {
221		t.Errorf("status = %v; want %v", got, want)
222	}
223}
224
225// TestH2H1StripXff tests that --strip-incoming-x-forwarded-for
226// option.
227func TestH2H1StripXff(t *testing.T) {
228	opts := options{
229		args: []string{"--strip-incoming-x-forwarded-for"},
230		handler: func(_ http.ResponseWriter, r *http.Request) {
231			if xff, found := r.Header["X-Forwarded-For"]; found {
232				t.Errorf("X-Forwarded-For = %v; want nothing", xff)
233			}
234		},
235	}
236
237	st := newServerTester(t, opts)
238	defer st.Close()
239
240	res, err := st.http2(requestParam{
241		name: "TestH2H1StripXff",
242		header: []hpack.HeaderField{
243			pair("x-forwarded-for", "host"),
244		},
245	})
246	if err != nil {
247		t.Fatalf("Error st.http2() = %v", err)
248	}
249
250	if got, want := res.status, http.StatusOK; got != want {
251		t.Errorf("status = %v; want %v", got, want)
252	}
253}
254
255// TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and
256// --add-x-forwarded-for options.
257func TestH2H1StripAddXff(t *testing.T) {
258	opts := options{
259		args: []string{
260			"--strip-incoming-x-forwarded-for",
261			"--add-x-forwarded-for",
262		},
263		handler: func(_ http.ResponseWriter, r *http.Request) {
264			xff := r.Header.Get("X-Forwarded-For")
265			want := "127.0.0.1"
266			if xff != want {
267				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
268			}
269		},
270	}
271
272	st := newServerTester(t, opts)
273	defer st.Close()
274
275	res, err := st.http2(requestParam{
276		name: "TestH2H1StripAddXff",
277		header: []hpack.HeaderField{
278			pair("x-forwarded-for", "host"),
279		},
280	})
281	if err != nil {
282		t.Fatalf("Error st.http2() = %v", err)
283	}
284
285	if got, want := res.status, http.StatusOK; got != want {
286		t.Errorf("status = %v; want %v", got, want)
287	}
288}
289
290// TestH2H1AddForwardedObfuscated tests that server generates
291// Forwarded header field with obfuscated "by" and "for" parameters.
292func TestH2H1AddForwardedObfuscated(t *testing.T) {
293	opts := options{
294		args: []string{"--add-forwarded=by,for,host,proto"},
295		handler: func(_ http.ResponseWriter, r *http.Request) {
296			pattern := fmt.Sprintf(`by=_[^;]+;for=_[^;]+;host="127\.0\.0\.1:%v";proto=http`, serverPort)
297			validFwd := regexp.MustCompile(pattern)
298			got := r.Header.Get("Forwarded")
299
300			if !validFwd.MatchString(got) {
301				t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
302			}
303		},
304	}
305
306	st := newServerTester(t, opts)
307	defer st.Close()
308
309	res, err := st.http2(requestParam{
310		name: "TestH2H1AddForwardedObfuscated",
311	})
312	if err != nil {
313		t.Fatalf("Error st.http2() = %v", err)
314	}
315
316	if got, want := res.status, http.StatusOK; got != want {
317		t.Errorf("status: %v; want %v", got, want)
318	}
319}
320
321// TestH2H1AddForwardedByIP tests that server generates Forwarded header
322// field with IP address in "by" parameter.
323func TestH2H1AddForwardedByIP(t *testing.T) {
324	opts := options{
325		args: []string{"--add-forwarded=by,for", "--forwarded-by=ip"},
326		handler: func(_ http.ResponseWriter, r *http.Request) {
327			pattern := fmt.Sprintf(`by="127\.0\.0\.1:%v";for=_[^;]+`, serverPort)
328			validFwd := regexp.MustCompile(pattern)
329			if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
330				t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
331			}
332		},
333	}
334
335	st := newServerTester(t, opts)
336	defer st.Close()
337
338	res, err := st.http2(requestParam{
339		name: "TestH2H1AddForwardedByIP",
340	})
341	if err != nil {
342		t.Fatalf("Error st.http2() = %v", err)
343	}
344
345	if got, want := res.status, http.StatusOK; got != want {
346		t.Errorf("status: %v; want %v", got, want)
347	}
348}
349
350// TestH2H1AddForwardedForIP tests that server generates Forwarded header
351// field with IP address in "for" parameters.
352func TestH2H1AddForwardedForIP(t *testing.T) {
353	opts := options{
354		args: []string{
355			"--add-forwarded=by,for,host,proto",
356			"--forwarded-by=_alpha",
357			"--forwarded-for=ip",
358		},
359		handler: func(_ http.ResponseWriter, r *http.Request) {
360			want := fmt.Sprintf(`by=_alpha;for=127.0.0.1;host="127.0.0.1:%v";proto=http`, serverPort)
361			if got := r.Header.Get("Forwarded"); got != want {
362				t.Errorf("Forwarded = %v; want %v", got, want)
363			}
364		},
365	}
366
367	st := newServerTester(t, opts)
368	defer st.Close()
369
370	res, err := st.http2(requestParam{
371		name: "TestH2H1AddForwardedForIP",
372	})
373	if err != nil {
374		t.Fatalf("Error st.http2() = %v", err)
375	}
376
377	if got, want := res.status, http.StatusOK; got != want {
378		t.Errorf("status: %v; want %v", got, want)
379	}
380}
381
382// TestH2H1AddForwardedMerge tests that server generates Forwarded
383// header field with IP address in "by" and "for" parameters.  The
384// generated values must be appended to the existing value.
385func TestH2H1AddForwardedMerge(t *testing.T) {
386	opts := options{
387		args: []string{"--add-forwarded=proto"},
388		handler: func(_ http.ResponseWriter, r *http.Request) {
389			if got, want := r.Header.Get("Forwarded"), `host=foo, proto=http`; got != want {
390				t.Errorf("Forwarded = %v; want %v", got, want)
391			}
392		},
393	}
394
395	st := newServerTester(t, opts)
396	defer st.Close()
397
398	res, err := st.http2(requestParam{
399		name: "TestH2H1AddForwardedMerge",
400		header: []hpack.HeaderField{
401			pair("forwarded", "host=foo"),
402		},
403	})
404	if err != nil {
405		t.Fatalf("Error st.http2() = %v", err)
406	}
407
408	if got, want := res.status, http.StatusOK; got != want {
409		t.Errorf("status: %v; want %v", got, want)
410	}
411}
412
413// TestH2H1AddForwardedStrip tests that server generates Forwarded
414// header field with IP address in "by" and "for" parameters.  The
415// generated values must not include the existing value.
416func TestH2H1AddForwardedStrip(t *testing.T) {
417	opts := options{
418		args: []string{
419			"--strip-incoming-forwarded",
420			"--add-forwarded=proto",
421		},
422		handler: func(_ http.ResponseWriter, r *http.Request) {
423			if got, want := r.Header.Get("Forwarded"), `proto=http`; got != want {
424				t.Errorf("Forwarded = %v; want %v", got, want)
425			}
426		},
427	}
428
429	st := newServerTester(t, opts)
430	defer st.Close()
431
432	res, err := st.http2(requestParam{
433		name: "TestH2H1AddForwardedStrip",
434		header: []hpack.HeaderField{
435			pair("forwarded", "host=foo"),
436		},
437	})
438	if err != nil {
439		t.Fatalf("Error st.http2() = %v", err)
440	}
441
442	if got, want := res.status, http.StatusOK; got != want {
443		t.Errorf("status: %v; want %v", got, want)
444	}
445}
446
447// TestH2H1StripForwarded tests that server strips incoming Forwarded
448// header field.
449func TestH2H1StripForwarded(t *testing.T) {
450	opts := options{
451		args: []string{"--strip-incoming-forwarded"},
452		handler: func(_ http.ResponseWriter, r *http.Request) {
453			if got, found := r.Header["Forwarded"]; found {
454				t.Errorf("Forwarded = %v; want nothing", got)
455			}
456		},
457	}
458
459	st := newServerTester(t, opts)
460	defer st.Close()
461
462	res, err := st.http2(requestParam{
463		name: "TestH2H1StripForwarded",
464		header: []hpack.HeaderField{
465			pair("forwarded", "host=foo"),
466		},
467	})
468	if err != nil {
469		t.Fatalf("Error st.http2() = %v", err)
470	}
471
472	if got, want := res.status, http.StatusOK; got != want {
473		t.Errorf("status: %v; want %v", got, want)
474	}
475}
476
477// TestH2H1AddForwardedStatic tests that server generates Forwarded
478// header field with the given static obfuscated string for "by"
479// parameter.
480func TestH2H1AddForwardedStatic(t *testing.T) {
481	opts := options{
482		args: []string{
483			"--add-forwarded=by,for",
484			"--forwarded-by=_alpha",
485		},
486		handler: func(_ http.ResponseWriter, r *http.Request) {
487			pattern := `by=_alpha;for=_[^;]+`
488			validFwd := regexp.MustCompile(pattern)
489			if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
490				t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
491			}
492		},
493	}
494
495	st := newServerTester(t, opts)
496	defer st.Close()
497
498	res, err := st.http2(requestParam{
499		name: "TestH2H1AddForwardedStatic",
500	})
501	if err != nil {
502		t.Fatalf("Error st.http2() = %v", err)
503	}
504
505	if got, want := res.status, http.StatusOK; got != want {
506		t.Errorf("status: %v; want %v", got, want)
507	}
508}
509
510// TestH2H1GenerateVia tests that server generates Via header field to and
511// from backend server.
512func TestH2H1GenerateVia(t *testing.T) {
513	opts := options{
514		handler: func(_ http.ResponseWriter, r *http.Request) {
515			if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want {
516				t.Errorf("Via: %v; want %v", got, want)
517			}
518		},
519	}
520
521	st := newServerTester(t, opts)
522	defer st.Close()
523
524	res, err := st.http2(requestParam{
525		name: "TestH2H1GenerateVia",
526	})
527	if err != nil {
528		t.Fatalf("Error st.http2() = %v", err)
529	}
530
531	if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
532		t.Errorf("Via: %v; want %v", got, want)
533	}
534}
535
536// TestH2H1AppendVia tests that server adds value to existing Via
537// header field to and from backend server.
538func TestH2H1AppendVia(t *testing.T) {
539	opts := options{
540		handler: func(w http.ResponseWriter, r *http.Request) {
541			if got, want := r.Header.Get("Via"), "foo, 2 nghttpx"; got != want {
542				t.Errorf("Via: %v; want %v", got, want)
543			}
544			w.Header().Add("Via", "bar")
545		},
546	}
547
548	st := newServerTester(t, opts)
549	defer st.Close()
550
551	res, err := st.http2(requestParam{
552		name: "TestH2H1AppendVia",
553		header: []hpack.HeaderField{
554			pair("via", "foo"),
555		},
556	})
557	if err != nil {
558		t.Fatalf("Error st.http2() = %v", err)
559	}
560
561	if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
562		t.Errorf("Via: %v; want %v", got, want)
563	}
564}
565
566// TestH2H1NoVia tests that server does not add value to existing Via
567// header field to and from backend server.
568func TestH2H1NoVia(t *testing.T) {
569	opts := options{
570		args: []string{"--no-via"},
571		handler: func(w http.ResponseWriter, r *http.Request) {
572			if got, want := r.Header.Get("Via"), "foo"; got != want {
573				t.Errorf("Via: %v; want %v", got, want)
574			}
575			w.Header().Add("Via", "bar")
576		},
577	}
578
579	st := newServerTester(t, opts)
580	defer st.Close()
581
582	res, err := st.http2(requestParam{
583		name: "TestH2H1NoVia",
584		header: []hpack.HeaderField{
585			pair("via", "foo"),
586		},
587	})
588	if err != nil {
589		t.Fatalf("Error st.http2() = %v", err)
590	}
591
592	if got, want := res.header.Get("Via"), "bar"; got != want {
593		t.Errorf("Via: %v; want %v", got, want)
594	}
595}
596
597// TestH2H1HostRewrite tests that server rewrites host header field
598func TestH2H1HostRewrite(t *testing.T) {
599	opts := options{
600		args: []string{"--host-rewrite"},
601		handler: func(w http.ResponseWriter, r *http.Request) {
602			w.Header().Add("request-host", r.Host)
603		},
604	}
605
606	st := newServerTester(t, opts)
607	defer st.Close()
608
609	res, err := st.http2(requestParam{
610		name: "TestH2H1HostRewrite",
611	})
612	if err != nil {
613		t.Fatalf("Error st.http2() = %v", err)
614	}
615
616	if got, want := res.status, http.StatusOK; got != want {
617		t.Errorf("status: %v; want %v", got, want)
618	}
619
620	if got, want := res.header.Get("request-host"), st.backendHost; got != want {
621		t.Errorf("request-host: %v; want %v", got, want)
622	}
623}
624
625// TestH2H1NoHostRewrite tests that server does not rewrite host
626// header field
627func TestH2H1NoHostRewrite(t *testing.T) {
628	opts := options{
629		handler: func(w http.ResponseWriter, r *http.Request) {
630			w.Header().Add("request-host", r.Host)
631		},
632	}
633
634	st := newServerTester(t, opts)
635	defer st.Close()
636
637	res, err := st.http2(requestParam{
638		name: "TestH2H1NoHostRewrite",
639	})
640	if err != nil {
641		t.Fatalf("Error st.http2() = %v", err)
642	}
643
644	if got, want := res.status, http.StatusOK; got != want {
645		t.Errorf("status: %v; want %v", got, want)
646	}
647
648	if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
649		t.Errorf("request-host: %v; want %v", got, want)
650	}
651}
652
653// TestH2H1BadRequestCL tests that server rejects request whose
654// content-length header field value does not match its request body
655// size.
656func TestH2H1BadRequestCL(t *testing.T) {
657	st := newServerTester(t, options{})
658	defer st.Close()
659
660	// we set content-length: 1024, but the actual request body is
661	// 3 bytes.
662	res, err := st.http2(requestParam{
663		name:   "TestH2H1BadRequestCL",
664		method: "POST",
665		header: []hpack.HeaderField{
666			pair("content-length", "1024"),
667		},
668		body: []byte("foo"),
669	})
670	if err != nil {
671		t.Fatalf("Error st.http2() = %v", err)
672	}
673
674	want := http2.ErrCodeProtocol
675	if res.errCode != want {
676		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
677	}
678}
679
680// TestH2H1BadResponseCL tests that server returns error when
681// content-length response header field value does not match its
682// response body size.
683func TestH2H1BadResponseCL(t *testing.T) {
684	opts := options{
685		handler: func(w http.ResponseWriter, _ *http.Request) {
686			// we set content-length: 1024, but only send 3 bytes.
687			w.Header().Add("Content-Length", "1024")
688			if _, err := w.Write([]byte("foo")); err != nil {
689				t.Fatalf("Error w.Write() = %v", err)
690			}
691		},
692	}
693
694	st := newServerTester(t, opts)
695	defer st.Close()
696
697	res, err := st.http2(requestParam{
698		name: "TestH2H1BadResponseCL",
699	})
700	if err != nil {
701		t.Fatalf("Error st.http2() = %v", err)
702	}
703
704	want := http2.ErrCodeInternal
705	if res.errCode != want {
706		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
707	}
708}
709
710// TestH2H1LocationRewrite tests location header field rewriting
711// works.
712func TestH2H1LocationRewrite(t *testing.T) {
713	opts := options{
714		handler: func(w http.ResponseWriter, _ *http.Request) {
715			// TODO we cannot get st.ts's port number
716			// here.. 8443 is just a place holder.  We
717			// ignore it on rewrite.
718			w.Header().Add("Location", "http://127.0.0.1:8443/p/q?a=b#fragment")
719		},
720	}
721
722	st := newServerTester(t, opts)
723	defer st.Close()
724
725	res, err := st.http2(requestParam{
726		name: "TestH2H1LocationRewrite",
727	})
728	if err != nil {
729		t.Fatalf("Error st.http2() = %v", err)
730	}
731
732	want := fmt.Sprintf("http://127.0.0.1:%v/p/q?a=b#fragment", serverPort)
733	if got := res.header.Get("Location"); got != want {
734		t.Errorf("Location: %v; want %v", got, want)
735	}
736}
737
738// TestH2H1ChunkedRequestBody tests that chunked request body works.
739func TestH2H1ChunkedRequestBody(t *testing.T) {
740	opts := options{
741		handler: func(_ http.ResponseWriter, r *http.Request) {
742			want := "[chunked]"
743			if got := fmt.Sprint(r.TransferEncoding); got != want {
744				t.Errorf("Transfer-Encoding: %v; want %v", got, want)
745			}
746			body, err := io.ReadAll(r.Body)
747			if err != nil {
748				t.Fatalf("Error reading r.body: %v", err)
749			}
750			want = "foo"
751			if got := string(body); got != want {
752				t.Errorf("body: %v; want %v", got, want)
753			}
754		},
755	}
756
757	st := newServerTester(t, opts)
758	defer st.Close()
759
760	res, err := st.http2(requestParam{
761		name:   "TestH2H1ChunkedRequestBody",
762		method: "POST",
763		body:   []byte("foo"),
764	})
765	if err != nil {
766		t.Fatalf("Error st.http2() = %v", err)
767	}
768
769	if got, want := res.status, http.StatusOK; got != want {
770		t.Errorf("status = %v; want %v", got, want)
771	}
772}
773
774// TestH2H1MultipleRequestCL tests that server rejects request with
775// multiple Content-Length request header fields.
776func TestH2H1MultipleRequestCL(t *testing.T) {
777	opts := options{
778		handler: func(http.ResponseWriter, *http.Request) {
779			t.Errorf("server should not forward bad request")
780		},
781	}
782
783	st := newServerTester(t, opts)
784	defer st.Close()
785
786	res, err := st.http2(requestParam{
787		name: "TestH2H1MultipleRequestCL",
788		header: []hpack.HeaderField{
789			pair("content-length", "1"),
790			pair("content-length", "1"),
791		},
792	})
793	if err != nil {
794		t.Fatalf("Error st.http2() = %v", err)
795	}
796
797	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
798		t.Errorf("res.errCode: %v; want %v", got, want)
799	}
800}
801
802// TestH2H1InvalidRequestCL tests that server rejects request with
803// Content-Length which cannot be parsed as a number.
804func TestH2H1InvalidRequestCL(t *testing.T) {
805	opts := options{
806		handler: func(http.ResponseWriter, *http.Request) {
807			t.Errorf("server should not forward bad request")
808		},
809	}
810
811	st := newServerTester(t, opts)
812	defer st.Close()
813
814	res, err := st.http2(requestParam{
815		name: "TestH2H1InvalidRequestCL",
816		header: []hpack.HeaderField{
817			pair("content-length", ""),
818		},
819	})
820	if err != nil {
821		t.Fatalf("Error st.http2() = %v", err)
822	}
823
824	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
825		t.Errorf("res.errCode: %v; want %v", got, want)
826	}
827}
828
829// // TestH2H1ConnectFailure tests that server handles the situation that
830// // connection attempt to HTTP/1 backend failed.
831// func TestH2H1ConnectFailure(t *testing.T) {
832// 	st := newServerTester(t, options{})
833// 	defer st.Close()
834
835// 	// shutdown backend server to simulate backend connect failure
836// 	st.ts.Close()
837
838// 	res, err := st.http2(requestParam{
839// 		name: "TestH2H1ConnectFailure",
840// 	})
841// 	if err != nil {
842// 		t.Fatalf("Error st.http2() = %v", err)
843// 	}
844// 	want := 503
845// 	if got := res.status; got != want {
846// 		t.Errorf("status: %v; want %v", got, want)
847// 	}
848// }
849
850// TestH2H1InvalidMethod tests that server rejects invalid method with
851// 501.
852func TestH2H1InvalidMethod(t *testing.T) {
853	opts := options{
854		handler: func(http.ResponseWriter, *http.Request) {
855			t.Errorf("server should not forward this request")
856		},
857	}
858
859	st := newServerTester(t, opts)
860	defer st.Close()
861
862	res, err := st.http2(requestParam{
863		name:   "TestH2H1InvalidMethod",
864		method: "get",
865	})
866	if err != nil {
867		t.Fatalf("Error st.http2() = %v", err)
868	}
869
870	if got, want := res.status, http.StatusNotImplemented; got != want {
871		t.Errorf("status: %v; want %v", got, want)
872	}
873}
874
875// TestH2H1BadAuthority tests that server rejects request including
876// bad characters in :authority header field.
877func TestH2H1BadAuthority(t *testing.T) {
878	opts := options{
879		handler: func(http.ResponseWriter, *http.Request) {
880			t.Errorf("server should not forward this request")
881		},
882	}
883
884	st := newServerTester(t, opts)
885	defer st.Close()
886
887	res, err := st.http2(requestParam{
888		name:      "TestH2H1BadAuthority",
889		authority: `foo\bar`,
890	})
891	if err != nil {
892		t.Fatalf("Error st.http2() = %v", err)
893	}
894
895	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
896		t.Errorf("res.errCode: %v; want %v", got, want)
897	}
898}
899
900// TestH2H1BadScheme tests that server rejects request including
901// bad characters in :scheme header field.
902func TestH2H1BadScheme(t *testing.T) {
903	opts := options{
904		handler: func(http.ResponseWriter, *http.Request) {
905			t.Errorf("server should not forward this request")
906		},
907	}
908
909	st := newServerTester(t, opts)
910	defer st.Close()
911
912	res, err := st.http2(requestParam{
913		name:   "TestH2H1BadScheme",
914		scheme: "http*",
915	})
916	if err != nil {
917		t.Fatalf("Error st.http2() = %v", err)
918	}
919
920	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
921		t.Errorf("res.errCode: %v; want %v", got, want)
922	}
923}
924
925// TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2
926// request is assembled into 1 when forwarding to HTTP/1 backend link.
927func TestH2H1AssembleCookies(t *testing.T) {
928	opts := options{
929		handler: func(_ http.ResponseWriter, r *http.Request) {
930			if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
931				t.Errorf("Cookie: %v; want %v", got, want)
932			}
933		},
934	}
935
936	st := newServerTester(t, opts)
937	defer st.Close()
938
939	res, err := st.http2(requestParam{
940		name: "TestH2H1AssembleCookies",
941		header: []hpack.HeaderField{
942			pair("cookie", "alpha"),
943			pair("cookie", "bravo"),
944			pair("cookie", "charlie"),
945		},
946	})
947	if err != nil {
948		t.Fatalf("Error st.http2() = %v", err)
949	}
950
951	if got, want := res.status, http.StatusOK; got != want {
952		t.Errorf("status: %v; want %v", got, want)
953	}
954}
955
956// TestH2H1TETrailers tests that server accepts TE request header
957// field if it has trailers only.
958func TestH2H1TETrailers(t *testing.T) {
959	st := newServerTester(t, options{})
960	defer st.Close()
961
962	res, err := st.http2(requestParam{
963		name: "TestH2H1TETrailers",
964		header: []hpack.HeaderField{
965			pair("te", "trailers"),
966		},
967	})
968	if err != nil {
969		t.Fatalf("Error st.http2() = %v", err)
970	}
971
972	if got, want := res.status, http.StatusOK; got != want {
973		t.Errorf("status: %v; want %v", got, want)
974	}
975}
976
977// TestH2H1TEGzip tests that server resets stream if TE request header
978// field contains gzip.
979func TestH2H1TEGzip(t *testing.T) {
980	opts := options{
981		handler: func(http.ResponseWriter, *http.Request) {
982			t.Error("server should not forward bad request")
983		},
984	}
985
986	st := newServerTester(t, opts)
987	defer st.Close()
988
989	res, err := st.http2(requestParam{
990		name: "TestH2H1TEGzip",
991		header: []hpack.HeaderField{
992			pair("te", "gzip"),
993		},
994	})
995	if err != nil {
996		t.Fatalf("Error st.http2() = %v", err)
997	}
998
999	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
1000		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
1001	}
1002}
1003
1004// TestH2H1SNI tests server's TLS SNI extension feature.  It must
1005// choose appropriate certificate depending on the indicated
1006// server_name from client.
1007func TestH2H1SNI(t *testing.T) {
1008	opts := options{
1009		args: []string{"--subcert=" + testDir + "/alt-server.key:" + testDir + "/alt-server.crt"},
1010		tls:  true,
1011		tlsConfig: &tls.Config{
1012			ServerName: "alt-domain",
1013		},
1014	}
1015
1016	st := newServerTester(t, opts)
1017	defer st.Close()
1018
1019	tlsConn := st.conn.(*tls.Conn)
1020	connState := tlsConn.ConnectionState()
1021	cert := connState.PeerCertificates[0]
1022
1023	if got, want := cert.Subject.CommonName, "alt-domain"; got != want {
1024		t.Errorf("CommonName: %v; want %v", got, want)
1025	}
1026}
1027
1028// TestH2H1TLSXfp tests nghttpx sends x-forwarded-proto header field
1029// with http value since :scheme is http, even if the frontend
1030// connection is encrypted.
1031func TestH2H1TLSXfp(t *testing.T) {
1032	opts := options{
1033		handler: func(_ http.ResponseWriter, r *http.Request) {
1034			if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
1035				t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
1036			}
1037		},
1038		tls: true,
1039	}
1040
1041	st := newServerTester(t, opts)
1042	defer st.Close()
1043
1044	res, err := st.http2(requestParam{
1045		name: "TestH2H1TLSXfp",
1046	})
1047	if err != nil {
1048		t.Fatalf("Error st.http2() = %v", err)
1049	}
1050
1051	if got, want := res.status, http.StatusOK; got != want {
1052		t.Errorf("res.status: %v; want %v", got, want)
1053	}
1054}
1055
1056// TestH2H1ServerPush tests server push using Link header field from
1057// backend server.
1058func TestH2H1ServerPush(t *testing.T) {
1059	opts := options{
1060		handler: func(w http.ResponseWriter, r *http.Request) {
1061			// only resources marked as rel=preload are pushed
1062			if !strings.HasPrefix(r.URL.Path, "/css/") {
1063				w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
1064			}
1065		},
1066	}
1067
1068	st := newServerTester(t, opts)
1069	defer st.Close()
1070
1071	res, err := st.http2(requestParam{
1072		name: "TestH2H1ServerPush",
1073	})
1074	if err != nil {
1075		t.Fatalf("Error st.http2() = %v", err)
1076	}
1077
1078	if got, want := res.status, http.StatusOK; got != want {
1079		t.Errorf("res.status: %v; want %v", got, want)
1080	}
1081
1082	if got, want := len(res.pushResponse), 2; got != want {
1083		t.Fatalf("len(res.pushResponse): %v; want %v", got, want)
1084	}
1085
1086	mainCSS := res.pushResponse[0]
1087	if got, want := mainCSS.status, http.StatusOK; got != want {
1088		t.Errorf("mainCSS.status: %v; want %v", got, want)
1089	}
1090
1091	themeCSS := res.pushResponse[1]
1092	if got, want := themeCSS.status, http.StatusOK; got != want {
1093		t.Errorf("themeCSS.status: %v; want %v", got, want)
1094	}
1095}
1096
1097// TestH2H1RequestTrailer tests request trailer part is forwarded to
1098// backend.
1099func TestH2H1RequestTrailer(t *testing.T) {
1100	opts := options{
1101		handler: func(_ http.ResponseWriter, r *http.Request) {
1102			buf := make([]byte, 4096)
1103			for {
1104				_, err := r.Body.Read(buf)
1105				if err != nil {
1106					if errors.Is(err, io.EOF) {
1107						break
1108					}
1109
1110					t.Fatalf("r.Body.Read() = %v", err)
1111				}
1112			}
1113			if got, want := r.Trailer.Get("foo"), "bar"; got != want {
1114				t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
1115			}
1116		},
1117	}
1118
1119	st := newServerTester(t, opts)
1120	defer st.Close()
1121
1122	res, err := st.http2(requestParam{
1123		name: "TestH2H1RequestTrailer",
1124		body: []byte("1"),
1125		trailer: []hpack.HeaderField{
1126			pair("foo", "bar"),
1127		},
1128	})
1129	if err != nil {
1130		t.Fatalf("Error st.http2() = %v", err)
1131	}
1132
1133	if got, want := res.status, http.StatusOK; got != want {
1134		t.Errorf("res.status: %v; want %v", got, want)
1135	}
1136}
1137
1138// TestH2H1HeaderFieldBuffer tests that request with header fields
1139// larger than configured buffer size is rejected.
1140func TestH2H1HeaderFieldBuffer(t *testing.T) {
1141	opts := options{
1142		args: []string{"--request-header-field-buffer=10"},
1143		handler: func(http.ResponseWriter, *http.Request) {
1144			t.Fatal("execution path should not be here")
1145		},
1146	}
1147
1148	st := newServerTester(t, opts)
1149	defer st.Close()
1150
1151	res, err := st.http2(requestParam{
1152		name: "TestH2H1HeaderFieldBuffer",
1153	})
1154	if err != nil {
1155		t.Fatalf("Error st.http2() = %v", err)
1156	}
1157
1158	if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
1159		t.Errorf("status: %v; want %v", got, want)
1160	}
1161}
1162
1163// TestH2H1HeaderFields tests that request with header fields more
1164// than configured number is rejected.
1165func TestH2H1HeaderFields(t *testing.T) {
1166	opts := options{
1167		args: []string{"--max-request-header-fields=1"},
1168		handler: func(http.ResponseWriter, *http.Request) {
1169			t.Fatal("execution path should not be here")
1170		},
1171	}
1172
1173	st := newServerTester(t, opts)
1174	defer st.Close()
1175
1176	res, err := st.http2(requestParam{
1177		name: "TestH2H1HeaderFields",
1178		// we have at least 4 pseudo-header fields sent, and
1179		// that ensures that buffer limit exceeds.
1180	})
1181	if err != nil {
1182		t.Fatalf("Error st.http2() = %v", err)
1183	}
1184
1185	if got, want := res.status, http.StatusRequestHeaderFieldsTooLarge; got != want {
1186		t.Errorf("status: %v; want %v", got, want)
1187	}
1188}
1189
1190// TestH2H1ReqPhaseSetHeader tests mruby request phase hook
1191// modifies request header fields.
1192func TestH2H1ReqPhaseSetHeader(t *testing.T) {
1193	opts := options{
1194		args: []string{"--mruby-file=" + testDir + "/req-set-header.rb"},
1195		handler: func(_ http.ResponseWriter, r *http.Request) {
1196			if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
1197				t.Errorf("User-Agent = %v; want %v", got, want)
1198			}
1199		},
1200	}
1201
1202	st := newServerTester(t, opts)
1203	defer st.Close()
1204
1205	res, err := st.http2(requestParam{
1206		name: "TestH2H1ReqPhaseSetHeader",
1207	})
1208	if err != nil {
1209		t.Fatalf("Error st.http2() = %v", err)
1210	}
1211
1212	if got, want := res.status, http.StatusOK; got != want {
1213		t.Errorf("status = %v; want %v", got, want)
1214	}
1215}
1216
1217// TestH2H1ReqPhaseReturn tests mruby request phase hook returns
1218// custom response.
1219func TestH2H1ReqPhaseReturn(t *testing.T) {
1220	opts := options{
1221		args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
1222		handler: func(http.ResponseWriter, *http.Request) {
1223			t.Fatalf("request should not be forwarded")
1224		},
1225	}
1226
1227	st := newServerTester(t, opts)
1228	defer st.Close()
1229
1230	res, err := st.http2(requestParam{
1231		name: "TestH2H1ReqPhaseReturn",
1232	})
1233	if err != nil {
1234		t.Fatalf("Error st.http2() = %v", err)
1235	}
1236
1237	if got, want := res.status, http.StatusNotFound; got != want {
1238		t.Errorf("status = %v; want %v", got, want)
1239	}
1240
1241	hdtests := []struct {
1242		k, v string
1243	}{
1244		{"content-length", "20"},
1245		{"from", "mruby"},
1246	}
1247
1248	for _, tt := range hdtests {
1249		if got, want := res.header.Get(tt.k), tt.v; got != want {
1250			t.Errorf("%v = %v; want %v", tt.k, got, want)
1251		}
1252	}
1253
1254	if got, want := string(res.body), "Hello World from req"; got != want {
1255		t.Errorf("body = %v; want %v", got, want)
1256	}
1257}
1258
1259// TestH2H1RespPhaseSetHeader tests mruby response phase hook modifies
1260// response header fields.
1261func TestH2H1RespPhaseSetHeader(t *testing.T) {
1262	opts := options{
1263		args: []string{"--mruby-file=" + testDir + "/resp-set-header.rb"},
1264	}
1265
1266	st := newServerTester(t, opts)
1267	defer st.Close()
1268
1269	res, err := st.http2(requestParam{
1270		name: "TestH2H1RespPhaseSetHeader",
1271	})
1272	if err != nil {
1273		t.Fatalf("Error st.http2() = %v", err)
1274	}
1275
1276	if got, want := res.status, http.StatusOK; got != want {
1277		t.Errorf("status = %v; want %v", got, want)
1278	}
1279
1280	if got, want := res.header.Get("alpha"), "bravo"; got != want {
1281		t.Errorf("alpha = %v; want %v", got, want)
1282	}
1283}
1284
1285// TestH2H1RespPhaseReturn tests mruby response phase hook returns
1286// custom response.
1287func TestH2H1RespPhaseReturn(t *testing.T) {
1288	opts := options{
1289		args: []string{"--mruby-file=" + testDir + "/resp-return.rb"},
1290	}
1291
1292	st := newServerTester(t, opts)
1293	defer st.Close()
1294
1295	res, err := st.http2(requestParam{
1296		name: "TestH2H1RespPhaseReturn",
1297	})
1298	if err != nil {
1299		t.Fatalf("Error st.http2() = %v", err)
1300	}
1301
1302	if got, want := res.status, http.StatusNotFound; got != want {
1303		t.Errorf("status = %v; want %v", got, want)
1304	}
1305
1306	hdtests := []struct {
1307		k, v string
1308	}{
1309		{"content-length", "21"},
1310		{"from", "mruby"},
1311	}
1312
1313	for _, tt := range hdtests {
1314		if got, want := res.header.Get(tt.k), tt.v; got != want {
1315			t.Errorf("%v = %v; want %v", tt.k, got, want)
1316		}
1317	}
1318
1319	if got, want := string(res.body), "Hello World from resp"; got != want {
1320		t.Errorf("body = %v; want %v", got, want)
1321	}
1322}
1323
1324// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
1325func TestH2H1Upgrade(t *testing.T) {
1326	st := newServerTester(t, options{})
1327	defer st.Close()
1328
1329	res, err := st.http1(requestParam{
1330		name: "TestH2H1Upgrade",
1331		header: []hpack.HeaderField{
1332			pair("Connection", "Upgrade, HTTP2-Settings"),
1333			pair("Upgrade", "h2c"),
1334			pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
1335		},
1336	})
1337
1338	if err != nil {
1339		t.Fatalf("Error st.http1() = %v", err)
1340	}
1341
1342	if got, want := res.status, http.StatusSwitchingProtocols; got != want {
1343		t.Errorf("res.status: %v; want %v", got, want)
1344	}
1345
1346	res, err = st.http2(requestParam{
1347		httpUpgrade: true,
1348	})
1349	if err != nil {
1350		t.Fatalf("Error st.http2() = %v", err)
1351	}
1352
1353	if got, want := res.status, http.StatusOK; got != want {
1354		t.Errorf("res.status: %v; want %v", got, want)
1355	}
1356}
1357
1358// TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded
1359// header field includes obfuscated address even if PROXY protocol
1360// version 1 containing TCP4 entry is accepted.
1361func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) {
1362	pattern := `^for=_[^;]+$`
1363	validFwd := regexp.MustCompile(pattern)
1364	opts := options{
1365		args: []string{
1366			"--accept-proxy-protocol",
1367			"--add-x-forwarded-for",
1368			"--add-forwarded=for",
1369			"--forwarded-for=obfuscated",
1370		},
1371		handler: func(_ http.ResponseWriter, r *http.Request) {
1372			if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
1373				t.Errorf("Forwarded: %v; want pattern %v", got, pattern)
1374			}
1375		},
1376	}
1377
1378	st := newServerTester(t, opts)
1379	defer st.Close()
1380
1381	if _, err := st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n")); err != nil {
1382		t.Fatalf("Error st.conn.Write() = %v", err)
1383	}
1384
1385	res, err := st.http2(requestParam{
1386		name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated",
1387	})
1388	if err != nil {
1389		t.Fatalf("Error st.http2() = %v", err)
1390	}
1391
1392	if got, want := res.status, http.StatusOK; got != want {
1393		t.Errorf("res.status: %v; want %v", got, want)
1394	}
1395}
1396
1397// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
1398// containing TCP4 entry is accepted and X-Forwarded-For contains
1399// advertised src address.
1400func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
1401	opts := options{
1402		args: []string{
1403			"--accept-proxy-protocol",
1404			"--add-x-forwarded-for",
1405			"--add-forwarded=for",
1406			"--forwarded-for=ip",
1407		},
1408		handler: func(_ http.ResponseWriter, r *http.Request) {
1409			if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
1410				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1411			}
1412			if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1413				t.Errorf("Forwarded: %v; want %v", got, want)
1414			}
1415		},
1416	}
1417
1418	st := newServerTester(t, opts)
1419	defer st.Close()
1420
1421	if _, err := st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n")); err != nil {
1422		t.Fatalf("Error st.conn.Write() = %v", err)
1423	}
1424
1425	res, err := st.http2(requestParam{
1426		name: "TestH2H1ProxyProtocolV1TCP4",
1427	})
1428	if err != nil {
1429		t.Fatalf("Error st.http2() = %v", err)
1430	}
1431
1432	if got, want := res.status, http.StatusOK; got != want {
1433		t.Errorf("res.status: %v; want %v", got, want)
1434	}
1435}
1436
1437// TestH2H1ProxyProtocolV1TCP6 tests PROXY protocol version 1
1438// containing TCP6 entry is accepted and X-Forwarded-For contains
1439// advertised src address.
1440func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
1441	opts := options{
1442		args: []string{
1443			"--accept-proxy-protocol",
1444			"--add-x-forwarded-for",
1445			"--add-forwarded=for",
1446			"--forwarded-for=ip",
1447		},
1448		handler: func(_ http.ResponseWriter, r *http.Request) {
1449			if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
1450				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1451			}
1452			if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want {
1453				t.Errorf("Forwarded: %v; want %v", got, want)
1454			}
1455		},
1456	}
1457
1458	st := newServerTester(t, opts)
1459	defer st.Close()
1460
1461	if _, err := st.conn.Write([]byte("PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ::1 12345 8080\r\n")); err != nil {
1462		t.Fatalf("Error st.conn.Write() = %v", err)
1463	}
1464
1465	res, err := st.http2(requestParam{
1466		name: "TestH2H1ProxyProtocolV1TCP6",
1467	})
1468	if err != nil {
1469		t.Fatalf("Error st.http2() = %v", err)
1470	}
1471
1472	if got, want := res.status, http.StatusOK; got != want {
1473		t.Errorf("res.status: %v; want %v", got, want)
1474	}
1475}
1476
1477// TestH2H1ProxyProtocolV1TCP4TLS tests PROXY protocol version 1 over
1478// TLS containing TCP4 entry is accepted and X-Forwarded-For contains
1479// advertised src address.
1480func TestH2H1ProxyProtocolV1TCP4TLS(t *testing.T) {
1481	opts := options{
1482		args: []string{
1483			"--accept-proxy-protocol",
1484			"--add-x-forwarded-for",
1485			"--add-forwarded=for",
1486			"--forwarded-for=ip",
1487		},
1488		handler: func(_ http.ResponseWriter, r *http.Request) {
1489			if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
1490				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1491			}
1492			if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1493				t.Errorf("Forwarded: %v; want %v", got, want)
1494			}
1495		},
1496		tls:     true,
1497		tcpData: []byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"),
1498	}
1499
1500	st := newServerTester(t, opts)
1501	defer st.Close()
1502
1503	res, err := st.http2(requestParam{
1504		name: "TestH2H1ProxyProtocolV1TCP4TLS",
1505	})
1506	if err != nil {
1507		t.Fatalf("Error st.http2() = %v", err)
1508	}
1509
1510	if got, want := res.status, http.StatusOK; got != want {
1511		t.Errorf("res.status: %v; want %v", got, want)
1512	}
1513}
1514
1515// TestH2H1ProxyProtocolV1TCP6TLS tests PROXY protocol version 1 over
1516// TLS containing TCP6 entry is accepted and X-Forwarded-For contains
1517// advertised src address.
1518func TestH2H1ProxyProtocolV1TCP6TLS(t *testing.T) {
1519	opts := options{
1520		args: []string{
1521			"--accept-proxy-protocol",
1522			"--add-x-forwarded-for",
1523			"--add-forwarded=for",
1524			"--forwarded-for=ip",
1525		},
1526		handler: func(_ http.ResponseWriter, r *http.Request) {
1527			if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
1528				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1529			}
1530			if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want {
1531				t.Errorf("Forwarded: %v; want %v", got, want)
1532			}
1533		},
1534		tls:     true,
1535		tcpData: []byte("PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ::1 12345 8080\r\n"),
1536	}
1537
1538	st := newServerTester(t, opts)
1539	defer st.Close()
1540
1541	res, err := st.http2(requestParam{
1542		name: "TestH2H1ProxyProtocolV1TCP6TLS",
1543	})
1544	if err != nil {
1545		t.Fatalf("Error st.http2() = %v", err)
1546	}
1547
1548	if got, want := res.status, http.StatusOK; got != want {
1549		t.Errorf("res.status: %v; want %v", got, want)
1550	}
1551}
1552
1553// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
1554// containing UNKNOWN entry is accepted.
1555func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
1556	opts := options{
1557		args: []string{
1558			"--accept-proxy-protocol",
1559			"--add-x-forwarded-for",
1560			"--add-forwarded=for",
1561			"--forwarded-for=ip",
1562		},
1563		handler: func(_ http.ResponseWriter, r *http.Request) {
1564			if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
1565				t.Errorf("X-Forwarded-For: %v; want something else", got)
1566			}
1567			if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant {
1568				t.Errorf("Forwarded: %v; want something else", got)
1569			}
1570		},
1571	}
1572
1573	st := newServerTester(t, opts)
1574	defer st.Close()
1575
1576	if _, err := st.conn.Write([]byte("PROXY UNKNOWN 192.168.0.2 192.168.0.100 12345 8080\r\n")); err != nil {
1577		t.Fatalf("Error st.conn.Write() = %v", err)
1578	}
1579
1580	res, err := st.http2(requestParam{
1581		name: "TestH2H1ProxyProtocolV1Unknown",
1582	})
1583	if err != nil {
1584		t.Fatalf("Error st.http2() = %v", err)
1585	}
1586
1587	if got, want := res.status, http.StatusOK; got != want {
1588		t.Errorf("res.status: %v; want %v", got, want)
1589	}
1590}
1591
1592// TestH2H1ProxyProtocolV1JustUnknown tests PROXY protocol version 1
1593// containing only "PROXY UNKNOWN" is accepted.
1594func TestH2H1ProxyProtocolV1JustUnknown(t *testing.T) {
1595	opts := options{
1596		args: []string{
1597			"--accept-proxy-protocol",
1598			"--add-x-forwarded-for",
1599		},
1600	}
1601
1602	st := newServerTester(t, opts)
1603	defer st.Close()
1604
1605	if _, err := st.conn.Write([]byte("PROXY UNKNOWN\r\n")); err != nil {
1606		t.Fatalf("Error st.conn.Write() = %v", err)
1607	}
1608
1609	res, err := st.http2(requestParam{
1610		name: "TestH2H1ProxyProtocolV1JustUnknown",
1611	})
1612	if err != nil {
1613		t.Fatalf("Error st.http2() = %v", err)
1614	}
1615
1616	if got, want := res.status, http.StatusOK; got != want {
1617		t.Errorf("res.status: %v; want %v", got, want)
1618	}
1619}
1620
1621// TestH2H1ProxyProtocolV1TooLongLine tests PROXY protocol version 1
1622// line longer than 107 bytes must be rejected
1623func TestH2H1ProxyProtocolV1TooLongLine(t *testing.T) {
1624	opts := options{
1625		args: []string{
1626			"--accept-proxy-protocol",
1627			"--add-x-forwarded-for",
1628		},
1629	}
1630
1631	st := newServerTester(t, opts)
1632	defer st.Close()
1633
1634	if _, err := st.conn.Write([]byte("PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 655350\r\n")); err != nil {
1635		t.Fatalf("Error st.conn.Write() = %v", err)
1636	}
1637
1638	_, err := st.http2(requestParam{
1639		name: "TestH2H1ProxyProtocolV1TooLongLine",
1640	})
1641	if err == nil {
1642		t.Fatalf("connection was not terminated")
1643	}
1644}
1645
1646// TestH2H1ProxyProtocolV1BadLineEnd tests that PROXY protocol version
1647// 1 line ending without \r\n should be rejected.
1648func TestH2H1ProxyProtocolV1BadLineEnd(t *testing.T) {
1649	opts := options{
1650		args: []string{"--accept-proxy-protocol"},
1651	}
1652
1653	st := newServerTester(t, opts)
1654	defer st.Close()
1655
1656	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080\r \n")); err != nil {
1657		t.Fatalf("Error st.conn.Write() = %v", err)
1658	}
1659
1660	_, err := st.http2(requestParam{
1661		name: "TestH2H1ProxyProtocolV1BadLineEnd",
1662	})
1663	if err == nil {
1664		t.Fatalf("connection was not terminated")
1665	}
1666}
1667
1668// TestH2H1ProxyProtocolV1NoEnd tests that PROXY protocol version 1
1669// line containing no \r\n should be rejected.
1670func TestH2H1ProxyProtocolV1NoEnd(t *testing.T) {
1671	opts := options{
1672		args: []string{"--accept-proxy-protocol"},
1673	}
1674
1675	st := newServerTester(t, opts)
1676	defer st.Close()
1677
1678	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080")); err != nil {
1679		t.Fatalf("Error st.conn.Write() = %v", err)
1680	}
1681
1682	_, err := st.http2(requestParam{
1683		name: "TestH2H1ProxyProtocolV1NoEnd",
1684	})
1685	if err == nil {
1686		t.Fatalf("connection was not terminated")
1687	}
1688}
1689
1690// TestH2H1ProxyProtocolV1EmbeddedNULL tests that PROXY protocol
1691// version 1 line containing NULL character should be rejected.
1692func TestH2H1ProxyProtocolV1EmbeddedNULL(t *testing.T) {
1693	opts := options{
1694		args: []string{"--accept-proxy-protocol"},
1695	}
1696
1697	st := newServerTester(t, opts)
1698	defer st.Close()
1699
1700	b := []byte("PROXY TCP6 ::1*foo ::1 12345 8080\r\n")
1701	b[14] = 0
1702
1703	if _, err := st.conn.Write(b); err != nil {
1704		t.Fatalf("Error st.conn.Write() = %v", err)
1705	}
1706
1707	_, err := st.http2(requestParam{
1708		name: "TestH2H1ProxyProtocolV1EmbeddedNULL",
1709	})
1710	if err == nil {
1711		t.Fatalf("connection was not terminated")
1712	}
1713}
1714
1715// TestH2H1ProxyProtocolV1MissingSrcPort tests that PROXY protocol
1716// version 1 line without src port should be rejected.
1717func TestH2H1ProxyProtocolV1MissingSrcPort(t *testing.T) {
1718	opts := options{
1719		args: []string{"--accept-proxy-protocol"},
1720	}
1721
1722	st := newServerTester(t, opts)
1723	defer st.Close()
1724
1725	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1  8080\r\n")); err != nil {
1726		t.Fatalf("Error st.conn.Write() = %v", err)
1727	}
1728
1729	_, err := st.http2(requestParam{
1730		name: "TestH2H1ProxyProtocolV1MissingSrcPort",
1731	})
1732	if err == nil {
1733		t.Fatalf("connection was not terminated")
1734	}
1735}
1736
1737// TestH2H1ProxyProtocolV1MissingDstPort tests that PROXY protocol
1738// version 1 line without dst port should be rejected.
1739func TestH2H1ProxyProtocolV1MissingDstPort(t *testing.T) {
1740	opts := options{
1741		args: []string{"--accept-proxy-protocol"},
1742	}
1743
1744	st := newServerTester(t, opts)
1745	defer st.Close()
1746
1747	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 \r\n")); err != nil {
1748		t.Fatalf("Error st.conn.Write() = %v", err)
1749	}
1750
1751	_, err := st.http2(requestParam{
1752		name: "TestH2H1ProxyProtocolV1MissingDstPort",
1753	})
1754	if err == nil {
1755		t.Fatalf("connection was not terminated")
1756	}
1757}
1758
1759// TestH2H1ProxyProtocolV1InvalidSrcPort tests that PROXY protocol
1760// containing invalid src port should be rejected.
1761func TestH2H1ProxyProtocolV1InvalidSrcPort(t *testing.T) {
1762	opts := options{
1763		args: []string{"--accept-proxy-protocol"},
1764	}
1765
1766	st := newServerTester(t, opts)
1767	defer st.Close()
1768
1769	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123x 8080\r\n")); err != nil {
1770		t.Fatalf("Error st.conn.Write() = %v", err)
1771	}
1772
1773	_, err := st.http2(requestParam{
1774		name: "TestH2H1ProxyProtocolV1InvalidSrcPort",
1775	})
1776	if err == nil {
1777		t.Fatalf("connection was not terminated")
1778	}
1779}
1780
1781// TestH2H1ProxyProtocolV1InvalidDstPort tests that PROXY protocol
1782// containing invalid dst port should be rejected.
1783func TestH2H1ProxyProtocolV1InvalidDstPort(t *testing.T) {
1784	opts := options{
1785		args: []string{"--accept-proxy-protocol"},
1786	}
1787
1788	st := newServerTester(t, opts)
1789	defer st.Close()
1790
1791	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123456 80x\r\n")); err != nil {
1792		t.Fatalf("Error st.conn.Write() = %v", err)
1793	}
1794
1795	_, err := st.http2(requestParam{
1796		name: "TestH2H1ProxyProtocolV1InvalidDstPort",
1797	})
1798	if err == nil {
1799		t.Fatalf("connection was not terminated")
1800	}
1801}
1802
1803// TestH2H1ProxyProtocolV1LeadingZeroPort tests that PROXY protocol
1804// version 1 line with non zero port with leading zero should be
1805// rejected.
1806func TestH2H1ProxyProtocolV1LeadingZeroPort(t *testing.T) {
1807	opts := options{
1808		args: []string{"--accept-proxy-protocol"},
1809	}
1810
1811	st := newServerTester(t, opts)
1812	defer st.Close()
1813
1814	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 03000 8080\r\n")); err != nil {
1815		t.Fatalf("Error st.conn.Write() = %v", err)
1816	}
1817
1818	_, err := st.http2(requestParam{
1819		name: "TestH2H1ProxyProtocolV1LeadingZeroPort",
1820	})
1821	if err == nil {
1822		t.Fatalf("connection was not terminated")
1823	}
1824}
1825
1826// TestH2H1ProxyProtocolV1TooLargeSrcPort tests that PROXY protocol
1827// containing too large src port should be rejected.
1828func TestH2H1ProxyProtocolV1TooLargeSrcPort(t *testing.T) {
1829	opts := options{
1830		args: []string{"--accept-proxy-protocol"},
1831	}
1832
1833	st := newServerTester(t, opts)
1834	defer st.Close()
1835
1836	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 65536 8080\r\n")); err != nil {
1837		t.Fatalf("Error st.conn.Write() = %v", err)
1838	}
1839
1840	_, err := st.http2(requestParam{
1841		name: "TestH2H1ProxyProtocolV1TooLargeSrcPort",
1842	})
1843	if err == nil {
1844		t.Fatalf("connection was not terminated")
1845	}
1846}
1847
1848// TestH2H1ProxyProtocolV1TooLargeDstPort tests that PROXY protocol
1849// containing too large dst port should be rejected.
1850func TestH2H1ProxyProtocolV1TooLargeDstPort(t *testing.T) {
1851	opts := options{
1852		args: []string{"--accept-proxy-protocol"},
1853	}
1854
1855	st := newServerTester(t, opts)
1856	defer st.Close()
1857
1858	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 65536\r\n")); err != nil {
1859		t.Fatalf("Error st.conn.Write() = %v", err)
1860	}
1861
1862	_, err := st.http2(requestParam{
1863		name: "TestH2H1ProxyProtocolV1TooLargeDstPort",
1864	})
1865	if err == nil {
1866		t.Fatalf("connection was not terminated")
1867	}
1868}
1869
1870// TestH2H1ProxyProtocolV1InvalidSrcAddr tests that PROXY protocol
1871// containing invalid src addr should be rejected.
1872func TestH2H1ProxyProtocolV1InvalidSrcAddr(t *testing.T) {
1873	opts := options{
1874		args: []string{"--accept-proxy-protocol"},
1875	}
1876
1877	st := newServerTester(t, opts)
1878	defer st.Close()
1879
1880	if _, err := st.conn.Write([]byte("PROXY TCP6 192.168.0.1 ::1 12345 8080\r\n")); err != nil {
1881		t.Fatalf("Error st.conn.Write() = %v", err)
1882	}
1883
1884	_, err := st.http2(requestParam{
1885		name: "TestH2H1ProxyProtocolV1InvalidSrcAddr",
1886	})
1887	if err == nil {
1888		t.Fatalf("connection was not terminated")
1889	}
1890}
1891
1892// TestH2H1ProxyProtocolV1InvalidDstAddr tests that PROXY protocol
1893// containing invalid dst addr should be rejected.
1894func TestH2H1ProxyProtocolV1InvalidDstAddr(t *testing.T) {
1895	opts := options{
1896		args: []string{"--accept-proxy-protocol"},
1897	}
1898
1899	st := newServerTester(t, opts)
1900	defer st.Close()
1901
1902	if _, err := st.conn.Write([]byte("PROXY TCP6 ::1 192.168.0.1 12345 8080\r\n")); err != nil {
1903		t.Fatalf("Error st.conn.Write() = %v", err)
1904	}
1905
1906	_, err := st.http2(requestParam{
1907		name: "TestH2H1ProxyProtocolV1InvalidDstAddr",
1908	})
1909	if err == nil {
1910		t.Fatalf("connection was not terminated")
1911	}
1912}
1913
1914// TestH2H1ProxyProtocolV1InvalidProtoFamily tests that PROXY protocol
1915// containing invalid protocol family should be rejected.
1916func TestH2H1ProxyProtocolV1InvalidProtoFamily(t *testing.T) {
1917	opts := options{
1918		args: []string{"--accept-proxy-protocol"},
1919	}
1920
1921	st := newServerTester(t, opts)
1922	defer st.Close()
1923
1924	if _, err := st.conn.Write([]byte("PROXY UNIX ::1 ::1 12345 8080\r\n")); err != nil {
1925		t.Fatalf("Error st.conn.Write() = %v", err)
1926	}
1927
1928	_, err := st.http2(requestParam{
1929		name: "TestH2H1ProxyProtocolV1InvalidProtoFamily",
1930	})
1931	if err == nil {
1932		t.Fatalf("connection was not terminated")
1933	}
1934}
1935
1936// TestH2H1ProxyProtocolV1InvalidID tests that PROXY protocol
1937// containing invalid PROXY protocol version 1 ID should be rejected.
1938func TestH2H1ProxyProtocolV1InvalidID(t *testing.T) {
1939	opts := options{
1940		args: []string{"--accept-proxy-protocol"},
1941	}
1942
1943	st := newServerTester(t, opts)
1944	defer st.Close()
1945
1946	if _, err := st.conn.Write([]byte("PR0XY TCP6 ::1 ::1 12345 8080\r\n")); err != nil {
1947		t.Fatalf("Error st.conn.Write() = %v", err)
1948	}
1949
1950	_, err := st.http2(requestParam{
1951		name: "TestH2H1ProxyProtocolV1InvalidID",
1952	})
1953	if err == nil {
1954		t.Fatalf("connection was not terminated")
1955	}
1956}
1957
1958// TestH2H1ProxyProtocolV2TCP4 tests PROXY protocol version 2
1959// containing AF_INET family is accepted and X-Forwarded-For contains
1960// advertised src address.
1961func TestH2H1ProxyProtocolV2TCP4(t *testing.T) {
1962	opts := options{
1963		args: []string{
1964			"--accept-proxy-protocol",
1965			"--add-x-forwarded-for",
1966			"--add-forwarded=for",
1967			"--forwarded-for=ip",
1968		},
1969		handler: func(_ http.ResponseWriter, r *http.Request) {
1970			if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
1971				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1972			}
1973			if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1974				t.Errorf("Forwarded: %v; want %v", got, want)
1975			}
1976		},
1977	}
1978
1979	st := newServerTester(t, opts)
1980	defer st.Close()
1981
1982	var b bytes.Buffer
1983	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
1984		command: proxyProtocolV2CommandProxy,
1985		sourceAddress: &net.TCPAddr{
1986			IP:   net.ParseIP("192.168.0.2").To4(),
1987			Port: 12345,
1988		},
1989		destinationAddress: &net.TCPAddr{
1990			IP:   net.ParseIP("192.168.0.100").To4(),
1991			Port: 8080,
1992		},
1993		additionalData: []byte("foobar"),
1994	}); err != nil {
1995		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
1996	}
1997
1998	if _, err := st.conn.Write(b.Bytes()); err != nil {
1999		t.Fatalf("Error st.conn.Write() = %v", err)
2000	}
2001
2002	res, err := st.http2(requestParam{
2003		name: "TestH2H1ProxyProtocolV2TCP4",
2004	})
2005	if err != nil {
2006		t.Fatalf("Error st.http2() = %v", err)
2007	}
2008
2009	if got, want := res.status, http.StatusOK; got != want {
2010		t.Errorf("res.status: %v; want %v", got, want)
2011	}
2012}
2013
2014// TestH2H1ProxyProtocolV2TCP6 tests PROXY protocol version 2
2015// containing AF_INET6 family is accepted and X-Forwarded-For contains
2016// advertised src address.
2017func TestH2H1ProxyProtocolV2TCP6(t *testing.T) {
2018	opts := options{
2019		args: []string{
2020			"--accept-proxy-protocol",
2021			"--add-x-forwarded-for",
2022			"--add-forwarded=for",
2023			"--forwarded-for=ip",
2024		},
2025		handler: func(_ http.ResponseWriter, r *http.Request) {
2026			if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
2027				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2028			}
2029			if got, want := r.Header.Get("Forwarded"), `for="[2001:db8:85a3::8a2e:370:7334]"`; got != want {
2030				t.Errorf("Forwarded: %v; want %v", got, want)
2031			}
2032		},
2033	}
2034
2035	st := newServerTester(t, opts)
2036	defer st.Close()
2037
2038	var b bytes.Buffer
2039	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
2040		command: proxyProtocolV2CommandProxy,
2041		sourceAddress: &net.TCPAddr{
2042			IP:   net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
2043			Port: 12345,
2044		},
2045		destinationAddress: &net.TCPAddr{
2046			IP:   net.ParseIP("::1"),
2047			Port: 8080,
2048		},
2049		additionalData: []byte("foobar"),
2050	}); err != nil {
2051		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2052	}
2053
2054	if _, err := st.conn.Write(b.Bytes()); err != nil {
2055		t.Fatalf("Error st.conn.Write() = %v", err)
2056	}
2057
2058	res, err := st.http2(requestParam{
2059		name: "TestH2H1ProxyProtocolV2TCP6",
2060	})
2061	if err != nil {
2062		t.Fatalf("Error st.http2() = %v", err)
2063	}
2064
2065	if got, want := res.status, http.StatusOK; got != want {
2066		t.Errorf("res.status: %v; want %v", got, want)
2067	}
2068}
2069
2070// TestH2H1ProxyProtocolV2TCP4TLS tests PROXY protocol version 2 over
2071// TLS containing AF_INET family is accepted and X-Forwarded-For
2072// contains advertised src address.
2073func TestH2H1ProxyProtocolV2TCP4TLS(t *testing.T) {
2074	var v2Hdr bytes.Buffer
2075	if err := writeProxyProtocolV2(&v2Hdr, proxyProtocolV2{
2076		command: proxyProtocolV2CommandProxy,
2077		sourceAddress: &net.TCPAddr{
2078			IP:   net.ParseIP("192.168.0.2").To4(),
2079			Port: 12345,
2080		},
2081		destinationAddress: &net.TCPAddr{
2082			IP:   net.ParseIP("192.168.0.100").To4(),
2083			Port: 8080,
2084		},
2085		additionalData: []byte("foobar"),
2086	}); err != nil {
2087		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2088	}
2089
2090	opts := options{
2091		args: []string{
2092			"--accept-proxy-protocol",
2093			"--add-x-forwarded-for",
2094			"--add-forwarded=for",
2095			"--forwarded-for=ip",
2096		},
2097		handler: func(_ http.ResponseWriter, r *http.Request) {
2098			if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
2099				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2100			}
2101			if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
2102				t.Errorf("Forwarded: %v; want %v", got, want)
2103			}
2104		},
2105		tls:     true,
2106		tcpData: v2Hdr.Bytes(),
2107	}
2108
2109	st := newServerTester(t, opts)
2110	defer st.Close()
2111
2112	res, err := st.http2(requestParam{
2113		name: "TestH2H1ProxyProtocolV2TCP4TLS",
2114	})
2115	if err != nil {
2116		t.Fatalf("Error st.http2() = %v", err)
2117	}
2118
2119	if got, want := res.status, http.StatusOK; got != want {
2120		t.Errorf("res.status: %v; want %v", got, want)
2121	}
2122}
2123
2124// TestH2H1ProxyProtocolV2TCP6TLS tests PROXY protocol version 2 over
2125// TLS containing AF_INET6 family is accepted and X-Forwarded-For
2126// contains advertised src address.
2127func TestH2H1ProxyProtocolV2TCP6TLS(t *testing.T) {
2128	var v2Hdr bytes.Buffer
2129	if err := writeProxyProtocolV2(&v2Hdr, proxyProtocolV2{
2130		command: proxyProtocolV2CommandProxy,
2131		sourceAddress: &net.TCPAddr{
2132			IP:   net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
2133			Port: 12345,
2134		},
2135		destinationAddress: &net.TCPAddr{
2136			IP:   net.ParseIP("::1"),
2137			Port: 8080,
2138		},
2139		additionalData: []byte("foobar"),
2140	}); err != nil {
2141		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2142	}
2143
2144	opts := options{
2145		args: []string{
2146			"--accept-proxy-protocol",
2147			"--add-x-forwarded-for",
2148			"--add-forwarded=for",
2149			"--forwarded-for=ip",
2150		},
2151		handler: func(_ http.ResponseWriter, r *http.Request) {
2152			if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
2153				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2154			}
2155			if got, want := r.Header.Get("Forwarded"), `for="[2001:db8:85a3::8a2e:370:7334]"`; got != want {
2156				t.Errorf("Forwarded: %v; want %v", got, want)
2157			}
2158		},
2159		tls:     true,
2160		tcpData: v2Hdr.Bytes(),
2161	}
2162
2163	st := newServerTester(t, opts)
2164	defer st.Close()
2165
2166	res, err := st.http2(requestParam{
2167		name: "TestH2H1ProxyProtocolV2TCP6TLS",
2168	})
2169	if err != nil {
2170		t.Fatalf("Error st.http2() = %v", err)
2171	}
2172
2173	if got, want := res.status, http.StatusOK; got != want {
2174		t.Errorf("res.status: %v; want %v", got, want)
2175	}
2176}
2177
2178// TestH2H1ProxyProtocolV2Local tests PROXY protocol version 2
2179// containing cmd == Local is ignored.
2180func TestH2H1ProxyProtocolV2Local(t *testing.T) {
2181	opts := options{
2182		args: []string{
2183			"--accept-proxy-protocol",
2184			"--add-x-forwarded-for",
2185			"--add-forwarded=for",
2186			"--forwarded-for=ip",
2187		},
2188		handler: func(_ http.ResponseWriter, r *http.Request) {
2189			if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
2190				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2191			}
2192			if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
2193				t.Errorf("Forwarded: %v; want %v", got, want)
2194			}
2195		},
2196	}
2197
2198	st := newServerTester(t, opts)
2199	defer st.Close()
2200
2201	var b bytes.Buffer
2202	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
2203		command: proxyProtocolV2CommandLocal,
2204		sourceAddress: &net.TCPAddr{
2205			IP:   net.ParseIP("192.168.0.2").To4(),
2206			Port: 12345,
2207		},
2208		destinationAddress: &net.TCPAddr{
2209			IP:   net.ParseIP("192.168.0.100").To4(),
2210			Port: 8080,
2211		},
2212		additionalData: []byte("foobar"),
2213	}); err != nil {
2214		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2215	}
2216
2217	if _, err := st.conn.Write(b.Bytes()); err != nil {
2218		t.Fatalf("Error st.conn.Write() = %v", err)
2219	}
2220
2221	res, err := st.http2(requestParam{
2222		name: "TestH2H1ProxyProtocolV2Local",
2223	})
2224	if err != nil {
2225		t.Fatalf("Error st.http2() = %v", err)
2226	}
2227
2228	if got, want := res.status, http.StatusOK; got != want {
2229		t.Errorf("res.status: %v; want %v", got, want)
2230	}
2231}
2232
2233// TestH2H1ProxyProtocolV2UnknownCmd tests PROXY protocol version 2
2234// containing unknown cmd should be rejected.
2235func TestH2H1ProxyProtocolV2UnknownCmd(t *testing.T) {
2236	opts := options{
2237		args: []string{"--accept-proxy-protocol"},
2238	}
2239
2240	st := newServerTester(t, opts)
2241	defer st.Close()
2242
2243	var b bytes.Buffer
2244	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
2245		command: 0xf,
2246		sourceAddress: &net.TCPAddr{
2247			IP:   net.ParseIP("192.168.0.2").To4(),
2248			Port: 12345,
2249		},
2250		destinationAddress: &net.TCPAddr{
2251			IP:   net.ParseIP("192.168.0.100").To4(),
2252			Port: 8080,
2253		},
2254		additionalData: []byte("foobar"),
2255	}); err != nil {
2256		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2257	}
2258
2259	if _, err := st.conn.Write(b.Bytes()); err != nil {
2260		t.Fatalf("Error st.conn.Write() = %v", err)
2261	}
2262
2263	_, err := st.http2(requestParam{
2264		name: "TestH2H1ProxyProtocolV2UnknownCmd",
2265	})
2266	if err == nil {
2267		t.Fatalf("connection was not terminated")
2268	}
2269}
2270
2271// TestH2H1ProxyProtocolV2Unix tests PROXY protocol version 2
2272// containing AF_UNIX family is ignored.
2273func TestH2H1ProxyProtocolV2Unix(t *testing.T) {
2274	opts := options{
2275		args: []string{
2276			"--accept-proxy-protocol",
2277			"--add-x-forwarded-for",
2278			"--add-forwarded=for",
2279			"--forwarded-for=ip",
2280		},
2281		handler: func(_ http.ResponseWriter, r *http.Request) {
2282			if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
2283				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2284			}
2285			if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
2286				t.Errorf("Forwarded: %v; want %v", got, want)
2287			}
2288		},
2289	}
2290
2291	st := newServerTester(t, opts)
2292	defer st.Close()
2293
2294	var b bytes.Buffer
2295	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
2296		command: proxyProtocolV2CommandProxy,
2297		sourceAddress: &net.UnixAddr{
2298			Name: "/foo",
2299			Net:  "unix",
2300		},
2301		destinationAddress: &net.UnixAddr{
2302			Name: "/bar",
2303			Net:  "unix",
2304		},
2305		additionalData: []byte("foobar"),
2306	}); err != nil {
2307		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2308	}
2309
2310	if _, err := st.conn.Write(b.Bytes()); err != nil {
2311		t.Fatalf("Error st.conn.Write() = %v", err)
2312	}
2313
2314	res, err := st.http2(requestParam{
2315		name: "TestH2H1ProxyProtocolV2Unix",
2316	})
2317	if err != nil {
2318		t.Fatalf("Error st.http2() = %v", err)
2319	}
2320
2321	if got, want := res.status, http.StatusOK; got != want {
2322		t.Errorf("res.status: %v; want %v", got, want)
2323	}
2324}
2325
2326// TestH2H1ProxyProtocolV2Unspec tests PROXY protocol version 2
2327// containing AF_UNSPEC family is ignored.
2328func TestH2H1ProxyProtocolV2Unspec(t *testing.T) {
2329	opts := options{
2330		args: []string{
2331			"--accept-proxy-protocol",
2332			"--add-x-forwarded-for",
2333			"--add-forwarded=for",
2334			"--forwarded-for=ip",
2335		},
2336		handler: func(_ http.ResponseWriter, r *http.Request) {
2337			if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
2338				t.Errorf("X-Forwarded-For: %v; want %v", got, want)
2339			}
2340			if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
2341				t.Errorf("Forwarded: %v; want %v", got, want)
2342			}
2343		},
2344	}
2345
2346	st := newServerTester(t, opts)
2347	defer st.Close()
2348
2349	var b bytes.Buffer
2350	if err := writeProxyProtocolV2(&b, proxyProtocolV2{
2351		command:        proxyProtocolV2CommandProxy,
2352		additionalData: []byte("foobar"),
2353	}); err != nil {
2354		t.Fatalf("Error writeProxyProtocolV2() = %v", err)
2355	}
2356
2357	if _, err := st.conn.Write(b.Bytes()); err != nil {
2358		t.Fatalf("Error st.conn.Write() = %v", err)
2359	}
2360
2361	res, err := st.http2(requestParam{
2362		name: "TestH2H1ProxyProtocolV2Unspec",
2363	})
2364	if err != nil {
2365		t.Fatalf("Error st.http2() = %v", err)
2366	}
2367
2368	if got, want := res.status, http.StatusOK; got != want {
2369		t.Errorf("res.status: %v; want %v", got, want)
2370	}
2371}
2372
2373// TestH2H1ExternalDNS tests that DNS resolution using external DNS
2374// with HTTP/1 backend works.
2375func TestH2H1ExternalDNS(t *testing.T) {
2376	opts := options{
2377		args: []string{"--external-dns"},
2378	}
2379
2380	st := newServerTester(t, opts)
2381	defer st.Close()
2382
2383	res, err := st.http2(requestParam{
2384		name: "TestH2H1ExternalDNS",
2385	})
2386	if err != nil {
2387		t.Fatalf("Error st.http2() = %v", err)
2388	}
2389
2390	if got, want := res.status, http.StatusOK; got != want {
2391		t.Errorf("status = %v; want %v", got, want)
2392	}
2393}
2394
2395// TestH2H1DNS tests that DNS resolution without external DNS with
2396// HTTP/1 backend works.
2397func TestH2H1DNS(t *testing.T) {
2398	opts := options{
2399		args: []string{"--dns"},
2400	}
2401
2402	st := newServerTester(t, opts)
2403	defer st.Close()
2404
2405	res, err := st.http2(requestParam{
2406		name: "TestH2H1DNS",
2407	})
2408	if err != nil {
2409		t.Fatalf("Error st.http2() = %v", err)
2410	}
2411
2412	if got, want := res.status, http.StatusOK; got != want {
2413		t.Errorf("status = %v; want %v", got, want)
2414	}
2415}
2416
2417// TestH2H1HTTPSRedirect tests that the request to the backend which
2418// requires TLS is redirected to https URI.
2419func TestH2H1HTTPSRedirect(t *testing.T) {
2420	opts := options{
2421		args: []string{"--redirect-if-not-tls"},
2422	}
2423
2424	st := newServerTester(t, opts)
2425	defer st.Close()
2426
2427	res, err := st.http2(requestParam{
2428		name: "TestH2H1HTTPSRedirect",
2429	})
2430	if err != nil {
2431		t.Fatalf("Error st.http2() = %v", err)
2432	}
2433
2434	if got, want := res.status, http.StatusPermanentRedirect; got != want {
2435		t.Errorf("status = %v; want %v", got, want)
2436	}
2437
2438	if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
2439		t.Errorf("location: %v; want %v", got, want)
2440	}
2441}
2442
2443// TestH2H1HTTPSRedirectPort tests that the request to the backend
2444// which requires TLS is redirected to https URI with given port.
2445func TestH2H1HTTPSRedirectPort(t *testing.T) {
2446	opts := options{
2447		args: []string{
2448			"--redirect-if-not-tls",
2449			"--redirect-https-port=8443",
2450		},
2451	}
2452
2453	st := newServerTester(t, opts)
2454	defer st.Close()
2455
2456	res, err := st.http2(requestParam{
2457		path: "/foo?bar",
2458		name: "TestH2H1HTTPSRedirectPort",
2459	})
2460	if err != nil {
2461		t.Fatalf("Error st.http2() = %v", err)
2462	}
2463
2464	if got, want := res.status, http.StatusPermanentRedirect; got != want {
2465		t.Errorf("status = %v; want %v", got, want)
2466	}
2467
2468	if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
2469		t.Errorf("location: %v; want %v", got, want)
2470	}
2471}
2472
2473// TestH2H1Code204 tests that 204 response without content-length, and
2474// transfer-encoding is valid.
2475func TestH2H1Code204(t *testing.T) {
2476	opts := options{
2477		handler: func(w http.ResponseWriter, _ *http.Request) {
2478			w.WriteHeader(http.StatusNoContent)
2479		},
2480	}
2481
2482	st := newServerTester(t, opts)
2483	defer st.Close()
2484
2485	res, err := st.http2(requestParam{
2486		name: "TestH2H1Code204",
2487	})
2488	if err != nil {
2489		t.Fatalf("Error st.http2() = %v", err)
2490	}
2491
2492	if got, want := res.status, http.StatusNoContent; got != want {
2493		t.Errorf("status = %v; want %v", got, want)
2494	}
2495}
2496
2497// TestH2H1Code204CL0 tests that 204 response with content-length: 0
2498// is allowed.
2499func TestH2H1Code204CL0(t *testing.T) {
2500	opts := options{
2501		handler: func(w http.ResponseWriter, _ *http.Request) {
2502			hj, ok := w.(http.Hijacker)
2503			if !ok {
2504				http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
2505				return
2506			}
2507			conn, bufrw, err := hj.Hijack()
2508			if err != nil {
2509				http.Error(w, err.Error(), http.StatusInternalServerError)
2510				return
2511			}
2512			defer conn.Close()
2513			if _, err := bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 0\r\n\r\n"); err != nil {
2514				t.Fatalf("Error bufrw.WriteString() = %v", err)
2515			}
2516			bufrw.Flush()
2517		},
2518	}
2519
2520	st := newServerTester(t, opts)
2521	defer st.Close()
2522
2523	res, err := st.http2(requestParam{
2524		name: "TestH2H1Code204CL0",
2525	})
2526	if err != nil {
2527		t.Fatalf("Error st.http2() = %v", err)
2528	}
2529
2530	if got, want := res.status, http.StatusNoContent; got != want {
2531		t.Errorf("status = %v; want %v", got, want)
2532	}
2533
2534	if got, found := res.header["Content-Length"]; found {
2535		t.Errorf("Content-Length = %v, want nothing", got)
2536	}
2537}
2538
2539// TestH2H1Code204CLNonzero tests that 204 response with nonzero
2540// content-length is not allowed.
2541func TestH2H1Code204CLNonzero(t *testing.T) {
2542	opts := options{
2543		handler: func(w http.ResponseWriter, _ *http.Request) {
2544			hj, ok := w.(http.Hijacker)
2545			if !ok {
2546				http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
2547				return
2548			}
2549			conn, bufrw, err := hj.Hijack()
2550			if err != nil {
2551				http.Error(w, err.Error(), http.StatusInternalServerError)
2552				return
2553			}
2554			defer conn.Close()
2555			if _, err := bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 1\r\n\r\n"); err != nil {
2556				t.Fatalf("Error bufrw.WriteString() = %v", err)
2557			}
2558			bufrw.Flush()
2559		},
2560	}
2561
2562	st := newServerTester(t, opts)
2563	defer st.Close()
2564
2565	res, err := st.http2(requestParam{
2566		name: "TestH2H1Code204CLNonzero",
2567	})
2568	if err != nil {
2569		t.Fatalf("Error st.http2() = %v", err)
2570	}
2571
2572	if got, want := res.status, http.StatusBadGateway; got != want {
2573		t.Errorf("status = %v; want %v", got, want)
2574	}
2575}
2576
2577// TestH2H1Code204TE tests that 204 response with transfer-encoding is
2578// not allowed.
2579func TestH2H1Code204TE(t *testing.T) {
2580	opts := options{
2581		handler: func(w http.ResponseWriter, _ *http.Request) {
2582			hj, ok := w.(http.Hijacker)
2583			if !ok {
2584				http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
2585				return
2586			}
2587			conn, bufrw, err := hj.Hijack()
2588			if err != nil {
2589				http.Error(w, err.Error(), http.StatusInternalServerError)
2590				return
2591			}
2592			defer conn.Close()
2593			if _, err := bufrw.WriteString("HTTP/1.1 204\r\nTransfer-Encoding: chunked\r\n\r\n"); err != nil {
2594				t.Fatalf("Error bufrw.WriteString() = %v", err)
2595			}
2596			bufrw.Flush()
2597		},
2598	}
2599
2600	st := newServerTester(t, opts)
2601	defer st.Close()
2602
2603	res, err := st.http2(requestParam{
2604		name: "TestH2H1Code204TE",
2605	})
2606	if err != nil {
2607		t.Fatalf("Error st.http2() = %v", err)
2608	}
2609
2610	if got, want := res.status, http.StatusBadGateway; got != want {
2611		t.Errorf("status = %v; want %v", got, want)
2612	}
2613}
2614
2615// TestH2H1AffinityCookie tests that affinity cookie is sent back in
2616// cleartext http.
2617func TestH2H1AffinityCookie(t *testing.T) {
2618	opts := options{
2619		args: []string{"--affinity-cookie"},
2620	}
2621
2622	st := newServerTester(t, opts)
2623	defer st.Close()
2624
2625	res, err := st.http2(requestParam{
2626		name: "TestH2H1AffinityCookie",
2627	})
2628	if err != nil {
2629		t.Fatalf("Error st.http2() = %v", err)
2630	}
2631
2632	if got, want := res.status, http.StatusOK; got != want {
2633		t.Errorf("status = %v; want %v", got, want)
2634	}
2635
2636	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
2637	validCookie := regexp.MustCompile(pattern)
2638
2639	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
2640		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
2641	}
2642}
2643
2644// TestH2H1AffinityCookieTLS tests that affinity cookie is sent back
2645// in https.
2646func TestH2H1AffinityCookieTLS(t *testing.T) {
2647	opts := options{
2648		args: []string{"--affinity-cookie"},
2649		tls:  true,
2650	}
2651
2652	st := newServerTester(t, opts)
2653	defer st.Close()
2654
2655	res, err := st.http2(requestParam{
2656		name:   "TestH2H1AffinityCookieTLS",
2657		scheme: "https",
2658	})
2659	if err != nil {
2660		t.Fatalf("Error st.http2() = %v", err)
2661	}
2662
2663	if got, want := res.status, http.StatusOK; got != want {
2664		t.Errorf("status = %v; want %v", got, want)
2665	}
2666
2667	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
2668	validCookie := regexp.MustCompile(pattern)
2669
2670	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
2671		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
2672	}
2673}
2674
2675// TestH2H1GracefulShutdown tests graceful shutdown.
2676func TestH2H1GracefulShutdown(t *testing.T) {
2677	st := newServerTester(t, options{})
2678	defer st.Close()
2679
2680	fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
2681
2682	if err := st.fr.WriteSettings(); err != nil {
2683		t.Fatalf("st.fr.WriteSettings(): %v", err)
2684	}
2685
2686	header := []hpack.HeaderField{
2687		pair(":method", "GET"),
2688		pair(":scheme", "http"),
2689		pair(":authority", st.authority),
2690		pair(":path", "/"),
2691	}
2692
2693	for _, h := range header {
2694		_ = st.enc.WriteField(h)
2695	}
2696
2697	if err := st.fr.WriteHeaders(http2.HeadersFrameParam{
2698		StreamID:      1,
2699		EndStream:     false,
2700		EndHeaders:    true,
2701		BlockFragment: st.headerBlkBuf.Bytes(),
2702	}); err != nil {
2703		t.Fatalf("st.fr.WriteHeaders(): %v", err)
2704	}
2705
2706	// send SIGQUIT signal to nghttpx to perform graceful shutdown
2707	if err := st.cmd.Process.Signal(syscall.SIGQUIT); err != nil {
2708		t.Fatalf("Error st.cmd.Process.Signal() = %v", err)
2709	}
2710
2711	time.Sleep(150 * time.Millisecond)
2712
2713	// after signal, finish request body
2714	if err := st.fr.WriteData(1, true, nil); err != nil {
2715		t.Fatalf("st.fr.WriteData(): %v", err)
2716	}
2717
2718	numGoAway := 0
2719
2720	for {
2721		fr, err := st.readFrame()
2722		if err != nil {
2723			if errors.Is(err, io.EOF) {
2724				want := 2
2725				if got := numGoAway; got != want {
2726					t.Fatalf("numGoAway: %v; want %v", got, want)
2727				}
2728
2729				return
2730			}
2731
2732			t.Fatalf("st.readFrame(): %v", err)
2733		}
2734
2735		switch f := fr.(type) {
2736		case *http2.GoAwayFrame:
2737			numGoAway++
2738
2739			want := http2.ErrCodeNo
2740			if got := f.ErrCode; got != want {
2741				t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want)
2742			}
2743
2744			switch numGoAway {
2745			case 1:
2746				want := (uint32(1) << 31) - 1
2747				if got := f.LastStreamID; got != want {
2748					t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
2749				}
2750			case 2:
2751				want := uint32(1)
2752				if got := f.LastStreamID; got != want {
2753					t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
2754				}
2755			case 3:
2756				t.Fatalf("too many GOAWAYs received")
2757			}
2758		}
2759	}
2760}
2761
2762// TestH2H2MultipleResponseCL tests that server returns error if
2763// multiple Content-Length response header fields are received.
2764func TestH2H2MultipleResponseCL(t *testing.T) {
2765	opts := options{
2766		args: []string{"--http2-bridge"},
2767		handler: func(w http.ResponseWriter, _ *http.Request) {
2768			w.Header().Add("content-length", "1")
2769			w.Header().Add("content-length", "1")
2770		},
2771	}
2772
2773	st := newServerTester(t, opts)
2774	defer st.Close()
2775
2776	res, err := st.http2(requestParam{
2777		name: "TestH2H2MultipleResponseCL",
2778	})
2779	if err != nil {
2780		t.Fatalf("Error st.http2() = %v", err)
2781	}
2782
2783	if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2784		t.Errorf("res.errCode: %v; want %v", got, want)
2785	}
2786}
2787
2788// TestH2H2InvalidResponseCL tests that server returns error if
2789// Content-Length response header field value cannot be parsed as a
2790// number.
2791func TestH2H2InvalidResponseCL(t *testing.T) {
2792	opts := options{
2793		args: []string{"--http2-bridge"},
2794		handler: func(w http.ResponseWriter, _ *http.Request) {
2795			w.Header().Add("content-length", "")
2796		},
2797	}
2798
2799	st := newServerTester(t, opts)
2800	defer st.Close()
2801
2802	res, err := st.http2(requestParam{
2803		name: "TestH2H2InvalidResponseCL",
2804	})
2805	if err != nil {
2806		t.Fatalf("Error st.http2() = %v", err)
2807	}
2808
2809	if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2810		t.Errorf("res.errCode: %v; want %v", got, want)
2811	}
2812}
2813
2814// // TestH2H2ConnectFailure tests that server handles the situation that
2815// // connection attempt to HTTP/2 backend failed.
2816// func TestH2H2ConnectFailure(t *testing.T) {
2817// 	opts := options{
2818// 		args: []string{"--http2-bridge"},
2819// 	}
2820// 	st := newServerTester(t, opts)
2821// 	defer st.Close()
2822
2823// 	// simulate backend connect attempt failure
2824// 	st.ts.Close()
2825
2826// 	res, err := st.http2(requestParam{
2827// 		name: "TestH2H2ConnectFailure",
2828// 	})
2829// 	if err != nil {
2830// 		t.Fatalf("Error st.http2() = %v", err)
2831// 	}
2832// 	want := 503
2833// 	if got := res.status; got != want {
2834// 		t.Errorf("status: %v; want %v", got, want)
2835// 	}
2836// }
2837
2838// TestH2H2HostRewrite tests that server rewrites host header field
2839func TestH2H2HostRewrite(t *testing.T) {
2840	opts := options{
2841		args: []string{"--http2-bridge", "--host-rewrite"},
2842		handler: func(w http.ResponseWriter, r *http.Request) {
2843			w.Header().Add("request-host", r.Host)
2844		},
2845	}
2846
2847	st := newServerTester(t, opts)
2848	defer st.Close()
2849
2850	res, err := st.http2(requestParam{
2851		name: "TestH2H2HostRewrite",
2852	})
2853	if err != nil {
2854		t.Fatalf("Error st.http2() = %v", err)
2855	}
2856
2857	if got, want := res.status, http.StatusOK; got != want {
2858		t.Errorf("status: %v; want %v", got, want)
2859	}
2860
2861	if got, want := res.header.Get("request-host"), st.backendHost; got != want {
2862		t.Errorf("request-host: %v; want %v", got, want)
2863	}
2864}
2865
2866// TestH2H2NoHostRewrite tests that server does not rewrite host
2867// header field
2868func TestH2H2NoHostRewrite(t *testing.T) {
2869	opts := options{
2870		args: []string{"--http2-bridge"},
2871		handler: func(w http.ResponseWriter, r *http.Request) {
2872			w.Header().Add("request-host", r.Host)
2873		},
2874	}
2875
2876	st := newServerTester(t, opts)
2877	defer st.Close()
2878
2879	res, err := st.http2(requestParam{
2880		name: "TestH2H2NoHostRewrite",
2881	})
2882	if err != nil {
2883		t.Fatalf("Error st.http2() = %v", err)
2884	}
2885
2886	if got, want := res.status, http.StatusOK; got != want {
2887		t.Errorf("status: %v; want %v", got, want)
2888	}
2889
2890	if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
2891		t.Errorf("request-host: %v; want %v", got, want)
2892	}
2893}
2894
2895// TestH2H2TLSXfp tests nghttpx sends x-forwarded-proto header field
2896// with http value since :scheme is http, even if the frontend
2897// connection is encrypted.
2898func TestH2H2TLSXfp(t *testing.T) {
2899	opts := options{
2900		args: []string{"--http2-bridge"},
2901		handler: func(_ http.ResponseWriter, r *http.Request) {
2902			if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
2903				t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
2904			}
2905		},
2906		tls: true,
2907	}
2908
2909	st := newServerTester(t, opts)
2910	defer st.Close()
2911
2912	res, err := st.http2(requestParam{
2913		name: "TestH2H2TLSXfp",
2914	})
2915	if err != nil {
2916		t.Fatalf("Error st.http2() = %v", err)
2917	}
2918
2919	if got, want := res.status, http.StatusOK; got != want {
2920		t.Errorf("res.status: %v; want %v", got, want)
2921	}
2922}
2923
2924// TestH2H2AddXfp tests that server appends :scheme to the existing
2925// x-forwarded-proto header field.
2926func TestH2H2AddXfp(t *testing.T) {
2927	opts := options{
2928		args: []string{
2929			"--http2-bridge",
2930			"--no-strip-incoming-x-forwarded-proto",
2931		},
2932		handler: func(_ http.ResponseWriter, r *http.Request) {
2933			xfp := r.Header.Get("X-Forwarded-Proto")
2934			if got, want := xfp, "foo, http"; got != want {
2935				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
2936			}
2937		},
2938		tls: true,
2939	}
2940
2941	st := newServerTester(t, opts)
2942	defer st.Close()
2943
2944	res, err := st.http2(requestParam{
2945		name: "TestH2H2AddXfp",
2946		header: []hpack.HeaderField{
2947			pair("x-forwarded-proto", "foo"),
2948		},
2949	})
2950	if err != nil {
2951		t.Fatalf("Error st.http2() = %v", err)
2952	}
2953
2954	if got, want := res.status, http.StatusOK; got != want {
2955		t.Errorf("status = %v; want %v", got, want)
2956	}
2957}
2958
2959// TestH2H2NoAddXfp tests that server does not append :scheme to the
2960// existing x-forwarded-proto header field.
2961func TestH2H2NoAddXfp(t *testing.T) {
2962	opts := options{
2963		args: []string{
2964			"--http2-bridge",
2965			"--no-add-x-forwarded-proto",
2966			"--no-strip-incoming-x-forwarded-proto",
2967		},
2968		handler: func(_ http.ResponseWriter, r *http.Request) {
2969			xfp := r.Header.Get("X-Forwarded-Proto")
2970			if got, want := xfp, "foo"; got != want {
2971				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
2972			}
2973		},
2974		tls: true,
2975	}
2976
2977	st := newServerTester(t, opts)
2978	defer st.Close()
2979
2980	res, err := st.http2(requestParam{
2981		name: "TestH2H2NoAddXfp",
2982		header: []hpack.HeaderField{
2983			pair("x-forwarded-proto", "foo"),
2984		},
2985	})
2986	if err != nil {
2987		t.Fatalf("Error st.http2() = %v", err)
2988	}
2989
2990	if got, want := res.status, http.StatusOK; got != want {
2991		t.Errorf("status = %v; want %v", got, want)
2992	}
2993}
2994
2995// TestH2H2StripXfp tests that server strips incoming
2996// x-forwarded-proto header field.
2997func TestH2H2StripXfp(t *testing.T) {
2998	opts := options{
2999		args: []string{"--http2-bridge"},
3000		handler: func(_ http.ResponseWriter, r *http.Request) {
3001			xfp := r.Header.Get("X-Forwarded-Proto")
3002			if got, want := xfp, "http"; got != want {
3003				t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
3004			}
3005		},
3006		tls: true,
3007	}
3008
3009	st := newServerTester(t, opts)
3010	defer st.Close()
3011
3012	res, err := st.http2(requestParam{
3013		name: "TestH2H2StripXfp",
3014		header: []hpack.HeaderField{
3015			pair("x-forwarded-proto", "foo"),
3016		},
3017	})
3018	if err != nil {
3019		t.Fatalf("Error st.http2() = %v", err)
3020	}
3021
3022	if got, want := res.status, http.StatusOK; got != want {
3023		t.Errorf("status = %v; want %v", got, want)
3024	}
3025}
3026
3027// TestH2H2StripNoAddXfp tests that server strips incoming
3028// x-forwarded-proto header field, and does not add another.
3029func TestH2H2StripNoAddXfp(t *testing.T) {
3030	opts := options{
3031		args: []string{"--http2-bridge", "--no-add-x-forwarded-proto"},
3032		handler: func(_ http.ResponseWriter, r *http.Request) {
3033			if got, found := r.Header["X-Forwarded-Proto"]; found {
3034				t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
3035			}
3036		},
3037		tls: true,
3038	}
3039
3040	st := newServerTester(t, opts)
3041	defer st.Close()
3042
3043	res, err := st.http2(requestParam{
3044		name: "TestH2H2StripNoAddXfp",
3045		header: []hpack.HeaderField{
3046			pair("x-forwarded-proto", "foo"),
3047		},
3048	})
3049	if err != nil {
3050		t.Fatalf("Error st.http2() = %v", err)
3051	}
3052
3053	if got, want := res.status, http.StatusOK; got != want {
3054		t.Errorf("status = %v; want %v", got, want)
3055	}
3056}
3057
3058// TestH2H2AddXff tests that server generates X-Forwarded-For header
3059// field when forwarding request to backend.
3060func TestH2H2AddXff(t *testing.T) {
3061	opts := options{
3062		args: []string{"--http2-bridge", "--add-x-forwarded-for"},
3063		handler: func(_ http.ResponseWriter, r *http.Request) {
3064			xff := r.Header.Get("X-Forwarded-For")
3065			want := "127.0.0.1"
3066			if xff != want {
3067				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
3068			}
3069		},
3070		tls: true,
3071	}
3072
3073	st := newServerTester(t, opts)
3074	defer st.Close()
3075
3076	res, err := st.http2(requestParam{
3077		name: "TestH2H2AddXff",
3078	})
3079	if err != nil {
3080		t.Fatalf("Error st.http2() = %v", err)
3081	}
3082
3083	if got, want := res.status, http.StatusOK; got != want {
3084		t.Errorf("status = %v; want %v", got, want)
3085	}
3086}
3087
3088// TestH2H2AddXff2 tests that server appends X-Forwarded-For header
3089// field to existing one when forwarding request to backend.
3090func TestH2H2AddXff2(t *testing.T) {
3091	opts := options{
3092		args: []string{"--http2-bridge", "--add-x-forwarded-for"},
3093		handler: func(_ http.ResponseWriter, r *http.Request) {
3094			xff := r.Header.Get("X-Forwarded-For")
3095			want := "host, 127.0.0.1"
3096			if xff != want {
3097				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
3098			}
3099		},
3100		tls: true,
3101	}
3102
3103	st := newServerTester(t, opts)
3104	defer st.Close()
3105
3106	res, err := st.http2(requestParam{
3107		name: "TestH2H2AddXff2",
3108		header: []hpack.HeaderField{
3109			pair("x-forwarded-for", "host"),
3110		},
3111	})
3112	if err != nil {
3113		t.Fatalf("Error st.http2() = %v", err)
3114	}
3115
3116	if got, want := res.status, http.StatusOK; got != want {
3117		t.Errorf("status = %v; want %v", got, want)
3118	}
3119}
3120
3121// TestH2H2StripXff tests that --strip-incoming-x-forwarded-for
3122// option.
3123func TestH2H2StripXff(t *testing.T) {
3124	opts := options{
3125		args: []string{
3126			"--http2-bridge",
3127			"--strip-incoming-x-forwarded-for",
3128		},
3129		handler: func(_ http.ResponseWriter, r *http.Request) {
3130			if xff, found := r.Header["X-Forwarded-For"]; found {
3131				t.Errorf("X-Forwarded-For = %v; want nothing", xff)
3132			}
3133		},
3134		tls: true,
3135	}
3136
3137	st := newServerTester(t, opts)
3138	defer st.Close()
3139
3140	res, err := st.http2(requestParam{
3141		name: "TestH2H2StripXff",
3142		header: []hpack.HeaderField{
3143			pair("x-forwarded-for", "host"),
3144		},
3145	})
3146	if err != nil {
3147		t.Fatalf("Error st.http2() = %v", err)
3148	}
3149
3150	if got, want := res.status, http.StatusOK; got != want {
3151		t.Errorf("status = %v; want %v", got, want)
3152	}
3153}
3154
3155// TestH2H2StripAddXff tests that --strip-incoming-x-forwarded-for and
3156// --add-x-forwarded-for options.
3157func TestH2H2StripAddXff(t *testing.T) {
3158	opts := options{
3159		args: []string{
3160			"--http2-bridge",
3161			"--strip-incoming-x-forwarded-for",
3162			"--add-x-forwarded-for",
3163		},
3164		handler: func(_ http.ResponseWriter, r *http.Request) {
3165			xff := r.Header.Get("X-Forwarded-For")
3166			want := "127.0.0.1"
3167			if xff != want {
3168				t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
3169			}
3170		},
3171		tls: true,
3172	}
3173
3174	st := newServerTester(t, opts)
3175	defer st.Close()
3176
3177	res, err := st.http2(requestParam{
3178		name: "TestH2H2StripAddXff",
3179		header: []hpack.HeaderField{
3180			pair("x-forwarded-for", "host"),
3181		},
3182	})
3183	if err != nil {
3184		t.Fatalf("Error st.http2() = %v", err)
3185	}
3186
3187	if got, want := res.status, http.StatusOK; got != want {
3188		t.Errorf("status = %v; want %v", got, want)
3189	}
3190}
3191
3192// TestH2H2AddForwarded tests that server generates Forwarded header
3193// field using static obfuscated "by" parameter.
3194func TestH2H2AddForwarded(t *testing.T) {
3195	opts := options{
3196		args: []string{
3197			"--http2-bridge",
3198			"--add-forwarded=by,for,host,proto",
3199			"--forwarded-by=_alpha",
3200		},
3201		handler: func(_ http.ResponseWriter, r *http.Request) {
3202			pattern := fmt.Sprintf(`by=_alpha;for=_[^;]+;host="127\.0\.0\.1:%v";proto=https`, serverPort)
3203			validFwd := regexp.MustCompile(pattern)
3204			if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
3205				t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
3206			}
3207		},
3208		tls: true,
3209	}
3210
3211	st := newServerTester(t, opts)
3212	defer st.Close()
3213
3214	res, err := st.http2(requestParam{
3215		name:   "TestH2H2AddForwarded",
3216		scheme: "https",
3217	})
3218	if err != nil {
3219		t.Fatalf("Error st.http2() = %v", err)
3220	}
3221
3222	if got, want := res.status, http.StatusOK; got != want {
3223		t.Errorf("status: %v; want %v", got, want)
3224	}
3225}
3226
3227// TestH2H2AddForwardedMerge tests that server generates Forwarded
3228// header field using static obfuscated "by" parameter, and
3229// existing Forwarded header field.
3230func TestH2H2AddForwardedMerge(t *testing.T) {
3231	opts := options{
3232		args: []string{
3233			"--http2-bridge",
3234			"--add-forwarded=by,host,proto",
3235			"--forwarded-by=_alpha",
3236		},
3237		handler: func(_ http.ResponseWriter, r *http.Request) {
3238			want := fmt.Sprintf(`host=foo, by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
3239			if got := r.Header.Get("Forwarded"); got != want {
3240				t.Errorf("Forwarded = %v; want %v", got, want)
3241			}
3242		},
3243		tls: true,
3244	}
3245
3246	st := newServerTester(t, opts)
3247	defer st.Close()
3248
3249	res, err := st.http2(requestParam{
3250		name:   "TestH2H2AddForwardedMerge",
3251		scheme: "https",
3252		header: []hpack.HeaderField{
3253			pair("forwarded", "host=foo"),
3254		},
3255	})
3256	if err != nil {
3257		t.Fatalf("Error st.http2() = %v", err)
3258	}
3259
3260	if got, want := res.status, http.StatusOK; got != want {
3261		t.Errorf("status: %v; want %v", got, want)
3262	}
3263}
3264
3265// TestH2H2AddForwardedStrip tests that server generates Forwarded
3266// header field using static obfuscated "by" parameter, and
3267// existing Forwarded header field stripped.
3268func TestH2H2AddForwardedStrip(t *testing.T) {
3269	opts := options{
3270		args: []string{
3271			"--http2-bridge",
3272			"--strip-incoming-forwarded",
3273			"--add-forwarded=by,host,proto",
3274			"--forwarded-by=_alpha",
3275		},
3276		handler: func(_ http.ResponseWriter, r *http.Request) {
3277			want := fmt.Sprintf(`by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
3278			if got := r.Header.Get("Forwarded"); got != want {
3279				t.Errorf("Forwarded = %v; want %v", got, want)
3280			}
3281		},
3282		tls: true,
3283	}
3284
3285	st := newServerTester(t, opts)
3286	defer st.Close()
3287
3288	res, err := st.http2(requestParam{
3289		name:   "TestH2H2AddForwardedStrip",
3290		scheme: "https",
3291		header: []hpack.HeaderField{
3292			pair("forwarded", "host=foo"),
3293		},
3294	})
3295	if err != nil {
3296		t.Fatalf("Error st.http2() = %v", err)
3297	}
3298
3299	if got, want := res.status, http.StatusOK; got != want {
3300		t.Errorf("status: %v; want %v", got, want)
3301	}
3302}
3303
3304// TestH2H2StripForwarded tests that server strips incoming Forwarded
3305// header field.
3306func TestH2H2StripForwarded(t *testing.T) {
3307	opts := options{
3308		args: []string{"--http2-bridge", "--strip-incoming-forwarded"},
3309		handler: func(_ http.ResponseWriter, r *http.Request) {
3310			if got, found := r.Header["Forwarded"]; found {
3311				t.Errorf("Forwarded = %v; want nothing", got)
3312			}
3313		},
3314		tls: true,
3315	}
3316
3317	st := newServerTester(t, opts)
3318	defer st.Close()
3319
3320	res, err := st.http2(requestParam{
3321		name:   "TestH2H2StripForwarded",
3322		scheme: "https",
3323		header: []hpack.HeaderField{
3324			pair("forwarded", "host=foo"),
3325		},
3326	})
3327	if err != nil {
3328		t.Fatalf("Error st.http2() = %v", err)
3329	}
3330
3331	if got, want := res.status, http.StatusOK; got != want {
3332		t.Errorf("status: %v; want %v", got, want)
3333	}
3334}
3335
3336// TestH2H2ReqPhaseReturn tests mruby request phase hook returns
3337// custom response.
3338func TestH2H2ReqPhaseReturn(t *testing.T) {
3339	opts := options{
3340		args: []string{
3341			"--http2-bridge",
3342			"--mruby-file=" + testDir + "/req-return.rb",
3343		},
3344		handler: func(http.ResponseWriter, *http.Request) {
3345			t.Fatalf("request should not be forwarded")
3346		},
3347	}
3348
3349	st := newServerTester(t, opts)
3350	defer st.Close()
3351
3352	res, err := st.http2(requestParam{
3353		name: "TestH2H2ReqPhaseReturn",
3354	})
3355	if err != nil {
3356		t.Fatalf("Error st.http2() = %v", err)
3357	}
3358
3359	if got, want := res.status, http.StatusNotFound; got != want {
3360		t.Errorf("status = %v; want %v", got, want)
3361	}
3362
3363	hdtests := []struct {
3364		k, v string
3365	}{
3366		{"content-length", "20"},
3367		{"from", "mruby"},
3368	}
3369
3370	for _, tt := range hdtests {
3371		if got, want := res.header.Get(tt.k), tt.v; got != want {
3372			t.Errorf("%v = %v; want %v", tt.k, got, want)
3373		}
3374	}
3375
3376	if got, want := string(res.body), "Hello World from req"; got != want {
3377		t.Errorf("body = %v; want %v", got, want)
3378	}
3379}
3380
3381// TestH2H2RespPhaseReturn tests mruby response phase hook returns
3382// custom response.
3383func TestH2H2RespPhaseReturn(t *testing.T) {
3384	opts := options{
3385		args: []string{
3386			"--http2-bridge",
3387			"--mruby-file=" + testDir + "/resp-return.rb",
3388		},
3389	}
3390
3391	st := newServerTester(t, opts)
3392	defer st.Close()
3393
3394	res, err := st.http2(requestParam{
3395		name: "TestH2H2RespPhaseReturn",
3396	})
3397	if err != nil {
3398		t.Fatalf("Error st.http2() = %v", err)
3399	}
3400
3401	if got, want := res.status, http.StatusNotFound; got != want {
3402		t.Errorf("status = %v; want %v", got, want)
3403	}
3404
3405	hdtests := []struct {
3406		k, v string
3407	}{
3408		{"content-length", "21"},
3409		{"from", "mruby"},
3410	}
3411
3412	for _, tt := range hdtests {
3413		if got, want := res.header.Get(tt.k), tt.v; got != want {
3414			t.Errorf("%v = %v; want %v", tt.k, got, want)
3415		}
3416	}
3417
3418	if got, want := string(res.body), "Hello World from resp"; got != want {
3419		t.Errorf("body = %v; want %v", got, want)
3420	}
3421}
3422
3423// TestH2H2ExternalDNS tests that DNS resolution using external DNS
3424// with HTTP/2 backend works.
3425func TestH2H2ExternalDNS(t *testing.T) {
3426	opts := options{
3427		args: []string{"--http2-bridge", "--external-dns"},
3428	}
3429
3430	st := newServerTester(t, opts)
3431	defer st.Close()
3432
3433	res, err := st.http2(requestParam{
3434		name: "TestH2H2ExternalDNS",
3435	})
3436	if err != nil {
3437		t.Fatalf("Error st.http2() = %v", err)
3438	}
3439
3440	if got, want := res.status, http.StatusOK; got != want {
3441		t.Errorf("status = %v; want %v", got, want)
3442	}
3443}
3444
3445// TestH2H2DNS tests that DNS resolution without external DNS with
3446// HTTP/2 backend works.
3447func TestH2H2DNS(t *testing.T) {
3448	opts := options{
3449		args: []string{"--http2-bridge", "--dns"},
3450	}
3451
3452	st := newServerTester(t, opts)
3453	defer st.Close()
3454
3455	res, err := st.http2(requestParam{
3456		name: "TestH2H2DNS",
3457	})
3458	if err != nil {
3459		t.Fatalf("Error st.http2() = %v", err)
3460	}
3461
3462	if got, want := res.status, http.StatusOK; got != want {
3463		t.Errorf("status = %v; want %v", got, want)
3464	}
3465}
3466
3467// TestH2H2Code204 tests that 204 response without content-length, and
3468// transfer-encoding is valid.
3469func TestH2H2Code204(t *testing.T) {
3470	opts := options{
3471		args: []string{"--http2-bridge"},
3472		handler: func(w http.ResponseWriter, _ *http.Request) {
3473			w.WriteHeader(http.StatusNoContent)
3474		},
3475	}
3476
3477	st := newServerTester(t, opts)
3478	defer st.Close()
3479
3480	res, err := st.http2(requestParam{
3481		name: "TestH2H2Code204",
3482	})
3483	if err != nil {
3484		t.Fatalf("Error st.http2() = %v", err)
3485	}
3486
3487	if got, want := res.status, http.StatusNoContent; got != want {
3488		t.Errorf("status = %v; want %v", got, want)
3489	}
3490}
3491
3492// TestH2APIBackendconfig exercise backendconfig API endpoint routine
3493// for successful case.
3494func TestH2APIBackendconfig(t *testing.T) {
3495	opts := options{
3496		args: []string{"-f127.0.0.1,3010;api;no-tls"},
3497		handler: func(http.ResponseWriter, *http.Request) {
3498			t.Fatalf("request should not be forwarded")
3499		},
3500		connectPort: 3010,
3501	}
3502
3503	st := newServerTester(t, opts)
3504	defer st.Close()
3505
3506	res, err := st.http2(requestParam{
3507		name:   "TestH2APIBackendconfig",
3508		path:   "/api/v1beta1/backendconfig",
3509		method: "PUT",
3510		body: []byte(`# comment
3511backend=127.0.0.1,3011
3512
3513`),
3514	})
3515	if err != nil {
3516		t.Fatalf("Error st.http2() = %v", err)
3517	}
3518
3519	if got, want := res.status, http.StatusOK; got != want {
3520		t.Errorf("res.status: %v; want %v", got, want)
3521	}
3522
3523	var apiResp APIResponse
3524
3525	if err := json.Unmarshal(res.body, &apiResp); err != nil {
3526		t.Fatalf("Error unmarshaling API response: %v", err)
3527	}
3528
3529	if got, want := apiResp.Status, "Success"; got != want {
3530		t.Errorf("apiResp.Status: %v; want %v", got, want)
3531	}
3532
3533	if got, want := apiResp.Code, 200; got != want {
3534		t.Errorf("apiResp.Status: %v; want %v", got, want)
3535	}
3536}
3537
3538// TestH2APIBackendconfigQuery exercise backendconfig API endpoint
3539// routine with query.
3540func TestH2APIBackendconfigQuery(t *testing.T) {
3541	opts := options{
3542		args: []string{"-f127.0.0.1,3010;api;no-tls"},
3543		handler: func(http.ResponseWriter, *http.Request) {
3544			t.Fatalf("request should not be forwarded")
3545		},
3546		connectPort: 3010,
3547	}
3548
3549	st := newServerTester(t, opts)
3550	defer st.Close()
3551
3552	res, err := st.http2(requestParam{
3553		name:   "TestH2APIBackendconfigQuery",
3554		path:   "/api/v1beta1/backendconfig?foo=bar",
3555		method: "PUT",
3556		body: []byte(`# comment
3557backend=127.0.0.1,3011
3558
3559`),
3560	})
3561	if err != nil {
3562		t.Fatalf("Error st.http2() = %v", err)
3563	}
3564
3565	if got, want := res.status, http.StatusOK; got != want {
3566		t.Errorf("res.status: %v; want %v", got, want)
3567	}
3568
3569	var apiResp APIResponse
3570
3571	if err := json.Unmarshal(res.body, &apiResp); err != nil {
3572		t.Fatalf("Error unmarshaling API response: %v", err)
3573	}
3574
3575	if got, want := apiResp.Status, "Success"; got != want {
3576		t.Errorf("apiResp.Status: %v; want %v", got, want)
3577	}
3578
3579	if got, want := apiResp.Code, 200; got != want {
3580		t.Errorf("apiResp.Status: %v; want %v", got, want)
3581	}
3582}
3583
3584// TestH2APIBackendconfigBadMethod exercise backendconfig API endpoint
3585// routine with bad method.
3586func TestH2APIBackendconfigBadMethod(t *testing.T) {
3587	opts := options{
3588		args: []string{"-f127.0.0.1,3010;api;no-tls"},
3589		handler: func(http.ResponseWriter, *http.Request) {
3590			t.Fatalf("request should not be forwarded")
3591		},
3592		connectPort: 3010,
3593	}
3594
3595	st := newServerTester(t, opts)
3596	defer st.Close()
3597
3598	res, err := st.http2(requestParam{
3599		name:   "TestH2APIBackendconfigBadMethod",
3600		path:   "/api/v1beta1/backendconfig",
3601		method: "GET",
3602		body: []byte(`# comment
3603backend=127.0.0.1,3011
3604
3605`),
3606	})
3607	if err != nil {
3608		t.Fatalf("Error st.http2() = %v", err)
3609	}
3610
3611	if got, want := res.status, http.StatusMethodNotAllowed; got != want {
3612		t.Errorf("res.status: %v; want %v", got, want)
3613	}
3614
3615	var apiResp APIResponse
3616
3617	if err := json.Unmarshal(res.body, &apiResp); err != nil {
3618		t.Fatalf("Error unmarshaling API response: %v", err)
3619	}
3620
3621	if got, want := apiResp.Status, "Failure"; got != want {
3622		t.Errorf("apiResp.Status: %v; want %v", got, want)
3623	}
3624
3625	if got, want := apiResp.Code, 405; got != want {
3626		t.Errorf("apiResp.Status: %v; want %v", got, want)
3627	}
3628}
3629
3630// TestH2APIConfigrevision tests configrevision API.
3631func TestH2APIConfigrevision(t *testing.T) {
3632	opts := options{
3633		args: []string{"-f127.0.0.1,3010;api;no-tls"},
3634		handler: func(http.ResponseWriter, *http.Request) {
3635			t.Fatalf("request should not be forwarded")
3636		},
3637		connectPort: 3010,
3638	}
3639
3640	st := newServerTester(t, opts)
3641	defer st.Close()
3642
3643	res, err := st.http2(requestParam{
3644		name:   "TestH2APIConfigrevision",
3645		path:   "/api/v1beta1/configrevision",
3646		method: "GET",
3647	})
3648	if err != nil {
3649		t.Fatalf("Error st.http2() = %v", err)
3650	}
3651
3652	if got, want := res.status, http.StatusOK; got != want {
3653		t.Errorf("res.status: %v; want = %v", got, want)
3654	}
3655
3656	var apiResp APIResponse
3657
3658	d := json.NewDecoder(bytes.NewBuffer(res.body))
3659	d.UseNumber()
3660
3661	if err := d.Decode(&apiResp); err != nil {
3662		t.Fatalf("Error unmarshalling API response: %v", err)
3663	}
3664
3665	if got, want := apiResp.Status, "Success"; got != want {
3666		t.Errorf("apiResp.Status: %v; want %v", got, want)
3667	}
3668
3669	if got, want := apiResp.Code, 200; got != want {
3670		t.Errorf("apiResp.Status: %v; want %v", got, want)
3671	}
3672
3673	if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want {
3674		t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want)
3675	}
3676}
3677
3678// TestH2APINotFound exercise backendconfig API endpoint routine when
3679// API endpoint is not found.
3680func TestH2APINotFound(t *testing.T) {
3681	opts := options{
3682		args: []string{"-f127.0.0.1,3010;api;no-tls"},
3683		handler: func(http.ResponseWriter, *http.Request) {
3684			t.Fatalf("request should not be forwarded")
3685		},
3686		connectPort: 3010,
3687	}
3688
3689	st := newServerTester(t, opts)
3690	defer st.Close()
3691
3692	res, err := st.http2(requestParam{
3693		name:   "TestH2APINotFound",
3694		path:   "/api/notfound",
3695		method: "GET",
3696		body: []byte(`# comment
3697backend=127.0.0.1,3011
3698
3699`),
3700	})
3701	if err != nil {
3702		t.Fatalf("Error st.http2() = %v", err)
3703	}
3704
3705	if got, want := res.status, http.StatusNotFound; got != want {
3706		t.Errorf("res.status: %v; want %v", got, want)
3707	}
3708
3709	var apiResp APIResponse
3710
3711	if err := json.Unmarshal(res.body, &apiResp); err != nil {
3712		t.Fatalf("Error unmarshaling API response: %v", err)
3713	}
3714
3715	if got, want := apiResp.Status, "Failure"; got != want {
3716		t.Errorf("apiResp.Status: %v; want %v", got, want)
3717	}
3718
3719	if got, want := apiResp.Code, 404; got != want {
3720		t.Errorf("apiResp.Status: %v; want %v", got, want)
3721	}
3722}
3723
3724// TestH2Healthmon tests health monitor endpoint.
3725func TestH2Healthmon(t *testing.T) {
3726	opts := options{
3727		args: []string{"-f127.0.0.1,3011;healthmon;no-tls"},
3728		handler: func(http.ResponseWriter, *http.Request) {
3729			t.Fatalf("request should not be forwarded")
3730		},
3731		connectPort: 3011,
3732	}
3733
3734	st := newServerTester(t, opts)
3735	defer st.Close()
3736
3737	res, err := st.http2(requestParam{
3738		name: "TestH2Healthmon",
3739		path: "/alpha/bravo",
3740	})
3741	if err != nil {
3742		t.Fatalf("Error st.http2() = %v", err)
3743	}
3744
3745	if got, want := res.status, http.StatusOK; got != want {
3746		t.Errorf("res.status: %v; want %v", got, want)
3747	}
3748}
3749
3750// TestH2ResponseBeforeRequestEnd tests the situation where response
3751// ends before request body finishes.
3752func TestH2ResponseBeforeRequestEnd(t *testing.T) {
3753	opts := options{
3754		args: []string{"--mruby-file=" + testDir + "/req-return.rb"},
3755		handler: func(http.ResponseWriter, *http.Request) {
3756			t.Fatal("request should not be forwarded")
3757		},
3758	}
3759
3760	st := newServerTester(t, opts)
3761	defer st.Close()
3762
3763	res, err := st.http2(requestParam{
3764		name:        "TestH2ResponseBeforeRequestEnd",
3765		noEndStream: true,
3766	})
3767	if err != nil {
3768		t.Fatalf("Error st.http2() = %v", err)
3769	}
3770
3771	if got, want := res.status, http.StatusNotFound; got != want {
3772		t.Errorf("res.status: %v; want %v", got, want)
3773	}
3774}
3775
3776// TestH2H1ChunkedEndsPrematurely tests that a stream is reset if the
3777// backend chunked encoded response ends prematurely.
3778func TestH2H1ChunkedEndsPrematurely(t *testing.T) {
3779	opts := options{
3780		handler: func(w http.ResponseWriter, _ *http.Request) {
3781			hj, ok := w.(http.Hijacker)
3782			if !ok {
3783				http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
3784				return
3785			}
3786
3787			conn, bufrw, err := hj.Hijack()
3788			if err != nil {
3789				http.Error(w, err.Error(), http.StatusInternalServerError)
3790				return
3791			}
3792
3793			defer conn.Close()
3794
3795			if _, err := bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n"); err != nil {
3796				t.Fatalf("Error bufrw.WriteString() = %v", err)
3797			}
3798
3799			bufrw.Flush()
3800		},
3801	}
3802
3803	st := newServerTester(t, opts)
3804	defer st.Close()
3805
3806	res, err := st.http2(requestParam{
3807		name: "TestH2H1ChunkedEndsPrematurely",
3808	})
3809	if err != nil {
3810		t.Fatalf("Error st.http2() = %v", err)
3811	}
3812
3813	if got, want := res.errCode, http2.ErrCodeInternal; got != want {
3814		t.Errorf("res.errCode = %v; want %v", got, want)
3815	}
3816}
3817
3818// TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption verifies that https
3819// scheme in non-encrypted connection is treated as error.
3820func TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption(t *testing.T) {
3821	opts := options{
3822		args: []string{"--require-http-scheme"},
3823		handler: func(http.ResponseWriter, *http.Request) {
3824			t.Errorf("server should not forward this request")
3825		},
3826	}
3827
3828	st := newServerTester(t, opts)
3829	defer st.Close()
3830
3831	res, err := st.http2(requestParam{
3832		name:   "TestH2H1RequireHTTPSchemeHTTPSWithoutEncryption",
3833		scheme: "https",
3834	})
3835	if err != nil {
3836		t.Fatalf("Error st.http2() = %v", err)
3837	}
3838
3839	if got, want := res.status, http.StatusBadRequest; got != want {
3840		t.Errorf("status = %v; want %v", got, want)
3841	}
3842}
3843
3844// TestH2H1RequireHTTPSchemeHTTPWithEncryption verifies that http
3845// scheme in encrypted connection is treated as error.
3846func TestH2H1RequireHTTPSchemeHTTPWithEncryption(t *testing.T) {
3847	opts := options{
3848		args: []string{"--require-http-scheme"},
3849		handler: func(http.ResponseWriter, *http.Request) {
3850			t.Errorf("server should not forward this request")
3851		},
3852		tls: true,
3853	}
3854
3855	st := newServerTester(t, opts)
3856	defer st.Close()
3857
3858	res, err := st.http2(requestParam{
3859		name:   "TestH2H1RequireHTTPSchemeHTTPWithEncryption",
3860		scheme: "http",
3861	})
3862	if err != nil {
3863		t.Fatalf("Error st.http2() = %v", err)
3864	}
3865
3866	if got, want := res.status, http.StatusBadRequest; got != want {
3867		t.Errorf("status = %v; want %v", got, want)
3868	}
3869}
3870
3871// TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption verifies
3872// that unknown scheme in non-encrypted connection is treated as
3873// error.
3874func TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption(t *testing.T) {
3875	opts := options{
3876		args: []string{"--require-http-scheme"},
3877		handler: func(http.ResponseWriter, *http.Request) {
3878			t.Errorf("server should not forward this request")
3879		},
3880	}
3881
3882	st := newServerTester(t, opts)
3883	defer st.Close()
3884
3885	res, err := st.http2(requestParam{
3886		name:   "TestH2H1RequireHTTPSchemeUnknownSchemeWithoutEncryption",
3887		scheme: "unknown",
3888	})
3889	if err != nil {
3890		t.Fatalf("Error st.http2() = %v", err)
3891	}
3892
3893	if got, want := res.status, http.StatusBadRequest; got != want {
3894		t.Errorf("status = %v; want %v", got, want)
3895	}
3896}
3897
3898// TestH2H1RequireHTTPSchemeUnknownSchemeWithEncryption verifies that
3899// unknown scheme in encrypted connection is treated as error.
3900func TestH2H1RequireHTTPSchemeUnknownSchemeWithEncryption(t *testing.T) {
3901	opts := options{
3902		args: []string{"--require-http-scheme"},
3903		handler: func(http.ResponseWriter, *http.Request) {
3904			t.Errorf("server should not forward this request")
3905		},
3906		tls: true,
3907	}
3908
3909	st := newServerTester(t, opts)
3910	defer st.Close()
3911
3912	res, err := st.http2(requestParam{
3913		name:   "TestH2H1RequireHTTPSchemeUnknownSchemeWithEncryption",
3914		scheme: "unknown",
3915	})
3916	if err != nil {
3917		t.Fatalf("Error st.http2() = %v", err)
3918	}
3919
3920	if got, want := res.status, http.StatusBadRequest; got != want {
3921		t.Errorf("status = %v; want %v", got, want)
3922	}
3923}
3924