Merge current v2.11 into v3.1

This commit is contained in:
romain 2024-09-30 14:59:38 +02:00
commit b641d5cf2a
17 changed files with 50 additions and 128 deletions

View file

@ -640,3 +640,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` - 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: `'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` - 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: `<entrypoint>.forwardedHeaders.connection`.
Please check out the [entrypoint forwarded headers connection option configuration](../routing/entrypoints.md#forwarded-headers) documentation.

View file

@ -67,6 +67,8 @@ accessLog:
### `format` ### `format`
_Optional, Default="common"_
By default, logs are written using the Common Log Format (CLF). By default, logs are written using the Common Log Format (CLF).
To write logs in JSON, use `json` in the `format` option. To write logs in JSON, use `json` in the `format` option.
If the given format is unsupported, the default (CLF) is used instead. If the given format is unsupported, the default (CLF) is used instead.

View file

@ -136,6 +136,15 @@ api:
All the following endpoints must be accessed with a `GET` HTTP request. All the following endpoints must be accessed with a `GET` HTTP request.
!!! info "Pagination"
By default, up to 100 results are returned per page, and the next page can be checked using the `X-Next-Page` HTTP Header.
To control pagination, use the `page` and `per_page` query parameters.
```bash
curl https://traefik.example.com:8080/api/http/routers?page=2&per_page=20
```
| Path | Description | | Path | Description |
|--------------------------------|---------------------------------------------------------------------------------------------| |--------------------------------|---------------------------------------------------------------------------------------------|
| `/api/http/routers` | Lists all the HTTP routers information. | | `/api/http/routers` | Lists all the HTTP routers information. |

2
go.mod
View file

@ -33,7 +33,7 @@ require (
github.com/http-wasm/http-wasm-host-go v0.6.0 github.com/http-wasm/http-wasm-host-go v0.6.0
github.com/influxdata/influxdb-client-go/v2 v2.7.0 github.com/influxdata/influxdb-client-go/v2 v2.7.0
github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab // No tag on the repo. github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab // No tag on the repo.
github.com/klauspost/compress v1.17.9 github.com/klauspost/compress v1.17.11-0.20240927175842-8e14b1b5a913 // Required to have the content-type fix: https://github.com/klauspost/compress/pull/1011
github.com/kvtools/consul v1.0.2 github.com/kvtools/consul v1.0.2
github.com/kvtools/etcdv3 v1.0.2 github.com/kvtools/etcdv3 v1.0.2
github.com/kvtools/redis v1.1.0 github.com/kvtools/redis v1.1.0

4
go.sum
View file

@ -595,8 +595,8 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.11-0.20240927175842-8e14b1b5a913 h1:7s7Xd7zVElAw1qh/eh+tXDNfDNXXj38Tpq54eeG6/BM=
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.11-0.20240927175842-8e14b1b5a913/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=

View file

@ -13,22 +13,21 @@ const (
upgradeHeader = "Upgrade" 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. // See RFC 7230, section 6.1.
func Remover(next http.Handler) http.HandlerFunc { func RemoveConnectionHeaders(req *http.Request) {
return func(rw http.ResponseWriter, req *http.Request) {
next.ServeHTTP(rw, Remove(req))
}
}
// Remove removes hop-by-hop header on the request.
func Remove(req *http.Request) *http.Request {
var reqUpType string var reqUpType string
if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) { if httpguts.HeaderValuesContainsToken(req.Header[connectionHeader], upgradeHeader) {
reqUpType = req.Header.Get(upgradeHeader) reqUpType = req.Header.Get(upgradeHeader)
} }
removeConnectionHeaders(req.Header) for _, f := range req.Header[connectionHeader] {
for _, sf := range strings.Split(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
req.Header.Del(sf)
}
}
}
if reqUpType != "" { if reqUpType != "" {
req.Header.Set(connectionHeader, upgradeHeader) req.Header.Set(connectionHeader, upgradeHeader)
@ -36,16 +35,4 @@ func Remove(req *http.Request) *http.Request {
} else { } else {
req.Header.Del(connectionHeader) req.Header.Del(connectionHeader)
} }
return req
}
func removeConnectionHeaders(h http.Header) {
for _, f := range h[connectionHeader] {
for _, sf := range strings.Split(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
h.Del(sf)
}
}
}
} }

View file

@ -50,19 +50,13 @@ func TestRemover(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
h := Remover(next)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil) req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
for k, v := range test.reqHeaders { for k, v := range test.reqHeaders {
req.Header.Set(k, v) req.Header.Set(k, v)
} }
rw := httptest.NewRecorder() RemoveConnectionHeaders(req)
h.ServeHTTP(rw, req)
assert.Equal(t, test.expected, req.Header) assert.Equal(t, test.expected, req.Header)
}) })

View file

@ -120,8 +120,6 @@ func (fa *forwardAuth) GetTracingInformation() (string, string, trace.SpanKind)
func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) { func (fa *forwardAuth) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), fa.name, typeNameForward) logger := middlewares.GetLogger(req.Context(), fa.name, typeNameForward)
req = Remove(req)
forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil) forwardReq, err := http.NewRequestWithContext(req.Context(), http.MethodGet, fa.address, nil)
if err != nil { if err != nil {
logger.Debug().Msgf("Error calling %s. Cause %s", fa.address, err) logger.Debug().Msgf("Error calling %s. Cause %s", fa.address, err)
@ -262,6 +260,8 @@ func (fa *forwardAuth) buildModifier(authCookies []*http.Cookie) func(res *http.
func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) { func writeHeader(req, forwardReq *http.Request, trustForwardHeader bool, allowedHeaders []string) {
utils.CopyHeaders(forwardReq.Header, req.Header) utils.CopyHeaders(forwardReq.Header, req.Header)
RemoveConnectionHeaders(forwardReq)
utils.RemoveHeaders(forwardReq.Header, hopHeaders...) utils.RemoveHeaders(forwardReq.Header, hopHeaders...)
forwardReq.Header = filterForwardRequestHeaders(forwardReq.Header, allowedHeaders) forwardReq.Header = filterForwardRequestHeaders(forwardReq.Header, allowedHeaders)

View file

@ -554,8 +554,11 @@ func (p *Provider) resolveDefaultCertificate(ctx context.Context, domains []stri
p.resolvingDomainsMutex.Lock() p.resolvingDomainsMutex.Lock()
sort.Strings(domains) sortedDomains := make([]string, len(domains))
domainKey := strings.Join(domains, ",") copy(sortedDomains, domains)
sort.Strings(sortedDomains)
domainKey := strings.Join(sortedDomains, ",")
if _, ok := p.resolvingDomains[domainKey]; ok { if _, ok := p.resolvingDomains[domainKey]; ok {
p.resolvingDomainsMutex.Unlock() p.resolvingDomainsMutex.Unlock()
@ -955,12 +958,14 @@ func (p *Provider) certExists(validDomains []string) bool {
p.certificatesMu.RLock() p.certificatesMu.RLock()
defer p.certificatesMu.RUnlock() defer p.certificatesMu.RUnlock()
sort.Strings(validDomains) sortedDomains := make([]string, len(validDomains))
copy(sortedDomains, validDomains)
sort.Strings(sortedDomains)
for _, cert := range p.certificates { for _, cert := range p.certificates {
domains := cert.Certificate.Domain.ToStrArray() domains := cert.Certificate.Domain.ToStrArray()
sort.Strings(domains) sort.Strings(domains)
if reflect.DeepEqual(domains, validDomains) { if reflect.DeepEqual(domains, sortedDomains) {
return true return true
} }
} }

View file

@ -5,6 +5,8 @@ import (
"io/fs" "io/fs"
) )
// Files starting with . and _ are excluded by default
//
//go:embed static //go:embed static
var assets embed.FS var assets embed.FS

View file

@ -20,16 +20,13 @@
"dependencies": { "dependencies": {
"@quasar/extras": "^1.16.12", "@quasar/extras": "^1.16.12",
"axios": "^1.7.4", "axios": "^1.7.4",
"bowser": "^2.11.0",
"chart.js": "^4.4.1", "chart.js": "^4.4.1",
"core-js": "^3.35.1", "core-js": "^3.35.1",
"dot-prop": "^8.0.2", "dot-prop": "^8.0.2",
"iframe-resizer": "^4.3.9",
"lodash.isequal": "4.5.0", "lodash.isequal": "4.5.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"quasar": "^2.16.6", "quasar": "^2.16.6",
"query-string": "^8.1.0", "query-string": "^8.1.0",
"vh-check": "^2.0.5",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-chartjs": "^5.3.0", "vue-chartjs": "^5.3.0",
"vue-router": "^4.0.12", "vue-router": "^4.0.12",

View file

@ -13,9 +13,7 @@ module.exports = configure(function (ctx) {
// app boot file (/src/boot) // app boot file (/src/boot)
// --> boot files are part of "main.js" // --> boot files are part of "main.js"
boot: [ boot: [
'api', 'api'
'_hacks',
'_init'
], ],
css: [ css: [

View file

@ -1,16 +0,0 @@
import iframeResize from 'iframe-resizer/js/iframeResizer'
const resize = {
mounted (el, binding) {
const options = binding.value || {}
el.addEventListener('load', () => iframeResize(options, el))
},
unmounted (el) {
const resizableEl = el
if (resizableEl.iFrameResizer) {
resizableEl.iFrameResizer.removeListeners()
}
}
}
export default resize

View file

@ -1,10 +0,0 @@
import { APP } from '../_helpers/APP'
import Boot from '../_middleware/Boot'
export default async ({ app, router, store }) => {
app.use(Boot)
APP.root = app
APP.router = router
APP.store = store
}

View file

@ -1,13 +0,0 @@
import Bowser from 'bowser'
import vhCheck from 'vh-check'
const browser = Bowser.getParser(window.navigator.userAgent)
// In Mobile
if (browser.getPlatform().type === 'mobile') {
vhCheck()
}
export default async ({ app, Vue }) => {
}

View file

@ -1,30 +0,0 @@
import { APP } from '../_helpers/APP'
import errors from '../_helpers/Errors'
import resize from '../_directives/resize'
export default async ({ app, router }) => {
// Directives
app.directive('resize', resize)
// Router
// ----------------------------------------------
router.beforeEach(async (to, from, next) => {
// Set APP
APP.routeTo = to
APP.routeFrom = from
next()
})
// Api (axios)
// ----------------------------------------------
APP.api.interceptors.request.use((config) => {
console.log('interceptors -> config', config)
// config.headers['Accept'] = '*/*'
return config
})
APP.api.interceptors.response.use((response) => {
console.log('interceptors -> response', response)
return response
}, errors.handleResponse)
}

View file

@ -2267,11 +2267,6 @@ boolbase@^1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
bowser@^2.11.0:
version "2.11.0"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f"
integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -3864,11 +3859,6 @@ ieee754@^1.1.13, ieee754@^1.2.1:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
iframe-resizer@^4.3.9:
version "4.4.5"
resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.4.5.tgz#f5048636e7f2fb5d9a09cc2ae78eb2da55ad555c"
integrity sha512-U8bCywf/Gh07O69RXo6dXAzTtODQrxaHGHRI7Nt4ipXsuq6EMxVsOP/jjaP43YtXz/ibESS0uSVDN3sOGCzSmw==
ignore@^5.2.0, ignore@^5.2.4: ignore@^5.2.0, ignore@^5.2.4:
version "5.3.1" version "5.3.1"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
@ -6007,11 +5997,6 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
vh-check@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/vh-check/-/vh-check-2.0.5.tgz#1b70610461e9776176f23d172daae3c4761aed09"
integrity sha512-vHtIYWt9uLl2P2tLlatVpMwv9+ezuJCtMNjUVIpzd5Pa/dJXN8AtqkKmVRcNSlmXyCjkCkbMQX/Vs9axmdlfgg==
vite-jsconfig-paths@^2.0.1: vite-jsconfig-paths@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/vite-jsconfig-paths/-/vite-jsconfig-paths-2.0.1.tgz#d66e36d67596dd8a8e4a6ed6e6db20debc50b45e" resolved "https://registry.yarnpkg.com/vite-jsconfig-paths/-/vite-jsconfig-paths-2.0.1.tgz#d66e36d67596dd8a8e4a6ed6e6db20debc50b45e"