• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package nghttp2
2
3import (
4	"bytes"
5	"crypto/tls"
6	"encoding/json"
7	"fmt"
8	"golang.org/x/net/http2"
9	"golang.org/x/net/http2/hpack"
10	"io"
11	"io/ioutil"
12	"net"
13	"net/http"
14	"regexp"
15	"strings"
16	"syscall"
17	"testing"
18	"time"
19)
20
21// TestH2H1PlainGET tests whether simple HTTP/2 GET request works.
22func TestH2H1PlainGET(t *testing.T) {
23	st := newServerTester(nil, t, noopHandler)
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	want := 200
34	if res.status != want {
35		t.Errorf("status = %v; want %v", res.status, want)
36	}
37}
38
39// TestH2H1AddXfp tests that server appends :scheme to the existing
40// x-forwarded-proto header field.
41func TestH2H1AddXfp(t *testing.T) {
42	st := newServerTester([]string{"--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
43		xfp := r.Header.Get("X-Forwarded-Proto")
44		if got, want := xfp, "foo, http"; got != want {
45			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
46		}
47	})
48	defer st.Close()
49
50	res, err := st.http2(requestParam{
51		name: "TestH2H1AddXfp",
52		header: []hpack.HeaderField{
53			pair("x-forwarded-proto", "foo"),
54		},
55	})
56	if err != nil {
57		t.Fatalf("Error st.http2() = %v", err)
58	}
59	if got, want := res.status, 200; got != want {
60		t.Errorf("status = %v; want %v", got, want)
61	}
62}
63
64// TestH2H1NoAddXfp tests that server does not append :scheme to the
65// existing x-forwarded-proto header field.
66func TestH2H1NoAddXfp(t *testing.T) {
67	st := newServerTester([]string{"--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
68		xfp := r.Header.Get("X-Forwarded-Proto")
69		if got, want := xfp, "foo"; got != want {
70			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
71		}
72	})
73	defer st.Close()
74
75	res, err := st.http2(requestParam{
76		name: "TestH2H1NoAddXfp",
77		header: []hpack.HeaderField{
78			pair("x-forwarded-proto", "foo"),
79		},
80	})
81	if err != nil {
82		t.Fatalf("Error st.http2() = %v", err)
83	}
84	if got, want := res.status, 200; got != want {
85		t.Errorf("status = %v; want %v", got, want)
86	}
87}
88
89// TestH2H1StripXfp tests that server strips incoming
90// x-forwarded-proto header field.
91func TestH2H1StripXfp(t *testing.T) {
92	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
93		xfp := r.Header.Get("X-Forwarded-Proto")
94		if got, want := xfp, "http"; got != want {
95			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
96		}
97	})
98	defer st.Close()
99
100	res, err := st.http2(requestParam{
101		name: "TestH2H1StripXfp",
102		header: []hpack.HeaderField{
103			pair("x-forwarded-proto", "foo"),
104		},
105	})
106	if err != nil {
107		t.Fatalf("Error st.http2() = %v", err)
108	}
109	if got, want := res.status, 200; got != want {
110		t.Errorf("status = %v; want %v", got, want)
111	}
112}
113
114// TestH2H1StripNoAddXfp tests that server strips incoming
115// x-forwarded-proto header field, and does not add another.
116func TestH2H1StripNoAddXfp(t *testing.T) {
117	st := newServerTester([]string{"--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
118		if got, found := r.Header["X-Forwarded-Proto"]; found {
119			t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
120		}
121	})
122	defer st.Close()
123
124	res, err := st.http2(requestParam{
125		name: "TestH2H1StripNoAddXfp",
126		header: []hpack.HeaderField{
127			pair("x-forwarded-proto", "foo"),
128		},
129	})
130	if err != nil {
131		t.Fatalf("Error st.http2() = %v", err)
132	}
133	if got, want := res.status, 200; got != want {
134		t.Errorf("status = %v; want %v", got, want)
135	}
136}
137
138// TestH2H1AddXff tests that server generates X-Forwarded-For header
139// field when forwarding request to backend.
140func TestH2H1AddXff(t *testing.T) {
141	st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
142		xff := r.Header.Get("X-Forwarded-For")
143		want := "127.0.0.1"
144		if xff != want {
145			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
146		}
147	})
148	defer st.Close()
149
150	res, err := st.http2(requestParam{
151		name: "TestH2H1AddXff",
152	})
153	if err != nil {
154		t.Fatalf("Error st.http2() = %v", err)
155	}
156	if got, want := res.status, 200; got != want {
157		t.Errorf("status = %v; want %v", got, want)
158	}
159}
160
161// TestH2H1AddXff2 tests that server appends X-Forwarded-For header
162// field to existing one when forwarding request to backend.
163func TestH2H1AddXff2(t *testing.T) {
164	st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
165		xff := r.Header.Get("X-Forwarded-For")
166		want := "host, 127.0.0.1"
167		if xff != want {
168			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
169		}
170	})
171	defer st.Close()
172
173	res, err := st.http2(requestParam{
174		name: "TestH2H1AddXff2",
175		header: []hpack.HeaderField{
176			pair("x-forwarded-for", "host"),
177		},
178	})
179	if err != nil {
180		t.Fatalf("Error st.http2() = %v", err)
181	}
182	if got, want := res.status, 200; got != want {
183		t.Errorf("status = %v; want %v", got, want)
184	}
185}
186
187// TestH2H1StripXff tests that --strip-incoming-x-forwarded-for
188// option.
189func TestH2H1StripXff(t *testing.T) {
190	st := newServerTester([]string{"--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
191		if xff, found := r.Header["X-Forwarded-For"]; found {
192			t.Errorf("X-Forwarded-For = %v; want nothing", xff)
193		}
194	})
195	defer st.Close()
196
197	res, err := st.http2(requestParam{
198		name: "TestH2H1StripXff",
199		header: []hpack.HeaderField{
200			pair("x-forwarded-for", "host"),
201		},
202	})
203	if err != nil {
204		t.Fatalf("Error st.http2() = %v", err)
205	}
206	if got, want := res.status, 200; got != want {
207		t.Errorf("status = %v; want %v", got, want)
208	}
209}
210
211// TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and
212// --add-x-forwarded-for options.
213func TestH2H1StripAddXff(t *testing.T) {
214	args := []string{
215		"--strip-incoming-x-forwarded-for",
216		"--add-x-forwarded-for",
217	}
218	st := newServerTester(args, t, func(w http.ResponseWriter, r *http.Request) {
219		xff := r.Header.Get("X-Forwarded-For")
220		want := "127.0.0.1"
221		if xff != want {
222			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
223		}
224	})
225	defer st.Close()
226
227	res, err := st.http2(requestParam{
228		name: "TestH2H1StripAddXff",
229		header: []hpack.HeaderField{
230			pair("x-forwarded-for", "host"),
231		},
232	})
233	if err != nil {
234		t.Fatalf("Error st.http2() = %v", err)
235	}
236	if got, want := res.status, 200; got != want {
237		t.Errorf("status = %v; want %v", got, want)
238	}
239}
240
241// TestH2H1AddForwardedObfuscated tests that server generates
242// Forwarded header field with obfuscated "by" and "for" parameters.
243func TestH2H1AddForwardedObfuscated(t *testing.T) {
244	st := newServerTester([]string{"--add-forwarded=by,for,host,proto"}, t, func(w http.ResponseWriter, r *http.Request) {
245		pattern := fmt.Sprintf(`by=_[^;]+;for=_[^;]+;host="127\.0\.0\.1:%v";proto=http`, serverPort)
246		validFwd := regexp.MustCompile(pattern)
247		got := r.Header.Get("Forwarded")
248
249		if !validFwd.MatchString(got) {
250			t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
251		}
252	})
253	defer st.Close()
254
255	res, err := st.http2(requestParam{
256		name: "TestH2H1AddForwardedObfuscated",
257	})
258	if err != nil {
259		t.Fatalf("Error st.http2() = %v", err)
260	}
261	if got, want := res.status, 200; got != want {
262		t.Errorf("status: %v; want %v", got, want)
263	}
264}
265
266// TestH2H1AddForwardedByIP tests that server generates Forwarded header
267// field with IP address in "by" parameter.
268func TestH2H1AddForwardedByIP(t *testing.T) {
269	st := newServerTester([]string{"--add-forwarded=by,for", "--forwarded-by=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
270		pattern := fmt.Sprintf(`by="127\.0\.0\.1:%v";for=_[^;]+`, serverPort)
271		validFwd := regexp.MustCompile(pattern)
272		if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
273			t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
274		}
275	})
276	defer st.Close()
277
278	res, err := st.http2(requestParam{
279		name: "TestH2H1AddForwardedByIP",
280	})
281	if err != nil {
282		t.Fatalf("Error st.http2() = %v", err)
283	}
284	if got, want := res.status, 200; got != want {
285		t.Errorf("status: %v; want %v", got, want)
286	}
287}
288
289// TestH2H1AddForwardedForIP tests that server generates Forwarded header
290// field with IP address in "for" parameters.
291func TestH2H1AddForwardedForIP(t *testing.T) {
292	st := newServerTester([]string{"--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
293		want := fmt.Sprintf(`by=_alpha;for=127.0.0.1;host="127.0.0.1:%v";proto=http`, serverPort)
294		if got := r.Header.Get("Forwarded"); got != want {
295			t.Errorf("Forwarded = %v; want %v", got, want)
296		}
297	})
298	defer st.Close()
299
300	res, err := st.http2(requestParam{
301		name: "TestH2H1AddForwardedForIP",
302	})
303	if err != nil {
304		t.Fatalf("Error st.http2() = %v", err)
305	}
306	if got, want := res.status, 200; got != want {
307		t.Errorf("status: %v; want %v", got, want)
308	}
309}
310
311// TestH2H1AddForwardedMerge tests that server generates Forwarded
312// header field with IP address in "by" and "for" parameters.  The
313// generated values must be appended to the existing value.
314func TestH2H1AddForwardedMerge(t *testing.T) {
315	st := newServerTester([]string{"--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) {
316		if got, want := r.Header.Get("Forwarded"), `host=foo, proto=http`; got != want {
317			t.Errorf("Forwarded = %v; want %v", got, want)
318		}
319	})
320	defer st.Close()
321
322	res, err := st.http2(requestParam{
323		name: "TestH2H1AddForwardedMerge",
324		header: []hpack.HeaderField{
325			pair("forwarded", "host=foo"),
326		},
327	})
328	if err != nil {
329		t.Fatalf("Error st.http2() = %v", err)
330	}
331	if got, want := res.status, 200; got != want {
332		t.Errorf("status: %v; want %v", got, want)
333	}
334}
335
336// TestH2H1AddForwardedStrip tests that server generates Forwarded
337// header field with IP address in "by" and "for" parameters.  The
338// generated values must not include the existing value.
339func TestH2H1AddForwardedStrip(t *testing.T) {
340	st := newServerTester([]string{"--strip-incoming-forwarded", "--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) {
341		if got, want := r.Header.Get("Forwarded"), `proto=http`; got != want {
342			t.Errorf("Forwarded = %v; want %v", got, want)
343		}
344	})
345	defer st.Close()
346
347	res, err := st.http2(requestParam{
348		name: "TestH2H1AddForwardedStrip",
349		header: []hpack.HeaderField{
350			pair("forwarded", "host=foo"),
351		},
352	})
353	if err != nil {
354		t.Fatalf("Error st.http2() = %v", err)
355	}
356	if got, want := res.status, 200; got != want {
357		t.Errorf("status: %v; want %v", got, want)
358	}
359}
360
361// TestH2H1StripForwarded tests that server strips incoming Forwarded
362// header field.
363func TestH2H1StripForwarded(t *testing.T) {
364	st := newServerTester([]string{"--strip-incoming-forwarded"}, t, func(w http.ResponseWriter, r *http.Request) {
365		if got, found := r.Header["Forwarded"]; found {
366			t.Errorf("Forwarded = %v; want nothing", got)
367		}
368	})
369	defer st.Close()
370
371	res, err := st.http2(requestParam{
372		name: "TestH2H1StripForwarded",
373		header: []hpack.HeaderField{
374			pair("forwarded", "host=foo"),
375		},
376	})
377	if err != nil {
378		t.Fatalf("Error st.http2() = %v", err)
379	}
380	if got, want := res.status, 200; got != want {
381		t.Errorf("status: %v; want %v", got, want)
382	}
383}
384
385// TestH2H1AddForwardedStatic tests that server generates Forwarded
386// header field with the given static obfuscated string for "by"
387// parameter.
388func TestH2H1AddForwardedStatic(t *testing.T) {
389	st := newServerTester([]string{"--add-forwarded=by,for", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) {
390		pattern := `by=_alpha;for=_[^;]+`
391		validFwd := regexp.MustCompile(pattern)
392		if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
393			t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
394		}
395	})
396	defer st.Close()
397
398	res, err := st.http2(requestParam{
399		name: "TestH2H1AddForwardedStatic",
400	})
401	if err != nil {
402		t.Fatalf("Error st.http2() = %v", err)
403	}
404	if got, want := res.status, 200; got != want {
405		t.Errorf("status: %v; want %v", got, want)
406	}
407}
408
409// TestH2H1GenerateVia tests that server generates Via header field to and
410// from backend server.
411func TestH2H1GenerateVia(t *testing.T) {
412	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
413		if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want {
414			t.Errorf("Via: %v; want %v", got, want)
415		}
416	})
417	defer st.Close()
418
419	res, err := st.http2(requestParam{
420		name: "TestH2H1GenerateVia",
421	})
422	if err != nil {
423		t.Fatalf("Error st.http2() = %v", err)
424	}
425	if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
426		t.Errorf("Via: %v; want %v", got, want)
427	}
428}
429
430// TestH2H1AppendVia tests that server adds value to existing Via
431// header field to and from backend server.
432func TestH2H1AppendVia(t *testing.T) {
433	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
434		if got, want := r.Header.Get("Via"), "foo, 2 nghttpx"; got != want {
435			t.Errorf("Via: %v; want %v", got, want)
436		}
437		w.Header().Add("Via", "bar")
438	})
439	defer st.Close()
440
441	res, err := st.http2(requestParam{
442		name: "TestH2H1AppendVia",
443		header: []hpack.HeaderField{
444			pair("via", "foo"),
445		},
446	})
447	if err != nil {
448		t.Fatalf("Error st.http2() = %v", err)
449	}
450	if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
451		t.Errorf("Via: %v; want %v", got, want)
452	}
453}
454
455// TestH2H1NoVia tests that server does not add value to existing Via
456// header field to and from backend server.
457func TestH2H1NoVia(t *testing.T) {
458	st := newServerTester([]string{"--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
459		if got, want := r.Header.Get("Via"), "foo"; got != want {
460			t.Errorf("Via: %v; want %v", got, want)
461		}
462		w.Header().Add("Via", "bar")
463	})
464	defer st.Close()
465
466	res, err := st.http2(requestParam{
467		name: "TestH2H1NoVia",
468		header: []hpack.HeaderField{
469			pair("via", "foo"),
470		},
471	})
472	if err != nil {
473		t.Fatalf("Error st.http2() = %v", err)
474	}
475	if got, want := res.header.Get("Via"), "bar"; got != want {
476		t.Errorf("Via: %v; want %v", got, want)
477	}
478}
479
480// TestH2H1HostRewrite tests that server rewrites host header field
481func TestH2H1HostRewrite(t *testing.T) {
482	st := newServerTester([]string{"--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
483		w.Header().Add("request-host", r.Host)
484	})
485	defer st.Close()
486
487	res, err := st.http2(requestParam{
488		name: "TestH2H1HostRewrite",
489	})
490	if err != nil {
491		t.Fatalf("Error st.http2() = %v", err)
492	}
493	if got, want := res.status, 200; got != want {
494		t.Errorf("status: %v; want %v", got, want)
495	}
496	if got, want := res.header.Get("request-host"), st.backendHost; got != want {
497		t.Errorf("request-host: %v; want %v", got, want)
498	}
499}
500
501// TestH2H1NoHostRewrite tests that server does not rewrite host
502// header field
503func TestH2H1NoHostRewrite(t *testing.T) {
504	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
505		w.Header().Add("request-host", r.Host)
506	})
507	defer st.Close()
508
509	res, err := st.http2(requestParam{
510		name: "TestH2H1NoHostRewrite",
511	})
512	if err != nil {
513		t.Fatalf("Error st.http2() = %v", err)
514	}
515	if got, want := res.status, 200; got != want {
516		t.Errorf("status: %v; want %v", got, want)
517	}
518	if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
519		t.Errorf("request-host: %v; want %v", got, want)
520	}
521}
522
523// TestH2H1BadRequestCL tests that server rejects request whose
524// content-length header field value does not match its request body
525// size.
526func TestH2H1BadRequestCL(t *testing.T) {
527	st := newServerTester(nil, t, noopHandler)
528	defer st.Close()
529
530	// we set content-length: 1024, but the actual request body is
531	// 3 bytes.
532	res, err := st.http2(requestParam{
533		name:   "TestH2H1BadRequestCL",
534		method: "POST",
535		header: []hpack.HeaderField{
536			pair("content-length", "1024"),
537		},
538		body: []byte("foo"),
539	})
540	if err != nil {
541		t.Fatalf("Error st.http2() = %v", err)
542	}
543
544	want := http2.ErrCodeProtocol
545	if res.errCode != want {
546		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
547	}
548}
549
550// TestH2H1BadResponseCL tests that server returns error when
551// content-length response header field value does not match its
552// response body size.
553func TestH2H1BadResponseCL(t *testing.T) {
554	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
555		// we set content-length: 1024, but only send 3 bytes.
556		w.Header().Add("Content-Length", "1024")
557		w.Write([]byte("foo"))
558	})
559	defer st.Close()
560
561	res, err := st.http2(requestParam{
562		name: "TestH2H1BadResponseCL",
563	})
564	if err != nil {
565		t.Fatalf("Error st.http2() = %v", err)
566	}
567
568	want := http2.ErrCodeProtocol
569	if res.errCode != want {
570		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
571	}
572}
573
574// TestH2H1LocationRewrite tests location header field rewriting
575// works.
576func TestH2H1LocationRewrite(t *testing.T) {
577	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
578		// TODO we cannot get st.ts's port number here.. 8443
579		// is just a place holder.  We ignore it on rewrite.
580		w.Header().Add("Location", "http://127.0.0.1:8443/p/q?a=b#fragment")
581	})
582	defer st.Close()
583
584	res, err := st.http2(requestParam{
585		name: "TestH2H1LocationRewrite",
586	})
587	if err != nil {
588		t.Fatalf("Error st.http2() = %v", err)
589	}
590
591	want := fmt.Sprintf("http://127.0.0.1:%v/p/q?a=b#fragment", serverPort)
592	if got := res.header.Get("Location"); got != want {
593		t.Errorf("Location: %v; want %v", got, want)
594	}
595}
596
597// TestH2H1ChunkedRequestBody tests that chunked request body works.
598func TestH2H1ChunkedRequestBody(t *testing.T) {
599	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
600		want := "[chunked]"
601		if got := fmt.Sprint(r.TransferEncoding); got != want {
602			t.Errorf("Transfer-Encoding: %v; want %v", got, want)
603		}
604		body, err := ioutil.ReadAll(r.Body)
605		if err != nil {
606			t.Fatalf("Error reading r.body: %v", err)
607		}
608		want = "foo"
609		if got := string(body); got != want {
610			t.Errorf("body: %v; want %v", got, want)
611		}
612	})
613	defer st.Close()
614
615	res, err := st.http2(requestParam{
616		name:   "TestH2H1ChunkedRequestBody",
617		method: "POST",
618		body:   []byte("foo"),
619	})
620	if err != nil {
621		t.Fatalf("Error st.http2() = %v", err)
622	}
623	if got, want := res.status, 200; got != want {
624		t.Errorf("status = %v; want %v", got, want)
625	}
626}
627
628// TestH2H1MultipleRequestCL tests that server rejects request with
629// multiple Content-Length request header fields.
630func TestH2H1MultipleRequestCL(t *testing.T) {
631	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
632		t.Errorf("server should not forward bad request")
633	})
634	defer st.Close()
635
636	res, err := st.http2(requestParam{
637		name: "TestH2H1MultipleRequestCL",
638		header: []hpack.HeaderField{
639			pair("content-length", "1"),
640			pair("content-length", "1"),
641		},
642	})
643	if err != nil {
644		t.Fatalf("Error st.http2() = %v", err)
645	}
646	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
647		t.Errorf("res.errCode: %v; want %v", got, want)
648	}
649}
650
651// TestH2H1InvalidRequestCL tests that server rejects request with
652// Content-Length which cannot be parsed as a number.
653func TestH2H1InvalidRequestCL(t *testing.T) {
654	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
655		t.Errorf("server should not forward bad request")
656	})
657	defer st.Close()
658
659	res, err := st.http2(requestParam{
660		name: "TestH2H1InvalidRequestCL",
661		header: []hpack.HeaderField{
662			pair("content-length", ""),
663		},
664	})
665	if err != nil {
666		t.Fatalf("Error st.http2() = %v", err)
667	}
668	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
669		t.Errorf("res.errCode: %v; want %v", got, want)
670	}
671}
672
673// // TestH2H1ConnectFailure tests that server handles the situation that
674// // connection attempt to HTTP/1 backend failed.
675// func TestH2H1ConnectFailure(t *testing.T) {
676// 	st := newServerTester(nil, t, noopHandler)
677// 	defer st.Close()
678
679// 	// shutdown backend server to simulate backend connect failure
680// 	st.ts.Close()
681
682// 	res, err := st.http2(requestParam{
683// 		name: "TestH2H1ConnectFailure",
684// 	})
685// 	if err != nil {
686// 		t.Fatalf("Error st.http2() = %v", err)
687// 	}
688// 	want := 503
689// 	if got := res.status; got != want {
690// 		t.Errorf("status: %v; want %v", got, want)
691// 	}
692// }
693
694// TestH2H1InvalidMethod tests that server rejects invalid method with
695// 501.
696func TestH2H1InvalidMethod(t *testing.T) {
697	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
698		t.Errorf("server should not forward this request")
699	})
700	defer st.Close()
701
702	res, err := st.http2(requestParam{
703		name:   "TestH2H1InvalidMethod",
704		method: "get",
705	})
706	if err != nil {
707		t.Fatalf("Error st.http2() = %v", err)
708	}
709	if got, want := res.status, 501; got != want {
710		t.Errorf("status: %v; want %v", got, want)
711	}
712}
713
714// TestH2H1BadAuthority tests that server rejects request including
715// bad characters in :authority header field.
716func TestH2H1BadAuthority(t *testing.T) {
717	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
718		t.Errorf("server should not forward this request")
719	})
720	defer st.Close()
721
722	res, err := st.http2(requestParam{
723		name:      "TestH2H1BadAuthority",
724		authority: `foo\bar`,
725	})
726	if err != nil {
727		t.Fatalf("Error st.http2() = %v", err)
728	}
729	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
730		t.Errorf("res.errCode: %v; want %v", got, want)
731	}
732}
733
734// TestH2H1BadScheme tests that server rejects request including
735// bad characters in :scheme header field.
736func TestH2H1BadScheme(t *testing.T) {
737	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
738		t.Errorf("server should not forward this request")
739	})
740	defer st.Close()
741
742	res, err := st.http2(requestParam{
743		name:   "TestH2H1BadScheme",
744		scheme: "http*",
745	})
746	if err != nil {
747		t.Fatalf("Error st.http2() = %v", err)
748	}
749	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
750		t.Errorf("res.errCode: %v; want %v", got, want)
751	}
752}
753
754// TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2
755// request is assembled into 1 when forwarding to HTTP/1 backend link.
756func TestH2H1AssembleCookies(t *testing.T) {
757	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
758		if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
759			t.Errorf("Cookie: %v; want %v", got, want)
760		}
761	})
762	defer st.Close()
763
764	res, err := st.http2(requestParam{
765		name: "TestH2H1AssembleCookies",
766		header: []hpack.HeaderField{
767			pair("cookie", "alpha"),
768			pair("cookie", "bravo"),
769			pair("cookie", "charlie"),
770		},
771	})
772	if err != nil {
773		t.Fatalf("Error st.http2() = %v", err)
774	}
775	if got, want := res.status, 200; got != want {
776		t.Errorf("status: %v; want %v", got, want)
777	}
778}
779
780// TestH2H1TETrailers tests that server accepts TE request header
781// field if it has trailers only.
782func TestH2H1TETrailers(t *testing.T) {
783	st := newServerTester(nil, t, noopHandler)
784	defer st.Close()
785
786	res, err := st.http2(requestParam{
787		name: "TestH2H1TETrailers",
788		header: []hpack.HeaderField{
789			pair("te", "trailers"),
790		},
791	})
792	if err != nil {
793		t.Fatalf("Error st.http2() = %v", err)
794	}
795	if got, want := res.status, 200; got != want {
796		t.Errorf("status: %v; want %v", got, want)
797	}
798}
799
800// TestH2H1TEGzip tests that server resets stream if TE request header
801// field contains gzip.
802func TestH2H1TEGzip(t *testing.T) {
803	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
804		t.Error("server should not forward bad request")
805	})
806	defer st.Close()
807
808	res, err := st.http2(requestParam{
809		name: "TestH2H1TEGzip",
810		header: []hpack.HeaderField{
811			pair("te", "gzip"),
812		},
813	})
814	if err != nil {
815		t.Fatalf("Error st.http2() = %v", err)
816	}
817	if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
818		t.Errorf("res.errCode = %v; want %v", res.errCode, want)
819	}
820}
821
822// TestH2H1SNI tests server's TLS SNI extension feature.  It must
823// choose appropriate certificate depending on the indicated
824// server_name from client.
825func TestH2H1SNI(t *testing.T) {
826	st := newServerTesterTLSConfig([]string{"--subcert=" + testDir + "/alt-server.key:" + testDir + "/alt-server.crt"}, t, noopHandler, &tls.Config{
827		ServerName: "alt-domain",
828	})
829	defer st.Close()
830
831	tlsConn := st.conn.(*tls.Conn)
832	connState := tlsConn.ConnectionState()
833	cert := connState.PeerCertificates[0]
834
835	if got, want := cert.Subject.CommonName, "alt-domain"; got != want {
836		t.Errorf("CommonName: %v; want %v", got, want)
837	}
838}
839
840// TestH2H1TLSXfp tests nghttpx sends x-forwarded-proto header field
841// with http value since :scheme is http, even if the frontend
842// connection is encrypted.
843func TestH2H1TLSXfp(t *testing.T) {
844	st := newServerTesterTLS(nil, t, func(w http.ResponseWriter, r *http.Request) {
845		if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
846			t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
847		}
848	})
849	defer st.Close()
850
851	res, err := st.http2(requestParam{
852		name: "TestH2H1TLSXfp",
853	})
854	if err != nil {
855		t.Fatalf("Error st.http2() = %v", err)
856	}
857	if got, want := res.status, 200; got != want {
858		t.Errorf("res.status: %v; want %v", got, want)
859	}
860}
861
862// TestH2H1ServerPush tests server push using Link header field from
863// backend server.
864func TestH2H1ServerPush(t *testing.T) {
865	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
866		// only resources marked as rel=preload are pushed
867		if !strings.HasPrefix(r.URL.Path, "/css/") {
868			w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload")
869		}
870	})
871	defer st.Close()
872
873	res, err := st.http2(requestParam{
874		name: "TestH2H1ServerPush",
875	})
876	if err != nil {
877		t.Fatalf("Error st.http2() = %v", err)
878	}
879	if got, want := res.status, 200; got != want {
880		t.Errorf("res.status: %v; want %v", got, want)
881	}
882	if got, want := len(res.pushResponse), 2; got != want {
883		t.Fatalf("len(res.pushResponse): %v; want %v", got, want)
884	}
885	mainCSS := res.pushResponse[0]
886	if got, want := mainCSS.status, 200; got != want {
887		t.Errorf("mainCSS.status: %v; want %v", got, want)
888	}
889	themeCSS := res.pushResponse[1]
890	if got, want := themeCSS.status, 200; got != want {
891		t.Errorf("themeCSS.status: %v; want %v", got, want)
892	}
893}
894
895// TestH2H1RequestTrailer tests request trailer part is forwarded to
896// backend.
897func TestH2H1RequestTrailer(t *testing.T) {
898	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
899		buf := make([]byte, 4096)
900		for {
901			_, err := r.Body.Read(buf)
902			if err == io.EOF {
903				break
904			}
905			if err != nil {
906				t.Fatalf("r.Body.Read() = %v", err)
907			}
908		}
909		if got, want := r.Trailer.Get("foo"), "bar"; got != want {
910			t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
911		}
912	})
913	defer st.Close()
914
915	res, err := st.http2(requestParam{
916		name: "TestH2H1RequestTrailer",
917		body: []byte("1"),
918		trailer: []hpack.HeaderField{
919			pair("foo", "bar"),
920		},
921	})
922	if err != nil {
923		t.Fatalf("Error st.http2() = %v", err)
924	}
925	if got, want := res.status, 200; got != want {
926		t.Errorf("res.status: %v; want %v", got, want)
927	}
928}
929
930// TestH2H1HeaderFieldBuffer tests that request with header fields
931// larger than configured buffer size is rejected.
932func TestH2H1HeaderFieldBuffer(t *testing.T) {
933	st := newServerTester([]string{"--request-header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
934		t.Fatal("execution path should not be here")
935	})
936	defer st.Close()
937
938	res, err := st.http2(requestParam{
939		name: "TestH2H1HeaderFieldBuffer",
940	})
941	if err != nil {
942		t.Fatalf("Error st.http2() = %v", err)
943	}
944	if got, want := res.status, 431; got != want {
945		t.Errorf("status: %v; want %v", got, want)
946	}
947}
948
949// TestH2H1HeaderFields tests that request with header fields more
950// than configured number is rejected.
951func TestH2H1HeaderFields(t *testing.T) {
952	st := newServerTester([]string{"--max-request-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
953		t.Fatal("execution path should not be here")
954	})
955	defer st.Close()
956
957	res, err := st.http2(requestParam{
958		name: "TestH2H1HeaderFields",
959		// we have at least 4 pseudo-header fields sent, and
960		// that ensures that buffer limit exceeds.
961	})
962	if err != nil {
963		t.Fatalf("Error st.http2() = %v", err)
964	}
965	if got, want := res.status, 431; got != want {
966		t.Errorf("status: %v; want %v", got, want)
967	}
968}
969
970// TestH2H1ReqPhaseSetHeader tests mruby request phase hook
971// modifies request header fields.
972func TestH2H1ReqPhaseSetHeader(t *testing.T) {
973	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-set-header.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
974		if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
975			t.Errorf("User-Agent = %v; want %v", got, want)
976		}
977	})
978	defer st.Close()
979
980	res, err := st.http2(requestParam{
981		name: "TestH2H1ReqPhaseSetHeader",
982	})
983	if err != nil {
984		t.Fatalf("Error st.http2() = %v", err)
985	}
986
987	if got, want := res.status, 200; got != want {
988		t.Errorf("status = %v; want %v", got, want)
989	}
990}
991
992// TestH2H1ReqPhaseReturn tests mruby request phase hook returns
993// custom response.
994func TestH2H1ReqPhaseReturn(t *testing.T) {
995	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
996		t.Fatalf("request should not be forwarded")
997	})
998	defer st.Close()
999
1000	res, err := st.http2(requestParam{
1001		name: "TestH2H1ReqPhaseReturn",
1002	})
1003	if err != nil {
1004		t.Fatalf("Error st.http2() = %v", err)
1005	}
1006
1007	if got, want := res.status, 404; got != want {
1008		t.Errorf("status = %v; want %v", got, want)
1009	}
1010
1011	hdtests := []struct {
1012		k, v string
1013	}{
1014		{"content-length", "20"},
1015		{"from", "mruby"},
1016	}
1017	for _, tt := range hdtests {
1018		if got, want := res.header.Get(tt.k), tt.v; got != want {
1019			t.Errorf("%v = %v; want %v", tt.k, got, want)
1020		}
1021	}
1022
1023	if got, want := string(res.body), "Hello World from req"; got != want {
1024		t.Errorf("body = %v; want %v", got, want)
1025	}
1026}
1027
1028// TestH2H1RespPhaseSetHeader tests mruby response phase hook modifies
1029// response header fields.
1030func TestH2H1RespPhaseSetHeader(t *testing.T) {
1031	st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler)
1032	defer st.Close()
1033
1034	res, err := st.http2(requestParam{
1035		name: "TestH2H1RespPhaseSetHeader",
1036	})
1037	if err != nil {
1038		t.Fatalf("Error st.http2() = %v", err)
1039	}
1040
1041	if got, want := res.status, 200; got != want {
1042		t.Errorf("status = %v; want %v", got, want)
1043	}
1044
1045	if got, want := res.header.Get("alpha"), "bravo"; got != want {
1046		t.Errorf("alpha = %v; want %v", got, want)
1047	}
1048}
1049
1050// TestH2H1RespPhaseReturn tests mruby response phase hook returns
1051// custom response.
1052func TestH2H1RespPhaseReturn(t *testing.T) {
1053	st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
1054	defer st.Close()
1055
1056	res, err := st.http2(requestParam{
1057		name: "TestH2H1RespPhaseReturn",
1058	})
1059	if err != nil {
1060		t.Fatalf("Error st.http2() = %v", err)
1061	}
1062
1063	if got, want := res.status, 404; got != want {
1064		t.Errorf("status = %v; want %v", got, want)
1065	}
1066
1067	hdtests := []struct {
1068		k, v string
1069	}{
1070		{"content-length", "21"},
1071		{"from", "mruby"},
1072	}
1073	for _, tt := range hdtests {
1074		if got, want := res.header.Get(tt.k), tt.v; got != want {
1075			t.Errorf("%v = %v; want %v", tt.k, got, want)
1076		}
1077	}
1078
1079	if got, want := string(res.body), "Hello World from resp"; got != want {
1080		t.Errorf("body = %v; want %v", got, want)
1081	}
1082}
1083
1084// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
1085func TestH2H1Upgrade(t *testing.T) {
1086	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
1087	defer st.Close()
1088
1089	res, err := st.http1(requestParam{
1090		name: "TestH2H1Upgrade",
1091		header: []hpack.HeaderField{
1092			pair("Connection", "Upgrade, HTTP2-Settings"),
1093			pair("Upgrade", "h2c"),
1094			pair("HTTP2-Settings", "AAMAAABkAAQAAP__"),
1095		},
1096	})
1097
1098	if err != nil {
1099		t.Fatalf("Error st.http1() = %v", err)
1100	}
1101
1102	if got, want := res.status, 101; got != want {
1103		t.Errorf("res.status: %v; want %v", got, want)
1104	}
1105
1106	res, err = st.http2(requestParam{
1107		httpUpgrade: true,
1108	})
1109	if err != nil {
1110		t.Fatalf("Error st.http2() = %v", err)
1111	}
1112	if got, want := res.status, 200; got != want {
1113		t.Errorf("res.status: %v; want %v", got, want)
1114	}
1115}
1116
1117// TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded
1118// header field includes obfuscated address even if PROXY protocol
1119// version 1 containing TCP4 entry is accepted.
1120func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) {
1121	pattern := fmt.Sprintf(`^for=_[^;]+$`)
1122	validFwd := regexp.MustCompile(pattern)
1123	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=obfuscated"}, t, func(w http.ResponseWriter, r *http.Request) {
1124		if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
1125			t.Errorf("Forwarded: %v; want pattern %v", got, pattern)
1126		}
1127	})
1128	defer st.Close()
1129
1130	st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1131
1132	res, err := st.http2(requestParam{
1133		name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated",
1134	})
1135
1136	if err != nil {
1137		t.Fatalf("Error st.http2() = %v", err)
1138	}
1139
1140	if got, want := res.status, 200; got != want {
1141		t.Errorf("res.status: %v; want %v", got, want)
1142	}
1143}
1144
1145// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
1146// containing TCP4 entry is accepted and X-Forwarded-For contains
1147// advertised src address.
1148func TestH2H1ProxyProtocolV1TCP4(t *testing.T) {
1149	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1150		if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
1151			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1152		}
1153		if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1154			t.Errorf("Forwarded: %v; want %v", got, want)
1155		}
1156	})
1157	defer st.Close()
1158
1159	st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1160
1161	res, err := st.http2(requestParam{
1162		name: "TestH2H1ProxyProtocolV1TCP4",
1163	})
1164
1165	if err != nil {
1166		t.Fatalf("Error st.http2() = %v", err)
1167	}
1168
1169	if got, want := res.status, 200; got != want {
1170		t.Errorf("res.status: %v; want %v", got, want)
1171	}
1172}
1173
1174// TestH2H1ProxyProtocolV1TCP6 tests PROXY protocol version 1
1175// containing TCP6 entry is accepted and X-Forwarded-For contains
1176// advertised src address.
1177func TestH2H1ProxyProtocolV1TCP6(t *testing.T) {
1178	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1179		if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want {
1180			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1181		}
1182		if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want {
1183			t.Errorf("Forwarded: %v; want %v", got, want)
1184		}
1185	})
1186	defer st.Close()
1187
1188	st.conn.Write([]byte("PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ::1 12345 8080\r\n"))
1189
1190	res, err := st.http2(requestParam{
1191		name: "TestH2H1ProxyProtocolV1TCP6",
1192	})
1193
1194	if err != nil {
1195		t.Fatalf("Error st.http2() = %v", err)
1196	}
1197
1198	if got, want := res.status, 200; got != want {
1199		t.Errorf("res.status: %v; want %v", got, want)
1200	}
1201}
1202
1203// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
1204// containing UNKNOWN entry is accepted.
1205func TestH2H1ProxyProtocolV1Unknown(t *testing.T) {
1206	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1207		if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant {
1208			t.Errorf("X-Forwarded-For: %v; want something else", got)
1209		}
1210		if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant {
1211			t.Errorf("Forwarded: %v; want something else", got)
1212		}
1213	})
1214	defer st.Close()
1215
1216	st.conn.Write([]byte("PROXY UNKNOWN 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1217
1218	res, err := st.http2(requestParam{
1219		name: "TestH2H1ProxyProtocolV1Unknown",
1220	})
1221
1222	if err != nil {
1223		t.Fatalf("Error st.http2() = %v", err)
1224	}
1225
1226	if got, want := res.status, 200; got != want {
1227		t.Errorf("res.status: %v; want %v", got, want)
1228	}
1229}
1230
1231// TestH2H1ProxyProtocolV1JustUnknown tests PROXY protocol version 1
1232// containing only "PROXY UNKNOWN" is accepted.
1233func TestH2H1ProxyProtocolV1JustUnknown(t *testing.T) {
1234	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler)
1235	defer st.Close()
1236
1237	st.conn.Write([]byte("PROXY UNKNOWN\r\n"))
1238
1239	res, err := st.http2(requestParam{
1240		name: "TestH2H1ProxyProtocolV1JustUnknown",
1241	})
1242
1243	if err != nil {
1244		t.Fatalf("Error st.http2() = %v", err)
1245	}
1246
1247	if got, want := res.status, 200; got != want {
1248		t.Errorf("res.status: %v; want %v", got, want)
1249	}
1250}
1251
1252// TestH2H1ProxyProtocolV1TooLongLine tests PROXY protocol version 1
1253// line longer than 107 bytes must be rejected
1254func TestH2H1ProxyProtocolV1TooLongLine(t *testing.T) {
1255	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler)
1256	defer st.Close()
1257
1258	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"))
1259
1260	_, err := st.http2(requestParam{
1261		name: "TestH2H1ProxyProtocolV1TooLongLine",
1262	})
1263
1264	if err == nil {
1265		t.Fatalf("connection was not terminated")
1266	}
1267}
1268
1269// TestH2H1ProxyProtocolV1BadLineEnd tests that PROXY protocol version
1270// 1 line ending without \r\n should be rejected.
1271func TestH2H1ProxyProtocolV1BadLineEnd(t *testing.T) {
1272	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1273	defer st.Close()
1274
1275	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080\r \n"))
1276
1277	_, err := st.http2(requestParam{
1278		name: "TestH2H1ProxyProtocolV1BadLineEnd",
1279	})
1280
1281	if err == nil {
1282		t.Fatalf("connection was not terminated")
1283	}
1284}
1285
1286// TestH2H1ProxyProtocolV1NoEnd tests that PROXY protocol version 1
1287// line containing no \r\n should be rejected.
1288func TestH2H1ProxyProtocolV1NoEnd(t *testing.T) {
1289	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1290	defer st.Close()
1291
1292	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080"))
1293
1294	_, err := st.http2(requestParam{
1295		name: "TestH2H1ProxyProtocolV1NoEnd",
1296	})
1297
1298	if err == nil {
1299		t.Fatalf("connection was not terminated")
1300	}
1301}
1302
1303// TestH2H1ProxyProtocolV1EmbeddedNULL tests that PROXY protocol
1304// version 1 line containing NULL character should be rejected.
1305func TestH2H1ProxyProtocolV1EmbeddedNULL(t *testing.T) {
1306	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1307	defer st.Close()
1308
1309	b := []byte("PROXY TCP6 ::1*foo ::1 12345 8080\r\n")
1310	b[14] = 0
1311	st.conn.Write(b)
1312
1313	_, err := st.http2(requestParam{
1314		name: "TestH2H1ProxyProtocolV1EmbeddedNULL",
1315	})
1316
1317	if err == nil {
1318		t.Fatalf("connection was not terminated")
1319	}
1320}
1321
1322// TestH2H1ProxyProtocolV1MissingSrcPort tests that PROXY protocol
1323// version 1 line without src port should be rejected.
1324func TestH2H1ProxyProtocolV1MissingSrcPort(t *testing.T) {
1325	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1326	defer st.Close()
1327
1328	st.conn.Write([]byte("PROXY TCP6 ::1 ::1  8080\r\n"))
1329
1330	_, err := st.http2(requestParam{
1331		name: "TestH2H1ProxyProtocolV1MissingSrcPort",
1332	})
1333
1334	if err == nil {
1335		t.Fatalf("connection was not terminated")
1336	}
1337}
1338
1339// TestH2H1ProxyProtocolV1MissingDstPort tests that PROXY protocol
1340// version 1 line without dst port should be rejected.
1341func TestH2H1ProxyProtocolV1MissingDstPort(t *testing.T) {
1342	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1343	defer st.Close()
1344
1345	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 \r\n"))
1346
1347	_, err := st.http2(requestParam{
1348		name: "TestH2H1ProxyProtocolV1MissingDstPort",
1349	})
1350
1351	if err == nil {
1352		t.Fatalf("connection was not terminated")
1353	}
1354}
1355
1356// TestH2H1ProxyProtocolV1InvalidSrcPort tests that PROXY protocol
1357// containing invalid src port should be rejected.
1358func TestH2H1ProxyProtocolV1InvalidSrcPort(t *testing.T) {
1359	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1360	defer st.Close()
1361
1362	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123x 8080\r\n"))
1363
1364	_, err := st.http2(requestParam{
1365		name: "TestH2H1ProxyProtocolV1InvalidSrcPort",
1366	})
1367
1368	if err == nil {
1369		t.Fatalf("connection was not terminated")
1370	}
1371}
1372
1373// TestH2H1ProxyProtocolV1InvalidDstPort tests that PROXY protocol
1374// containing invalid dst port should be rejected.
1375func TestH2H1ProxyProtocolV1InvalidDstPort(t *testing.T) {
1376	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1377	defer st.Close()
1378
1379	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123456 80x\r\n"))
1380
1381	_, err := st.http2(requestParam{
1382		name: "TestH2H1ProxyProtocolV1InvalidDstPort",
1383	})
1384
1385	if err == nil {
1386		t.Fatalf("connection was not terminated")
1387	}
1388}
1389
1390// TestH2H1ProxyProtocolV1LeadingZeroPort tests that PROXY protocol
1391// version 1 line with non zero port with leading zero should be
1392// rejected.
1393func TestH2H1ProxyProtocolV1LeadingZeroPort(t *testing.T) {
1394	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1395	defer st.Close()
1396
1397	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 03000 8080\r\n"))
1398
1399	_, err := st.http2(requestParam{
1400		name: "TestH2H1ProxyProtocolV1LeadingZeroPort",
1401	})
1402
1403	if err == nil {
1404		t.Fatalf("connection was not terminated")
1405	}
1406}
1407
1408// TestH2H1ProxyProtocolV1TooLargeSrcPort tests that PROXY protocol
1409// containing too large src port should be rejected.
1410func TestH2H1ProxyProtocolV1TooLargeSrcPort(t *testing.T) {
1411	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1412	defer st.Close()
1413
1414	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 65536 8080\r\n"))
1415
1416	_, err := st.http2(requestParam{
1417		name: "TestH2H1ProxyProtocolV1TooLargeSrcPort",
1418	})
1419
1420	if err == nil {
1421		t.Fatalf("connection was not terminated")
1422	}
1423}
1424
1425// TestH2H1ProxyProtocolV1TooLargeDstPort tests that PROXY protocol
1426// containing too large dst port should be rejected.
1427func TestH2H1ProxyProtocolV1TooLargeDstPort(t *testing.T) {
1428	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1429	defer st.Close()
1430
1431	st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 65536\r\n"))
1432
1433	_, err := st.http2(requestParam{
1434		name: "TestH2H1ProxyProtocolV1TooLargeDstPort",
1435	})
1436
1437	if err == nil {
1438		t.Fatalf("connection was not terminated")
1439	}
1440}
1441
1442// TestH2H1ProxyProtocolV1InvalidSrcAddr tests that PROXY protocol
1443// containing invalid src addr should be rejected.
1444func TestH2H1ProxyProtocolV1InvalidSrcAddr(t *testing.T) {
1445	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1446	defer st.Close()
1447
1448	st.conn.Write([]byte("PROXY TCP6 192.168.0.1 ::1 12345 8080\r\n"))
1449
1450	_, err := st.http2(requestParam{
1451		name: "TestH2H1ProxyProtocolV1InvalidSrcAddr",
1452	})
1453
1454	if err == nil {
1455		t.Fatalf("connection was not terminated")
1456	}
1457}
1458
1459// TestH2H1ProxyProtocolV1InvalidDstAddr tests that PROXY protocol
1460// containing invalid dst addr should be rejected.
1461func TestH2H1ProxyProtocolV1InvalidDstAddr(t *testing.T) {
1462	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1463	defer st.Close()
1464
1465	st.conn.Write([]byte("PROXY TCP6 ::1 192.168.0.1 12345 8080\r\n"))
1466
1467	_, err := st.http2(requestParam{
1468		name: "TestH2H1ProxyProtocolV1InvalidDstAddr",
1469	})
1470
1471	if err == nil {
1472		t.Fatalf("connection was not terminated")
1473	}
1474}
1475
1476// TestH2H1ProxyProtocolV1InvalidProtoFamily tests that PROXY protocol
1477// containing invalid protocol family should be rejected.
1478func TestH2H1ProxyProtocolV1InvalidProtoFamily(t *testing.T) {
1479	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1480	defer st.Close()
1481
1482	st.conn.Write([]byte("PROXY UNIX ::1 ::1 12345 8080\r\n"))
1483
1484	_, err := st.http2(requestParam{
1485		name: "TestH2H1ProxyProtocolV1InvalidProtoFamily",
1486	})
1487
1488	if err == nil {
1489		t.Fatalf("connection was not terminated")
1490	}
1491}
1492
1493// TestH2H1ProxyProtocolV1InvalidID tests that PROXY protocol
1494// containing invalid PROXY protocol version 1 ID should be rejected.
1495func TestH2H1ProxyProtocolV1InvalidID(t *testing.T) {
1496	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1497	defer st.Close()
1498
1499	st.conn.Write([]byte("PR0XY TCP6 ::1 ::1 12345 8080\r\n"))
1500
1501	_, err := st.http2(requestParam{
1502		name: "TestH2H1ProxyProtocolV1InvalidID",
1503	})
1504
1505	if err == nil {
1506		t.Fatalf("connection was not terminated")
1507	}
1508}
1509
1510// TestH2H1ProxyProtocolV2TCP4 tests PROXY protocol version 2
1511// containing AF_INET family is accepted and X-Forwarded-For contains
1512// advertised src address.
1513func TestH2H1ProxyProtocolV2TCP4(t *testing.T) {
1514	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1515		if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want {
1516			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1517		}
1518		if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1519			t.Errorf("Forwarded: %v; want %v", got, want)
1520		}
1521	})
1522	defer st.Close()
1523
1524	var b bytes.Buffer
1525	writeProxyProtocolV2(&b, proxyProtocolV2{
1526		command: proxyProtocolV2CommandProxy,
1527		sourceAddress: &net.TCPAddr{
1528			IP:   net.ParseIP("192.168.0.2").To4(),
1529			Port: 12345,
1530		},
1531		destinationAddress: &net.TCPAddr{
1532			IP:   net.ParseIP("192.168.0.100").To4(),
1533			Port: 8080,
1534		},
1535		additionalData: []byte("foobar"),
1536	})
1537	st.conn.Write(b.Bytes())
1538
1539	res, err := st.http2(requestParam{
1540		name: "TestH2H1ProxyProtocolV2TCP4",
1541	})
1542
1543	if err != nil {
1544		t.Fatalf("Error st.http2() = %v", err)
1545	}
1546
1547	if got, want := res.status, 200; got != want {
1548		t.Errorf("res.status: %v; want %v", got, want)
1549	}
1550}
1551
1552// TestH2H1ProxyProtocolV2TCP6 tests PROXY protocol version 2
1553// containing AF_INET6 family is accepted and X-Forwarded-For contains
1554// advertised src address.
1555func TestH2H1ProxyProtocolV2TCP6(t *testing.T) {
1556	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1557		if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want {
1558			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1559		}
1560		if got, want := r.Header.Get("Forwarded"), `for="[2001:db8:85a3::8a2e:370:7334]"`; got != want {
1561			t.Errorf("Forwarded: %v; want %v", got, want)
1562		}
1563	})
1564	defer st.Close()
1565
1566	var b bytes.Buffer
1567	writeProxyProtocolV2(&b, proxyProtocolV2{
1568		command: proxyProtocolV2CommandProxy,
1569		sourceAddress: &net.TCPAddr{
1570			IP:   net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
1571			Port: 12345,
1572		},
1573		destinationAddress: &net.TCPAddr{
1574			IP:   net.ParseIP("::1"),
1575			Port: 8080,
1576		},
1577		additionalData: []byte("foobar"),
1578	})
1579	st.conn.Write(b.Bytes())
1580
1581	res, err := st.http2(requestParam{
1582		name: "TestH2H1ProxyProtocolV2TCP6",
1583	})
1584
1585	if err != nil {
1586		t.Fatalf("Error st.http2() = %v", err)
1587	}
1588
1589	if got, want := res.status, 200; got != want {
1590		t.Errorf("res.status: %v; want %v", got, want)
1591	}
1592}
1593
1594// TestH2H1ProxyProtocolV2Local tests PROXY protocol version 2
1595// containing cmd == Local is ignored.
1596func TestH2H1ProxyProtocolV2Local(t *testing.T) {
1597	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1598		if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
1599			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1600		}
1601		if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1602			t.Errorf("Forwarded: %v; want %v", got, want)
1603		}
1604	})
1605	defer st.Close()
1606
1607	var b bytes.Buffer
1608	writeProxyProtocolV2(&b, proxyProtocolV2{
1609		command: proxyProtocolV2CommandLocal,
1610		sourceAddress: &net.TCPAddr{
1611			IP:   net.ParseIP("192.168.0.2").To4(),
1612			Port: 12345,
1613		},
1614		destinationAddress: &net.TCPAddr{
1615			IP:   net.ParseIP("192.168.0.100").To4(),
1616			Port: 8080,
1617		},
1618		additionalData: []byte("foobar"),
1619	})
1620	st.conn.Write(b.Bytes())
1621
1622	res, err := st.http2(requestParam{
1623		name: "TestH2H1ProxyProtocolV2Local",
1624	})
1625
1626	if err != nil {
1627		t.Fatalf("Error st.http2() = %v", err)
1628	}
1629
1630	if got, want := res.status, 200; got != want {
1631		t.Errorf("res.status: %v; want %v", got, want)
1632	}
1633}
1634
1635// TestH2H1ProxyProtocolV2UnknownCmd tests PROXY protocol version 2
1636// containing unknown cmd should be rejected.
1637func TestH2H1ProxyProtocolV2UnknownCmd(t *testing.T) {
1638	st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1639	defer st.Close()
1640
1641	var b bytes.Buffer
1642	writeProxyProtocolV2(&b, proxyProtocolV2{
1643		command: 0xf,
1644		sourceAddress: &net.TCPAddr{
1645			IP:   net.ParseIP("192.168.0.2").To4(),
1646			Port: 12345,
1647		},
1648		destinationAddress: &net.TCPAddr{
1649			IP:   net.ParseIP("192.168.0.100").To4(),
1650			Port: 8080,
1651		},
1652		additionalData: []byte("foobar"),
1653	})
1654	st.conn.Write(b.Bytes())
1655
1656	_, err := st.http2(requestParam{
1657		name: "TestH2H1ProxyProtocolV2UnknownCmd",
1658	})
1659
1660	if err == nil {
1661		t.Fatalf("connection was not terminated")
1662	}
1663}
1664
1665// TestH2H1ProxyProtocolV2Unix tests PROXY protocol version 2
1666// containing AF_UNIX family is ignored.
1667func TestH2H1ProxyProtocolV2Unix(t *testing.T) {
1668	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1669		if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
1670			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1671		}
1672		if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1673			t.Errorf("Forwarded: %v; want %v", got, want)
1674		}
1675	})
1676	defer st.Close()
1677
1678	var b bytes.Buffer
1679	writeProxyProtocolV2(&b, proxyProtocolV2{
1680		command: proxyProtocolV2CommandProxy,
1681		sourceAddress: &net.UnixAddr{
1682			Name: "/foo",
1683			Net:  "unix",
1684		},
1685		destinationAddress: &net.UnixAddr{
1686			Name: "/bar",
1687			Net:  "unix",
1688		},
1689		additionalData: []byte("foobar"),
1690	})
1691	st.conn.Write(b.Bytes())
1692
1693	res, err := st.http2(requestParam{
1694		name: "TestH2H1ProxyProtocolV2Unix",
1695	})
1696
1697	if err != nil {
1698		t.Fatalf("Error st.http2() = %v", err)
1699	}
1700
1701	if got, want := res.status, 200; got != want {
1702		t.Errorf("res.status: %v; want %v", got, want)
1703	}
1704}
1705
1706// TestH2H1ProxyProtocolV2Unspec tests PROXY protocol version 2
1707// containing AF_UNSPEC family is ignored.
1708func TestH2H1ProxyProtocolV2Unspec(t *testing.T) {
1709	st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) {
1710		if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want {
1711			t.Errorf("X-Forwarded-For: %v; want %v", got, want)
1712		}
1713		if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1714			t.Errorf("Forwarded: %v; want %v", got, want)
1715		}
1716	})
1717	defer st.Close()
1718
1719	var b bytes.Buffer
1720	writeProxyProtocolV2(&b, proxyProtocolV2{
1721		command:        proxyProtocolV2CommandProxy,
1722		additionalData: []byte("foobar"),
1723	})
1724	st.conn.Write(b.Bytes())
1725
1726	res, err := st.http2(requestParam{
1727		name: "TestH2H1ProxyProtocolV2Unspec",
1728	})
1729
1730	if err != nil {
1731		t.Fatalf("Error st.http2() = %v", err)
1732	}
1733
1734	if got, want := res.status, 200; got != want {
1735		t.Errorf("res.status: %v; want %v", got, want)
1736	}
1737}
1738
1739// TestH2H1ExternalDNS tests that DNS resolution using external DNS
1740// with HTTP/1 backend works.
1741func TestH2H1ExternalDNS(t *testing.T) {
1742	st := newServerTester([]string{"--external-dns"}, t, noopHandler)
1743	defer st.Close()
1744
1745	res, err := st.http2(requestParam{
1746		name: "TestH2H1ExternalDNS",
1747	})
1748	if err != nil {
1749		t.Fatalf("Error st.http2() = %v", err)
1750	}
1751
1752	if got, want := res.status, 200; got != want {
1753		t.Errorf("status = %v; want %v", got, want)
1754	}
1755}
1756
1757// TestH2H1DNS tests that DNS resolution without external DNS with
1758// HTTP/1 backend works.
1759func TestH2H1DNS(t *testing.T) {
1760	st := newServerTester([]string{"--dns"}, t, noopHandler)
1761	defer st.Close()
1762
1763	res, err := st.http2(requestParam{
1764		name: "TestH2H1DNS",
1765	})
1766	if err != nil {
1767		t.Fatalf("Error st.http2() = %v", err)
1768	}
1769
1770	if got, want := res.status, 200; got != want {
1771		t.Errorf("status = %v; want %v", got, want)
1772	}
1773}
1774
1775// TestH2H1HTTPSRedirect tests that the request to the backend which
1776// requires TLS is redirected to https URI.
1777func TestH2H1HTTPSRedirect(t *testing.T) {
1778	st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler)
1779	defer st.Close()
1780
1781	res, err := st.http2(requestParam{
1782		name: "TestH2H1HTTPSRedirect",
1783	})
1784	if err != nil {
1785		t.Fatalf("Error st.http2() = %v", err)
1786	}
1787
1788	if got, want := res.status, 308; got != want {
1789		t.Errorf("status = %v; want %v", got, want)
1790	}
1791	if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
1792		t.Errorf("location: %v; want %v", got, want)
1793	}
1794}
1795
1796// TestH2H1HTTPSRedirectPort tests that the request to the backend
1797// which requires TLS is redirected to https URI with given port.
1798func TestH2H1HTTPSRedirectPort(t *testing.T) {
1799	st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler)
1800	defer st.Close()
1801
1802	res, err := st.http2(requestParam{
1803		path: "/foo?bar",
1804		name: "TestH2H1HTTPSRedirectPort",
1805	})
1806	if err != nil {
1807		t.Fatalf("Error st.http2() = %v", err)
1808	}
1809
1810	if got, want := res.status, 308; got != want {
1811		t.Errorf("status = %v; want %v", got, want)
1812	}
1813	if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
1814		t.Errorf("location: %v; want %v", got, want)
1815	}
1816}
1817
1818// TestH2H1Code204 tests that 204 response without content-length, and
1819// transfer-encoding is valid.
1820func TestH2H1Code204(t *testing.T) {
1821	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1822		w.WriteHeader(http.StatusNoContent)
1823	})
1824	defer st.Close()
1825
1826	res, err := st.http2(requestParam{
1827		name: "TestH2H1Code204",
1828	})
1829	if err != nil {
1830		t.Fatalf("Error st.http2() = %v", err)
1831	}
1832
1833	if got, want := res.status, 204; got != want {
1834		t.Errorf("status = %v; want %v", got, want)
1835	}
1836}
1837
1838// TestH2H1Code204CL0 tests that 204 response with content-length: 0
1839// is allowed.
1840func TestH2H1Code204CL0(t *testing.T) {
1841	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1842		hj, ok := w.(http.Hijacker)
1843		if !ok {
1844			http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1845			return
1846		}
1847		conn, bufrw, err := hj.Hijack()
1848		if err != nil {
1849			http.Error(w, err.Error(), http.StatusInternalServerError)
1850			return
1851		}
1852		defer conn.Close()
1853		bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 0\r\n\r\n")
1854		bufrw.Flush()
1855	})
1856	defer st.Close()
1857
1858	res, err := st.http2(requestParam{
1859		name: "TestH2H1Code204CL0",
1860	})
1861	if err != nil {
1862		t.Fatalf("Error st.http2() = %v", err)
1863	}
1864
1865	if got, want := res.status, 204; got != want {
1866		t.Errorf("status = %v; want %v", got, want)
1867	}
1868
1869	if got, found := res.header["Content-Length"]; found {
1870		t.Errorf("Content-Length = %v, want nothing", got)
1871	}
1872}
1873
1874// TestH2H1Code204CLNonzero tests that 204 response with nonzero
1875// content-length is not allowed.
1876func TestH2H1Code204CLNonzero(t *testing.T) {
1877	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1878		hj, ok := w.(http.Hijacker)
1879		if !ok {
1880			http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1881			return
1882		}
1883		conn, bufrw, err := hj.Hijack()
1884		if err != nil {
1885			http.Error(w, err.Error(), http.StatusInternalServerError)
1886			return
1887		}
1888		defer conn.Close()
1889		bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 1\r\n\r\n")
1890		bufrw.Flush()
1891	})
1892	defer st.Close()
1893
1894	res, err := st.http2(requestParam{
1895		name: "TestH2H1Code204CLNonzero",
1896	})
1897	if err != nil {
1898		t.Fatalf("Error st.http2() = %v", err)
1899	}
1900
1901	if got, want := res.status, 502; got != want {
1902		t.Errorf("status = %v; want %v", got, want)
1903	}
1904}
1905
1906// TestH2H1Code204TE tests that 204 response with transfer-encoding is
1907// not allowed.
1908func TestH2H1Code204TE(t *testing.T) {
1909	st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1910		hj, ok := w.(http.Hijacker)
1911		if !ok {
1912			http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1913			return
1914		}
1915		conn, bufrw, err := hj.Hijack()
1916		if err != nil {
1917			http.Error(w, err.Error(), http.StatusInternalServerError)
1918			return
1919		}
1920		defer conn.Close()
1921		bufrw.WriteString("HTTP/1.1 204\r\nTransfer-Encoding: chunked\r\n\r\n")
1922		bufrw.Flush()
1923	})
1924	defer st.Close()
1925
1926	res, err := st.http2(requestParam{
1927		name: "TestH2H1Code204TE",
1928	})
1929	if err != nil {
1930		t.Fatalf("Error st.http2() = %v", err)
1931	}
1932
1933	if got, want := res.status, 502; got != want {
1934		t.Errorf("status = %v; want %v", got, want)
1935	}
1936}
1937
1938// TestH2H1AffinityCookie tests that affinity cookie is sent back in
1939// cleartext http.
1940func TestH2H1AffinityCookie(t *testing.T) {
1941	st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
1942	defer st.Close()
1943
1944	res, err := st.http2(requestParam{
1945		name: "TestH2H1AffinityCookie",
1946	})
1947	if err != nil {
1948		t.Fatalf("Error st.http2() = %v", err)
1949	}
1950
1951	if got, want := res.status, 200; got != want {
1952		t.Errorf("status = %v; want %v", got, want)
1953	}
1954
1955	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
1956	validCookie := regexp.MustCompile(pattern)
1957	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
1958		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
1959	}
1960}
1961
1962// TestH2H1AffinityCookieTLS tests that affinity cookie is sent back
1963// in https.
1964func TestH2H1AffinityCookieTLS(t *testing.T) {
1965	st := newServerTesterTLS([]string{"--affinity-cookie"}, t, noopHandler)
1966	defer st.Close()
1967
1968	res, err := st.http2(requestParam{
1969		name:   "TestH2H1AffinityCookieTLS",
1970		scheme: "https",
1971	})
1972	if err != nil {
1973		t.Fatalf("Error st.http2() = %v", err)
1974	}
1975
1976	if got, want := res.status, 200; got != want {
1977		t.Errorf("status = %v; want %v", got, want)
1978	}
1979
1980	const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
1981	validCookie := regexp.MustCompile(pattern)
1982	if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
1983		t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
1984	}
1985}
1986
1987// TestH2H1GracefulShutdown tests graceful shutdown.
1988func TestH2H1GracefulShutdown(t *testing.T) {
1989	st := newServerTester(nil, t, noopHandler)
1990	defer st.Close()
1991
1992	fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")
1993	if err := st.fr.WriteSettings(); err != nil {
1994		t.Fatalf("st.fr.WriteSettings(): %v", err)
1995	}
1996
1997	header := []hpack.HeaderField{
1998		pair(":method", "GET"),
1999		pair(":scheme", "http"),
2000		pair(":authority", st.authority),
2001		pair(":path", "/"),
2002	}
2003
2004	for _, h := range header {
2005		_ = st.enc.WriteField(h)
2006	}
2007
2008	if err := st.fr.WriteHeaders(http2.HeadersFrameParam{
2009		StreamID:      1,
2010		EndStream:     false,
2011		EndHeaders:    true,
2012		BlockFragment: st.headerBlkBuf.Bytes(),
2013	}); err != nil {
2014		t.Fatalf("st.fr.WriteHeaders(): %v", err)
2015	}
2016
2017	// send SIGQUIT signal to nghttpx to perform graceful shutdown
2018	st.cmd.Process.Signal(syscall.SIGQUIT)
2019	time.Sleep(150 * time.Millisecond)
2020
2021	// after signal, finish request body
2022	if err := st.fr.WriteData(1, true, nil); err != nil {
2023		t.Fatalf("st.fr.WriteData(): %v", err)
2024	}
2025
2026	numGoAway := 0
2027
2028	for {
2029		fr, err := st.readFrame()
2030		if err != nil {
2031			if err == io.EOF {
2032				want := 2
2033				if got := numGoAway; got != want {
2034					t.Fatalf("numGoAway: %v; want %v", got, want)
2035				}
2036				return
2037			}
2038			t.Fatalf("st.readFrame(): %v", err)
2039		}
2040		switch f := fr.(type) {
2041		case *http2.GoAwayFrame:
2042			numGoAway += 1
2043			want := http2.ErrCodeNo
2044			if got := f.ErrCode; got != want {
2045				t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want)
2046			}
2047			switch numGoAway {
2048			case 1:
2049				want := (uint32(1) << 31) - 1
2050				if got := f.LastStreamID; got != want {
2051					t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
2052				}
2053			case 2:
2054				want := uint32(1)
2055				if got := f.LastStreamID; got != want {
2056					t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
2057				}
2058			case 3:
2059				t.Fatalf("too many GOAWAYs received")
2060			}
2061		}
2062	}
2063}
2064
2065// TestH2H2MultipleResponseCL tests that server returns error if
2066// multiple Content-Length response header fields are received.
2067func TestH2H2MultipleResponseCL(t *testing.T) {
2068	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2069		w.Header().Add("content-length", "1")
2070		w.Header().Add("content-length", "1")
2071	})
2072	defer st.Close()
2073
2074	res, err := st.http2(requestParam{
2075		name: "TestH2H2MultipleResponseCL",
2076	})
2077	if err != nil {
2078		t.Fatalf("Error st.http2() = %v", err)
2079	}
2080	if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2081		t.Errorf("res.errCode: %v; want %v", got, want)
2082	}
2083}
2084
2085// TestH2H2InvalidResponseCL tests that server returns error if
2086// Content-Length response header field value cannot be parsed as a
2087// number.
2088func TestH2H2InvalidResponseCL(t *testing.T) {
2089	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2090		w.Header().Add("content-length", "")
2091	})
2092	defer st.Close()
2093
2094	res, err := st.http2(requestParam{
2095		name: "TestH2H2InvalidResponseCL",
2096	})
2097	if err != nil {
2098		t.Fatalf("Error st.http2() = %v", err)
2099	}
2100	if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2101		t.Errorf("res.errCode: %v; want %v", got, want)
2102	}
2103}
2104
2105// // TestH2H2ConnectFailure tests that server handles the situation that
2106// // connection attempt to HTTP/2 backend failed.
2107// func TestH2H2ConnectFailure(t *testing.T) {
2108// 	st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
2109// 	defer st.Close()
2110
2111// 	// simulate backend connect attempt failure
2112// 	st.ts.Close()
2113
2114// 	res, err := st.http2(requestParam{
2115// 		name: "TestH2H2ConnectFailure",
2116// 	})
2117// 	if err != nil {
2118// 		t.Fatalf("Error st.http2() = %v", err)
2119// 	}
2120// 	want := 503
2121// 	if got := res.status; got != want {
2122// 		t.Errorf("status: %v; want %v", got, want)
2123// 	}
2124// }
2125
2126// TestH2H2HostRewrite tests that server rewrites host header field
2127func TestH2H2HostRewrite(t *testing.T) {
2128	st := newServerTester([]string{"--http2-bridge", "--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
2129		w.Header().Add("request-host", r.Host)
2130	})
2131	defer st.Close()
2132
2133	res, err := st.http2(requestParam{
2134		name: "TestH2H2HostRewrite",
2135	})
2136	if err != nil {
2137		t.Fatalf("Error st.http2() = %v", err)
2138	}
2139	if got, want := res.status, 200; got != want {
2140		t.Errorf("status: %v; want %v", got, want)
2141	}
2142	if got, want := res.header.Get("request-host"), st.backendHost; got != want {
2143		t.Errorf("request-host: %v; want %v", got, want)
2144	}
2145}
2146
2147// TestH2H2NoHostRewrite tests that server does not rewrite host
2148// header field
2149func TestH2H2NoHostRewrite(t *testing.T) {
2150	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2151		w.Header().Add("request-host", r.Host)
2152	})
2153	defer st.Close()
2154
2155	res, err := st.http2(requestParam{
2156		name: "TestH2H2NoHostRewrite",
2157	})
2158	if err != nil {
2159		t.Fatalf("Error st.http2() = %v", err)
2160	}
2161	if got, want := res.status, 200; got != want {
2162		t.Errorf("status: %v; want %v", got, want)
2163	}
2164	if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
2165		t.Errorf("request-host: %v; want %v", got, want)
2166	}
2167}
2168
2169// TestH2H2TLSXfp tests nghttpx sends x-forwarded-proto header field
2170// with http value since :scheme is http, even if the frontend
2171// connection is encrypted.
2172func TestH2H2TLSXfp(t *testing.T) {
2173	st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2174		if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want {
2175			t.Errorf("x-forwarded-proto: want %v; got %v", want, got)
2176		}
2177	})
2178	defer st.Close()
2179
2180	res, err := st.http2(requestParam{
2181		name: "TestH2H2TLSXfp",
2182	})
2183	if err != nil {
2184		t.Fatalf("Error st.http2() = %v", err)
2185	}
2186	if got, want := res.status, 200; got != want {
2187		t.Errorf("res.status: %v; want %v", got, want)
2188	}
2189}
2190
2191// TestH2H2AddXfp tests that server appends :scheme to the existing
2192// x-forwarded-proto header field.
2193func TestH2H2AddXfp(t *testing.T) {
2194	st := newServerTesterTLS([]string{"--http2-bridge", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
2195		xfp := r.Header.Get("X-Forwarded-Proto")
2196		if got, want := xfp, "foo, http"; got != want {
2197			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
2198		}
2199	})
2200	defer st.Close()
2201
2202	res, err := st.http2(requestParam{
2203		name: "TestH2H2AddXfp",
2204		header: []hpack.HeaderField{
2205			pair("x-forwarded-proto", "foo"),
2206		},
2207	})
2208	if err != nil {
2209		t.Fatalf("Error st.http2() = %v", err)
2210	}
2211	if got, want := res.status, 200; got != want {
2212		t.Errorf("status = %v; want %v", got, want)
2213	}
2214}
2215
2216// TestH2H2NoAddXfp tests that server does not append :scheme to the
2217// existing x-forwarded-proto header field.
2218func TestH2H2NoAddXfp(t *testing.T) {
2219	st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
2220		xfp := r.Header.Get("X-Forwarded-Proto")
2221		if got, want := xfp, "foo"; got != want {
2222			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
2223		}
2224	})
2225	defer st.Close()
2226
2227	res, err := st.http2(requestParam{
2228		name: "TestH2H2NoAddXfp",
2229		header: []hpack.HeaderField{
2230			pair("x-forwarded-proto", "foo"),
2231		},
2232	})
2233	if err != nil {
2234		t.Fatalf("Error st.http2() = %v", err)
2235	}
2236	if got, want := res.status, 200; got != want {
2237		t.Errorf("status = %v; want %v", got, want)
2238	}
2239}
2240
2241// TestH2H2StripXfp tests that server strips incoming
2242// x-forwarded-proto header field.
2243func TestH2H2StripXfp(t *testing.T) {
2244	st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2245		xfp := r.Header.Get("X-Forwarded-Proto")
2246		if got, want := xfp, "http"; got != want {
2247			t.Errorf("X-Forwarded-Proto = %q; want %q", got, want)
2248		}
2249	})
2250	defer st.Close()
2251
2252	res, err := st.http2(requestParam{
2253		name: "TestH2H2StripXfp",
2254		header: []hpack.HeaderField{
2255			pair("x-forwarded-proto", "foo"),
2256		},
2257	})
2258	if err != nil {
2259		t.Fatalf("Error st.http2() = %v", err)
2260	}
2261	if got, want := res.status, 200; got != want {
2262		t.Errorf("status = %v; want %v", got, want)
2263	}
2264}
2265
2266// TestH2H2StripNoAddXfp tests that server strips incoming
2267// x-forwarded-proto header field, and does not add another.
2268func TestH2H2StripNoAddXfp(t *testing.T) {
2269	st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) {
2270		if got, found := r.Header["X-Forwarded-Proto"]; found {
2271			t.Errorf("X-Forwarded-Proto = %q; want nothing", got)
2272		}
2273	})
2274	defer st.Close()
2275
2276	res, err := st.http2(requestParam{
2277		name: "TestH2H2StripNoAddXfp",
2278		header: []hpack.HeaderField{
2279			pair("x-forwarded-proto", "foo"),
2280		},
2281	})
2282	if err != nil {
2283		t.Fatalf("Error st.http2() = %v", err)
2284	}
2285	if got, want := res.status, 200; got != want {
2286		t.Errorf("status = %v; want %v", got, want)
2287	}
2288}
2289
2290// TestH2H2AddXff tests that server generates X-Forwarded-For header
2291// field when forwarding request to backend.
2292func TestH2H2AddXff(t *testing.T) {
2293	st := newServerTesterTLS([]string{"--http2-bridge", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
2294		xff := r.Header.Get("X-Forwarded-For")
2295		want := "127.0.0.1"
2296		if xff != want {
2297			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2298		}
2299	})
2300	defer st.Close()
2301
2302	res, err := st.http2(requestParam{
2303		name: "TestH2H2AddXff",
2304	})
2305	if err != nil {
2306		t.Fatalf("Error st.http2() = %v", err)
2307	}
2308	if got, want := res.status, 200; got != want {
2309		t.Errorf("status = %v; want %v", got, want)
2310	}
2311}
2312
2313// TestH2H2AddXff2 tests that server appends X-Forwarded-For header
2314// field to existing one when forwarding request to backend.
2315func TestH2H2AddXff2(t *testing.T) {
2316	st := newServerTesterTLS([]string{"--http2-bridge", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
2317		xff := r.Header.Get("X-Forwarded-For")
2318		want := "host, 127.0.0.1"
2319		if xff != want {
2320			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2321		}
2322	})
2323	defer st.Close()
2324
2325	res, err := st.http2(requestParam{
2326		name: "TestH2H2AddXff2",
2327		header: []hpack.HeaderField{
2328			pair("x-forwarded-for", "host"),
2329		},
2330	})
2331	if err != nil {
2332		t.Fatalf("Error st.http2() = %v", err)
2333	}
2334	if got, want := res.status, 200; got != want {
2335		t.Errorf("status = %v; want %v", got, want)
2336	}
2337}
2338
2339// TestH2H2StripXff tests that --strip-incoming-x-forwarded-for
2340// option.
2341func TestH2H2StripXff(t *testing.T) {
2342	st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
2343		if xff, found := r.Header["X-Forwarded-For"]; found {
2344			t.Errorf("X-Forwarded-For = %v; want nothing", xff)
2345		}
2346	})
2347	defer st.Close()
2348
2349	res, err := st.http2(requestParam{
2350		name: "TestH2H2StripXff",
2351		header: []hpack.HeaderField{
2352			pair("x-forwarded-for", "host"),
2353		},
2354	})
2355	if err != nil {
2356		t.Fatalf("Error st.http2() = %v", err)
2357	}
2358	if got, want := res.status, 200; got != want {
2359		t.Errorf("status = %v; want %v", got, want)
2360	}
2361}
2362
2363// TestH2H2StripAddXff tests that --strip-incoming-x-forwarded-for and
2364// --add-x-forwarded-for options.
2365func TestH2H2StripAddXff(t *testing.T) {
2366	st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-x-forwarded-for", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) {
2367		xff := r.Header.Get("X-Forwarded-For")
2368		want := "127.0.0.1"
2369		if xff != want {
2370			t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2371		}
2372	})
2373	defer st.Close()
2374
2375	res, err := st.http2(requestParam{
2376		name: "TestH2H2StripAddXff",
2377		header: []hpack.HeaderField{
2378			pair("x-forwarded-for", "host"),
2379		},
2380	})
2381	if err != nil {
2382		t.Fatalf("Error st.http2() = %v", err)
2383	}
2384	if got, want := res.status, 200; got != want {
2385		t.Errorf("status = %v; want %v", got, want)
2386	}
2387}
2388
2389// TestH2H2AddForwarded tests that server generates Forwarded header
2390// field using static obfuscated "by" parameter.
2391func TestH2H2AddForwarded(t *testing.T) {
2392	st := newServerTesterTLS([]string{"--http2-bridge", "--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) {
2393		pattern := fmt.Sprintf(`by=_alpha;for=_[^;]+;host="127\.0\.0\.1:%v";proto=https`, serverPort)
2394		validFwd := regexp.MustCompile(pattern)
2395		if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) {
2396			t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
2397		}
2398	})
2399	defer st.Close()
2400
2401	res, err := st.http2(requestParam{
2402		name:   "TestH2H2AddForwarded",
2403		scheme: "https",
2404	})
2405	if err != nil {
2406		t.Fatalf("Error st.http2() = %v", err)
2407	}
2408	if got, want := res.status, 200; got != want {
2409		t.Errorf("status: %v; want %v", got, want)
2410	}
2411}
2412
2413// TestH2H2AddForwardedMerge tests that server generates Forwarded
2414// header field using static obfuscated "by" parameter, and
2415// existing Forwarded header field.
2416func TestH2H2AddForwardedMerge(t *testing.T) {
2417	st := newServerTesterTLS([]string{"--http2-bridge", "--add-forwarded=by,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) {
2418		want := fmt.Sprintf(`host=foo, by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
2419		if got := r.Header.Get("Forwarded"); got != want {
2420			t.Errorf("Forwarded = %v; want %v", got, want)
2421		}
2422	})
2423	defer st.Close()
2424
2425	res, err := st.http2(requestParam{
2426		name:   "TestH2H2AddForwardedMerge",
2427		scheme: "https",
2428		header: []hpack.HeaderField{
2429			pair("forwarded", "host=foo"),
2430		},
2431	})
2432	if err != nil {
2433		t.Fatalf("Error st.http2() = %v", err)
2434	}
2435	if got, want := res.status, 200; got != want {
2436		t.Errorf("status: %v; want %v", got, want)
2437	}
2438}
2439
2440// TestH2H2AddForwardedStrip tests that server generates Forwarded
2441// header field using static obfuscated "by" parameter, and
2442// existing Forwarded header field stripped.
2443func TestH2H2AddForwardedStrip(t *testing.T) {
2444	st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-forwarded", "--add-forwarded=by,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) {
2445		want := fmt.Sprintf(`by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort)
2446		if got := r.Header.Get("Forwarded"); got != want {
2447			t.Errorf("Forwarded = %v; want %v", got, want)
2448		}
2449	})
2450	defer st.Close()
2451
2452	res, err := st.http2(requestParam{
2453		name:   "TestH2H2AddForwardedStrip",
2454		scheme: "https",
2455		header: []hpack.HeaderField{
2456			pair("forwarded", "host=foo"),
2457		},
2458	})
2459	if err != nil {
2460		t.Fatalf("Error st.http2() = %v", err)
2461	}
2462	if got, want := res.status, 200; got != want {
2463		t.Errorf("status: %v; want %v", got, want)
2464	}
2465}
2466
2467// TestH2H2StripForwarded tests that server strips incoming Forwarded
2468// header field.
2469func TestH2H2StripForwarded(t *testing.T) {
2470	st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-forwarded"}, t, func(w http.ResponseWriter, r *http.Request) {
2471		if got, found := r.Header["Forwarded"]; found {
2472			t.Errorf("Forwarded = %v; want nothing", got)
2473		}
2474	})
2475	defer st.Close()
2476
2477	res, err := st.http2(requestParam{
2478		name:   "TestH2H2StripForwarded",
2479		scheme: "https",
2480		header: []hpack.HeaderField{
2481			pair("forwarded", "host=foo"),
2482		},
2483	})
2484	if err != nil {
2485		t.Fatalf("Error st.http2() = %v", err)
2486	}
2487	if got, want := res.status, 200; got != want {
2488		t.Errorf("status: %v; want %v", got, want)
2489	}
2490}
2491
2492// TestH2H2ReqPhaseReturn tests mruby request phase hook returns
2493// custom response.
2494func TestH2H2ReqPhaseReturn(t *testing.T) {
2495	st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
2496		t.Fatalf("request should not be forwarded")
2497	})
2498	defer st.Close()
2499
2500	res, err := st.http2(requestParam{
2501		name: "TestH2H2ReqPhaseReturn",
2502	})
2503	if err != nil {
2504		t.Fatalf("Error st.http2() = %v", err)
2505	}
2506
2507	if got, want := res.status, 404; got != want {
2508		t.Errorf("status = %v; want %v", got, want)
2509	}
2510
2511	hdtests := []struct {
2512		k, v string
2513	}{
2514		{"content-length", "20"},
2515		{"from", "mruby"},
2516	}
2517	for _, tt := range hdtests {
2518		if got, want := res.header.Get(tt.k), tt.v; got != want {
2519			t.Errorf("%v = %v; want %v", tt.k, got, want)
2520		}
2521	}
2522
2523	if got, want := string(res.body), "Hello World from req"; got != want {
2524		t.Errorf("body = %v; want %v", got, want)
2525	}
2526}
2527
2528// TestH2H2RespPhaseReturn tests mruby response phase hook returns
2529// custom response.
2530func TestH2H2RespPhaseReturn(t *testing.T) {
2531	st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
2532	defer st.Close()
2533
2534	res, err := st.http2(requestParam{
2535		name: "TestH2H2RespPhaseReturn",
2536	})
2537	if err != nil {
2538		t.Fatalf("Error st.http2() = %v", err)
2539	}
2540
2541	if got, want := res.status, 404; got != want {
2542		t.Errorf("status = %v; want %v", got, want)
2543	}
2544
2545	hdtests := []struct {
2546		k, v string
2547	}{
2548		{"content-length", "21"},
2549		{"from", "mruby"},
2550	}
2551	for _, tt := range hdtests {
2552		if got, want := res.header.Get(tt.k), tt.v; got != want {
2553			t.Errorf("%v = %v; want %v", tt.k, got, want)
2554		}
2555	}
2556
2557	if got, want := string(res.body), "Hello World from resp"; got != want {
2558		t.Errorf("body = %v; want %v", got, want)
2559	}
2560}
2561
2562// TestH2H2ExternalDNS tests that DNS resolution using external DNS
2563// with HTTP/2 backend works.
2564func TestH2H2ExternalDNS(t *testing.T) {
2565	st := newServerTester([]string{"--http2-bridge", "--external-dns"}, t, noopHandler)
2566	defer st.Close()
2567
2568	res, err := st.http2(requestParam{
2569		name: "TestH2H2ExternalDNS",
2570	})
2571	if err != nil {
2572		t.Fatalf("Error st.http2() = %v", err)
2573	}
2574
2575	if got, want := res.status, 200; got != want {
2576		t.Errorf("status = %v; want %v", got, want)
2577	}
2578}
2579
2580// TestH2H2DNS tests that DNS resolution without external DNS with
2581// HTTP/2 backend works.
2582func TestH2H2DNS(t *testing.T) {
2583	st := newServerTester([]string{"--http2-bridge", "--dns"}, t, noopHandler)
2584	defer st.Close()
2585
2586	res, err := st.http2(requestParam{
2587		name: "TestH2H2DNS",
2588	})
2589	if err != nil {
2590		t.Fatalf("Error st.http2() = %v", err)
2591	}
2592
2593	if got, want := res.status, 200; got != want {
2594		t.Errorf("status = %v; want %v", got, want)
2595	}
2596}
2597
2598// TestH2H2Code204 tests that 204 response without content-length, and
2599// transfer-encoding is valid.
2600func TestH2H2Code204(t *testing.T) {
2601	st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2602		w.WriteHeader(http.StatusNoContent)
2603	})
2604	defer st.Close()
2605
2606	res, err := st.http2(requestParam{
2607		name: "TestH2H2Code204",
2608	})
2609	if err != nil {
2610		t.Fatalf("Error st.http2() = %v", err)
2611	}
2612
2613	if got, want := res.status, 204; got != want {
2614		t.Errorf("status = %v; want %v", got, want)
2615	}
2616}
2617
2618// TestH2APIBackendconfig exercise backendconfig API endpoint routine
2619// for successful case.
2620func TestH2APIBackendconfig(t *testing.T) {
2621	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2622		t.Fatalf("request should not be forwarded")
2623	}, 3010)
2624	defer st.Close()
2625
2626	res, err := st.http2(requestParam{
2627		name:   "TestH2APIBackendconfig",
2628		path:   "/api/v1beta1/backendconfig",
2629		method: "PUT",
2630		body: []byte(`# comment
2631backend=127.0.0.1,3011
2632
2633`),
2634	})
2635	if err != nil {
2636		t.Fatalf("Error st.http2() = %v", err)
2637	}
2638	if got, want := res.status, 200; got != want {
2639		t.Errorf("res.status: %v; want %v", got, want)
2640	}
2641
2642	var apiResp APIResponse
2643	err = json.Unmarshal(res.body, &apiResp)
2644	if err != nil {
2645		t.Fatalf("Error unmarshaling API response: %v", err)
2646	}
2647	if got, want := apiResp.Status, "Success"; got != want {
2648		t.Errorf("apiResp.Status: %v; want %v", got, want)
2649	}
2650	if got, want := apiResp.Code, 200; got != want {
2651		t.Errorf("apiResp.Status: %v; want %v", got, want)
2652	}
2653}
2654
2655// TestH2APIBackendconfigQuery exercise backendconfig API endpoint
2656// routine with query.
2657func TestH2APIBackendconfigQuery(t *testing.T) {
2658	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2659		t.Fatalf("request should not be forwarded")
2660	}, 3010)
2661	defer st.Close()
2662
2663	res, err := st.http2(requestParam{
2664		name:   "TestH2APIBackendconfigQuery",
2665		path:   "/api/v1beta1/backendconfig?foo=bar",
2666		method: "PUT",
2667		body: []byte(`# comment
2668backend=127.0.0.1,3011
2669
2670`),
2671	})
2672	if err != nil {
2673		t.Fatalf("Error st.http2() = %v", err)
2674	}
2675	if got, want := res.status, 200; got != want {
2676		t.Errorf("res.status: %v; want %v", got, want)
2677	}
2678
2679	var apiResp APIResponse
2680	err = json.Unmarshal(res.body, &apiResp)
2681	if err != nil {
2682		t.Fatalf("Error unmarshaling API response: %v", err)
2683	}
2684	if got, want := apiResp.Status, "Success"; got != want {
2685		t.Errorf("apiResp.Status: %v; want %v", got, want)
2686	}
2687	if got, want := apiResp.Code, 200; got != want {
2688		t.Errorf("apiResp.Status: %v; want %v", got, want)
2689	}
2690}
2691
2692// TestH2APIBackendconfigBadMethod exercise backendconfig API endpoint
2693// routine with bad method.
2694func TestH2APIBackendconfigBadMethod(t *testing.T) {
2695	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2696		t.Fatalf("request should not be forwarded")
2697	}, 3010)
2698	defer st.Close()
2699
2700	res, err := st.http2(requestParam{
2701		name:   "TestH2APIBackendconfigBadMethod",
2702		path:   "/api/v1beta1/backendconfig",
2703		method: "GET",
2704		body: []byte(`# comment
2705backend=127.0.0.1,3011
2706
2707`),
2708	})
2709	if err != nil {
2710		t.Fatalf("Error st.http2() = %v", err)
2711	}
2712	if got, want := res.status, 405; got != want {
2713		t.Errorf("res.status: %v; want %v", got, want)
2714	}
2715
2716	var apiResp APIResponse
2717	err = json.Unmarshal(res.body, &apiResp)
2718	if err != nil {
2719		t.Fatalf("Error unmarshaling API response: %v", err)
2720	}
2721	if got, want := apiResp.Status, "Failure"; got != want {
2722		t.Errorf("apiResp.Status: %v; want %v", got, want)
2723	}
2724	if got, want := apiResp.Code, 405; got != want {
2725		t.Errorf("apiResp.Status: %v; want %v", got, want)
2726	}
2727}
2728
2729// TestH2APIConfigrevision tests configrevision API.
2730func TestH2APIConfigrevision(t *testing.T) {
2731	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2732		t.Fatalf("request should not be forwarded")
2733	}, 3010)
2734	defer st.Close()
2735
2736	res, err := st.http2(requestParam{
2737		name:   "TestH2APIConfigrevision",
2738		path:   "/api/v1beta1/configrevision",
2739		method: "GET",
2740	})
2741	if err != nil {
2742		t.Fatalf("Error st.http2() = %v", err)
2743	}
2744	if got, want := res.status, 200; got != want {
2745		t.Errorf("res.status: %v; want = %v", got, want)
2746	}
2747
2748	var apiResp APIResponse
2749	d := json.NewDecoder(bytes.NewBuffer(res.body))
2750	d.UseNumber()
2751	err = d.Decode(&apiResp)
2752	if err != nil {
2753		t.Fatalf("Error unmarshalling API response: %v", err)
2754	}
2755	if got, want := apiResp.Status, "Success"; got != want {
2756		t.Errorf("apiResp.Status: %v; want %v", got, want)
2757	}
2758	if got, want := apiResp.Code, 200; got != want {
2759		t.Errorf("apiResp.Status: %v; want %v", got, want)
2760	}
2761	if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want {
2762		t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want)
2763	}
2764}
2765
2766// TestH2APINotFound exercise backendconfig API endpoint routine when
2767// API endpoint is not found.
2768func TestH2APINotFound(t *testing.T) {
2769	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2770		t.Fatalf("request should not be forwarded")
2771	}, 3010)
2772	defer st.Close()
2773
2774	res, err := st.http2(requestParam{
2775		name:   "TestH2APINotFound",
2776		path:   "/api/notfound",
2777		method: "GET",
2778		body: []byte(`# comment
2779backend=127.0.0.1,3011
2780
2781`),
2782	})
2783	if err != nil {
2784		t.Fatalf("Error st.http2() = %v", err)
2785	}
2786	if got, want := res.status, 404; got != want {
2787		t.Errorf("res.status: %v; want %v", got, want)
2788	}
2789
2790	var apiResp APIResponse
2791	err = json.Unmarshal(res.body, &apiResp)
2792	if err != nil {
2793		t.Fatalf("Error unmarshaling API response: %v", err)
2794	}
2795	if got, want := apiResp.Status, "Failure"; got != want {
2796		t.Errorf("apiResp.Status: %v; want %v", got, want)
2797	}
2798	if got, want := apiResp.Code, 404; got != want {
2799		t.Errorf("apiResp.Status: %v; want %v", got, want)
2800	}
2801}
2802
2803// TestH2Healthmon tests health monitor endpoint.
2804func TestH2Healthmon(t *testing.T) {
2805	st := newServerTesterConnectPort([]string{"-f127.0.0.1,3011;healthmon;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
2806		t.Fatalf("request should not be forwarded")
2807	}, 3011)
2808	defer st.Close()
2809
2810	res, err := st.http2(requestParam{
2811		name: "TestH2Healthmon",
2812		path: "/alpha/bravo",
2813	})
2814	if err != nil {
2815		t.Fatalf("Error st.http2() = %v", err)
2816	}
2817	if got, want := res.status, 200; got != want {
2818		t.Errorf("res.status: %v; want %v", got, want)
2819	}
2820}
2821
2822// TestH2ResponseBeforeRequestEnd tests the situation where response
2823// ends before request body finishes.
2824func TestH2ResponseBeforeRequestEnd(t *testing.T) {
2825	st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
2826		t.Fatal("request should not be forwarded")
2827	})
2828	defer st.Close()
2829
2830	res, err := st.http2(requestParam{
2831		name:        "TestH2ResponseBeforeRequestEnd",
2832		noEndStream: true,
2833	})
2834	if err != nil {
2835		t.Fatalf("Error st.http2() = %v", err)
2836	}
2837	if got, want := res.status, 404; got != want {
2838		t.Errorf("res.status: %v; want %v", got, want)
2839	}
2840}
2841