@marcel91200 / caddy Mirror · read-only / commits / 0b265eb8
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 11, 11:00 UTC

reverseproxy: Add regression test for DialInfo network override (#7758)

Eyüp Can Akman committed May 20, 2026 at 16:43 UTC 0b265eb845efd76045e8d8327a72c7d8d27fa2c4
1 file changed +85
modules/caddyhttp/reverseproxy/httptransport_test.go
+85
@@ -4,11 +4,14 @@ import (
4 "context"
5 "encoding/json"
6 "fmt"
7 + "net"
8 + "net/url"
9 "reflect"
10 "testing"
11
12 "github.com/caddyserver/caddy/v2"
13 "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
14 + "github.com/caddyserver/caddy/v2/modules/caddyhttp"
15 )
16
17 func TestHTTPTransportUnmarshalCaddyFileWithCaPools(t *testing.T) {
@@ -194,3 +197,85 @@ func TestHTTPTransport_DialTLSContext_ProxyProtocol(t *testing.T) {
197 })
198 }
199 }
200 +
201 +// TestHTTPTransport_DialContext_DialInfoOverride is a regression test for
202 +// issue #6447: a `tcp4/`-prefixed upstream silently fell back to plain `tcp`
203 +// because dialContext only honored DialInfo for unix networks. PR #7300 widened
204 +// the condition so DialInfo is honored when no upstream HTTP proxy is in use,
205 +// and skipped (for non-unix networks) when one is. Both halves are pinned here.
206 +func TestHTTPTransport_DialContext_DialInfoOverride(t *testing.T) {
207 + ctx, cancel := caddy.NewContext(caddy.Context{Context: context.Background()})
208 + defer cancel()
209 +
210 + ln, err := net.Listen("tcp4", "127.0.0.1:0")
211 + if err != nil {
212 + t.Fatalf("listen: %v", err)
213 + }
214 + t.Cleanup(func() { ln.Close() })
215 + go func() {
216 + for {
217 + c, err := ln.Accept()
218 + if err != nil {
219 + return
220 + }
221 + c.Close()
222 + }
223 + }()
224 +
225 + ht := &HTTPTransport{}
226 + rt, err := ht.NewTransport(ctx)
227 + if err != nil {
228 + t.Fatalf("NewTransport: %v", err)
229 + }
230 +
231 + proxyURL, err := url.Parse("http://proxy.example:8080")
232 + if err != nil {
233 + t.Fatalf("parse proxy URL: %v", err)
234 + }
235 +
236 + tests := []struct {
237 + name string
238 + proxy bool
239 + dialInfo string
240 + defaultAddr string
241 + }{
242 + {
243 + // no proxy: DialInfo should be applied, so the dial lands on
244 + // the live listener despite the bogus default address.
245 + name: "honors DialInfo when no proxy",
246 + proxy: false,
247 + dialInfo: ln.Addr().String(),
248 + defaultAddr: "127.0.0.1:1",
249 + },
250 + {
251 + // proxy active: DialInfo must NOT be applied for non-unix
252 + // networks; the default address (the live listener) is used.
253 + name: "skips DialInfo when proxy active",
254 + proxy: true,
255 + dialInfo: "127.0.0.1:1",
256 + defaultAddr: ln.Addr().String(),
257 + },
258 + }
259 +
260 + for _, tt := range tests {
261 + t.Run(tt.name, func(t *testing.T) {
262 + dialCtx := context.WithValue(context.Background(), caddyhttp.VarsCtxKey, make(map[string]any))
263 + caddyhttp.SetVar(dialCtx, dialInfoVarKey, DialInfo{
264 + Network: "tcp4",
265 + Address: tt.dialInfo,
266 + })
267 + if tt.proxy {
268 + caddyhttp.SetVar(dialCtx, proxyVarKey, proxyURL)
269 + }
270 +
271 + conn, err := rt.DialContext(dialCtx, "tcp", tt.defaultAddr)
272 + if err != nil {
273 + t.Fatalf("DialContext: %v", err)
274 + }
275 + t.Cleanup(func() { conn.Close() })
276 + if got := conn.RemoteAddr().String(); got != ln.Addr().String() {
277 + t.Fatalf("conn.RemoteAddr() = %s, want %s", got, ln.Addr().String())
278 + }
279 + })
280 + }
281 +}