Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 12, 00:45 UTC
reverseproxy: Use DialTLSContext if ServerName has placeholder (#6955)
Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
WeidiDeng committed
Apr 28, 2025 at 23:14 UTC
aa3d20be3ee451af9465470a28937690104e9422
1 file changed
+32
-38
modules/caddyhttp/reverseproxy/httptransport.go
+32
-38
@@ -382,6 +382,36 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
382
if err != nil {
383
return nil, fmt.Errorf("making TLS client config: %v", err)
384
}
385
+
386
+ // servername has a placeholder, so we need to replace it
387
+ if strings.Contains(h.TLS.ServerName, "{") {
388
+ rt.DialTLSContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
389
+ // reuses the dialer from above to establish a plaintext connection
390
+ conn, err := dialContext(ctx, network, addr)
391
+ if err != nil {
392
+ return nil, err
393
+ }
394
+
395
+ // but add our own handshake logic
396
+ repl := ctx.Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
397
+ tlsConfig := rt.TLSClientConfig.Clone()
398
+ tlsConfig.ServerName = repl.ReplaceAll(tlsConfig.ServerName, "")
399
+ tlsConn := tls.Client(conn, tlsConfig)
400
+
401
+ // complete the handshake before returning the connection
402
+ if rt.TLSHandshakeTimeout != 0 {
403
+ var cancel context.CancelFunc
404
+ ctx, cancel = context.WithTimeout(ctx, rt.TLSHandshakeTimeout)
405
+ defer cancel()
406
+ }
407
+ err = tlsConn.HandshakeContext(ctx)
408
+ if err != nil {
409
+ _ = tlsConn.Close()
410
+ return nil, err
411
+ }
412
+ return tlsConn, nil
413
+ }
414
+ }
415
}
416
417
if h.KeepAlive != nil {
@@ -453,45 +483,9 @@ func (h *HTTPTransport) NewTransport(caddyCtx caddy.Context) (*http.Transport, e
483
return rt, nil
484
}
485
456
-// replaceTLSServername checks TLS servername to see if it needs replacing
457
-// if it does need replacing, it creates a new cloned HTTPTransport object to avoid any races
458
-// and does the replacing of the TLS servername on that and returns the new object
459
-// if no replacement is necessary it returns the original
460
-func (h *HTTPTransport) replaceTLSServername(repl *caddy.Replacer) *HTTPTransport {
461
- // check whether we have TLS and need to replace the servername in the TLSClientConfig
462
- if h.TLSEnabled() && strings.Contains(h.TLS.ServerName, "{") {
463
- // make a new h, "copy" the parts we don't need to touch, add a new *tls.Config and replace servername
464
- newtransport := &HTTPTransport{
465
- Resolver: h.Resolver,
466
- TLS: h.TLS,
467
- KeepAlive: h.KeepAlive,
468
- Compression: h.Compression,
469
- MaxConnsPerHost: h.MaxConnsPerHost,
470
- DialTimeout: h.DialTimeout,
471
- FallbackDelay: h.FallbackDelay,
472
- ResponseHeaderTimeout: h.ResponseHeaderTimeout,
473
- ExpectContinueTimeout: h.ExpectContinueTimeout,
474
- MaxResponseHeaderSize: h.MaxResponseHeaderSize,
475
- WriteBufferSize: h.WriteBufferSize,
476
- ReadBufferSize: h.ReadBufferSize,
477
- Versions: h.Versions,
478
- Transport: h.Transport.Clone(),
479
- h2cTransport: h.h2cTransport,
480
- }
481
- newtransport.Transport.TLSClientConfig.ServerName = repl.ReplaceAll(newtransport.Transport.TLSClientConfig.ServerName, "")
482
- return newtransport
483
- }
484
-
485
- return h
486
-}
487
-
486
// RoundTrip implements http.RoundTripper.
487
func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
490
- // Try to replace TLS servername if needed
491
- repl := req.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
492
- transport := h.replaceTLSServername(repl)
493
-
494
- transport.SetScheme(req)
488
+ h.SetScheme(req)
489
490
// use HTTP/3 if enabled (TODO: This is EXPERIMENTAL)
491
if h.h3Transport != nil {
@@ -507,7 +501,7 @@ func (h *HTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
501
return h.h2cTransport.RoundTrip(req)
502
}
503
510
- return transport.Transport.RoundTrip(req)
504
+ return h.Transport.RoundTrip(req)
505
}
506
507
// SetScheme ensures that the outbound request req