1package nghttp2 2 3import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "golang.org/x/net/http2/hpack" 9 "golang.org/x/net/websocket" 10 "io" 11 "net/http" 12 "regexp" 13 "syscall" 14 "testing" 15 "time" 16) 17 18// TestH1H1PlainGET tests whether simple HTTP/1 GET request works. 19func TestH1H1PlainGET(t *testing.T) { 20 st := newServerTester(nil, t, noopHandler) 21 defer st.Close() 22 23 res, err := st.http1(requestParam{ 24 name: "TestH1H1PlainGET", 25 }) 26 if err != nil { 27 t.Fatalf("Error st.http1() = %v", err) 28 } 29 30 want := 200 31 if got := res.status; got != want { 32 t.Errorf("status = %v; want %v", got, want) 33 } 34} 35 36// TestH1H1PlainGETClose tests whether simple HTTP/1 GET request with 37// Connetion: close request header field works. 38func TestH1H1PlainGETClose(t *testing.T) { 39 st := newServerTester(nil, t, noopHandler) 40 defer st.Close() 41 42 res, err := st.http1(requestParam{ 43 name: "TestH1H1PlainGETClose", 44 header: []hpack.HeaderField{ 45 pair("Connection", "close"), 46 }, 47 }) 48 if err != nil { 49 t.Fatalf("Error st.http1() = %v", err) 50 } 51 52 want := 200 53 if got := res.status; got != want { 54 t.Errorf("status = %v; want %v", got, want) 55 } 56} 57 58// TestH1H1InvalidMethod tests that server rejects invalid method with 59// 501 status code 60func 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") 63 }) 64 defer st.Close() 65 66 res, err := st.http1(requestParam{ 67 name: "TestH1H1InvalidMethod", 68 method: "get", 69 }) 70 if err != nil { 71 t.Fatalf("Error st.http1() = %v", err) 72 } 73 74 if got, want := res.status, 501; got != want { 75 t.Errorf("status = %v; want %v", got, want) 76 } 77} 78 79// TestH1H1MultipleRequestCL tests that server rejects request which 80// contains multiple Content-Length header fields. 81func 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") 84 }) 85 defer st.Close() 86 87 if _, err := io.WriteString(st.conn, fmt.Sprintf(`GET / HTTP/1.1 88Host: %v 89Test-Case: TestH1H1MultipleRequestCL 90Content-Length: 0 91Content-Length: 0 92 93`, st.authority)); err != nil { 94 t.Fatalf("Error io.WriteString() = %v", err) 95 } 96 97 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 98 if err != nil { 99 t.Fatalf("Error http.ReadResponse() = %v", err) 100 } 101 102 want := 400 103 if got := resp.StatusCode; got != want { 104 t.Errorf("status: %v; want %v", got, want) 105 } 106} 107 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) 112// defer st.Close() 113 114// // shutdown backend server to simulate backend connect failure 115// st.ts.Close() 116 117// res, err := st.http1(requestParam{ 118// name: "TestH1H1ConnectFailure", 119// }) 120// if err != nil { 121// t.Fatalf("Error st.http1() = %v", err) 122// } 123// want := 503 124// if got := res.status; got != want { 125// t.Errorf("status: %v; want %v", got, want) 126// } 127// } 128 129// TestH1H1AffinityCookie tests that affinity cookie is sent back in 130// cleartext http. 131func TestH1H1AffinityCookie(t *testing.T) { 132 st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler) 133 defer st.Close() 134 135 res, err := st.http1(requestParam{ 136 name: "TestH1H1AffinityCookie", 137 }) 138 if err != nil { 139 t.Fatalf("Error st.http1() = %v", err) 140 } 141 142 if got, want := res.status, 200; got != want { 143 t.Errorf("status = %v; want %v", got, want) 144 } 145 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) 150 } 151} 152 153// TestH1H1AffinityCookieTLS tests that affinity cookie is sent back 154// in https. 155func TestH1H1AffinityCookieTLS(t *testing.T) { 156 st := newServerTesterTLS([]string{"--alpn-h1", "--affinity-cookie"}, t, noopHandler) 157 defer st.Close() 158 159 res, err := st.http1(requestParam{ 160 name: "TestH1H1AffinityCookieTLS", 161 }) 162 if err != nil { 163 t.Fatalf("Error st.http1() = %v", err) 164 } 165 166 if got, want := res.status, 200; got != want { 167 t.Errorf("status = %v; want %v", got, want) 168 } 169 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) 174 } 175} 176 177// TestH1H1GracefulShutdown tests graceful shutdown. 178func TestH1H1GracefulShutdown(t *testing.T) { 179 st := newServerTester(nil, t, noopHandler) 180 defer st.Close() 181 182 res, err := st.http1(requestParam{ 183 name: "TestH1H1GracefulShutdown-1", 184 }) 185 if err != nil { 186 t.Fatalf("Error st.http1() = %v", err) 187 } 188 189 if got, want := res.status, 200; got != want { 190 t.Errorf("status: %v; want %v", got, want) 191 } 192 193 st.cmd.Process.Signal(syscall.SIGQUIT) 194 time.Sleep(150 * time.Millisecond) 195 196 res, err = st.http1(requestParam{ 197 name: "TestH1H1GracefulShutdown-2", 198 }) 199 if err != nil { 200 t.Fatalf("Error st.http1() = %v", err) 201 } 202 203 if got, want := res.status, 200; got != want { 204 t.Errorf("status: %v; want %v", got, want) 205 } 206 207 if got, want := res.connClose, true; got != want { 208 t.Errorf("res.connClose: %v; want %v", got, want) 209 } 210 211 want := io.EOF 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) 215 } 216} 217 218// TestH1H1HostRewrite tests that server rewrites Host header field 219func 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) 222 }) 223 defer st.Close() 224 225 res, err := st.http1(requestParam{ 226 name: "TestH1H1HostRewrite", 227 }) 228 if err != nil { 229 t.Fatalf("Error st.http1() = %v", err) 230 } 231 if got, want := res.status, 200; got != want { 232 t.Errorf("status: %v; want %v", got, want) 233 } 234 if got, want := res.header.Get("request-host"), st.backendHost; got != want { 235 t.Errorf("request-host: %v; want %v", got, want) 236 } 237} 238 239// TestH1H1BadHost tests that server rejects request including bad 240// characters in host header field. 241func 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") 244 }) 245 defer st.Close() 246 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) 249 } 250 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 251 if err != nil { 252 t.Fatalf("Error http.ReadResponse() = %v", err) 253 } 254 if got, want := resp.StatusCode, 400; got != want { 255 t.Errorf("status: %v; want %v", got, want) 256 } 257} 258 259// TestH1H1BadAuthority tests that server rejects request including 260// bad characters in authority component of requset URI. 261func 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") 264 }) 265 defer st.Close() 266 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) 269 } 270 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 271 if err != nil { 272 t.Fatalf("Error http.ReadResponse() = %v", err) 273 } 274 if got, want := resp.StatusCode, 400; got != want { 275 t.Errorf("status: %v; want %v", got, want) 276 } 277} 278 279// TestH1H1BadScheme tests that server rejects request including 280// bad characters in scheme component of requset URI. 281func 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") 284 }) 285 defer st.Close() 286 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) 289 } 290 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 291 if err != nil { 292 t.Fatalf("Error http.ReadResponse() = %v", err) 293 } 294 if got, want := resp.StatusCode, 400; got != want { 295 t.Errorf("status: %v; want %v", got, want) 296 } 297} 298 299// TestH1H1HTTP10 tests that server can accept HTTP/1.0 request 300// without Host header field 301func TestH1H1HTTP10(t *testing.T) { 302 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 303 w.Header().Add("request-host", r.Host) 304 }) 305 defer st.Close() 306 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) 309 } 310 311 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 312 if err != nil { 313 t.Fatalf("Error http.ReadResponse() = %v", err) 314 } 315 316 if got, want := resp.StatusCode, 200; got != want { 317 t.Errorf("status: %v; want %v", got, want) 318 } 319 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { 320 t.Errorf("request-host: %v; want %v", got, want) 321 } 322} 323 324// TestH1H1HTTP10NoHostRewrite tests that server generates host header 325// field using actual backend server even if --no-http-rewrite is 326// used. 327func TestH1H1HTTP10NoHostRewrite(t *testing.T) { 328 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 329 w.Header().Add("request-host", r.Host) 330 }) 331 defer st.Close() 332 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) 335 } 336 337 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 338 if err != nil { 339 t.Fatalf("Error http.ReadResponse() = %v", err) 340 } 341 342 if got, want := resp.StatusCode, 200; got != want { 343 t.Errorf("status: %v; want %v", got, want) 344 } 345 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { 346 t.Errorf("request-host: %v; want %v", got, want) 347 } 348} 349 350// TestH1H1RequestTrailer tests request trailer part is forwarded to 351// backend. 352func TestH1H1RequestTrailer(t *testing.T) { 353 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 354 buf := make([]byte, 4096) 355 for { 356 _, err := r.Body.Read(buf) 357 if err == io.EOF { 358 break 359 } 360 if err != nil { 361 t.Fatalf("r.Body.Read() = %v", err) 362 } 363 } 364 if got, want := r.Trailer.Get("foo"), "bar"; got != want { 365 t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want) 366 } 367 }) 368 defer st.Close() 369 370 res, err := st.http1(requestParam{ 371 name: "TestH1H1RequestTrailer", 372 body: []byte("1"), 373 trailer: []hpack.HeaderField{ 374 pair("foo", "bar"), 375 }, 376 }) 377 if err != nil { 378 t.Fatalf("Error st.http1() = %v", err) 379 } 380 if got, want := res.status, 200; got != want { 381 t.Errorf("res.status: %v; want %v", got, want) 382 } 383} 384 385// TestH1H1HeaderFieldBufferPath tests that request with request path 386// larger than configured buffer size is rejected. 387func 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 390 // limit. 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") 393 }) 394 defer st.Close() 395 396 res, err := st.http1(requestParam{ 397 name: "TestH1H1HeaderFieldBufferPath", 398 path: "/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 399 }) 400 if err != nil { 401 t.Fatalf("Error st.http1() = %v", err) 402 } 403 if got, want := res.status, 431; got != want { 404 t.Errorf("status: %v; want %v", got, want) 405 } 406} 407 408// TestH1H1HeaderFieldBuffer tests that request with header fields 409// larger than configured buffer size is rejected. 410func 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") 413 }) 414 defer st.Close() 415 416 res, err := st.http1(requestParam{ 417 name: "TestH1H1HeaderFieldBuffer", 418 }) 419 if err != nil { 420 t.Fatalf("Error st.http1() = %v", err) 421 } 422 if got, want := res.status, 431; got != want { 423 t.Errorf("status: %v; want %v", got, want) 424 } 425} 426 427// TestH1H1HeaderFields tests that request with header fields more 428// than configured number is rejected. 429func 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") 432 }) 433 defer st.Close() 434 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"), 441 }, 442 }) 443 if err != nil { 444 t.Fatalf("Error st.http1() = %v", err) 445 } 446 if got, want := res.status, 431; got != want { 447 t.Errorf("status: %v; want %v", got, want) 448 } 449} 450 451// TestH1H1Websocket tests that HTTP Upgrade to WebSocket works. 452func TestH1H1Websocket(t *testing.T) { 453 st := newServerTesterHandler(nil, t, websocket.Handler(func(ws *websocket.Conn) { 454 io.Copy(ws, ws) 455 })) 456 defer st.Close() 457 458 content := []byte("hello world") 459 res, err := st.websocket(requestParam{ 460 name: "TestH1H1Websocket", 461 body: content, 462 }) 463 if err != nil { 464 t.Fatalf("Error st.websocket() = %v", err) 465 } 466 if got, want := res.body, content; !bytes.Equal(got, want) { 467 t.Errorf("echo: %q; want %q", got, want) 468 } 469} 470 471// TestH1H1ReqPhaseSetHeader tests mruby request phase hook 472// modifies request header fields. 473func 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) 477 } 478 }) 479 defer st.Close() 480 481 res, err := st.http1(requestParam{ 482 name: "TestH1H1ReqPhaseSetHeader", 483 }) 484 if err != nil { 485 t.Fatalf("Error st.http1() = %v", err) 486 } 487 488 if got, want := res.status, 200; got != want { 489 t.Errorf("status = %v; want %v", got, want) 490 } 491} 492 493// TestH1H1ReqPhaseReturn tests mruby request phase hook returns 494// custom response. 495func 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") 498 }) 499 defer st.Close() 500 501 res, err := st.http1(requestParam{ 502 name: "TestH1H1ReqPhaseReturn", 503 }) 504 if err != nil { 505 t.Fatalf("Error st.http1() = %v", err) 506 } 507 508 if got, want := res.status, 404; got != want { 509 t.Errorf("status = %v; want %v", got, want) 510 } 511 512 hdtests := []struct { 513 k, v string 514 }{ 515 {"content-length", "20"}, 516 {"from", "mruby"}, 517 } 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) 521 } 522 } 523 524 if got, want := string(res.body), "Hello World from req"; got != want { 525 t.Errorf("body = %v; want %v", got, want) 526 } 527} 528 529// TestH1H1RespPhaseSetHeader tests mruby response phase hook modifies 530// response header fields. 531func TestH1H1RespPhaseSetHeader(t *testing.T) { 532 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler) 533 defer st.Close() 534 535 res, err := st.http1(requestParam{ 536 name: "TestH1H1RespPhaseSetHeader", 537 }) 538 if err != nil { 539 t.Fatalf("Error st.http1() = %v", err) 540 } 541 542 if got, want := res.status, 200; got != want { 543 t.Errorf("status = %v; want %v", got, want) 544 } 545 546 if got, want := res.header.Get("alpha"), "bravo"; got != want { 547 t.Errorf("alpha = %v; want %v", got, want) 548 } 549} 550 551// TestH1H1RespPhaseReturn tests mruby response phase hook returns 552// custom response. 553func TestH1H1RespPhaseReturn(t *testing.T) { 554 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler) 555 defer st.Close() 556 557 res, err := st.http1(requestParam{ 558 name: "TestH1H1RespPhaseReturn", 559 }) 560 if err != nil { 561 t.Fatalf("Error st.http1() = %v", err) 562 } 563 564 if got, want := res.status, 404; got != want { 565 t.Errorf("status = %v; want %v", got, want) 566 } 567 568 hdtests := []struct { 569 k, v string 570 }{ 571 {"content-length", "21"}, 572 {"from", "mruby"}, 573 } 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) 577 } 578 } 579 580 if got, want := string(res.body), "Hello World from resp"; got != want { 581 t.Errorf("body = %v; want %v", got, want) 582 } 583} 584 585// TestH1H1HTTPSRedirect tests that the request to the backend which 586// requires TLS is redirected to https URI. 587func TestH1H1HTTPSRedirect(t *testing.T) { 588 st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler) 589 defer st.Close() 590 591 res, err := st.http1(requestParam{ 592 name: "TestH1H1HTTPSRedirect", 593 }) 594 if err != nil { 595 t.Fatalf("Error st.http1() = %v", err) 596 } 597 598 if got, want := res.status, 308; got != want { 599 t.Errorf("status = %v; want %v", got, want) 600 } 601 if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want { 602 t.Errorf("location: %v; want %v", got, want) 603 } 604} 605 606// TestH1H1HTTPSRedirectPort tests that the request to the backend 607// which requires TLS is redirected to https URI with given port. 608func TestH1H1HTTPSRedirectPort(t *testing.T) { 609 st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler) 610 defer st.Close() 611 612 res, err := st.http1(requestParam{ 613 path: "/foo?bar", 614 name: "TestH1H1HTTPSRedirectPort", 615 }) 616 if err != nil { 617 t.Fatalf("Error st.http1() = %v", err) 618 } 619 620 if got, want := res.status, 308; got != want { 621 t.Errorf("status = %v; want %v", got, want) 622 } 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) 625 } 626} 627 628// TestH1H1POSTRequests tests that server can handle 2 requests with 629// request body. 630func TestH1H1POSTRequests(t *testing.T) { 631 st := newServerTester(nil, t, noopHandler) 632 defer st.Close() 633 634 res, err := st.http1(requestParam{ 635 name: "TestH1H1POSTRequestsNo1", 636 body: make([]byte, 1), 637 }) 638 if err != nil { 639 t.Fatalf("Error st.http1() = %v", err) 640 } 641 if got, want := res.status, 200; got != want { 642 t.Errorf("res.status: %v; want %v", got, want) 643 } 644 645 res, err = st.http1(requestParam{ 646 name: "TestH1H1POSTRequestsNo2", 647 body: make([]byte, 65536), 648 }) 649 if err != nil { 650 t.Fatalf("Error st.http1() = %v", err) 651 } 652 if got, want := res.status, 200; got != want { 653 t.Errorf("res.status: %v; want %v", got, want) 654 } 655} 656 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) 661// defer st.Close() 662 663// // simulate backend connect attempt failure 664// st.ts.Close() 665 666// res, err := st.http1(requestParam{ 667// name: "TestH1H2ConnectFailure", 668// }) 669// if err != nil { 670// t.Fatalf("Error st.http1() = %v", err) 671// } 672// want := 503 673// if got := res.status; got != want { 674// t.Errorf("status: %v; want %v", got, want) 675// } 676// } 677 678// TestH1H2NoHost tests that server rejects request without Host 679// header field for HTTP/2 backend. 680func 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") 683 }) 684 defer st.Close() 685 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) 689 } 690 691 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 692 if err != nil { 693 t.Fatalf("Error http.ReadResponse() = %v", err) 694 } 695 696 want := 400 697 if got := resp.StatusCode; got != want { 698 t.Errorf("status: %v; want %v", got, want) 699 } 700} 701 702// TestH1H2HTTP10 tests that server can accept HTTP/1.0 request 703// without Host header field 704func 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) 707 }) 708 defer st.Close() 709 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) 712 } 713 714 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 715 if err != nil { 716 t.Fatalf("Error http.ReadResponse() = %v", err) 717 } 718 719 if got, want := resp.StatusCode, 200; got != want { 720 t.Errorf("status: %v; want %v", got, want) 721 } 722 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { 723 t.Errorf("request-host: %v; want %v", got, want) 724 } 725} 726 727// TestH1H2HTTP10NoHostRewrite tests that server generates host header 728// field using actual backend server even if --no-http-rewrite is 729// used. 730func 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) 733 }) 734 defer st.Close() 735 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) 738 } 739 740 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 741 if err != nil { 742 t.Fatalf("Error http.ReadResponse() = %v", err) 743 } 744 745 if got, want := resp.StatusCode, 200; got != want { 746 t.Errorf("status: %v; want %v", got, want) 747 } 748 if got, want := resp.Header.Get("request-host"), st.backendHost; got != want { 749 t.Errorf("request-host: %v; want %v", got, want) 750 } 751} 752 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. 757func 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) 761 } 762 }) 763 defer st.Close() 764 765 res, err := st.http1(requestParam{ 766 name: "TestH1H2CrumbleCookie", 767 header: []hpack.HeaderField{ 768 pair("Cookie", "alpha; bravo; charlie"), 769 }, 770 }) 771 if err != nil { 772 t.Fatalf("Error st.http1() = %v", err) 773 } 774 if got, want := res.status, 200; got != want { 775 t.Errorf("status: %v; want %v", got, want) 776 } 777} 778 779// TestH1H2GenerateVia tests that server generates Via header field to and 780// from backend server. 781func 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) 785 } 786 }) 787 defer st.Close() 788 789 res, err := st.http1(requestParam{ 790 name: "TestH1H2GenerateVia", 791 }) 792 if err != nil { 793 t.Fatalf("Error st.http1() = %v", err) 794 } 795 if got, want := res.header.Get("Via"), "2 nghttpx"; got != want { 796 t.Errorf("Via: %v; want %v", got, want) 797 } 798} 799 800// TestH1H2AppendVia tests that server adds value to existing Via 801// header field to and from backend server. 802func 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) 806 } 807 w.Header().Add("Via", "bar") 808 }) 809 defer st.Close() 810 811 res, err := st.http1(requestParam{ 812 name: "TestH1H2AppendVia", 813 header: []hpack.HeaderField{ 814 pair("via", "foo"), 815 }, 816 }) 817 if err != nil { 818 t.Fatalf("Error st.http1() = %v", err) 819 } 820 if got, want := res.header.Get("Via"), "bar, 2 nghttpx"; got != want { 821 t.Errorf("Via: %v; want %v", got, want) 822 } 823} 824 825// TestH1H2NoVia tests that server does not add value to existing Via 826// header field to and from backend server. 827func 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) 831 } 832 w.Header().Add("Via", "bar") 833 }) 834 defer st.Close() 835 836 res, err := st.http1(requestParam{ 837 name: "TestH1H2NoVia", 838 header: []hpack.HeaderField{ 839 pair("via", "foo"), 840 }, 841 }) 842 if err != nil { 843 t.Fatalf("Error st.http1() = %v", err) 844 } 845 if got, want := res.header.Get("Via"), "bar"; got != want { 846 t.Errorf("Via: %v; want %v", got, want) 847 } 848} 849 850// TestH1H2ReqPhaseReturn tests mruby request phase hook returns 851// custom response. 852func 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") 855 }) 856 defer st.Close() 857 858 res, err := st.http1(requestParam{ 859 name: "TestH1H2ReqPhaseReturn", 860 }) 861 if err != nil { 862 t.Fatalf("Error st.http1() = %v", err) 863 } 864 865 if got, want := res.status, 404; got != want { 866 t.Errorf("status = %v; want %v", got, want) 867 } 868 869 hdtests := []struct { 870 k, v string 871 }{ 872 {"content-length", "20"}, 873 {"from", "mruby"}, 874 } 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) 878 } 879 } 880 881 if got, want := string(res.body), "Hello World from req"; got != want { 882 t.Errorf("body = %v; want %v", got, want) 883 } 884} 885 886// TestH1H2RespPhaseReturn tests mruby response phase hook returns 887// custom response. 888func TestH1H2RespPhaseReturn(t *testing.T) { 889 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler) 890 defer st.Close() 891 892 res, err := st.http1(requestParam{ 893 name: "TestH1H2RespPhaseReturn", 894 }) 895 if err != nil { 896 t.Fatalf("Error st.http1() = %v", err) 897 } 898 899 if got, want := res.status, 404; got != want { 900 t.Errorf("status = %v; want %v", got, want) 901 } 902 903 hdtests := []struct { 904 k, v string 905 }{ 906 {"content-length", "21"}, 907 {"from", "mruby"}, 908 } 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) 912 } 913 } 914 915 if got, want := string(res.body), "Hello World from resp"; got != want { 916 t.Errorf("body = %v; want %v", got, want) 917 } 918} 919 920// TestH1H2TE tests that "te: trailers" header is forwarded to HTTP/2 921// backend server by stripping other encodings. 922func 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) 926 } 927 }) 928 defer st.Close() 929 930 res, err := st.http1(requestParam{ 931 name: "TestH1H2TE", 932 header: []hpack.HeaderField{ 933 pair("te", "foo,trailers,bar"), 934 }, 935 }) 936 if err != nil { 937 t.Fatalf("Error st.http1() = %v", err) 938 } 939 if got, want := res.status, 200; got != want { 940 t.Errorf("status: %v; want %v", got, want) 941 } 942} 943 944// TestH1APIBackendconfig exercise backendconfig API endpoint routine 945// for successful case. 946func 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") 949 }, 3010) 950 defer st.Close() 951 952 res, err := st.http1(requestParam{ 953 name: "TestH1APIBackendconfig", 954 path: "/api/v1beta1/backendconfig", 955 method: "PUT", 956 body: []byte(`# comment 957backend=127.0.0.1,3011 958 959`), 960 }) 961 if err != nil { 962 t.Fatalf("Error st.http1() = %v", err) 963 } 964 if got, want := res.status, 200; got != want { 965 t.Errorf("res.status: %v; want %v", got, want) 966 } 967 968 var apiResp APIResponse 969 err = json.Unmarshal(res.body, &apiResp) 970 if err != nil { 971 t.Fatalf("Error unmarshaling API response: %v", err) 972 } 973 if got, want := apiResp.Status, "Success"; got != want { 974 t.Errorf("apiResp.Status: %v; want %v", got, want) 975 } 976 if got, want := apiResp.Code, 200; got != want { 977 t.Errorf("apiResp.Status: %v; want %v", got, want) 978 } 979} 980 981// TestH1APIBackendconfigQuery exercise backendconfig API endpoint 982// routine with query. 983func 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") 986 }, 3010) 987 defer st.Close() 988 989 res, err := st.http1(requestParam{ 990 name: "TestH1APIBackendconfigQuery", 991 path: "/api/v1beta1/backendconfig?foo=bar", 992 method: "PUT", 993 body: []byte(`# comment 994backend=127.0.0.1,3011 995 996`), 997 }) 998 if err != nil { 999 t.Fatalf("Error st.http1() = %v", err) 1000 } 1001 if got, want := res.status, 200; got != want { 1002 t.Errorf("res.status: %v; want %v", got, want) 1003 } 1004 1005 var apiResp APIResponse 1006 err = json.Unmarshal(res.body, &apiResp) 1007 if err != nil { 1008 t.Fatalf("Error unmarshaling API response: %v", err) 1009 } 1010 if got, want := apiResp.Status, "Success"; got != want { 1011 t.Errorf("apiResp.Status: %v; want %v", got, want) 1012 } 1013 if got, want := apiResp.Code, 200; got != want { 1014 t.Errorf("apiResp.Status: %v; want %v", got, want) 1015 } 1016} 1017 1018// TestH1APIBackendconfigBadMethod exercise backendconfig API endpoint 1019// routine with bad method. 1020func 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") 1023 }, 3010) 1024 defer st.Close() 1025 1026 res, err := st.http1(requestParam{ 1027 name: "TestH1APIBackendconfigBadMethod", 1028 path: "/api/v1beta1/backendconfig", 1029 method: "GET", 1030 body: []byte(`# comment 1031backend=127.0.0.1,3011 1032 1033`), 1034 }) 1035 if err != nil { 1036 t.Fatalf("Error st.http1() = %v", err) 1037 } 1038 if got, want := res.status, 405; got != want { 1039 t.Errorf("res.status: %v; want %v", got, want) 1040 } 1041 1042 var apiResp APIResponse 1043 err = json.Unmarshal(res.body, &apiResp) 1044 if err != nil { 1045 t.Fatalf("Error unmarshaling API response: %v", err) 1046 } 1047 if got, want := apiResp.Status, "Failure"; got != want { 1048 t.Errorf("apiResp.Status: %v; want %v", got, want) 1049 } 1050 if got, want := apiResp.Code, 405; got != want { 1051 t.Errorf("apiResp.Status: %v; want %v", got, want) 1052 } 1053} 1054 1055// TestH1APIConfigrevision tests configrevision API. 1056func 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") 1059 }, 3010) 1060 defer st.Close() 1061 1062 res, err := st.http1(requestParam{ 1063 name: "TestH1APIConfigrevision", 1064 path: "/api/v1beta1/configrevision", 1065 method: "GET", 1066 }) 1067 if err != nil { 1068 t.Fatalf("Error st.http1() = %v", err) 1069 } 1070 if got, want := res.status, 200; got != want { 1071 t.Errorf("res.status: %v; want = %v", got, want) 1072 } 1073 1074 var apiResp APIResponse 1075 d := json.NewDecoder(bytes.NewBuffer(res.body)) 1076 d.UseNumber() 1077 err = d.Decode(&apiResp) 1078 if err != nil { 1079 t.Fatalf("Error unmarshalling API response: %v", err) 1080 } 1081 if got, want := apiResp.Status, "Success"; got != want { 1082 t.Errorf("apiResp.Status: %v; want %v", got, want) 1083 } 1084 if got, want := apiResp.Code, 200; got != want { 1085 t.Errorf("apiResp.Status: %v; want %v", got, want) 1086 } 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) 1089 } 1090} 1091 1092// TestH1APINotFound exercise backendconfig API endpoint routine when 1093// API endpoint is not found. 1094func 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") 1097 }, 3010) 1098 defer st.Close() 1099 1100 res, err := st.http1(requestParam{ 1101 name: "TestH1APINotFound", 1102 path: "/api/notfound", 1103 method: "GET", 1104 body: []byte(`# comment 1105backend=127.0.0.1,3011 1106 1107`), 1108 }) 1109 if err != nil { 1110 t.Fatalf("Error st.http1() = %v", err) 1111 } 1112 if got, want := res.status, 404; got != want { 1113 t.Errorf("res.status: %v; want %v", got, want) 1114 } 1115 1116 var apiResp APIResponse 1117 err = json.Unmarshal(res.body, &apiResp) 1118 if err != nil { 1119 t.Fatalf("Error unmarshaling API response: %v", err) 1120 } 1121 if got, want := apiResp.Status, "Failure"; got != want { 1122 t.Errorf("apiResp.Status: %v; want %v", got, want) 1123 } 1124 if got, want := apiResp.Code, 404; got != want { 1125 t.Errorf("apiResp.Status: %v; want %v", got, want) 1126 } 1127} 1128 1129// TestH1Healthmon tests health monitor endpoint. 1130func 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") 1133 }, 3011) 1134 defer st.Close() 1135 1136 res, err := st.http1(requestParam{ 1137 name: "TestH1Healthmon", 1138 path: "/alpha/bravo", 1139 }) 1140 if err != nil { 1141 t.Fatalf("Error st.http1() = %v", err) 1142 } 1143 if got, want := res.status, 200; got != want { 1144 t.Errorf("res.status: %v; want %v", got, want) 1145 } 1146} 1147 1148// TestH1ResponseBeforeRequestEnd tests the situation where response 1149// ends before request body finishes. 1150func 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") 1153 }) 1154 defer st.Close() 1155 1156 if _, err := io.WriteString(st.conn, fmt.Sprintf(`POST / HTTP/1.1 1157Host: %v 1158Test-Case: TestH1ResponseBeforeRequestEnd 1159Content-Length: 1000000 1160 1161`, st.authority)); err != nil { 1162 t.Fatalf("Error io.WriteString() = %v", err) 1163 } 1164 1165 resp, err := http.ReadResponse(bufio.NewReader(st.conn), nil) 1166 if err != nil { 1167 t.Fatalf("Error http.ReadResponse() = %v", err) 1168 } 1169 1170 if got, want := resp.StatusCode, 404; got != want { 1171 t.Errorf("status: %v; want %v", got, want) 1172 } 1173} 1174