1package nghttp2 2 3import ( 4 "bytes" 5 "crypto/tls" 6 "encoding/json" 7 "fmt" 8 "golang.org/x/net/http2" 9 "golang.org/x/net/http2/hpack" 10 "io" 11 "io/ioutil" 12 "net" 13 "net/http" 14 "regexp" 15 "strings" 16 "syscall" 17 "testing" 18 "time" 19) 20 21// TestH2H1PlainGET tests whether simple HTTP/2 GET request works. 22func TestH2H1PlainGET(t *testing.T) { 23 st := newServerTester(nil, t, noopHandler) 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 want := 200 34 if res.status != want { 35 t.Errorf("status = %v; want %v", res.status, want) 36 } 37} 38 39// TestH2H1AddXfp tests that server appends :scheme to the existing 40// x-forwarded-proto header field. 41func TestH2H1AddXfp(t *testing.T) { 42 st := newServerTester([]string{"--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 43 xfp := r.Header.Get("X-Forwarded-Proto") 44 if got, want := xfp, "foo, http"; got != want { 45 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 46 } 47 }) 48 defer st.Close() 49 50 res, err := st.http2(requestParam{ 51 name: "TestH2H1AddXfp", 52 header: []hpack.HeaderField{ 53 pair("x-forwarded-proto", "foo"), 54 }, 55 }) 56 if err != nil { 57 t.Fatalf("Error st.http2() = %v", err) 58 } 59 if got, want := res.status, 200; got != want { 60 t.Errorf("status = %v; want %v", got, want) 61 } 62} 63 64// TestH2H1NoAddXfp tests that server does not append :scheme to the 65// existing x-forwarded-proto header field. 66func TestH2H1NoAddXfp(t *testing.T) { 67 st := newServerTester([]string{"--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 68 xfp := r.Header.Get("X-Forwarded-Proto") 69 if got, want := xfp, "foo"; got != want { 70 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 71 } 72 }) 73 defer st.Close() 74 75 res, err := st.http2(requestParam{ 76 name: "TestH2H1NoAddXfp", 77 header: []hpack.HeaderField{ 78 pair("x-forwarded-proto", "foo"), 79 }, 80 }) 81 if err != nil { 82 t.Fatalf("Error st.http2() = %v", err) 83 } 84 if got, want := res.status, 200; got != want { 85 t.Errorf("status = %v; want %v", got, want) 86 } 87} 88 89// TestH2H1StripXfp tests that server strips incoming 90// x-forwarded-proto header field. 91func TestH2H1StripXfp(t *testing.T) { 92 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 93 xfp := r.Header.Get("X-Forwarded-Proto") 94 if got, want := xfp, "http"; got != want { 95 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 96 } 97 }) 98 defer st.Close() 99 100 res, err := st.http2(requestParam{ 101 name: "TestH2H1StripXfp", 102 header: []hpack.HeaderField{ 103 pair("x-forwarded-proto", "foo"), 104 }, 105 }) 106 if err != nil { 107 t.Fatalf("Error st.http2() = %v", err) 108 } 109 if got, want := res.status, 200; got != want { 110 t.Errorf("status = %v; want %v", got, want) 111 } 112} 113 114// TestH2H1StripNoAddXfp tests that server strips incoming 115// x-forwarded-proto header field, and does not add another. 116func TestH2H1StripNoAddXfp(t *testing.T) { 117 st := newServerTester([]string{"--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 118 if got, found := r.Header["X-Forwarded-Proto"]; found { 119 t.Errorf("X-Forwarded-Proto = %q; want nothing", got) 120 } 121 }) 122 defer st.Close() 123 124 res, err := st.http2(requestParam{ 125 name: "TestH2H1StripNoAddXfp", 126 header: []hpack.HeaderField{ 127 pair("x-forwarded-proto", "foo"), 128 }, 129 }) 130 if err != nil { 131 t.Fatalf("Error st.http2() = %v", err) 132 } 133 if got, want := res.status, 200; got != want { 134 t.Errorf("status = %v; want %v", got, want) 135 } 136} 137 138// TestH2H1AddXff tests that server generates X-Forwarded-For header 139// field when forwarding request to backend. 140func TestH2H1AddXff(t *testing.T) { 141 st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 142 xff := r.Header.Get("X-Forwarded-For") 143 want := "127.0.0.1" 144 if xff != want { 145 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 146 } 147 }) 148 defer st.Close() 149 150 res, err := st.http2(requestParam{ 151 name: "TestH2H1AddXff", 152 }) 153 if err != nil { 154 t.Fatalf("Error st.http2() = %v", err) 155 } 156 if got, want := res.status, 200; got != want { 157 t.Errorf("status = %v; want %v", got, want) 158 } 159} 160 161// TestH2H1AddXff2 tests that server appends X-Forwarded-For header 162// field to existing one when forwarding request to backend. 163func TestH2H1AddXff2(t *testing.T) { 164 st := newServerTester([]string{"--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 165 xff := r.Header.Get("X-Forwarded-For") 166 want := "host, 127.0.0.1" 167 if xff != want { 168 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 169 } 170 }) 171 defer st.Close() 172 173 res, err := st.http2(requestParam{ 174 name: "TestH2H1AddXff2", 175 header: []hpack.HeaderField{ 176 pair("x-forwarded-for", "host"), 177 }, 178 }) 179 if err != nil { 180 t.Fatalf("Error st.http2() = %v", err) 181 } 182 if got, want := res.status, 200; got != want { 183 t.Errorf("status = %v; want %v", got, want) 184 } 185} 186 187// TestH2H1StripXff tests that --strip-incoming-x-forwarded-for 188// option. 189func TestH2H1StripXff(t *testing.T) { 190 st := newServerTester([]string{"--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 191 if xff, found := r.Header["X-Forwarded-For"]; found { 192 t.Errorf("X-Forwarded-For = %v; want nothing", xff) 193 } 194 }) 195 defer st.Close() 196 197 res, err := st.http2(requestParam{ 198 name: "TestH2H1StripXff", 199 header: []hpack.HeaderField{ 200 pair("x-forwarded-for", "host"), 201 }, 202 }) 203 if err != nil { 204 t.Fatalf("Error st.http2() = %v", err) 205 } 206 if got, want := res.status, 200; got != want { 207 t.Errorf("status = %v; want %v", got, want) 208 } 209} 210 211// TestH2H1StripAddXff tests that --strip-incoming-x-forwarded-for and 212// --add-x-forwarded-for options. 213func TestH2H1StripAddXff(t *testing.T) { 214 args := []string{ 215 "--strip-incoming-x-forwarded-for", 216 "--add-x-forwarded-for", 217 } 218 st := newServerTester(args, t, func(w http.ResponseWriter, r *http.Request) { 219 xff := r.Header.Get("X-Forwarded-For") 220 want := "127.0.0.1" 221 if xff != want { 222 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 223 } 224 }) 225 defer st.Close() 226 227 res, err := st.http2(requestParam{ 228 name: "TestH2H1StripAddXff", 229 header: []hpack.HeaderField{ 230 pair("x-forwarded-for", "host"), 231 }, 232 }) 233 if err != nil { 234 t.Fatalf("Error st.http2() = %v", err) 235 } 236 if got, want := res.status, 200; got != want { 237 t.Errorf("status = %v; want %v", got, want) 238 } 239} 240 241// TestH2H1AddForwardedObfuscated tests that server generates 242// Forwarded header field with obfuscated "by" and "for" parameters. 243func TestH2H1AddForwardedObfuscated(t *testing.T) { 244 st := newServerTester([]string{"--add-forwarded=by,for,host,proto"}, t, func(w http.ResponseWriter, r *http.Request) { 245 pattern := fmt.Sprintf(`by=_[^;]+;for=_[^;]+;host="127\.0\.0\.1:%v";proto=http`, serverPort) 246 validFwd := regexp.MustCompile(pattern) 247 got := r.Header.Get("Forwarded") 248 249 if !validFwd.MatchString(got) { 250 t.Errorf("Forwarded = %v; want pattern %v", got, pattern) 251 } 252 }) 253 defer st.Close() 254 255 res, err := st.http2(requestParam{ 256 name: "TestH2H1AddForwardedObfuscated", 257 }) 258 if err != nil { 259 t.Fatalf("Error st.http2() = %v", err) 260 } 261 if got, want := res.status, 200; got != want { 262 t.Errorf("status: %v; want %v", got, want) 263 } 264} 265 266// TestH2H1AddForwardedByIP tests that server generates Forwarded header 267// field with IP address in "by" parameter. 268func TestH2H1AddForwardedByIP(t *testing.T) { 269 st := newServerTester([]string{"--add-forwarded=by,for", "--forwarded-by=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 270 pattern := fmt.Sprintf(`by="127\.0\.0\.1:%v";for=_[^;]+`, serverPort) 271 validFwd := regexp.MustCompile(pattern) 272 if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { 273 t.Errorf("Forwarded = %v; want pattern %v", got, pattern) 274 } 275 }) 276 defer st.Close() 277 278 res, err := st.http2(requestParam{ 279 name: "TestH2H1AddForwardedByIP", 280 }) 281 if err != nil { 282 t.Fatalf("Error st.http2() = %v", err) 283 } 284 if got, want := res.status, 200; got != want { 285 t.Errorf("status: %v; want %v", got, want) 286 } 287} 288 289// TestH2H1AddForwardedForIP tests that server generates Forwarded header 290// field with IP address in "for" parameters. 291func TestH2H1AddForwardedForIP(t *testing.T) { 292 st := newServerTester([]string{"--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 293 want := fmt.Sprintf(`by=_alpha;for=127.0.0.1;host="127.0.0.1:%v";proto=http`, serverPort) 294 if got := r.Header.Get("Forwarded"); got != want { 295 t.Errorf("Forwarded = %v; want %v", got, want) 296 } 297 }) 298 defer st.Close() 299 300 res, err := st.http2(requestParam{ 301 name: "TestH2H1AddForwardedForIP", 302 }) 303 if err != nil { 304 t.Fatalf("Error st.http2() = %v", err) 305 } 306 if got, want := res.status, 200; got != want { 307 t.Errorf("status: %v; want %v", got, want) 308 } 309} 310 311// TestH2H1AddForwardedMerge tests that server generates Forwarded 312// header field with IP address in "by" and "for" parameters. The 313// generated values must be appended to the existing value. 314func TestH2H1AddForwardedMerge(t *testing.T) { 315 st := newServerTester([]string{"--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) { 316 if got, want := r.Header.Get("Forwarded"), `host=foo, proto=http`; got != want { 317 t.Errorf("Forwarded = %v; want %v", got, want) 318 } 319 }) 320 defer st.Close() 321 322 res, err := st.http2(requestParam{ 323 name: "TestH2H1AddForwardedMerge", 324 header: []hpack.HeaderField{ 325 pair("forwarded", "host=foo"), 326 }, 327 }) 328 if err != nil { 329 t.Fatalf("Error st.http2() = %v", err) 330 } 331 if got, want := res.status, 200; got != want { 332 t.Errorf("status: %v; want %v", got, want) 333 } 334} 335 336// TestH2H1AddForwardedStrip tests that server generates Forwarded 337// header field with IP address in "by" and "for" parameters. The 338// generated values must not include the existing value. 339func TestH2H1AddForwardedStrip(t *testing.T) { 340 st := newServerTester([]string{"--strip-incoming-forwarded", "--add-forwarded=proto"}, t, func(w http.ResponseWriter, r *http.Request) { 341 if got, want := r.Header.Get("Forwarded"), `proto=http`; got != want { 342 t.Errorf("Forwarded = %v; want %v", got, want) 343 } 344 }) 345 defer st.Close() 346 347 res, err := st.http2(requestParam{ 348 name: "TestH2H1AddForwardedStrip", 349 header: []hpack.HeaderField{ 350 pair("forwarded", "host=foo"), 351 }, 352 }) 353 if err != nil { 354 t.Fatalf("Error st.http2() = %v", err) 355 } 356 if got, want := res.status, 200; got != want { 357 t.Errorf("status: %v; want %v", got, want) 358 } 359} 360 361// TestH2H1StripForwarded tests that server strips incoming Forwarded 362// header field. 363func TestH2H1StripForwarded(t *testing.T) { 364 st := newServerTester([]string{"--strip-incoming-forwarded"}, t, func(w http.ResponseWriter, r *http.Request) { 365 if got, found := r.Header["Forwarded"]; found { 366 t.Errorf("Forwarded = %v; want nothing", got) 367 } 368 }) 369 defer st.Close() 370 371 res, err := st.http2(requestParam{ 372 name: "TestH2H1StripForwarded", 373 header: []hpack.HeaderField{ 374 pair("forwarded", "host=foo"), 375 }, 376 }) 377 if err != nil { 378 t.Fatalf("Error st.http2() = %v", err) 379 } 380 if got, want := res.status, 200; got != want { 381 t.Errorf("status: %v; want %v", got, want) 382 } 383} 384 385// TestH2H1AddForwardedStatic tests that server generates Forwarded 386// header field with the given static obfuscated string for "by" 387// parameter. 388func TestH2H1AddForwardedStatic(t *testing.T) { 389 st := newServerTester([]string{"--add-forwarded=by,for", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) { 390 pattern := `by=_alpha;for=_[^;]+` 391 validFwd := regexp.MustCompile(pattern) 392 if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { 393 t.Errorf("Forwarded = %v; want pattern %v", got, pattern) 394 } 395 }) 396 defer st.Close() 397 398 res, err := st.http2(requestParam{ 399 name: "TestH2H1AddForwardedStatic", 400 }) 401 if err != nil { 402 t.Fatalf("Error st.http2() = %v", err) 403 } 404 if got, want := res.status, 200; got != want { 405 t.Errorf("status: %v; want %v", got, want) 406 } 407} 408 409// TestH2H1GenerateVia tests that server generates Via header field to and 410// from backend server. 411func TestH2H1GenerateVia(t *testing.T) { 412 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 413 if got, want := r.Header.Get("Via"), "2 nghttpx"; got != want { 414 t.Errorf("Via: %v; want %v", got, want) 415 } 416 }) 417 defer st.Close() 418 419 res, err := st.http2(requestParam{ 420 name: "TestH2H1GenerateVia", 421 }) 422 if err != nil { 423 t.Fatalf("Error st.http2() = %v", err) 424 } 425 if got, want := res.header.Get("Via"), "1.1 nghttpx"; got != want { 426 t.Errorf("Via: %v; want %v", got, want) 427 } 428} 429 430// TestH2H1AppendVia tests that server adds value to existing Via 431// header field to and from backend server. 432func TestH2H1AppendVia(t *testing.T) { 433 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 434 if got, want := r.Header.Get("Via"), "foo, 2 nghttpx"; got != want { 435 t.Errorf("Via: %v; want %v", got, want) 436 } 437 w.Header().Add("Via", "bar") 438 }) 439 defer st.Close() 440 441 res, err := st.http2(requestParam{ 442 name: "TestH2H1AppendVia", 443 header: []hpack.HeaderField{ 444 pair("via", "foo"), 445 }, 446 }) 447 if err != nil { 448 t.Fatalf("Error st.http2() = %v", err) 449 } 450 if got, want := res.header.Get("Via"), "bar, 1.1 nghttpx"; got != want { 451 t.Errorf("Via: %v; want %v", got, want) 452 } 453} 454 455// TestH2H1NoVia tests that server does not add value to existing Via 456// header field to and from backend server. 457func TestH2H1NoVia(t *testing.T) { 458 st := newServerTester([]string{"--no-via"}, t, func(w http.ResponseWriter, r *http.Request) { 459 if got, want := r.Header.Get("Via"), "foo"; got != want { 460 t.Errorf("Via: %v; want %v", got, want) 461 } 462 w.Header().Add("Via", "bar") 463 }) 464 defer st.Close() 465 466 res, err := st.http2(requestParam{ 467 name: "TestH2H1NoVia", 468 header: []hpack.HeaderField{ 469 pair("via", "foo"), 470 }, 471 }) 472 if err != nil { 473 t.Fatalf("Error st.http2() = %v", err) 474 } 475 if got, want := res.header.Get("Via"), "bar"; got != want { 476 t.Errorf("Via: %v; want %v", got, want) 477 } 478} 479 480// TestH2H1HostRewrite tests that server rewrites host header field 481func TestH2H1HostRewrite(t *testing.T) { 482 st := newServerTester([]string{"--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) { 483 w.Header().Add("request-host", r.Host) 484 }) 485 defer st.Close() 486 487 res, err := st.http2(requestParam{ 488 name: "TestH2H1HostRewrite", 489 }) 490 if err != nil { 491 t.Fatalf("Error st.http2() = %v", err) 492 } 493 if got, want := res.status, 200; got != want { 494 t.Errorf("status: %v; want %v", got, want) 495 } 496 if got, want := res.header.Get("request-host"), st.backendHost; got != want { 497 t.Errorf("request-host: %v; want %v", got, want) 498 } 499} 500 501// TestH2H1NoHostRewrite tests that server does not rewrite host 502// header field 503func TestH2H1NoHostRewrite(t *testing.T) { 504 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 505 w.Header().Add("request-host", r.Host) 506 }) 507 defer st.Close() 508 509 res, err := st.http2(requestParam{ 510 name: "TestH2H1NoHostRewrite", 511 }) 512 if err != nil { 513 t.Fatalf("Error st.http2() = %v", err) 514 } 515 if got, want := res.status, 200; got != want { 516 t.Errorf("status: %v; want %v", got, want) 517 } 518 if got, want := res.header.Get("request-host"), st.frontendHost; got != want { 519 t.Errorf("request-host: %v; want %v", got, want) 520 } 521} 522 523// TestH2H1BadRequestCL tests that server rejects request whose 524// content-length header field value does not match its request body 525// size. 526func TestH2H1BadRequestCL(t *testing.T) { 527 st := newServerTester(nil, t, noopHandler) 528 defer st.Close() 529 530 // we set content-length: 1024, but the actual request body is 531 // 3 bytes. 532 res, err := st.http2(requestParam{ 533 name: "TestH2H1BadRequestCL", 534 method: "POST", 535 header: []hpack.HeaderField{ 536 pair("content-length", "1024"), 537 }, 538 body: []byte("foo"), 539 }) 540 if err != nil { 541 t.Fatalf("Error st.http2() = %v", err) 542 } 543 544 want := http2.ErrCodeProtocol 545 if res.errCode != want { 546 t.Errorf("res.errCode = %v; want %v", res.errCode, want) 547 } 548} 549 550// TestH2H1BadResponseCL tests that server returns error when 551// content-length response header field value does not match its 552// response body size. 553func TestH2H1BadResponseCL(t *testing.T) { 554 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 555 // we set content-length: 1024, but only send 3 bytes. 556 w.Header().Add("Content-Length", "1024") 557 w.Write([]byte("foo")) 558 }) 559 defer st.Close() 560 561 res, err := st.http2(requestParam{ 562 name: "TestH2H1BadResponseCL", 563 }) 564 if err != nil { 565 t.Fatalf("Error st.http2() = %v", err) 566 } 567 568 want := http2.ErrCodeProtocol 569 if res.errCode != want { 570 t.Errorf("res.errCode = %v; want %v", res.errCode, want) 571 } 572} 573 574// TestH2H1LocationRewrite tests location header field rewriting 575// works. 576func TestH2H1LocationRewrite(t *testing.T) { 577 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 578 // TODO we cannot get st.ts's port number here.. 8443 579 // is just a place holder. We ignore it on rewrite. 580 w.Header().Add("Location", "http://127.0.0.1:8443/p/q?a=b#fragment") 581 }) 582 defer st.Close() 583 584 res, err := st.http2(requestParam{ 585 name: "TestH2H1LocationRewrite", 586 }) 587 if err != nil { 588 t.Fatalf("Error st.http2() = %v", err) 589 } 590 591 want := fmt.Sprintf("http://127.0.0.1:%v/p/q?a=b#fragment", serverPort) 592 if got := res.header.Get("Location"); got != want { 593 t.Errorf("Location: %v; want %v", got, want) 594 } 595} 596 597// TestH2H1ChunkedRequestBody tests that chunked request body works. 598func TestH2H1ChunkedRequestBody(t *testing.T) { 599 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 600 want := "[chunked]" 601 if got := fmt.Sprint(r.TransferEncoding); got != want { 602 t.Errorf("Transfer-Encoding: %v; want %v", got, want) 603 } 604 body, err := ioutil.ReadAll(r.Body) 605 if err != nil { 606 t.Fatalf("Error reading r.body: %v", err) 607 } 608 want = "foo" 609 if got := string(body); got != want { 610 t.Errorf("body: %v; want %v", got, want) 611 } 612 }) 613 defer st.Close() 614 615 res, err := st.http2(requestParam{ 616 name: "TestH2H1ChunkedRequestBody", 617 method: "POST", 618 body: []byte("foo"), 619 }) 620 if err != nil { 621 t.Fatalf("Error st.http2() = %v", err) 622 } 623 if got, want := res.status, 200; got != want { 624 t.Errorf("status = %v; want %v", got, want) 625 } 626} 627 628// TestH2H1MultipleRequestCL tests that server rejects request with 629// multiple Content-Length request header fields. 630func TestH2H1MultipleRequestCL(t *testing.T) { 631 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 632 t.Errorf("server should not forward bad request") 633 }) 634 defer st.Close() 635 636 res, err := st.http2(requestParam{ 637 name: "TestH2H1MultipleRequestCL", 638 header: []hpack.HeaderField{ 639 pair("content-length", "1"), 640 pair("content-length", "1"), 641 }, 642 }) 643 if err != nil { 644 t.Fatalf("Error st.http2() = %v", err) 645 } 646 if got, want := res.errCode, http2.ErrCodeProtocol; got != want { 647 t.Errorf("res.errCode: %v; want %v", got, want) 648 } 649} 650 651// TestH2H1InvalidRequestCL tests that server rejects request with 652// Content-Length which cannot be parsed as a number. 653func TestH2H1InvalidRequestCL(t *testing.T) { 654 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 655 t.Errorf("server should not forward bad request") 656 }) 657 defer st.Close() 658 659 res, err := st.http2(requestParam{ 660 name: "TestH2H1InvalidRequestCL", 661 header: []hpack.HeaderField{ 662 pair("content-length", ""), 663 }, 664 }) 665 if err != nil { 666 t.Fatalf("Error st.http2() = %v", err) 667 } 668 if got, want := res.errCode, http2.ErrCodeProtocol; got != want { 669 t.Errorf("res.errCode: %v; want %v", got, want) 670 } 671} 672 673// // TestH2H1ConnectFailure tests that server handles the situation that 674// // connection attempt to HTTP/1 backend failed. 675// func TestH2H1ConnectFailure(t *testing.T) { 676// st := newServerTester(nil, t, noopHandler) 677// defer st.Close() 678 679// // shutdown backend server to simulate backend connect failure 680// st.ts.Close() 681 682// res, err := st.http2(requestParam{ 683// name: "TestH2H1ConnectFailure", 684// }) 685// if err != nil { 686// t.Fatalf("Error st.http2() = %v", err) 687// } 688// want := 503 689// if got := res.status; got != want { 690// t.Errorf("status: %v; want %v", got, want) 691// } 692// } 693 694// TestH2H1InvalidMethod tests that server rejects invalid method with 695// 501. 696func TestH2H1InvalidMethod(t *testing.T) { 697 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 698 t.Errorf("server should not forward this request") 699 }) 700 defer st.Close() 701 702 res, err := st.http2(requestParam{ 703 name: "TestH2H1InvalidMethod", 704 method: "get", 705 }) 706 if err != nil { 707 t.Fatalf("Error st.http2() = %v", err) 708 } 709 if got, want := res.status, 501; got != want { 710 t.Errorf("status: %v; want %v", got, want) 711 } 712} 713 714// TestH2H1BadAuthority tests that server rejects request including 715// bad characters in :authority header field. 716func TestH2H1BadAuthority(t *testing.T) { 717 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 718 t.Errorf("server should not forward this request") 719 }) 720 defer st.Close() 721 722 res, err := st.http2(requestParam{ 723 name: "TestH2H1BadAuthority", 724 authority: `foo\bar`, 725 }) 726 if err != nil { 727 t.Fatalf("Error st.http2() = %v", err) 728 } 729 if got, want := res.errCode, http2.ErrCodeProtocol; got != want { 730 t.Errorf("res.errCode: %v; want %v", got, want) 731 } 732} 733 734// TestH2H1BadScheme tests that server rejects request including 735// bad characters in :scheme header field. 736func TestH2H1BadScheme(t *testing.T) { 737 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 738 t.Errorf("server should not forward this request") 739 }) 740 defer st.Close() 741 742 res, err := st.http2(requestParam{ 743 name: "TestH2H1BadScheme", 744 scheme: "http*", 745 }) 746 if err != nil { 747 t.Fatalf("Error st.http2() = %v", err) 748 } 749 if got, want := res.errCode, http2.ErrCodeProtocol; got != want { 750 t.Errorf("res.errCode: %v; want %v", got, want) 751 } 752} 753 754// TestH2H1AssembleCookies tests that crumbled cookies in HTTP/2 755// request is assembled into 1 when forwarding to HTTP/1 backend link. 756func TestH2H1AssembleCookies(t *testing.T) { 757 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 758 if got, want := r.Header.Get("Cookie"), "alpha; bravo; charlie"; got != want { 759 t.Errorf("Cookie: %v; want %v", got, want) 760 } 761 }) 762 defer st.Close() 763 764 res, err := st.http2(requestParam{ 765 name: "TestH2H1AssembleCookies", 766 header: []hpack.HeaderField{ 767 pair("cookie", "alpha"), 768 pair("cookie", "bravo"), 769 pair("cookie", "charlie"), 770 }, 771 }) 772 if err != nil { 773 t.Fatalf("Error st.http2() = %v", err) 774 } 775 if got, want := res.status, 200; got != want { 776 t.Errorf("status: %v; want %v", got, want) 777 } 778} 779 780// TestH2H1TETrailers tests that server accepts TE request header 781// field if it has trailers only. 782func TestH2H1TETrailers(t *testing.T) { 783 st := newServerTester(nil, t, noopHandler) 784 defer st.Close() 785 786 res, err := st.http2(requestParam{ 787 name: "TestH2H1TETrailers", 788 header: []hpack.HeaderField{ 789 pair("te", "trailers"), 790 }, 791 }) 792 if err != nil { 793 t.Fatalf("Error st.http2() = %v", err) 794 } 795 if got, want := res.status, 200; got != want { 796 t.Errorf("status: %v; want %v", got, want) 797 } 798} 799 800// TestH2H1TEGzip tests that server resets stream if TE request header 801// field contains gzip. 802func TestH2H1TEGzip(t *testing.T) { 803 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 804 t.Error("server should not forward bad request") 805 }) 806 defer st.Close() 807 808 res, err := st.http2(requestParam{ 809 name: "TestH2H1TEGzip", 810 header: []hpack.HeaderField{ 811 pair("te", "gzip"), 812 }, 813 }) 814 if err != nil { 815 t.Fatalf("Error st.http2() = %v", err) 816 } 817 if got, want := res.errCode, http2.ErrCodeProtocol; got != want { 818 t.Errorf("res.errCode = %v; want %v", res.errCode, want) 819 } 820} 821 822// TestH2H1SNI tests server's TLS SNI extension feature. It must 823// choose appropriate certificate depending on the indicated 824// server_name from client. 825func TestH2H1SNI(t *testing.T) { 826 st := newServerTesterTLSConfig([]string{"--subcert=" + testDir + "/alt-server.key:" + testDir + "/alt-server.crt"}, t, noopHandler, &tls.Config{ 827 ServerName: "alt-domain", 828 }) 829 defer st.Close() 830 831 tlsConn := st.conn.(*tls.Conn) 832 connState := tlsConn.ConnectionState() 833 cert := connState.PeerCertificates[0] 834 835 if got, want := cert.Subject.CommonName, "alt-domain"; got != want { 836 t.Errorf("CommonName: %v; want %v", got, want) 837 } 838} 839 840// TestH2H1TLSXfp tests nghttpx sends x-forwarded-proto header field 841// with http value since :scheme is http, even if the frontend 842// connection is encrypted. 843func TestH2H1TLSXfp(t *testing.T) { 844 st := newServerTesterTLS(nil, t, func(w http.ResponseWriter, r *http.Request) { 845 if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want { 846 t.Errorf("x-forwarded-proto: want %v; got %v", want, got) 847 } 848 }) 849 defer st.Close() 850 851 res, err := st.http2(requestParam{ 852 name: "TestH2H1TLSXfp", 853 }) 854 if err != nil { 855 t.Fatalf("Error st.http2() = %v", err) 856 } 857 if got, want := res.status, 200; got != want { 858 t.Errorf("res.status: %v; want %v", got, want) 859 } 860} 861 862// TestH2H1ServerPush tests server push using Link header field from 863// backend server. 864func TestH2H1ServerPush(t *testing.T) { 865 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 866 // only resources marked as rel=preload are pushed 867 if !strings.HasPrefix(r.URL.Path, "/css/") { 868 w.Header().Add("Link", "</css/main.css>; rel=preload, </foo>, </css/theme.css>; rel=preload") 869 } 870 }) 871 defer st.Close() 872 873 res, err := st.http2(requestParam{ 874 name: "TestH2H1ServerPush", 875 }) 876 if err != nil { 877 t.Fatalf("Error st.http2() = %v", err) 878 } 879 if got, want := res.status, 200; got != want { 880 t.Errorf("res.status: %v; want %v", got, want) 881 } 882 if got, want := len(res.pushResponse), 2; got != want { 883 t.Fatalf("len(res.pushResponse): %v; want %v", got, want) 884 } 885 mainCSS := res.pushResponse[0] 886 if got, want := mainCSS.status, 200; got != want { 887 t.Errorf("mainCSS.status: %v; want %v", got, want) 888 } 889 themeCSS := res.pushResponse[1] 890 if got, want := themeCSS.status, 200; got != want { 891 t.Errorf("themeCSS.status: %v; want %v", got, want) 892 } 893} 894 895// TestH2H1RequestTrailer tests request trailer part is forwarded to 896// backend. 897func TestH2H1RequestTrailer(t *testing.T) { 898 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 899 buf := make([]byte, 4096) 900 for { 901 _, err := r.Body.Read(buf) 902 if err == io.EOF { 903 break 904 } 905 if err != nil { 906 t.Fatalf("r.Body.Read() = %v", err) 907 } 908 } 909 if got, want := r.Trailer.Get("foo"), "bar"; got != want { 910 t.Errorf("r.Trailer.Get(foo): %v; want %v", got, want) 911 } 912 }) 913 defer st.Close() 914 915 res, err := st.http2(requestParam{ 916 name: "TestH2H1RequestTrailer", 917 body: []byte("1"), 918 trailer: []hpack.HeaderField{ 919 pair("foo", "bar"), 920 }, 921 }) 922 if err != nil { 923 t.Fatalf("Error st.http2() = %v", err) 924 } 925 if got, want := res.status, 200; got != want { 926 t.Errorf("res.status: %v; want %v", got, want) 927 } 928} 929 930// TestH2H1HeaderFieldBuffer tests that request with header fields 931// larger than configured buffer size is rejected. 932func TestH2H1HeaderFieldBuffer(t *testing.T) { 933 st := newServerTester([]string{"--request-header-field-buffer=10"}, t, func(w http.ResponseWriter, r *http.Request) { 934 t.Fatal("execution path should not be here") 935 }) 936 defer st.Close() 937 938 res, err := st.http2(requestParam{ 939 name: "TestH2H1HeaderFieldBuffer", 940 }) 941 if err != nil { 942 t.Fatalf("Error st.http2() = %v", err) 943 } 944 if got, want := res.status, 431; got != want { 945 t.Errorf("status: %v; want %v", got, want) 946 } 947} 948 949// TestH2H1HeaderFields tests that request with header fields more 950// than configured number is rejected. 951func TestH2H1HeaderFields(t *testing.T) { 952 st := newServerTester([]string{"--max-request-header-fields=1"}, t, func(w http.ResponseWriter, r *http.Request) { 953 t.Fatal("execution path should not be here") 954 }) 955 defer st.Close() 956 957 res, err := st.http2(requestParam{ 958 name: "TestH2H1HeaderFields", 959 // we have at least 4 pseudo-header fields sent, and 960 // that ensures that buffer limit exceeds. 961 }) 962 if err != nil { 963 t.Fatalf("Error st.http2() = %v", err) 964 } 965 if got, want := res.status, 431; got != want { 966 t.Errorf("status: %v; want %v", got, want) 967 } 968} 969 970// TestH2H1ReqPhaseSetHeader tests mruby request phase hook 971// modifies request header fields. 972func TestH2H1ReqPhaseSetHeader(t *testing.T) { 973 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-set-header.rb"}, t, func(w http.ResponseWriter, r *http.Request) { 974 if got, want := r.Header.Get("User-Agent"), "mruby"; got != want { 975 t.Errorf("User-Agent = %v; want %v", got, want) 976 } 977 }) 978 defer st.Close() 979 980 res, err := st.http2(requestParam{ 981 name: "TestH2H1ReqPhaseSetHeader", 982 }) 983 if err != nil { 984 t.Fatalf("Error st.http2() = %v", err) 985 } 986 987 if got, want := res.status, 200; got != want { 988 t.Errorf("status = %v; want %v", got, want) 989 } 990} 991 992// TestH2H1ReqPhaseReturn tests mruby request phase hook returns 993// custom response. 994func TestH2H1ReqPhaseReturn(t *testing.T) { 995 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) { 996 t.Fatalf("request should not be forwarded") 997 }) 998 defer st.Close() 999 1000 res, err := st.http2(requestParam{ 1001 name: "TestH2H1ReqPhaseReturn", 1002 }) 1003 if err != nil { 1004 t.Fatalf("Error st.http2() = %v", err) 1005 } 1006 1007 if got, want := res.status, 404; got != want { 1008 t.Errorf("status = %v; want %v", got, want) 1009 } 1010 1011 hdtests := []struct { 1012 k, v string 1013 }{ 1014 {"content-length", "20"}, 1015 {"from", "mruby"}, 1016 } 1017 for _, tt := range hdtests { 1018 if got, want := res.header.Get(tt.k), tt.v; got != want { 1019 t.Errorf("%v = %v; want %v", tt.k, got, want) 1020 } 1021 } 1022 1023 if got, want := string(res.body), "Hello World from req"; got != want { 1024 t.Errorf("body = %v; want %v", got, want) 1025 } 1026} 1027 1028// TestH2H1RespPhaseSetHeader tests mruby response phase hook modifies 1029// response header fields. 1030func TestH2H1RespPhaseSetHeader(t *testing.T) { 1031 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-set-header.rb"}, t, noopHandler) 1032 defer st.Close() 1033 1034 res, err := st.http2(requestParam{ 1035 name: "TestH2H1RespPhaseSetHeader", 1036 }) 1037 if err != nil { 1038 t.Fatalf("Error st.http2() = %v", err) 1039 } 1040 1041 if got, want := res.status, 200; got != want { 1042 t.Errorf("status = %v; want %v", got, want) 1043 } 1044 1045 if got, want := res.header.Get("alpha"), "bravo"; got != want { 1046 t.Errorf("alpha = %v; want %v", got, want) 1047 } 1048} 1049 1050// TestH2H1RespPhaseReturn tests mruby response phase hook returns 1051// custom response. 1052func TestH2H1RespPhaseReturn(t *testing.T) { 1053 st := newServerTester([]string{"--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler) 1054 defer st.Close() 1055 1056 res, err := st.http2(requestParam{ 1057 name: "TestH2H1RespPhaseReturn", 1058 }) 1059 if err != nil { 1060 t.Fatalf("Error st.http2() = %v", err) 1061 } 1062 1063 if got, want := res.status, 404; got != want { 1064 t.Errorf("status = %v; want %v", got, want) 1065 } 1066 1067 hdtests := []struct { 1068 k, v string 1069 }{ 1070 {"content-length", "21"}, 1071 {"from", "mruby"}, 1072 } 1073 for _, tt := range hdtests { 1074 if got, want := res.header.Get(tt.k), tt.v; got != want { 1075 t.Errorf("%v = %v; want %v", tt.k, got, want) 1076 } 1077 } 1078 1079 if got, want := string(res.body), "Hello World from resp"; got != want { 1080 t.Errorf("body = %v; want %v", got, want) 1081 } 1082} 1083 1084// TestH2H1Upgrade tests HTTP Upgrade to HTTP/2 1085func TestH2H1Upgrade(t *testing.T) { 1086 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) {}) 1087 defer st.Close() 1088 1089 res, err := st.http1(requestParam{ 1090 name: "TestH2H1Upgrade", 1091 header: []hpack.HeaderField{ 1092 pair("Connection", "Upgrade, HTTP2-Settings"), 1093 pair("Upgrade", "h2c"), 1094 pair("HTTP2-Settings", "AAMAAABkAAQAAP__"), 1095 }, 1096 }) 1097 1098 if err != nil { 1099 t.Fatalf("Error st.http1() = %v", err) 1100 } 1101 1102 if got, want := res.status, 101; got != want { 1103 t.Errorf("res.status: %v; want %v", got, want) 1104 } 1105 1106 res, err = st.http2(requestParam{ 1107 httpUpgrade: true, 1108 }) 1109 if err != nil { 1110 t.Fatalf("Error st.http2() = %v", err) 1111 } 1112 if got, want := res.status, 200; got != want { 1113 t.Errorf("res.status: %v; want %v", got, want) 1114 } 1115} 1116 1117// TestH2H1ProxyProtocolV1ForwardedForObfuscated tests that Forwarded 1118// header field includes obfuscated address even if PROXY protocol 1119// version 1 containing TCP4 entry is accepted. 1120func TestH2H1ProxyProtocolV1ForwardedForObfuscated(t *testing.T) { 1121 pattern := fmt.Sprintf(`^for=_[^;]+$`) 1122 validFwd := regexp.MustCompile(pattern) 1123 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=obfuscated"}, t, func(w http.ResponseWriter, r *http.Request) { 1124 if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { 1125 t.Errorf("Forwarded: %v; want pattern %v", got, pattern) 1126 } 1127 }) 1128 defer st.Close() 1129 1130 st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n")) 1131 1132 res, err := st.http2(requestParam{ 1133 name: "TestH2H1ProxyProtocolV1ForwardedForObfuscated", 1134 }) 1135 1136 if err != nil { 1137 t.Fatalf("Error st.http2() = %v", err) 1138 } 1139 1140 if got, want := res.status, 200; got != want { 1141 t.Errorf("res.status: %v; want %v", got, want) 1142 } 1143} 1144 1145// TestH2H1ProxyProtocolV1TCP4 tests PROXY protocol version 1 1146// containing TCP4 entry is accepted and X-Forwarded-For contains 1147// advertised src address. 1148func TestH2H1ProxyProtocolV1TCP4(t *testing.T) { 1149 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1150 if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { 1151 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1152 } 1153 if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want { 1154 t.Errorf("Forwarded: %v; want %v", got, want) 1155 } 1156 }) 1157 defer st.Close() 1158 1159 st.conn.Write([]byte("PROXY TCP4 192.168.0.2 192.168.0.100 12345 8080\r\n")) 1160 1161 res, err := st.http2(requestParam{ 1162 name: "TestH2H1ProxyProtocolV1TCP4", 1163 }) 1164 1165 if err != nil { 1166 t.Fatalf("Error st.http2() = %v", err) 1167 } 1168 1169 if got, want := res.status, 200; got != want { 1170 t.Errorf("res.status: %v; want %v", got, want) 1171 } 1172} 1173 1174// TestH2H1ProxyProtocolV1TCP6 tests PROXY protocol version 1 1175// containing TCP6 entry is accepted and X-Forwarded-For contains 1176// advertised src address. 1177func TestH2H1ProxyProtocolV1TCP6(t *testing.T) { 1178 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1179 if got, want := r.Header.Get("X-Forwarded-For"), "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; got != want { 1180 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1181 } 1182 if got, want := r.Header.Get("Forwarded"), `for="[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"`; got != want { 1183 t.Errorf("Forwarded: %v; want %v", got, want) 1184 } 1185 }) 1186 defer st.Close() 1187 1188 st.conn.Write([]byte("PROXY TCP6 2001:0db8:85a3:0000:0000:8a2e:0370:7334 ::1 12345 8080\r\n")) 1189 1190 res, err := st.http2(requestParam{ 1191 name: "TestH2H1ProxyProtocolV1TCP6", 1192 }) 1193 1194 if err != nil { 1195 t.Fatalf("Error st.http2() = %v", err) 1196 } 1197 1198 if got, want := res.status, 200; got != want { 1199 t.Errorf("res.status: %v; want %v", got, want) 1200 } 1201} 1202 1203// TestH2H1ProxyProtocolV1Unknown tests PROXY protocol version 1 1204// containing UNKNOWN entry is accepted. 1205func TestH2H1ProxyProtocolV1Unknown(t *testing.T) { 1206 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1207 if got, notWant := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got == notWant { 1208 t.Errorf("X-Forwarded-For: %v; want something else", got) 1209 } 1210 if got, notWant := r.Header.Get("Forwarded"), "for=192.168.0.2"; got == notWant { 1211 t.Errorf("Forwarded: %v; want something else", got) 1212 } 1213 }) 1214 defer st.Close() 1215 1216 st.conn.Write([]byte("PROXY UNKNOWN 192.168.0.2 192.168.0.100 12345 8080\r\n")) 1217 1218 res, err := st.http2(requestParam{ 1219 name: "TestH2H1ProxyProtocolV1Unknown", 1220 }) 1221 1222 if err != nil { 1223 t.Fatalf("Error st.http2() = %v", err) 1224 } 1225 1226 if got, want := res.status, 200; got != want { 1227 t.Errorf("res.status: %v; want %v", got, want) 1228 } 1229} 1230 1231// TestH2H1ProxyProtocolV1JustUnknown tests PROXY protocol version 1 1232// containing only "PROXY UNKNOWN" is accepted. 1233func TestH2H1ProxyProtocolV1JustUnknown(t *testing.T) { 1234 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler) 1235 defer st.Close() 1236 1237 st.conn.Write([]byte("PROXY UNKNOWN\r\n")) 1238 1239 res, err := st.http2(requestParam{ 1240 name: "TestH2H1ProxyProtocolV1JustUnknown", 1241 }) 1242 1243 if err != nil { 1244 t.Fatalf("Error st.http2() = %v", err) 1245 } 1246 1247 if got, want := res.status, 200; got != want { 1248 t.Errorf("res.status: %v; want %v", got, want) 1249 } 1250} 1251 1252// TestH2H1ProxyProtocolV1TooLongLine tests PROXY protocol version 1 1253// line longer than 107 bytes must be rejected 1254func TestH2H1ProxyProtocolV1TooLongLine(t *testing.T) { 1255 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for"}, t, noopHandler) 1256 defer st.Close() 1257 1258 st.conn.Write([]byte("PROXY UNKNOWN ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 65535 655350\r\n")) 1259 1260 _, err := st.http2(requestParam{ 1261 name: "TestH2H1ProxyProtocolV1TooLongLine", 1262 }) 1263 1264 if err == nil { 1265 t.Fatalf("connection was not terminated") 1266 } 1267} 1268 1269// TestH2H1ProxyProtocolV1BadLineEnd tests that PROXY protocol version 1270// 1 line ending without \r\n should be rejected. 1271func TestH2H1ProxyProtocolV1BadLineEnd(t *testing.T) { 1272 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1273 defer st.Close() 1274 1275 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080\r \n")) 1276 1277 _, err := st.http2(requestParam{ 1278 name: "TestH2H1ProxyProtocolV1BadLineEnd", 1279 }) 1280 1281 if err == nil { 1282 t.Fatalf("connection was not terminated") 1283 } 1284} 1285 1286// TestH2H1ProxyProtocolV1NoEnd tests that PROXY protocol version 1 1287// line containing no \r\n should be rejected. 1288func TestH2H1ProxyProtocolV1NoEnd(t *testing.T) { 1289 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1290 defer st.Close() 1291 1292 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 8080")) 1293 1294 _, err := st.http2(requestParam{ 1295 name: "TestH2H1ProxyProtocolV1NoEnd", 1296 }) 1297 1298 if err == nil { 1299 t.Fatalf("connection was not terminated") 1300 } 1301} 1302 1303// TestH2H1ProxyProtocolV1EmbeddedNULL tests that PROXY protocol 1304// version 1 line containing NULL character should be rejected. 1305func TestH2H1ProxyProtocolV1EmbeddedNULL(t *testing.T) { 1306 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1307 defer st.Close() 1308 1309 b := []byte("PROXY TCP6 ::1*foo ::1 12345 8080\r\n") 1310 b[14] = 0 1311 st.conn.Write(b) 1312 1313 _, err := st.http2(requestParam{ 1314 name: "TestH2H1ProxyProtocolV1EmbeddedNULL", 1315 }) 1316 1317 if err == nil { 1318 t.Fatalf("connection was not terminated") 1319 } 1320} 1321 1322// TestH2H1ProxyProtocolV1MissingSrcPort tests that PROXY protocol 1323// version 1 line without src port should be rejected. 1324func TestH2H1ProxyProtocolV1MissingSrcPort(t *testing.T) { 1325 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1326 defer st.Close() 1327 1328 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 8080\r\n")) 1329 1330 _, err := st.http2(requestParam{ 1331 name: "TestH2H1ProxyProtocolV1MissingSrcPort", 1332 }) 1333 1334 if err == nil { 1335 t.Fatalf("connection was not terminated") 1336 } 1337} 1338 1339// TestH2H1ProxyProtocolV1MissingDstPort tests that PROXY protocol 1340// version 1 line without dst port should be rejected. 1341func TestH2H1ProxyProtocolV1MissingDstPort(t *testing.T) { 1342 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1343 defer st.Close() 1344 1345 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 \r\n")) 1346 1347 _, err := st.http2(requestParam{ 1348 name: "TestH2H1ProxyProtocolV1MissingDstPort", 1349 }) 1350 1351 if err == nil { 1352 t.Fatalf("connection was not terminated") 1353 } 1354} 1355 1356// TestH2H1ProxyProtocolV1InvalidSrcPort tests that PROXY protocol 1357// containing invalid src port should be rejected. 1358func TestH2H1ProxyProtocolV1InvalidSrcPort(t *testing.T) { 1359 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1360 defer st.Close() 1361 1362 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123x 8080\r\n")) 1363 1364 _, err := st.http2(requestParam{ 1365 name: "TestH2H1ProxyProtocolV1InvalidSrcPort", 1366 }) 1367 1368 if err == nil { 1369 t.Fatalf("connection was not terminated") 1370 } 1371} 1372 1373// TestH2H1ProxyProtocolV1InvalidDstPort tests that PROXY protocol 1374// containing invalid dst port should be rejected. 1375func TestH2H1ProxyProtocolV1InvalidDstPort(t *testing.T) { 1376 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1377 defer st.Close() 1378 1379 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 123456 80x\r\n")) 1380 1381 _, err := st.http2(requestParam{ 1382 name: "TestH2H1ProxyProtocolV1InvalidDstPort", 1383 }) 1384 1385 if err == nil { 1386 t.Fatalf("connection was not terminated") 1387 } 1388} 1389 1390// TestH2H1ProxyProtocolV1LeadingZeroPort tests that PROXY protocol 1391// version 1 line with non zero port with leading zero should be 1392// rejected. 1393func TestH2H1ProxyProtocolV1LeadingZeroPort(t *testing.T) { 1394 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1395 defer st.Close() 1396 1397 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 03000 8080\r\n")) 1398 1399 _, err := st.http2(requestParam{ 1400 name: "TestH2H1ProxyProtocolV1LeadingZeroPort", 1401 }) 1402 1403 if err == nil { 1404 t.Fatalf("connection was not terminated") 1405 } 1406} 1407 1408// TestH2H1ProxyProtocolV1TooLargeSrcPort tests that PROXY protocol 1409// containing too large src port should be rejected. 1410func TestH2H1ProxyProtocolV1TooLargeSrcPort(t *testing.T) { 1411 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1412 defer st.Close() 1413 1414 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 65536 8080\r\n")) 1415 1416 _, err := st.http2(requestParam{ 1417 name: "TestH2H1ProxyProtocolV1TooLargeSrcPort", 1418 }) 1419 1420 if err == nil { 1421 t.Fatalf("connection was not terminated") 1422 } 1423} 1424 1425// TestH2H1ProxyProtocolV1TooLargeDstPort tests that PROXY protocol 1426// containing too large dst port should be rejected. 1427func TestH2H1ProxyProtocolV1TooLargeDstPort(t *testing.T) { 1428 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1429 defer st.Close() 1430 1431 st.conn.Write([]byte("PROXY TCP6 ::1 ::1 12345 65536\r\n")) 1432 1433 _, err := st.http2(requestParam{ 1434 name: "TestH2H1ProxyProtocolV1TooLargeDstPort", 1435 }) 1436 1437 if err == nil { 1438 t.Fatalf("connection was not terminated") 1439 } 1440} 1441 1442// TestH2H1ProxyProtocolV1InvalidSrcAddr tests that PROXY protocol 1443// containing invalid src addr should be rejected. 1444func TestH2H1ProxyProtocolV1InvalidSrcAddr(t *testing.T) { 1445 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1446 defer st.Close() 1447 1448 st.conn.Write([]byte("PROXY TCP6 192.168.0.1 ::1 12345 8080\r\n")) 1449 1450 _, err := st.http2(requestParam{ 1451 name: "TestH2H1ProxyProtocolV1InvalidSrcAddr", 1452 }) 1453 1454 if err == nil { 1455 t.Fatalf("connection was not terminated") 1456 } 1457} 1458 1459// TestH2H1ProxyProtocolV1InvalidDstAddr tests that PROXY protocol 1460// containing invalid dst addr should be rejected. 1461func TestH2H1ProxyProtocolV1InvalidDstAddr(t *testing.T) { 1462 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1463 defer st.Close() 1464 1465 st.conn.Write([]byte("PROXY TCP6 ::1 192.168.0.1 12345 8080\r\n")) 1466 1467 _, err := st.http2(requestParam{ 1468 name: "TestH2H1ProxyProtocolV1InvalidDstAddr", 1469 }) 1470 1471 if err == nil { 1472 t.Fatalf("connection was not terminated") 1473 } 1474} 1475 1476// TestH2H1ProxyProtocolV1InvalidProtoFamily tests that PROXY protocol 1477// containing invalid protocol family should be rejected. 1478func TestH2H1ProxyProtocolV1InvalidProtoFamily(t *testing.T) { 1479 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1480 defer st.Close() 1481 1482 st.conn.Write([]byte("PROXY UNIX ::1 ::1 12345 8080\r\n")) 1483 1484 _, err := st.http2(requestParam{ 1485 name: "TestH2H1ProxyProtocolV1InvalidProtoFamily", 1486 }) 1487 1488 if err == nil { 1489 t.Fatalf("connection was not terminated") 1490 } 1491} 1492 1493// TestH2H1ProxyProtocolV1InvalidID tests that PROXY protocol 1494// containing invalid PROXY protocol version 1 ID should be rejected. 1495func TestH2H1ProxyProtocolV1InvalidID(t *testing.T) { 1496 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1497 defer st.Close() 1498 1499 st.conn.Write([]byte("PR0XY TCP6 ::1 ::1 12345 8080\r\n")) 1500 1501 _, err := st.http2(requestParam{ 1502 name: "TestH2H1ProxyProtocolV1InvalidID", 1503 }) 1504 1505 if err == nil { 1506 t.Fatalf("connection was not terminated") 1507 } 1508} 1509 1510// TestH2H1ProxyProtocolV2TCP4 tests PROXY protocol version 2 1511// containing AF_INET family is accepted and X-Forwarded-For contains 1512// advertised src address. 1513func TestH2H1ProxyProtocolV2TCP4(t *testing.T) { 1514 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1515 if got, want := r.Header.Get("X-Forwarded-For"), "192.168.0.2"; got != want { 1516 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1517 } 1518 if got, want := r.Header.Get("Forwarded"), "for=192.168.0.2"; got != want { 1519 t.Errorf("Forwarded: %v; want %v", got, want) 1520 } 1521 }) 1522 defer st.Close() 1523 1524 var b bytes.Buffer 1525 writeProxyProtocolV2(&b, proxyProtocolV2{ 1526 command: proxyProtocolV2CommandProxy, 1527 sourceAddress: &net.TCPAddr{ 1528 IP: net.ParseIP("192.168.0.2").To4(), 1529 Port: 12345, 1530 }, 1531 destinationAddress: &net.TCPAddr{ 1532 IP: net.ParseIP("192.168.0.100").To4(), 1533 Port: 8080, 1534 }, 1535 additionalData: []byte("foobar"), 1536 }) 1537 st.conn.Write(b.Bytes()) 1538 1539 res, err := st.http2(requestParam{ 1540 name: "TestH2H1ProxyProtocolV2TCP4", 1541 }) 1542 1543 if err != nil { 1544 t.Fatalf("Error st.http2() = %v", err) 1545 } 1546 1547 if got, want := res.status, 200; got != want { 1548 t.Errorf("res.status: %v; want %v", got, want) 1549 } 1550} 1551 1552// TestH2H1ProxyProtocolV2TCP6 tests PROXY protocol version 2 1553// containing AF_INET6 family is accepted and X-Forwarded-For contains 1554// advertised src address. 1555func TestH2H1ProxyProtocolV2TCP6(t *testing.T) { 1556 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1557 if got, want := r.Header.Get("X-Forwarded-For"), "2001:db8:85a3::8a2e:370:7334"; got != want { 1558 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1559 } 1560 if got, want := r.Header.Get("Forwarded"), `for="[2001:db8:85a3::8a2e:370:7334]"`; got != want { 1561 t.Errorf("Forwarded: %v; want %v", got, want) 1562 } 1563 }) 1564 defer st.Close() 1565 1566 var b bytes.Buffer 1567 writeProxyProtocolV2(&b, proxyProtocolV2{ 1568 command: proxyProtocolV2CommandProxy, 1569 sourceAddress: &net.TCPAddr{ 1570 IP: net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), 1571 Port: 12345, 1572 }, 1573 destinationAddress: &net.TCPAddr{ 1574 IP: net.ParseIP("::1"), 1575 Port: 8080, 1576 }, 1577 additionalData: []byte("foobar"), 1578 }) 1579 st.conn.Write(b.Bytes()) 1580 1581 res, err := st.http2(requestParam{ 1582 name: "TestH2H1ProxyProtocolV2TCP6", 1583 }) 1584 1585 if err != nil { 1586 t.Fatalf("Error st.http2() = %v", err) 1587 } 1588 1589 if got, want := res.status, 200; got != want { 1590 t.Errorf("res.status: %v; want %v", got, want) 1591 } 1592} 1593 1594// TestH2H1ProxyProtocolV2Local tests PROXY protocol version 2 1595// containing cmd == Local is ignored. 1596func TestH2H1ProxyProtocolV2Local(t *testing.T) { 1597 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1598 if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { 1599 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1600 } 1601 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want { 1602 t.Errorf("Forwarded: %v; want %v", got, want) 1603 } 1604 }) 1605 defer st.Close() 1606 1607 var b bytes.Buffer 1608 writeProxyProtocolV2(&b, proxyProtocolV2{ 1609 command: proxyProtocolV2CommandLocal, 1610 sourceAddress: &net.TCPAddr{ 1611 IP: net.ParseIP("192.168.0.2").To4(), 1612 Port: 12345, 1613 }, 1614 destinationAddress: &net.TCPAddr{ 1615 IP: net.ParseIP("192.168.0.100").To4(), 1616 Port: 8080, 1617 }, 1618 additionalData: []byte("foobar"), 1619 }) 1620 st.conn.Write(b.Bytes()) 1621 1622 res, err := st.http2(requestParam{ 1623 name: "TestH2H1ProxyProtocolV2Local", 1624 }) 1625 1626 if err != nil { 1627 t.Fatalf("Error st.http2() = %v", err) 1628 } 1629 1630 if got, want := res.status, 200; got != want { 1631 t.Errorf("res.status: %v; want %v", got, want) 1632 } 1633} 1634 1635// TestH2H1ProxyProtocolV2UnknownCmd tests PROXY protocol version 2 1636// containing unknown cmd should be rejected. 1637func TestH2H1ProxyProtocolV2UnknownCmd(t *testing.T) { 1638 st := newServerTester([]string{"--accept-proxy-protocol"}, t, noopHandler) 1639 defer st.Close() 1640 1641 var b bytes.Buffer 1642 writeProxyProtocolV2(&b, proxyProtocolV2{ 1643 command: 0xf, 1644 sourceAddress: &net.TCPAddr{ 1645 IP: net.ParseIP("192.168.0.2").To4(), 1646 Port: 12345, 1647 }, 1648 destinationAddress: &net.TCPAddr{ 1649 IP: net.ParseIP("192.168.0.100").To4(), 1650 Port: 8080, 1651 }, 1652 additionalData: []byte("foobar"), 1653 }) 1654 st.conn.Write(b.Bytes()) 1655 1656 _, err := st.http2(requestParam{ 1657 name: "TestH2H1ProxyProtocolV2UnknownCmd", 1658 }) 1659 1660 if err == nil { 1661 t.Fatalf("connection was not terminated") 1662 } 1663} 1664 1665// TestH2H1ProxyProtocolV2Unix tests PROXY protocol version 2 1666// containing AF_UNIX family is ignored. 1667func TestH2H1ProxyProtocolV2Unix(t *testing.T) { 1668 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1669 if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { 1670 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1671 } 1672 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want { 1673 t.Errorf("Forwarded: %v; want %v", got, want) 1674 } 1675 }) 1676 defer st.Close() 1677 1678 var b bytes.Buffer 1679 writeProxyProtocolV2(&b, proxyProtocolV2{ 1680 command: proxyProtocolV2CommandProxy, 1681 sourceAddress: &net.UnixAddr{ 1682 Name: "/foo", 1683 Net: "unix", 1684 }, 1685 destinationAddress: &net.UnixAddr{ 1686 Name: "/bar", 1687 Net: "unix", 1688 }, 1689 additionalData: []byte("foobar"), 1690 }) 1691 st.conn.Write(b.Bytes()) 1692 1693 res, err := st.http2(requestParam{ 1694 name: "TestH2H1ProxyProtocolV2Unix", 1695 }) 1696 1697 if err != nil { 1698 t.Fatalf("Error st.http2() = %v", err) 1699 } 1700 1701 if got, want := res.status, 200; got != want { 1702 t.Errorf("res.status: %v; want %v", got, want) 1703 } 1704} 1705 1706// TestH2H1ProxyProtocolV2Unspec tests PROXY protocol version 2 1707// containing AF_UNSPEC family is ignored. 1708func TestH2H1ProxyProtocolV2Unspec(t *testing.T) { 1709 st := newServerTester([]string{"--accept-proxy-protocol", "--add-x-forwarded-for", "--add-forwarded=for", "--forwarded-for=ip"}, t, func(w http.ResponseWriter, r *http.Request) { 1710 if got, want := r.Header.Get("X-Forwarded-For"), "127.0.0.1"; got != want { 1711 t.Errorf("X-Forwarded-For: %v; want %v", got, want) 1712 } 1713 if got, want := r.Header.Get("Forwarded"), "for=127.0.0.1"; got != want { 1714 t.Errorf("Forwarded: %v; want %v", got, want) 1715 } 1716 }) 1717 defer st.Close() 1718 1719 var b bytes.Buffer 1720 writeProxyProtocolV2(&b, proxyProtocolV2{ 1721 command: proxyProtocolV2CommandProxy, 1722 additionalData: []byte("foobar"), 1723 }) 1724 st.conn.Write(b.Bytes()) 1725 1726 res, err := st.http2(requestParam{ 1727 name: "TestH2H1ProxyProtocolV2Unspec", 1728 }) 1729 1730 if err != nil { 1731 t.Fatalf("Error st.http2() = %v", err) 1732 } 1733 1734 if got, want := res.status, 200; got != want { 1735 t.Errorf("res.status: %v; want %v", got, want) 1736 } 1737} 1738 1739// TestH2H1ExternalDNS tests that DNS resolution using external DNS 1740// with HTTP/1 backend works. 1741func TestH2H1ExternalDNS(t *testing.T) { 1742 st := newServerTester([]string{"--external-dns"}, t, noopHandler) 1743 defer st.Close() 1744 1745 res, err := st.http2(requestParam{ 1746 name: "TestH2H1ExternalDNS", 1747 }) 1748 if err != nil { 1749 t.Fatalf("Error st.http2() = %v", err) 1750 } 1751 1752 if got, want := res.status, 200; got != want { 1753 t.Errorf("status = %v; want %v", got, want) 1754 } 1755} 1756 1757// TestH2H1DNS tests that DNS resolution without external DNS with 1758// HTTP/1 backend works. 1759func TestH2H1DNS(t *testing.T) { 1760 st := newServerTester([]string{"--dns"}, t, noopHandler) 1761 defer st.Close() 1762 1763 res, err := st.http2(requestParam{ 1764 name: "TestH2H1DNS", 1765 }) 1766 if err != nil { 1767 t.Fatalf("Error st.http2() = %v", err) 1768 } 1769 1770 if got, want := res.status, 200; got != want { 1771 t.Errorf("status = %v; want %v", got, want) 1772 } 1773} 1774 1775// TestH2H1HTTPSRedirect tests that the request to the backend which 1776// requires TLS is redirected to https URI. 1777func TestH2H1HTTPSRedirect(t *testing.T) { 1778 st := newServerTester([]string{"--redirect-if-not-tls"}, t, noopHandler) 1779 defer st.Close() 1780 1781 res, err := st.http2(requestParam{ 1782 name: "TestH2H1HTTPSRedirect", 1783 }) 1784 if err != nil { 1785 t.Fatalf("Error st.http2() = %v", err) 1786 } 1787 1788 if got, want := res.status, 308; got != want { 1789 t.Errorf("status = %v; want %v", got, want) 1790 } 1791 if got, want := res.header.Get("location"), "https://127.0.0.1/"; got != want { 1792 t.Errorf("location: %v; want %v", got, want) 1793 } 1794} 1795 1796// TestH2H1HTTPSRedirectPort tests that the request to the backend 1797// which requires TLS is redirected to https URI with given port. 1798func TestH2H1HTTPSRedirectPort(t *testing.T) { 1799 st := newServerTester([]string{"--redirect-if-not-tls", "--redirect-https-port=8443"}, t, noopHandler) 1800 defer st.Close() 1801 1802 res, err := st.http2(requestParam{ 1803 path: "/foo?bar", 1804 name: "TestH2H1HTTPSRedirectPort", 1805 }) 1806 if err != nil { 1807 t.Fatalf("Error st.http2() = %v", err) 1808 } 1809 1810 if got, want := res.status, 308; got != want { 1811 t.Errorf("status = %v; want %v", got, want) 1812 } 1813 if got, want := res.header.Get("location"), "https://127.0.0.1:8443/foo?bar"; got != want { 1814 t.Errorf("location: %v; want %v", got, want) 1815 } 1816} 1817 1818// TestH2H1Code204 tests that 204 response without content-length, and 1819// transfer-encoding is valid. 1820func TestH2H1Code204(t *testing.T) { 1821 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 1822 w.WriteHeader(http.StatusNoContent) 1823 }) 1824 defer st.Close() 1825 1826 res, err := st.http2(requestParam{ 1827 name: "TestH2H1Code204", 1828 }) 1829 if err != nil { 1830 t.Fatalf("Error st.http2() = %v", err) 1831 } 1832 1833 if got, want := res.status, 204; got != want { 1834 t.Errorf("status = %v; want %v", got, want) 1835 } 1836} 1837 1838// TestH2H1Code204CL0 tests that 204 response with content-length: 0 1839// is allowed. 1840func TestH2H1Code204CL0(t *testing.T) { 1841 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 1842 hj, ok := w.(http.Hijacker) 1843 if !ok { 1844 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) 1845 return 1846 } 1847 conn, bufrw, err := hj.Hijack() 1848 if err != nil { 1849 http.Error(w, err.Error(), http.StatusInternalServerError) 1850 return 1851 } 1852 defer conn.Close() 1853 bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 0\r\n\r\n") 1854 bufrw.Flush() 1855 }) 1856 defer st.Close() 1857 1858 res, err := st.http2(requestParam{ 1859 name: "TestH2H1Code204CL0", 1860 }) 1861 if err != nil { 1862 t.Fatalf("Error st.http2() = %v", err) 1863 } 1864 1865 if got, want := res.status, 204; got != want { 1866 t.Errorf("status = %v; want %v", got, want) 1867 } 1868 1869 if got, found := res.header["Content-Length"]; found { 1870 t.Errorf("Content-Length = %v, want nothing", got) 1871 } 1872} 1873 1874// TestH2H1Code204CLNonzero tests that 204 response with nonzero 1875// content-length is not allowed. 1876func TestH2H1Code204CLNonzero(t *testing.T) { 1877 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 1878 hj, ok := w.(http.Hijacker) 1879 if !ok { 1880 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) 1881 return 1882 } 1883 conn, bufrw, err := hj.Hijack() 1884 if err != nil { 1885 http.Error(w, err.Error(), http.StatusInternalServerError) 1886 return 1887 } 1888 defer conn.Close() 1889 bufrw.WriteString("HTTP/1.1 204\r\nContent-Length: 1\r\n\r\n") 1890 bufrw.Flush() 1891 }) 1892 defer st.Close() 1893 1894 res, err := st.http2(requestParam{ 1895 name: "TestH2H1Code204CLNonzero", 1896 }) 1897 if err != nil { 1898 t.Fatalf("Error st.http2() = %v", err) 1899 } 1900 1901 if got, want := res.status, 502; got != want { 1902 t.Errorf("status = %v; want %v", got, want) 1903 } 1904} 1905 1906// TestH2H1Code204TE tests that 204 response with transfer-encoding is 1907// not allowed. 1908func TestH2H1Code204TE(t *testing.T) { 1909 st := newServerTester(nil, t, func(w http.ResponseWriter, r *http.Request) { 1910 hj, ok := w.(http.Hijacker) 1911 if !ok { 1912 http.Error(w, "Could not hijack the connection", http.StatusInternalServerError) 1913 return 1914 } 1915 conn, bufrw, err := hj.Hijack() 1916 if err != nil { 1917 http.Error(w, err.Error(), http.StatusInternalServerError) 1918 return 1919 } 1920 defer conn.Close() 1921 bufrw.WriteString("HTTP/1.1 204\r\nTransfer-Encoding: chunked\r\n\r\n") 1922 bufrw.Flush() 1923 }) 1924 defer st.Close() 1925 1926 res, err := st.http2(requestParam{ 1927 name: "TestH2H1Code204TE", 1928 }) 1929 if err != nil { 1930 t.Fatalf("Error st.http2() = %v", err) 1931 } 1932 1933 if got, want := res.status, 502; got != want { 1934 t.Errorf("status = %v; want %v", got, want) 1935 } 1936} 1937 1938// TestH2H1AffinityCookie tests that affinity cookie is sent back in 1939// cleartext http. 1940func TestH2H1AffinityCookie(t *testing.T) { 1941 st := newServerTester([]string{"--affinity-cookie"}, t, noopHandler) 1942 defer st.Close() 1943 1944 res, err := st.http2(requestParam{ 1945 name: "TestH2H1AffinityCookie", 1946 }) 1947 if err != nil { 1948 t.Fatalf("Error st.http2() = %v", err) 1949 } 1950 1951 if got, want := res.status, 200; got != want { 1952 t.Errorf("status = %v; want %v", got, want) 1953 } 1954 1955 const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar` 1956 validCookie := regexp.MustCompile(pattern) 1957 if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) { 1958 t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern) 1959 } 1960} 1961 1962// TestH2H1AffinityCookieTLS tests that affinity cookie is sent back 1963// in https. 1964func TestH2H1AffinityCookieTLS(t *testing.T) { 1965 st := newServerTesterTLS([]string{"--affinity-cookie"}, t, noopHandler) 1966 defer st.Close() 1967 1968 res, err := st.http2(requestParam{ 1969 name: "TestH2H1AffinityCookieTLS", 1970 scheme: "https", 1971 }) 1972 if err != nil { 1973 t.Fatalf("Error st.http2() = %v", err) 1974 } 1975 1976 if got, want := res.status, 200; got != want { 1977 t.Errorf("status = %v; want %v", got, want) 1978 } 1979 1980 const pattern = `affinity=[0-9a-f]{8}; Path=/foo/bar; Secure` 1981 validCookie := regexp.MustCompile(pattern) 1982 if got := res.header.Get("Set-Cookie"); !validCookie.MatchString(got) { 1983 t.Errorf("Set-Cookie: %v; want pattern %v", got, pattern) 1984 } 1985} 1986 1987// TestH2H1GracefulShutdown tests graceful shutdown. 1988func TestH2H1GracefulShutdown(t *testing.T) { 1989 st := newServerTester(nil, t, noopHandler) 1990 defer st.Close() 1991 1992 fmt.Fprint(st.conn, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") 1993 if err := st.fr.WriteSettings(); err != nil { 1994 t.Fatalf("st.fr.WriteSettings(): %v", err) 1995 } 1996 1997 header := []hpack.HeaderField{ 1998 pair(":method", "GET"), 1999 pair(":scheme", "http"), 2000 pair(":authority", st.authority), 2001 pair(":path", "/"), 2002 } 2003 2004 for _, h := range header { 2005 _ = st.enc.WriteField(h) 2006 } 2007 2008 if err := st.fr.WriteHeaders(http2.HeadersFrameParam{ 2009 StreamID: 1, 2010 EndStream: false, 2011 EndHeaders: true, 2012 BlockFragment: st.headerBlkBuf.Bytes(), 2013 }); err != nil { 2014 t.Fatalf("st.fr.WriteHeaders(): %v", err) 2015 } 2016 2017 // send SIGQUIT signal to nghttpx to perform graceful shutdown 2018 st.cmd.Process.Signal(syscall.SIGQUIT) 2019 time.Sleep(150 * time.Millisecond) 2020 2021 // after signal, finish request body 2022 if err := st.fr.WriteData(1, true, nil); err != nil { 2023 t.Fatalf("st.fr.WriteData(): %v", err) 2024 } 2025 2026 numGoAway := 0 2027 2028 for { 2029 fr, err := st.readFrame() 2030 if err != nil { 2031 if err == io.EOF { 2032 want := 2 2033 if got := numGoAway; got != want { 2034 t.Fatalf("numGoAway: %v; want %v", got, want) 2035 } 2036 return 2037 } 2038 t.Fatalf("st.readFrame(): %v", err) 2039 } 2040 switch f := fr.(type) { 2041 case *http2.GoAwayFrame: 2042 numGoAway += 1 2043 want := http2.ErrCodeNo 2044 if got := f.ErrCode; got != want { 2045 t.Fatalf("f.ErrCode(%v): %v; want %v", numGoAway, got, want) 2046 } 2047 switch numGoAway { 2048 case 1: 2049 want := (uint32(1) << 31) - 1 2050 if got := f.LastStreamID; got != want { 2051 t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want) 2052 } 2053 case 2: 2054 want := uint32(1) 2055 if got := f.LastStreamID; got != want { 2056 t.Fatalf("f.LastStreamID(%v): %v; want %v", numGoAway, got, want) 2057 } 2058 case 3: 2059 t.Fatalf("too many GOAWAYs received") 2060 } 2061 } 2062 } 2063} 2064 2065// TestH2H2MultipleResponseCL tests that server returns error if 2066// multiple Content-Length response header fields are received. 2067func TestH2H2MultipleResponseCL(t *testing.T) { 2068 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2069 w.Header().Add("content-length", "1") 2070 w.Header().Add("content-length", "1") 2071 }) 2072 defer st.Close() 2073 2074 res, err := st.http2(requestParam{ 2075 name: "TestH2H2MultipleResponseCL", 2076 }) 2077 if err != nil { 2078 t.Fatalf("Error st.http2() = %v", err) 2079 } 2080 if got, want := res.errCode, http2.ErrCodeInternal; got != want { 2081 t.Errorf("res.errCode: %v; want %v", got, want) 2082 } 2083} 2084 2085// TestH2H2InvalidResponseCL tests that server returns error if 2086// Content-Length response header field value cannot be parsed as a 2087// number. 2088func TestH2H2InvalidResponseCL(t *testing.T) { 2089 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2090 w.Header().Add("content-length", "") 2091 }) 2092 defer st.Close() 2093 2094 res, err := st.http2(requestParam{ 2095 name: "TestH2H2InvalidResponseCL", 2096 }) 2097 if err != nil { 2098 t.Fatalf("Error st.http2() = %v", err) 2099 } 2100 if got, want := res.errCode, http2.ErrCodeInternal; got != want { 2101 t.Errorf("res.errCode: %v; want %v", got, want) 2102 } 2103} 2104 2105// // TestH2H2ConnectFailure tests that server handles the situation that 2106// // connection attempt to HTTP/2 backend failed. 2107// func TestH2H2ConnectFailure(t *testing.T) { 2108// st := newServerTester([]string{"--http2-bridge"}, t, noopHandler) 2109// defer st.Close() 2110 2111// // simulate backend connect attempt failure 2112// st.ts.Close() 2113 2114// res, err := st.http2(requestParam{ 2115// name: "TestH2H2ConnectFailure", 2116// }) 2117// if err != nil { 2118// t.Fatalf("Error st.http2() = %v", err) 2119// } 2120// want := 503 2121// if got := res.status; got != want { 2122// t.Errorf("status: %v; want %v", got, want) 2123// } 2124// } 2125 2126// TestH2H2HostRewrite tests that server rewrites host header field 2127func TestH2H2HostRewrite(t *testing.T) { 2128 st := newServerTester([]string{"--http2-bridge", "--host-rewrite"}, t, func(w http.ResponseWriter, r *http.Request) { 2129 w.Header().Add("request-host", r.Host) 2130 }) 2131 defer st.Close() 2132 2133 res, err := st.http2(requestParam{ 2134 name: "TestH2H2HostRewrite", 2135 }) 2136 if err != nil { 2137 t.Fatalf("Error st.http2() = %v", err) 2138 } 2139 if got, want := res.status, 200; got != want { 2140 t.Errorf("status: %v; want %v", got, want) 2141 } 2142 if got, want := res.header.Get("request-host"), st.backendHost; got != want { 2143 t.Errorf("request-host: %v; want %v", got, want) 2144 } 2145} 2146 2147// TestH2H2NoHostRewrite tests that server does not rewrite host 2148// header field 2149func TestH2H2NoHostRewrite(t *testing.T) { 2150 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2151 w.Header().Add("request-host", r.Host) 2152 }) 2153 defer st.Close() 2154 2155 res, err := st.http2(requestParam{ 2156 name: "TestH2H2NoHostRewrite", 2157 }) 2158 if err != nil { 2159 t.Fatalf("Error st.http2() = %v", err) 2160 } 2161 if got, want := res.status, 200; got != want { 2162 t.Errorf("status: %v; want %v", got, want) 2163 } 2164 if got, want := res.header.Get("request-host"), st.frontendHost; got != want { 2165 t.Errorf("request-host: %v; want %v", got, want) 2166 } 2167} 2168 2169// TestH2H2TLSXfp tests nghttpx sends x-forwarded-proto header field 2170// with http value since :scheme is http, even if the frontend 2171// connection is encrypted. 2172func TestH2H2TLSXfp(t *testing.T) { 2173 st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2174 if got, want := r.Header.Get("x-forwarded-proto"), "http"; got != want { 2175 t.Errorf("x-forwarded-proto: want %v; got %v", want, got) 2176 } 2177 }) 2178 defer st.Close() 2179 2180 res, err := st.http2(requestParam{ 2181 name: "TestH2H2TLSXfp", 2182 }) 2183 if err != nil { 2184 t.Fatalf("Error st.http2() = %v", err) 2185 } 2186 if got, want := res.status, 200; got != want { 2187 t.Errorf("res.status: %v; want %v", got, want) 2188 } 2189} 2190 2191// TestH2H2AddXfp tests that server appends :scheme to the existing 2192// x-forwarded-proto header field. 2193func TestH2H2AddXfp(t *testing.T) { 2194 st := newServerTesterTLS([]string{"--http2-bridge", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 2195 xfp := r.Header.Get("X-Forwarded-Proto") 2196 if got, want := xfp, "foo, http"; got != want { 2197 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 2198 } 2199 }) 2200 defer st.Close() 2201 2202 res, err := st.http2(requestParam{ 2203 name: "TestH2H2AddXfp", 2204 header: []hpack.HeaderField{ 2205 pair("x-forwarded-proto", "foo"), 2206 }, 2207 }) 2208 if err != nil { 2209 t.Fatalf("Error st.http2() = %v", err) 2210 } 2211 if got, want := res.status, 200; got != want { 2212 t.Errorf("status = %v; want %v", got, want) 2213 } 2214} 2215 2216// TestH2H2NoAddXfp tests that server does not append :scheme to the 2217// existing x-forwarded-proto header field. 2218func TestH2H2NoAddXfp(t *testing.T) { 2219 st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto", "--no-strip-incoming-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 2220 xfp := r.Header.Get("X-Forwarded-Proto") 2221 if got, want := xfp, "foo"; got != want { 2222 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 2223 } 2224 }) 2225 defer st.Close() 2226 2227 res, err := st.http2(requestParam{ 2228 name: "TestH2H2NoAddXfp", 2229 header: []hpack.HeaderField{ 2230 pair("x-forwarded-proto", "foo"), 2231 }, 2232 }) 2233 if err != nil { 2234 t.Fatalf("Error st.http2() = %v", err) 2235 } 2236 if got, want := res.status, 200; got != want { 2237 t.Errorf("status = %v; want %v", got, want) 2238 } 2239} 2240 2241// TestH2H2StripXfp tests that server strips incoming 2242// x-forwarded-proto header field. 2243func TestH2H2StripXfp(t *testing.T) { 2244 st := newServerTesterTLS([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2245 xfp := r.Header.Get("X-Forwarded-Proto") 2246 if got, want := xfp, "http"; got != want { 2247 t.Errorf("X-Forwarded-Proto = %q; want %q", got, want) 2248 } 2249 }) 2250 defer st.Close() 2251 2252 res, err := st.http2(requestParam{ 2253 name: "TestH2H2StripXfp", 2254 header: []hpack.HeaderField{ 2255 pair("x-forwarded-proto", "foo"), 2256 }, 2257 }) 2258 if err != nil { 2259 t.Fatalf("Error st.http2() = %v", err) 2260 } 2261 if got, want := res.status, 200; got != want { 2262 t.Errorf("status = %v; want %v", got, want) 2263 } 2264} 2265 2266// TestH2H2StripNoAddXfp tests that server strips incoming 2267// x-forwarded-proto header field, and does not add another. 2268func TestH2H2StripNoAddXfp(t *testing.T) { 2269 st := newServerTesterTLS([]string{"--http2-bridge", "--no-add-x-forwarded-proto"}, t, func(w http.ResponseWriter, r *http.Request) { 2270 if got, found := r.Header["X-Forwarded-Proto"]; found { 2271 t.Errorf("X-Forwarded-Proto = %q; want nothing", got) 2272 } 2273 }) 2274 defer st.Close() 2275 2276 res, err := st.http2(requestParam{ 2277 name: "TestH2H2StripNoAddXfp", 2278 header: []hpack.HeaderField{ 2279 pair("x-forwarded-proto", "foo"), 2280 }, 2281 }) 2282 if err != nil { 2283 t.Fatalf("Error st.http2() = %v", err) 2284 } 2285 if got, want := res.status, 200; got != want { 2286 t.Errorf("status = %v; want %v", got, want) 2287 } 2288} 2289 2290// TestH2H2AddXff tests that server generates X-Forwarded-For header 2291// field when forwarding request to backend. 2292func TestH2H2AddXff(t *testing.T) { 2293 st := newServerTesterTLS([]string{"--http2-bridge", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 2294 xff := r.Header.Get("X-Forwarded-For") 2295 want := "127.0.0.1" 2296 if xff != want { 2297 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 2298 } 2299 }) 2300 defer st.Close() 2301 2302 res, err := st.http2(requestParam{ 2303 name: "TestH2H2AddXff", 2304 }) 2305 if err != nil { 2306 t.Fatalf("Error st.http2() = %v", err) 2307 } 2308 if got, want := res.status, 200; got != want { 2309 t.Errorf("status = %v; want %v", got, want) 2310 } 2311} 2312 2313// TestH2H2AddXff2 tests that server appends X-Forwarded-For header 2314// field to existing one when forwarding request to backend. 2315func TestH2H2AddXff2(t *testing.T) { 2316 st := newServerTesterTLS([]string{"--http2-bridge", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 2317 xff := r.Header.Get("X-Forwarded-For") 2318 want := "host, 127.0.0.1" 2319 if xff != want { 2320 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 2321 } 2322 }) 2323 defer st.Close() 2324 2325 res, err := st.http2(requestParam{ 2326 name: "TestH2H2AddXff2", 2327 header: []hpack.HeaderField{ 2328 pair("x-forwarded-for", "host"), 2329 }, 2330 }) 2331 if err != nil { 2332 t.Fatalf("Error st.http2() = %v", err) 2333 } 2334 if got, want := res.status, 200; got != want { 2335 t.Errorf("status = %v; want %v", got, want) 2336 } 2337} 2338 2339// TestH2H2StripXff tests that --strip-incoming-x-forwarded-for 2340// option. 2341func TestH2H2StripXff(t *testing.T) { 2342 st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 2343 if xff, found := r.Header["X-Forwarded-For"]; found { 2344 t.Errorf("X-Forwarded-For = %v; want nothing", xff) 2345 } 2346 }) 2347 defer st.Close() 2348 2349 res, err := st.http2(requestParam{ 2350 name: "TestH2H2StripXff", 2351 header: []hpack.HeaderField{ 2352 pair("x-forwarded-for", "host"), 2353 }, 2354 }) 2355 if err != nil { 2356 t.Fatalf("Error st.http2() = %v", err) 2357 } 2358 if got, want := res.status, 200; got != want { 2359 t.Errorf("status = %v; want %v", got, want) 2360 } 2361} 2362 2363// TestH2H2StripAddXff tests that --strip-incoming-x-forwarded-for and 2364// --add-x-forwarded-for options. 2365func TestH2H2StripAddXff(t *testing.T) { 2366 st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-x-forwarded-for", "--add-x-forwarded-for"}, t, func(w http.ResponseWriter, r *http.Request) { 2367 xff := r.Header.Get("X-Forwarded-For") 2368 want := "127.0.0.1" 2369 if xff != want { 2370 t.Errorf("X-Forwarded-For = %v; want %v", xff, want) 2371 } 2372 }) 2373 defer st.Close() 2374 2375 res, err := st.http2(requestParam{ 2376 name: "TestH2H2StripAddXff", 2377 header: []hpack.HeaderField{ 2378 pair("x-forwarded-for", "host"), 2379 }, 2380 }) 2381 if err != nil { 2382 t.Fatalf("Error st.http2() = %v", err) 2383 } 2384 if got, want := res.status, 200; got != want { 2385 t.Errorf("status = %v; want %v", got, want) 2386 } 2387} 2388 2389// TestH2H2AddForwarded tests that server generates Forwarded header 2390// field using static obfuscated "by" parameter. 2391func TestH2H2AddForwarded(t *testing.T) { 2392 st := newServerTesterTLS([]string{"--http2-bridge", "--add-forwarded=by,for,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) { 2393 pattern := fmt.Sprintf(`by=_alpha;for=_[^;]+;host="127\.0\.0\.1:%v";proto=https`, serverPort) 2394 validFwd := regexp.MustCompile(pattern) 2395 if got := r.Header.Get("Forwarded"); !validFwd.MatchString(got) { 2396 t.Errorf("Forwarded = %v; want pattern %v", got, pattern) 2397 } 2398 }) 2399 defer st.Close() 2400 2401 res, err := st.http2(requestParam{ 2402 name: "TestH2H2AddForwarded", 2403 scheme: "https", 2404 }) 2405 if err != nil { 2406 t.Fatalf("Error st.http2() = %v", err) 2407 } 2408 if got, want := res.status, 200; got != want { 2409 t.Errorf("status: %v; want %v", got, want) 2410 } 2411} 2412 2413// TestH2H2AddForwardedMerge tests that server generates Forwarded 2414// header field using static obfuscated "by" parameter, and 2415// existing Forwarded header field. 2416func TestH2H2AddForwardedMerge(t *testing.T) { 2417 st := newServerTesterTLS([]string{"--http2-bridge", "--add-forwarded=by,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) { 2418 want := fmt.Sprintf(`host=foo, by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort) 2419 if got := r.Header.Get("Forwarded"); got != want { 2420 t.Errorf("Forwarded = %v; want %v", got, want) 2421 } 2422 }) 2423 defer st.Close() 2424 2425 res, err := st.http2(requestParam{ 2426 name: "TestH2H2AddForwardedMerge", 2427 scheme: "https", 2428 header: []hpack.HeaderField{ 2429 pair("forwarded", "host=foo"), 2430 }, 2431 }) 2432 if err != nil { 2433 t.Fatalf("Error st.http2() = %v", err) 2434 } 2435 if got, want := res.status, 200; got != want { 2436 t.Errorf("status: %v; want %v", got, want) 2437 } 2438} 2439 2440// TestH2H2AddForwardedStrip tests that server generates Forwarded 2441// header field using static obfuscated "by" parameter, and 2442// existing Forwarded header field stripped. 2443func TestH2H2AddForwardedStrip(t *testing.T) { 2444 st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-forwarded", "--add-forwarded=by,host,proto", "--forwarded-by=_alpha"}, t, func(w http.ResponseWriter, r *http.Request) { 2445 want := fmt.Sprintf(`by=_alpha;host="127.0.0.1:%v";proto=https`, serverPort) 2446 if got := r.Header.Get("Forwarded"); got != want { 2447 t.Errorf("Forwarded = %v; want %v", got, want) 2448 } 2449 }) 2450 defer st.Close() 2451 2452 res, err := st.http2(requestParam{ 2453 name: "TestH2H2AddForwardedStrip", 2454 scheme: "https", 2455 header: []hpack.HeaderField{ 2456 pair("forwarded", "host=foo"), 2457 }, 2458 }) 2459 if err != nil { 2460 t.Fatalf("Error st.http2() = %v", err) 2461 } 2462 if got, want := res.status, 200; got != want { 2463 t.Errorf("status: %v; want %v", got, want) 2464 } 2465} 2466 2467// TestH2H2StripForwarded tests that server strips incoming Forwarded 2468// header field. 2469func TestH2H2StripForwarded(t *testing.T) { 2470 st := newServerTesterTLS([]string{"--http2-bridge", "--strip-incoming-forwarded"}, t, func(w http.ResponseWriter, r *http.Request) { 2471 if got, found := r.Header["Forwarded"]; found { 2472 t.Errorf("Forwarded = %v; want nothing", got) 2473 } 2474 }) 2475 defer st.Close() 2476 2477 res, err := st.http2(requestParam{ 2478 name: "TestH2H2StripForwarded", 2479 scheme: "https", 2480 header: []hpack.HeaderField{ 2481 pair("forwarded", "host=foo"), 2482 }, 2483 }) 2484 if err != nil { 2485 t.Fatalf("Error st.http2() = %v", err) 2486 } 2487 if got, want := res.status, 200; got != want { 2488 t.Errorf("status: %v; want %v", got, want) 2489 } 2490} 2491 2492// TestH2H2ReqPhaseReturn tests mruby request phase hook returns 2493// custom response. 2494func TestH2H2ReqPhaseReturn(t *testing.T) { 2495 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) { 2496 t.Fatalf("request should not be forwarded") 2497 }) 2498 defer st.Close() 2499 2500 res, err := st.http2(requestParam{ 2501 name: "TestH2H2ReqPhaseReturn", 2502 }) 2503 if err != nil { 2504 t.Fatalf("Error st.http2() = %v", err) 2505 } 2506 2507 if got, want := res.status, 404; got != want { 2508 t.Errorf("status = %v; want %v", got, want) 2509 } 2510 2511 hdtests := []struct { 2512 k, v string 2513 }{ 2514 {"content-length", "20"}, 2515 {"from", "mruby"}, 2516 } 2517 for _, tt := range hdtests { 2518 if got, want := res.header.Get(tt.k), tt.v; got != want { 2519 t.Errorf("%v = %v; want %v", tt.k, got, want) 2520 } 2521 } 2522 2523 if got, want := string(res.body), "Hello World from req"; got != want { 2524 t.Errorf("body = %v; want %v", got, want) 2525 } 2526} 2527 2528// TestH2H2RespPhaseReturn tests mruby response phase hook returns 2529// custom response. 2530func TestH2H2RespPhaseReturn(t *testing.T) { 2531 st := newServerTester([]string{"--http2-bridge", "--mruby-file=" + testDir + "/resp-return.rb"}, t, noopHandler) 2532 defer st.Close() 2533 2534 res, err := st.http2(requestParam{ 2535 name: "TestH2H2RespPhaseReturn", 2536 }) 2537 if err != nil { 2538 t.Fatalf("Error st.http2() = %v", err) 2539 } 2540 2541 if got, want := res.status, 404; got != want { 2542 t.Errorf("status = %v; want %v", got, want) 2543 } 2544 2545 hdtests := []struct { 2546 k, v string 2547 }{ 2548 {"content-length", "21"}, 2549 {"from", "mruby"}, 2550 } 2551 for _, tt := range hdtests { 2552 if got, want := res.header.Get(tt.k), tt.v; got != want { 2553 t.Errorf("%v = %v; want %v", tt.k, got, want) 2554 } 2555 } 2556 2557 if got, want := string(res.body), "Hello World from resp"; got != want { 2558 t.Errorf("body = %v; want %v", got, want) 2559 } 2560} 2561 2562// TestH2H2ExternalDNS tests that DNS resolution using external DNS 2563// with HTTP/2 backend works. 2564func TestH2H2ExternalDNS(t *testing.T) { 2565 st := newServerTester([]string{"--http2-bridge", "--external-dns"}, t, noopHandler) 2566 defer st.Close() 2567 2568 res, err := st.http2(requestParam{ 2569 name: "TestH2H2ExternalDNS", 2570 }) 2571 if err != nil { 2572 t.Fatalf("Error st.http2() = %v", err) 2573 } 2574 2575 if got, want := res.status, 200; got != want { 2576 t.Errorf("status = %v; want %v", got, want) 2577 } 2578} 2579 2580// TestH2H2DNS tests that DNS resolution without external DNS with 2581// HTTP/2 backend works. 2582func TestH2H2DNS(t *testing.T) { 2583 st := newServerTester([]string{"--http2-bridge", "--dns"}, t, noopHandler) 2584 defer st.Close() 2585 2586 res, err := st.http2(requestParam{ 2587 name: "TestH2H2DNS", 2588 }) 2589 if err != nil { 2590 t.Fatalf("Error st.http2() = %v", err) 2591 } 2592 2593 if got, want := res.status, 200; got != want { 2594 t.Errorf("status = %v; want %v", got, want) 2595 } 2596} 2597 2598// TestH2H2Code204 tests that 204 response without content-length, and 2599// transfer-encoding is valid. 2600func TestH2H2Code204(t *testing.T) { 2601 st := newServerTester([]string{"--http2-bridge"}, t, func(w http.ResponseWriter, r *http.Request) { 2602 w.WriteHeader(http.StatusNoContent) 2603 }) 2604 defer st.Close() 2605 2606 res, err := st.http2(requestParam{ 2607 name: "TestH2H2Code204", 2608 }) 2609 if err != nil { 2610 t.Fatalf("Error st.http2() = %v", err) 2611 } 2612 2613 if got, want := res.status, 204; got != want { 2614 t.Errorf("status = %v; want %v", got, want) 2615 } 2616} 2617 2618// TestH2APIBackendconfig exercise backendconfig API endpoint routine 2619// for successful case. 2620func TestH2APIBackendconfig(t *testing.T) { 2621 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2622 t.Fatalf("request should not be forwarded") 2623 }, 3010) 2624 defer st.Close() 2625 2626 res, err := st.http2(requestParam{ 2627 name: "TestH2APIBackendconfig", 2628 path: "/api/v1beta1/backendconfig", 2629 method: "PUT", 2630 body: []byte(`# comment 2631backend=127.0.0.1,3011 2632 2633`), 2634 }) 2635 if err != nil { 2636 t.Fatalf("Error st.http2() = %v", err) 2637 } 2638 if got, want := res.status, 200; got != want { 2639 t.Errorf("res.status: %v; want %v", got, want) 2640 } 2641 2642 var apiResp APIResponse 2643 err = json.Unmarshal(res.body, &apiResp) 2644 if err != nil { 2645 t.Fatalf("Error unmarshaling API response: %v", err) 2646 } 2647 if got, want := apiResp.Status, "Success"; got != want { 2648 t.Errorf("apiResp.Status: %v; want %v", got, want) 2649 } 2650 if got, want := apiResp.Code, 200; got != want { 2651 t.Errorf("apiResp.Status: %v; want %v", got, want) 2652 } 2653} 2654 2655// TestH2APIBackendconfigQuery exercise backendconfig API endpoint 2656// routine with query. 2657func TestH2APIBackendconfigQuery(t *testing.T) { 2658 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2659 t.Fatalf("request should not be forwarded") 2660 }, 3010) 2661 defer st.Close() 2662 2663 res, err := st.http2(requestParam{ 2664 name: "TestH2APIBackendconfigQuery", 2665 path: "/api/v1beta1/backendconfig?foo=bar", 2666 method: "PUT", 2667 body: []byte(`# comment 2668backend=127.0.0.1,3011 2669 2670`), 2671 }) 2672 if err != nil { 2673 t.Fatalf("Error st.http2() = %v", err) 2674 } 2675 if got, want := res.status, 200; got != want { 2676 t.Errorf("res.status: %v; want %v", got, want) 2677 } 2678 2679 var apiResp APIResponse 2680 err = json.Unmarshal(res.body, &apiResp) 2681 if err != nil { 2682 t.Fatalf("Error unmarshaling API response: %v", err) 2683 } 2684 if got, want := apiResp.Status, "Success"; got != want { 2685 t.Errorf("apiResp.Status: %v; want %v", got, want) 2686 } 2687 if got, want := apiResp.Code, 200; got != want { 2688 t.Errorf("apiResp.Status: %v; want %v", got, want) 2689 } 2690} 2691 2692// TestH2APIBackendconfigBadMethod exercise backendconfig API endpoint 2693// routine with bad method. 2694func TestH2APIBackendconfigBadMethod(t *testing.T) { 2695 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2696 t.Fatalf("request should not be forwarded") 2697 }, 3010) 2698 defer st.Close() 2699 2700 res, err := st.http2(requestParam{ 2701 name: "TestH2APIBackendconfigBadMethod", 2702 path: "/api/v1beta1/backendconfig", 2703 method: "GET", 2704 body: []byte(`# comment 2705backend=127.0.0.1,3011 2706 2707`), 2708 }) 2709 if err != nil { 2710 t.Fatalf("Error st.http2() = %v", err) 2711 } 2712 if got, want := res.status, 405; got != want { 2713 t.Errorf("res.status: %v; want %v", got, want) 2714 } 2715 2716 var apiResp APIResponse 2717 err = json.Unmarshal(res.body, &apiResp) 2718 if err != nil { 2719 t.Fatalf("Error unmarshaling API response: %v", err) 2720 } 2721 if got, want := apiResp.Status, "Failure"; got != want { 2722 t.Errorf("apiResp.Status: %v; want %v", got, want) 2723 } 2724 if got, want := apiResp.Code, 405; got != want { 2725 t.Errorf("apiResp.Status: %v; want %v", got, want) 2726 } 2727} 2728 2729// TestH2APIConfigrevision tests configrevision API. 2730func TestH2APIConfigrevision(t *testing.T) { 2731 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2732 t.Fatalf("request should not be forwarded") 2733 }, 3010) 2734 defer st.Close() 2735 2736 res, err := st.http2(requestParam{ 2737 name: "TestH2APIConfigrevision", 2738 path: "/api/v1beta1/configrevision", 2739 method: "GET", 2740 }) 2741 if err != nil { 2742 t.Fatalf("Error st.http2() = %v", err) 2743 } 2744 if got, want := res.status, 200; got != want { 2745 t.Errorf("res.status: %v; want = %v", got, want) 2746 } 2747 2748 var apiResp APIResponse 2749 d := json.NewDecoder(bytes.NewBuffer(res.body)) 2750 d.UseNumber() 2751 err = d.Decode(&apiResp) 2752 if err != nil { 2753 t.Fatalf("Error unmarshalling API response: %v", err) 2754 } 2755 if got, want := apiResp.Status, "Success"; got != want { 2756 t.Errorf("apiResp.Status: %v; want %v", got, want) 2757 } 2758 if got, want := apiResp.Code, 200; got != want { 2759 t.Errorf("apiResp.Status: %v; want %v", got, want) 2760 } 2761 if got, want := apiResp.Data["configRevision"], json.Number("0"); got != want { 2762 t.Errorf(`apiResp.Data["configRevision"]: %v %t; want %v`, got, got, want) 2763 } 2764} 2765 2766// TestH2APINotFound exercise backendconfig API endpoint routine when 2767// API endpoint is not found. 2768func TestH2APINotFound(t *testing.T) { 2769 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3010;api;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2770 t.Fatalf("request should not be forwarded") 2771 }, 3010) 2772 defer st.Close() 2773 2774 res, err := st.http2(requestParam{ 2775 name: "TestH2APINotFound", 2776 path: "/api/notfound", 2777 method: "GET", 2778 body: []byte(`# comment 2779backend=127.0.0.1,3011 2780 2781`), 2782 }) 2783 if err != nil { 2784 t.Fatalf("Error st.http2() = %v", err) 2785 } 2786 if got, want := res.status, 404; got != want { 2787 t.Errorf("res.status: %v; want %v", got, want) 2788 } 2789 2790 var apiResp APIResponse 2791 err = json.Unmarshal(res.body, &apiResp) 2792 if err != nil { 2793 t.Fatalf("Error unmarshaling API response: %v", err) 2794 } 2795 if got, want := apiResp.Status, "Failure"; got != want { 2796 t.Errorf("apiResp.Status: %v; want %v", got, want) 2797 } 2798 if got, want := apiResp.Code, 404; got != want { 2799 t.Errorf("apiResp.Status: %v; want %v", got, want) 2800 } 2801} 2802 2803// TestH2Healthmon tests health monitor endpoint. 2804func TestH2Healthmon(t *testing.T) { 2805 st := newServerTesterConnectPort([]string{"-f127.0.0.1,3011;healthmon;no-tls"}, t, func(w http.ResponseWriter, r *http.Request) { 2806 t.Fatalf("request should not be forwarded") 2807 }, 3011) 2808 defer st.Close() 2809 2810 res, err := st.http2(requestParam{ 2811 name: "TestH2Healthmon", 2812 path: "/alpha/bravo", 2813 }) 2814 if err != nil { 2815 t.Fatalf("Error st.http2() = %v", err) 2816 } 2817 if got, want := res.status, 200; got != want { 2818 t.Errorf("res.status: %v; want %v", got, want) 2819 } 2820} 2821 2822// TestH2ResponseBeforeRequestEnd tests the situation where response 2823// ends before request body finishes. 2824func TestH2ResponseBeforeRequestEnd(t *testing.T) { 2825 st := newServerTester([]string{"--mruby-file=" + testDir + "/req-return.rb"}, t, func(w http.ResponseWriter, r *http.Request) { 2826 t.Fatal("request should not be forwarded") 2827 }) 2828 defer st.Close() 2829 2830 res, err := st.http2(requestParam{ 2831 name: "TestH2ResponseBeforeRequestEnd", 2832 noEndStream: true, 2833 }) 2834 if err != nil { 2835 t.Fatalf("Error st.http2() = %v", err) 2836 } 2837 if got, want := res.status, 404; got != want { 2838 t.Errorf("res.status: %v; want %v", got, want) 2839 } 2840} 2841