8 "golang.org/x/net/http2/hpack"
9 "golang.org/x/net/websocket"
18 // TestH1H1PlainGET tests whether simple HTTP/1 GET request works.
19 func TestH1H1PlainGET(t *testing.T) {
20 st := newServerTester(nil, t, noopHandler)
23 res, err := st.http1(requestParam{
24 name: "TestH1H1PlainGET",
27 t.Fatalf("Error st.http1() = %v", err)
31 if got := res.status; got != want {
32 t.Errorf("status = %v; want %v", got, want)
36 // TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with
37 // Connetion: close request header field works.
38 func TestH1H1PlainGETClose(t *testing.T) {
39 st := newServerTester(nil, t, noopHandler)
42 res, err := st.http1(requestParam{
43 name: "TestH1H1PlainGETClose",
44 header: []hpack.HeaderField{
45 pair("Connection", "close"),
49 t.Fatalf("Error st.http1() = %v", err)
53 if got := res.status; got != want {
54 t.Errorf("status = %v; want %v", got, want)
58 // TestH1H1InvalidMethod tests that server rejects invalid method with
60 func TestH1H1InvalidMethod(t *testing.T) {
61 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
62 t.Errorf("server should not forward this request")
66 res, err := st.http1(requestParam{
67 name: "TestH1H1InvalidMethod",
71 t.Fatalf("Error st.http1() = %v", err)
74 if got, want := res.status, 501; got != want {
75 t.Errorf("status = %v; want %v", got, want)
79 // TestH1H1MultipleRequestCL tests that server rejects request which
80 // contains multiple Content-Length header fields.
81 func TestH1H1MultipleRequestCL(t *testing.T) {
82 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
83 t.Errorf("server should not forward bad request")
87 if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1
89 Test-Case: TestH1H1MultipleRequestCL
93 `, st.authority)); err != nil {
94 t.Fatalf("Error io.WriteString() = %v", err)
97 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
99 t.Fatalf("Error http.ReadResponse() = %v", err)
103 if got := resp.StatusCode; got != want {
104 t.Errorf("status: %v; want %v", got, want)
108 // // TestH1H1ConnectFailure tests that server handles the situation that
109 // // connection attempt to HTTP/1 backend failed.
110 // func TestH1H1ConnectFailure(t *testing.T) {
111 // st := newServerTester(nil, t, noopHandler)
114 // // shutdown backend server to simulate backend connect failure
117 // res, err := st.http1(requestParam{
118 // name: "TestH1H1ConnectFailure",
121 // t.Fatalf("Error st.http1() = %v", err)
124 // if got := res.status; got != want {
125 // t.Errorf("status: %v; want %v", got, want)
129 // TestH1H1AffinityCookie tests that affinity cookie is sent back in
131 func TestH1H1AffinityCookie(t *testing.T) {
132 st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler)
135 res, err := st.http1(requestParam{
136 name: "TestH1H1AffinityCookie",
139 t.Fatalf("Error st.http1() = %v", err)
142 if got, want := res.status, 200; got != want {
143 t.Errorf("status = %v; want %v", got, want)
146 const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar`
147 validCookie := regexp.MustCompile(pattern)
148 if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
149 t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
153 // TestH1H1AffinityCookieTLS tests that affinity cookie is sent back
155 func TestH1H1AffinityCookieTLS(t *testing.T) {
156 st := newServerTesterTLS([]string{"--alpn-h1", "--affinity-cookie"}, t, noopHandler)
159 res, err := st.http1(requestParam{
160 name: "TestH1H1AffinityCookieTLS",
163 t.Fatalf("Error st.http1() = %v", err)
166 if got, want := res.status, 200; got != want {
167 t.Errorf("status = %v; want %v", got, want)
170 const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure`
171 validCookie := regexp.MustCompile(pattern)
172 if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) {
173 t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern)
177 // TestH1H1GracefulShutdown tests graceful shutdown.
178 func TestH1H1GracefulShutdown(t *testing.T) {
179 st := newServerTester(nil, t, noopHandler)
182 res, err := st.http1(requestParam{
183 name: "TestH1H1GracefulShutdown-1",
186 t.Fatalf("Error st.http1() = %v", err)
189 if got, want := res.status, 200; got != want {
190 t.Errorf("status: %v; want %v", got, want)
193 st.cmd.Process.Signal(syscall.SIGQUIT)
194 time.Sleep(150 * time.Millisecond)
196 res, err = st.http1(requestParam{
197 name: "TestH1H1GracefulShutdown-2",
200 t.Fatalf("Error st.http1() = %v", err)
203 if got, want := res.status, 200; got != want {
204 t.Errorf("status: %v; want %v", got, want)
207 if got, want := res.connClose, true; got != want {
208 t.Errorf("res.connClose: %v; want %v", got, want)
212 b := make([]byte, 256)
213 if _, err := st.conn.Read(b); err == nil || err != want {
214 t.Errorf("st.conn.Read(): %v; want %v", err, want)
218 // TestH1H1HostRewrite tests that server rewrites Host header field
219 func TestH1H1HostRewrite(t *testing.T) {
220 st := newServerTester([]string{"--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) {
221 w.Header().Add("request-host", r.Host)
225 res, err := st.http1(requestParam{
226 name: "TestH1H1HostRewrite",
229 t.Fatalf("Error st.http1() = %v", err)
231 if got, want := res.status, 200; got != want {
232 t.Errorf("status: %v; want %v", got, want)
234 if got, want := res.header.Get("request-host"), st.backendHost; got != want {
235 t.Errorf("request-host: %v; want %v", got, want)
239 // TestH1H1BadHost tests that server rejects request including bad
240 // characters in host header field.
241 func TestH1H1BadHost(t *testing.T) {
242 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
243 t.Errorf("server should not forward this request")
247 if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H1HBadHost\r\nHost: foo\"bar\r\n\r\n"); err != nil {
248 t.Fatalf("Error io.WriteString() = %v", err)
250 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
252 t.Fatalf("Error http.ReadResponse() = %v", err)
254 if got, want := resp.StatusCode, 400; got != want {
255 t.Errorf("status: %v; want %v", got, want)
259 // TestH1H1BadAuthority tests that server rejects request including
260 // bad characters in authority component of requset URI.
261 func TestH1H1BadAuthority(t *testing.T) {
262 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
263 t.Errorf("server should not forward this request")
267 if _, err := io.WriteString(st.conn, "GET http://foo\"bar/ HTTP/1.1\r\nTest-Case: TestH1H1HBadAuthority\r\nHost: foobar\r\n\r\n"); err != nil {
268 t.Fatalf("Error io.WriteString() = %v", err)
270 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
272 t.Fatalf("Error http.ReadResponse() = %v", err)
274 if got, want := resp.StatusCode, 400; got != want {
275 t.Errorf("status: %v; want %v", got, want)
279 // TestH1H1BadScheme tests that server rejects request including
280 // bad characters in scheme component of requset URI.
281 func TestH1H1BadScheme(t *testing.T) {
282 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
283 t.Errorf("server should not forward this request")
287 if _, err := io.WriteString(st.conn, "GET http*://example.com/ HTTP/1.1\r\nTest-Case: TestH1H1HBadScheme\r\nHost: example.com\r\n\r\n"); err != nil {
288 t.Fatalf("Error io.WriteString() = %v", err)
290 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
292 t.Fatalf("Error http.ReadResponse() = %v", err)
294 if got, want := resp.StatusCode, 400; got != want {
295 t.Errorf("status: %v; want %v", got, want)
299 // TestH1H1HTTP10 tests that server can accept HTTP/1.0 request
300 // without Host header field
301 func TestH1H1HTTP10(t *testing.T) {
302 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
303 w.Header().Add("request-host", r.Host)
307 if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10\r\n\r\n"); err != nil {
308 t.Fatalf("Error io.WriteString() = %v", err)
311 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
313 t.Fatalf("Error http.ReadResponse() = %v", err)
316 if got, want := resp.StatusCode, 200; got != want {
317 t.Errorf("status: %v; want %v", got, want)
319 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
320 t.Errorf("request-host: %v; want %v", got, want)
324 // TestH1H1HTTP10NoHostRewrite tests that server generates host header
325 // field using actual backend server even if --no-http-rewrite is
327 func TestH1H1HTTP10NoHostRewrite(t *testing.T) {
328 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
329 w.Header().Add("request-host", r.Host)
333 if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H1HTTP10NoHostRewrite\r\n\r\n"); err != nil {
334 t.Fatalf("Error io.WriteString() = %v", err)
337 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
339 t.Fatalf("Error http.ReadResponse() = %v", err)
342 if got, want := resp.StatusCode, 200; got != want {
343 t.Errorf("status: %v; want %v", got, want)
345 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
346 t.Errorf("request-host: %v; want %v", got, want)
350 // TestH1H1RequestTrailer tests request trailer part is forwarded to
352 func TestH1H1RequestTrailer(t *testing.T) {
353 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
354 buf := make([]byte, 4096)
356 _, err := r.Body.Read(buf)
361 t.Fatalf("r.Body.Read() = %v", err)
364 if got, want := r.Trailer.Get("foo"), "bar"; got != want {
365 t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want)
370 res, err := st.http1(requestParam{
371 name: "TestH1H1RequestTrailer",
373 trailer: []hpack.HeaderField{
378 t.Fatalf("Error st.http1() = %v", err)
380 if got, want := res.status, 200; got != want {
381 t.Errorf("res.status: %v; want %v", got, want)
385 // TestH1H1HeaderFieldBufferPath tests that request with request path
386 // larger than configured buffer size is rejected.
387 func TestH1H1HeaderFieldBufferPath(t *testing.T) {
388 // The value 100 is chosen so that sum of header fields bytes
389 // does not exceed it. We use > 100 bytes URI to exceed this
391 st := newServerTester([]string{"--request-header-field-buffer=100"}, t, func(w http.ResponseWriter, r *http.Request) {
392 t.Fatal("execution path should not be here")
396 res, err := st.http1(requestParam{
397 name: "TestH1H1HeaderFieldBufferPath",
398 path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
401 t.Fatalf("Error st.http1() = %v", err)
403 if got, want := res.status, 431; got != want {
404 t.Errorf("status: %v; want %v", got, want)
408 // TestH1H1HeaderFieldBuffer tests that request with header fields
409 // larger than configured buffer size is rejected.
410 func TestH1H1HeaderFieldBuffer(t *testing.T) {
411 st := newServerTester([]string{"--request-header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) {
412 t.Fatal("execution path should not be here")
416 res, err := st.http1(requestParam{
417 name: "TestH1H1HeaderFieldBuffer",
420 t.Fatalf("Error st.http1() = %v", err)
422 if got, want := res.status, 431; got != want {
423 t.Errorf("status: %v; want %v", got, want)
427 // TestH1H1HeaderFields tests that request with header fields more
428 // than configured number is rejected.
429 func TestH1H1HeaderFields(t *testing.T) {
430 st := newServerTester([]string{"--max-request-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) {
431 t.Fatal("execution path should not be here")
435 res, err := st.http1(requestParam{
436 name: "TestH1H1HeaderFields",
437 header: []hpack.HeaderField{
438 // Add extra header field to ensure that
439 // header field limit exceeds
440 pair("Connection", "close"),
444 t.Fatalf("Error st.http1() = %v", err)
446 if got, want := res.status, 431; got != want {
447 t.Errorf("status: %v; want %v", got, want)
451 // TestH1H1Websocket tests that HTTP Upgrade to WebSocket works.
452 func TestH1H1Websocket(t *testing.T) {
453 st := newServerTesterHandler(nil, t, websocket.Handler(func(ws *websocket.Conn) {
458 content := []byte("hello world")
459 res, err := st.websocket(requestParam{
460 name: "TestH1H1Websocket",
464 t.Fatalf("Error st.websocket() = %v", err)
466 if got, want := res.body, content; !bytes.Equal(got, want) {
467 t.Errorf("echo: %q; want %q", got, want)
471 // TestH1H1ReqPhaseSetHeader tests mruby request phase hook
472 // modifies request header fields.
473 func TestH1H1ReqPhaseSetHeader(t *testing.T) {
474 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-set-header.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
475 if got, want := r.Header.Get("User-Agent"), "mruby"; got != want {
476 t.Errorf("User-Agent = %v; want %v", got, want)
481 res, err := st.http1(requestParam{
482 name: "TestH1H1ReqPhaseSetHeader",
485 t.Fatalf("Error st.http1() = %v", err)
488 if got, want := res.status, 200; got != want {
489 t.Errorf("status = %v; want %v", got, want)
493 // TestH1H1ReqPhaseReturn tests mruby request phase hook returns
495 func TestH1H1ReqPhaseReturn(t *testing.T) {
496 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
497 t.Fatalf("request should not be forwarded")
501 res, err := st.http1(requestParam{
502 name: "TestH1H1ReqPhaseReturn",
505 t.Fatalf("Error st.http1() = %v", err)
508 if got, want := res.status, 404; got != want {
509 t.Errorf("status = %v; want %v", got, want)
512 hdtests := []struct {
515 {"content-length", "20"},
518 for _, tt := range hdtests {
519 if got, want := res.header.Get(tt.k), tt.v; got != want {
520 t.Errorf("%v = %v; want %v", tt.k, got, want)
524 if got, want := string(res.body), "Hello World from req"; got != want {
525 t.Errorf("body = %v; want %v", got, want)
529 // TestH1H1RespPhaseSetHeader tests mruby response phase hook modifies
530 // response header fields.
531 func TestH1H1RespPhaseSetHeader(t *testing.T) {
532 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler)
535 res, err := st.http1(requestParam{
536 name: "TestH1H1RespPhaseSetHeader",
539 t.Fatalf("Error st.http1() = %v", err)
542 if got, want := res.status, 200; got != want {
543 t.Errorf("status = %v; want %v", got, want)
546 if got, want := res.header.Get("alpha"), "bravo"; got != want {
547 t.Errorf("alpha = %v; want %v", got, want)
551 // TestH1H1RespPhaseReturn tests mruby response phase hook returns
553 func TestH1H1RespPhaseReturn(t *testing.T) {
554 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
557 res, err := st.http1(requestParam{
558 name: "TestH1H1RespPhaseReturn",
561 t.Fatalf("Error st.http1() = %v", err)
564 if got, want := res.status, 404; got != want {
565 t.Errorf("status = %v; want %v", got, want)
568 hdtests := []struct {
571 {"content-length", "21"},
574 for _, tt := range hdtests {
575 if got, want := res.header.Get(tt.k), tt.v; got != want {
576 t.Errorf("%v = %v; want %v", tt.k, got, want)
580 if got, want := string(res.body), "Hello World from resp"; got != want {
581 t.Errorf("body = %v; want %v", got, want)
585 // TestH1H1HTTPSRedirect tests that the request to the backend which
586 // requires TLS is redirected to https URI.
587 func TestH1H1HTTPSRedirect(t *testing.T) {
588 st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler)
591 res, err := st.http1(requestParam{
592 name: "TestH1H1HTTPSRedirect",
595 t.Fatalf("Error st.http1() = %v", err)
598 if got, want := res.status, 308; got != want {
599 t.Errorf("status = %v; want %v", got, want)
601 if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want {
602 t.Errorf("location: %v; want %v", got, want)
606 // TestH1H1HTTPSRedirectPort tests that the request to the backend
607 // which requires TLS is redirected to https URI with given port.
608 func TestH1H1HTTPSRedirectPort(t *testing.T) {
609 st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler)
612 res, err := st.http1(requestParam{
614 name: "TestH1H1HTTPSRedirectPort",
617 t.Fatalf("Error st.http1() = %v", err)
620 if got, want := res.status, 308; got != want {
621 t.Errorf("status = %v; want %v", got, want)
623 if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want {
624 t.Errorf("location: %v; want %v", got, want)
628 // TestH1H1POSTRequests tests that server can handle 2 requests with
630 func TestH1H1POSTRequests(t *testing.T) {
631 st := newServerTester(nil, t, noopHandler)
634 res, err := st.http1(requestParam{
635 name: "TestH1H1POSTRequestsNo1",
636 body: make([]byte, 1),
639 t.Fatalf("Error st.http1() = %v", err)
641 if got, want := res.status, 200; got != want {
642 t.Errorf("res.status: %v; want %v", got, want)
645 res, err = st.http1(requestParam{
646 name: "TestH1H1POSTRequestsNo2",
647 body: make([]byte, 65536),
650 t.Fatalf("Error st.http1() = %v", err)
652 if got, want := res.status, 200; got != want {
653 t.Errorf("res.status: %v; want %v", got, want)
657 // // TestH1H2ConnectFailure tests that server handles the situation that
658 // // connection attempt to HTTP/2 backend failed.
659 // func TestH1H2ConnectFailure(t *testing.T) {
660 // st := newServerTester([]string{"--http2-bridge"}, t, noopHandler)
663 // // simulate backend connect attempt failure
666 // res, err := st.http1(requestParam{
667 // name: "TestH1H2ConnectFailure",
670 // t.Fatalf("Error st.http1() = %v", err)
673 // if got := res.status; got != want {
674 // t.Errorf("status: %v; want %v", got, want)
678 // TestH1H2NoHost tests that server rejects request without Host
679 // header field for HTTP/2 backend.
680 func TestH1H2NoHost(t *testing.T) {
681 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
682 t.Errorf("server should not forward bad request")
686 // without Host header field, we expect 400 response
687 if _, err := io.WriteString(st.conn, "GET / HTTP/1.1\r\nTest-Case: TestH1H2NoHost\r\n\r\n"); err != nil {
688 t.Fatalf("Error io.WriteString() = %v", err)
691 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
693 t.Fatalf("Error http.ReadResponse() = %v", err)
697 if got := resp.StatusCode; got != want {
698 t.Errorf("status: %v; want %v", got, want)
702 // TestH1H2HTTP10 tests that server can accept HTTP/1.0 request
703 // without Host header field
704 func TestH1H2HTTP10(t *testing.T) {
705 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
706 w.Header().Add("request-host", r.Host)
710 if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10\r\n\r\n"); err != nil {
711 t.Fatalf("Error io.WriteString() = %v", err)
714 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
716 t.Fatalf("Error http.ReadResponse() = %v", err)
719 if got, want := resp.StatusCode, 200; got != want {
720 t.Errorf("status: %v; want %v", got, want)
722 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
723 t.Errorf("request-host: %v; want %v", got, want)
727 // TestH1H2HTTP10NoHostRewrite tests that server generates host header
728 // field using actual backend server even if --no-http-rewrite is
730 func TestH1H2HTTP10NoHostRewrite(t *testing.T) {
731 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
732 w.Header().Add("request-host", r.Host)
736 if _, err := io.WriteString(st.conn, "GET / HTTP/1.0\r\nTest-Case: TestH1H2HTTP10NoHostRewrite\r\n\r\n"); err != nil {
737 t.Fatalf("Error io.WriteString() = %v", err)
740 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
742 t.Fatalf("Error http.ReadResponse() = %v", err)
745 if got, want := resp.StatusCode, 200; got != want {
746 t.Errorf("status: %v; want %v", got, want)
748 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want {
749 t.Errorf("request-host: %v; want %v", got, want)
753 // TestH1H2CrumbleCookie tests that Cookies are crumbled and assembled
754 // when forwarding to HTTP/2 backend link. go-nghttp2 server
755 // concatenates crumbled Cookies automatically, so this test is not
756 // much effective now.
757 func TestH1H2CrumbleCookie(t *testing.T) {
758 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
759 if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want {
760 t.Errorf("Cookie: %v; want %v", got, want)
765 res, err := st.http1(requestParam{
766 name: "TestH1H2CrumbleCookie",
767 header: []hpack.HeaderField{
768 pair("Cookie", "alpha; bravo; charlie"),
772 t.Fatalf("Error st.http1() = %v", err)
774 if got, want := res.status, 200; got != want {
775 t.Errorf("status: %v; want %v", got, want)
779 // TestH1H2GenerateVia tests that server generates Via header field to and
780 // from backend server.
781 func TestH1H2GenerateVia(t *testing.T) {
782 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
783 if got, want := r.Header.Get("Via"), "1.1 nghttpx"; got != want {
784 t.Errorf("Via: %v; want %v", got, want)
789 res, err := st.http1(requestParam{
790 name: "TestH1H2GenerateVia",
793 t.Fatalf("Error st.http1() = %v", err)
795 if got, want := res.header.Get("Via"), "2 nghttpx"; got != want {
796 t.Errorf("Via: %v; want %v", got, want)
800 // TestH1H2AppendVia tests that server adds value to existing Via
801 // header field to and from backend server.
802 func TestH1H2AppendVia(t *testing.T) {
803 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
804 if got, want := r.Header.Get("Via"), "foo, 1.1 nghttpx"; got != want {
805 t.Errorf("Via: %v; want %v", got, want)
807 w.Header().Add("Via", "bar")
811 res, err := st.http1(requestParam{
812 name: "TestH1H2AppendVia",
813 header: []hpack.HeaderField{
818 t.Fatalf("Error st.http1() = %v", err)
820 if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want {
821 t.Errorf("Via: %v; want %v", got, want)
825 // TestH1H2NoVia tests that server does not add value to existing Via
826 // header field to and from backend server.
827 func TestH1H2NoVia(t *testing.T) {
828 st := newServerTester([]string{"--http2-bridge", "--no-via"}, t, func(w http.ResponseWriter, r *http.Request) {
829 if got, want := r.Header.Get("Via"), "foo"; got != want {
830 t.Errorf("Via: %v; want %v", got, want)
832 w.Header().Add("Via", "bar")
836 res, err := st.http1(requestParam{
837 name: "TestH1H2NoVia",
838 header: []hpack.HeaderField{
843 t.Fatalf("Error st.http1() = %v", err)
845 if got, want := res.header.Get("Via"), "bar"; got != want {
846 t.Errorf("Via: %v; want %v", got, want)
850 // TestH1H2ReqPhaseReturn tests mruby request phase hook returns
852 func TestH1H2ReqPhaseReturn(t *testing.T) {
853 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
854 t.Fatalf("request should not be forwarded")
858 res, err := st.http1(requestParam{
859 name: "TestH1H2ReqPhaseReturn",
862 t.Fatalf("Error st.http1() = %v", err)
865 if got, want := res.status, 404; got != want {
866 t.Errorf("status = %v; want %v", got, want)
869 hdtests := []struct {
872 {"content-length", "20"},
875 for _, tt := range hdtests {
876 if got, want := res.header.Get(tt.k), tt.v; got != want {
877 t.Errorf("%v = %v; want %v", tt.k, got, want)
881 if got, want := string(res.body), "Hello World from req"; got != want {
882 t.Errorf("body = %v; want %v", got, want)
886 // TestH1H2RespPhaseReturn tests mruby response phase hook returns
888 func TestH1H2RespPhaseReturn(t *testing.T) {
889 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler)
892 res, err := st.http1(requestParam{
893 name: "TestH1H2RespPhaseReturn",
896 t.Fatalf("Error st.http1() = %v", err)
899 if got, want := res.status, 404; got != want {
900 t.Errorf("status = %v; want %v", got, want)
903 hdtests := []struct {
906 {"content-length", "21"},
909 for _, tt := range hdtests {
910 if got, want := res.header.Get(tt.k), tt.v; got != want {
911 t.Errorf("%v = %v; want %v", tt.k, got, want)
915 if got, want := string(res.body), "Hello World from resp"; got != want {
916 t.Errorf("body = %v; want %v", got, want)
920 // TestH1H2TE tests that "te: trailers" header is forwarded to HTTP/2
921 // backend server by stripping other encodings.
922 func TestH1H2TE(t *testing.T) {
923 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) {
924 if got, want := r.Header.Get("te"), "trailers"; got != want {
925 t.Errorf("te: %v; want %v", got, want)
930 res, err := st.http1(requestParam{
932 header: []hpack.HeaderField{
933 pair("te", "foo,trailers,bar"),
937 t.Fatalf("Error st.http1() = %v", err)
939 if got, want := res.status, 200; got != want {
940 t.Errorf("status: %v; want %v", got, want)
944 // TestH1APIBackendconfig exercise backendconfig API endpoint routine
945 // for successful case.
946 func TestH1APIBackendconfig(t *testing.T) {
947 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
948 t.Fatalf("request should not be forwarded")
952 res, err := st.http1(requestParam{
953 name: "TestH1APIBackendconfig",
954 path: "/api/v1beta1/backendconfig",
956 body: []byte(`# comment
957 backend=127.0.0.1,3011
962 t.Fatalf("Error st.http1() = %v", err)
964 if got, want := res.status, 200; got != want {
965 t.Errorf("res.status: %v; want %v", got, want)
968 var apiResp APIResponse
969 err = json.Unmarshal(res.body, &apiResp)
971 t.Fatalf("Error unmarshaling API response: %v", err)
973 if got, want := apiResp.Status, "Success"; got != want {
974 t.Errorf("apiResp.Status: %v; want %v", got, want)
976 if got, want := apiResp.Code, 200; got != want {
977 t.Errorf("apiResp.Status: %v; want %v", got, want)
981 // TestH1APIBackendconfigQuery exercise backendconfig API endpoint
982 // routine with query.
983 func TestH1APIBackendconfigQuery(t *testing.T) {
984 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
985 t.Fatalf("request should not be forwarded")
989 res, err := st.http1(requestParam{
990 name: "TestH1APIBackendconfigQuery",
991 path: "/api/v1beta1/backendconfig?foo=bar",
993 body: []byte(`# comment
994 backend=127.0.0.1,3011
999 t.Fatalf("Error st.http1() = %v", err)
1001 if got, want := res.status, 200; got != want {
1002 t.Errorf("res.status: %v; want %v", got, want)
1005 var apiResp APIResponse
1006 err = json.Unmarshal(res.body, &apiResp)
1008 t.Fatalf("Error unmarshaling API response: %v", err)
1010 if got, want := apiResp.Status, "Success"; got != want {
1011 t.Errorf("apiResp.Status: %v; want %v", got, want)
1013 if got, want := apiResp.Code, 200; got != want {
1014 t.Errorf("apiResp.Status: %v; want %v", got, want)
1018 // TestH1APIBackendconfigBadMethod exercise backendconfig API endpoint
1019 // routine with bad method.
1020 func TestH1APIBackendconfigBadMethod(t *testing.T) {
1021 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1022 t.Fatalf("request should not be forwarded")
1026 res, err := st.http1(requestParam{
1027 name: "TestH1APIBackendconfigBadMethod",
1028 path: "/api/v1beta1/backendconfig",
1030 body: []byte(`# comment
1031 backend=127.0.0.1,3011
1036 t.Fatalf("Error st.http1() = %v", err)
1038 if got, want := res.status, 405; got != want {
1039 t.Errorf("res.status: %v; want %v", got, want)
1042 var apiResp APIResponse
1043 err = json.Unmarshal(res.body, &apiResp)
1045 t.Fatalf("Error unmarshaling API response: %v", err)
1047 if got, want := apiResp.Status, "Failure"; got != want {
1048 t.Errorf("apiResp.Status: %v; want %v", got, want)
1050 if got, want := apiResp.Code, 405; got != want {
1051 t.Errorf("apiResp.Status: %v; want %v", got, want)
1055 // TestH1APIConfigrevision tests configrevision API.
1056 func TestH1APIConfigrevision(t *testing.T) {
1057 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1058 t.Fatalf("request should not be forwarded")
1062 res, err := st.http1(requestParam{
1063 name: "TestH1APIConfigrevision",
1064 path: "/api/v1beta1/configrevision",
1068 t.Fatalf("Error st.http1() = %v", err)
1070 if got, want := res.status, 200; got != want {
1071 t.Errorf("res.status: %v; want = %v", got, want)
1074 var apiResp APIResponse
1075 d := json.NewDecoder(bytes.NewBuffer(res.body))
1077 err = d.Decode(&apiResp)
1079 t.Fatalf("Error unmarshalling API response: %v", err)
1081 if got, want := apiResp.Status, "Success"; got != want {
1082 t.Errorf("apiResp.Status: %v; want %v", got, want)
1084 if got, want := apiResp.Code, 200; got != want {
1085 t.Errorf("apiResp.Status: %v; want %v", got, want)
1087 if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want {
1088 t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want)
1092 // TestH1APINotFound exercise backendconfig API endpoint routine when
1093 // API endpoint is not found.
1094 func TestH1APINotFound(t *testing.T) {
1095 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1096 t.Fatalf("request should not be forwarded")
1100 res, err := st.http1(requestParam{
1101 name: "TestH1APINotFound",
1102 path: "/api/notfound",
1104 body: []byte(`# comment
1105 backend=127.0.0.1,3011
1110 t.Fatalf("Error st.http1() = %v", err)
1112 if got, want := res.status, 404; got != want {
1113 t.Errorf("res.status: %v; want %v", got, want)
1116 var apiResp APIResponse
1117 err = json.Unmarshal(res.body, &apiResp)
1119 t.Fatalf("Error unmarshaling API response: %v", err)
1121 if got, want := apiResp.Status, "Failure"; got != want {
1122 t.Errorf("apiResp.Status: %v; want %v", got, want)
1124 if got, want := apiResp.Code, 404; got != want {
1125 t.Errorf("apiResp.Status: %v; want %v", got, want)
1129 // TestH1Healthmon tests health monitor endpoint.
1130 func TestH1Healthmon(t *testing.T) {
1131 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3011;healthmon;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) {
1132 t.Fatalf("request should not be forwarded")
1136 res, err := st.http1(requestParam{
1137 name: "TestH1Healthmon",
1138 path: "/alpha/bravo",
1141 t.Fatalf("Error st.http1() = %v", err)
1143 if got, want := res.status, 200; got != want {
1144 t.Errorf("res.status: %v; want %v", got, want)
1148 // TestH1ResponseBeforeRequestEnd tests the situation where response
1149 // ends before request body finishes.
1150 func TestH1ResponseBeforeRequestEnd(t *testing.T) {
1151 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) {
1152 t.Fatal("request should not be forwarded")
1156 if _, err := io.WriteString(st.conn, fmt.Sprintf(`POST / HTTP/1.1
1158 Test-Case: TestH1ResponseBeforeRequestEnd
1159 Content-Length: 1000000
1161 `, st.authority)); err != nil {
1162 t.Fatalf("Error io.WriteString() = %v", err)
1165 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil)
1167 t.Fatalf("Error http.ReadResponse() = %v", err)
1170 if got, want := resp.StatusCode, 404; got != want {
1171 t.Errorf("status: %v; want %v", got, want)
1175 // TestH1H1ChunkedEndsPrematurely tests that an HTTP/1.1 request fails
1176 // if the backend chunked encoded response ends prematurely.
1177 func TestH1H1ChunkedEndsPrematurely(t *testing.T) {
1178 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {
1179 hj, ok := w.(http.Hijacker)
1181 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError)
1184 conn, bufrw, err := hj.Hijack()
1186 http.Error(w, err.Error(), http.StatusInternalServerError)
1190 bufrw.WriteString("HTTP/1.1 200\r\nTransfer-Encoding: chunked\r\n\r\n")
1195 _, err := st.http1(requestParam{
1196 name: "TestH1H1ChunkedEndsPrematurely",
1199 t.Fatal("st.http1() should fail")