From 05e9974570a08df14b1162a1e98315d4ee9ec2ee Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 27 Mar 2023 16:22:59 -0400 Subject: caddyhttp: Determine real client IP if trusted proxies configured (#5104) * caddyhttp: Determine real client IP if trusted proxies configured * Support customizing client IP header * Implement client_ip matcher, deprecate remote_ip's forwarded option --- modules/caddyhttp/server.go | 74 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 65 insertions(+), 9 deletions(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 13ebbe6..eb61806 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -130,6 +130,17 @@ type Server struct { // to trust sensitive incoming `X-Forwarded-*` headers. TrustedProxiesRaw json.RawMessage `json:"trusted_proxies,omitempty" caddy:"namespace=http.ip_sources inline_key=source"` + // The headers from which the client IP address could be + // read from. These will be considered in order, with the + // first good value being used as the client IP. + // By default, only `X-Forwarded-For` is considered. + // + // This depends on `trusted_proxies` being configured and + // the request being validated as coming from a trusted + // proxy, otherwise the client IP will be set to the direct + // remote IP address. + ClientIPHeaders []string `json:"client_ip_headers,omitempty"` + // Enables access logging and configures how access logs are handled // in this server. To minimally enable access logs, simply set this // to a non-null, empty struct. @@ -690,10 +701,15 @@ func PrepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter // set up the context for the request ctx := context.WithValue(r.Context(), caddy.ReplacerCtxKey, repl) ctx = context.WithValue(ctx, ServerCtxKey, s) + + trusted, clientIP := determineTrustedProxy(r, s) ctx = context.WithValue(ctx, VarsCtxKey, map[string]any{ - TrustedProxyVarKey: determineTrustedProxy(r, s), + TrustedProxyVarKey: trusted, + ClientIPVarKey: clientIP, }) + ctx = context.WithValue(ctx, routeGroupCtxKey, make(map[string]struct{})) + var url2 url.URL // avoid letting this escape to the heap ctx = context.WithValue(ctx, OriginalRequestCtxKey, originalRequest(r, &url2)) r = r.WithContext(ctx) @@ -724,11 +740,12 @@ func originalRequest(req *http.Request, urlCopy *url.URL) http.Request { // determineTrustedProxy parses the remote IP address of // the request, and determines (if the server configured it) -// if the client is a trusted proxy. -func determineTrustedProxy(r *http.Request, s *Server) bool { +// if the client is a trusted proxy. If trusted, also returns +// the real client IP if possible. +func determineTrustedProxy(r *http.Request, s *Server) (bool, string) { // If there's no server, then we can't check anything if s == nil { - return false + return false, "" } // Parse the remote IP, ignore the error as non-fatal, @@ -738,7 +755,7 @@ func determineTrustedProxy(r *http.Request, s *Server) bool { // remote address and used an invalid value. clientIP, _, err := net.SplitHostPort(r.RemoteAddr) if err != nil { - return false + return false, "" } // Client IP may contain a zone if IPv6, so we need @@ -746,20 +763,56 @@ func determineTrustedProxy(r *http.Request, s *Server) bool { clientIP, _, _ = strings.Cut(clientIP, "%") ipAddr, err := netip.ParseAddr(clientIP) if err != nil { - return false + return false, "" } // Check if the client is a trusted proxy if s.trustedProxies == nil { - return false + return false, ipAddr.String() } for _, ipRange := range s.trustedProxies.GetIPRanges(r) { if ipRange.Contains(ipAddr) { - return true + // We trust the proxy, so let's try to + // determine the real client IP + return true, trustedRealClientIP(r, s.ClientIPHeaders, ipAddr.String()) } } - return false + return false, ipAddr.String() +} + +// trustedRealClientIP finds the client IP from the request assuming it is +// from a trusted client. If there is no client IP headers, then the +// direct remote address is returned. If there are client IP headers, +// then the first value from those headers is used. +func trustedRealClientIP(r *http.Request, headers []string, clientIP string) string { + // Read all the values of the configured client IP headers, in order + var values []string + for _, field := range headers { + values = append(values, r.Header.Values(field)...) + } + + // If we don't have any values, then give up + if len(values) == 0 { + return clientIP + } + + // Since there can be many header values, we need to + // join them together before splitting to get the full list + allValues := strings.Split(strings.Join(values, ","), ",") + + // Get first valid left-most IP address + for _, ip := range allValues { + ip, _, _ = strings.Cut(strings.TrimSpace(ip), "%") + ipAddr, err := netip.ParseAddr(ip) + if err != nil { + continue + } + return ipAddr.String() + } + + // We didn't find a valid IP + return clientIP } // cloneURL makes a copy of r.URL and returns a @@ -787,4 +840,7 @@ const ( // For tracking whether the client is a trusted proxy TrustedProxyVarKey string = "trusted_proxy" + + // For tracking the real client IP (affected by trusted_proxy) + ClientIPVarKey string = "client_ip" ) -- cgit v1.2.3 From 2b3046de36bad70bd7e48478c99a8a030fb35b98 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Mon, 27 Mar 2023 18:40:15 -0400 Subject: caddyhttp: Log request body bytes read (#5461) --- modules/caddyhttp/server.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index eb61806..82fdbe5 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -19,6 +19,7 @@ import ( "crypto/tls" "encoding/json" "fmt" + "io" "net" "net/http" "net/netip" @@ -259,6 +260,14 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { wrec := NewResponseRecorder(w, nil, nil) w = wrec + // wrap the request body in a LengthReader + // so we can track the number of bytes read from it + var bodyReader *lengthReader + if r.Body != nil { + bodyReader = &lengthReader{Source: r.Body} + r.Body = bodyReader + } + // capture the original version of the request accLog := s.accessLogger.With(loggableReq) @@ -285,7 +294,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { userID, _ := repl.GetString("http.auth.user.id") + reqBodyLength := 0 + if bodyReader != nil { + reqBodyLength = bodyReader.Length + } + log("handled request", + zap.Int("bytes_read", reqBodyLength), zap.String("user_id", userID), zap.Duration("duration", duration), zap.Int("size", wrec.Size()), @@ -826,6 +841,23 @@ func cloneURL(from, to *url.URL) { } } +// lengthReader is an io.ReadCloser that keeps track of the +// number of bytes read from the request body. +type lengthReader struct { + Source io.ReadCloser + Length int +} + +func (r *lengthReader) Read(b []byte) (int, error) { + n, err := r.Source.Read(b) + r.Length += n + return n, err +} + +func (r *lengthReader) Close() error { + return r.Source.Close() +} + // Context keys for HTTP request context values. const ( // For referencing the server instance -- cgit v1.2.3 From d8d87a378f37d31cfe6502cc66ac3c95fc799489 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Tue, 11 Apr 2023 01:05:02 +0800 Subject: caddyhttp: Serve http2 when listener wrapper doesn't return *tls.Conn (#4929) * Serve http2 when listener wrapper doesn't return *tls.Conn * close conn when h2server serveConn returns * merge from upstream * rebase from latest * run New and Closed ConnState hook for h2 conns * go fmt * fix lint * Add comments * reorder import --- modules/caddyhttp/server.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 82fdbe5..9721007 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -198,6 +198,7 @@ type Server struct { server *http.Server h3server *http3.Server h3listeners []net.PacketConn // TODO: we have to hold these because quic-go won't close listeners it didn't create + h2listeners []*http2Listener addresses []caddy.NetworkAddress trustedProxies IPRangeSource @@ -213,6 +214,16 @@ 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. + // Can be removed if https://github.com/golang/go/pull/56110 is ever merged. + if r.TLS == nil { + conn := r.Context().Value(ConnCtxKey).(net.Conn) + if csc, ok := conn.(connectionStateConn); ok { + r.TLS = new(tls.ConnectionState) + *r.TLS = csc.ConnectionState() + } + } + w.Header().Set("Server", "Caddy") // advertise HTTP/3, if enabled @@ -870,6 +881,9 @@ const ( // originally came into the server's entry handler OriginalRequestCtxKey caddy.CtxKey = "original_request" + // For referencing underlying net.Conn + ConnCtxKey caddy.CtxKey = "conn" + // For tracking whether the client is a trusted proxy TrustedProxyVarKey string = "trusted_proxy" -- cgit v1.2.3 From f0e39817746903bb24948893348ae1cab67f1e46 Mon Sep 17 00:00:00 2001 From: Dave Henderson Date: Wed, 26 Apr 2023 22:46:41 -0400 Subject: logging: Add traceID field to access logs when tracing is active (#5507) Co-authored-by: Francis Lavoie --- modules/caddyhttp/server.go | 95 ++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 40 deletions(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 9721007..fb71b1b 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -282,46 +282,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // capture the original version of the request accLog := s.accessLogger.With(loggableReq) - defer func() { - // this request may be flagged as omitted from the logs - if skipLog, ok := GetVar(r.Context(), SkipLogVar).(bool); ok && skipLog { - return - } - - repl.Set("http.response.status", wrec.Status()) // will be 0 if no response is written by us (Go will write 200 to client) - repl.Set("http.response.size", wrec.Size()) - repl.Set("http.response.duration", duration) - repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666) - - logger := accLog - if s.Logs != nil { - logger = s.Logs.wrapLogger(logger, r.Host) - } - - log := logger.Info - if wrec.Status() >= 400 { - log = logger.Error - } - - userID, _ := repl.GetString("http.auth.user.id") - - reqBodyLength := 0 - if bodyReader != nil { - reqBodyLength = bodyReader.Length - } - - log("handled request", - zap.Int("bytes_read", reqBodyLength), - zap.String("user_id", userID), - zap.Duration("duration", duration), - zap.Int("size", wrec.Size()), - zap.Int("status", wrec.Status()), - zap.Object("resp_headers", LoggableHTTPHeader{ - Header: wrec.Header(), - ShouldLogCredentials: shouldLogCredentials, - }), - ) - }() + defer s.logRequest(accLog, r, wrec, &duration, repl, bodyReader, shouldLogCredentials) } start := time.Now() @@ -703,6 +664,57 @@ func (s *Server) shouldLogRequest(r *http.Request) bool { return !s.Logs.SkipUnmappedHosts } +// logRequest logs the request to access logs, unless skipped. +func (s *Server) logRequest( + accLog *zap.Logger, r *http.Request, wrec ResponseRecorder, duration *time.Duration, + repl *caddy.Replacer, bodyReader *lengthReader, shouldLogCredentials bool, +) { + // this request may be flagged as omitted from the logs + if skipLog, ok := GetVar(r.Context(), SkipLogVar).(bool); ok && skipLog { + return + } + + repl.Set("http.response.status", wrec.Status()) // will be 0 if no response is written by us (Go will write 200 to client) + repl.Set("http.response.size", wrec.Size()) + repl.Set("http.response.duration", duration) + repl.Set("http.response.duration_ms", duration.Seconds()*1e3) // multiply seconds to preserve decimal (see #4666) + + logger := accLog + if s.Logs != nil { + logger = s.Logs.wrapLogger(logger, r.Host) + } + + log := logger.Info + if wrec.Status() >= 400 { + log = logger.Error + } + + userID, _ := repl.GetString("http.auth.user.id") + + reqBodyLength := 0 + if bodyReader != nil { + reqBodyLength = bodyReader.Length + } + + extra := r.Context().Value(ExtraLogFieldsCtxKey).(*ExtraLogFields) + + fieldCount := 6 + fields := make([]zapcore.Field, 0, fieldCount+len(extra.fields)) + fields = append(fields, + zap.Int("bytes_read", reqBodyLength), + zap.String("user_id", userID), + zap.Duration("duration", *duration), + zap.Int("size", wrec.Size()), + zap.Int("status", wrec.Status()), + zap.Object("resp_headers", LoggableHTTPHeader{ + Header: wrec.Header(), + ShouldLogCredentials: shouldLogCredentials, + })) + fields = append(fields, extra.fields...) + + log("handled request", fields...) +} + // protocol returns true if the protocol proto is configured/enabled. func (s *Server) protocol(proto string) bool { for _, p := range s.Protocols { @@ -738,6 +750,9 @@ func PrepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter var url2 url.URL // avoid letting this escape to the heap ctx = context.WithValue(ctx, OriginalRequestCtxKey, originalRequest(r, &url2)) + + ctx = context.WithValue(ctx, ExtraLogFieldsCtxKey, new(ExtraLogFields)) + r = r.WithContext(ctx) // once the pointer to the request won't change -- cgit v1.2.3 From cfc85ae8caf032c3ef92675a024fc5d1264ab7ce Mon Sep 17 00:00:00 2001 From: jjiang-stripe <55402658+jjiang-stripe@users.noreply.github.com> Date: Thu, 11 May 2023 09:34:05 -0700 Subject: caddyhttp: Add a getter for Server.name (#5531) --- modules/caddyhttp/server.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index fb71b1b..411ec72 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -733,6 +733,9 @@ func (s *Server) protocol(proto string) bool { // EXPERIMENTAL: Subject to change or removal. func (s *Server) Listeners() []net.Listener { return s.listeners } +// Name returns the server's name. +func (s *Server) Name() string { return s.name } + // PrepareRequest fills the request r for use in a Caddy HTTP handler chain. w and s can // be nil, but the handlers will lose response placeholders and access to the server. func PrepareRequest(r *http.Request, repl *caddy.Replacer, w http.ResponseWriter, s *Server) *http.Request { -- cgit v1.2.3 From cbf16f6d9eb77f37d6eb588ff3e54cfdfddecc21 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Tue, 16 May 2023 11:27:52 -0400 Subject: caddyhttp: Implement named routes, `invoke` directive (#5107) * caddyhttp: Implement named routes, `invoke` directive * gofmt * Add experimental marker * Adjust route compile comments --- modules/caddyhttp/server.go | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 411ec72..d2de09b 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -102,6 +102,16 @@ type Server struct { // The error routes work exactly like the normal routes. Errors *HTTPErrorConfig `json:"errors,omitempty"` + // NamedRoutes describes a mapping of reusable routes that can be + // invoked by their name. This can be used to optimize memory usage + // when the same route is needed for many subroutes, by having + // the handlers and matchers be only provisioned once, but used from + // many places. These routes are not executed unless they are invoked + // from another route. + // + // EXPERIMENTAL: Subject to change or removal. + NamedRoutes map[string]*Route `json:"named_routes,omitempty"` + // How to handle TLS connections. At least one policy is // required to enable HTTPS on this server if automatic // HTTPS is disabled or does not apply. -- cgit v1.2.3 From 29452647d803aa1259b4430b52349ce7ac1495a4 Mon Sep 17 00:00:00 2001 From: WeidiDeng Date: Sat, 20 May 2023 00:00:00 +0800 Subject: caddyhttp: Fix h3 shutdown (#5541) * swap h3server close and listener close, avoid quic-listener not closing * fix typo --- modules/caddyhttp/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index d2de09b..db370db 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -555,7 +555,7 @@ func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error } } - s.h3listeners = append(s.h3listeners, lnAny.(net.PacketConn)) + s.h3listeners = append(s.h3listeners, ln) //nolint:errcheck go s.h3server.ServeListener(h3ln) -- cgit v1.2.3 From 6a41b62e70f867eff30b38a8ff33e90108077b0f Mon Sep 17 00:00:00 2001 From: Dominik Roos Date: Wed, 14 Jun 2023 03:33:39 +0200 Subject: caddyhttp: Support custom network for HTTP/3 (#5573) Allow registering a custom network mapping for HTTP/3. This is useful if the original network for HTTP/1.1 and HTTP/2 is not a standard `unix`, `tcp4`, or `tcp6` network. To keep backwards compatibility, we fall back to `udp` if the original network is not registered in the mapping. Fixes #5555 --- modules/caddyhttp/server.go | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index db370db..4bbd23b 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -520,17 +520,7 @@ func (s *Server) findLastRouteWithHostMatcher() int { // not already done, and then uses that server to serve HTTP/3 over // the listener, with Server s as the handler. func (s *Server) serveHTTP3(addr caddy.NetworkAddress, tlsCfg *tls.Config) error { - switch addr.Network { - case "unix": - addr.Network = "unixgram" - case "tcp4": - addr.Network = "udp4" - case "tcp6": - addr.Network = "udp6" - default: - addr.Network = "udp" // TODO: Maybe a better default is to not enable HTTP/3 if we do not know the network? - } - + addr.Network = getHTTP3Network(addr.Network) lnAny, err := addr.Listen(s.ctx, 0, net.ListenConfig{}) if err != nil { return err @@ -918,3 +908,30 @@ const ( // For tracking the real client IP (affected by trusted_proxy) ClientIPVarKey string = "client_ip" ) + +var networkTypesHTTP3 = map[string]string{ + "unix": "unixgram", + "tcp4": "udp4", + "tcp6": "udp6", +} + +// RegisterNetworkHTTP3 registers a mapping from non-HTTP/3 network to HTTP/3 +// network. This should be called during init() and will panic if the network +// type is standard, reserved, or already registered. +// +// EXPERIMENTAL: Subject to change. +func RegisterNetworkHTTP3(originalNetwork, h3Network string) { + if _, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)]; ok { + panic("network type " + originalNetwork + " is already registered") + } + networkTypesHTTP3[originalNetwork] = h3Network +} + +func getHTTP3Network(originalNetwork string) string { + h3Network, ok := networkTypesHTTP3[strings.ToLower(originalNetwork)] + if !ok { + // TODO: Maybe a better default is to not enable HTTP/3 if we do not know the network? + return "udp" + } + return h3Network +} -- cgit v1.2.3 From cd486c25d168caf58f4b6fe5d3252df9432901ec Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Wed, 2 Aug 2023 16:03:26 -0400 Subject: caddyhttp: Make use of `http.ResponseController` (#5654) * caddyhttp: Make use of http.ResponseController Also syncs the reverseproxy implementation with stdlib's which now uses ResponseController as well https://github.com/golang/go/commit/2449bbb5e614954ce9e99c8a481ea2ee73d72d61 * Enable full-duplex for HTTP/1.1 * Appease linter * Add warning for builds with Go 1.20, so it's less surprising to users * Improved godoc for EnableFullDuplex, copied text from stdlib * Only wrap in encode if not already wrapped --- modules/caddyhttp/server.go | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 4bbd23b..69b02c7 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -82,6 +82,26 @@ type Server struct { // HTTP request headers. MaxHeaderBytes int `json:"max_header_bytes,omitempty"` + // Enable full-duplex communication for HTTP/1 requests. + // Only has an effect if Caddy was built with Go 1.21 or later. + // + // For HTTP/1 requests, the Go HTTP server by default consumes any + // unread portion of the request body before beginning to write the + // response, preventing handlers from concurrently reading from the + // request and writing the response. Enabling this option disables + // this behavior and permits handlers to continue to read from the + // request while concurrently writing the response. + // + // For HTTP/2 requests, the Go HTTP server always permits concurrent + // reads and responses, so this option has no effect. + // + // Test thoroughly with your HTTP clients, as some older clients may + // not support full-duplex HTTP/1 which can cause them to deadlock. + // See https://github.com/golang/go/issues/57786 for more info. + // + // TODO: This is an EXPERIMENTAL feature. Subject to change or removal. + EnableFullDuplex bool `json:"enable_full_duplex,omitempty"` + // Routes describes how this server will handle requests. // Routes are executed sequentially. First a route's matchers // are evaluated, then its grouping. If it matches and has @@ -264,6 +284,14 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { repl := caddy.NewReplacer() r = PrepareRequest(r, repl, w, s) + // enable full-duplex for HTTP/1, ensuring the entire + // request body gets consumed before writing the response + if s.EnableFullDuplex { + // TODO: Remove duplex_go12*.go abstraction once our + // minimum Go version is 1.21 or later + enableFullDuplex(w) + } + // encode the request for logging purposes before // it enters any handler chain; this is necessary // to capture the original request in case it gets -- cgit v1.2.3 From 431adc09805972196314b2b188904942cbe5dfee Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Mon, 7 Aug 2023 12:53:21 -0600 Subject: templates: Fix httpInclude (fix #5698) Allowable during feature freeze because this is a simple, non-invasive bug fix only. --- modules/caddyhttp/server.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index 69b02c7..b31e6e5 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -245,12 +245,14 @@ 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. - // Can be removed if https://github.com/golang/go/pull/56110 is ever merged. + // TODO: Can be removed if https://github.com/golang/go/pull/56110 is ever merged. if r.TLS == nil { - conn := r.Context().Value(ConnCtxKey).(net.Conn) - if csc, ok := conn.(connectionStateConn); ok { - r.TLS = new(tls.ConnectionState) - *r.TLS = csc.ConnectionState() + // 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.(connectionStateConn); ok { + r.TLS = new(tls.ConnectionState) + *r.TLS = csc.ConnectionState() + } } } -- cgit v1.2.3 From 6cdcc2a78208b1d30b37fb06780160fcad48aab4 Mon Sep 17 00:00:00 2001 From: Matt Holt Date: Wed, 9 Aug 2023 10:34:28 -0600 Subject: ci: Update to Go 1.21 (#5719) * ci: Update to Go 1.21 * Bump quic-go to v0.37.4 * Check EnableFullDuplex err * Linter bug suppression See https://github.com/timakin/bodyclose/issues/52 --------- Co-authored-by: Francis Lavoie --- modules/caddyhttp/server.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index b31e6e5..daef777 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -291,7 +291,10 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { if s.EnableFullDuplex { // TODO: Remove duplex_go12*.go abstraction once our // minimum Go version is 1.21 or later - enableFullDuplex(w) + err := enableFullDuplex(w) + if err != nil { + s.accessLogger.Warn("failed to enable full duplex", zap.Error(err)) + } } // encode the request for logging purposes before -- cgit v1.2.3 From d6f86cccf5fa5b4eb30141da390cf2439746c5da Mon Sep 17 00:00:00 2001 From: Jacob Gadikian Date: Mon, 14 Aug 2023 23:41:15 +0800 Subject: ci: use gci linter (#5708) * use gofmput to format code * use gci to format imports * reconfigure gci * linter autofixes * rearrange imports a little * export GOOS=windows golangci-lint run ./... --fix --- modules/caddyhttp/server.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'modules/caddyhttp/server.go') diff --git a/modules/caddyhttp/server.go b/modules/caddyhttp/server.go index daef777..cf17609 100644 --- a/modules/caddyhttp/server.go +++ b/modules/caddyhttp/server.go @@ -30,14 +30,15 @@ import ( "sync/atomic" "time" - "github.com/caddyserver/caddy/v2" - "github.com/caddyserver/caddy/v2/modules/caddyevents" - "github.com/caddyserver/caddy/v2/modules/caddytls" "github.com/caddyserver/certmagic" "github.com/quic-go/quic-go" "github.com/quic-go/quic-go/http3" "go.uber.org/zap" "go.uber.org/zap/zapcore" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/modules/caddyevents" + "github.com/caddyserver/caddy/v2/modules/caddytls" ) // Server describes an HTTP server. -- cgit v1.2.3