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