Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion modules/caddyhttp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,21 @@ func (app *App) Start() error {
ErrorLog: serverLogger,
Protocols: new(http.Protocols),
ConnContext: func(ctx context.Context, c net.Conn) context.Context {
return context.WithValue(ctx, ConnCtxKey, c)
if nc, ok := c.(interface{ tlsNetConn() net.Conn }); ok {
var (
tlsConState *tls.ConnectionState
getTlsConStateFunc = func() *tls.ConnectionState {
if tlsConState != nil {
return tlsConState
}
tlsConStateVal := nc.tlsNetConn().(connectionStater).ConnectionState()
tlsConState = &tlsConStateVal
return tlsConState
}
)
ctx = context.WithValue(ctx, tlsConnectionStateFuncCtxKey, getTlsConStateFunc)
}
return ctx
},
}

Expand Down
17 changes: 16 additions & 1 deletion modules/caddyhttp/http2listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,36 @@ func (h *http2Listener) Accept() (net.Conn, error) {

// if both h1 and h2 are enabled, we don't need to check the preface
if h.useH1 && h.useH2 {
if isConnectionStater {
return tlsStateConn{conn}, nil
}
return conn, nil
}

// impossible both are false, either useH1 or useH2 must be true,
// or else the listener wouldn't be created
h2Conn := &http2Conn{
h2Expected: h.useH2,
logger: h.logger,
Conn: conn,
}
if isConnectionStater {
return http2StateConn{h2Conn}, nil
return tlsStateConn{http2StateConn{h2Conn}}, nil
}
return h2Conn, nil
}

// tlsStateConn wraps a net.Conn that implements connectionStater to hide that method
// we can call netConn to get the original net.Conn and get the tls connection state
// golang 1.25 will call that method, and it breaks h2 with connections other than *tls.Conn
type tlsStateConn struct {
net.Conn
}

func (conn tlsStateConn) tlsNetConn() net.Conn {
return conn.Conn
}

type http2StateConn struct {
*http2Conn
}
Expand Down
16 changes: 7 additions & 9 deletions modules/caddyhttp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,9 @@ type Server struct {
// ServeHTTP is the entry point for all HTTP requests.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// If there are listener wrappers that process tls connections but don't return a *tls.Conn, this field will be nil.
// TODO: Scheduled to be removed later because https://github.com/golang/go/pull/56110 has been merged.
if r.TLS == nil {
// not all requests have a conn (like virtual requests) - see #5698
if conn, ok := r.Context().Value(ConnCtxKey).(net.Conn); ok {
if csc, ok := conn.(connectionStater); ok {
r.TLS = new(tls.ConnectionState)
*r.TLS = csc.ConnectionState()
}
if tlsConnStateFunc, ok := r.Context().Value(tlsConnectionStateFuncCtxKey).(func() *tls.ConnectionState); ok {
r.TLS = tlsConnStateFunc()
}
}

Expand Down Expand Up @@ -1081,11 +1076,14 @@ const (
// originally came into the server's entry handler
OriginalRequestCtxKey caddy.CtxKey = "original_request"

// For referencing underlying net.Conn
// This will eventually be deprecated and not used. To refer to the underlying connection, implement a middleware plugin
// DEPRECATED: not used anymore.
// To refer to the underlying connection, implement a middleware plugin
// that RegisterConnContext during provisioning.
ConnCtxKey caddy.CtxKey = "conn"

// used to get the tls connection state in the context, if available
tlsConnectionStateFuncCtxKey caddy.CtxKey = "tls_connection_state_func"

// For tracking whether the client is a trusted proxy
TrustedProxyVarKey string = "trusted_proxy"

Expand Down
Loading