Merge branch v3.4 into master

This commit is contained in:
kevinpollet 2025-06-02 16:54:12 +02:00
commit 289d6e5dca
No known key found for this signature in database
GPG Key ID: 0C9A5DDD1B292453
195 changed files with 1963 additions and 892 deletions

View File

@ -10,7 +10,7 @@ on:
- 'script/gcg/**' - 'script/gcg/**'
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
CGO_ENABLED: 0 CGO_ENABLED: 0
jobs: jobs:

View File

@ -7,7 +7,7 @@ on:
- v* - v*
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
CGO_ENABLED: 0 CGO_ENABLED: 0
jobs: jobs:

View File

@ -6,7 +6,7 @@ on:
- 'v*.*.*' - 'v*.*.*'
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
CGO_ENABLED: 0 CGO_ENABLED: 0
VERSION: ${{ github.ref_name }} VERSION: ${{ github.ref_name }}
TRAEFIKER_EMAIL: "traefiker@traefik.io" TRAEFIKER_EMAIL: "traefiker@traefik.io"

View File

@ -10,7 +10,7 @@ on:
- 'script/gcg/**' - 'script/gcg/**'
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
CGO_ENABLED: 0 CGO_ENABLED: 0
jobs: jobs:

View File

@ -10,11 +10,39 @@ on:
- 'script/gcg/**' - 'script/gcg/**'
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
jobs: jobs:
generate-packages:
name: List Go Packages
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Go ${{ env.GO_VERSION }}
uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
check-latest: true
- name: Generate matrix
id: set-matrix
run: |
matrix_output=$(go run ./internal/testsci/genmatrix.go)
echo "$matrix_output"
echo "$matrix_output" >> $GITHUB_OUTPUT
test-unit: test-unit:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: generate-packages
strategy:
matrix:
package: ${{ fromJson(needs.generate-packages.outputs.matrix) }}
steps: steps:
- name: Check out code - name: Check out code
@ -34,7 +62,8 @@ jobs:
touch webui/static/index.html touch webui/static/index.html
- name: Tests - name: Tests
run: make test-unit run: |
go test -v -parallel 8 ${{ matrix.package.group }}
test-ui-unit: test-ui-unit:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@ -6,7 +6,7 @@ on:
- '*' - '*'
env: env:
GO_VERSION: '1.23' GO_VERSION: '1.24'
GOLANGCI_LINT_VERSION: v2.0.2 GOLANGCI_LINT_VERSION: v2.0.2
MISSPELL_VERSION: v0.6.0 MISSPELL_VERSION: v0.6.0

View File

@ -1,3 +1,39 @@
## [v3.4.1](https://github.com/traefik/traefik/tree/v3.4.1) (2025-05-27)
[All Commits](https://github.com/traefik/traefik/compare/v3.4.0...v3.4.1)
**Bug fixes:**
- **[docker]** Do not warn network missing if connected to a container network ([#11698](https://github.com/traefik/traefik/pull/11698) by [holysoles](https://github.com/holysoles))
- **[k8s/crd]** Fix CEL validation for RootCA in ServersTransport ([#11775](https://github.com/traefik/traefik/pull/11775) by [rtribotte](https://github.com/rtribotte))
- **[middleware]** Scope the rate limit counter key by source and by middleware ([#11753](https://github.com/traefik/traefik/pull/11753) by [aromeyer](https://github.com/aromeyer))
- **[server]** Use routing path in v3 matchers ([#11790](https://github.com/traefik/traefik/pull/11790) by [kevinpollet](https://github.com/kevinpollet))
- **[service]** Make P2C strategy thread-safe ([#11762](https://github.com/traefik/traefik/pull/11762) by [lbenguigui](https://github.com/lbenguigui))
- **[webui]** Do not display RemoveHeader option when not defined ([#11782](https://github.com/traefik/traefik/pull/11782) by [kevinpollet](https://github.com/kevinpollet))
**Documentation:**
- **[acme]** Fix ambiguous wording in ACME page ([#11789](https://github.com/traefik/traefik/pull/11789) by [joshka](https://github.com/joshka))
- **[k8s]** Fix incorrect case and missing rbac in documentation ([#11742](https://github.com/traefik/traefik/pull/11742) by [mmatur](https://github.com/mmatur))
- **[middleware]** Match encoded certificate to example data for TLS passthrough ([#11759](https://github.com/traefik/traefik/pull/11759) by [holysoles](https://github.com/holysoles))
**Misc:**
- Merge branch v2.11 into v3.4 ([#11799](https://github.com/traefik/traefik/pull/11799) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v2.11 into v3.4 ([#11796](https://github.com/traefik/traefik/pull/11796) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v2.11 into v3.4 ([#11783](https://github.com/traefik/traefik/pull/11783) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v2.11 into v3.4 ([#11757](https://github.com/traefik/traefik/pull/11757) by [mmatur](https://github.com/mmatur))
- Merge v2.11 into v3.4 ([#11751](https://github.com/traefik/traefik/pull/11751) by [mmatur](https://github.com/mmatur))
## [v2.11.25](https://github.com/traefik/traefik/tree/v2.11.25) (2025-05-27)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.24...v2.11.25)
**Bug fixes:**
- **[k8s/ingress]** Fix panic for ingress with backend resource ([#11777](https://github.com/traefik/traefik/pull/11777) by [rtribotte](https://github.com/rtribotte))
- **[server]** Normalize request path ([#11768](https://github.com/traefik/traefik/pull/11768) by [kevinpollet](https://github.com/kevinpollet))
**Documentation:**
- **[middleware,k8s]** Add multi-tenant TLS guidance to the docs ([#11724](https://github.com/traefik/traefik/pull/11724) by [sheddy-traefik](https://github.com/sheddy-traefik))
- **[service]** Add a note about how to disable connection reuse with backends ([#11716](https://github.com/traefik/traefik/pull/11716) by [rtribotte](https://github.com/rtribotte))
- Fix broken link in documentation ([#11761](https://github.com/traefik/traefik/pull/11761) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Change version for path sanitization migration guide ([#11702](https://github.com/traefik/traefik/pull/11702) by [rtribotte](https://github.com/rtribotte))
## [v3.4.0](https://github.com/traefik/traefik/tree/v3.4.0) (2025-05-05) ## [v3.4.0](https://github.com/traefik/traefik/tree/v3.4.0) (2025-05-05)
[All Commits](https://github.com/traefik/traefik/compare/v3.3.0-rc1...v3.4.0) [All Commits](https://github.com/traefik/traefik/compare/v3.3.0-rc1...v3.4.0)

View File

@ -301,7 +301,10 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
// Router factory // Router factory
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, observabilityMgr, pluginBuilder, dialerManager) routerFactory, err := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, observabilityMgr, pluginBuilder, dialerManager)
if err != nil {
return nil, fmt.Errorf("creating router factory: %w", err)
}
// Watcher // Watcher

View File

@ -15,8 +15,6 @@ A Use Case Using Docker
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image: Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
```yaml ```yaml
version: '3'
services: services:
reverse-proxy: reverse-proxy:
# The official v3 Traefik docker image # The official v3 Traefik docker image
@ -50,8 +48,6 @@ Now that you have a Traefik instance up and running, you will deploy new service
Edit your `docker-compose.yml` file and add the following at the end of your file. Edit your `docker-compose.yml` file and add the following at the end of your file.
```yaml ```yaml
version: '3'
services: services:
... ...

View File

@ -13,7 +13,7 @@ You can configure Traefik to use an ACME provider (like Let's Encrypt) for autom
!!! 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 cannot 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 the `acme.json` 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.
To configure where certificates are stored, please take a look at the [storage](#storage) configuration. To configure where certificates are stored, please take a look at the [storage](#storage) configuration.
@ -795,6 +795,8 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
_Optional, Default=2160_ _Optional, Default=2160_
`certificatesDuration` specifies the duration (in hours) of the certificates issued by the CA server. It is used to determine when to renew the certificate, but it **doesn't** define the duration of the certificates, that is up to the CA server.
`certificatesDuration` is used to calculate two durations: `certificatesDuration` is used to calculate two durations:
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed. - `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.

View File

@ -677,3 +677,32 @@ it can lead to unsafe routing when the `sanitizePath` option is set to `false`.
Setting the `sanitizePath` option to `false` is not safe. Setting the `sanitizePath` option to `false` is not safe.
Ensure every request is properly url encoded instead. Ensure every request is properly url encoded instead.
## v2.11.25
### Request Path Normalization
Since `v2.11.25`, the request path is now normalized by decoding unreserved characters in the request path,
and also uppercasing the percent-encoded characters.
This follows [RFC 3986 percent-encoding normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.2),
and [RFC 3986 case normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
The normalization happens before the request path is sanitized,
and cannot be disabled.
This notably helps with encoded dots characters (which are unreserved characters) to be sanitized properly.
### Routing Path
Since `v2.11.25`, the reserved characters [(as per RFC 3986)](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2) are kept encoded in the request path when matching the router rules.
Those characters, when decoded, change the meaning of the request path for routing purposes,
and Traefik now keeps them encoded to avoid any ambiguity.
### Request Path Matching Examples
| Request Path | Router Rule | Traefik v2.11.24 | Traefik v2.11.25 |
|-------------------|------------------------|------------------|------------------|
| `/foo%2Fbar` | PathPrefix(`/foo/bar`) | Match | No match |
| `/foo/../bar` | PathPrefix(`/foo`) | No match | No match |
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |

View File

@ -290,3 +290,32 @@ and to help with the migration from v2 to v3.
The `ruleSyntax` router's option was used to override the default rule syntax for a specific router. The `ruleSyntax` router's option was used to override the default rule syntax for a specific router.
In preparation for the next major release, please remove any use of these two options and use the v3 syntax for writing the router's rules. In preparation for the next major release, please remove any use of these two options and use the v3 syntax for writing the router's rules.
## v3.4.1
### Request Path Normalization
Since `v3.4.1`, the request path is now normalized by decoding unreserved characters in the request path,
and also uppercasing the percent-encoded characters.
This follows [RFC 3986 percent-encoding normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.2),
and [RFC 3986 case normalization](https://datatracker.ietf.org/doc/html/rfc3986#section-6.2.2.1).
The normalization happens before the request path is sanitized,
and cannot be disabled.
This notably helps with encoded dots characters (which are unreserved characters) to be sanitized properly.
### Routing Path
Since `v3.4.1`, the reserved characters [(as per RFC 3986)](https://datatracker.ietf.org/doc/html/rfc3986#section-2.2) are kept encoded in the request path when matching the router rules.
Those characters, when decoded, change the meaning of the request path for routing purposes,
and Traefik now keeps them encoded to avoid any ambiguity.
### Request Path Matching Examples
| Request Path | Router Rule | Traefik v3.4.0 | Traefik v3.4.1 |
|-------------------|------------------------|----------------|----------------|
| `/foo%2Fbar` | PathPrefix(`/foo/bar`) | Match | No match |
| `/foo/../bar` | PathPrefix(`/foo`) | No match | No match |
| `/foo/../bar` | PathPrefix(`/bar`) | Match | Match |
| `/foo/%2E%2E/bar` | PathPrefix(`/foo`) | Match | No match |
| `/foo/%2E%2E/bar` | PathPrefix(`/bar`) | No match | Match |

View File

@ -288,8 +288,6 @@ It is possible to configure the Traefik to timestamp in a specific timezone by e
Example utilizing Docker Compose: Example utilizing Docker Compose:
```yaml ```yaml
version: "3.7"
services: services:
traefik: traefik:
image: traefik:v3.4 image: traefik:v3.4

View File

@ -40,7 +40,6 @@ This provider works with [Docker (standalone) Engine](https://docs.docker.com/en
Attaching labels to containers (in your docker compose file) Attaching labels to containers (in your docker compose file)
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -162,8 +161,6 @@ See the [Docker API Access](#docker-api-access) section for more information.
The docker-compose file shares the docker sock with the Traefik container The docker-compose file shares the docker sock with the Traefik container
```yaml ```yaml
version: '3'
services: services:
traefik: traefik:
image: traefik:v3.4 # The official v3 Traefik docker image image: traefik:v3.4 # The official v3 Traefik docker image

View File

@ -53,7 +53,6 @@ This provider works with [Docker Swarm Mode](https://docs.docker.com/engine/swar
then that service is automatically assigned to the router. then that service is automatically assigned to the router.
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
deploy: deploy:
@ -176,8 +175,6 @@ docker service create \
``` ```
```yml tab="With Docker Compose" ```yml tab="With Docker Compose"
version: '3'
services: services:
traefik: traefik:
# ... # ...
@ -208,8 +205,6 @@ See the [Docker Swarm API Access](#docker-api-access) section for more informati
The docker-compose file shares the docker sock with the Traefik container The docker-compose file shares the docker sock with the Traefik container
```yaml ```yaml
version: '3'
services: services:
traefik: traefik:
image: traefik:v3.4 # The official v3 Traefik docker image image: traefik:v3.4 # The official v3 Traefik docker image

View File

@ -2291,7 +2291,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-
@ -2436,7 +2436,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-

View File

@ -134,7 +134,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-

View File

@ -110,7 +110,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-

View File

@ -199,8 +199,6 @@ It is possible to configure the Traefik to timestamp in a specific timezone by e
Example utilizing Docker Compose: Example utilizing Docker Compose:
```yaml ```yaml
version: "3.7"
services: services:
traefik: traefik:
image: traefik:v3.4 image: traefik:v3.4

View File

@ -29,7 +29,6 @@ providers:
Attach labels to containers (in your Docker compose file) Attach labels to containers (in your Docker compose file)
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -67,8 +66,6 @@ See the [Docker API Access](#docker-api-access) section for more information.
The docker-compose file shares the docker sock with the Traefik container The docker-compose file shares the docker sock with the Traefik container
```yaml ```yaml
version: '3'
services: services:
traefik: traefik:
image: traefik:v3.1 # The official v3 Traefik docker image image: traefik:v3.1 # The official v3 Traefik docker image

View File

@ -33,7 +33,6 @@ When there is only one service, and the router does not specify a service,
then that service is automatically assigned to the router. then that service is automatically assigned to the router.
```yaml tab="Labels" ```yaml tab="Labels"
version: "3"
services: services:
my-container: my-container:
deploy: deploy:
@ -73,8 +72,6 @@ See the [Docker Swarm API Access](#docker-api-access) section for more informati
The docker-compose file shares the docker sock with the Traefik container The docker-compose file shares the docker sock with the Traefik container
```yaml ```yaml
version: '3'
services: services:
traefik: traefik:
image: traefik:v3.1 # The official v3 Traefik docker image image: traefik:v3.1 # The official v3 Traefik docker image
@ -405,8 +402,6 @@ docker service create \
``` ```
```yml tab="With Docker Compose" ```yml tab="With Docker Compose"
version: '3'
services: services:
traefik: traefik:
# ... # ...

View File

@ -72,8 +72,6 @@ When using Docker or Amazon ECS, you can define routing configuration using cont
When deploying a Docker container, you can specify labels to define routing rules and services: When deploying a Docker container, you can specify labels to define routing rules and services:
```yaml ```yaml
version: '3'
services: services:
my-service: my-service:
image: my-image image: my-image

View File

@ -202,109 +202,6 @@ spec:
- `X-Forwarded-Tls-Client-Cert-Info` header value is a string that has been escaped in order to be a valid URL query. - `X-Forwarded-Tls-Client-Cert-Info` header value is a string that has been escaped in order to be a valid URL query.
- These options only work accordingly to the MutualTLS configuration. i.e, only the certificates that match the `clientAuth.clientAuthType` policy are passed. - These options only work accordingly to the MutualTLS configuration. i.e, only the certificates that match the `clientAuth.clientAuthType` policy are passed.
??? example "Example of a complete certificate and explaining each of the middleware options"
```txt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 1 (0x1)
Signature Algorithm: sha1WithRSAEncryption
Issuer: DC=org, DC=cheese, O=Cheese, O=Cheese 2, OU=Simple Signing Section, OU=Simple Signing Section 2, CN=Simple Signing CA, CN=Simple Signing CA 2, C=FR, C=US, L=TOULOUSE, L=LYON, ST=Signing State, ST=Signing State 2/emailAddress=simple@signing.com/emailAddress=simple2@signing.com
Validity
Not Before: Dec 6 11:10:16 2018 GMT
Not After : Dec 5 11:10:16 2020 GMT
Subject: DC=org, DC=cheese, O=Cheese, O=Cheese 2, OU=Simple Signing Section, OU=Simple Signing Section 2, CN=*.example.org, CN=*.example.com, C=FR, C=US, L=TOULOUSE, L=LYON, ST=Cheese org state, ST=Cheese com statemailAddress=cert@example.org/emailAddress=cert@sexample.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:de:77:fa:8d:03:70:30:39:dd:51:1b:cc:60:db:
a9:5a:13:b1:af:fe:2c:c6:38:9b:88:0a:0f:8e:d9:
1b:a1:1d:af:0d:66:e4:13:5b:bc:5d:36:92:d7:5e:
d0:fa:88:29:d3:78:e1:81:de:98:b2:a9:22:3f:bf:
8a:af:12:92:63:d4:a9:c3:f2:e4:7e:d2:dc:a2:c5:
39:1c:7a:eb:d7:12:70:63:2e:41:47:e0:f0:08:e8:
dc:be:09:01:ec:28:09:af:35:d7:79:9c:50:35:d1:
6b:e5:87:7b:34:f6:d2:31:65:1d:18:42:69:6c:04:
11:83:fe:44:ae:90:92:2d:0b:75:39:57:62:e6:17:
2f:47:2b:c7:53:dd:10:2d:c9:e3:06:13:d2:b9:ba:
63:2e:3c:7d:83:6b:d6:89:c9:cc:9d:4d:bf:9f:e8:
a3:7b:da:c8:99:2b:ba:66:d6:8e:f8:41:41:a0:c9:
d0:5e:c8:11:a4:55:4a:93:83:87:63:04:63:41:9c:
fb:68:04:67:c2:71:2f:f2:65:1d:02:5d:15:db:2c:
d9:04:69:85:c2:7d:0d:ea:3b:ac:85:f8:d4:8f:0f:
c5:70:b2:45:e1:ec:b2:54:0b:e9:f7:82:b4:9b:1b:
2d:b9:25:d4:ab:ca:8f:5b:44:3e:15:dd:b8:7f:b7:
ee:f9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Basic Constraints:
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Key Identifier:
94:BA:73:78:A2:87:FB:58:28:28:CF:98:3B:C2:45:70:16:6E:29:2F
X509v3 Authority Key Identifier:
keyid:1E:52:A2:E8:54:D5:37:EB:D5:A8:1D:E4:C2:04:1D:37:E2:F7:70:03
X509v3 Subject Alternative Name:
DNS:*.example.org, DNS:*.example.net, DNS:*.example.com, IP Address:10.0.1.0, IP Address:10.0.1.2, email:test@example.org, email:test@example.net
Signature Algorithm: sha1WithRSAEncryption
76:6b:05:b0:0e:34:11:b1:83:99:91:dc:ae:1b:e2:08:15:8b:
16:b2:9b:27:1c:02:ac:b5:df:1b:d0:d0:75:a4:2b:2c:5c:65:
ed:99:ab:f7:cd:fe:38:3f:c3:9a:22:31:1b:ac:8c:1c:c2:f9:
5d:d4:75:7a:2e:72:c7:85:a9:04:af:9f:2a:cc:d3:96:75:f0:
8e:c7:c6:76:48:ac:45:a4:b9:02:1e:2f:c0:15:c4:07:08:92:
cb:27:50:67:a1:c8:05:c5:3a:b3:a6:48:be:eb:d5:59:ab:a2:
1b:95:30:71:13:5b:0a:9a:73:3b:60:cc:10:d0:6a:c7:e5:d7:
8b:2f:f9:2e:98:f2:ff:81:14:24:09:e3:4b:55:57:09:1a:22:
74:f1:f6:40:13:31:43:89:71:0a:96:1a:05:82:1f:83:3a:87:
9b:17:25:ef:5a:55:f2:2d:cd:0d:4d:e4:81:58:b6:e3:8d:09:
62:9a:0c:bd:e4:e5:5c:f0:95:da:cb:c7:34:2c:34:5f:6d:fc:
60:7b:12:5b:86:fd:df:21:89:3b:48:08:30:bf:67:ff:8c:e6:
9b:53:cc:87:36:47:70:40:3b:d9:90:2a:d2:d2:82:c6:9c:f5:
d1:d8:e0:e6:fd:aa:2f:95:7e:39:ac:fc:4e:d4:ce:65:b3:ec:
c6:98:8a:31
-----BEGIN CERTIFICATE-----
MIIGWjCCBUKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCCAYQxEzARBgoJkiaJk/Is
ZAEZFgNvcmcxFjAUBgoJkiaJk/IsZAEZFgZjaGVlc2UxDzANBgNVBAoMBkNoZWVz
ZTERMA8GA1UECgwIQ2hlZXNlIDIxHzAdBgNVBAsMFlNpbXBsZSBTaWduaW5nIFNl
Y3Rpb24xITAfBgNVBAsMGFNpbXBsZSBTaWduaW5nIFNlY3Rpb24gMjEaMBgGA1UE
AwwRU2ltcGxlIFNpZ25pbmcgQ0ExHDAaBgNVBAMME1NpbXBsZSBTaWduaW5nIENB
IDIxCzAJBgNVBAYTAkZSMQswCQYDVQQGEwJVUzERMA8GA1UEBwwIVE9VTE9VU0Ux
DTALBgNVBAcMBExZT04xFjAUBgNVBAgMDVNpZ25pbmcgU3RhdGUxGDAWBgNVBAgM
D1NpZ25pbmcgU3RhdGUgMjEhMB8GCSqGSIb3DQEJARYSc2ltcGxlQHNpZ25pbmcu
Y29tMSIwIAYJKoZIhvcNAQkBFhNzaW1wbGUyQHNpZ25pbmcuY29tMB4XDTE4MTIw
NjExMTAxNloXDTIwMTIwNTExMTAxNlowggF2MRMwEQYKCZImiZPyLGQBGRYDb3Jn
MRYwFAYKCZImiZPyLGQBGRYGY2hlZXNlMQ8wDQYDVQQKDAZDaGVlc2UxETAPBgNV
BAoMCENoZWVzZSAyMR8wHQYDVQQLDBZTaW1wbGUgU2lnbmluZyBTZWN0aW9uMSEw
HwYDVQQLDBhTaW1wbGUgU2lnbmluZyBTZWN0aW9uIDIxFTATBgNVBAMMDCouY2hl
ZXNlLm9yZzEVMBMGA1UEAwwMKi5jaGVlc2UuY29tMQswCQYDVQQGEwJGUjELMAkG
A1UEBhMCVVMxETAPBgNVBAcMCFRPVUxPVVNFMQ0wCwYDVQQHDARMWU9OMRkwFwYD
VQQIDBBDaGVlc2Ugb3JnIHN0YXRlMRkwFwYDVQQIDBBDaGVlc2UgY29tIHN0YXRl
MR4wHAYJKoZIhvcNAQkBFg9jZXJ0QGNoZWVzZS5vcmcxHzAdBgkqhkiG9w0BCQEW
EGNlcnRAc2NoZWVzZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDed/qNA3AwOd1RG8xg26laE7Gv/izGOJuICg+O2RuhHa8NZuQTW7xdNpLXXtD6
iCnTeOGB3piyqSI/v4qvEpJj1KnD8uR+0tyixTkceuvXEnBjLkFH4PAI6Ny+CQHs
KAmvNdd5nFA10Wvlh3s09tIxZR0YQmlsBBGD/kSukJItC3U5V2LmFy9HK8dT3RAt
yeMGE9K5umMuPH2Da9aJycydTb+f6KN72siZK7pm1o74QUGgydBeyBGkVUqTg4dj
BGNBnPtoBGfCcS/yZR0CXRXbLNkEaYXCfQ3qO6yF+NSPD8VwskXh7LJUC+n3grSb
Gy25JdSryo9bRD4V3bh/t+75AgMBAAGjgeAwgd0wDgYDVR0PAQH/BAQDAgWgMAkG
A1UdEwQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW
BBSUunN4oof7WCgoz5g7wkVwFm4pLzAfBgNVHSMEGDAWgBQeUqLoVNU369WoHeTC
BB034vdwAzBhBgNVHREEWjBYggwqLmNoZWVzZS5vcmeCDCouY2hlZXNlLm5ldIIM
Ki5jaGVlc2UuY29thwQKAAEAhwQKAAECgQ90ZXN0QGNoZWVzZS5vcmeBD3Rlc3RA
Y2hlZXNlLm5ldDANBgkqhkiG9w0BAQUFAAOCAQEAdmsFsA40EbGDmZHcrhviCBWL
FrKbJxwCrLXfG9DQdaQrLFxl7Zmr983+OD/DmiIxG6yMHML5XdR1ei5yx4WpBK+f
KszTlnXwjsfGdkisRaS5Ah4vwBXEBwiSyydQZ6HIBcU6s6ZIvuvVWauiG5UwcRNb
CppzO2DMENBqx+XXiy/5Lpjy/4EUJAnjS1VXCRoidPH2QBMxQ4lxCpYaBYIfgzqH
mxcl71pV8i3NDU3kgVi2440JYpoMveTlXPCV2svHNCw0X238YHsSW4b93yGJO0gI
-----END CERTIFICATE-----
```
## Configuration Options ## Configuration Options
| Field | Description | Default | Required | | Field | Description | Default | Required |
@ -362,5 +259,5 @@ If there are more than one certificate, they are separated by a `,`.
The following example shows such a concatenation, when all the available fields are selected: The following example shows such a concatenation, when all the available fields are selected:
```text ```text
Subject="DC=org,DC=cheese,C=FR,C=US,ST=Cheese org state,ST=Cheese com state,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=*.example.com";Issuer="DC=org,DC=cheese,C=FR,C=US,ST=Signing State,ST=Signing State 2,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=Simple Signing CA 2";NB="1544094616";NA="1607166616";SAN="*.example.org,*.example.net,*.example.com,test@example.org,test@example.net,10.0.1.0,10.0.1.2" Subject="DC=org,DC=cheese,C=FR,C=US,ST=Cheese org state,ST=Cheese com state,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=*.example.com";Issuer="DC=org,DC=cheese,C=FR,C=US,ST=Signing State,ST=Signing State 2,L=TOULOUSE,L=LYON,O=Cheese,O=Cheese 2,CN=Simple Signing CA 2";NB="1747282426";NA="1778818426"SAN="*.example.org,*.example.net,*.example.com,test@example.org,test@example.net,10.0.1.0,10.0.1.2"
``` ```

View File

@ -35,7 +35,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Attaching labels to containers (in your docker compose file) Attaching labels to containers (in your docker compose file)
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -48,7 +47,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Forward requests for `http://example.com` to `http://<private IP of container>:12345`: Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -71,7 +69,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`: In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...

View File

@ -48,7 +48,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
then that service is automatically assigned to the router. then that service is automatically assigned to the router.
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
deploy: deploy:
@ -67,7 +66,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
Forward requests for `http://example.com` to `http://<private IP of container>:12345`: Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -93,7 +91,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`: In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...

View File

@ -42,7 +42,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Attaching labels to containers (in your docker compose file) Attaching labels to containers (in your docker compose file)
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -55,7 +54,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
Forward requests for `http://example.com` to `http://<private IP of container>:12345`: Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -78,7 +76,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`: In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...

View File

@ -55,7 +55,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
then that service is automatically assigned to the router. then that service is automatically assigned to the router.
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
deploy: deploy:
@ -74,7 +73,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
Forward requests for `http://example.com` to `http://<private IP of container>:12345`: Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...
@ -100,7 +98,6 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`: In this example, requests are forwarded for `http://example-a.com` to `http://<private IP of container>:8000` in addition to `http://example-b.com` forwarding to `http://<private IP of container>:9000`:
```yaml ```yaml
version: "3"
services: services:
my-container: my-container:
# ... # ...

View File

@ -5,7 +5,7 @@ description: "Enforce strict ContentLength validation in Traefik by streaming
Traefik acts as a streaming proxy. By default, it checks each chunk of data against the `Content-Length` header as it passes it on to the backend or client. This live check blocks truncated or overlong streams without holding the entire message. Traefik acts as a streaming proxy. By default, it checks each chunk of data against the `Content-Length` header as it passes it on to the backend or client. This live check blocks truncated or overlong streams without holding the entire message.
If you need Traefik to read and verify the full body before any data moves on, add the [buffering middleware](../../reference/routing-configuration/http/middlewares/buffering.md): If you need Traefik to read and verify the full body before any data moves on, add the [buffering middleware](../middlewares/http/buffering.md):
```yaml ```yaml
http: http:

View File

@ -1,5 +1,3 @@
version: "3.3"
services: services:
traefik: traefik:

View File

@ -1,5 +1,3 @@
version: "3.3"
secrets: secrets:
ovh_endpoint: ovh_endpoint:
file: "./secrets/ovh_endpoint.secret" file: "./secrets/ovh_endpoint.secret"

View File

@ -1,5 +1,3 @@
version: "3.3"
services: services:
traefik: traefik:

View File

@ -1,5 +1,3 @@
version: "3.3"
services: services:
traefik: traefik:

View File

@ -1,5 +1,3 @@
version: "3.3"
services: services:
traefik: traefik:

View File

@ -23,8 +23,6 @@ Create a `docker-compose.yml` file with the following content:
You can use a [pre-existing network](https://docs.docker.com/compose/networking/#use-a-pre-existing-network "Link to Docker Compose networking docs") too. You can use a [pre-existing network](https://docs.docker.com/compose/networking/#use-a-pre-existing-network "Link to Docker Compose networking docs") too.
```yaml ```yaml
version: "3.3"
networks: networks:
traefiknet: {} traefiknet: {}

View File

@ -0,0 +1,355 @@
---
title: "Traefik WebSocket Documentation"
description: "How to configure WebSocket and WebSocket Secure (WSS) connections with Traefik Proxy."
---
# WebSocket
Configuring Traefik to handle WebSocket and WebSocket Secure (WSS) connections.
{: .subtitle }
## Overview
WebSocket is a communication protocol that provides full-duplex communication channels over a single TCP connection.
WebSocket Secure (WSS) is the encrypted version of WebSocket, using TLS/SSL encryption.
Traefik supports WebSocket and WebSocket Secure (WSS) out of the box. This guide will walk through examples of how to configure Traefik for different WebSocket scenarios.
## Basic WebSocket Configuration
A basic WebSocket configuration only requires defining a router and a service that points to your WebSocket server.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-websocket.rule=Host(`ws.example.com`)"
- "traefik.http.routers.my-websocket.service=my-websocket-service"
- "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-route
spec:
entryPoints:
- web
routes:
- match: Host(`ws.example.com`)
kind: Rule
services:
- name: my-websocket-service
port: 8000
```
```yaml tab="File (YAML)"
http:
routers:
my-websocket:
rule: "Host(`ws.example.com`)"
service: my-websocket-service
services:
my-websocket-service:
loadBalancer:
servers:
- url: "http://my-websocket-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-websocket]
rule = "Host(`ws.example.com`)"
service = "my-websocket-service"
[http.services]
[http.services.my-websocket-service]
[http.services.my-websocket-service.loadBalancer]
[[http.services.my-websocket-service.loadBalancer.servers]]
url = "http://my-websocket-server:8000"
```
## WebSocket Secure (WSS) Configuration
WebSocket Secure (WSS) requires TLS configuration.
The client connects using the `wss://` protocol instead of `ws://`.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-websocket-secure.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-websocket-secure.service=my-websocket-service"
- "traefik.http.routers.my-websocket-secure.tls=true"
- "traefik.http.services.my-websocket-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-secure-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-websocket-service
port: 8000
tls: {}
```
```yaml tab="File (YAML)"
http:
routers:
my-websocket-secure:
rule: "Host(`wss.example.com`)"
service: my-websocket-service
tls: {}
services:
my-websocket-service:
loadBalancer:
servers:
- url: "http://my-websocket-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-websocket-secure]
rule = "Host(`wss.example.com`)"
service = "my-websocket-service"
[http.routers.my-websocket-secure.tls]
[http.services]
[http.services.my-websocket-service]
[http.services.my-websocket-service.loadBalancer]
[[http.services.my-websocket-service.loadBalancer.servers]]
url = "http://my-websocket-server:8000"
```
## SSL Termination for WebSockets
In this scenario, clients connect to Traefik using WSS (encrypted), but Traefik connects to your backend server using WS (unencrypted).
This is called SSL termination.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-wss-termination.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-wss-termination.service=my-ws-service"
- "traefik.http.routers.my-wss-termination.tls=true"
- "traefik.http.services.my-ws-service.loadbalancer.server.port=8000"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-wss-termination-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-ws-service
port: 8000
tls: {}
```
```yaml tab="File (YAML)"
http:
routers:
my-wss-termination:
rule: "Host(`wss.example.com`)"
service: my-ws-service
tls: {}
services:
my-ws-service:
loadBalancer:
servers:
- url: "http://my-ws-server:8000"
```
```toml tab="File (TOML)"
[http.routers]
[http.routers.my-wss-termination]
rule = "Host(`wss.example.com`)"
service = "my-ws-service"
[http.routers.my-wss-termination.tls]
[http.services]
[http.services.my-ws-service]
[http.services.my-ws-service.loadBalancer]
[[http.services.my-ws-service.loadBalancer.servers]]
url = "http://my-ws-server:8000"
```
## End-to-End WebSocket Secure (WSS)
For end-to-end encryption, Traefik can be configured to connect to your backend using HTTPS.
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.routers.my-wss-e2e.rule=Host(`wss.example.com`)"
- "traefik.http.routers.my-wss-e2e.service=my-wss-service"
- "traefik.http.routers.my-wss-e2e.tls=true"
- "traefik.http.services.my-wss-service.loadbalancer.server.port=8443"
# If the backend uses a self-signed certificate
- "traefik.http.serversTransports.insecureTransport.insecureSkipVerify=true"
- "traefik.http.services.my-wss-service.loadBalancer.serversTransport=insecureTransport"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: insecure-transport
spec:
insecureSkipVerify: true
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-wss-e2e-route
spec:
entryPoints:
- websecure
routes:
- match: Host(`wss.example.com`)
kind: Rule
services:
- name: my-wss-service
port: 8443
serversTransport: insecure-transport
tls: {}
```
```yaml tab="File (YAML)"
http:
serversTransports:
insecureTransport:
insecureSkipVerify: true
routers:
my-wss-e2e:
rule: "Host(`wss.example.com`)"
service: my-wss-service
tls: {}
services:
my-wss-service:
loadBalancer:
serversTransport: insecureTransport
servers:
- url: "https://my-wss-server:8443"
```
```toml tab="File (TOML)"
[http.serversTransports]
[http.serversTransports.insecureTransport]
insecureSkipVerify = true
[http.routers]
[http.routers.my-wss-e2e]
rule = "Host(`wss.example.com`)"
service = "my-wss-service"
[http.routers.my-wss-e2e.tls]
[http.services]
[http.services.my-wss-service]
[http.services.my-wss-service.loadBalancer]
serversTransport = "insecureTransport"
[[http.services.my-wss-service.loadBalancer.servers]]
url = "https://my-wss-server:8443"
```
## EntryPoints Configuration for WebSockets
In your Traefik static configuration, you'll need to define entryPoints for both WS and WSS:
```yaml tab="File (YAML)"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
```
```toml tab="File (TOML)"
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
```
## Testing WebSocket Connections
You can test your WebSocket configuration using various tools:
1. Browser Developer Tools: Most modern browsers include WebSocket debugging in their developer tools.
2. WebSocket client tools like [wscat](https://github.com/websockets/wscat) or online tools like [Piesocket's WebSocket Tester](https://www.piesocket.com/websocket-tester).
Example wscat commands:
```bash
# Test standard WebSocket
wscat -c ws://ws.example.com
# Test WebSocket Secure
wscat -c wss://wss.example.com
```
## Common Issues and Solutions
### Headers and Origin Checks
Some WebSocket servers implement origin checking. Traefik passes the original headers to your backend, including the `Origin` header.
If you need to manipulate headers for WebSocket connections, you can use Traefik's Headers middleware:
```yaml tab="Docker & Swarm"
labels:
- "traefik.http.middlewares.my-headers.headers.customrequestheaders.Origin=https://allowed-origin.com"
- "traefik.http.routers.my-websocket.middlewares=my-headers"
```
```yaml tab="Kubernetes"
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: my-headers
spec:
headers:
customRequestHeaders:
Origin: "https://allowed-origin.com"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: my-websocket-route
spec:
routes:
- match: Host(`ws.example.com`)
kind: Rule
middlewares:
- name: my-headers
services:
- name: my-websocket-service
port: 8000
```
### Certificate Issues with WSS
If you're experiencing certificate issues with WSS:
1. Ensure your certificates are valid and not expired
2. For testing with self-signed certificates, configure your clients to accept them
3. When using Let's Encrypt, ensure your domain is properly configured
For backends with self-signed certificates, use the `insecureSkipVerify` option in the ServersTransport configuration as shown in the examples above.

View File

@ -171,6 +171,7 @@ nav:
- 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md' - 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
- 'Kubernetes and cert-manager': 'user-guides/cert-manager.md' - 'Kubernetes and cert-manager': 'user-guides/cert-manager.md'
- 'gRPC Examples': 'user-guides/grpc.md' - 'gRPC Examples': 'user-guides/grpc.md'
- 'WebSocket Examples': 'user-guides/websocket.md'
- 'Docker': - 'Docker':
- 'Basic Example': 'user-guides/docker-compose/basic-example/index.md' - 'Basic Example': 'user-guides/docker-compose/basic-example/index.md'
- 'HTTPS with Let''s Encrypt': - 'HTTPS with Let''s Encrypt':

4
go.mod
View File

@ -1,6 +1,6 @@
module github.com/traefik/traefik/v3 module github.com/traefik/traefik/v3
go 1.23.0 go 1.24.0
require ( require (
github.com/BurntSushi/toml v1.5.0 github.com/BurntSushi/toml v1.5.0
@ -391,7 +391,7 @@ require (
// Containous forks // Containous forks
replace ( replace (
github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e github.com/abbot/go-http-auth => github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e
github.com/gorilla/mux => github.com/containous/mux v0.0.0-20220627093034-b2dd784e613f github.com/gorilla/mux => github.com/containous/mux v0.0.0-20250523120546-41b6ec3aed59
github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 github.com/mailgun/minheap => github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595
) )

4
go.sum
View File

@ -253,8 +253,8 @@ github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e h1:D+uTE
github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e/go.mod h1:s8kLgBQolDbsJOPVIGCEEv9zGAKUUf/685Gi0Qqg8z8= github.com/containous/go-http-auth v0.4.1-0.20200324110947-a37a7636d23e/go.mod h1:s8kLgBQolDbsJOPVIGCEEv9zGAKUUf/685Gi0Qqg8z8=
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 h1:aPspFRO6b94To3gl4yTDOEtpjFwXI7V2W+z0JcNljQ4= github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595 h1:aPspFRO6b94To3gl4yTDOEtpjFwXI7V2W+z0JcNljQ4=
github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595/go.mod h1:+lHFbEasIiQVGzhVDVw/cn0ZaOzde2OwNncp1NhXV4c= github.com/containous/minheap v0.0.0-20190809180810-6e71eb837595/go.mod h1:+lHFbEasIiQVGzhVDVw/cn0ZaOzde2OwNncp1NhXV4c=
github.com/containous/mux v0.0.0-20220627093034-b2dd784e613f h1:1uEtynq2C0ljy3630jt7EAxg8jZY2gy6YHdGwdqEpWw= github.com/containous/mux v0.0.0-20250523120546-41b6ec3aed59 h1:lJUOWjGohYjLKEfAz2nyI/dpzfKNPQLi5GLH7aaOZkw=
github.com/containous/mux v0.0.0-20220627093034-b2dd784e613f/go.mod h1:z8WW7n06n8/1xF9Jl9WmuDeZuHAhfL+bwarNjsciwwg= github.com/containous/mux v0.0.0-20250523120546-41b6ec3aed59/go.mod h1:z8WW7n06n8/1xF9Jl9WmuDeZuHAhfL+bwarNjsciwwg=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=

View File

@ -2,7 +2,6 @@ package integration
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
@ -43,7 +42,7 @@ func (s *ConsulSuite) SetupSuite() {
s.consulURL = fmt.Sprintf("http://%s", consulAddr) s.consulURL = fmt.Sprintf("http://%s", consulAddr)
kv, err := valkeyrie.NewStore( kv, err := valkeyrie.NewStore(
context.Background(), s.T().Context(),
consul.StoreName, consul.StoreName,
[]string{consulAddr}, []string{consulAddr},
&consul.Config{ &consul.Config{
@ -63,7 +62,7 @@ func (s *ConsulSuite) TearDownSuite() {
} }
func (s *ConsulSuite) TearDownTest() { func (s *ConsulSuite) TearDownTest() {
err := s.kvClient.DeleteTree(context.Background(), "traefik") err := s.kvClient.DeleteTree(s.T().Context(), "traefik")
if err != nil && !errors.Is(err, store.ErrKeyNotFound) { if err != nil && !errors.Is(err, store.ErrKeyNotFound) {
require.ErrorIs(s.T(), err, store.ErrKeyNotFound) require.ErrorIs(s.T(), err, store.ErrKeyNotFound)
} }
@ -118,7 +117,7 @@ func (s *ConsulSuite) TestSimpleConfiguration() {
} }
for k, v := range data { for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil) err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
@ -178,7 +177,7 @@ func (s *ConsulSuite) TestDeleteRootKey() {
file := s.adaptFile("fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL}) file := s.adaptFile("fixtures/consul/simple.toml", struct{ ConsulAddress string }{s.consulURL})
ctx := context.Background() ctx := s.T().Context()
svcaddr := net.JoinHostPort(s.getComposeServiceIP("whoami"), "80") svcaddr := net.JoinHostPort(s.getComposeServiceIP("whoami"), "80")
data := map[string]string{ data := map[string]string{

View File

@ -2,7 +2,6 @@ package integration
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"net" "net"
"net/http" "net/http"
@ -41,7 +40,7 @@ func (s *EtcdSuite) SetupSuite() {
var err error var err error
s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP("etcd"), "2379") s.etcdAddr = net.JoinHostPort(s.getComposeServiceIP("etcd"), "2379")
s.kvClient, err = valkeyrie.NewStore( s.kvClient, err = valkeyrie.NewStore(
context.Background(), s.T().Context(),
etcdv3.StoreName, etcdv3.StoreName,
[]string{s.etcdAddr}, []string{s.etcdAddr},
&etcdv3.Config{ &etcdv3.Config{
@ -108,7 +107,7 @@ func (s *EtcdSuite) TestSimpleConfiguration() {
} }
for k, v := range data { for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil) err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }

View File

@ -0,0 +1,28 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[serversTransport]
insecureSkipVerify=true
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.web.http2]
maxConcurrentStreams = 42
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[tls.stores]
[tls.stores.default.defaultCertificate]
certFile = "resources/tls/local.cert"
keyFile = "resources/tls/local.key"

View File

@ -2291,7 +2291,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-
@ -2436,7 +2436,7 @@ spec:
type: object type: object
x-kubernetes-validations: x-kubernetes-validations:
- message: RootCA cannot have both Secret and ConfigMap defined. - message: RootCA cannot have both Secret and ConfigMap defined.
rule: has(self.secret) && has(self.configMap) rule: '!has(self.secret) || !has(self.configMap)'
type: array type: array
rootCAsSecrets: rootCAsSecrets:
description: |- description: |-

View File

@ -19,6 +19,9 @@
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"
[core]
defaultRuleSyntax = "{{ .DefaultRuleSyntax }}"
# dynamic configuration # dynamic configuration
[http.routers] [http.routers]
[http.routers.without] [http.routers.without]

View File

@ -108,7 +108,9 @@ func getHelloClientGRPCh2c() (helloworld.GreeterClient, func() error, error) {
return helloworld.NewGreeterClient(conn), conn.Close, nil return helloworld.NewGreeterClient(conn), conn.Close, nil
} }
func callHelloClientGRPC(name string, secure bool) (string, error) { func callHelloClientGRPC(t *testing.T, name string, secure bool) (string, error) {
t.Helper()
var client helloworld.GreeterClient var client helloworld.GreeterClient
var closer func() error var closer func() error
var err error var err error
@ -123,24 +125,26 @@ func callHelloClientGRPC(name string, secure bool) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
r, err := client.SayHello(context.Background(), &helloworld.HelloRequest{Name: name}) r, err := client.SayHello(t.Context(), &helloworld.HelloRequest{Name: name})
if err != nil { if err != nil {
return "", err return "", err
} }
return r.GetMessage(), nil return r.GetMessage(), nil
} }
func callStreamExampleClientGRPC() (helloworld.Greeter_StreamExampleClient, func() error, error) { func callStreamExampleClientGRPC(t *testing.T) (helloworld.Greeter_StreamExampleClient, func() error, error) {
t.Helper()
client, closer, err := getHelloClientGRPC() client, closer, err := getHelloClientGRPC()
if err != nil { if err != nil {
return nil, closer, err return nil, closer, err
} }
t, err := client.StreamExample(context.Background(), &helloworld.StreamExampleRequest{}) s, err := client.StreamExample(t.Context(), &helloworld.StreamExampleRequest{})
if err != nil { if err != nil {
return nil, closer, err return nil, closer, err
} }
return t, closer, nil return s, closer, nil
} }
func (s *GRPCSuite) TestGRPC() { func (s *GRPCSuite) TestGRPC() {
@ -172,7 +176,7 @@ func (s *GRPCSuite) TestGRPC() {
var response string var response string
err = try.Do(1*time.Second, func() error { err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true) response, err = callHelloClientGRPC(s.T(), "World", true)
return err return err
}) })
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
@ -204,7 +208,7 @@ func (s *GRPCSuite) TestGRPCh2c() {
var response string var response string
err = try.Do(1*time.Second, func() error { err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", false) response, err = callHelloClientGRPC(s.T(), "World", false)
return err return err
}) })
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
@ -240,7 +244,7 @@ func (s *GRPCSuite) TestGRPCh2cTermination() {
var response string var response string
err = try.Do(1*time.Second, func() error { err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true) response, err = callHelloClientGRPC(s.T(), "World", true)
return err return err
}) })
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
@ -276,7 +280,7 @@ func (s *GRPCSuite) TestGRPCInsecure() {
var response string var response string
err = try.Do(1*time.Second, func() error { err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true) response, err = callHelloClientGRPC(s.T(), "World", true)
return err return err
}) })
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
@ -314,7 +318,7 @@ func (s *GRPCSuite) TestGRPCBuffer() {
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)")) err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`127.0.0.1`)"))
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
var client helloworld.Greeter_StreamExampleClient var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC() client, closer, err := callStreamExampleClientGRPC(s.T())
defer func() { _ = closer() }() defer func() { _ = closer() }()
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
@ -367,7 +371,7 @@ func (s *GRPCSuite) TestGRPCBufferWithFlushInterval() {
assert.NoError(s.T(), err) assert.NoError(s.T(), err)
var client helloworld.Greeter_StreamExampleClient var client helloworld.Greeter_StreamExampleClient
client, closer, err := callStreamExampleClientGRPC() client, closer, err := callStreamExampleClientGRPC(s.T())
defer func() { defer func() {
_ = closer() _ = closer()
stopStreamExample <- true stopStreamExample <- true
@ -422,7 +426,7 @@ func (s *GRPCSuite) TestGRPCWithRetry() {
var response string var response string
err = try.Do(1*time.Second, func() error { err = try.Do(1*time.Second, func() error {
response, err = callHelloClientGRPC("World", true) response, err = callHelloClientGRPC(s.T(), "World", true)
return err return err
}) })
assert.NoError(s.T(), err) assert.NoError(s.T(), err)

View File

@ -3,6 +3,7 @@ package integration
import ( import (
"bytes" "bytes"
"crypto/tls" "crypto/tls"
"crypto/x509"
"fmt" "fmt"
"net" "net"
"net/http" "net/http"
@ -19,6 +20,7 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/traefik/traefik/v3/pkg/config/dynamic"
traefiktls "github.com/traefik/traefik/v3/pkg/tls" traefiktls "github.com/traefik/traefik/v3/pkg/tls"
"github.com/traefik/traefik/v3/pkg/types" "github.com/traefik/traefik/v3/pkg/types"
"golang.org/x/net/http2"
) )
// HTTPSSuite tests suite. // HTTPSSuite tests suite.
@ -1174,3 +1176,38 @@ func (s *HTTPSSuite) TestWithInvalidTLSOption() {
assert.Nil(s.T(), conn) assert.Nil(s.T(), conn)
} }
} }
func (s *SimpleSuite) TestMaxConcurrentStream() {
file := s.adaptFile("fixtures/https/max_concurrent_stream.toml", struct{}{})
s.traefikCmd(withConfigFile(file), "--log.level=DEBUG", "--accesslog")
// Wait for traefik.
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", time.Second, try.BodyContains("api@internal"))
require.NoError(s.T(), err)
// Add client self-signed cert.
roots := x509.NewCertPool()
certContent, err := os.ReadFile("./resources/tls/local.cert")
require.NoError(s.T(), err)
roots.AppendCertsFromPEM(certContent)
// Open a connection to inspect SettingsFrame.
conn, err := tls.Dial("tcp", "127.0.0.1:8000", &tls.Config{
RootCAs: roots,
NextProtos: []string{"h2"},
})
require.NoError(s.T(), err)
framer := http2.NewFramer(nil, conn)
frame, err := framer.ReadFrame()
require.NoError(s.T(), err)
fr, ok := frame.(*http2.SettingsFrame)
require.True(s.T(), ok)
maxConcurrentStream, ok := fr.Value(http2.SettingMaxConcurrentStreams)
assert.True(s.T(), ok)
assert.Equal(s.T(), uint32(42), maxConcurrentStream)
}

View File

@ -106,7 +106,7 @@ func (s *BaseSuite) displayTraefikLogFile(path string) {
} }
func (s *BaseSuite) SetupSuite() { func (s *BaseSuite) SetupSuite() {
if isDockerDesktop(context.Background(), s.T()) { if isDockerDesktop(s.T()) {
_, err := os.Stat(tailscaleSecretFilePath) _, err := os.Stat(tailscaleSecretFilePath)
require.NoError(s.T(), err, "Tailscale need to be configured when running integration tests with Docker Desktop: (https://doc.traefik.io/traefik/v2.11/contributing/building-testing/#testing)") require.NoError(s.T(), err, "Tailscale need to be configured when running integration tests with Docker Desktop: (https://doc.traefik.io/traefik/v2.11/contributing/building-testing/#testing)")
} }
@ -116,7 +116,6 @@ func (s *BaseSuite) SetupSuite() {
// TODO // TODO
// stdlog.SetOutput(log.Logger) // stdlog.SetOutput(log.Logger)
ctx := context.Background()
// Create docker network // Create docker network
// docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24 // docker network create traefik-test-network --driver bridge --subnet 172.31.42.0/24
var opts []network.NetworkCustomizer var opts []network.NetworkCustomizer
@ -129,18 +128,18 @@ func (s *BaseSuite) SetupSuite() {
}, },
}, },
})) }))
dockerNetwork, err := network.New(ctx, opts...) dockerNetwork, err := network.New(s.T().Context(), opts...)
require.NoError(s.T(), err) require.NoError(s.T(), err)
s.network = dockerNetwork s.network = dockerNetwork
s.hostIP = "172.31.42.1" s.hostIP = "172.31.42.1"
if isDockerDesktop(ctx, s.T()) { if isDockerDesktop(s.T()) {
s.hostIP = getDockerDesktopHostIP(ctx, s.T()) s.hostIP = getDockerDesktopHostIP(s.T())
s.setupVPN(tailscaleSecretFilePath) s.setupVPN(tailscaleSecretFilePath)
} }
} }
func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string { func getDockerDesktopHostIP(t *testing.T) string {
t.Helper() t.Helper()
req := testcontainers.ContainerRequest{ req := testcontainers.ContainerRequest{
@ -151,13 +150,13 @@ func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
Cmd: []string{"getent", "hosts", "host.docker.internal"}, Cmd: []string{"getent", "hosts", "host.docker.internal"},
} }
con, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ con, err := testcontainers.GenericContainer(t.Context(), testcontainers.GenericContainerRequest{
ContainerRequest: req, ContainerRequest: req,
Started: true, Started: true,
}) })
require.NoError(t, err) require.NoError(t, err)
closer, err := con.Logs(ctx) closer, err := con.Logs(t.Context())
require.NoError(t, err) require.NoError(t, err)
all, err := io.ReadAll(closer) all, err := io.ReadAll(closer)
@ -170,15 +169,15 @@ func getDockerDesktopHostIP(ctx context.Context, t *testing.T) string {
return matches[0] return matches[0]
} }
func isDockerDesktop(ctx context.Context, t *testing.T) bool { func isDockerDesktop(t *testing.T) bool {
t.Helper() t.Helper()
cli, err := testcontainers.NewDockerClientWithOpts(ctx) cli, err := testcontainers.NewDockerClientWithOpts(t.Context())
if err != nil { if err != nil {
t.Fatalf("failed to create docker client: %s", err) t.Fatalf("failed to create docker client: %s", err)
} }
info, err := cli.Info(ctx) info, err := cli.Info(t.Context())
if err != nil { if err != nil {
t.Fatalf("failed to get docker info: %s", err) t.Fatalf("failed to get docker info: %s", err)
} }
@ -191,7 +190,7 @@ func (s *BaseSuite) TearDownSuite() {
err := try.Do(5*time.Second, func() error { err := try.Do(5*time.Second, func() error {
if s.network != nil { if s.network != nil {
err := s.network.Remove(context.Background()) err := s.network.Remove(s.T().Context())
if err != nil { if err != nil {
return err return err
} }
@ -218,7 +217,7 @@ func (s *BaseSuite) createComposeProject(name string) {
s.containers = map[string]testcontainers.Container{} s.containers = map[string]testcontainers.Container{}
} }
ctx := context.Background() ctx := s.T().Context()
for id, containerConfig := range composeConfigData.Services { for id, containerConfig := range composeConfigData.Services {
var mounts []mount.Mount var mounts []mount.Mount
@ -273,7 +272,7 @@ func (s *BaseSuite) createContainer(ctx context.Context, containerConfig compose
if containerConfig.CapAdd != nil { if containerConfig.CapAdd != nil {
config.CapAdd = containerConfig.CapAdd config.CapAdd = containerConfig.CapAdd
} }
if !isDockerDesktop(ctx, s.T()) { if !isDockerDesktop(s.T()) {
config.ExtraHosts = append(config.ExtraHosts, "host.docker.internal:"+s.hostIP) config.ExtraHosts = append(config.ExtraHosts, "host.docker.internal:"+s.hostIP)
} }
config.Mounts = mounts config.Mounts = mounts
@ -292,7 +291,7 @@ func (s *BaseSuite) createContainer(ctx context.Context, containerConfig compose
func (s *BaseSuite) composeUp(services ...string) { func (s *BaseSuite) composeUp(services ...string) {
for name, con := range s.containers { for name, con := range s.containers {
if len(services) == 0 || slices.Contains(services, name) { if len(services) == 0 || slices.Contains(services, name) {
err := con.Start(context.Background()) err := con.Start(s.T().Context())
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
} }
@ -303,7 +302,7 @@ func (s *BaseSuite) composeStop(services ...string) {
for name, con := range s.containers { for name, con := range s.containers {
if len(services) == 0 || slices.Contains(services, name) { if len(services) == 0 || slices.Contains(services, name) {
timeout := 10 * time.Second timeout := 10 * time.Second
err := con.Stop(context.Background(), &timeout) err := con.Stop(s.T().Context(), &timeout)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
} }
@ -312,7 +311,7 @@ func (s *BaseSuite) composeStop(services ...string) {
// composeDown stops all compose project services and removes the corresponding containers. // composeDown stops all compose project services and removes the corresponding containers.
func (s *BaseSuite) composeDown() { func (s *BaseSuite) composeDown() {
for _, c := range s.containers { for _, c := range s.containers {
err := c.Terminate(context.Background()) err := c.Terminate(s.T().Context())
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
s.containers = map[string]testcontainers.Container{} s.containers = map[string]testcontainers.Container{}
@ -383,7 +382,7 @@ func (s *BaseSuite) displayLogK3S() {
func (s *BaseSuite) displayLogCompose() { func (s *BaseSuite) displayLogCompose() {
for name, ctn := range s.containers { for name, ctn := range s.containers {
readCloser, err := ctn.Logs(context.Background()) readCloser, err := ctn.Logs(s.T().Context())
require.NoError(s.T(), err) require.NoError(s.T(), err)
for { for {
b := make([]byte, 1024) b := make([]byte, 1024)
@ -451,7 +450,7 @@ func (s *BaseSuite) getComposeServiceIP(name string) string {
if !ok { if !ok {
return "" return ""
} }
ip, err := container.ContainerIP(context.Background()) ip, err := container.ContainerIP(s.T().Context())
if err != nil { if err != nil {
return "" return ""
} }
@ -501,7 +500,7 @@ func (s *BaseSuite) setupVPN(keyFile string) {
func (s *BaseSuite) composeExec(service string, args ...string) string { func (s *BaseSuite) composeExec(service string, args ...string) string {
require.Contains(s.T(), s.containers, service) require.Contains(s.T(), s.containers, service)
_, reader, err := s.containers[service].Exec(context.Background(), args) _, reader, err := s.containers[service].Exec(s.T().Context(), args)
require.NoError(s.T(), err) require.NoError(s.T(), err)
content, err := io.ReadAll(reader) content, err := io.ReadAll(reader)

View File

@ -1,7 +1,6 @@
package integration package integration
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@ -74,7 +73,7 @@ func (s *K8sConformanceSuite) SetupSuite() {
s.T().Fatal(err) s.T().Fatal(err)
} }
ctx := context.Background() ctx := s.T().Context()
// Ensure image is available locally. // Ensure image is available locally.
images, err := provider.ListImages(ctx) images, err := provider.ListImages(ctx)
@ -146,7 +145,7 @@ func (s *K8sConformanceSuite) SetupSuite() {
} }
func (s *K8sConformanceSuite) TearDownSuite() { func (s *K8sConformanceSuite) TearDownSuite() {
ctx := context.Background() ctx := s.T().Context()
if s.T().Failed() || *showLog { if s.T().Failed() || *showLog {
k3sLogs, err := s.k3sContainer.Logs(ctx) k3sLogs, err := s.k3sContainer.Logs(ctx)
@ -173,7 +172,7 @@ func (s *K8sConformanceSuite) TearDownSuite() {
func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() { func (s *K8sConformanceSuite) TestK8sGatewayAPIConformance() {
// Wait for traefik to start // Wait for traefik to start
k3sContainerIP, err := s.k3sContainer.ContainerIP(context.Background()) k3sContainerIP, err := s.k3sContainer.ContainerIP(s.T().Context())
require.NoError(s.T(), err) require.NoError(s.T(), err)
err = try.GetRequest("http://"+k3sContainerIP+":9000/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`)) err = try.GetRequest("http://"+k3sContainerIP+":9000/api/entrypoints", 10*time.Second, try.BodyContains(`"name":"web"`))

View File

@ -2,7 +2,6 @@ package integration
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net" "net"
@ -51,7 +50,7 @@ func (s *RedisSentinelSuite) SetupSuite() {
net.JoinHostPort(s.getComposeServiceIP("sentinel3"), "26379"), net.JoinHostPort(s.getComposeServiceIP("sentinel3"), "26379"),
} }
kv, err := valkeyrie.NewStore( kv, err := valkeyrie.NewStore(
context.Background(), s.T().Context(),
redis.StoreName, redis.StoreName,
s.redisEndpoints, s.redisEndpoints,
&redis.Config{ &redis.Config{
@ -157,7 +156,7 @@ func (s *RedisSentinelSuite) TestSentinelConfiguration() {
} }
for k, v := range data { for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil) err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }

View File

@ -2,7 +2,6 @@ package integration
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"net" "net"
"net/http" "net/http"
@ -43,7 +42,7 @@ func (s *RedisSuite) SetupSuite() {
s.redisEndpoints = append(s.redisEndpoints, net.JoinHostPort(s.getComposeServiceIP("redis"), "6379")) s.redisEndpoints = append(s.redisEndpoints, net.JoinHostPort(s.getComposeServiceIP("redis"), "6379"))
kv, err := valkeyrie.NewStore( kv, err := valkeyrie.NewStore(
context.Background(), s.T().Context(),
redis.StoreName, redis.StoreName,
s.redisEndpoints, s.redisEndpoints,
&redis.Config{}, &redis.Config{},
@ -112,7 +111,7 @@ func (s *RedisSuite) TestSimpleConfiguration() {
} }
for k, v := range data { for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil) err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
server0: server0:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
noOverrideAllowlist: noOverrideAllowlist:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
consul: consul:
image: consul:1.6 image: consul:1.6

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
consul: consul:
image: consul:1.6.2 image: consul:1.6.2

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
simple: simple:
image: swarm:1.0.0 image: swarm:1.0.0

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
nginx1: nginx1:
image: nginx:1.25.3-alpine3.18 image: nginx:1.25.3-alpine3.18

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
etcd: etcd:
image: quay.io/coreos/etcd:v3.5.14 image: quay.io/coreos/etcd:v3.5.14

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
server1: server1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
server: server:
image: rancher/k3s:v1.21.14-k3s1 image: rancher/k3s:v1.21.14-k3s1

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
pebble: pebble:
image: letsencrypt/pebble:v2.3.1 image: letsencrypt/pebble:v2.3.1

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami: whoami:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
redis: redis:
image: redis:5.0 image: redis:5.0

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
master: master:
image: redis image: redis

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami: whoami:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami: whoami:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami1: whoami1:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
tailscaled: tailscaled:
hostname: traefik-tests-gw # This will become the tailscale device name hostname: traefik-tests-gw # This will become the tailscale device name

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami-a: whoami-a:
image: traefik/whoamitcp image: traefik/whoamitcp

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
timeoutEndpoint: timeoutEndpoint:
image: yaman/timeout image: yaman/timeout

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami: whoami:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
tempo: tempo:
hostname: tempo hostname: tempo

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
whoami-a: whoami-a:
image: traefik/whoamiudp:latest image: traefik/whoamiudp:latest

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
noOverrideWhitelist: noOverrideWhitelist:
image: traefik/whoami image: traefik/whoami

View File

@ -1,4 +1,3 @@
version: "3.8"
services: services:
zookeeper: zookeeper:
image: zookeeper:3.5 image: zookeeper:3.5

View File

@ -711,11 +711,11 @@ func (s *SimpleSuite) TestWithDefaultRuleSyntax() {
require.NoError(s.T(), err) require.NoError(s.T(), err)
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2) // router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp")) err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
require.NoError(s.T(), err) require.NoError(s.T(), err)
// router3 has an error because it uses the wrong rule syntax (v2 instead of v3) // router3 has an error because it uses the wrong rule syntax (v2 instead of v3)
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]")) err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
@ -741,11 +741,11 @@ func (s *SimpleSuite) TestWithoutDefaultRuleSyntax() {
require.NoError(s.T(), err) require.NoError(s.T(), err)
// router2 has an error because it uses the wrong rule syntax (v3 instead of v2) // router2 has an error because it uses the wrong rule syntax (v3 instead of v2)
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("error while adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]")) err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router2@file", 1*time.Second, try.BodyContains("adding rule PathPrefix: unexpected number of parameters; got 2, expected one of [1]"))
require.NoError(s.T(), err) require.NoError(s.T(), err)
// router2 has an error because it uses the wrong rule syntax (v2 instead of v3) // router2 has an error because it uses the wrong rule syntax (v2 instead of v3)
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("error while parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp")) err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router3@file", 1*time.Second, try.BodyContains("parsing rule QueryRegexp(`foo`, `bar`): unsupported function: QueryRegexp"))
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }
@ -1606,9 +1606,10 @@ func (s *SimpleSuite) TestSanitizePath() {
whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80") whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80")
file := s.adaptFile("fixtures/simple_clean_path.toml", struct { file := s.adaptFile("fixtures/simple_sanitize_path.toml", struct {
Server1 string Server1 string
}{whoami1URL}) DefaultRuleSyntax string
}{whoami1URL, "v3"})
s.traefikCmd(withConfigFile(file)) s.traefikCmd(withConfigFile(file))
@ -1641,6 +1642,116 @@ func (s *SimpleSuite) TestSanitizePath() {
target: "127.0.0.1:8000", target: "127.0.0.1:8000",
expected: http.StatusFound, expected: http.StatusFound,
}, },
{
desc: "Implicit encoded dot dots call to the route with a middleware",
request: "GET /without/%2E%2E/with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{
desc: "Implicit with encoded unreserved character call to the route with a middleware",
request: "GET /%77ith HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{
desc: "Explicit call to the route with a middleware, and disable path sanitization",
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8001",
expected: http.StatusFound,
},
{
desc: "Explicit call to the route without a middleware, and disable path sanitization",
request: "GET /without HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8001",
expected: http.StatusOK,
body: "GET /without HTTP/1.1",
},
{
desc: "Implicit call to the route with a middleware, and disable path sanitization",
request: "GET /without/../with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8001",
// The whoami is redirecting to /with, but the path is not sanitized.
expected: http.StatusMovedPermanently,
},
}
for _, test := range testCases {
conn, err := net.Dial("tcp", test.target)
require.NoError(s.T(), err)
_, err = conn.Write([]byte(test.request))
require.NoError(s.T(), err)
resp, err := http.ReadResponse(bufio.NewReader(conn), nil)
require.NoError(s.T(), err)
assert.Equalf(s.T(), test.expected, resp.StatusCode, "%s failed with %d instead of %d", test.desc, resp.StatusCode, test.expected)
if test.body != "" {
body, err := io.ReadAll(resp.Body)
require.NoError(s.T(), err)
assert.Contains(s.T(), string(body), test.body)
}
}
}
func (s *SimpleSuite) TestSanitizePathSyntaxV2() {
s.createComposeProject("base")
s.composeUp()
defer s.composeDown()
whoami1URL := "http://" + net.JoinHostPort(s.getComposeServiceIP("whoami1"), "80")
file := s.adaptFile("fixtures/simple_sanitize_path.toml", struct {
Server1 string
DefaultRuleSyntax string
}{whoami1URL, "v2"})
s.traefikCmd(withConfigFile(file))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix(`/with`)"))
require.NoError(s.T(), err)
testCases := []struct {
desc string
request string
target string
body string
expected int
}{
{
desc: "Explicit call to the route with a middleware",
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{
desc: "Explicit call to the route without a middleware",
request: "GET /without HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusOK,
body: "GET /without HTTP/1.1",
},
{
desc: "Implicit call to the route with a middleware",
request: "GET /without/../with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{
desc: "Implicit encoded dot dots call to the route with a middleware",
request: "GET /without/%2E%2E/with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{
desc: "Implicit with encoded unreserved character call to the route with a middleware",
request: "GET /%77ith HTTP/1.1\r\nHost: other.localhost\r\n\r\n",
target: "127.0.0.1:8000",
expected: http.StatusFound,
},
{ {
desc: "Explicit call to the route with a middleware, and disable path sanitization", desc: "Explicit call to the route with a middleware, and disable path sanitization",
request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n", request: "GET /with HTTP/1.1\r\nHost: other.localhost\r\n\r\n",

View File

@ -2,7 +2,6 @@ package integration
import ( import (
"bytes" "bytes"
"context"
"encoding/json" "encoding/json"
"net" "net"
"net/http" "net/http"
@ -43,7 +42,7 @@ func (s *ZookeeperSuite) SetupSuite() {
var err error var err error
s.kvClient, err = valkeyrie.NewStore( s.kvClient, err = valkeyrie.NewStore(
context.Background(), s.T().Context(),
zookeeper.StoreName, zookeeper.StoreName,
[]string{s.zookeeperAddr}, []string{s.zookeeperAddr},
&zookeeper.Config{ &zookeeper.Config{
@ -110,7 +109,7 @@ func (s *ZookeeperSuite) TestSimpleConfiguration() {
} }
for k, v := range data { for k, v := range data {
err := s.kvClient.Put(context.Background(), k, []byte(v), nil) err := s.kvClient.Put(s.T().Context(), k, []byte(v), nil)
require.NoError(s.T(), err) require.NoError(s.T(), err)
} }

View File

@ -0,0 +1,64 @@
package main
import (
"encoding/json"
"fmt"
"os"
"strings"
"github.com/rs/zerolog/log"
"golang.org/x/tools/go/packages"
)
const groupCount = 12
type group struct {
Group string `json:"group"`
}
func main() {
cfg := &packages.Config{
Mode: packages.NeedName,
Dir: ".",
}
pkgs, err := packages.Load(cfg, "./cmd/...", "./pkg/...")
if err != nil {
log.Fatal().Err(err).Msg("Loading packages")
}
var packageNames []string
for _, pkg := range pkgs {
if pkg.PkgPath != "" {
packageNames = append(packageNames, pkg.PkgPath)
}
}
total := len(packageNames)
perGroup := (total + groupCount - 1) / groupCount
fmt.Fprintf(os.Stderr, "Total packages: %d\n", total)
fmt.Fprintf(os.Stderr, "Packages per group: %d\n", perGroup)
var matrix []group
for i := range groupCount {
start := i * perGroup
end := start + perGroup
if start >= total {
break
}
if end > total {
end = total
}
g := strings.Join(packageNames[start:end], " ")
matrix = append(matrix, group{Group: g})
}
jsonBytes, err := json.Marshal(matrix)
if err != nil {
log.Fatal().Err(err).Msg("Failed to marshal matrix")
}
// Output for GitHub Actions
fmt.Printf("matrix=%s\n", string(jsonBytes))
}

View File

@ -1,7 +1,6 @@
package api package api
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -1004,8 +1003,8 @@ func TestHandler_HTTP(t *testing.T) {
rtConf := &test.conf rtConf := &test.conf
// To lazily initialize the Statuses. // To lazily initialize the Statuses.
rtConf.PopulateUsedBy() rtConf.PopulateUsedBy()
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, false) rtConf.GetRoutersByEntryPoints(t.Context(), []string{"web"}, false)
rtConf.GetRoutersByEntryPoints(context.Background(), []string{"web"}, true) rtConf.GetRoutersByEntryPoints(t.Context(), []string{"web"}, true)
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf) handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
server := httptest.NewServer(handler.createRouter()) server := httptest.NewServer(handler.createRouter())

View File

@ -1,7 +1,6 @@
package api package api
import ( import (
"context"
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
@ -880,7 +879,7 @@ func TestHandler_TCP(t *testing.T) {
rtConf := &test.conf rtConf := &test.conf
// To lazily initialize the Statuses. // To lazily initialize the Statuses.
rtConf.PopulateUsedBy() rtConf.PopulateUsedBy()
rtConf.GetTCPRoutersByEntryPoints(context.Background(), []string{"web"}) rtConf.GetTCPRoutersByEntryPoints(t.Context(), []string{"web"})
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf) handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
server := httptest.NewServer(handler.createRouter()) server := httptest.NewServer(handler.createRouter())

View File

@ -1,7 +1,6 @@
package api package api
import ( import (
"context"
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
@ -570,7 +569,7 @@ func TestHandler_UDP(t *testing.T) {
rtConf := &test.conf rtConf := &test.conf
// To lazily initialize the Statuses. // To lazily initialize the Statuses.
rtConf.PopulateUsedBy() rtConf.PopulateUsedBy()
rtConf.GetUDPRoutersByEntryPoints(context.Background(), []string{"web"}) rtConf.GetUDPRoutersByEntryPoints(t.Context(), []string{"web"})
handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf) handler := New(static.Configuration{API: &static.API{}, Global: &static.Global{}}, rtConf)
server := httptest.NewServer(handler.createRouter()) server := httptest.NewServer(handler.createRouter())

View File

@ -1,7 +1,6 @@
package runtime package runtime
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -211,7 +210,7 @@ func TestGetRoutersByEntryPoints(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
runtimeConfig := NewConfig(test.conf) runtimeConfig := NewConfig(test.conf)
actual := runtimeConfig.GetRoutersByEntryPoints(context.Background(), test.entryPoints, false) actual := runtimeConfig.GetRoutersByEntryPoints(t.Context(), test.entryPoints, false)
assert.Equal(t, test.expected, actual) assert.Equal(t, test.expected, actual)
}) })
} }

View File

@ -1,7 +1,6 @@
package runtime package runtime
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -211,7 +210,7 @@ func TestGetTCPRoutersByEntryPoints(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
runtimeConfig := NewConfig(test.conf) runtimeConfig := NewConfig(test.conf)
actual := runtimeConfig.GetTCPRoutersByEntryPoints(context.Background(), test.entryPoints) actual := runtimeConfig.GetTCPRoutersByEntryPoints(t.Context(), test.entryPoints)
assert.Equal(t, test.expected, actual) assert.Equal(t, test.expected, actual)
}) })
} }

View File

@ -1,7 +1,6 @@
package runtime package runtime
import ( import (
"context"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -192,7 +191,7 @@ func TestGetUDPRoutersByEntryPoints(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
runtimeConfig := NewConfig(test.conf) runtimeConfig := NewConfig(test.conf)
actual := runtimeConfig.GetUDPRoutersByEntryPoints(context.Background(), test.entryPoints) actual := runtimeConfig.GetUDPRoutersByEntryPoints(t.Context(), test.entryPoints)
assert.Equal(t, test.expected, actual) assert.Equal(t, test.expected, actual)
}) })
} }

View File

@ -66,7 +66,7 @@ func TestNewServiceHealthChecker_durations(t *testing.T) {
for _, test := range testCases { for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
healthChecker := NewServiceHealthChecker(context.Background(), nil, test.config, nil, nil, http.DefaultTransport, nil, "") healthChecker := NewServiceHealthChecker(t.Context(), nil, test.config, nil, nil, http.DefaultTransport, nil, "")
assert.Equal(t, test.expInterval, healthChecker.interval) assert.Equal(t, test.expInterval, healthChecker.interval)
assert.Equal(t, test.expTimeout, healthChecker.timeout) assert.Equal(t, test.expTimeout, healthChecker.timeout)
}) })
@ -251,7 +251,7 @@ func TestServiceHealthChecker_newRequest(t *testing.T) {
shc := ServiceHealthChecker{config: &test.config} shc := ServiceHealthChecker{config: &test.config}
u := testhelpers.MustParseURL(test.targetURL) u := testhelpers.MustParseURL(test.targetURL)
req, err := shc.newRequest(context.Background(), u) req, err := shc.newRequest(t.Context(), u)
if test.expError { if test.expError {
require.Error(t, err) require.Error(t, err)
@ -276,7 +276,7 @@ func TestServiceHealthChecker_checkHealthHTTP_NotFollowingRedirects(t *testing.T
})) }))
defer redirectTestServer.Close() defer redirectTestServer.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(dynamic.DefaultHealthCheckTimeout)) ctx, cancel := context.WithTimeout(t.Context(), time.Duration(dynamic.DefaultHealthCheckTimeout))
defer cancel() defer cancel()
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -411,7 +411,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
// The context is passed to the health check and // The context is passed to the health check and
// canonically canceled by the test server once all expected requests have been received. // canonically canceled by the test server once all expected requests have been received.
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
t.Cleanup(cancel) t.Cleanup(cancel)
targetURL, timeout := test.server.Start(t, cancel) targetURL, timeout := test.server.Start(t, cancel)
@ -461,7 +461,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
func TestDifferentIntervals(t *testing.T) { func TestDifferentIntervals(t *testing.T) {
// The context is passed to the health check and // The context is passed to the health check and
// canonically canceled by the test server once all expected requests have been received. // canonically canceled by the test server once all expected requests have been received.
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(t.Context())
t.Cleanup(cancel) t.Cleanup(cancel)
healthyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { healthyServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {

View File

@ -2,7 +2,6 @@ package logs
import ( import (
"compress/gzip" "compress/gzip"
"context"
"encoding/json" "encoding/json"
"io" "io"
"net/http" "net/http"
@ -175,7 +174,7 @@ func TestLog(t *testing.T) {
logger, err := SetupOTelLogger(logger, config) logger, err := SetupOTelLogger(logger, config)
require.NoError(t, err) require.NoError(t, err)
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
})) }))

View File

@ -1,7 +1,6 @@
package metrics package metrics
import ( import (
"context"
"net/http" "net/http"
"strconv" "strconv"
"testing" "testing"
@ -20,7 +19,7 @@ func TestDatadog(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true}) datadogRegistry := RegisterDatadog(t.Context(), &types.Datadog{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() { if !datadogRegistry.IsEpEnabled() || !datadogRegistry.IsRouterEnabled() || !datadogRegistry.IsSvcEnabled() {
t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()") t.Errorf("DatadogRegistry should return true for IsEnabled(), IsRouterEnabled() and IsSvcEnabled()")
@ -35,7 +34,7 @@ func TestDatadogWithPrefix(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
datadogRegistry := RegisterDatadog(context.Background(), &types.Datadog{Prefix: "testPrefix", Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true}) datadogRegistry := RegisterDatadog(t.Context(), &types.Datadog{Prefix: "testPrefix", Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
testDatadogRegistry(t, "testPrefix", datadogRegistry) testDatadogRegistry(t, "testPrefix", datadogRegistry)
} }

View File

@ -1,7 +1,6 @@
package metrics package metrics
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -26,7 +25,7 @@ func TestInfluxDB2(t *testing.T) {
_, _ = fmt.Fprintln(w, "ok") _, _ = fmt.Fprintln(w, "ok")
})) }))
influxDB2Registry := RegisterInfluxDB2(context.Background(), influxDB2Registry := RegisterInfluxDB2(t.Context(),
&types.InfluxDB2{ &types.InfluxDB2{
Address: ts.URL, Address: ts.URL,
Token: "test-token", Token: "test-token",

View File

@ -2,7 +2,6 @@ package metrics
import ( import (
"compress/gzip" "compress/gzip"
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@ -338,7 +337,7 @@ func TestOpenTelemetry(t *testing.T) {
wantServiceName = test.serviceName wantServiceName = test.serviceName
} }
registry := RegisterOpenTelemetry(context.Background(), &cfg) registry := RegisterOpenTelemetry(t.Context(), &cfg)
require.NotNil(t, registry) require.NotNil(t, registry)
if !registry.IsEpEnabled() || !registry.IsRouterEnabled() || !registry.IsSvcEnabled() { if !registry.IsEpEnabled() || !registry.IsRouterEnabled() || !registry.IsSvcEnabled() {

View File

@ -1,7 +1,6 @@
package metrics package metrics
import ( import (
"context"
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
@ -70,7 +69,7 @@ func TestRegisterPromState(t *testing.T) {
if test.initPromState { if test.initPromState {
initStandardRegistry(prom) initStandardRegistry(prom)
} }
if registerPromState(context.Background()) { if registerPromState(t.Context()) {
actualNbRegistries++ actualNbRegistries++
} }
if test.unregisterPromState { if test.unregisterPromState {
@ -91,7 +90,7 @@ func TestPrometheus(t *testing.T) {
promRegistry = prometheus.NewRegistry() promRegistry = prometheus.NewRegistry()
t.Cleanup(promState.reset) t.Cleanup(promState.reset)
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{ prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{
AddEntryPointsLabels: true, AddEntryPointsLabels: true,
AddRoutersLabels: true, AddRoutersLabels: true,
AddServicesLabels: true, AddServicesLabels: true,
@ -405,7 +404,7 @@ func TestPrometheusMetricRemoval(t *testing.T) {
promRegistry = prometheus.NewRegistry() promRegistry = prometheus.NewRegistry()
t.Cleanup(promState.reset) t.Cleanup(promState.reset)
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true, AddRoutersLabels: true}) prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true, AddRoutersLabels: true})
defer promRegistry.Unregister(promState) defer promRegistry.Unregister(promState)
conf1 := dynamic.Configuration{ conf1 := dynamic.Configuration{
@ -496,7 +495,7 @@ func TestPrometheusMetricRemoveEndpointForRecoveredService(t *testing.T) {
promRegistry = prometheus.NewRegistry() promRegistry = prometheus.NewRegistry()
t.Cleanup(promState.reset) t.Cleanup(promState.reset)
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddServicesLabels: true}) prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddServicesLabels: true})
defer promRegistry.Unregister(promState) defer promRegistry.Unregister(promState)
conf1 := dynamic.Configuration{ conf1 := dynamic.Configuration{
@ -535,7 +534,7 @@ func TestPrometheusMetricRemoveEndpointForRecoveredService(t *testing.T) {
func TestPrometheusRemovedMetricsReset(t *testing.T) { func TestPrometheusRemovedMetricsReset(t *testing.T) {
t.Cleanup(promState.reset) t.Cleanup(promState.reset)
prometheusRegistry := RegisterPrometheus(context.Background(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true}) prometheusRegistry := RegisterPrometheus(t.Context(), &types.Prometheus{AddEntryPointsLabels: true, AddServicesLabels: true})
defer promRegistry.Unregister(promState) defer promRegistry.Unregister(promState)
conf1 := dynamic.Configuration{ conf1 := dynamic.Configuration{

View File

@ -1,7 +1,6 @@
package metrics package metrics
import ( import (
"context"
"net/http" "net/http"
"strconv" "strconv"
"testing" "testing"
@ -21,7 +20,7 @@ func TestStatsD(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true}) statsdRegistry := RegisterStatsd(t.Context(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true})
testRegistry(t, defaultMetricsPrefix, statsdRegistry) testRegistry(t, defaultMetricsPrefix, statsdRegistry)
} }
@ -35,7 +34,7 @@ func TestStatsDWithPrefix(t *testing.T) {
// This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond // This is needed to make sure that UDP Listener listens for data a bit longer, otherwise it will quit after a millisecond
udp.Timeout = 5 * time.Second udp.Timeout = 5 * time.Second
statsdRegistry := RegisterStatsd(context.Background(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true, Prefix: "testPrefix"}) statsdRegistry := RegisterStatsd(t.Context(), &types.Statsd{Address: ":18125", PushInterval: ptypes.Duration(time.Second), AddEntryPointsLabels: true, AddRoutersLabels: true, AddServicesLabels: true, Prefix: "testPrefix"})
testRegistry(t, "testPrefix", statsdRegistry) testRegistry(t, "testPrefix", statsdRegistry)
} }

View File

@ -97,7 +97,7 @@ func TestOTelAccessLog(t *testing.T) {
Path: testPath, Path: testPath,
}, },
} }
ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ ctx := trace.ContextWithSpanContext(t.Context(), trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, TraceID: trace.TraceID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}, SpanID: trace.SpanID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8},
})) }))
@ -1055,7 +1055,7 @@ func doLoggingWithAbortedStream(t *testing.T, config *types.AccessLog) {
require.NoError(t, err, "logger should create "+config.FilePath) require.NoError(t, err, "logger should create "+config.FilePath)
} }
reqContext, cancelRequest := context.WithCancel(context.Background()) reqContext, cancelRequest := context.WithCancel(t.Context())
req := &http.Request{ req := &http.Request{
Header: map[string][]string{ Header: map[string][]string{

View File

@ -1,7 +1,6 @@
package addprefix package addprefix
import ( import (
"context"
"net/http" "net/http"
"testing" "testing"
@ -34,7 +33,7 @@ func TestNewAddPrefix(t *testing.T) {
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}) next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
_, err := New(context.Background(), next, test.prefix, "foo-add-prefix") _, err := New(t.Context(), next, test.prefix, "foo-add-prefix")
if test.expectsError { if test.expectsError {
assert.Error(t, err) assert.Error(t, err)
} else { } else {
@ -87,7 +86,7 @@ func TestAddPrefix(t *testing.T) {
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil) req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost"+test.path, nil)
handler, err := New(context.Background(), next, test.prefix, "foo-add-prefix") handler, err := New(t.Context(), next, test.prefix, "foo-add-prefix")
require.NoError(t, err) require.NoError(t, err)
handler.ServeHTTP(nil, req) handler.ServeHTTP(nil, req)

View File

@ -1,7 +1,6 @@
package auth package auth
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -25,13 +24,13 @@ func TestBasicAuthFail(t *testing.T) {
auth := dynamic.BasicAuth{ auth := dynamic.BasicAuth{
Users: []string{"test"}, Users: []string{"test"},
} }
_, err := NewBasic(context.Background(), next, auth, "authName") _, err := NewBasic(t.Context(), next, auth, "authName")
require.Error(t, err) require.Error(t, err)
auth2 := dynamic.BasicAuth{ auth2 := dynamic.BasicAuth{
Users: []string{"test:test"}, Users: []string{"test:test"},
} }
authMiddleware, err := NewBasic(context.Background(), next, auth2, "authTest") authMiddleware, err := NewBasic(t.Context(), next, auth2, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authMiddleware) ts := httptest.NewServer(authMiddleware)
@ -54,7 +53,7 @@ func TestBasicAuthSuccess(t *testing.T) {
auth := dynamic.BasicAuth{ auth := dynamic.BasicAuth{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"}, Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
} }
authMiddleware, err := NewBasic(context.Background(), next, auth, "authName") authMiddleware, err := NewBasic(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authMiddleware) ts := httptest.NewServer(authMiddleware)
@ -85,7 +84,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"}, Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
HeaderField: "X-Webauth-User", HeaderField: "X-Webauth-User",
} }
middleware, err := NewBasic(context.Background(), next, auth, "authName") middleware, err := NewBasic(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -116,7 +115,7 @@ func TestBasicAuthHeaderRemoved(t *testing.T) {
RemoveHeader: true, RemoveHeader: true,
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"}, Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
} }
middleware, err := NewBasic(context.Background(), next, auth, "authName") middleware, err := NewBasic(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -147,7 +146,7 @@ func TestBasicAuthHeaderPresent(t *testing.T) {
auth := dynamic.BasicAuth{ auth := dynamic.BasicAuth{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"}, Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
} }
middleware, err := NewBasic(context.Background(), next, auth, "authName") middleware, err := NewBasic(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -177,7 +176,7 @@ func TestBasicAuthConcurrentHashOnce(t *testing.T) {
Users: []string{"test:$2a$04$.8sTYfcxbSplCtoxt5TdJOgpBYkarKtZYsYfYxQ1edbYRuO1DNi0e"}, Users: []string{"test:$2a$04$.8sTYfcxbSplCtoxt5TdJOgpBYkarKtZYsYfYxQ1edbYRuO1DNi0e"},
} }
authMiddleware, err := NewBasic(context.Background(), next, auth, "authName") authMiddleware, err := NewBasic(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
hashCount := 0 hashCount := 0
@ -277,7 +276,7 @@ func TestBasicAuthUsersFromFile(t *testing.T) {
fmt.Fprintln(w, "traefik") fmt.Fprintln(w, "traefik")
}) })
authenticator, err := NewBasic(context.Background(), next, authenticatorConfiguration, "authName") authenticator, err := NewBasic(t.Context(), next, authenticatorConfiguration, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authenticator) ts := httptest.NewServer(authenticator)

View File

@ -1,7 +1,6 @@
package auth package auth
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
@ -23,7 +22,7 @@ func TestDigestAuthError(t *testing.T) {
auth := dynamic.DigestAuth{ auth := dynamic.DigestAuth{
Users: []string{"test"}, Users: []string{"test"},
} }
_, err := NewDigest(context.Background(), next, auth, "authName") _, err := NewDigest(t.Context(), next, auth, "authName")
assert.Error(t, err) assert.Error(t, err)
} }
@ -35,7 +34,7 @@ func TestDigestAuthFail(t *testing.T) {
auth := dynamic.DigestAuth{ auth := dynamic.DigestAuth{
Users: []string{"test:traefik:a2688e031edb4be6a3797f3882655c05"}, Users: []string{"test:traefik:a2688e031edb4be6a3797f3882655c05"},
} }
authMiddleware, err := NewDigest(context.Background(), next, auth, "authName") authMiddleware, err := NewDigest(t.Context(), next, auth, "authName")
require.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, authMiddleware, "this should not be nil") assert.NotNil(t, authMiddleware, "this should not be nil")
@ -109,7 +108,7 @@ func TestDigestAuthUsersFromFile(t *testing.T) {
fmt.Fprintln(w, "traefik") fmt.Fprintln(w, "traefik")
}) })
authenticator, err := NewDigest(context.Background(), next, authenticatorConfiguration, "authName") authenticator, err := NewDigest(t.Context(), next, authenticatorConfiguration, "authName")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authenticator) ts := httptest.NewServer(authenticator)

View File

@ -37,7 +37,7 @@ func TestForwardAuthFail(t *testing.T) {
})) }))
t.Cleanup(server.Close) t.Cleanup(server.Close)
middleware, err := NewForward(context.Background(), next, dynamic.ForwardAuth{ middleware, err := NewForward(t.Context(), next, dynamic.ForwardAuth{
Address: server.URL, Address: server.URL,
}, "authTest") }, "authTest")
require.NoError(t, err) require.NoError(t, err)
@ -90,7 +90,7 @@ func TestForwardAuthSuccess(t *testing.T) {
AuthResponseHeadersRegex: "^Foo-", AuthResponseHeadersRegex: "^Foo-",
AddAuthCookiesToResponse: []string{"authCookie"}, AddAuthCookiesToResponse: []string{"authCookie"},
} }
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -135,7 +135,7 @@ func TestForwardAuthForwardBody(t *testing.T) {
maxBodySize := int64(len(data)) maxBodySize := int64(len(data))
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize} auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize}
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -170,7 +170,7 @@ func TestForwardAuthForwardBodyEmptyBody(t *testing.T) {
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true} auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true}
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -208,7 +208,7 @@ func TestForwardAuthForwardBodySizeLimit(t *testing.T) {
maxBodySize := int64(len(data)) - 1 maxBodySize := int64(len(data)) - 1
auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize} auth := dynamic.ForwardAuth{Address: server.URL, ForwardBody: true, MaxBodySize: &maxBodySize}
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -245,7 +245,7 @@ func TestForwardAuthNotForwardBody(t *testing.T) {
auth := dynamic.ForwardAuth{Address: server.URL} auth := dynamic.ForwardAuth{Address: server.URL}
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -273,7 +273,7 @@ func TestForwardAuthRedirect(t *testing.T) {
auth := dynamic.ForwardAuth{Address: authTs.URL} auth := dynamic.ForwardAuth{Address: authTs.URL}
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest") authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authMiddleware) ts := httptest.NewServer(authMiddleware)
@ -324,7 +324,7 @@ func TestForwardAuthRemoveHopByHopHeaders(t *testing.T) {
auth := dynamic.ForwardAuth{Address: authTs.URL} auth := dynamic.ForwardAuth{Address: authTs.URL}
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest") authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authMiddleware) ts := httptest.NewServer(authMiddleware)
@ -370,7 +370,7 @@ func TestForwardAuthFailResponseHeaders(t *testing.T) {
auth := dynamic.ForwardAuth{ auth := dynamic.ForwardAuth{
Address: authTs.URL, Address: authTs.URL,
} }
authMiddleware, err := NewForward(context.Background(), next, auth, "authTest") authMiddleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(authMiddleware) ts := httptest.NewServer(authMiddleware)
@ -682,7 +682,7 @@ func TestForwardAuthTracing(t *testing.T) {
Address: server.URL, Address: server.URL,
AuthRequestHeaders: []string{"X-Foo"}, AuthRequestHeaders: []string{"X-Foo"},
} }
next, err := NewForward(context.Background(), next, auth, "authTest") next, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry", nil) req := httptest.NewRequest(http.MethodGet, "http://www.test.com/search?q=Opentelemetry", nil)
@ -725,7 +725,7 @@ func TestForwardAuthPreserveLocationHeader(t *testing.T) {
Address: server.URL, Address: server.URL,
PreserveLocationHeader: true, PreserveLocationHeader: true,
} }
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)
@ -779,7 +779,7 @@ func TestForwardAuthPreserveRequestMethod(t *testing.T) {
PreserveRequestMethod: test.preserveRequestMethod, PreserveRequestMethod: test.preserveRequestMethod,
} }
middleware, err := NewForward(context.Background(), next, auth, "authTest") middleware, err := NewForward(t.Context(), next, auth, "authTest")
require.NoError(t, err) require.NoError(t, err)
ts := httptest.NewServer(middleware) ts := httptest.NewServer(middleware)

Some files were not shown because too many files have changed in this diff Show More