diff --git a/docs/content/migration/v2.md b/docs/content/migration/v2.md index e0c000cad..c0a58100b 100644 --- a/docs/content/migration/v2.md +++ b/docs/content/migration/v2.md @@ -637,3 +637,15 @@ Increasing the `readTimeout` value could be the solution notably if you are deal - TCP: `Error while handling TCP connection: readfrom tcp X.X.X.X:X->X.X.X.X:X: read tcp X.X.X.X:X->X.X.X.X:X: i/o timeout` - HTTP: `'499 Client Closed Request' caused by: context canceled` - HTTP: `ReverseProxy read error during body copy: read tcp X.X.X.X:X->X.X.X.X:X: use of closed network connection` + +## v2.11.3 + +### Connection headers + +In `v2.11.3`, the handling of the request Connection headers directives has changed to prevent any abuse. +Before, Traefik removed any header listed in the Connection header just before forwarding the request to the backends. +Now, Traefik removes the headers listed in the Connection header as soon as the request is handled. +As a consequence, middlewares do not have access to those Connection headers, +and a new option has been introduced to specify which ones could go through the middleware chain before being removed: `.forwardedHeaders.connection`. + +Please check out the [entrypoint forwarded headers connection option configuration](../routing/entrypoints.md#forwarded-headers) documentation. diff --git a/pkg/middlewares/auth/connectionheader.go b/pkg/middlewares/auth/connectionheader.go index 1cd1da81a..8b78b9430 100644 --- a/pkg/middlewares/auth/connectionheader.go +++ b/pkg/middlewares/auth/connectionheader.go @@ -13,34 +13,26 @@ const ( upgradeHeader = "Upgrade" ) -// Remover removes hop-by-hop headers listed in the "Connection" header. +// RemoveConnectionHeaders removes hop-by-hop headers listed in the "Connection" header. // See RFC 7230, section 6.1. -func Remover(next http.Handler) http.HandlerFunc { - return func(rw http.ResponseWriter, req *http.Request) { - var reqUpType string - if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) { - reqUpType = req.Header.Get(upgradeHeader) - } - - removeConnectionHeaders(req.Header) - - if reqUpType != "" { - req.Header.Set(connectionHeader, upgradeHeader) - req.Header.Set(upgradeHeader, reqUpType) - } else { - req.Header.Del(connectionHeader) - } - - next.ServeHTTP(rw, req) +func RemoveConnectionHeaders(req *http.Request) { + var reqUpType string + if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) { + reqUpType = req.Header.Get(upgradeHeader) } -} -func removeConnectionHeaders(h http.Header) { - for _, f := range h[connectionHeader] { + for _, f := range req.Header[connectionHeader] { for _, sf := range strings.Split(f, ",") { if sf = textproto.TrimString(sf); sf != "" { - h.Del(sf) + req.Header.Del(sf) } } } + + if reqUpType != "" { + req.Header.Set(connectionHeader, upgradeHeader) + req.Header.Set(upgradeHeader, reqUpType) + } else { + req.Header.Del(connectionHeader) + } } diff --git a/pkg/middlewares/auth/connectionheader_test.go b/pkg/middlewares/auth/connectionheader_test.go index 00d719ef0..26854b858 100644 --- a/pkg/middlewares/auth/connectionheader_test.go +++ b/pkg/middlewares/auth/connectionheader_test.go @@ -50,19 +50,13 @@ func TestRemover(t *testing.T) { t.Run(test.desc, func(t *testing.T) { t.Parallel() - next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}) - - h := Remover(next) - req := httptest.NewRequest(http.MethodGet, "https://localhost", nil) for k, v := range test.reqHeaders { req.Header.Set(k, v) } - rw := httptest.NewRecorder() - - h.ServeHTTP(rw, req) + RemoveConnectionHeaders(req) assert.Equal(t, test.expected, req.Header) }) diff --git a/pkg/middlewares/auth/forward.go b/pkg/middlewares/auth/forward.go index 27d42973c..6004a01fa 100644 --- a/pkg/middlewares/auth/forward.go +++ b/pkg/middlewares/auth/forward.go @@ -89,7 +89,7 @@ func NewForward(ctx context.Context, next http.Handler, config dynamic.ForwardAu fa.authResponseHeadersRegex = re } - return Remover(fa), nil + return fa, nil } func (fa *forwardAuth) GetTracingInformation() (string, ext.SpanKindEnum) { @@ -195,6 +195,8 @@ func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) { utils.CopyHeaders(forwardReq.Header, req.Header) + + RemoveConnectionHeaders(forwardReq) utils.RemoveHeaders(forwardReq.Header, hopHeaders...) forwardReq.Header = filterForwardRequestHeaders(forwardReq.Header, allowedHeaders)