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
+}