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