Merge branch v3.1 into master

This commit is contained in:
kevinpollet 2024-09-20 09:51:54 +02:00
commit a398536688
No known key found for this signature in database
GPG key ID: 0C9A5DDD1B292453
76 changed files with 1073 additions and 220 deletions

View file

@ -5,11 +5,13 @@ on:
branches: branches:
- '*' - '*'
paths: paths:
- '.github/workflows/test-conformance.yaml'
- 'pkg/provider/kubernetes/gateway/**' - 'pkg/provider/kubernetes/gateway/**'
- 'integration/fixtures/k8s-conformance/**'
- 'integration/k8s_conformance_test.go' - 'integration/k8s_conformance_test.go'
env: env:
GO_VERSION: '1.22' GO_VERSION: '1.23'
CGO_ENABLED: 0 CGO_ENABLED: 0
jobs: jobs:

View file

@ -8,7 +8,7 @@ on:
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.23'
GOLANGCI_LINT_VERSION: v1.60.3 GOLANGCI_LINT_VERSION: v1.60.3
MISSSPELL_VERSION: v0.6.0 MISSPELL_VERSION: v0.6.0
jobs: jobs:
@ -29,8 +29,8 @@ jobs:
- name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }} - name: Install golangci-lint ${{ env.GOLANGCI_LINT_VERSION }}
run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION} run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin ${GOLANGCI_LINT_VERSION}
- name: Install missspell ${{ env.MISSSPELL_VERSION }} - name: Install misspell ${{ env.MISSPELL_VERSION }}
run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSSPELL_VERSION} run: curl -sfL https://raw.githubusercontent.com/golangci/misspell/master/install-misspell.sh | sh -s -- -b $(go env GOPATH)/bin ${MISSPELL_VERSION}
- name: Avoid generating webui - name: Avoid generating webui
run: touch webui/static/index.html run: touch webui/static/index.html

View file

@ -1,3 +1,63 @@
## [v3.1.4](https://github.com/traefik/traefik/tree/v3.1.4) (2024-09-19)
[All Commits](https://github.com/traefik/traefik/compare/v3.1.3...v3.1.4)
**Bug fixes:**
- **[metrics]** Guess Datadog socket type when prefix is unix ([#11102](https://github.com/traefik/traefik/pull/11102) by [kevinpollet](https://github.com/kevinpollet))
**Documentation:**
- Mention v3 in readme ([#11082](https://github.com/traefik/traefik/pull/11082) by [kabaluyot](https://github.com/kabaluyot))
**Misc:**
- Merge branch v2.11 into v3.1 ([#11107](https://github.com/traefik/traefik/pull/11107) by [rtribotte](https://github.com/rtribotte))
## [v2.11.10](https://github.com/traefik/traefik/tree/v2.11.10) (2024-09-19)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.9...v2.11.10)
**Bug fixes:**
- **[http3]** Bump github.com/quic-go/quic-go to v0.47.0 ([#11104](https://github.com/traefik/traefik/pull/11104) by [rtribotte](https://github.com/rtribotte))
- **[server]** Check if ACME certificate resolver is not nil ([#11103](https://github.com/traefik/traefik/pull/11103) by [kevinpollet](https://github.com/kevinpollet))
## [v3.1.3](https://github.com/traefik/traefik/tree/v3.1.3) (2024-09-16)
[All Commits](https://github.com/traefik/traefik/compare/v3.1.2...v3.1.3)
**Bug fixes:**
- **[k8s/ingress,rules,k8s]** Allow configuring rule syntax with Kubernetes Ingress annotation ([#10985](https://github.com/traefik/traefik/pull/10985) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress]** Re-allow empty configuration for Kubernetes Ingress provider ([#11008](https://github.com/traefik/traefik/pull/11008) by [rtribotte](https://github.com/rtribotte))
- **[middleware,metrics]** Wrap capture for services used by pieces of middleware ([#11058](https://github.com/traefik/traefik/pull/11058) by [rtribotte](https://github.com/rtribotte))
- **[plugins]** Removes goexport dependency and adds _initialize ([#11088](https://github.com/traefik/traefik/pull/11088) by [juliens](https://github.com/juliens))
**Documentation:**
- **[k8s/crd,k8s]** Remove mentions about APIVersion traefik.io/v1 ([#11020](https://github.com/traefik/traefik/pull/11020) by [rtribotte](https://github.com/rtribotte))
- **[k8s]** Update quick-start-with-kubernetes.md to include required permissions ([#11010](https://github.com/traefik/traefik/pull/11010) by [eastmane](https://github.com/eastmane))
- **[metrics]** Mention missing metrics removal in the migration guide ([#10982](https://github.com/traefik/traefik/pull/10982) by [rtribotte](https://github.com/rtribotte))
- **[tracing]** Fix tracing documentation ([#11067](https://github.com/traefik/traefik/pull/11067) by [mmatur](https://github.com/mmatur))
- **[tracing]** OTLP doc + potential panic ([#11052](https://github.com/traefik/traefik/pull/11052) by [mmatur](https://github.com/mmatur))
**Misc:**
- Merge v2.11 into v3.1 ([#11092](https://github.com/traefik/traefik/pull/11092) by [kevinpollet](https://github.com/kevinpollet))
- Merge v2.11 into v3.1 ([#11065](https://github.com/traefik/traefik/pull/11065) by [mmatur](https://github.com/mmatur))
- Merge v2.11 into v3.1 ([#11044](https://github.com/traefik/traefik/pull/11044) by [rtribotte](https://github.com/rtribotte))
## [v2.11.9](https://github.com/traefik/traefik/tree/v2.11.9) (2024-09-16)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.8...v2.11.9)
**Bug fixes:**
- **[acme]** Update go-acme/lego to v4.18.0 ([#11060](https://github.com/traefik/traefik/pull/11060) by [ldez](https://github.com/ldez))
- **[acme]** Allow handling ACME challenges with custom routers ([#10981](https://github.com/traefik/traefik/pull/10981) by [rtribotte](https://github.com/rtribotte))
- **[logs,middleware]** Make the keys of the accessLog.fields.names map case-insensitive ([#11040](https://github.com/traefik/traefik/pull/11040) by [SpecLad](https://github.com/SpecLad))
- **[logs,middleware]** Ensure proper logs for aborted streaming responses ([#10819](https://github.com/traefik/traefik/pull/10819) by [hood](https://github.com/hood))
- **[middleware,server]** Cleanup Connection headers before passing the middleware chain ([#11077](https://github.com/traefik/traefik/pull/11077) by [kevinpollet](https://github.com/kevinpollet))
- **[plugins]** Upgrade paerser to v0.2.1 ([#11048](https://github.com/traefik/traefik/pull/11048) by [mmatur](https://github.com/mmatur))
- **[server,tcp]** Prevent error logging when TCP WRR pool is empty ([#10989](https://github.com/traefik/traefik/pull/10989) by [kevinpollet](https://github.com/kevinpollet))
- **[webui]** Upgrade webui dependencies ([#11031](https://github.com/traefik/traefik/pull/11031) by [mloiseleur](https://github.com/mloiseleur))
**Documentation:**
- **[acme]** Fix typo in multiple DNS challenge provider warning ([#11001](https://github.com/traefik/traefik/pull/11001) by [tired-engineer](https://github.com/tired-engineer))
- **[k8s]** Update k8s quickstart permissions ([#11049](https://github.com/traefik/traefik/pull/11049) by [mmatur](https://github.com/mmatur))
- **[metrics]** Remove documentation for unimplemented service retries metric ([#10983](https://github.com/traefik/traefik/pull/10983) by [rtribotte](https://github.com/rtribotte))
- **[middleware]** Unify tab titles ([#11072](https://github.com/traefik/traefik/pull/11072) by [jsoref](https://github.com/jsoref))
- Give valid examples for exposing dashboard with default Helm values ([#11015](https://github.com/traefik/traefik/pull/11015) by [holysoles](https://github.com/holysoles))
## [v3.1.2](https://github.com/traefik/traefik/tree/v3.1.2) (2024-08-06) ## [v3.1.2](https://github.com/traefik/traefik/tree/v3.1.2) (2024-08-06)
[All Commits](https://github.com/traefik/traefik/compare/v3.1.1...v3.1.2) [All Commits](https://github.com/traefik/traefik/compare/v3.1.1...v3.1.2)

View file

@ -47,7 +47,7 @@ Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
When an inapropriate behavior is reported, maintainers will discuss on the Maintainer's Discord before marking the message as "abuse". When an inappropriate behavior is reported, maintainers will discuss on the Maintainer's Discord before marking the message as "abuse".
This conversation beforehand avoids one-sided decisions. This conversation beforehand avoids one-sided decisions.
The first message will be edited and marked as abuse. The first message will be edited and marked as abuse.

View file

@ -35,7 +35,8 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
--- ---
:warning: Please be aware that the old configurations for Traefik v1.x are NOT compatible with the v2.x config as of now. If you're running v2, please ensure you are using a [v2 configuration](https://doc.traefik.io/traefik/). :warning: When migrating to a new major version of Traefik, please refer to the [migration guide](https://doc.traefik.io/traefik/migration/v2-to-v3/) to ensure a smooth transition and to be aware of any breaking changes.
## Overview ## Overview
@ -87,7 +88,7 @@ You can access the simple HTML frontend of Traefik.
## Documentation ## Documentation
You can find the complete documentation of Traefik v2 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/). You can find the complete documentation of Traefik v3 at [https://doc.traefik.io/traefik/](https://doc.traefik.io/traefik/).
A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io). A collection of contributions around Traefik can be found at [https://awesome.traefik.io](https://awesome.traefik.io).

View file

@ -364,7 +364,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
if _, ok := resolverNames[rt.TLS.CertResolver]; !ok { if _, ok := resolverNames[rt.TLS.CertResolver]; !ok {
log.Error().Err(err).Str(logs.RouterName, rtName).Str("certificateResolver", rt.TLS.CertResolver). log.Error().Err(err).Str(logs.RouterName, rtName).Str("certificateResolver", rt.TLS.CertResolver).
Msg("Router uses a non-existent certificate resolver") Msg("Router uses a nonexistent certificate resolver")
} }
} }
}) })

View file

@ -11,7 +11,7 @@ Automatic HTTPS
You can configure Traefik to use an ACME provider (like Let's Encrypt) for automatic certificate generation. You can configure Traefik to use an ACME provider (like Let's Encrypt) for automatic certificate generation.
!!! warning "Let's Encrypt and Rate Limiting" !!! warning "Let's Encrypt and Rate Limiting"
Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to **one week**, and can not be overridden. Note that Let's Encrypt API has [rate limiting](https://letsencrypt.org/docs/rate-limits). These last up to **one week**, and cannot be overridden.
When running Traefik in a container this file should be persisted across restarts. When running Traefik in a container this file should be persisted across restarts.
If Traefik requests new certificates each time it starts up, a crash-looping container can quickly reach Let's Encrypt's ratelimits. If Traefik requests new certificates each time it starts up, a crash-looping container can quickly reach Let's Encrypt's ratelimits.
@ -298,7 +298,7 @@ Use the `DNS-01` challenge to generate and renew ACME certificates by provisioni
Multiple DNS challenge provider are not supported with Traefik, but you can use `CNAME` to handle that. Multiple DNS challenge provider are not supported with Traefik, but you can use `CNAME` to handle that.
For example, if you have `example.org` (account foo) and `example.com` (account bar) you can create a CNAME on `example.org` called `_acme-challenge.example.org` pointing to `challenge.example.com`. For example, if you have `example.org` (account foo) and `example.com` (account bar) you can create a CNAME on `example.org` called `_acme-challenge.example.org` pointing to `challenge.example.com`.
This way, you can obtain certificates for `example.com` with the `foo` account. This way, you can obtain certificates for `example.org` with the `bar` account.
!!! important !!! important
A `provider` is mandatory. A `provider` is mandatory.

View file

@ -278,7 +278,7 @@ spec:
requestHost: true requestHost: true
``` ```
```yaml tab="Cosul Catalog" ```yaml tab="Consul Catalog"
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true" - "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true"
``` ```

View file

@ -24,7 +24,7 @@ whoami:
- "traefik.http.routers.router1.middlewares=foo-add-prefix@docker" - "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"
``` ```
```yaml tab="Kubernetes IngressRoute" ```yaml tab="IngressRoute"
# As a Kubernetes Traefik IngressRoute # As a Kubernetes Traefik IngressRoute
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1

View file

@ -35,7 +35,7 @@ whoami:
- "traefik.http.routers.router1.middlewares=foo-add-prefix@docker" - "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"
``` ```
```yaml tab="Kubernetes IngressRoute" ```yaml tab="IngressRoute"
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: Middleware kind: Middleware

View file

@ -24,7 +24,7 @@ whoami:
- "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@docker" - "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@docker"
``` ```
```yaml tab="Kubernetes IngressRoute" ```yaml tab="IngressRoute"
# As a Kubernetes Traefik IngressRoute # As a Kubernetes Traefik IngressRoute
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1

View file

@ -44,7 +44,7 @@ Then any router can refer to an instance of the wanted middleware.
- "traefik.frontend.auth.basic.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" - "traefik.frontend.auth.basic.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
``` ```
```yaml tab="K8s Ingress" ```yaml tab="Ingress"
apiVersion: networking.k8s.io/v1beta1 apiVersion: networking.k8s.io/v1beta1
kind: Ingress kind: Ingress
metadata: metadata:
@ -107,7 +107,7 @@ Then any router can refer to an instance of the wanted middleware.
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0" - "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
``` ```
```yaml tab="K8s IngressRoute" ```yaml tab="IngressRoute"
# The definitions below require the definitions for the Middleware and IngressRoute kinds. # The definitions below require the definitions for the Middleware and IngressRoute kinds.
# https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions # https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
@ -278,7 +278,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
] ]
``` ```
```yaml tab="K8s IngressRoute" ```yaml tab="IngressRoute"
# The definitions below require the definitions for the TLSOption and IngressRoute kinds. # The definitions below require the definitions for the TLSOption and IngressRoute kinds.
# https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions # https://doc.traefik.io/traefik/reference/dynamic-configuration/kubernetes-crd/#definitions
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
@ -442,7 +442,7 @@ To apply a redirection:
traefik.http.middlewares.https_redirect.redirectscheme.permanent: true traefik.http.middlewares.https_redirect.redirectscheme.permanent: true
``` ```
```yaml tab="K8s IngressRoute" ```yaml tab="IngressRoute"
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute
metadata: metadata:
@ -561,7 +561,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
- "traefik.frontend.rule=Host:example.org;PathPrefixStrip:/admin" - "traefik.frontend.rule=Host:example.org;PathPrefixStrip:/admin"
``` ```
```yaml tab="Kubernetes Ingress" ```yaml tab="Ingress"
apiVersion: networking.k8s.io/v1beta1 apiVersion: networking.k8s.io/v1beta1
kind: Ingress kind: Ingress
metadata: metadata:
@ -595,7 +595,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
- "traefik.http.middlewares.admin-stripprefix.stripprefix.prefixes=/admin" - "traefik.http.middlewares.admin-stripprefix.stripprefix.prefixes=/admin"
``` ```
```yaml tab="Kubernetes IngressRoute" ```yaml tab="IngressRoute"
--- ---
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute

View file

@ -432,7 +432,7 @@ For more advanced use cases, you can use either the [RedirectScheme middleware](
Following up on the deprecation started [previously](#x509-commonname-deprecation), Following up on the deprecation started [previously](#x509-commonname-deprecation),
as the `x509ignoreCN=0` value for the `GODEBUG` is [deprecated in Go 1.17](https://tip.golang.org/doc/go1.17#crypto/x509), as the `x509ignoreCN=0` value for the `GODEBUG` is [deprecated in Go 1.17](https://tip.golang.org/doc/go1.17#crypto/x509),
the legacy behavior related to the CommonName field can not be enabled at all anymore. the legacy behavior related to the CommonName field cannot be enabled at all anymore.
## v2.5.3 to v2.5.4 ## v2.5.3 to v2.5.4

View file

@ -27,7 +27,9 @@ _Required, Default="127.0.0.1:8125"_
Address instructs exporter to send metrics to datadog-agent at this address. Address instructs exporter to send metrics to datadog-agent at this address.
This address can be a Unix Domain Socket (UDS) address with the following form: `unix:///path/to/datadog.socket`. This address can be a Unix Domain Socket (UDS) in the following format: `unix:///path/to/datadog.socket`.
When the prefix is set to `unix`, the socket type will be automatically determined.
To explicitly define the socket type and avoid automatic detection, you can use the prefixes `unixgram` for `SOCK_DGRAM` (datagram sockets) and `unixstream` for `SOCK_STREAM` (stream sockets), respectively.
```yaml tab="File (YAML)" ```yaml tab="File (YAML)"
metrics: metrics:

View file

@ -33,7 +33,7 @@ traefik [--flag[=true|false| ]] [-f [true|false| ]]
All flags are documented in the [(static configuration) CLI reference](../reference/static-configuration/cli.md). All flags are documented in the [(static configuration) CLI reference](../reference/static-configuration/cli.md).
!!! info "Flags are case insensitive." !!! info "Flags are case-insensitive."
### `healthcheck` ### `healthcheck`

View file

@ -81,7 +81,7 @@ For the list of the providers names, see the [supported providers](#supported-pr
- "traefik.http.routers.my-container.middlewares=add-foo-prefix@file" - "traefik.http.routers.my-container.middlewares=add-foo-prefix@file"
``` ```
```yaml tab="Kubernetes Ingress Route" ```yaml tab="IngressRoute"
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: IngressRoute kind: IngressRoute
metadata: metadata:
@ -103,7 +103,7 @@ For the list of the providers names, see the [supported providers](#supported-pr
# when the cross-provider syntax is used. # when the cross-provider syntax is used.
``` ```
```yaml tab="Kubernetes Ingress" ```yaml tab="Ingress"
apiVersion: traefik.io/v1alpha1 apiVersion: traefik.io/v1alpha1
kind: Middleware kind: Middleware
metadata: metadata:

View file

@ -8,7 +8,7 @@ description: "View the reference for performing dynamic configurations with Trae
Dynamic configuration with Consul Catalog Dynamic configuration with Consul Catalog
{: .subtitle } {: .subtitle }
The labels are case insensitive. The labels are case-insensitive.
```yaml ```yaml
--8<-- "content/reference/dynamic-configuration/consul-catalog.yml" --8<-- "content/reference/dynamic-configuration/consul-catalog.yml"

View file

@ -8,7 +8,7 @@ description: "Learn how to do dynamic configuration in Traefik Proxy with AWS EC
Dynamic configuration with ECS provider Dynamic configuration with ECS provider
{: .subtitle } {: .subtitle }
The labels are case insensitive. The labels are case-insensitive.
```yaml ```yaml
--8<-- "content/reference/dynamic-configuration/ecs.yml" --8<-- "content/reference/dynamic-configuration/ecs.yml"

View file

@ -8,7 +8,7 @@ description: "View the reference for performing dynamic configurations with Trae
Dynamic configuration with Nomad Service Discovery Dynamic configuration with Nomad Service Discovery
{: .subtitle } {: .subtitle }
The labels are case insensitive. The labels are case-insensitive.
```yaml ```yaml
--8<-- "content/reference/dynamic-configuration/nomad.yml" --8<-- "content/reference/dynamic-configuration/nomad.yml"

View file

@ -126,9 +126,15 @@ Entry points definition. (Default: ```false```)
`--entrypoints.<name>.address`: `--entrypoints.<name>.address`:
Entry point address. Entry point address.
`--entrypoints.<name>.allowacmebypass`:
Enables handling of ACME TLS and HTTP challenges with custom routers. (Default: ```false```)
`--entrypoints.<name>.asdefault`: `--entrypoints.<name>.asdefault`:
Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. (Default: ```false```) Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. (Default: ```false```)
`--entrypoints.<name>.forwardedheaders.connection`:
List of Connection headers that are allowed to pass through the middleware chain before being removed.
`--entrypoints.<name>.forwardedheaders.insecure`: `--entrypoints.<name>.forwardedheaders.insecure`:
Trust all forwarded headers. (Default: ```false```) Trust all forwarded headers. (Default: ```false```)

View file

@ -126,9 +126,15 @@ Entry points definition. (Default: ```false```)
`TRAEFIK_ENTRYPOINTS_<NAME>_ADDRESS`: `TRAEFIK_ENTRYPOINTS_<NAME>_ADDRESS`:
Entry point address. Entry point address.
`TRAEFIK_ENTRYPOINTS_<NAME>_ALLOWACMEBYPASS`:
Enables handling of ACME TLS and HTTP challenges with custom routers. (Default: ```false```)
`TRAEFIK_ENTRYPOINTS_<NAME>_ASDEFAULT`: `TRAEFIK_ENTRYPOINTS_<NAME>_ASDEFAULT`:
Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. (Default: ```false```) Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. (Default: ```false```)
`TRAEFIK_ENTRYPOINTS_<NAME>_FORWARDEDHEADERS_CONNECTION`:
List of Connection headers that are allowed to pass through the middleware chain before being removed.
`TRAEFIK_ENTRYPOINTS_<NAME>_FORWARDEDHEADERS_INSECURE`: `TRAEFIK_ENTRYPOINTS_<NAME>_FORWARDEDHEADERS_INSECURE`:
Trust all forwarded headers. (Default: ```false```) Trust all forwarded headers. (Default: ```false```)

View file

@ -30,6 +30,7 @@
[entryPoints] [entryPoints]
[entryPoints.EntryPoint0] [entryPoints.EntryPoint0]
address = "foobar" address = "foobar"
allowACMEByPass = true
reusePort = true reusePort = true
asDefault = true asDefault = true
[entryPoints.EntryPoint0.transport] [entryPoints.EntryPoint0.transport]
@ -48,6 +49,7 @@
[entryPoints.EntryPoint0.forwardedHeaders] [entryPoints.EntryPoint0.forwardedHeaders]
insecure = true insecure = true
trustedIPs = ["foobar", "foobar"] trustedIPs = ["foobar", "foobar"]
connection = ["foobar", "foobar"]
[entryPoints.EntryPoint0.http] [entryPoints.EntryPoint0.http]
middlewares = ["foobar", "foobar"] middlewares = ["foobar", "foobar"]
encodeQuerySemicolons = true encodeQuerySemicolons = true

View file

@ -35,6 +35,7 @@ tcpServersTransport:
entryPoints: entryPoints:
EntryPoint0: EntryPoint0:
address: foobar address: foobar
allowACMEByPass: true
reusePort: true reusePort: true
asDefault: true asDefault: true
transport: transport:
@ -57,6 +58,9 @@ entryPoints:
trustedIPs: trustedIPs:
- foobar - foobar
- foobar - foobar
connection:
- foobar
- foobar
http: http:
redirections: redirections:
entryPoint: entryPoint:

View file

@ -233,6 +233,35 @@ If both TCP and UDP are wanted for the same port, two entryPoints definitions ar
Full details for how to specify `address` can be found in [net.Listen](https://golang.org/pkg/net/#Listen) (and [net.Dial](https://golang.org/pkg/net/#Dial)) of the doc for go. Full details for how to specify `address` can be found in [net.Listen](https://golang.org/pkg/net/#Listen) (and [net.Dial](https://golang.org/pkg/net/#Dial)) of the doc for go.
### AllowACMEByPass
_Optional, Default=false_
`allowACMEByPass` determines whether a user defined router can handle ACME TLS or HTTP challenges instead of the Traefik dedicated one.
This option can be used when a Traefik instance has one or more certificate resolvers configured,
but is also used to route challenges connections/requests to services that could also initiate their own ACME challenges.
??? info "No Certificate Resolvers configured"
It is not necessary to use the `allowACMEByPass' option certificate option if no certificate resolver is defined.
In fact, Traefik will automatically allow ACME TLS or HTTP requests to be handled by custom routers in this case, since there can be no concurrency with its own challenge handlers.
```yaml tab="File (YAML)"
entryPoints:
foo:
allowACMEByPass: true
```
```toml tab="File (TOML)"
[entryPoints.foo]
[entryPoints.foo.allowACMEByPass]
allowACMEByPass = true
```
```bash tab="CLI"
--entryPoints.name.allowACMEByPass=true
```
### ReusePort ### ReusePort
_Optional, Default=false_ _Optional, Default=false_
@ -500,6 +529,40 @@ You can configure Traefik to trust the forwarded headers information (`X-Forward
--entryPoints.web.forwardedHeaders.insecure --entryPoints.web.forwardedHeaders.insecure
``` ```
??? info "`forwardedHeaders.connection`"
As per RFC7230, Traefik respects the Connection options from the client request.
By doing so, it removes any header field(s) listed in the request Connection header and the Connection header field itself when empty.
The removal happens as soon as the request is handled by Traefik,
thus the removed headers are not available when the request passes through the middleware chain.
The `connection` option lists the Connection headers allowed to passthrough the middleware chain before their removal.
```yaml tab="File (YAML)"
## Static configuration
entryPoints:
web:
address: ":80"
forwardedHeaders:
connection:
- foobar
```
```toml tab="File (TOML)"
## Static configuration
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.forwardedHeaders]
connection = ["foobar"]
```
```bash tab="CLI"
## Static configuration
--entryPoints.web.address=:80
--entryPoints.web.forwardedHeaders.connection=foobar
```
### Transport ### Transport
#### `respondingTimeouts` #### `respondingTimeouts`

View file

@ -24,7 +24,7 @@ With Consul Catalog, Traefik can leverage tags attached to a service to generate
!!! info "tags" !!! info "tags"
- tags are case insensitive. - tags are case-insensitive.
- The complete list of tags can be found [the reference page](../../reference/dynamic-configuration/consul-catalog.md) - The complete list of tags can be found [the reference page](../../reference/dynamic-configuration/consul-catalog.md)
### General ### General

View file

@ -95,7 +95,7 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
!!! info "Labels" !!! info "Labels"
- Labels are case insensitive. - Labels are case-insensitive.
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md). - The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md).
### General ### General

View file

@ -22,7 +22,7 @@ With ECS, Traefik can leverage labels attached to a container to generate routin
!!! info "labels" !!! info "labels"
- labels are case insensitive. - labels are case-insensitive.
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/ecs.md). - The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/ecs.md).
### General ### General

View file

@ -12,7 +12,7 @@ A Story of key & values
!!! info "Keys" !!! info "Keys"
- Keys are case insensitive. - Keys are case-insensitive.
- The complete list of keys can be found in [the reference page](../../reference/dynamic-configuration/kv.md). - The complete list of keys can be found in [the reference page](../../reference/dynamic-configuration/kv.md).
### Routers ### Routers

View file

@ -24,7 +24,7 @@ With Nomad, Traefik can leverage tags attached to a service to generate routing
!!! info "tags" !!! info "tags"
- tags are case insensitive. - tags are case-insensitive.
- The complete list of tags can be found [the reference page](../../reference/dynamic-configuration/nomad.md) - The complete list of tags can be found [the reference page](../../reference/dynamic-configuration/nomad.md)
### General ### General

View file

@ -118,7 +118,7 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
!!! info "Labels" !!! info "Labels"
- Labels are case insensitive. - Labels are case-insensitive.
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md). - The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/docker.md).
### General ### General

View file

@ -1197,7 +1197,7 @@ A value of `0` for the priority is ignored: `priority = 0` means that the defaul
| Router-2 | ```ClientIP(`192.168.0.0/24`)``` | 26 | | Router-2 | ```ClientIP(`192.168.0.0/24`)``` | 26 |
Which means that requests from `192.168.0.12` would go to Router-2 even though Router-1 is intended to specifically handle them. Which means that requests from `192.168.0.12` would go to Router-2 even though Router-1 is intended to specifically handle them.
To achieve this intention, a priority (higher than 26) should be set on Router-1. To achieve this intention, a priority (greater than 26) should be set on Router-1.
??? example "Setting priorities -- using the [File Provider](../../providers/file.md)" ??? example "Setting priorities -- using the [File Provider](../../providers/file.md)"

View file

@ -1,6 +1,6 @@
--- ---
title: "Traefik Docker DNS Challenge Documentation" title: "Traefik Docker DNS Challenge Documentation"
description: "Learn how to create a certificate with the Let's Encrypt DNS challenge to use HTTPS on a Service exposed with Traefik Proxy. Read the tehnical documentation." description: "Learn how to create a certificate with the Let's Encrypt DNS challenge to use HTTPS on a Service exposed with Traefik Proxy. Read the technical documentation."
--- ---
# Docker-compose with Let's Encrypt: DNS Challenge # Docker-compose with Let's Encrypt: DNS Challenge

28
go.mod
View file

@ -33,7 +33,6 @@ 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/juliens/wasm-goexport v0.0.6
github.com/klauspost/compress v1.17.9 github.com/klauspost/compress v1.17.9
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
@ -50,7 +49,7 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo. github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo.
github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_golang v1.19.1
github.com/prometheus/client_model v0.5.0 github.com/prometheus/client_model v0.5.0
github.com/quic-go/quic-go v0.45.1 github.com/quic-go/quic-go v0.47.0
github.com/rs/zerolog v1.29.0 github.com/rs/zerolog v1.29.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spiffe/go-spiffe/v2 v2.1.1 github.com/spiffe/go-spiffe/v2 v2.1.1
@ -82,13 +81,13 @@ require (
go.opentelemetry.io/otel/sdk v1.28.0 go.opentelemetry.io/otel/sdk v1.28.0
go.opentelemetry.io/otel/sdk/metric v1.28.0 go.opentelemetry.io/otel/sdk/metric v1.28.0
go.opentelemetry.io/otel/trace v1.28.0 go.opentelemetry.io/otel/trace v1.28.0
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // No tag on the repo. golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // No tag on the repo.
golang.org/x/mod v0.18.0 golang.org/x/mod v0.21.0
golang.org/x/net v0.26.0 golang.org/x/net v0.29.0
golang.org/x/sys v0.23.0 golang.org/x/sys v0.25.0
golang.org/x/text v0.17.0 golang.org/x/text v0.18.0
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
golang.org/x/tools v0.22.0 golang.org/x/tools v0.25.0
google.golang.org/grpc v1.64.1 google.golang.org/grpc v1.64.1
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
@ -190,7 +189,7 @@ require (
github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-resty/resty/v2 v2.11.0 // indirect github.com/go-resty/resty/v2 v2.11.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/goccy/go-json v0.10.3 // indirect github.com/goccy/go-json v0.10.3 // indirect
@ -204,7 +203,7 @@ require (
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b // indirect github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 // indirect
github.com/google/s2a-go v0.1.7 // indirect github.com/google/s2a-go v0.1.7 // indirect
github.com/google/uuid v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
@ -275,7 +274,7 @@ require (
github.com/nrdcg/porkbun v0.3.0 // indirect github.com/nrdcg/porkbun v0.3.0 // indirect
github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect
github.com/onsi/ginkgo v1.16.5 // indirect github.com/onsi/ginkgo v1.16.5 // indirect
github.com/onsi/ginkgo/v2 v2.17.1 // indirect github.com/onsi/ginkgo/v2 v2.20.2 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
@ -288,7 +287,7 @@ require (
github.com/pquerna/otp v1.4.0 // indirect github.com/pquerna/otp v1.4.0 // indirect
github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.5.1 // indirect
github.com/redis/go-redis/v9 v9.2.1 // indirect github.com/redis/go-redis/v9 v9.2.1 // indirect
github.com/rs/cors v1.7.0 // indirect github.com/rs/cors v1.7.0 // indirect
github.com/sacloud/api-client-go v0.2.10 // indirect github.com/sacloud/api-client-go v0.2.10 // indirect
@ -338,10 +337,10 @@ require (
go.uber.org/ratelimit v0.3.0 // indirect go.uber.org/ratelimit v0.3.0 // indirect
go.uber.org/zap v1.26.0 // indirect go.uber.org/zap v1.26.0 // indirect
golang.org/x/arch v0.4.0 // indirect golang.org/x/arch v0.4.0 // indirect
golang.org/x/crypto v0.26.0 // indirect golang.org/x/crypto v0.27.0 // indirect
golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/term v0.23.0 // indirect golang.org/x/term v0.24.0 // indirect
google.golang.org/api v0.172.0 // indirect google.golang.org/api v0.172.0 // indirect
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
@ -371,4 +370,5 @@ replace (
// tencentcloud uses monorepo with multimodule but the go.mod files are incomplete. // tencentcloud uses monorepo with multimodule but the go.mod files are incomplete.
exclude github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible exclude github.com/tencentcloud/tencentcloud-sdk-go v3.0.83+incompatible
// Replace to handle new wasmexport in official go and wazergo for http calls.
replace github.com/http-wasm/http-wasm-host-go => github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70 replace github.com/http-wasm/http-wasm-host-go => github.com/traefik/http-wasm-host-go v0.0.0-20240618100324-3c53dcaa1a70

67
go.sum
View file

@ -356,23 +356,20 @@ github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqx
github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A= github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc= github.com/go-viper/mapstructure/v2 v2.0.0 h1:dhn8MZ1gZ0mzeodTG3jt5Vj/o87xZKuNAprG2mQfMfc=
github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-viper/mapstructure/v2 v2.0.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw= github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA= github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw= github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/gobwas/ws v1.2.1 h1:F2aeBZrm2NDsc7vbovKrWSogd4wvfAxg0FQ89/iqOTk=
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.7.8/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
@ -455,8 +452,8 @@ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXi
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b h1:h9U78+dx9a4BKdQkBBos92HalKpaGKHrp+3Uo6yTodo= github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ=
github.com/google/pprof v0.0.0-20230817174616-7a8ec2ada47b/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
@ -590,8 +587,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juliens/wasm-goexport v0.0.6 h1:YU0c+j0dF/HNy32vgYTA+K/6wnsZXgGc+ihl/UDw8iA=
github.com/juliens/wasm-goexport v0.0.6/go.mod h1:VTTpJVY3tIBet0Gv8r5TxdsNg0vDkkqXYm0Hp5hR42A=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
@ -800,15 +795,15 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk= github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.32.0/go.mod h1:a4x4gW6Pz2yK1MAmvluYme5lvYTn61afQ2ETw/8n4Lg= github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
@ -876,10 +871,10 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA= github.com/quic-go/quic-go v0.47.0 h1:yXs3v7r2bm1wmPTYNLKAAJTHMYkPEsfYJmTazXrCZ7Y=
github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= github.com/quic-go/quic-go v0.47.0/go.mod h1:3bCapYsJvXGZcipOHuu7plYtaV6tnF+z7wIFsU0WK9E=
github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
@ -1161,8 +1156,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1171,8 +1166,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -1193,8 +1188,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1234,8 +1229,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1322,8 +1317,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@ -1333,8 +1328,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@ -1348,8 +1343,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1389,8 +1384,8 @@ golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View file

@ -0,0 +1,37 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
# Limiting the Logs to Specific Fields
[accessLog]
format = "json"
filePath = "access.log"
[accessLog.fields.headers.names]
"Foo" = "keep"
"Bar" = "keep"
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.web.forwardedHeaders]
insecure = true
connection = ["Foo"]
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[http.routers]
[http.routers.router1]
rule = "Host(`test.localhost`)"
service = "service1"
[http.services]
[http.services.service1.loadBalancer]
[[http.services.service1.loadBalancer.servers]]
url = "http://127.0.0.1:9000"

View file

@ -48,7 +48,7 @@ openssl genrsa -out client3.key 2048
# Locality Name (eg, city) []:. # Locality Name (eg, city) []:.
# Organization Name (eg, company) [Internet Widgits Pty Ltd]:. # Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
# Organizational Unit Name (eg, section) []:. # Organizational Unit Name (eg, section) []:.
# Common Name (e.g. server FQDN or YOUR name) []:clien1.example.com # Common Name (e.g. server FQDN or YOUR name) []:client1.example.com
# Email Address []:. # Email Address []:.
# #
# Please enter the following 'extra' attributes # Please enter the following 'extra' attributes
@ -58,7 +58,7 @@ openssl genrsa -out client3.key 2048
# Issuer # Issuer
# CN = ca1.example.com # CN = ca1.example.com
# Subject # Subject
# CN = clien1.example.com # CN = client1.example.com
openssl req -key client1.key -new -out client1.csr openssl req -key client1.key -new -out client1.csr
# Country Name (2 letter code) [AU]:. # Country Name (2 letter code) [AU]:.

View file

@ -4,6 +4,7 @@ import (
"net" "net"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os"
"testing" "testing"
"time" "time"
@ -20,6 +21,11 @@ func TestHeadersSuite(t *testing.T) {
suite.Run(t, new(HeadersSuite)) suite.Run(t, new(HeadersSuite))
} }
func (s *HeadersSuite) TearDownTest() {
s.displayTraefikLogFile(traefikTestLogFile)
_ = os.Remove(traefikTestAccessLogFile)
}
func (s *HeadersSuite) TestSimpleConfiguration() { func (s *HeadersSuite) TestSimpleConfiguration() {
s.traefikCmd(withConfigFile("fixtures/headers/basic.toml")) s.traefikCmd(withConfigFile("fixtures/headers/basic.toml"))
@ -62,6 +68,53 @@ func (s *HeadersSuite) TestReverseProxyHeaderRemoved() {
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
func (s *HeadersSuite) TestConnectionHopByHop() {
file := s.adaptFile("fixtures/headers/connection_hop_by_hop_headers.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, found := r.Header["X-Forwarded-For"]
assert.True(s.T(), found)
xHost, found := r.Header["X-Forwarded-Host"]
assert.True(s.T(), found)
assert.Equal(s.T(), "localhost", xHost[0])
_, found = r.Header["Foo"]
assert.False(s.T(), found)
_, found = r.Header["Bar"]
assert.False(s.T(), found)
})
listener, err := net.Listen("tcp", "127.0.0.1:9000")
require.NoError(s.T(), err)
ts := &httptest.Server{
Listener: listener,
Config: &http.Server{Handler: handler},
}
ts.Start()
defer ts.Close()
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/", nil)
require.NoError(s.T(), err)
req.Host = "test.localhost"
req.Header = http.Header{
"Connection": {"Foo,Bar,X-Forwarded-For,X-Forwarded-Host"},
"Foo": {"bar"},
"Bar": {"foo"},
"X-Forwarded-Host": {"localhost"},
}
err = try.Request(req, time.Second, try.StatusCodeIs(http.StatusOK))
require.NoError(s.T(), err)
accessLog, err := os.ReadFile(traefikTestAccessLogFile)
require.NoError(s.T(), err)
assert.Contains(s.T(), string(accessLog), "\"request_Foo\":\"bar\"")
assert.NotContains(s.T(), string(accessLog), "\"request_Bar\":\"\"")
}
func (s *HeadersSuite) TestCorsResponses() { func (s *HeadersSuite) TestCorsResponses() {
file := s.adaptFile("fixtures/headers/cors.toml", struct{}{}) file := s.adaptFile("fixtures/headers/cors.toml", struct{}{})
s.traefikCmd(withConfigFile(file)) s.traefikCmd(withConfigFile(file))

View file

@ -24,7 +24,7 @@ const traefikTestAccessLogFileRotated = traefikTestAccessLogFile + ".rotated"
// Log rotation integration test suite. // Log rotation integration test suite.
type LogRotationSuite struct{ BaseSuite } type LogRotationSuite struct{ BaseSuite }
func TestLogRorationSuite(t *testing.T) { func TestLogRotationSuite(t *testing.T) {
suite.Run(t, new(LogRotationSuite)) suite.Run(t, new(LogRotationSuite))
} }

View file

@ -1414,7 +1414,7 @@ func (s *SimpleSuite) TestDebugLog() {
req, err := http.NewRequest(http.MethodGet, "http://localhost:8000/whoami", http.NoBody) req, err := http.NewRequest(http.MethodGet, "http://localhost:8000/whoami", http.NoBody)
require.NoError(s.T(), err) require.NoError(s.T(), err)
req.Header.Set("Autorization", "Bearer ThisIsABearerToken") req.Header.Set("Authorization", "Bearer ThisIsABearerToken")
response, err := http.DefaultClient.Do(req) response, err := http.DefaultClient.Do(req)
require.NoError(s.T(), err) require.NoError(s.T(), err)

View file

@ -19,7 +19,7 @@ const (
type timedAction func(timeout time.Duration, operation DoCondition) error type timedAction func(timeout time.Duration, operation DoCondition) error
// Sleep pauses the current goroutine for at least the duration d. // Sleep pauses the current goroutine for at least the duration d.
// Deprecated: Use only when use an other Try[...] functions is not possible. // Deprecated: Use only when use another Try[...] functions is not possible.
func Sleep(d time.Duration) { func Sleep(d time.Duration) {
d = applyCIMultiplier(d) d = applyCIMultiplier(d)
time.Sleep(d) time.Sleep(d)

View file

@ -71,7 +71,7 @@ func TestDecodeToNode(t *testing.T) {
desc: "several entries, level 0", desc: "several entries, level 0",
in: map[string]string{ in: map[string]string{
"traefik": "bar", "traefik": "bar",
"traefic": "bur", "traefik_": "bur",
}, },
expected: expected{error: true}, expected: expected{error: true},
}, },
@ -120,7 +120,7 @@ func TestDecodeToNode(t *testing.T) {
}}, }},
}, },
{ {
desc: "several entries, level 2, case insensitive", desc: "several entries, level 2, case-insensitive",
in: map[string]string{ in: map[string]string{
"traefik/foo/aaa": "bar", "traefik/foo/aaa": "bar",
"traefik/Foo/bbb": "bur", "traefik/Foo/bbb": "bur",

View file

@ -13,6 +13,7 @@ import (
// EntryPoint holds the entry point configuration. // EntryPoint holds the entry point configuration.
type EntryPoint struct { type EntryPoint struct {
Address string `description:"Entry point address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"` Address string `description:"Entry point address." json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
AllowACMEByPass bool `description:"Enables handling of ACME TLS and HTTP challenges with custom routers." json:"allowACMEByPass,omitempty" toml:"allowACMEByPass,omitempty" yaml:"allowACMEByPass,omitempty"`
ReusePort bool `description:"Enables EntryPoints from the same or different processes listening on the same TCP/UDP port." json:"reusePort,omitempty" toml:"reusePort,omitempty" yaml:"reusePort,omitempty"` ReusePort bool `description:"Enables EntryPoints from the same or different processes listening on the same TCP/UDP port." json:"reusePort,omitempty" toml:"reusePort,omitempty" yaml:"reusePort,omitempty"`
AsDefault bool `description:"Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined." json:"asDefault,omitempty" toml:"asDefault,omitempty" yaml:"asDefault,omitempty"` AsDefault bool `description:"Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined." json:"asDefault,omitempty" toml:"asDefault,omitempty" yaml:"asDefault,omitempty"`
Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty" export:"true"` Transport *EntryPointsTransport `description:"Configures communication between clients and Traefik." json:"transport,omitempty" toml:"transport,omitempty" yaml:"transport,omitempty" export:"true"`
@ -120,6 +121,7 @@ type TLSConfig struct {
type ForwardedHeaders struct { type ForwardedHeaders struct {
Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"` Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
TrustedIPs []string `description:"Trust only forwarded headers from selected IPs." json:"trustedIPs,omitempty" toml:"trustedIPs,omitempty" yaml:"trustedIPs,omitempty"` TrustedIPs []string `description:"Trust only forwarded headers from selected IPs." json:"trustedIPs,omitempty" toml:"trustedIPs,omitempty" yaml:"trustedIPs,omitempty"`
Connection []string `description:"List of Connection headers that are allowed to pass through the middleware chain before being removed." json:"connection,omitempty" toml:"connection,omitempty" yaml:"connection,omitempty"`
} }
// ProxyProtocol contains Proxy-Protocol configuration. // ProxyProtocol contains Proxy-Protocol configuration.

View file

@ -46,7 +46,7 @@ func TestDepthStrategy_GetIP(t *testing.T) {
expected: "10.0.0.3", expected: "10.0.0.3",
}, },
{ {
desc: "Use non existing depth in XForwardedFor", desc: "Use nonexistent depth in XForwardedFor",
depth: 2, depth: 2,
xForwardedFor: "", xForwardedFor: "",
expected: "", expected: "",

View file

@ -2,23 +2,30 @@ package metrics
import ( import (
"context" "context"
"net"
"strings" "strings"
"time" "time"
"github.com/go-kit/kit/metrics/dogstatsd" "github.com/go-kit/kit/metrics/dogstatsd"
"github.com/go-kit/kit/util/conn"
gokitlog "github.com/go-kit/log"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/safe" "github.com/traefik/traefik/v3/pkg/safe"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
) )
const (
unixAddressPrefix = "unix://"
unixAddressDatagramPrefix = "unixgram://"
unixAddressStreamPrefix = "unixstream://"
)
var ( var (
datadogClient *dogstatsd.Dogstatsd datadogClient *dogstatsd.Dogstatsd
datadogLoopCancelFunc context.CancelFunc datadogLoopCancelFunc context.CancelFunc
) )
const unixAddressPrefix = "unix://"
// Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64 // Metric names consistent with https://github.com/DataDog/integrations-extras/pull/64
const ( const (
ddConfigReloadsName = "config.reload.total" ddConfigReloadsName = "config.reload.total"
@ -58,9 +65,10 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
config.Prefix = defaultMetricsPrefix config.Prefix = defaultMetricsPrefix
} }
datadogClient = dogstatsd.New(config.Prefix+".", logs.NewGoKitWrapper(log.Logger.With().Str(logs.MetricsProviderName, "datadog").Logger())) datadogLogger := logs.NewGoKitWrapper(log.Logger.With().Str(logs.MetricsProviderName, "datadog").Logger())
datadogClient = dogstatsd.New(config.Prefix+".", datadogLogger)
initDatadogClient(ctx, config) initDatadogClient(ctx, config, datadogLogger)
registry := &standardRegistry{ registry := &standardRegistry{
configReloadsCounter: datadogClient.NewCounter(ddConfigReloadsName, 1.0), configReloadsCounter: datadogClient.NewCounter(ddConfigReloadsName, 1.0),
@ -101,7 +109,7 @@ func RegisterDatadog(ctx context.Context, config *types.Datadog) Registry {
return registry return registry
} }
func initDatadogClient(ctx context.Context, config *types.Datadog) { func initDatadogClient(ctx context.Context, config *types.Datadog, logger gokitlog.LoggerFunc) {
network, address := parseDatadogAddress(config.Address) network, address := parseDatadogAddress(config.Address)
ctx, datadogLoopCancelFunc = context.WithCancel(ctx) ctx, datadogLoopCancelFunc = context.WithCancel(ctx)
@ -110,10 +118,38 @@ func initDatadogClient(ctx context.Context, config *types.Datadog) {
ticker := time.NewTicker(time.Duration(config.PushInterval)) ticker := time.NewTicker(time.Duration(config.PushInterval))
defer ticker.Stop() defer ticker.Stop()
datadogClient.SendLoop(ctx, ticker.C, network, address) dialer := func(network, address string) (net.Conn, error) {
switch network {
case "unix":
// To mimic the Datadog client when the network is unix we will try to guess the UDS type.
newConn, err := net.Dial("unixgram", address)
if err != nil && strings.Contains(err.Error(), "protocol wrong type for socket") {
return net.Dial("unix", address)
}
return newConn, err
case "unixgram":
return net.Dial("unixgram", address)
case "unixstream":
return net.Dial("unix", address)
default:
return net.Dial(network, address)
}
}
datadogClient.WriteLoop(ctx, ticker.C, conn.NewManager(dialer, network, address, time.After, logger))
}) })
} }
// StopDatadog stops the Datadog metrics pusher.
func StopDatadog() {
if datadogLoopCancelFunc != nil {
datadogLoopCancelFunc()
datadogLoopCancelFunc = nil
}
}
func parseDatadogAddress(address string) (string, string) { func parseDatadogAddress(address string) (string, string) {
network := "udp" network := "udp"
@ -122,6 +158,12 @@ func parseDatadogAddress(address string) (string, string) {
case strings.HasPrefix(address, unixAddressPrefix): case strings.HasPrefix(address, unixAddressPrefix):
network = "unix" network = "unix"
addr = address[len(unixAddressPrefix):] addr = address[len(unixAddressPrefix):]
case strings.HasPrefix(address, unixAddressDatagramPrefix):
network = "unixgram"
addr = address[len(unixAddressDatagramPrefix):]
case strings.HasPrefix(address, unixAddressStreamPrefix):
network = "unixstream"
addr = address[len(unixAddressStreamPrefix):]
case address != "": case address != "":
addr = address addr = address
default: default:
@ -130,11 +172,3 @@ func parseDatadogAddress(address string) (string, string) {
return network, addr return network, addr
} }
// StopDatadog stops the Datadog metrics pusher.
func StopDatadog() {
if datadogLoopCancelFunc != nil {
datadogLoopCancelFunc()
datadogLoopCancelFunc = nil
}
}

View file

@ -64,6 +64,18 @@ func TestDatadog_parseDatadogAddress(t *testing.T) {
expNetwork: "unix", expNetwork: "unix",
expAddress: "/path/to/datadog.socket", expAddress: "/path/to/datadog.socket",
}, },
{
desc: "unixgram address",
address: "unixgram:///path/to/datadog.socket",
expNetwork: "unixgram",
expAddress: "/path/to/datadog.socket",
},
{
desc: "unixstream address",
address: "unixstream:///path/to/datadog.socket",
expNetwork: "unixstream",
expAddress: "/path/to/datadog.socket",
},
} }
for _, test := range tests { for _, test := range tests {

View file

@ -106,8 +106,20 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
Level: logrus.InfoLevel, Level: logrus.InfoLevel,
} }
// Transform headers names in config to a canonical form, to be used as is without further transformations. // Transform header names to a canonical form, to be used as is without further transformations,
if config.Fields != nil && config.Fields.Headers != nil && len(config.Fields.Headers.Names) > 0 { // and transform field names to lower case, to enable case-insensitive lookup.
if config.Fields != nil {
if len(config.Fields.Names) > 0 {
fields := map[string]string{}
for h, v := range config.Fields.Names {
fields[strings.ToLower(h)] = v
}
config.Fields.Names = fields
}
if config.Fields.Headers != nil && len(config.Fields.Headers.Names) > 0 {
fields := map[string]string{} fields := map[string]string{}
for h, v := range config.Fields.Headers.Names { for h, v := range config.Fields.Headers.Names {
@ -116,6 +128,7 @@ func NewHandler(config *types.AccessLog) (*Handler, error) {
config.Fields.Headers.Names = fields config.Fields.Headers.Names = fields
} }
}
logHandler := &Handler{ logHandler := &Handler{
config: config, config: config,
@ -184,16 +197,6 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
}, },
} }
defer func() {
if h.config.BufferingSize > 0 {
h.logHandlerChan <- handlerParams{
logDataTable: logDataTable,
}
return
}
h.logTheRoundTrip(logDataTable)
}()
reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable)) reqWithDataTable := req.WithContext(context.WithValue(req.Context(), DataTableKey, logDataTable))
core[RequestCount] = nextRequestCount() core[RequestCount] = nextRequestCount()
@ -238,12 +241,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
return return
} }
next.ServeHTTP(rw, reqWithDataTable) defer func() {
if _, ok := core[ClientUsername]; !ok {
core[ClientUsername] = usernameIfPresent(reqWithDataTable.URL)
}
logDataTable.DownstreamResponse = downstreamResponse{ logDataTable.DownstreamResponse = downstreamResponse{
headers: rw.Header().Clone(), headers: rw.Header().Clone(),
} }
@ -251,6 +249,22 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
logDataTable.DownstreamResponse.status = capt.StatusCode() logDataTable.DownstreamResponse.status = capt.StatusCode()
logDataTable.DownstreamResponse.size = capt.ResponseSize() logDataTable.DownstreamResponse.size = capt.ResponseSize()
logDataTable.Request.size = capt.RequestSize() logDataTable.Request.size = capt.RequestSize()
if _, ok := core[ClientUsername]; !ok {
core[ClientUsername] = usernameIfPresent(reqWithDataTable.URL)
}
if h.config.BufferingSize > 0 {
h.logHandlerChan <- handlerParams{
logDataTable: logDataTable,
}
return
}
h.logTheRoundTrip(logDataTable)
}()
next.ServeHTTP(rw, reqWithDataTable)
} }
// Close closes the Logger (i.e. the file, drain logHandlerChan, etc). // Close closes the Logger (i.e. the file, drain logHandlerChan, etc).
@ -334,7 +348,7 @@ func (h *Handler) logTheRoundTrip(logDataTable *LogData) {
fields := logrus.Fields{} fields := logrus.Fields{}
for k, v := range logDataTable.Core { for k, v := range logDataTable.Core {
if h.config.Fields.Keep(k) { if h.config.Fields.Keep(strings.ToLower(k)) {
fields[k] = v fields[k] = v
} }
} }

View file

@ -2,6 +2,7 @@ package accesslog
import ( import (
"bytes" "bytes"
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
@ -24,6 +25,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
ptypes "github.com/traefik/paerser/types" ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v3/pkg/middlewares/capture" "github.com/traefik/traefik/v3/pkg/middlewares/capture"
"github.com/traefik/traefik/v3/pkg/middlewares/recovery"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
) )
@ -164,7 +166,7 @@ func TestLoggerHeaderFields(t *testing.T) {
}, },
}, },
{ {
desc: "with case insensitive match on header name", desc: "with case-insensitive match on header name",
header: "User-Agent", header: "User-Agent",
expected: types.AccessLogKeep, expected: types.AccessLogKeep,
accessLogFields: types.AccessLogFields{ accessLogFields: types.AccessLogFields{
@ -465,6 +467,32 @@ func TestLoggerJSON(t *testing.T) {
RequestRefererHeader: assertString(testReferer), RequestRefererHeader: assertString(testReferer),
}, },
}, },
{
desc: "fields and headers with unconventional letter case",
config: &types.AccessLog{
FilePath: "",
Format: JSONFormat,
Fields: &types.AccessLogFields{
DefaultMode: "drop",
Names: map[string]string{
"rEqUeStHoSt": "keep",
},
Headers: &types.FieldHeaders{
DefaultMode: "drop",
Names: map[string]string{
"ReFeReR": "keep",
},
},
},
},
expected: map[string]func(t *testing.T, value interface{}){
RequestHost: assertString(testHostname),
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEmpty(),
RequestRefererHeader: assertString(testReferer),
},
},
} }
for _, test := range testCases { for _, test := range testCases {
@ -496,6 +524,64 @@ func TestLoggerJSON(t *testing.T) {
} }
} }
func TestLogger_AbortedRequest(t *testing.T) {
expected := map[string]func(t *testing.T, value interface{}){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(""),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
DownstreamStatus: assertFloat64(float64(200)),
DownstreamContentSize: assertFloat64(float64(40)),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
ServiceURL: assertString("http://stream"),
ServiceAddr: assertString("127.0.0.1"),
ServiceName: assertString("stream"),
ClientUsername: assertString(testUsername),
ClientHost: assertString(testHostname),
ClientPort: assertString(strconv.Itoa(testPort)),
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
"level": assertString("info"),
"msg": assertString(""),
RequestCount: assertFloat64NotZero(),
Duration: assertFloat64NotZero(),
Overhead: assertFloat64NotZero(),
RetryAttempts: assertFloat64(float64(0)),
"time": assertNotEmpty(),
StartLocal: assertNotEmpty(),
StartUTC: assertNotEmpty(),
"downstream_Content-Type": assertString("text/plain"),
"downstream_Transfer-Encoding": assertString("chunked"),
"downstream_Cache-Control": assertString("no-cache"),
}
config := &types.AccessLog{
FilePath: filepath.Join(t.TempDir(), logFileNameSuffix),
Format: JSONFormat,
}
doLoggingWithAbortedStream(t, config)
logData, err := os.ReadFile(config.FilePath)
require.NoError(t, err)
jsonData := make(map[string]interface{})
err = json.Unmarshal(logData, &jsonData)
require.NoError(t, err)
assert.Equal(t, len(expected), len(jsonData))
for field, assertion := range expected {
assertion(t, jsonData[field])
if t.Failed() {
return
}
}
}
func TestNewLogHandlerOutputStdout(t *testing.T) { func TestNewLogHandlerOutputStdout(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
@ -832,3 +918,89 @@ func logWriterTestHandlerFunc(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(testStatus) rw.WriteHeader(testStatus)
} }
func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) {
t.Helper()
logger, err := NewHandler(config)
require.NoError(t, err)
t.Cleanup(func() {
err := logger.Close()
require.NoError(t, err)
})
if config.FilePath != "" {
_, err = os.Stat(config.FilePath)
require.NoError(t, err, "logger should create "+config.FilePath)
}
reqContext, cancelRequest := context.WithCancel(context.Background())
req := &http.Request{
Header: map[string][]string{
"User-Agent": {testUserAgent},
"Referer": {testReferer},
},
Proto: testProto,
Host: testHostname,
Method: testMethod,
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
URL: &url.URL{
User: url.UserPassword(testUsername, ""),
},
Body: nil,
}
req = req.WithContext(reqContext)
chain := alice.New()
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
return recovery.New(context.Background(), next)
})
chain = chain.Append(capture.Wrap)
chain = chain.Append(WrapHandler(logger))
service := NewFieldHandler(http.HandlerFunc(streamBackend), ServiceURL, "http://stream", nil)
service = NewFieldHandler(service, ServiceAddr, "127.0.0.1", nil)
service = NewFieldHandler(service, ServiceName, "stream", AddServiceFields)
handler, err := chain.Then(service)
require.NoError(t, err)
go func() {
time.Sleep(499 * time.Millisecond)
cancelRequest()
}()
handler.ServeHTTP(httptest.NewRecorder(), req)
}
func streamBackend(rw http.ResponseWriter, r *http.Request) {
// Get the Flusher to flush the response to the client
flusher, ok := rw.(http.Flusher)
if !ok {
http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
return
}
// Set the headers for streaming
rw.Header().Set("Content-Type", "text/plain")
rw.Header().Set("Transfer-Encoding", "chunked")
rw.Header().Set("Cache-Control", "no-cache")
for {
time.Sleep(100 * time.Millisecond)
select {
case <-r.Context().Done():
panic(http.ErrAbortHandler)
default:
if _, err := fmt.Fprint(rw, "FOOBAR!!!!"); err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
flusher.Flush()
}
}
}

View file

@ -1,4 +1,4 @@
package connectionheader package auth
import ( import (
"net/http" "net/http"

View file

@ -1,4 +1,4 @@
package connectionheader package auth
import ( import (
"net/http" "net/http"

View file

@ -14,7 +14,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/accesslog" "github.com/traefik/traefik/v3/pkg/middlewares/accesslog"
"github.com/traefik/traefik/v3/pkg/middlewares/connectionheader"
"github.com/traefik/traefik/v3/pkg/middlewares/observability" "github.com/traefik/traefik/v3/pkg/middlewares/observability"
"github.com/traefik/traefik/v3/pkg/tracing" "github.com/traefik/traefik/v3/pkg/tracing"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
@ -124,7 +123,7 @@ 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 = connectionheader.Remove(req) 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 {

View file

@ -235,7 +235,7 @@ func (cc *codeCatcher) Flush() {
// since we want to serve the ones from the error page, // since we want to serve the ones from the error page,
// so we just don't flush. // so we just don't flush.
// (e.g., To prevent superfluous WriteHeader on request with a // (e.g., To prevent superfluous WriteHeader on request with a
// `Transfert-Encoding: chunked` header). // `Transfer-Encoding: chunked` header).
if cc.caughtFilteredCode { if cc.caughtFilteredCode {
return return
} }

View file

@ -3,10 +3,13 @@ package forwardedheaders
import ( import (
"net" "net"
"net/http" "net/http"
"net/textproto"
"os" "os"
"slices"
"strings" "strings"
"github.com/traefik/traefik/v3/pkg/ip" "github.com/traefik/traefik/v3/pkg/ip"
"golang.org/x/net/http/httpguts"
) )
const ( const (
@ -43,18 +46,19 @@ var xHeaders = []string{
// it first removes all the existing values for those headers if the remote address is not one of the trusted ones. // it first removes all the existing values for those headers if the remote address is not one of the trusted ones.
type XForwarded struct { type XForwarded struct {
insecure bool insecure bool
trustedIps []string trustedIPs []string
connectionHeaders []string
ipChecker *ip.Checker ipChecker *ip.Checker
next http.Handler next http.Handler
hostname string hostname string
} }
// NewXForwarded creates a new XForwarded. // NewXForwarded creates a new XForwarded.
func NewXForwarded(insecure bool, trustedIps []string, next http.Handler) (*XForwarded, error) { func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []string, next http.Handler) (*XForwarded, error) {
var ipChecker *ip.Checker var ipChecker *ip.Checker
if len(trustedIps) > 0 { if len(trustedIPs) > 0 {
var err error var err error
ipChecker, err = ip.NewChecker(trustedIps) ipChecker, err = ip.NewChecker(trustedIPs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -67,7 +71,8 @@ func NewXForwarded(insecure bool, trustedIps []string, next http.Handler) (*XFor
return &XForwarded{ return &XForwarded{
insecure: insecure, insecure: insecure,
trustedIps: trustedIps, trustedIPs: trustedIPs,
connectionHeaders: connectionHeaders,
ipChecker: ipChecker, ipChecker: ipChecker,
next: next, next: next,
hostname: hostname, hostname: hostname,
@ -189,9 +194,53 @@ func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
x.rewrite(r) x.rewrite(r)
x.removeConnectionHeaders(r)
x.next.ServeHTTP(w, r) x.next.ServeHTTP(w, r)
} }
func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
var reqUpType string
if httpguts.HeaderValuesContainsToken(req.Header[connection], upgrade) {
reqUpType = unsafeHeader(req.Header).Get(upgrade)
}
var connectionHopByHopHeaders []string
for _, f := range req.Header[connection] {
for _, sf := range strings.Split(f, ",") {
if sf = textproto.TrimString(sf); sf != "" {
// Connection header cannot dictate to remove X- headers managed by Traefik,
// as per rfc7230 https://datatracker.ietf.org/doc/html/rfc7230#section-6.1,
// A proxy or gateway MUST ... and then remove the Connection header field itself
// (or replace it with the intermediary's own connection options for the forwarded message).
if slices.Contains(xHeaders, sf) {
continue
}
// Keep headers allowed through the middleware chain.
if slices.Contains(x.connectionHeaders, sf) {
connectionHopByHopHeaders = append(connectionHopByHopHeaders, sf)
continue
}
// Apply Connection header option.
req.Header.Del(sf)
}
}
}
if reqUpType != "" {
connectionHopByHopHeaders = append(connectionHopByHopHeaders, upgrade)
unsafeHeader(req.Header).Set(upgrade, reqUpType)
}
if len(connectionHopByHopHeaders) > 0 {
unsafeHeader(req.Header).Set(connection, strings.Join(connectionHopByHopHeaders, ","))
return
}
unsafeHeader(req.Header).Del(connection)
}
// unsafeHeader allows to manage Header values. // unsafeHeader allows to manage Header values.
// Must be used only when the header name is already a canonical key. // Must be used only when the header name is already a canonical key.
type unsafeHeader map[string][]string type unsafeHeader map[string][]string

View file

@ -15,6 +15,7 @@ func TestServeHTTP(t *testing.T) {
desc string desc string
insecure bool insecure bool
trustedIps []string trustedIps []string
connectionHeaders []string
incomingHeaders map[string][]string incomingHeaders map[string][]string
remoteAddr string remoteAddr string
expectedHeaders map[string]string expectedHeaders map[string]string
@ -269,6 +270,196 @@ func TestServeHTTP(t *testing.T) {
xForwardedServer: "foo.com:8080", xForwardedServer: "foo.com:8080",
}, },
}, },
{
desc: "Untrusted: Connection header has no effect on X- forwarded headers",
insecure: false,
incomingHeaders: map[string][]string{
connection: {
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
xForwardedProto: {"foo"},
xForwardedFor: {"foo"},
xForwardedURI: {"foo"},
xForwardedMethod: {"foo"},
xForwardedHost: {"foo"},
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
xForwardedProto: "http",
xForwardedFor: "",
xForwardedURI: "",
xForwardedMethod: "",
xForwardedHost: "",
xForwardedPort: "80",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xRealIP: "",
connection: "",
},
},
{
desc: "Trusted (insecure): Connection header has no effect on X- forwarded headers",
insecure: true,
incomingHeaders: map[string][]string{
connection: {
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
xForwardedProto: {"foo"},
xForwardedFor: {"foo"},
xForwardedURI: {"foo"},
xForwardedMethod: {"foo"},
xForwardedHost: {"foo"},
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
xForwardedProto: "foo",
xForwardedFor: "foo",
xForwardedURI: "foo",
xForwardedMethod: "foo",
xForwardedHost: "foo",
xForwardedPort: "foo",
xForwardedTLSClientCert: "foo",
xForwardedTLSClientCertInfo: "foo",
xRealIP: "foo",
connection: "",
},
},
{
desc: "Untrusted and Connection: Connection header has no effect on X- forwarded headers",
insecure: false,
connectionHeaders: []string{
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
incomingHeaders: map[string][]string{
connection: {
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
xForwardedProto: {"foo"},
xForwardedFor: {"foo"},
xForwardedURI: {"foo"},
xForwardedMethod: {"foo"},
xForwardedHost: {"foo"},
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
xForwardedProto: "http",
xForwardedFor: "",
xForwardedURI: "",
xForwardedMethod: "",
xForwardedHost: "",
xForwardedPort: "80",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xRealIP: "",
connection: "",
},
},
{
desc: "Trusted (insecure) and Connection: Connection header has no effect on X- forwarded headers",
insecure: true,
connectionHeaders: []string{
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
incomingHeaders: map[string][]string{
connection: {
xForwardedProto,
xForwardedFor,
xForwardedURI,
xForwardedMethod,
xForwardedHost,
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,
},
xForwardedProto: {"foo"},
xForwardedFor: {"foo"},
xForwardedURI: {"foo"},
xForwardedMethod: {"foo"},
xForwardedHost: {"foo"},
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
xForwardedProto: "foo",
xForwardedFor: "foo",
xForwardedURI: "foo",
xForwardedMethod: "foo",
xForwardedHost: "foo",
xForwardedPort: "foo",
xForwardedTLSClientCert: "foo",
xForwardedTLSClientCertInfo: "foo",
xRealIP: "foo",
connection: "",
},
},
{
desc: "Connection: one remove, and one passthrough header",
connectionHeaders: []string{
"foo",
},
incomingHeaders: map[string][]string{
connection: {
"foo",
},
"Foo": {"bar"},
"Bar": {"foo"},
},
expectedHeaders: map[string]string{
"Bar": "foo",
},
},
} }
for _, test := range testCases { for _, test := range testCases {
@ -299,7 +490,7 @@ func TestServeHTTP(t *testing.T) {
} }
} }
m, err := NewXForwarded(test.insecure, test.trustedIps, m, err := NewXForwarded(test.insecure, test.trustedIps, test.connectionHeaders,
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})) http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
require.NoError(t, err) require.NoError(t, err)
@ -382,3 +573,74 @@ func Test_isWebsocketRequest(t *testing.T) {
}) })
} }
} }
func TestConnection(t *testing.T) {
testCases := []struct {
desc string
reqHeaders map[string]string
connectionHeaders []string
expected http.Header
}{
{
desc: "simple remove",
reqHeaders: map[string]string{
"Foo": "bar",
connection: "foo",
},
expected: http.Header{},
},
{
desc: "remove and upgrade",
reqHeaders: map[string]string{
upgrade: "test",
"Foo": "bar",
connection: "upgrade,foo",
},
expected: http.Header{
upgrade: []string{"test"},
connection: []string{"Upgrade"},
},
},
{
desc: "no remove",
reqHeaders: map[string]string{
"Foo": "bar",
connection: "fii",
},
expected: http.Header{
"Foo": []string{"bar"},
},
},
{
desc: "no remove because connection header pass through",
reqHeaders: map[string]string{
"Foo": "bar",
connection: "Foo",
},
connectionHeaders: []string{"Foo"},
expected: http.Header{
"Foo": []string{"bar"},
connection: []string{"Foo"},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
forwarded, err := NewXForwarded(true, nil, test.connectionHeaders, nil)
require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
for k, v := range test.reqHeaders {
req.Header.Set(k, v)
}
forwarded.removeConnectionHeaders(req)
assert.Equal(t, test.expected, req.Header)
})
}
}

View file

@ -8,7 +8,6 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/connectionheader"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@ -46,12 +45,11 @@ func New(ctx context.Context, next http.Handler, cfg dynamic.Headers, name strin
if hasCustomHeaders || hasCorsHeaders { if hasCustomHeaders || hasCorsHeaders {
logger.Debug().Msgf("Setting up customHeaders/Cors from %v", cfg) logger.Debug().Msgf("Setting up customHeaders/Cors from %v", cfg)
h, err := NewHeader(nextHandler, cfg) var err error
handler, err = NewHeader(nextHandler, cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
handler = connectionheader.Remover(h)
} }
return &headers{ return &headers{

View file

@ -149,7 +149,7 @@ func (rl *rateLimiter) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
} }
// We Set even in the case where the source already exists, // We Set even in the case where the source already exists,
// because we want to update the expiryTime everytime we get the source, // because we want to update the expiryTime every time we get the source,
// as the expiryTime is supposed to reflect the activity (or lack thereof) on that source. // as the expiryTime is supposed to reflect the activity (or lack thereof) on that source.
if err := rl.buckets.Set(source, bucket, rl.ttl); err != nil { if err := rl.buckets.Set(source, bucket, rl.ttl); err != nil {
logger.Error().Err(err).Msg("Could not insert/update bucket") logger.Error().Err(err).Msg("Could not insert/update bucket")

View file

@ -12,7 +12,6 @@ import (
"github.com/http-wasm/http-wasm-host-go/handler" "github.com/http-wasm/http-wasm-host-go/handler"
wasm "github.com/http-wasm/http-wasm-host-go/handler/nethttp" wasm "github.com/http-wasm/http-wasm-host-go/handler/nethttp"
"github.com/juliens/wasm-goexport/host"
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
"github.com/traefik/traefik/v3/pkg/logs" "github.com/traefik/traefik/v3/pkg/logs"
"github.com/traefik/traefik/v3/pkg/middlewares" "github.com/traefik/traefik/v3/pkg/middlewares"
@ -67,7 +66,7 @@ func (b *wasmMiddlewareBuilder) buildMiddleware(ctx context.Context, next http.H
return nil, nil, fmt.Errorf("loading binary: %w", err) return nil, nil, fmt.Errorf("loading binary: %w", err)
} }
rt := host.NewRuntime(wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCompilationCache(b.cache))) rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCompilationCache(b.cache))
guestModule, err := rt.CompileModule(ctx, code) guestModule, err := rt.CompileModule(ctx, code)
if err != nil { if err != nil {
@ -81,7 +80,7 @@ func (b *wasmMiddlewareBuilder) buildMiddleware(ctx context.Context, next http.H
logger := middlewares.GetLogger(ctx, middlewareName, "wasm") logger := middlewares.GetLogger(ctx, middlewareName, "wasm")
config := wazero.NewModuleConfig().WithSysWalltime() config := wazero.NewModuleConfig().WithSysWalltime().WithStartFunctions("_start", "_initialize")
for _, env := range b.settings.Envs { for _, env := range b.settings.Envs {
config.WithEnv(env, os.Getenv(env)) config.WithEnv(env, os.Getenv(env))
} }

View file

@ -801,7 +801,7 @@ func deleteUnnecessaryDomains(ctx context.Context, domains []types.Domain) []typ
} }
// Check if CN or SANS to check already exists // Check if CN or SANS to check already exists
// or can not be checked by a wildcard // or cannot be checked by a wildcard
var newDomainsToCheck []string var newDomainsToCheck []string
for _, domainProcessed := range domainToCheck.ToStrArray() { for _, domainProcessed := range domainToCheck.ToStrArray() {
if idxDomain < idxDomainToCheck && isDomainAlreadyChecked(domainProcessed, domain.ToStrArray()) { if idxDomain < idxDomainToCheck && isDomainAlreadyChecked(domainProcessed, domain.ToStrArray()) {

View file

@ -205,7 +205,7 @@ func withEndpointSpec(ops ...func(*swarm.EndpointSpec)) func(*swarm.Service) {
} }
} }
func modeDNSSR(spec *swarm.EndpointSpec) { func modeDNSRR(spec *swarm.EndpointSpec) {
spec.Mode = swarm.ResolutionModeDNSRR spec.Mode = swarm.ResolutionModeDNSRR
} }

View file

@ -3976,7 +3976,7 @@ func TestDynConfBuilder_getIPAddress_swarm(t *testing.T) {
networks map[string]*network.Summary networks map[string]*network.Summary
}{ }{
{ {
service: swarmService(withEndpointSpec(modeDNSSR)), service: swarmService(withEndpointSpec(modeDNSRR)),
expected: "", expected: "",
networks: map[string]*network.Summary{}, networks: map[string]*network.Summary{},
}, },

View file

@ -114,7 +114,7 @@ func TestSwarmProvider_listServices(t *testing.T) {
"traefik.docker.network": "barnet", "traefik.docker.network": "barnet",
"traefik.docker.LBSwarm": "true", "traefik.docker.LBSwarm": "true",
}), }),
withEndpointSpec(modeDNSSR)), withEndpointSpec(modeDNSRR)),
}, },
dockerVersion: "1.30", dockerVersion: "1.30",
networks: []network.Summary{}, networks: []network.Summary{},
@ -140,7 +140,7 @@ func TestSwarmProvider_listServices(t *testing.T) {
"traefik.docker.network": "barnet", "traefik.docker.network": "barnet",
"traefik.docker.LBSwarm": "true", "traefik.docker.LBSwarm": "true",
}), }),
withEndpointSpec(modeDNSSR)), withEndpointSpec(modeDNSRR)),
}, },
dockerVersion: "1.30", dockerVersion: "1.30",
networks: []network.Summary{ networks: []network.Summary{
@ -185,7 +185,7 @@ func TestSwarmProvider_listServices(t *testing.T) {
serviceLabels(map[string]string{ serviceLabels(map[string]string{
"traefik.docker.network": "barnet", "traefik.docker.network": "barnet",
}), }),
withEndpointSpec(modeDNSSR)), withEndpointSpec(modeDNSRR)),
}, },
tasks: []swarm.Task{ tasks: []swarm.Task{
swarmTask("id1", swarmTask("id1",

View file

@ -86,7 +86,7 @@ func Test_getPort_swarm(t *testing.T) {
}{ }{
{ {
service: swarmService( service: swarmService(
withEndpointSpec(modeDNSSR), withEndpointSpec(modeDNSRR),
), ),
networks: map[string]*docker.NetworkResource{}, networks: map[string]*docker.NetworkResource{},
serverPort: "8080", serverPort: "8080",

View file

@ -91,15 +91,27 @@ func (i *Provider) createConfiguration(ctx context.Context) *dynamic.Configurati
} }
func (i *Provider) acme(cfg *dynamic.Configuration) { func (i *Provider) acme(cfg *dynamic.Configuration) {
var eps []string allowACMEByPass := map[string]bool{}
for name, ep := range i.staticCfg.EntryPoints {
allowACMEByPass[name] = ep.AllowACMEByPass
}
var eps []string
var epsByPass []string
uniq := map[string]struct{}{} uniq := map[string]struct{}{}
for _, resolver := range i.staticCfg.CertificatesResolvers { for _, resolver := range i.staticCfg.CertificatesResolvers {
if resolver.ACME != nil && resolver.ACME.HTTPChallenge != nil && resolver.ACME.HTTPChallenge.EntryPoint != "" { if resolver.ACME != nil && resolver.ACME.HTTPChallenge != nil && resolver.ACME.HTTPChallenge.EntryPoint != "" {
if _, ok := uniq[resolver.ACME.HTTPChallenge.EntryPoint]; !ok { if _, ok := uniq[resolver.ACME.HTTPChallenge.EntryPoint]; ok {
eps = append(eps, resolver.ACME.HTTPChallenge.EntryPoint) continue
uniq[resolver.ACME.HTTPChallenge.EntryPoint] = struct{}{}
} }
uniq[resolver.ACME.HTTPChallenge.EntryPoint] = struct{}{}
if allowByPass, ok := allowACMEByPass[resolver.ACME.HTTPChallenge.EntryPoint]; ok && allowByPass {
epsByPass = append(epsByPass, resolver.ACME.HTTPChallenge.EntryPoint)
continue
}
eps = append(eps, resolver.ACME.HTTPChallenge.EntryPoint)
} }
} }
@ -115,6 +127,17 @@ func (i *Provider) acme(cfg *dynamic.Configuration) {
cfg.HTTP.Routers["acme-http"] = rt cfg.HTTP.Routers["acme-http"] = rt
cfg.HTTP.Services["acme-http"] = &dynamic.Service{} cfg.HTTP.Services["acme-http"] = &dynamic.Service{}
} }
if len(epsByPass) > 0 {
rt := &dynamic.Router{
Rule: "PathPrefix(`/.well-known/acme-challenge/`)",
EntryPoints: epsByPass,
Service: "acme-http@internal",
}
cfg.HTTP.Routers["acme-http-bypass"] = rt
cfg.HTTP.Services["acme-http"] = &dynamic.Service{}
}
} }
func (i *Provider) redirection(ctx context.Context, cfg *dynamic.Configuration) { func (i *Provider) redirection(ctx context.Context, cfg *dynamic.Configuration) {

View file

@ -777,7 +777,7 @@ func TestDo_staticConfiguration(t *testing.T) {
} }
config.Providers.HTTP = &http.Provider{ config.Providers.HTTP = &http.Provider{
Endpoint: "Myenpoint", Endpoint: "Myendpoint",
PollInterval: 42, PollInterval: 42,
PollTimeout: 42, PollTimeout: 42,
TLS: &types.ClientTLS{ TLS: &types.ClientTLS{

View file

@ -858,7 +858,7 @@ func BenchmarkService(b *testing.B) {
LoadBalancer: &dynamic.ServersLoadBalancer{ LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{ Servers: []dynamic.Server{
{ {
URL: "tchouck", URL: "tchouk",
}, },
}, },
}, },

View file

@ -21,6 +21,8 @@ const defaultBufSize = 4096
// Router is a TCP router. // Router is a TCP router.
type Router struct { type Router struct {
acmeTLSPassthrough bool
// Contains TCP routes. // Contains TCP routes.
muxerTCP tcpmuxer.Muxer muxerTCP tcpmuxer.Muxer
// Contains TCP TLS routes. // Contains TCP TLS routes.
@ -164,7 +166,7 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) {
} }
// Handling ACME-TLS/1 challenges. // Handling ACME-TLS/1 challenges.
if slices.Contains(hello.protos, tlsalpn01.ACMETLS1Protocol) { if !r.acmeTLSPassthrough && slices.Contains(hello.protos, tlsalpn01.ACMETLS1Protocol) {
r.acmeTLSALPNHandler().ServeTCP(r.GetConn(conn, hello.peeked)) r.acmeTLSALPNHandler().ServeTCP(r.GetConn(conn, hello.peeked))
return return
} }
@ -317,6 +319,10 @@ func (r *Router) SetHTTPSHandler(handler http.Handler, config *tls.Config) {
r.httpsTLSConfig = config r.httpsTLSConfig = config
} }
func (r *Router) EnableACMETLSPassthrough() {
r.acmeTLSPassthrough = true
}
// Conn is a connection proxy that handles Peeked bytes. // Conn is a connection proxy that handles Peeked bytes.
type Conn struct { type Conn struct {
// Peeked are the bytes that have been read from Conn for the purposes of route matching, // Peeked are the bytes that have been read from Conn for the purposes of route matching,

View file

@ -215,6 +215,7 @@ func Test_Routing(t *testing.T) {
desc string desc string
routers []applyRouter routers []applyRouter
checks []checkCase checks []checkCase
allowACMETLSPassthrough bool
}{ }{
{ {
desc: "No routers", desc: "No routers",
@ -271,6 +272,18 @@ func Test_Routing(t *testing.T) {
}, },
}, },
}, },
{
desc: "TCP TLS passthrough catches ACME TLS",
allowACMETLSPassthrough: true,
routers: []applyRouter{routerTCPTLSCatchAllPassthrough},
checks: []checkCase{
{
desc: "ACME TLS Challenge",
checkRouter: checkACMETLS,
expectedError: "tls: first record does not look like a TLS handshake",
},
},
},
{ {
desc: "Single TCP CatchAll router", desc: "Single TCP CatchAll router",
routers: []applyRouter{routerTCPCatchAll}, routers: []applyRouter{routerTCPCatchAll},
@ -596,6 +609,10 @@ func Test_Routing(t *testing.T) {
router, err := manager.buildEntryPointHandler(context.Background(), dynConf.TCPRouters, dynConf.Routers, nil, nil) router, err := manager.buildEntryPointHandler(context.Background(), dynConf.TCPRouters, dynConf.Routers, nil, nil)
require.NoError(t, err) require.NoError(t, err)
if test.allowACMETLSPassthrough {
router.EnableACMETLSPassthrough()
}
epListener, err := net.Listen("tcp", "127.0.0.1:0") epListener, err := net.Listen("tcp", "127.0.0.1:0")
require.NoError(t, err) require.NoError(t, err)
@ -717,7 +734,7 @@ func routerTCPTLSCatchAll(conf *runtime.Configuration) {
} }
} }
// routerTCPTLSCatchAllPassthrough a TCP TLS CatchAll Passthrough - HostSNI(`*`) router with TLS 1.0 config. // routerTCPTLSCatchAllPassthrough a TCP TLS CatchAll Passthrough - HostSNI(`*`) router with TLS 1.2 config.
func routerTCPTLSCatchAllPassthrough(conf *runtime.Configuration) { func routerTCPTLSCatchAllPassthrough(conf *runtime.Configuration) {
conf.TCPRouters["tcp-tls-catchall-passthrough"] = &runtime.TCPRouterInfo{ conf.TCPRouters["tcp-tls-catchall-passthrough"] = &runtime.TCPRouterInfo{
TCPRouter: &dynamic.TCPRouter{ TCPRouter: &dynamic.TCPRouter{

View file

@ -23,6 +23,7 @@ import (
type RouterFactory struct { type RouterFactory struct {
entryPointsTCP []string entryPointsTCP []string
entryPointsUDP []string entryPointsUDP []string
allowACMEByPass map[string]bool
managerFactory *service.ManagerFactory managerFactory *service.ManagerFactory
@ -40,9 +41,20 @@ type RouterFactory struct {
func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *service.ManagerFactory, tlsManager *tls.Manager, func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *service.ManagerFactory, tlsManager *tls.Manager,
observabilityMgr *middleware.ObservabilityMgr, pluginBuilder middleware.PluginsBuilder, dialerManager *tcp.DialerManager, observabilityMgr *middleware.ObservabilityMgr, pluginBuilder middleware.PluginsBuilder, dialerManager *tcp.DialerManager,
) *RouterFactory { ) *RouterFactory {
handlesTLSChallenge := false
for _, resolver := range staticConfiguration.CertificatesResolvers {
if resolver.ACME != nil && resolver.ACME.TLSChallenge != nil {
handlesTLSChallenge = true
break
}
}
allowACMEByPass := map[string]bool{}
var entryPointsTCP, entryPointsUDP []string var entryPointsTCP, entryPointsUDP []string
for name, cfg := range staticConfiguration.EntryPoints { for name, ep := range staticConfiguration.EntryPoints {
protocol, err := cfg.GetProtocol() allowACMEByPass[name] = ep.AllowACMEByPass || !handlesTLSChallenge
protocol, err := ep.GetProtocol()
if err != nil { if err != nil {
// Should never happen because Traefik should not start if protocol is invalid. // Should never happen because Traefik should not start if protocol is invalid.
log.Error().Err(err).Msg("Invalid protocol") log.Error().Err(err).Msg("Invalid protocol")
@ -63,6 +75,7 @@ func NewRouterFactory(staticConfiguration static.Configuration, managerFactory *
tlsManager: tlsManager, tlsManager: tlsManager,
pluginBuilder: pluginBuilder, pluginBuilder: pluginBuilder,
dialerManager: dialerManager, dialerManager: dialerManager,
allowACMEByPass: allowACMEByPass,
} }
} }
@ -95,6 +108,12 @@ func (f *RouterFactory) CreateRouters(rtConf *runtime.Configuration) (map[string
rtTCPManager := tcprouter.NewManager(rtConf, svcTCPManager, middlewaresTCPBuilder, handlersNonTLS, handlersTLS, f.tlsManager) rtTCPManager := tcprouter.NewManager(rtConf, svcTCPManager, middlewaresTCPBuilder, handlersNonTLS, handlersTLS, f.tlsManager)
routersTCP := rtTCPManager.BuildHandlers(ctx, f.entryPointsTCP) routersTCP := rtTCPManager.BuildHandlers(ctx, f.entryPointsTCP)
for ep, r := range routersTCP {
if allowACMEByPass, ok := f.allowACMEByPass[ep]; ok && allowACMEByPass {
r.EnableACMETLSPassthrough()
}
}
// UDP // UDP
svcUDPManager := udpsvc.NewManager(rtConf) svcUDPManager := udpsvc.NewManager(rtConf)
rtUDPManager := udprouter.NewManager(rtConf, svcUDPManager) rtUDPManager := udprouter.NewManager(rtConf, svcUDPManager)

View file

@ -185,7 +185,10 @@ func NewTCPEntryPoint(ctx context.Context, name string, config *static.EntryPoin
return nil, fmt.Errorf("error preparing server: %w", err) return nil, fmt.Errorf("error preparing server: %w", err)
} }
rt := &tcprouter.Router{} rt, err := tcprouter.NewRouter()
if err != nil {
return nil, fmt.Errorf("error preparing tcp router: %w", err)
}
reqDecorator := requestdecorator.New(hostResolverConfig) reqDecorator := requestdecorator.New(hostResolverConfig)
@ -607,6 +610,7 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
handler, err = forwardedheaders.NewXForwarded( handler, err = forwardedheaders.NewXForwarded(
configuration.ForwardedHeaders.Insecure, configuration.ForwardedHeaders.Insecure,
configuration.ForwardedHeaders.TrustedIPs, configuration.ForwardedHeaders.TrustedIPs,
configuration.ForwardedHeaders.Connection,
next) next)
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -20,7 +20,9 @@ import (
) )
func TestShutdownHijacked(t *testing.T) { func TestShutdownHijacked(t *testing.T) {
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
conn, _, err := rw.(http.Hijacker).Hijack() conn, _, err := rw.(http.Hijacker).Hijack()
require.NoError(t, err) require.NoError(t, err)
@ -34,7 +36,9 @@ func TestShutdownHijacked(t *testing.T) {
} }
func TestShutdownHTTP(t *testing.T) { func TestShutdownHTTP(t *testing.T) {
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
time.Sleep(time.Second) time.Sleep(time.Second)
@ -167,7 +171,9 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) {
}, nil, nil) }, nil, nil)
require.NoError(t, err) require.NoError(t, err)
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -204,7 +210,9 @@ func TestReadTimeoutWithFirstByte(t *testing.T) {
}, nil, nil) }, nil, nil)
require.NoError(t, err) require.NoError(t, err)
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -244,7 +252,9 @@ func TestKeepAliveMaxRequests(t *testing.T) {
}, nil, nil) }, nil, nil)
require.NoError(t, err) require.NoError(t, err)
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))
@ -290,7 +300,9 @@ func TestKeepAliveMaxTime(t *testing.T) {
}, nil, nil) }, nil, nil)
require.NoError(t, err) require.NoError(t, err)
router := &tcprouter.Router{} router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK) rw.WriteHeader(http.StatusOK)
})) }))

View file

@ -47,7 +47,7 @@ func TestGetBestCertificate(t *testing.T) {
expectedCert: "*.snitest.com", expectedCert: "*.snitest.com",
}, },
{ {
desc: "Best Match with dynamic wildcard only, case insensitive", desc: "Best Match with dynamic wildcard only, case-insensitive",
domainToCheck: "bar.www.snitest.com", domainToCheck: "bar.www.snitest.com",
dynamicCert: "*.www.snitest.com", dynamicCert: "*.www.snitest.com",
expectedCert: "*.www.snitest.com", expectedCert: "*.www.snitest.com",

View file

@ -137,7 +137,7 @@ func TestMatchDomain(t *testing.T) {
expected: true, expected: true,
}, },
{ {
desc: "dot replaced by a cahr", desc: "dot replaced by a char",
certDomain: "sub.sub.traefik.wtf", certDomain: "sub.sub.traefik.wtf",
domain: "sub.sub.traefikiwtf", domain: "sub.sub.traefikiwtf",
expected: false, expected: false,

View file

@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file" OutputType = "file"
FileName = "traefik_changelog.md" FileName = "traefik_changelog.md"
# example new bugfix v3.1.2 # example new bugfix v3.1.4
CurrentRef = "v3.1" CurrentRef = "v3.1"
PreviousRef = "v3.1.1" PreviousRef = "v3.1.3"
BaseBranch = "v3.1" BaseBranch = "v3.1"
FutureCurrentRefName = "v3.1.2" FutureCurrentRefName = "v3.1.4"
ThresholdPreviousRef = 10 ThresholdPreviousRef = 10
ThresholdCurrentRef = 10 ThresholdCurrentRef = 10

View file

@ -129,7 +129,7 @@
align="left" align="left"
icon="eva-github-outline" icon="eva-github-outline"
no-caps no-caps
label="Github repository" label="GitHub repository"
class="btn-submenu full-width" class="btn-submenu full-width"
/> />
</q-item> </q-item>