8 "golang.org/x/net/http2"
9 "golang.org/x/net/http2/hpack"
21 // TestH2H1PlainGET tests whether simple HTTP/2 GET request works.
22 func TestH2H1PlainGET(t *testing.T) {
23 st := newServerTester(nil, t, noopHandler)
26 res, err := st.http2(requestParam{
27 name: "TestH2H1PlainGET",
30 t.Fatalf("Error st.http2() = %v", err)
34 if res.status != want {
35 t.Errorf("status = %v; want %v", res.status, want)
39 // TestH2H1AddXfp tests that server appends :scheme to the existing
40 // x-forwarded-proto header field.
41 func 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)
50 res, err := st.http2(requestParam{
51 name: "TestH2H1AddXfp",
52 header: []hpack.HeaderField{
53 pair("x-forwarded-proto", "foo"),
57 t.Fatalf("Error st.http2() = %v", err)
59 if got, want := res.status, 200; got != want {
60 t.Errorf("status = %v; want %v", got, want)
64 // TestH2H1NoAddXfp tests that server does not append :scheme to the
65 // existing x-forwarded-proto header field.
66 func 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)
75 res, err := st.http2(requestParam{
76 name: "TestH2H1NoAddXfp",
77 header: []hpack.HeaderField{
78 pair("x-forwarded-proto", "foo"),
82 t.Fatalf("Error st.http2() = %v", err)
84 if got, want := res.status, 200; got != want {
85 t.Errorf("status = %v; want %v", got, want)
89 // TestH2H1StripXfp tests that server strips incoming
90 // x-forwarded-proto header field.
91 func 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)
100 res, err := st.http2(requestParam{
101 name: "TestH2H1StripXfp",
102 header: []hpack.HeaderField{
103 pair("x-forwarded-proto", "foo"),
107 t.Fatalf("Error st.http2() = %v", err)
109 if got, want := res.status, 200; got != want {
110 t.Errorf("status = %v; want %v", got, want)
114 // TestH2H1StripNoAddXfp tests that server strips incoming
115 // x-forwarded-proto header field, and does not add another.
116 func 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)
124 res, err := st.http2(requestParam{
125 name: "TestH2H1StripNoAddXfp",
126 header: []hpack.HeaderField{
127 pair("x-forwarded-proto", "foo"),
131 t.Fatalf("Error st.http2() = %v", err)
133 if got, want := res.status, 200; got != want {
134 t.Errorf("status = %v; want %v", got, want)
138 // TestH2H1AddXff tests that server generates X-Forwarded-For header
139 // field when forwarding request to backend.
140 func 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")
145 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
150 res, err := st.http2(requestParam{
151 name: "TestH2H1AddXff",
154 t.Fatalf("Error st.http2() = %v", err)
156 if got, want := res.status, 200; got != want {
157 t.Errorf("status = %v; want %v", got, want)
161 // TestH2H1AddXff2 tests that server appends X-Forwarded-For header
162 // field to existing one when forwarding request to backend.
163 func 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"
168 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
173 res, err := st.http2(requestParam{
174 name: "TestH2H1AddXff2",
175 header: []hpack.HeaderField{
176 pair("x-forwarded-for", "host"),
180 t.Fatalf("Error st.http2() = %v", err)
182 if got, want := res.status, 200; got != want {
183 t.Errorf("status = %v; want %v", got, want)
187 // TestH2H1StripXff tests that --strip-incoming-x-forwarded-for
189 func 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)
197 res, err := st.http2(requestParam{
198 name: "TestH2H1StripXff",
199 header: []hpack.HeaderField{
200 pair("x-forwarded-for", "host"),
204 t.Fatalf("Error st.http2() = %v", err)
206 if got, want := res.status, 200; got != want {
207 t.Errorf("status = %v; want %v", got, want)
211 // TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and
212 // --add-x-forwarded-for options.
213 func TestH2H1StripAddXff(t *testing.T) {
215 "--strip-incoming-x-forwarded-for",
216 "--add-x-forwarded-for",
218 st := newServerTester(args, t, func(w http.ResponseWriter, r *http.Request) {
219 xff := r.Header.Get("X-Forwarded-For")
222 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
227 res, err := st.http2(requestParam{
228 name: "TestH2H1StripAddXff",
229 header: []hpack.HeaderField{
230 pair("x-forwarded-for", "host"),
234 t.Fatalf("Error st.http2() = %v", err)
236 if got, want := res.status, 200; got != want {
237 t.Errorf("status = %v; want %v", got, want)
241 // TestH2H1AddForwardedObfuscated tests that server generates
242 // Forwarded header field with obfuscated "by" and "for" parameters.
243 func 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")
249 if !validFwd.MatchString(got) {
250 t.Errorf("Forwarded = %v; want pattern %v", got, pattern)
255 res, err := st.http2(requestParam{
256 name: "TestH2H1AddForwardedObfuscated",
259 t.Fatalf("Error st.http2() = %v", err)
261 if got, want := res.status, 200; got != want {
262 t.Errorf("status: %v; want %v", got, want)
266 // TestH2H1AddForwardedByIP tests that server generates Forwarded header
267 // field with IP address in "by" parameter.
268 func 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)
278 res, err := st.http2(requestParam{
279 name: "TestH2H1AddForwardedByIP",
282 t.Fatalf("Error st.http2() = %v", err)
284 if got, want := res.status, 200; got != want {
285 t.Errorf("status: %v; want %v", got, want)
289 // TestH2H1AddForwardedForIP tests that server generates Forwarded header
290 // field with IP address in "for" parameters.
291 func 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)
300 res, err := st.http2(requestParam{
301 name: "TestH2H1AddForwardedForIP",
304 t.Fatalf("Error st.http2() = %v", err)
306 if got, want := res.status, 200; got != want {
307 t.Errorf("status: %v; want %v", got, want)
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.
314 func 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)
322 res, err := st.http2(requestParam{
323 name: "TestH2H1AddForwardedMerge",
324 header: []hpack.HeaderField{
325 pair("forwarded", "host=foo"),
329 t.Fatalf("Error st.http2() = %v", err)
331 if got, want := res.status, 200; got != want {
332 t.Errorf("status: %v; want %v", got, want)
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.
339 func 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)
347 res, err := st.http2(requestParam{
348 name: "TestH2H1AddForwardedStrip",
349 header: []hpack.HeaderField{
350 pair("forwarded", "host=foo"),
354 t.Fatalf("Error st.http2() = %v", err)
356 if got, want := res.status, 200; got != want {
357 t.Errorf("status: %v; want %v", got, want)
361 // TestH2H1StripForwarded tests that server strips incoming Forwarded
363 func 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)
371 res, err := st.http2(requestParam{
372 name: "TestH2H1StripForwarded",
373 header: []hpack.HeaderField{
374 pair("forwarded", "host=foo"),
378 t.Fatalf("Error st.http2() = %v", err)
380 if got, want := res.status, 200; got != want {
381 t.Errorf("status: %v; want %v", got, want)
385 // TestH2H1AddForwardedStatic tests that server generates Forwarded
386 // header field with the given static obfuscated string for "by"
388 func 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)
398 res, err := st.http2(requestParam{
399 name: "TestH2H1AddForwardedStatic",
402 t.Fatalf("Error st.http2() = %v", err)
404 if got, want := res.status, 200; got != want {
405 t.Errorf("status: %v; want %v", got, want)
409 // TestH2H1GenerateVia tests that server generates Via header field to and
410 // from backend server.
411 func 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)
419 res, err := st.http2(requestParam{
420 name: "TestH2H1GenerateVia",
423 t.Fatalf("Error st.http2() = %v", err)
425 if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want {
426 t.Errorf("Via: %v; want %v", got, want)
430 // TestH2H1AppendVia tests that server adds value to existing Via
431 // header field to and from backend server.
432 func 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)
437 w.Header().Add("Via", "bar")
441 res, err := st.http2(requestParam{
442 name: "TestH2H1AppendVia",
443 header: []hpack.HeaderField{
448 t.Fatalf("Error st.http2() = %v", err)
450 if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want {
451 t.Errorf("Via: %v; want %v", got, want)
455 // TestH2H1NoVia tests that server does not add value to existing Via
456 // header field to and from backend server.
457 func 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)
462 w.Header().Add("Via", "bar")
466 res, err := st.http2(requestParam{
467 name: "TestH2H1NoVia",
468 header: []hpack.HeaderField{
473 t.Fatalf("Error st.http2() = %v", err)
475 if got, want := res.header.Get("Via"), "bar"; got != want {
476 t.Errorf("Via: %v; want %v", got, want)
480 // TestH2H1HostRewrite tests that server rewrites host header field
481 func 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)
487 res, err := st.http2(requestParam{
488 name: "TestH2H1HostRewrite",
491 t.Fatalf("Error st.http2() = %v", err)
493 if got, want := res.status, 200; got != want {
494 t.Errorf("status: %v; want %v", got, want)
496 if got, want := res.header.Get("request-host"), st.backendHost; got != want {
497 t.Errorf("request-host: %v; want %v", got, want)
501 // TestH2H1NoHostRewrite tests that server does not rewrite host
503 func TestH2H1NoHostRewrite(t *testing.T) {
504 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
505 w.Header().Add("request-host", r.Host)
509 res, err := st.http2(requestParam{
510 name: "TestH2H1NoHostRewrite",
513 t.Fatalf("Error st.http2() = %v", err)
515 if got, want := res.status, 200; got != want {
516 t.Errorf("status: %v; want %v", got, want)
518 if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
519 t.Errorf("request-host: %v; want %v", got, want)
523 // TestH2H1BadRequestCL tests that server rejects request whose
524 // content-length header field value does not match its request body
526 func TestH2H1BadRequestCL(t *testing.T) {
527 st := newServerTester(nil, t, noopHandler)
530 // we set content-length: 1024, but the actual request body is
532 res, err := st.http2(requestParam{
533 name: "TestH2H1BadRequestCL",
535 header: []hpack.HeaderField{
536 pair("content-length", "1024"),
541 t.Fatalf("Error st.http2() = %v", err)
544 want := http2.ErrCodeProtocol
545 if res.errCode != want {
546 t.Errorf("res.errCode = %v; want %v", res.errCode, want)
550 // TestH2H1BadResponseCL tests that server returns error when
551 // content-length response header field value does not match its
552 // response body size.
553 func 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"))
561 res, err := st.http2(requestParam{
562 name: "TestH2H1BadResponseCL",
565 t.Fatalf("Error st.http2() = %v", err)
568 want := http2.ErrCodeProtocol
569 if res.errCode != want {
570 t.Errorf("res.errCode = %v; want %v", res.errCode, want)
574 // TestH2H1LocationRewrite tests location header field rewriting
576 func 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")
584 res, err := st.http2(requestParam{
585 name: "TestH2H1LocationRewrite",
588 t.Fatalf("Error st.http2() = %v", err)
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)
597 // TestH2H1ChunkedRequestBody tests that chunked request body works.
598 func TestH2H1ChunkedRequestBody(t *testing.T) {
599 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
601 if got := fmt.Sprint(r.TransferEncoding); got != want {
602 t.Errorf("Transfer-Encoding: %v; want %v", got, want)
604 body, err := ioutil.ReadAll(r.Body)
606 t.Fatalf("Error reading r.body: %v", err)
609 if got := string(body); got != want {
610 t.Errorf("body: %v; want %v", got, want)
615 res, err := st.http2(requestParam{
616 name: "TestH2H1ChunkedRequestBody",
621 t.Fatalf("Error st.http2() = %v", err)
623 if got, want := res.status, 200; got != want {
624 t.Errorf("status = %v; want %v", got, want)
628 // TestH2H1MultipleRequestCL tests that server rejects request with
629 // multiple Content-Length request header fields.
630 func 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")
636 res, err := st.http2(requestParam{
637 name: "TestH2H1MultipleRequestCL",
638 header: []hpack.HeaderField{
639 pair("content-length", "1"),
640 pair("content-length", "1"),
644 t.Fatalf("Error st.http2() = %v", err)
646 if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
647 t.Errorf("res.errCode: %v; want %v", got, want)
651 // TestH2H1InvalidRequestCL tests that server rejects request with
652 // Content-Length which cannot be parsed as a number.
653 func 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")
659 res, err := st.http2(requestParam{
660 name: "TestH2H1InvalidRequestCL",
661 header: []hpack.HeaderField{
662 pair("content-length", ""),
666 t.Fatalf("Error st.http2() = %v", err)
668 if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
669 t.Errorf("res.errCode: %v; want %v", got, want)
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)
679 // // shutdown backend server to simulate backend connect failure
682 // res, err := st.http2(requestParam{
683 // name: "TestH2H1ConnectFailure",
686 // t.Fatalf("Error st.http2() = %v", err)
689 // if got := res.status; got != want {
690 // t.Errorf("status: %v; want %v", got, want)
694 // TestH2H1InvalidMethod tests that server rejects invalid method with
696 func 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")
702 res, err := st.http2(requestParam{
703 name: "TestH2H1InvalidMethod",
707 t.Fatalf("Error st.http2() = %v", err)
709 if got, want := res.status, 501; got != want {
710 t.Errorf("status: %v; want %v", got, want)
714 // TestH2H1BadAuthority tests that server rejects request including
715 // bad characters in :authority header field.
716 func 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")
722 res, err := st.http2(requestParam{
723 name: "TestH2H1BadAuthority",
724 authority: `foo\bar`,
727 t.Fatalf("Error st.http2() = %v", err)
729 if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
730 t.Errorf("res.errCode: %v; want %v", got, want)
734 // TestH2H1BadScheme tests that server rejects request including
735 // bad characters in :scheme header field.
736 func 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")
742 res, err := st.http2(requestParam{
743 name: "TestH2H1BadScheme",
747 t.Fatalf("Error st.http2() = %v", err)
749 if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
750 t.Errorf("res.errCode: %v; want %v", got, want)
754 // TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2
755 // request is assembled into 1 when forwarding to HTTP/1 backend link.
756 func 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)
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"),
773 t.Fatalf("Error st.http2() = %v", err)
775 if got, want := res.status, 200; got != want {
776 t.Errorf("status: %v; want %v", got, want)
780 // TestH2H1TETrailers tests that server accepts TE request header
781 // field if it has trailers only.
782 func TestH2H1TETrailers(t *testing.T) {
783 st := newServerTester(nil, t, noopHandler)
786 res, err := st.http2(requestParam{
787 name: "TestH2H1TETrailers",
788 header: []hpack.HeaderField{
789 pair("te", "trailers"),
793 t.Fatalf("Error st.http2() = %v", err)
795 if got, want := res.status, 200; got != want {
796 t.Errorf("status: %v; want %v", got, want)
800 // TestH2H1TEGzip tests that server resets stream if TE request header
801 // field contains gzip.
802 func 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")
808 res, err := st.http2(requestParam{
809 name: "TestH2H1TEGzip",
810 header: []hpack.HeaderField{
815 t.Fatalf("Error st.http2() = %v", err)
817 if got, want := res.errCode, http2.ErrCodeProtocol; got != want {
818 t.Errorf("res.errCode = %v; want %v", res.errCode, want)
822 // TestH2H1SNI tests server's TLS SNI extension feature. It must
823 // choose appropriate certificate depending on the indicated
824 // server_name from client.
825 func 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",
831 tlsConn := st.conn.(*tls.Conn)
832 connState := tlsConn.ConnectionState()
833 cert := connState.PeerCertificates[0]
835 if got, want := cert.Subject.CommonName, "alt-domain"; got != want {
836 t.Errorf("CommonName: %v; want %v", got, want)
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.
843 func 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)
851 res, err := st.http2(requestParam{
852 name: "TestH2H1TLSXfp",
855 t.Fatalf("Error st.http2() = %v", err)
857 if got, want := res.status, 200; got != want {
858 t.Errorf("res.status: %v; want %v", got, want)
862 // TestH2H1ServerPush tests server push using Link header field from
864 func 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")
873 res, err := st.http2(requestParam{
874 name: "TestH2H1ServerPush",
877 t.Fatalf("Error st.http2() = %v", err)
879 if got, want := res.status, 200; got != want {
880 t.Errorf("res.status: %v; want %v", got, want)
882 if got, want := len(res.pushResponse), 2; got != want {
883 t.Fatalf("len(res.pushResponse): %v; want %v", got, want)
885 mainCSS := res.pushResponse[0]
886 if got, want := mainCSS.status, 200; got != want {
887 t.Errorf("mainCSS.status: %v; want %v", got, want)
889 themeCSS := res.pushResponse[1]
890 if got, want := themeCSS.status, 200; got != want {
891 t.Errorf("themeCSS.status: %v; want %v", got, want)
895 // TestH2H1RequestTrailer tests request trailer part is forwarded to
897 func TestH2H1RequestTrailer(t *testing.T) {
898 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
899 buf := make([]byte, 4096)
901 _, err := r.Body.Read(buf)
906 t.Fatalf("r.Body.Read() = %v", err)
909 if got, want := r.Trailer.Get("foo"), "bar"; got != want {
910 t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
915 res, err := st.http2(requestParam{
916 name: "TestH2H1RequestTrailer",
918 trailer: []hpack.HeaderField{
923 t.Fatalf("Error st.http2() = %v", err)
925 if got, want := res.status, 200; got != want {
926 t.Errorf("res.status: %v; want %v", got, want)
930 // TestH2H1HeaderFieldBuffer tests that request with header fields
931 // larger than configured buffer size is rejected.
932 func 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")
938 res, err := st.http2(requestParam{
939 name: "TestH2H1HeaderFieldBuffer",
942 t.Fatalf("Error st.http2() = %v", err)
944 if got, want := res.status, 431; got != want {
945 t.Errorf("status: %v; want %v", got, want)
949 // TestH2H1HeaderFields tests that request with header fields more
950 // than configured number is rejected.
951 func 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")
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.
963 t.Fatalf("Error st.http2() = %v", err)
965 if got, want := res.status, 431; got != want {
966 t.Errorf("status: %v; want %v", got, want)
970 // TestH2H1ReqPhaseSetHeader tests mruby request phase hook
971 // modifies request header fields.
972 func 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)
980 res, err := st.http2(requestParam{
981 name: "TestH2H1ReqPhaseSetHeader",
984 t.Fatalf("Error st.http2() = %v", err)
987 if got, want := res.status, 200; got != want {
988 t.Errorf("status = %v; want %v", got, want)
992 // TestH2H1ReqPhaseReturn tests mruby request phase hook returns
994 func 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")
1000 res, err := st.http2(requestParam{
1001 name: "TestH2H1ReqPhaseReturn",
1004 t.Fatalf("Error st.http2() = %v", err)
1007 if got, want := res.status, 404; got != want {
1008 t.Errorf("status = %v; want %v", got, want)
1011 hdtests := []struct {
1014 {"content-length", "20"},
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)
1023 if got, want := string(res.body), "Hello World from req"; got != want {
1024 t.Errorf("body = %v; want %v", got, want)
1028 // TestH2H1RespPhaseSetHeader tests mruby response phase hook modifies
1029 // response header fields.
1030 func TestH2H1RespPhaseSetHeader(t *testing.T) {
1031 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler)
1034 res, err := st.http2(requestParam{
1035 name: "TestH2H1RespPhaseSetHeader",
1038 t.Fatalf("Error st.http2() = %v", err)
1041 if got, want := res.status, 200; got != want {
1042 t.Errorf("status = %v; want %v", got, want)
1045 if got, want := res.header.Get("alpha"), "bravo"; got != want {
1046 t.Errorf("alpha = %v; want %v", got, want)
1050 // TestH2H1RespPhaseReturn tests mruby response phase hook returns
1052 func TestH2H1RespPhaseReturn(t *testing.T) {
1053 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
1056 res, err := st.http2(requestParam{
1057 name: "TestH2H1RespPhaseReturn",
1060 t.Fatalf("Error st.http2() = %v", err)
1063 if got, want := res.status, 404; got != want {
1064 t.Errorf("status = %v; want %v", got, want)
1067 hdtests := []struct {
1070 {"content-length", "21"},
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)
1079 if got, want := string(res.body), "Hello World from resp"; got != want {
1080 t.Errorf("body = %v; want %v", got, want)
1084 // TestH2H1Upgrade tests HTTP Upgrade to HTTP/2
1085 func TestH2H1Upgrade(t *testing.T) {
1086 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {})
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__"),
1099 t.Fatalf("Error st.http1() = %v", err)
1102 if got, want := res.status, 101; got != want {
1103 t.Errorf("res.status: %v; want %v", got, want)
1106 res, err = st.http2(requestParam{
1110 t.Fatalf("Error st.http2() = %v", err)
1112 if got, want := res.status, 200; got != want {
1113 t.Errorf("res.status: %v; want %v", got, want)
1117 // TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded
1118 // header field includes obfuscated address even if PROXY protocol
1119 // version 1 containing TCP4 entry is accepted.
1120 func 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)
1130 st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1132 res, err := st.http2(requestParam{
1133 name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated",
1137 t.Fatalf("Error st.http2() = %v", err)
1140 if got, want := res.status, 200; got != want {
1141 t.Errorf("res.status: %v; want %v", got, want)
1145 // TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1
1146 // containing TCP4 entry is accepted and X-Forwarded-For contains
1147 // advertised src address.
1148 func 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)
1153 if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1154 t.Errorf("Forwarded: %v; want %v", got, want)
1159 st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1161 res, err := st.http2(requestParam{
1162 name: "TestH2H1ProxyProtocolV1TCP4",
1166 t.Fatalf("Error st.http2() = %v", err)
1169 if got, want := res.status, 200; got != want {
1170 t.Errorf("res.status: %v; want %v", got, want)
1174 // TestH2H1ProxyProtocolV1TCP6 tests PROXY protocol version 1
1175 // containing TCP6 entry is accepted and X-Forwarded-For contains
1176 // advertised src address.
1177 func 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)
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)
1188 st.conn.Write([]byte("PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ::1 12345 8080\r\n"))
1190 res, err := st.http2(requestParam{
1191 name: "TestH2H1ProxyProtocolV1TCP6",
1195 t.Fatalf("Error st.http2() = %v", err)
1198 if got, want := res.status, 200; got != want {
1199 t.Errorf("res.status: %v; want %v", got, want)
1203 // TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1
1204 // containing UNKNOWN entry is accepted.
1205 func 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)
1210 if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant {
1211 t.Errorf("Forwarded: %v; want something else", got)
1216 st.conn.Write([]byte("PROXY UNKNOWN 192.168.0.2 192.168.0.100 12345 8080\r\n"))
1218 res, err := st.http2(requestParam{
1219 name: "TestH2H1ProxyProtocolV1Unknown",
1223 t.Fatalf("Error st.http2() = %v", err)
1226 if got, want := res.status, 200; got != want {
1227 t.Errorf("res.status: %v; want %v", got, want)
1231 // TestH2H1ProxyProtocolV1JustUnknown tests PROXY protocol version 1
1232 // containing only "PROXY UNKNOWN" is accepted.
1233 func TestH2H1ProxyProtocolV1JustUnknown(t *testing.T) {
1234 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler)
1237 st.conn.Write([]byte("PROXY UNKNOWN\r\n"))
1239 res, err := st.http2(requestParam{
1240 name: "TestH2H1ProxyProtocolV1JustUnknown",
1244 t.Fatalf("Error st.http2() = %v", err)
1247 if got, want := res.status, 200; got != want {
1248 t.Errorf("res.status: %v; want %v", got, want)
1252 // TestH2H1ProxyProtocolV1TooLongLine tests PROXY protocol version 1
1253 // line longer than 107 bytes must be rejected
1254 func TestH2H1ProxyProtocolV1TooLongLine(t *testing.T) {
1255 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler)
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"))
1260 _, err := st.http2(requestParam{
1261 name: "TestH2H1ProxyProtocolV1TooLongLine",
1265 t.Fatalf("connection was not terminated")
1269 // TestH2H1ProxyProtocolV1BadLineEnd tests that PROXY protocol version
1270 // 1 line ending without \r\n should be rejected.
1271 func TestH2H1ProxyProtocolV1BadLineEnd(t *testing.T) {
1272 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1275 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080\r \n"))
1277 _, err := st.http2(requestParam{
1278 name: "TestH2H1ProxyProtocolV1BadLineEnd",
1282 t.Fatalf("connection was not terminated")
1286 // TestH2H1ProxyProtocolV1NoEnd tests that PROXY protocol version 1
1287 // line containing no \r\n should be rejected.
1288 func TestH2H1ProxyProtocolV1NoEnd(t *testing.T) {
1289 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1292 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080"))
1294 _, err := st.http2(requestParam{
1295 name: "TestH2H1ProxyProtocolV1NoEnd",
1299 t.Fatalf("connection was not terminated")
1303 // TestH2H1ProxyProtocolV1EmbeddedNULL tests that PROXY protocol
1304 // version 1 line containing NULL character should be rejected.
1305 func TestH2H1ProxyProtocolV1EmbeddedNULL(t *testing.T) {
1306 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1309 b := []byte("PROXY TCP6 ::1*foo ::1 12345 8080\r\n")
1313 _, err := st.http2(requestParam{
1314 name: "TestH2H1ProxyProtocolV1EmbeddedNULL",
1318 t.Fatalf("connection was not terminated")
1322 // TestH2H1ProxyProtocolV1MissingSrcPort tests that PROXY protocol
1323 // version 1 line without src port should be rejected.
1324 func TestH2H1ProxyProtocolV1MissingSrcPort(t *testing.T) {
1325 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1328 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 8080\r\n"))
1330 _, err := st.http2(requestParam{
1331 name: "TestH2H1ProxyProtocolV1MissingSrcPort",
1335 t.Fatalf("connection was not terminated")
1339 // TestH2H1ProxyProtocolV1MissingDstPort tests that PROXY protocol
1340 // version 1 line without dst port should be rejected.
1341 func TestH2H1ProxyProtocolV1MissingDstPort(t *testing.T) {
1342 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1345 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 \r\n"))
1347 _, err := st.http2(requestParam{
1348 name: "TestH2H1ProxyProtocolV1MissingDstPort",
1352 t.Fatalf("connection was not terminated")
1356 // TestH2H1ProxyProtocolV1InvalidSrcPort tests that PROXY protocol
1357 // containing invalid src port should be rejected.
1358 func TestH2H1ProxyProtocolV1InvalidSrcPort(t *testing.T) {
1359 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1362 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123x 8080\r\n"))
1364 _, err := st.http2(requestParam{
1365 name: "TestH2H1ProxyProtocolV1InvalidSrcPort",
1369 t.Fatalf("connection was not terminated")
1373 // TestH2H1ProxyProtocolV1InvalidDstPort tests that PROXY protocol
1374 // containing invalid dst port should be rejected.
1375 func TestH2H1ProxyProtocolV1InvalidDstPort(t *testing.T) {
1376 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1379 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123456 80x\r\n"))
1381 _, err := st.http2(requestParam{
1382 name: "TestH2H1ProxyProtocolV1InvalidDstPort",
1386 t.Fatalf("connection was not terminated")
1390 // TestH2H1ProxyProtocolV1LeadingZeroPort tests that PROXY protocol
1391 // version 1 line with non zero port with leading zero should be
1393 func TestH2H1ProxyProtocolV1LeadingZeroPort(t *testing.T) {
1394 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1397 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 03000 8080\r\n"))
1399 _, err := st.http2(requestParam{
1400 name: "TestH2H1ProxyProtocolV1LeadingZeroPort",
1404 t.Fatalf("connection was not terminated")
1408 // TestH2H1ProxyProtocolV1TooLargeSrcPort tests that PROXY protocol
1409 // containing too large src port should be rejected.
1410 func TestH2H1ProxyProtocolV1TooLargeSrcPort(t *testing.T) {
1411 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1414 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 65536 8080\r\n"))
1416 _, err := st.http2(requestParam{
1417 name: "TestH2H1ProxyProtocolV1TooLargeSrcPort",
1421 t.Fatalf("connection was not terminated")
1425 // TestH2H1ProxyProtocolV1TooLargeDstPort tests that PROXY protocol
1426 // containing too large dst port should be rejected.
1427 func TestH2H1ProxyProtocolV1TooLargeDstPort(t *testing.T) {
1428 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1431 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 65536\r\n"))
1433 _, err := st.http2(requestParam{
1434 name: "TestH2H1ProxyProtocolV1TooLargeDstPort",
1438 t.Fatalf("connection was not terminated")
1442 // TestH2H1ProxyProtocolV1InvalidSrcAddr tests that PROXY protocol
1443 // containing invalid src addr should be rejected.
1444 func TestH2H1ProxyProtocolV1InvalidSrcAddr(t *testing.T) {
1445 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1448 st.conn.Write([]byte("PROXY TCP6 192.168.0.1 ::1 12345 8080\r\n"))
1450 _, err := st.http2(requestParam{
1451 name: "TestH2H1ProxyProtocolV1InvalidSrcAddr",
1455 t.Fatalf("connection was not terminated")
1459 // TestH2H1ProxyProtocolV1InvalidDstAddr tests that PROXY protocol
1460 // containing invalid dst addr should be rejected.
1461 func TestH2H1ProxyProtocolV1InvalidDstAddr(t *testing.T) {
1462 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1465 st.conn.Write([]byte("PROXY TCP6 ::1 192.168.0.1 12345 8080\r\n"))
1467 _, err := st.http2(requestParam{
1468 name: "TestH2H1ProxyProtocolV1InvalidDstAddr",
1472 t.Fatalf("connection was not terminated")
1476 // TestH2H1ProxyProtocolV1InvalidProtoFamily tests that PROXY protocol
1477 // containing invalid protocol family should be rejected.
1478 func TestH2H1ProxyProtocolV1InvalidProtoFamily(t *testing.T) {
1479 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1482 st.conn.Write([]byte("PROXY UNIX ::1 ::1 12345 8080\r\n"))
1484 _, err := st.http2(requestParam{
1485 name: "TestH2H1ProxyProtocolV1InvalidProtoFamily",
1489 t.Fatalf("connection was not terminated")
1493 // TestH2H1ProxyProtocolV1InvalidID tests that PROXY protocol
1494 // containing invalid PROXY protocol version 1 ID should be rejected.
1495 func TestH2H1ProxyProtocolV1InvalidID(t *testing.T) {
1496 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1499 st.conn.Write([]byte("PR0XY TCP6 ::1 ::1 12345 8080\r\n"))
1501 _, err := st.http2(requestParam{
1502 name: "TestH2H1ProxyProtocolV1InvalidID",
1506 t.Fatalf("connection was not terminated")
1510 // TestH2H1ProxyProtocolV2TCP4 tests PROXY protocol version 2
1511 // containing AF_INET family is accepted and X-Forwarded-For contains
1512 // advertised src address.
1513 func 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)
1518 if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want {
1519 t.Errorf("Forwarded: %v; want %v", got, want)
1525 writeProxyProtocolV2(&b, proxyProtocolV2{
1526 command: proxyProtocolV2CommandProxy,
1527 sourceAddress: &net.TCPAddr{
1528 IP: net.ParseIP("192.168.0.2").To4(),
1531 destinationAddress: &net.TCPAddr{
1532 IP: net.ParseIP("192.168.0.100").To4(),
1535 additionalData: []byte("foobar"),
1537 st.conn.Write(b.Bytes())
1539 res, err := st.http2(requestParam{
1540 name: "TestH2H1ProxyProtocolV2TCP4",
1544 t.Fatalf("Error st.http2() = %v", err)
1547 if got, want := res.status, 200; got != want {
1548 t.Errorf("res.status: %v; want %v", got, want)
1552 // TestH2H1ProxyProtocolV2TCP6 tests PROXY protocol version 2
1553 // containing AF_INET6 family is accepted and X-Forwarded-For contains
1554 // advertised src address.
1555 func 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)
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)
1567 writeProxyProtocolV2(&b, proxyProtocolV2{
1568 command: proxyProtocolV2CommandProxy,
1569 sourceAddress: &net.TCPAddr{
1570 IP: net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
1573 destinationAddress: &net.TCPAddr{
1574 IP: net.ParseIP("::1"),
1577 additionalData: []byte("foobar"),
1579 st.conn.Write(b.Bytes())
1581 res, err := st.http2(requestParam{
1582 name: "TestH2H1ProxyProtocolV2TCP6",
1586 t.Fatalf("Error st.http2() = %v", err)
1589 if got, want := res.status, 200; got != want {
1590 t.Errorf("res.status: %v; want %v", got, want)
1594 // TestH2H1ProxyProtocolV2Local tests PROXY protocol version 2
1595 // containing cmd == Local is ignored.
1596 func 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)
1601 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1602 t.Errorf("Forwarded: %v; want %v", got, want)
1608 writeProxyProtocolV2(&b, proxyProtocolV2{
1609 command: proxyProtocolV2CommandLocal,
1610 sourceAddress: &net.TCPAddr{
1611 IP: net.ParseIP("192.168.0.2").To4(),
1614 destinationAddress: &net.TCPAddr{
1615 IP: net.ParseIP("192.168.0.100").To4(),
1618 additionalData: []byte("foobar"),
1620 st.conn.Write(b.Bytes())
1622 res, err := st.http2(requestParam{
1623 name: "TestH2H1ProxyProtocolV2Local",
1627 t.Fatalf("Error st.http2() = %v", err)
1630 if got, want := res.status, 200; got != want {
1631 t.Errorf("res.status: %v; want %v", got, want)
1635 // TestH2H1ProxyProtocolV2UnknownCmd tests PROXY protocol version 2
1636 // containing unknown cmd should be rejected.
1637 func TestH2H1ProxyProtocolV2UnknownCmd(t *testing.T) {
1638 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler)
1642 writeProxyProtocolV2(&b, proxyProtocolV2{
1644 sourceAddress: &net.TCPAddr{
1645 IP: net.ParseIP("192.168.0.2").To4(),
1648 destinationAddress: &net.TCPAddr{
1649 IP: net.ParseIP("192.168.0.100").To4(),
1652 additionalData: []byte("foobar"),
1654 st.conn.Write(b.Bytes())
1656 _, err := st.http2(requestParam{
1657 name: "TestH2H1ProxyProtocolV2UnknownCmd",
1661 t.Fatalf("connection was not terminated")
1665 // TestH2H1ProxyProtocolV2Unix tests PROXY protocol version 2
1666 // containing AF_UNIX family is ignored.
1667 func 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)
1672 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1673 t.Errorf("Forwarded: %v; want %v", got, want)
1679 writeProxyProtocolV2(&b, proxyProtocolV2{
1680 command: proxyProtocolV2CommandProxy,
1681 sourceAddress: &net.UnixAddr{
1685 destinationAddress: &net.UnixAddr{
1689 additionalData: []byte("foobar"),
1691 st.conn.Write(b.Bytes())
1693 res, err := st.http2(requestParam{
1694 name: "TestH2H1ProxyProtocolV2Unix",
1698 t.Fatalf("Error st.http2() = %v", err)
1701 if got, want := res.status, 200; got != want {
1702 t.Errorf("res.status: %v; want %v", got, want)
1706 // TestH2H1ProxyProtocolV2Unspec tests PROXY protocol version 2
1707 // containing AF_UNSPEC family is ignored.
1708 func 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)
1713 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want {
1714 t.Errorf("Forwarded: %v; want %v", got, want)
1720 writeProxyProtocolV2(&b, proxyProtocolV2{
1721 command: proxyProtocolV2CommandProxy,
1722 additionalData: []byte("foobar"),
1724 st.conn.Write(b.Bytes())
1726 res, err := st.http2(requestParam{
1727 name: "TestH2H1ProxyProtocolV2Unspec",
1731 t.Fatalf("Error st.http2() = %v", err)
1734 if got, want := res.status, 200; got != want {
1735 t.Errorf("res.status: %v; want %v", got, want)
1739 // TestH2H1ExternalDNS tests that DNS resolution using external DNS
1740 // with HTTP/1 backend works.
1741 func TestH2H1ExternalDNS(t *testing.T) {
1742 st := newServerTester([]string{"--external-dns"}, t, noopHandler)
1745 res, err := st.http2(requestParam{
1746 name: "TestH2H1ExternalDNS",
1749 t.Fatalf("Error st.http2() = %v", err)
1752 if got, want := res.status, 200; got != want {
1753 t.Errorf("status = %v; want %v", got, want)
1757 // TestH2H1DNS tests that DNS resolution without external DNS with
1758 // HTTP/1 backend works.
1759 func TestH2H1DNS(t *testing.T) {
1760 st := newServerTester([]string{"--dns"}, t, noopHandler)
1763 res, err := st.http2(requestParam{
1764 name: "TestH2H1DNS",
1767 t.Fatalf("Error st.http2() = %v", err)
1770 if got, want := res.status, 200; got != want {
1771 t.Errorf("status = %v; want %v", got, want)
1775 // TestH2H1HTTPSRedirect tests that the request to the backend which
1776 // requires TLS is redirected to https URI.
1777 func TestH2H1HTTPSRedirect(t *testing.T) {
1778 st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler)
1781 res, err := st.http2(requestParam{
1782 name: "TestH2H1HTTPSRedirect",
1785 t.Fatalf("Error st.http2() = %v", err)
1788 if got, want := res.status, 308; got != want {
1789 t.Errorf("status = %v; want %v", got, want)
1791 if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
1792 t.Errorf("location: %v; want %v", got, want)
1796 // TestH2H1HTTPSRedirectPort tests that the request to the backend
1797 // which requires TLS is redirected to https URI with given port.
1798 func TestH2H1HTTPSRedirectPort(t *testing.T) {
1799 st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler)
1802 res, err := st.http2(requestParam{
1804 name: "TestH2H1HTTPSRedirectPort",
1807 t.Fatalf("Error st.http2() = %v", err)
1810 if got, want := res.status, 308; got != want {
1811 t.Errorf("status = %v; want %v", got, want)
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)
1818 // TestH2H1Code204 tests that 204 response without content-length, and
1819 // transfer-encoding is valid.
1820 func TestH2H1Code204(t *testing.T) {
1821 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1822 w.WriteHeader(http.StatusNoContent)
1826 res, err := st.http2(requestParam{
1827 name: "TestH2H1Code204",
1830 t.Fatalf("Error st.http2() = %v", err)
1833 if got, want := res.status, 204; got != want {
1834 t.Errorf("status = %v; want %v", got, want)
1838 // TestH2H1Code204CL0 tests that 204 response with content-length: 0
1840 func TestH2H1Code204CL0(t *testing.T) {
1841 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1842 hj, ok := w.(http.Hijacker)
1844 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1847 conn, bufrw, err := hj.Hijack()
1849 http.Error(w, err.Error(), http.StatusInternalServerError)
1853 bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 0\r\n\r\n")
1858 res, err := st.http2(requestParam{
1859 name: "TestH2H1Code204CL0",
1862 t.Fatalf("Error st.http2() = %v", err)
1865 if got, want := res.status, 204; got != want {
1866 t.Errorf("status = %v; want %v", got, want)
1869 if got, found := res.header["Content-Length"]; found {
1870 t.Errorf("Content-Length = %v, want nothing", got)
1874 // TestH2H1Code204CLNonzero tests that 204 response with nonzero
1875 // content-length is not allowed.
1876 func TestH2H1Code204CLNonzero(t *testing.T) {
1877 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1878 hj, ok := w.(http.Hijacker)
1880 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1883 conn, bufrw, err := hj.Hijack()
1885 http.Error(w, err.Error(), http.StatusInternalServerError)
1889 bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 1\r\n\r\n")
1894 res, err := st.http2(requestParam{
1895 name: "TestH2H1Code204CLNonzero",
1898 t.Fatalf("Error st.http2() = %v", err)
1901 if got, want := res.status, 502; got != want {
1902 t.Errorf("status = %v; want %v", got, want)
1906 // TestH2H1Code204TE tests that 204 response with transfer-encoding is
1908 func TestH2H1Code204TE(t *testing.T) {
1909 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1910 hj, ok := w.(http.Hijacker)
1912 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1915 conn, bufrw, err := hj.Hijack()
1917 http.Error(w, err.Error(), http.StatusInternalServerError)
1921 bufrw.WriteString("HTTP/1.1 204\r\nTransfer-Encoding: chunked\r\n\r\n")
1926 res, err := st.http2(requestParam{
1927 name: "TestH2H1Code204TE",
1930 t.Fatalf("Error st.http2() = %v", err)
1933 if got, want := res.status, 502; got != want {
1934 t.Errorf("status = %v; want %v", got, want)
1938 // TestH2H1AffinityCookie tests that affinity cookie is sent back in
1940 func TestH2H1AffinityCookie(t *testing.T) {
1941 st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
1944 res, err := st.http2(requestParam{
1945 name: "TestH2H1AffinityCookie",
1948 t.Fatalf("Error st.http2() = %v", err)
1951 if got, want := res.status, 200; got != want {
1952 t.Errorf("status = %v; want %v", got, want)
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)
1962 // TestH2H1AffinityCookieTLS tests that affinity cookie is sent back
1964 func TestH2H1AffinityCookieTLS(t *testing.T) {
1965 st := newServerTesterTLS([]string{"--affinity-cookie"}, t, noopHandler)
1968 res, err := st.http2(requestParam{
1969 name: "TestH2H1AffinityCookieTLS",
1973 t.Fatalf("Error st.http2() = %v", err)
1976 if got, want := res.status, 200; got != want {
1977 t.Errorf("status = %v; want %v", got, want)
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)
1987 // TestH2H1GracefulShutdown tests graceful shutdown.
1988 func TestH2H1GracefulShutdown(t *testing.T) {
1989 st := newServerTester(nil, t, noopHandler)
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)
1997 header := []hpack.HeaderField{
1998 pair(":method", "GET"),
1999 pair(":scheme", "http"),
2000 pair(":authority", st.authority),
2004 for _, h := range header {
2005 _ = st.enc.WriteField(h)
2008 if err := st.fr.WriteHeaders(http2.HeadersFrameParam{
2012 BlockFragment: st.headerBlkBuf.Bytes(),
2014 t.Fatalf("st.fr.WriteHeaders(): %v", err)
2017 // send SIGQUIT signal to nghttpx to perform graceful shutdown
2018 st.cmd.Process.Signal(syscall.SIGQUIT)
2019 time.Sleep(150 * time.Millisecond)
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)
2029 fr, err := st.readFrame()
2033 if got := numGoAway; got != want {
2034 t.Fatalf("numGoAway: %v; want %v", got, want)
2038 t.Fatalf("st.readFrame(): %v", err)
2040 switch f := fr.(type) {
2041 case *http2.GoAwayFrame:
2043 want := http2.ErrCodeNo
2044 if got := f.ErrCode; got != want {
2045 t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want)
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)
2055 if got := f.LastStreamID; got != want {
2056 t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want)
2059 t.Fatalf("too many GOAWAYs received")
2065 // TestH2H2MultipleResponseCL tests that server returns error if
2066 // multiple Content-Length response header fields are received.
2067 func 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")
2074 res, err := st.http2(requestParam{
2075 name: "TestH2H2MultipleResponseCL",
2078 t.Fatalf("Error st.http2() = %v", err)
2080 if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2081 t.Errorf("res.errCode: %v; want %v", got, want)
2085 // TestH2H2InvalidResponseCL tests that server returns error if
2086 // Content-Length response header field value cannot be parsed as a
2088 func TestH2H2InvalidResponseCL(t *testing.T) {
2089 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2090 w.Header().Add("content-length", "")
2094 res, err := st.http2(requestParam{
2095 name: "TestH2H2InvalidResponseCL",
2098 t.Fatalf("Error st.http2() = %v", err)
2100 if got, want := res.errCode, http2.ErrCodeInternal; got != want {
2101 t.Errorf("res.errCode: %v; want %v", got, want)
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)
2111 // // simulate backend connect attempt failure
2114 // res, err := st.http2(requestParam{
2115 // name: "TestH2H2ConnectFailure",
2118 // t.Fatalf("Error st.http2() = %v", err)
2121 // if got := res.status; got != want {
2122 // t.Errorf("status: %v; want %v", got, want)
2126 // TestH2H2HostRewrite tests that server rewrites host header field
2127 func 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)
2133 res, err := st.http2(requestParam{
2134 name: "TestH2H2HostRewrite",
2137 t.Fatalf("Error st.http2() = %v", err)
2139 if got, want := res.status, 200; got != want {
2140 t.Errorf("status: %v; want %v", got, want)
2142 if got, want := res.header.Get("request-host"), st.backendHost; got != want {
2143 t.Errorf("request-host: %v; want %v", got, want)
2147 // TestH2H2NoHostRewrite tests that server does not rewrite host
2149 func 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)
2155 res, err := st.http2(requestParam{
2156 name: "TestH2H2NoHostRewrite",
2159 t.Fatalf("Error st.http2() = %v", err)
2161 if got, want := res.status, 200; got != want {
2162 t.Errorf("status: %v; want %v", got, want)
2164 if got, want := res.header.Get("request-host"), st.frontendHost; got != want {
2165 t.Errorf("request-host: %v; want %v", got, want)
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.
2172 func 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)
2180 res, err := st.http2(requestParam{
2181 name: "TestH2H2TLSXfp",
2184 t.Fatalf("Error st.http2() = %v", err)
2186 if got, want := res.status, 200; got != want {
2187 t.Errorf("res.status: %v; want %v", got, want)
2191 // TestH2H2AddXfp tests that server appends :scheme to the existing
2192 // x-forwarded-proto header field.
2193 func 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)
2202 res, err := st.http2(requestParam{
2203 name: "TestH2H2AddXfp",
2204 header: []hpack.HeaderField{
2205 pair("x-forwarded-proto", "foo"),
2209 t.Fatalf("Error st.http2() = %v", err)
2211 if got, want := res.status, 200; got != want {
2212 t.Errorf("status = %v; want %v", got, want)
2216 // TestH2H2NoAddXfp tests that server does not append :scheme to the
2217 // existing x-forwarded-proto header field.
2218 func 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)
2227 res, err := st.http2(requestParam{
2228 name: "TestH2H2NoAddXfp",
2229 header: []hpack.HeaderField{
2230 pair("x-forwarded-proto", "foo"),
2234 t.Fatalf("Error st.http2() = %v", err)
2236 if got, want := res.status, 200; got != want {
2237 t.Errorf("status = %v; want %v", got, want)
2241 // TestH2H2StripXfp tests that server strips incoming
2242 // x-forwarded-proto header field.
2243 func 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)
2252 res, err := st.http2(requestParam{
2253 name: "TestH2H2StripXfp",
2254 header: []hpack.HeaderField{
2255 pair("x-forwarded-proto", "foo"),
2259 t.Fatalf("Error st.http2() = %v", err)
2261 if got, want := res.status, 200; got != want {
2262 t.Errorf("status = %v; want %v", got, want)
2266 // TestH2H2StripNoAddXfp tests that server strips incoming
2267 // x-forwarded-proto header field, and does not add another.
2268 func 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)
2276 res, err := st.http2(requestParam{
2277 name: "TestH2H2StripNoAddXfp",
2278 header: []hpack.HeaderField{
2279 pair("x-forwarded-proto", "foo"),
2283 t.Fatalf("Error st.http2() = %v", err)
2285 if got, want := res.status, 200; got != want {
2286 t.Errorf("status = %v; want %v", got, want)
2290 // TestH2H2AddXff tests that server generates X-Forwarded-For header
2291 // field when forwarding request to backend.
2292 func 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")
2297 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2302 res, err := st.http2(requestParam{
2303 name: "TestH2H2AddXff",
2306 t.Fatalf("Error st.http2() = %v", err)
2308 if got, want := res.status, 200; got != want {
2309 t.Errorf("status = %v; want %v", got, want)
2313 // TestH2H2AddXff2 tests that server appends X-Forwarded-For header
2314 // field to existing one when forwarding request to backend.
2315 func 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"
2320 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2325 res, err := st.http2(requestParam{
2326 name: "TestH2H2AddXff2",
2327 header: []hpack.HeaderField{
2328 pair("x-forwarded-for", "host"),
2332 t.Fatalf("Error st.http2() = %v", err)
2334 if got, want := res.status, 200; got != want {
2335 t.Errorf("status = %v; want %v", got, want)
2339 // TestH2H2StripXff tests that --strip-incoming-x-forwarded-for
2341 func 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)
2349 res, err := st.http2(requestParam{
2350 name: "TestH2H2StripXff",
2351 header: []hpack.HeaderField{
2352 pair("x-forwarded-for", "host"),
2356 t.Fatalf("Error st.http2() = %v", err)
2358 if got, want := res.status, 200; got != want {
2359 t.Errorf("status = %v; want %v", got, want)
2363 // TestH2H2StripAddXff tests that --strip-incoming-x-forwarded-for and
2364 // --add-x-forwarded-for options.
2365 func 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")
2370 t.Errorf("X-Forwarded-For = %v; want %v", xff, want)
2375 res, err := st.http2(requestParam{
2376 name: "TestH2H2StripAddXff",
2377 header: []hpack.HeaderField{
2378 pair("x-forwarded-for", "host"),
2382 t.Fatalf("Error st.http2() = %v", err)
2384 if got, want := res.status, 200; got != want {
2385 t.Errorf("status = %v; want %v", got, want)
2389 // TestH2H2AddForwarded tests that server generates Forwarded header
2390 // field using static obfuscated "by" parameter.
2391 func 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)
2401 res, err := st.http2(requestParam{
2402 name: "TestH2H2AddForwarded",
2406 t.Fatalf("Error st.http2() = %v", err)
2408 if got, want := res.status, 200; got != want {
2409 t.Errorf("status: %v; want %v", got, want)
2413 // TestH2H2AddForwardedMerge tests that server generates Forwarded
2414 // header field using static obfuscated "by" parameter, and
2415 // existing Forwarded header field.
2416 func 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)
2425 res, err := st.http2(requestParam{
2426 name: "TestH2H2AddForwardedMerge",
2428 header: []hpack.HeaderField{
2429 pair("forwarded", "host=foo"),
2433 t.Fatalf("Error st.http2() = %v", err)
2435 if got, want := res.status, 200; got != want {
2436 t.Errorf("status: %v; want %v", got, want)
2440 // TestH2H2AddForwardedStrip tests that server generates Forwarded
2441 // header field using static obfuscated "by" parameter, and
2442 // existing Forwarded header field stripped.
2443 func 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)
2452 res, err := st.http2(requestParam{
2453 name: "TestH2H2AddForwardedStrip",
2455 header: []hpack.HeaderField{
2456 pair("forwarded", "host=foo"),
2460 t.Fatalf("Error st.http2() = %v", err)
2462 if got, want := res.status, 200; got != want {
2463 t.Errorf("status: %v; want %v", got, want)
2467 // TestH2H2StripForwarded tests that server strips incoming Forwarded
2469 func 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)
2477 res, err := st.http2(requestParam{
2478 name: "TestH2H2StripForwarded",
2480 header: []hpack.HeaderField{
2481 pair("forwarded", "host=foo"),
2485 t.Fatalf("Error st.http2() = %v", err)
2487 if got, want := res.status, 200; got != want {
2488 t.Errorf("status: %v; want %v", got, want)
2492 // TestH2H2ReqPhaseReturn tests mruby request phase hook returns
2494 func 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")
2500 res, err := st.http2(requestParam{
2501 name: "TestH2H2ReqPhaseReturn",
2504 t.Fatalf("Error st.http2() = %v", err)
2507 if got, want := res.status, 404; got != want {
2508 t.Errorf("status = %v; want %v", got, want)
2511 hdtests := []struct {
2514 {"content-length", "20"},
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)
2523 if got, want := string(res.body), "Hello World from req"; got != want {
2524 t.Errorf("body = %v; want %v", got, want)
2528 // TestH2H2RespPhaseReturn tests mruby response phase hook returns
2530 func TestH2H2RespPhaseReturn(t *testing.T) {
2531 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
2534 res, err := st.http2(requestParam{
2535 name: "TestH2H2RespPhaseReturn",
2538 t.Fatalf("Error st.http2() = %v", err)
2541 if got, want := res.status, 404; got != want {
2542 t.Errorf("status = %v; want %v", got, want)
2545 hdtests := []struct {
2548 {"content-length", "21"},
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)
2557 if got, want := string(res.body), "Hello World from resp"; got != want {
2558 t.Errorf("body = %v; want %v", got, want)
2562 // TestH2H2ExternalDNS tests that DNS resolution using external DNS
2563 // with HTTP/2 backend works.
2564 func TestH2H2ExternalDNS(t *testing.T) {
2565 st := newServerTester([]string{"--http2-bridge", "--external-dns"}, t, noopHandler)
2568 res, err := st.http2(requestParam{
2569 name: "TestH2H2ExternalDNS",
2572 t.Fatalf("Error st.http2() = %v", err)
2575 if got, want := res.status, 200; got != want {
2576 t.Errorf("status = %v; want %v", got, want)
2580 // TestH2H2DNS tests that DNS resolution without external DNS with
2581 // HTTP/2 backend works.
2582 func TestH2H2DNS(t *testing.T) {
2583 st := newServerTester([]string{"--http2-bridge", "--dns"}, t, noopHandler)
2586 res, err := st.http2(requestParam{
2587 name: "TestH2H2DNS",
2590 t.Fatalf("Error st.http2() = %v", err)
2593 if got, want := res.status, 200; got != want {
2594 t.Errorf("status = %v; want %v", got, want)
2598 // TestH2H2Code204 tests that 204 response without content-length, and
2599 // transfer-encoding is valid.
2600 func TestH2H2Code204(t *testing.T) {
2601 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
2602 w.WriteHeader(http.StatusNoContent)
2606 res, err := st.http2(requestParam{
2607 name: "TestH2H2Code204",
2610 t.Fatalf("Error st.http2() = %v", err)
2613 if got, want := res.status, 204; got != want {
2614 t.Errorf("status = %v; want %v", got, want)
2618 // TestH2APIBackendconfig exercise backendconfig API endpoint routine
2619 // for successful case.
2620 func 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")
2626 res, err := st.http2(requestParam{
2627 name: "TestH2APIBackendconfig",
2628 path: "/api/v1beta1/backendconfig",
2630 body: []byte(`# comment
2631 backend=127.0.0.1,3011
2636 t.Fatalf("Error st.http2() = %v", err)
2638 if got, want := res.status, 200; got != want {
2639 t.Errorf("res.status: %v; want %v", got, want)
2642 var apiResp APIResponse
2643 err = json.Unmarshal(res.body, &apiResp)
2645 t.Fatalf("Error unmarshaling API response: %v", err)
2647 if got, want := apiResp.Status, "Success"; got != want {
2648 t.Errorf("apiResp.Status: %v; want %v", got, want)
2650 if got, want := apiResp.Code, 200; got != want {
2651 t.Errorf("apiResp.Status: %v; want %v", got, want)
2655 // TestH2APIBackendconfigQuery exercise backendconfig API endpoint
2656 // routine with query.
2657 func 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")
2663 res, err := st.http2(requestParam{
2664 name: "TestH2APIBackendconfigQuery",
2665 path: "/api/v1beta1/backendconfig?foo=bar",
2667 body: []byte(`# comment
2668 backend=127.0.0.1,3011
2673 t.Fatalf("Error st.http2() = %v", err)
2675 if got, want := res.status, 200; got != want {
2676 t.Errorf("res.status: %v; want %v", got, want)
2679 var apiResp APIResponse
2680 err = json.Unmarshal(res.body, &apiResp)
2682 t.Fatalf("Error unmarshaling API response: %v", err)
2684 if got, want := apiResp.Status, "Success"; got != want {
2685 t.Errorf("apiResp.Status: %v; want %v", got, want)
2687 if got, want := apiResp.Code, 200; got != want {
2688 t.Errorf("apiResp.Status: %v; want %v", got, want)
2692 // TestH2APIBackendconfigBadMethod exercise backendconfig API endpoint
2693 // routine with bad method.
2694 func 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")
2700 res, err := st.http2(requestParam{
2701 name: "TestH2APIBackendconfigBadMethod",
2702 path: "/api/v1beta1/backendconfig",
2704 body: []byte(`# comment
2705 backend=127.0.0.1,3011
2710 t.Fatalf("Error st.http2() = %v", err)
2712 if got, want := res.status, 405; got != want {
2713 t.Errorf("res.status: %v; want %v", got, want)
2716 var apiResp APIResponse
2717 err = json.Unmarshal(res.body, &apiResp)
2719 t.Fatalf("Error unmarshaling API response: %v", err)
2721 if got, want := apiResp.Status, "Failure"; got != want {
2722 t.Errorf("apiResp.Status: %v; want %v", got, want)
2724 if got, want := apiResp.Code, 405; got != want {
2725 t.Errorf("apiResp.Status: %v; want %v", got, want)
2729 // TestH2APIConfigrevision tests configrevision API.
2730 func 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")
2736 res, err := st.http2(requestParam{
2737 name: "TestH2APIConfigrevision",
2738 path: "/api/v1beta1/configrevision",
2742 t.Fatalf("Error st.http2() = %v", err)
2744 if got, want := res.status, 200; got != want {
2745 t.Errorf("res.status: %v; want = %v", got, want)
2748 var apiResp APIResponse
2749 d := json.NewDecoder(bytes.NewBuffer(res.body))
2751 err = d.Decode(&apiResp)
2753 t.Fatalf("Error unmarshalling API response: %v", err)
2755 if got, want := apiResp.Status, "Success"; got != want {
2756 t.Errorf("apiResp.Status: %v; want %v", got, want)
2758 if got, want := apiResp.Code, 200; got != want {
2759 t.Errorf("apiResp.Status: %v; want %v", got, want)
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)
2766 // TestH2APINotFound exercise backendconfig API endpoint routine when
2767 // API endpoint is not found.
2768 func 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")
2774 res, err := st.http2(requestParam{
2775 name: "TestH2APINotFound",
2776 path: "/api/notfound",
2778 body: []byte(`# comment
2779 backend=127.0.0.1,3011
2784 t.Fatalf("Error st.http2() = %v", err)
2786 if got, want := res.status, 404; got != want {
2787 t.Errorf("res.status: %v; want %v", got, want)
2790 var apiResp APIResponse
2791 err = json.Unmarshal(res.body, &apiResp)
2793 t.Fatalf("Error unmarshaling API response: %v", err)
2795 if got, want := apiResp.Status, "Failure"; got != want {
2796 t.Errorf("apiResp.Status: %v; want %v", got, want)
2798 if got, want := apiResp.Code, 404; got != want {
2799 t.Errorf("apiResp.Status: %v; want %v", got, want)
2803 // TestH2Healthmon tests health monitor endpoint.
2804 func 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")
2810 res, err := st.http2(requestParam{
2811 name: "TestH2Healthmon",
2812 path: "/alpha/bravo",
2815 t.Fatalf("Error st.http2() = %v", err)
2817 if got, want := res.status, 200; got != want {
2818 t.Errorf("res.status: %v; want %v", got, want)
2822 // TestH2ResponseBeforeRequestEnd tests the situation where response
2823 // ends before request body finishes.
2824 func 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")
2830 res, err := st.http2(requestParam{
2831 name: "TestH2ResponseBeforeRequestEnd",
2835 t.Fatalf("Error st.http2() = %v", err)
2837 if got, want := res.status, 404; got != want {
2838 t.Errorf("res.status: %v; want %v", got, want)