testProxyProtocolMatrix is the shared implementation for the proxy protocol tests. It: 1. Starts a go-proxyproto-wrapped backend. 2. Configures Caddy as a reverse proxy with the given PROXY protocol version and transport versions. 3. Sends numRequests GET requests through Caddy and asserts 200 OK e
(t *testing.T, ppVersion string, transportVersions []string, numRequests int)
| 473 | // 4. Asserts the backend recorded at least one PROXY header whose source host |
| 474 | // is 127.0.0.1 (the loopback address used by the test client). |
| 475 | func testProxyProtocolMatrix(t *testing.T, ppVersion string, transportVersions []string, numRequests int) { |
| 476 | t.Helper() |
| 477 | |
| 478 | backend := newProxyProtoBackend(t) |
| 479 | listenPort := freePort(t) |
| 480 | |
| 481 | tester := caddytest.NewTester(t) |
| 482 | tester.WithDefaultOverrides(caddytest.Config{ |
| 483 | AdminPort: 2999, |
| 484 | }) |
| 485 | cfg := proxyProtoConfig(listenPort, backend.addr(), ppVersion, transportVersions) |
| 486 | tester.InitServer(cfg, "json") |
| 487 | |
| 488 | // If the test is h2c-only (no "1.1" in versions), reconfigure the test |
| 489 | // client transport to use unencrypted HTTP/2 so we actually exercise the |
| 490 | // h2c code path through Caddy. |
| 491 | if slices.Contains(transportVersions, "h2c") && !slices.Contains(transportVersions, "1.1") { |
| 492 | tr, ok := tester.Client.Transport.(*http.Transport) |
| 493 | if ok { |
| 494 | tr.Protocols = new(http.Protocols) |
| 495 | tr.Protocols.SetHTTP1(false) |
| 496 | tr.Protocols.SetUnencryptedHTTP2(true) |
| 497 | } |
| 498 | } |
| 499 | |
| 500 | proxyURL := fmt.Sprintf("http://127.0.0.1:%d/", listenPort) |
| 501 | |
| 502 | for i := 0; i < numRequests; i++ { |
| 503 | resp, err := tester.Client.Get(proxyURL) |
| 504 | if err != nil { |
| 505 | t.Fatalf("request %d/%d: GET %s: %v", i+1, numRequests, proxyURL, err) |
| 506 | } |
| 507 | resp.Body.Close() |
| 508 | if resp.StatusCode != http.StatusOK { |
| 509 | t.Errorf("request %d/%d: expected status 200, got %d", i+1, numRequests, resp.StatusCode) |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | // The backend must have seen at least one PROXY header. For h1, there is |
| 514 | // one per request; for h2c, requests share the same connection so only one |
| 515 | // header is written at connection establishment. |
| 516 | addrs := backend.recordedAddrs() |
| 517 | if len(addrs) == 0 { |
| 518 | t.Fatalf("backend recorded no PROXY protocol addresses (expected at least 1)") |
| 519 | } |
| 520 | |
| 521 | // Every PROXY-decoded source address must be the loopback address since |
| 522 | // the test client always connects from 127.0.0.1. |
| 523 | for i, addr := range addrs { |
| 524 | host, _, err := net.SplitHostPort(addr) |
| 525 | if err != nil { |
| 526 | t.Errorf("addr[%d] %q: SplitHostPort: %v", i, addr, err) |
| 527 | continue |
| 528 | } |
| 529 | if host != "127.0.0.1" { |
| 530 | t.Errorf("addr[%d]: expected source 127.0.0.1, got %q", i, host) |
| 531 | } |
| 532 | } |
no test coverage detected