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