Merge branch v3.2 into master

This commit is contained in:
kevinpollet 2024-11-21 11:45:02 +01:00
commit 090db6d4b0
No known key found for this signature in database
GPG key ID: 0C9A5DDD1B292453
76 changed files with 1823 additions and 1016 deletions

View file

@ -7,7 +7,7 @@ on:
env:
GO_VERSION: '1.23'
GOLANGCI_LINT_VERSION: v1.61.0
GOLANGCI_LINT_VERSION: v1.62.0
MISSPELL_VERSION: v0.6.0
jobs:

View file

@ -162,8 +162,6 @@ linters-settings:
linters:
enable-all: true
disable:
- execinquery # deprecated
- gomnd # deprecated
- sqlclosecheck # not relevant (SQL)
- rowserrcheck # not relevant (SQL)
- cyclop # duplicate of gocyclo
@ -286,4 +284,18 @@ issues:
- path: pkg/types/metrics.go
linters:
- goconst
- path: pkg/tls/certificate.go
text: 'the methods of "Certificates" use pointer receiver and non-pointer receiver.'
linters:
- recvcheck
- path: pkg/plugins/middlewarewasm.go
text: 'the methods of "wasmMiddlewareBuilder" use pointer receiver and non-pointer receiver.'
linters:
- recvcheck
output:
show-stats: true
sort-results: true
sort-order:
- linter
- file

View file

@ -25,7 +25,7 @@ global_job_config:
- export "PATH=${GOPATH}/bin:${PATH}"
- mkdir -vp "${SEMAPHORE_GIT_DIR}" "${GOPATH}/bin"
- export GOPROXY=https://proxy.golang.org,direct
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.61.0
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${GOPATH}/bin" v1.62.0
- curl -sSfL https://gist.githubusercontent.com/traefiker/6d7ac019c11d011e4f131bb2cca8900e/raw/goreleaser.sh | bash -s -- -b "${GOPATH}/bin"
- checkout
- cache restore traefik-$(checksum go.sum)

View file

@ -1,3 +1,42 @@
## [v3.2.1](https://github.com/traefik/traefik/tree/v3.2.1) (2024-11-20)
[All Commits](https://github.com/traefik/traefik/compare/v3.2.0...v3.2.1)
**Bug fixes:**
- **[k8s/ingress,k8s]** Fix HostRegexp config for rule syntax v2 ([#11288](https://github.com/traefik/traefik/pull/11288) by [kevinpollet](https://github.com/kevinpollet))
- **[logs]** Change level of peeking first byte error log to DEBUG for Postgres ([#11270](https://github.com/traefik/traefik/pull/11270) by [rtribotte](https://github.com/rtribotte))
- **[service,fastproxy]** Fix case problem for websocket upgrade ([#11246](https://github.com/traefik/traefik/pull/11246) by [juliens](https://github.com/juliens))
**Documentation:**
- **[acme,tls]** Document how to use Certificates of cert-manager ([#11053](https://github.com/traefik/traefik/pull/11053) by [mloiseleur](https://github.com/mloiseleur))
- **[docker/swarm]** Add tips about the use of docker in dynamic configuration for swarm provider ([#11207](https://github.com/traefik/traefik/pull/11207) by [webash](https://github.com/webash))
- **[middleware]** Add Compress middleware to migration guide ([#11229](https://github.com/traefik/traefik/pull/11229) by [logica0419](https://github.com/logica0419))
**Misc:**
- Merge branch v2.11 into v3.2 ([#11290](https://github.com/traefik/traefik/pull/11290) by [kevinpollet](https://github.com/kevinpollet))
- Merge branch v2.11 into v3.2 ([#11287](https://github.com/traefik/traefik/pull/11287) by [rtribotte](https://github.com/rtribotte))
- Merge branch v2.11 into v3.2 ([#11285](https://github.com/traefik/traefik/pull/11285) by [juliens](https://github.com/juliens))
- Merge branch v2.11 into v3.2 ([#11268](https://github.com/traefik/traefik/pull/11268) by [kevinpollet](https://github.com/kevinpollet))
## [v2.11.14](https://github.com/traefik/traefik/tree/v2.11.14) (2024-11-20)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.13...v2.11.14)
**Bug fixes:**
- **[acme]** Update go-acme/lego to v4.20.2 ([#11263](https://github.com/traefik/traefik/pull/11263) by [ldez](https://github.com/ldez))
- **[logs,server]** Change level of peeking first byte error log to DEBUG ([#11254](https://github.com/traefik/traefik/pull/11254) by [rtribotte](https://github.com/rtribotte))
- **[middleware,server]** Drop untrusted X-Forwarded-Prefix header ([#11253](https://github.com/traefik/traefik/pull/11253) by [rtribotte](https://github.com/rtribotte))
- **[server]** Apply keepalive config to h2c entrypoints ([#11276](https://github.com/traefik/traefik/pull/11276) by [davefu113](https://github.com/davefu113))
- **[service]** Fix internal handlers ServiceBuilder composition ([#11281](https://github.com/traefik/traefik/pull/11281) by [juliens](https://github.com/juliens))
**Documentation:**
- **[accesslogs]** Update access-logs.md, add examples for accesslog.format ([#11275](https://github.com/traefik/traefik/pull/11275) by [bluepuma77](https://github.com/bluepuma77))
- Fix the defaultRule CLI examples ([#11282](https://github.com/traefik/traefik/pull/11282) by [kevinpollet](https://github.com/kevinpollet))
- Fix spelling, grammar, and rephrase sections for clarity in some documentation pages ([#11280](https://github.com/traefik/traefik/pull/11280) by [AntoineDeveloper](https://github.com/AntoineDeveloper))
- Fix absolute link in the migration guide ([#11269](https://github.com/traefik/traefik/pull/11269) by [kevinpollet](https://github.com/kevinpollet))
- Add X-Forwarded-Prefix to the migration guide ([#11267](https://github.com/traefik/traefik/pull/11267) by [kevinpollet](https://github.com/kevinpollet))
- Fix a small typo in entrypoints documentation ([#11261](https://github.com/traefik/traefik/pull/11261) by [quiode](https://github.com/quiode))
- Add a warning about environment variables casing for static configuration ([#11226](https://github.com/traefik/traefik/pull/11226) by [anchal00](https://github.com/anchal00))
- Improve documentation on dashboard ([#11220](https://github.com/traefik/traefik/pull/11220) by [mloiseleur](https://github.com/mloiseleur))
## [v3.2.0](https://github.com/traefik/traefik/tree/v3.2.0) (2024-10-28)
[All Commits](https://github.com/traefik/traefik/compare/v3.2.0-rc1...v3.2.0)

View file

@ -62,7 +62,7 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
- Provides HTTPS to your microservices by leveraging [Let's Encrypt](https://letsencrypt.org) (wildcard certificates support)
- Circuit breakers, retry
- See the magic through its clean web UI
- Websocket, HTTP/2, gRPC ready
- WebSocket, HTTP/2, gRPC ready
- Provides metrics (Rest, Prometheus, Datadog, Statsd, InfluxDB 2.X)
- Keeps access logs (JSON, CLF)
- Fast

View file

@ -1,7 +1,7 @@
# Security Policy
You can join our security mailing list to be aware of the latest announcements from our security team.
You can subscribe sending a mail to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
You can subscribe by sending an email to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
Reported vulnerabilities can be found on [cve.mitre.org](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=traefik).

View file

@ -189,11 +189,11 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
return nil, err
}
acmeProviders := initACMEProvider(staticConfiguration, &providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider)
acmeProviders := initACMEProvider(staticConfiguration, providerAggregator, tlsManager, httpChallengeProvider, tlsChallengeProvider)
// Tailscale
tsProviders := initTailscaleProviders(staticConfiguration, &providerAggregator)
tsProviders := initTailscaleProviders(staticConfiguration, providerAggregator)
// Observability

View file

@ -92,7 +92,7 @@ For development purposes, you can specify which tests to run by using (only work
Create `tailscale.secret` file in `integration` directory.
This file need to contains a [Tailscale auth key](https://tailscale.com/kb/1085/auth-keys)
This file needs to contain a [Tailscale auth key](https://tailscale.com/kb/1085/auth-keys)
(an ephemeral, but reusable, one is recommended).
Add this section to your tailscale ACLs to auto-approve the routes for the

View file

@ -15,13 +15,13 @@ Let's see how.
### General
This [documentation](../../ "Link to the official Traefik documentation") is built with [MkDocs](https://mkdocs.org/ "Link to website of MkDocs").
This [documentation](../../ "Link to the official Traefik documentation") is built with [MkDocs](https://mkdocs.org/ "Link to the website of MkDocs").
### Method 1: `Docker` and `make`
Please make sure you have the following requirements installed:
- [Docker](https://www.docker.com/ "Link to website of Docker")
- [Docker](https://www.docker.com/ "Link to the website of Docker")
You can build the documentation and test it locally (with live reloading), using the `docs-serve` target:
@ -51,7 +51,7 @@ $ make docs-build
Please make sure you have the following requirements installed:
- [Python](https://www.python.org/ "Link to website of Python")
- [Python](https://www.python.org/ "Link to the website of Python")
- [pip](https://pypi.org/project/pip/ "Link to the website of pip on PyPI")
```bash

View file

@ -32,7 +32,7 @@ The contributor should also meet one or several of the following requirements:
including those of other maintainers and contributors.
- The contributor is active on Traefik Community forums
or other technical forums/boards such as K8S slack, Reddit, StackOverflow, hacker news.
or other technical forums/boards, such as K8S Slack, Reddit, StackOverflow, and Hacker News.
Any existing active maintainer can create an issue to discuss promoting a contributor to maintainer.
Other maintainers can vote on the issue, and if the quorum is reached, the contributor is promoted to maintainer.

View file

@ -17,7 +17,7 @@ or the list of [confirmed bugs](https://github.com/traefik/traefik/labels/kind%2
## How We Prioritize
We wish we could review every pull request right away, but because it's a time consuming operation, it's not always possible.
We wish we could review every pull request right away, but because it's a time-consuming operation, it's not always possible.
The PRs we are able to handle the fastest are:
@ -130,7 +130,7 @@ This label can be used when:
Traefik Proxy is made by the community for the community,
as such the goal is to engage the community to make Traefik the best reverse proxy available.
Part of this goal is maintaining a lean codebase and ensuring code velocity.
unfortunately, this means that sometimes we will not be able to merge a pull request.
Unfortunately, this means that sometimes we will not be able to merge a pull request.
Because we respect the work you did, you will always be told why we are closing your pull request.
If you do not agree with our decision, do not worry; closed pull requests are effortless to recreate,

View file

@ -8,7 +8,7 @@ description: "Security is a key part of Traefik Proxy. Read the technical docume
## Security Advisories
We strongly advise you to join our mailing list to be aware of the latest announcements from our security team.
You can subscribe sending a mail to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
You can subscribe by sending an email to security+subscribe@traefik.io or on [the online viewer](https://groups.google.com/a/traefik.io/forum/#!forum/security).
## CVE

View file

@ -326,7 +326,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [AzureDNS](https://azure.microsoft.com/services/dns/) | `azuredns` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID`, `AZURE_SUBSCRIPTION_ID`, `AZURE_RESOURCE_GROUP`, `[AZURE_ENVIRONMENT]`, `[AZURE_PRIVATE_ZONE]`, `[AZURE_ZONE_NAME]` | [Additional configuration](https://go-acme.github.io/lego/dns/azuredns) |
| [Bindman](https://github.com/labbsr0x/bindman-dns-webhook) | `bindman` | `BINDMAN_MANAGER_ADDRESS` | [Additional configuration](https://go-acme.github.io/lego/dns/bindman) |
| [Blue Cat](https://www.bluecatnetworks.com/) | `bluecat` | `BLUECAT_SERVER_URL`, `BLUECAT_USER_NAME`, `BLUECAT_PASSWORD`, `BLUECAT_CONFIG_NAME`, `BLUECAT_DNS_VIEW` | [Additional configuration](https://go-acme.github.io/lego/dns/bluecat) |
| [Brandit](https://www.brandit.com) | `brandit` | `BRANDIT_API_USERNAME`, `BRANDIT_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/brandit) |
| [Brandit](https://www.brandit.com) (DEPRECATED) | `brandit` | `BRANDIT_API_USERNAME`, `BRANDIT_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/brandit) |
| [Bunny](https://bunny.net) | `bunny` | `BUNNY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/bunny) |
| [Checkdomain](https://www.checkdomain.de/) | `checkdomain` | `CHECKDOMAIN_TOKEN`, | [Additional configuration](https://go-acme.github.io/lego/dns/checkdomain/) |
| [Civo](https://www.civo.com/) | `civo` | `CIVO_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/civo) |
@ -334,9 +334,10 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [CloudDNS](https://vshosting.eu/) | `clouddns` | `CLOUDDNS_CLIENT_ID`, `CLOUDDNS_EMAIL`, `CLOUDDNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/clouddns) |
| [Cloudflare](https://www.cloudflare.com) | `cloudflare` | `CF_API_EMAIL`, `CF_API_KEY` [^5] or `CF_DNS_API_TOKEN`, `[CF_ZONE_API_TOKEN]` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudflare) |
| [ClouDNS](https://www.cloudns.net/) | `cloudns` | `CLOUDNS_AUTH_ID`, `CLOUDNS_AUTH_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudns) |
| [CloudXNS](https://www.cloudxns.net) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
| [CloudXNS](https://www.cloudxns.net) (DEPRECATED) | `cloudxns` | `CLOUDXNS_API_KEY`, `CLOUDXNS_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/cloudxns) |
| [ConoHa](https://www.conoha.jp) | `conoha` | `CONOHA_TENANT_ID`, `CONOHA_API_USERNAME`, `CONOHA_API_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/conoha) |
| [Constellix](https://constellix.com) | `constellix` | `CONSTELLIX_API_KEY`, `CONSTELLIX_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/constellix) |
| [Core-Networks](https://www.core-networks.de) | `corenetworks` | `CORENETWORKS_LOGIN`, `CORENETWORKS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/corenetworks) |
| [CPanel and WHM](https://cpanel.net/) | `cpanel` | `CPANEL_MODE`, `CPANEL_USERNAME`, `CPANEL_TOKEN`, `CPANEL_BASE_URL` | [Additional configuration](https://go-acme.github.io/lego/dns/cpanel) |
| [Derak Cloud](https://derak.cloud/) | `derak` | `DERAK_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/derak) |
| [deSEC](https://desec.io) | `desec` | `DESEC_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/desec) |
@ -418,6 +419,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Rackspace](https://www.rackspace.com/cloud/dns) | `rackspace` | `RACKSPACE_USER`, `RACKSPACE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rackspace) |
| [RcodeZero](https://www.rcodezero.at) | `rcodezero` | `RCODEZERO_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/rcodezero) |
| [reg.ru](https://www.reg.ru) | `regru` | `REGRU_USERNAME`, `REGRU_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/regru) |
| [Regfish](https://regfish.de) | `regfish` | `regfish` | [Additional configuration](https://go-acme.github.io/lego/dns/regfish) |
| [RFC2136](https://tools.ietf.org/html/rfc2136) | `rfc2136` | `RFC2136_TSIG_KEY`, `RFC2136_TSIG_SECRET`, `RFC2136_TSIG_ALGORITHM`, `RFC2136_NAMESERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/rfc2136) |
| [RimuHosting](https://rimuhosting.com) | `rimuhosting` | `RIMUHOSTING_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/rimuhosting) |
| [Route 53](https://aws.amazon.com/route53/) | `route53` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `[AWS_REGION]`, `[AWS_HOSTED_ZONE_ID]` or a configured user/instance IAM profile. | [Additional configuration](https://go-acme.github.io/lego/dns/route53) |
@ -431,7 +433,9 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Simply.com](https://www.simply.com/en/domains/) | `simply` | `SIMPLY_ACCOUNT_NAME`, `SIMPLY_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/simply) |
| [Sonic](https://www.sonic.com/) | `sonic` | `SONIC_USER_ID`, `SONIC_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/sonic) |
| [Stackpath](https://www.stackpath.com/) | `stackpath` | `STACKPATH_CLIENT_ID`, `STACKPATH_CLIENT_SECRET`, `STACKPATH_STACK_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/stackpath) |
| [Technitium](https://technitium.com) | `technitium` | `TECHNITIUM_SERVER_BASE_URL`, `TECHNITIUM_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/technitium) |
| [Tencent Cloud DNS](https://cloud.tencent.com/product/cns) | `tencentcloud` | `TENCENTCLOUD_SECRET_ID`, `TENCENTCLOUD_SECRET_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/tencentcloud) |
| [Timeweb Cloud](https://timeweb.cloud) | `timewebcloud` | `TIMEWEBCLOUD_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/timewebcloud) |
| [TransIP](https://www.transip.nl/) | `transip` | `TRANSIP_ACCOUNT_NAME`, `TRANSIP_PRIVATE_KEY_PATH` | [Additional configuration](https://go-acme.github.io/lego/dns/transip) |
| [UKFast SafeDNS](https://docs.ukfast.co.uk/domains/safedns/index.html) | `safedns` | `SAFEDNS_AUTH_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/safedns) |
| [Ultradns](https://neustarsecurityservices.com/dns-services) | `ultradns` | `ULTRADNS_USERNAME`, `ULTRADNS_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/ultradns) |
@ -441,6 +445,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [Versio](https://www.versio.nl/domeinnamen) | `versio` | `VERSIO_USERNAME`, `VERSIO_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/versio) |
| [VinylDNS](https://www.vinyldns.io) | `vinyldns` | `VINYLDNS_ACCESS_KEY`, `VINYLDNS_SECRET_KEY`, `VINYLDNS_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/vinyldns) |
| [VK Cloud](https://mcs.mail.ru/) | `vkcloud` | `VK_CLOUD_PASSWORD`, `VK_CLOUD_PROJECT_ID`, `VK_CLOUD_USERNAME` | [Additional configuration](https://go-acme.github.io/lego/dns/vkcloud) |
| [Volcano Engine](https://www.volcengine.com) | `volcengine` | `VOLC_ACCESSKEY`, `VOLC_SECRETKEY` | [Additional configuration](https://go-acme.github.io/lego/dns/volcengine) |
| [Vscale](https://vscale.io/) | `vscale` | `VSCALE_API_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/vscale) |
| [VULTR](https://www.vultr.com) | `vultr` | `VULTR_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/vultr) |
| [Webnames](https://www.webnames.ru/) | `webnames` | `WEBNAMES_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/webnames) |

View file

@ -652,3 +652,10 @@ As a consequence, middlewares do not have access to those Connection headers,
and a new option has been introduced to specify which ones could go through the middleware chain before being removed: `<entrypoint>.forwardedHeaders.connection`.
Please check out the [entrypoint forwarded headers connection option configuration](../routing/entrypoints.md#forwarded-headers) documentation.
## v2.11.14
### X-Forwarded-Prefix
In `v2.11.14`, the `X-Forwarded-Prefix` header is now handled like the other `X-Forwarded-*` headers: Traefik removes it when it's sent from an untrusted source.
Please refer to the Forwarded headers [documentation](../routing/entrypoints.md#forwarded-headers) for more details.

View file

@ -80,7 +80,7 @@ Please use the `disableClusterScopeResources` option instead to avoid cluster sc
### Kubernetes CRD Provider
Starting with v3.2, the CRDs has been updated on [TraefikService](../routing/services#mirroring-service) (PR [#11032](https://github.com/traefik/traefik/pull/11032)) and on [RateLimit](../middlewares/http/ratelimit) & [InFlightReq](../middlewares/http/inflightreq) middlewares (PR [#9747](https://github.com/traefik/traefik/pull/9747)).
Starting with v3.2, the CRDs has been updated on [TraefikService](../routing/services#mirroring-service) (PR [#11032](https://github.com/traefik/traefik/pull/11032)), on [RateLimit](../middlewares/http/ratelimit) & [InFlightReq](../middlewares/http/inflightreq) middlewares (PR [#9747](https://github.com/traefik/traefik/pull/9747)) and on [Compress](../middlewares/http/compress) middleware (PR [#10943](https://github.com/traefik/traefik/pull/10943)).
This update adds only new optional fields.
CRDs can be updated with this command:
@ -153,3 +153,10 @@ the `configmaps`, `backendtlspolicies` and `backendtlspolicies/status` rights ha
- update
...
```
## v3.2.1
### X-Forwarded-Prefix
In `v3.2.1`, the `X-Forwarded-Prefix` header is now handled like the other `X-Forwarded-*` headers: Traefik removes it when it's sent from an untrusted source.
Please refer to the Forwarded headers [documentation](../routing/entrypoints.md#forwarded-headers) for more details.

View file

@ -79,6 +79,20 @@ If the given format is unsupported, the default (CLF) is used instead.
<remote_IP_address> - <client_user_name_if_available> [<timestamp>] "<request_method> <request_path> <request_protocol>" <HTTP_status> <content-length> "<request_referrer>" "<request_user_agent>" <number_of_requests_received_since_Traefik_started> "<Traefik_router_name>" "<Traefik_server_URL>" <request_duration_in_ms>ms
```
```yaml tab="File (YAML)"
accessLog:
format: "json"
```
```toml tab="File (TOML)"
[accessLog]
format = "json"
```
```bash tab="CLI"
--accesslog.format=json
```
### `bufferingSize`
To write the logs in an asynchronous fashion, specify a `bufferingSize` option.

View file

@ -70,7 +70,7 @@ And then define a routing configuration on Traefik itself with the
### `insecure`
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`.
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`, on path `/api`.
!!! info
If the entryPoint named `traefik` is not configured, it will be automatically created on port 8080.

View file

@ -37,32 +37,15 @@ Start by enabling the dashboard by using the following option from [Traefik's AP
on the [static configuration](../getting-started/configuration-overview.md#the-static-configuration):
```yaml tab="File (YAML)"
api:
# Dashboard
#
# Optional
# Default: true
#
dashboard: true
api: {}
```
```toml tab="File (TOML)"
[api]
# Dashboard
#
# Optional
# Default: true
#
dashboard = true
```
```bash tab="CLI"
# Dashboard
#
# Optional
# Default: true
#
--api.dashboard=true
--api=true
```
Then define a routing configuration on Traefik itself,
@ -106,27 +89,47 @@ rule = "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashb
## Insecure Mode
This mode is not recommended because it does not allow the use of security features.
When _insecure_ mode is enabled, one can access the dashboard on the `traefik` port (default: `8080`) of the Traefik instance,
at the following URL: `http://<Traefik IP>:8080/dashboard/` (trailing slash is mandatory).
To enable the "insecure mode", use the following options from [Traefik's API](./api.md#insecure):
This mode is **not** recommended because it does not allow security features.
For example, it is not possible to add an authentication middleware with this mode.
It should be used for testing purpose **only**.
To enable the _insecure_ mode, use the following options from [Traefik's API](./api.md#insecure):
```yaml tab="File (YAML)"
api:
dashboard: true
insecure: true
```
```toml tab="File (TOML)"
[api]
dashboard = true
insecure = true
```
```bash tab="CLI"
--api.dashboard=true --api.insecure=true
--api.insecure=true
```
You can now access the dashboard on the port `8080` of the Traefik instance,
at the following URL: `http://<Traefik IP>:8080/dashboard/` (trailing slash is mandatory).
## Disable The Dashboard
By default, the dashboard is enabled when the API is enabled.
If necessary, the dashboard can be disabled by using the following option.
```yaml tab="File (YAML)"
api:
dashboard: false
```
```toml tab="File (TOML)"
[api]
dashboard = false
```
```bash tab="CLI"
--api.dashboard=false
```
{!traefik-for-business-applications.md!}

View file

@ -525,7 +525,7 @@ providers:
```
```bash tab="CLI"
--providers.consulcatalog.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
--providers.consulcatalog.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)'
# ...
```

View file

@ -455,7 +455,7 @@ providers:
```
```bash tab="CLI"
--providers.docker.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
--providers.docker.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)'
# ...
```

View file

@ -283,7 +283,7 @@ providers:
```
```bash tab="CLI"
--providers.ecs.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
--providers.ecs.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)'
# ...
```

View file

@ -432,7 +432,7 @@ providers:
```
```bash tab="CLI"
--providers.nomad.defaultRule="Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
--providers.nomad.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)'
# ...
```

View file

@ -455,7 +455,10 @@ _Optional, Default=""_
Defines a default docker network to use for connections to all containers.
This option can be overridden on a per-container basis with the `traefik.docker.network` label.
This option can be overridden on a per-container basis with the `traefik.docker.network` [routing label](../routing/providers/swarm.md#traefikdockernetwork).
!!! warning
The Docker Swarm provider still uses the same per-container mechanism as the Docker provider, so therefore the label still uses the `docker` keyword intentionally.
```yaml tab="File (YAML)"
providers:
@ -500,7 +503,7 @@ providers:
```
```bash tab="CLI"
--providers.swarm.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
--providers.swarm.defaultRule='Host(`{{ .Name }}.{{ index .Labels "customLabel"}}`)'
# ...
```

View file

@ -5,4 +5,23 @@ description: "Reference the environment variables for static configuration in Tr
# Static Configuration: Environment variables
!!! warning "Environment Variable Casing"
Traefik normalizes the environment variable key-value pairs by lowercasing them.
This means that when you interpolate a string in an environment variable's name,
that string will be treated as lowercase, regardless of its original casing.
For example, assuming you have set environment variables as follows:
```bash
export TRAEFIK_ENTRYPOINTS_WEB=true
export TRAEFIK_ENTRYPOINTS_WEB_ADDRESS=:80
export TRAEFIK_CERTIFICATESRESOLVERS_myResolver=true
export TRAEFIK_CERTIFICATESRESOLVERS_myResolver_ACME_CASERVER=....
```
Although the Entrypoint is named `WEB` and the Certificate Resolver is named `myResolver`,
they have to be referenced respectively as `web`, and `myresolver` in the configuration.
--8<-- "content/reference/static-configuration/env-ref.md"

View file

@ -579,7 +579,7 @@ Setting them has no effect for UDP entryPoints.
If zero, no timeout exists.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
If no units are provided, the value is parsed assuming seconds.
We strongly suggest to adapt this value accordingly to the your needs.
We strongly suggest adapting this value accordingly to your needs.
```yaml tab="File (YAML)"
## Static configuration

View file

@ -667,6 +667,9 @@ Overrides the default docker network to use for connections to the container.
If a container is linked to several networks, be sure to set the proper network name (you can check this with `docker inspect <container_id>`),
otherwise it will randomly pick one (depending on how docker is returning them).
!!! warning
The Docker Swarm provider still uses the same per-container mechanism as the Docker provider, so therefore the label still uses the `docker` keyword intentionally.
!!! warning
When deploying a stack from a compose file `stack`, the networks defined are prefixed with `stack`.
@ -680,3 +683,6 @@ Enables Swarm's inbuilt load balancer (only relevant in Swarm Mode).
If you enable this option, Traefik will use the virtual IP provided by docker swarm instead of the containers IPs.
Which means that Traefik will not perform any kind of load balancing and will delegate this task to swarm.
!!! warning
The Docker Swarm provider still uses the same per-container mechanism as the Docker provider, so therefore the label still uses the `docker` keyword intentionally.

View file

@ -0,0 +1,183 @@
---
title: "Integration with cert-manager"
description: "Learn how to use cert-manager certificates with Traefik Proxy for your routers. Read the technical documentation."
---
# cert-manager
Provision TLS Certificate for Traefik Proxy with cert-manager on Kubernetes
{: .subtitle }
## Pre-requisites
To obtain certificates from cert-manager that can be used in Traefik Proxy, you will need to:
1. Have cert-manager properly configured
2. Have Traefik Proxy configured
The certificates can then be used in an Ingress / IngressRoute / HTTPRoute.
## Example with ACME and HTTP challenge
!!! example "ACME issuer for HTTP challenge"
```yaml tab="Issuer"
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: acme
spec:
acme:
# Production server is on https://acme-v02.api.letsencrypt.org/directory
# Use staging by default.
server: https://acme-staging-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: acme
solvers:
- http01:
ingress:
ingressClassName: traefik
```
```yaml tab="Certificate"
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: whoami
namespace: traefik
spec:
secretName: domain-tls # <=== Name of secret where the generated certificate will be stored.
dnsNames:
- "domain.example.com"
issuerRef:
name: acme
kind: Issuer
```
Let's see now how to use it with the various Kubernetes providers of Traefik Proxy.
The enabled providers can be seen on the [dashboard](../../operations/dashboard/) of Traefik Proxy and also in the INFO logs when Traefik Proxy starts.
### With an Ingress
To use this certificate with an Ingress, the [Kubernetes Ingress](../../providers/kubernetes-ingress/) provider has to be enabled.
!!! info Traefik Helm Chart
This provider is enabled by default in the Traefik Helm Chart.
!!! example "Route with this Certificate"
```yaml tab="Ingress"
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: domain
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
spec:
rules:
- host: domain.example.com
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: domain-service
port:
number: 80
tls:
- secretName: domain-tls # <=== Use the name defined in Certificate resource.
```
### With an IngressRoute
To use this certificate with an IngressRoute, the [Kubernetes CRD](../../providers/kubernetes-crd) provider has to be enabled.
!!! info Traefik Helm Chart
This provider is enabled by default in the Traefik Helm Chart.
!!! example "Route with this Certificate"
```yaml tab="IngressRoute"
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: domain
spec:
entryPoints:
- websecure
routes:
- match: Host(`domain.example.com`)
kind: Rule
services:
- name: domain-service
port: 80
tls:
secretName: domain-tls # <=== Use the name defined in Certificate resource.
```
### With an HTTPRoute
To use this certificate with an HTTPRoute, the [Kubernetes Gateway](../../routing/providers/kubernetes-gateway) provider has to be enabled.
!!! info Traefik Helm Chart
This provider is disabled by default in the Traefik Helm Chart.
!!! example "Route with this Certificate"
```yaml tab="HTTPRoute"
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: domain-gateway
spec:
gatewayClassName: traefik
listeners:
- name: websecure
port: 8443
protocol: HTTPS
hostname: domain.example.com
tls:
certificateRefs:
- name: domain-tls # <==== Use the name defined in Certificate resource.
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: domain
spec:
parentRefs:
- name: domain-gateway
hostnames:
- domain.example.com
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: domain-service
port: 80
weight: 1
```
## Troubleshooting
There are multiple event sources available to investigate when using cert-manager:
1. Kubernetes events in `Certificate` and `CertificateRequest` resources
2. cert-manager logs
3. Dashboard and/or (debug) logs from Traefik Proxy
cert-manager documentation provides a [detailed guide](https://cert-manager.io/docs/troubleshooting/) on how to troubleshoot a certificate request.
{!traefik-for-business-applications.md!}

View file

@ -165,6 +165,7 @@ nav:
- 'User Guides':
- 'FastProxy': 'user-guides/fastproxy.md'
- 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
- 'Kubernetes and cert-manager': 'user-guides/cert-manager.md'
- 'gRPC Examples': 'user-guides/grpc.md'
- 'Docker':
- 'Basic Example': 'user-guides/docker-compose/basic-example/index.md'

106
go.mod
View file

@ -18,7 +18,7 @@ require (
github.com/docker/go-connections v0.5.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.7.0
github.com/go-acme/lego/v4 v4.19.2
github.com/go-acme/lego/v4 v4.20.2
github.com/go-kit/kit v0.13.0
github.com/go-kit/log v0.2.1
github.com/golang/protobuf v1.5.4
@ -29,8 +29,8 @@ require (
github.com/hashicorp/go-hclog v1.6.3
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/hashicorp/go-version v1.6.0
github.com/hashicorp/nomad/api v0.0.0-20240122103822-8a4bd61caf74 // No tag on the repo.
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/nomad/api v0.0.0-20231213195942-64e3dca9274b // No tag on the repo.
github.com/http-wasm/http-wasm-host-go v0.7.0
github.com/influxdata/influxdb-client-go/v2 v2.7.0
github.com/influxdata/influxdb1-client v0.0.0-20200827194710-b269163b24ab // No tag on the repo.
@ -85,13 +85,13 @@ require (
go.opentelemetry.io/otel/trace v1.29.0
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // No tag on the repo.
golang.org/x/mod v0.21.0
golang.org/x/net v0.29.0
golang.org/x/net v0.30.0
golang.org/x/sync v0.8.0
golang.org/x/sys v0.25.0
golang.org/x/text v0.18.0
golang.org/x/time v0.6.0
golang.org/x/sys v0.26.0
golang.org/x/text v0.19.0
golang.org/x/time v0.7.0
golang.org/x/tools v0.25.0
google.golang.org/grpc v1.66.2
google.golang.org/grpc v1.67.1
gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.31.1
@ -106,17 +106,17 @@ require (
)
require (
cloud.google.com/go/auth v0.9.3 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.4 // indirect
cloud.google.com/go/compute/metadata v0.5.1 // indirect
cloud.google.com/go/auth v0.10.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.5 // indirect
cloud.google.com/go/compute/metadata v0.5.2 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.3.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@ -137,30 +137,30 @@ require (
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
github.com/VividCortex/gohistogram v1.0.0 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.15 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.63.47 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.33 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.28.1 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.42 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.40.6 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.43.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.3 // indirect
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect
github.com/aws/smithy-go v1.22.0 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bytedance/sonic v1.10.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/civo/civogo v0.3.11 // indirect
github.com/cloudflare/cloudflare-go v0.104.0 // indirect
github.com/cloudflare/cloudflare-go v0.108.0 // indirect
github.com/containerd/containerd v1.7.20 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
@ -177,7 +177,7 @@ require (
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/exoscale/egoscale/v3 v3.1.5 // indirect
github.com/exoscale/egoscale/v3 v3.1.7 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
@ -199,12 +199,12 @@ require (
github.com/go-playground/validator/v10 v10.16.0 // indirect
github.com/go-resty/resty/v2 v2.13.1 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-zookeeper/zk v1.0.3 // indirect
github.com/goccy/go-json v0.10.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/google/gnostic-models v0.6.8 // indirect
@ -216,7 +216,7 @@ require (
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.13.0 // indirect
github.com/gophercloud/gophercloud v1.14.0 // indirect
github.com/gophercloud/gophercloud v1.14.1 // indirect
github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
@ -230,7 +230,7 @@ require (
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.114 // indirect
github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.120 // indirect
github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 // indirect
@ -246,7 +246,7 @@ require (
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
github.com/labbsr0x/goh v1.0.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/linode/linodego v1.40.0 // indirect
github.com/linode/linodego v1.42.0 // indirect
github.com/liquidweb/liquidweb-cli v0.6.9 // indirect
github.com/liquidweb/liquidweb-go v1.6.4 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
@ -289,7 +289,7 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/oracle/oci-go-sdk/v65 v65.73.0 // indirect
github.com/oracle/oci-go-sdk/v65 v65.77.1 // indirect
github.com/ovh/go-ovh v1.6.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
@ -299,7 +299,8 @@ require (
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/redis/go-redis/v9 v9.2.1 // indirect
github.com/redis/go-redis/v9 v9.6.1 // indirect
github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/sacloud/api-client-go v0.2.10 // indirect
github.com/sacloud/go-http v0.1.8 // indirect
@ -314,7 +315,7 @@ require (
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
github.com/softlayer/softlayer-go v1.1.5 // indirect
github.com/softlayer/softlayer-go v1.1.7 // indirect
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/sony/gobreaker v0.5.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@ -323,21 +324,22 @@ require (
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1002 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1002 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1034 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1034 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/transip/gotransip/v6 v6.26.0 // indirect
github.com/ultradns/ultradns-go-sdk v1.7.0-20240913052650-970ca9a // indirect
github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
github.com/volcengine/volc-sdk-golang v1.0.183 // indirect
github.com/vultr/govultr/v3 v3.9.1 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20240911120709-1fa0cb6f47c2 // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20240911121212-e4e74d0d02f5 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20241101135610-76a0cfc1a773 // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20241101143304-947cf519f6bd // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
github.com/zeebo/errs v1.2.2 // indirect
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
@ -357,19 +359,19 @@ require (
go.uber.org/ratelimit v0.3.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/arch v0.4.0 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/oauth2 v0.23.0 // indirect
golang.org/x/term v0.24.0 // indirect
google.golang.org/api v0.197.0 // indirect
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
golang.org/x/term v0.25.0 // indirect
google.golang.org/api v0.204.0 // indirect
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect
google.golang.org/protobuf v1.35.1 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/h2non/gock.v1 v1.0.16 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.12.0 // indirect
gopkg.in/ns1/ns1-go.v2 v2.12.2 // indirect
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect

539
go.sum

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@ func (s *HTTPSuite) TestSimpleConfiguration() {
Services: map[string]*dynamic.Service{
"serviceHTTP": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: boolRef(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://bacon:80",
@ -81,6 +81,4 @@ func startTestServerWithResponse(response []byte) (ts *httptest.Server) {
return ts
}
func boolRef(b bool) *bool {
return &b
}
func pointer[T any](v T) *T { return &v }

View file

@ -3,7 +3,7 @@ package dashboard
import (
"io/fs"
"net/http"
"net/url"
"strings"
"github.com/gorilla/mux"
"github.com/traefik/traefik/v3/webui"
@ -25,7 +25,8 @@ func Append(router *mux.Router, customAssets fs.FS) {
router.Methods(http.MethodGet).
Path("/").
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
http.Redirect(resp, req, safePrefix(req)+"/dashboard/", http.StatusFound)
prefix := strings.TrimSuffix(req.Header.Get("X-Forwarded-Prefix"), "/")
http.Redirect(resp, req, prefix+"/dashboard/", http.StatusFound)
})
router.Methods(http.MethodGet).
@ -58,21 +59,3 @@ func (g Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.FileServerFS(assets).ServeHTTP(w, r)
}
func safePrefix(req *http.Request) string {
prefix := req.Header.Get("X-Forwarded-Prefix")
if prefix == "" {
return ""
}
parse, err := url.Parse(prefix)
if err != nil {
return ""
}
if parse.Host != "" {
return ""
}
return parse.Path
}

View file

@ -10,53 +10,8 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_safePrefix(t *testing.T) {
testCases := []struct {
desc string
value string
expected string
}{
{
desc: "host",
value: "https://example.com",
expected: "",
},
{
desc: "host with path",
value: "https://example.com/foo/bar?test",
expected: "",
},
{
desc: "path",
value: "/foo/bar",
expected: "/foo/bar",
},
{
desc: "path without leading slash",
value: "foo/bar",
expected: "foo/bar",
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
req, err := http.NewRequest(http.MethodGet, "http://localhost", nil)
require.NoError(t, err)
req.Header.Set("X-Forwarded-Prefix", test.value)
prefix := safePrefix(req)
assert.Equal(t, test.expected, prefix)
})
}
}
func Test_ContentSecurityPolicy(t *testing.T) {
testCases := []struct {
desc string

View file

@ -19,7 +19,7 @@ import (
"github.com/traefik/traefik/v3/pkg/config/static"
)
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }
func TestHandler_HTTP(t *testing.T) {
type expected struct {
@ -415,7 +415,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -432,7 +432,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@ -501,7 +501,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -518,7 +518,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@ -535,7 +535,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.3",
@ -565,7 +565,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -583,7 +583,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@ -614,7 +614,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -632,7 +632,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.2",
@ -663,7 +663,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -692,7 +692,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",
@ -721,7 +721,7 @@ func TestHandler_HTTP(t *testing.T) {
si := &runtime.ServiceInfo{
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",

View file

@ -38,7 +38,7 @@ func TestHandler_RawData(t *testing.T) {
"foo-service@myprovider": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://127.0.0.1",

View file

@ -341,11 +341,7 @@ func (m tcpMiddlewareRepresentation) status() string {
return m.Status
}
type orderedByName interface {
orderedWithName
}
func sortByName[T orderedByName](direction string, results []T) {
func sortByName[T orderedWithName](direction string, results []T) {
// Ascending
if direction == ascendantSorting {
sort.Slice(results, func(i, j int) bool {

View file

@ -13,8 +13,7 @@ import (
"github.com/traefik/traefik/v3/pkg/types"
)
func Bool(v bool) *bool { return &v }
func String(v string) *string { return &v }
func pointer[T any](v T) *T { return &v }
func TestDecodeConfiguration(t *testing.T) {
labels := map[string]string{
@ -284,7 +283,7 @@ func TestDecodeConfiguration(t *testing.T) {
Port: "42",
},
},
TerminationDelay: func(i int) *int { return &i }(42),
TerminationDelay: pointer(42),
ProxyProtocol: &dynamic.ProxyProtocol{Version: 42},
ServersTransport: "foo",
},
@ -296,7 +295,7 @@ func TestDecodeConfiguration(t *testing.T) {
Port: "42",
},
},
TerminationDelay: func(i int) *int { return &i }(42),
TerminationDelay: pointer(42),
ProxyProtocol: &dynamic.ProxyProtocol{Version: 2},
ServersTransport: "foo",
},
@ -486,7 +485,7 @@ func TestDecodeConfiguration(t *testing.T) {
"foobar",
"fiibar",
},
ForceSlash: Bool(true),
ForceSlash: pointer(true),
},
},
"Middleware18": {
@ -562,7 +561,7 @@ func TestDecodeConfiguration(t *testing.T) {
Cert: "foobar",
Key: "foobar",
InsecureSkipVerify: true,
CAOptional: Bool(true),
CAOptional: pointer(true),
},
TrustForwardHeader: true,
AuthResponseHeaders: []string{
@ -616,14 +615,14 @@ func TestDecodeConfiguration(t *testing.T) {
"foobar",
"fiibar",
},
SSLRedirect: Bool(true),
SSLTemporaryRedirect: Bool(true),
SSLHost: String("foobar"),
SSLRedirect: pointer(true),
SSLTemporaryRedirect: pointer(true),
SSLHost: pointer("foobar"),
SSLProxyHeaders: map[string]string{
"name0": "foobar",
"name1": "foobar",
},
SSLForceHost: Bool(true),
SSLForceHost: pointer(true),
STSSeconds: 42,
STSIncludeSubdomains: true,
STSPreload: true,
@ -637,7 +636,7 @@ func TestDecodeConfiguration(t *testing.T) {
ContentSecurityPolicyReportOnly: "foobar",
PublicKey: "foobar",
ReferrerPolicy: "foobar",
FeaturePolicy: String("foobar"),
FeaturePolicy: pointer("foobar"),
PermissionsPolicy: "foobar",
IsDevelopment: true,
},
@ -698,9 +697,9 @@ func TestDecodeConfiguration(t *testing.T) {
"name0": "foobar",
"name1": "foobar",
},
FollowRedirects: func(v bool) *bool { return &v }(true),
FollowRedirects: pointer(true),
},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(time.Second),
},
@ -729,9 +728,9 @@ func TestDecodeConfiguration(t *testing.T) {
"name0": "foobar",
"name1": "foobar",
},
FollowRedirects: func(v bool) *bool { return &v }(true),
FollowRedirects: pointer(true),
},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(time.Second),
},
@ -812,7 +811,7 @@ func TestEncodeConfiguration(t *testing.T) {
},
},
ServersTransport: "foo",
TerminationDelay: func(i int) *int { return &i }(42),
TerminationDelay: pointer(42),
},
},
"Service1": {
@ -823,7 +822,7 @@ func TestEncodeConfiguration(t *testing.T) {
},
},
ServersTransport: "foo",
TerminationDelay: func(i int) *int { return &i }(42),
TerminationDelay: pointer(42),
},
},
},
@ -1010,7 +1009,7 @@ func TestEncodeConfiguration(t *testing.T) {
"foobar",
"fiibar",
},
ForceSlash: Bool(true),
ForceSlash: pointer(true),
},
},
"Middleware18": {
@ -1094,7 +1093,7 @@ func TestEncodeConfiguration(t *testing.T) {
Cert: "foobar",
Key: "foobar",
InsecureSkipVerify: true,
CAOptional: Bool(true),
CAOptional: pointer(true),
},
TrustForwardHeader: true,
AuthResponseHeaders: []string{
@ -1148,14 +1147,14 @@ func TestEncodeConfiguration(t *testing.T) {
"foobar",
"fiibar",
},
SSLRedirect: Bool(true),
SSLTemporaryRedirect: Bool(true),
SSLHost: String("foobar"),
SSLRedirect: pointer(true),
SSLTemporaryRedirect: pointer(true),
SSLHost: pointer("foobar"),
SSLProxyHeaders: map[string]string{
"name0": "foobar",
"name1": "foobar",
},
SSLForceHost: Bool(true),
SSLForceHost: pointer(true),
STSSeconds: 42,
STSIncludeSubdomains: true,
STSPreload: true,
@ -1169,7 +1168,7 @@ func TestEncodeConfiguration(t *testing.T) {
ContentSecurityPolicyReportOnly: "foobar",
PublicKey: "foobar",
ReferrerPolicy: "foobar",
FeaturePolicy: String("foobar"),
FeaturePolicy: pointer("foobar"),
PermissionsPolicy: "foobar",
IsDevelopment: true,
},
@ -1221,7 +1220,7 @@ func TestEncodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(time.Second),
},
@ -1250,7 +1249,7 @@ func TestEncodeConfiguration(t *testing.T) {
"name1": "foobar",
},
},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(time.Second),
},

View file

@ -27,14 +27,14 @@ type EntryPoint struct {
// GetAddress strips any potential protocol part of the address field of the
// entry point, in order to return the actual address.
func (ep EntryPoint) GetAddress() string {
func (ep *EntryPoint) GetAddress() string {
splitN := strings.SplitN(ep.Address, "/", 2)
return splitN[0]
}
// GetProtocol returns the protocol part of the address field of the entry point.
// If none is specified, it defaults to "tcp".
func (ep EntryPoint) GetProtocol() (string, error) {
func (ep *EntryPoint) GetProtocol() (string, error) {
splitN := strings.SplitN(ep.Address, "/", 2)
if len(splitN) < 2 {
return "tcp", nil

View file

@ -297,6 +297,12 @@ func (c *Configuration) SetEffectiveConfiguration() {
c.Providers.KubernetesGateway.EntryPoints = entryPoints
}
// Defines the default rule syntax for the Kubernetes Ingress Provider.
// This allows the provider to adapt the matcher syntax to the desired rule syntax version.
if c.Core != nil && c.Providers.KubernetesIngress != nil {
c.Providers.KubernetesIngress.DefaultRuleSyntax = c.Core.DefaultRuleSyntax
}
c.initACMEProvider()
}

View file

@ -20,6 +20,8 @@ import (
const delta float64 = 1e-10
func pointer[T any](v T) *T { return &v }
func TestNewServiceHealthChecker_durations(t *testing.T) {
testCases := []struct {
desc string
@ -285,7 +287,7 @@ func TestServiceHealthChecker_checkHealthHTTP_NotFollowingRedirects(t *testing.T
config := &dynamic.ServerHealthCheck{
Path: "/path",
FollowRedirects: Bool(false),
FollowRedirects: pointer(false),
Interval: dynamic.DefaultHealthCheckInterval,
Timeout: dynamic.DefaultHealthCheckTimeout,
}
@ -454,7 +456,3 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
})
}
}
func Bool(b bool) *bool {
return &b
}

View file

@ -14,7 +14,6 @@ import (
"net/url"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"testing"
@ -812,10 +811,10 @@ func assertValidLogData(t *testing.T, expected string, logData []byte) {
assert.Equal(t, resultExpected[OriginContentSize], result[OriginContentSize], formatErrMessage)
assert.Equal(t, resultExpected[RequestRefererHeader], result[RequestRefererHeader], formatErrMessage)
assert.Equal(t, resultExpected[RequestUserAgentHeader], result[RequestUserAgentHeader], formatErrMessage)
assert.Regexp(t, regexp.MustCompile(`\d*`), result[RequestCount], formatErrMessage)
assert.Regexp(t, `\d*`, result[RequestCount], formatErrMessage)
assert.Equal(t, resultExpected[RouterName], result[RouterName], formatErrMessage)
assert.Equal(t, resultExpected[ServiceURL], result[ServiceURL], formatErrMessage)
assert.Regexp(t, regexp.MustCompile(`\d*ms`), result[Duration], formatErrMessage)
assert.Regexp(t, `\d*ms`, result[Duration], formatErrMessage)
}
func captureStdout(t *testing.T) (out *os.File, restoreStdout func()) {

View file

@ -20,6 +20,7 @@ const (
xForwardedServer = "X-Forwarded-Server"
xForwardedURI = "X-Forwarded-Uri"
xForwardedMethod = "X-Forwarded-Method"
xForwardedPrefix = "X-Forwarded-Prefix"
xForwardedTLSClientCert = "X-Forwarded-Tls-Client-Cert"
xForwardedTLSClientCertInfo = "X-Forwarded-Tls-Client-Cert-Info"
xRealIP = "X-Real-Ip"
@ -35,6 +36,7 @@ var xHeaders = []string{
xForwardedServer,
xForwardedURI,
xForwardedMethod,
xForwardedPrefix,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xRealIP,

View file

@ -48,6 +48,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "10.0.1.0, 10.0.1.12",
@ -55,6 +56,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "GET",
xForwardedTLSClientCert: "Cert",
xForwardedTLSClientCertInfo: "CertInfo",
xForwardedPrefix: "/prefix",
},
},
{
@ -68,6 +70,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "",
@ -75,6 +78,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xForwardedPrefix: "",
},
},
{
@ -88,6 +92,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "10.0.1.0, 10.0.1.12",
@ -95,6 +100,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "GET",
xForwardedTLSClientCert: "Cert",
xForwardedTLSClientCertInfo: "CertInfo",
xForwardedPrefix: "/prefix",
},
},
{
@ -108,6 +114,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "",
@ -115,6 +122,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xForwardedPrefix: "",
},
},
{
@ -128,6 +136,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "10.0.1.0, 10.0.1.12",
@ -135,6 +144,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "GET",
xForwardedTLSClientCert: "Cert",
xForwardedTLSClientCertInfo: "CertInfo",
xForwardedPrefix: "/prefix",
},
},
{
@ -148,6 +158,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: {"GET"},
xForwardedTLSClientCert: {"Cert"},
xForwardedTLSClientCertInfo: {"CertInfo"},
xForwardedPrefix: {"/prefix"},
},
expectedHeaders: map[string]string{
xForwardedFor: "",
@ -155,6 +166,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedMethod: "",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xForwardedPrefix: "",
},
},
{
@ -283,6 +295,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
xForwardedProto: {"foo"},
@ -293,6 +306,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xForwardedPrefix: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
@ -304,6 +318,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: "80",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xForwardedPrefix: "",
xRealIP: "",
connection: "",
},
@ -321,6 +336,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
xForwardedProto: {"foo"},
@ -331,6 +347,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xForwardedPrefix: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
@ -342,6 +359,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: "foo",
xForwardedTLSClientCert: "foo",
xForwardedTLSClientCertInfo: "foo",
xForwardedPrefix: "foo",
xRealIP: "foo",
connection: "",
},
@ -358,6 +376,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
incomingHeaders: map[string][]string{
@ -370,6 +389,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
xForwardedProto: {"foo"},
@ -380,6 +400,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xForwardedPrefix: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
@ -391,6 +412,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: "80",
xForwardedTLSClientCert: "",
xForwardedTLSClientCertInfo: "",
xForwardedPrefix: "",
xRealIP: "",
connection: "",
},
@ -407,6 +429,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
incomingHeaders: map[string][]string{
@ -419,6 +442,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort,
xForwardedTLSClientCert,
xForwardedTLSClientCertInfo,
xForwardedPrefix,
xRealIP,
},
xForwardedProto: {"foo"},
@ -429,6 +453,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: {"foo"},
xForwardedTLSClientCert: {"foo"},
xForwardedTLSClientCertInfo: {"foo"},
xForwardedPrefix: {"foo"},
xRealIP: {"foo"},
},
expectedHeaders: map[string]string{
@ -440,6 +465,7 @@ func TestServeHTTP(t *testing.T) {
xForwardedPort: "foo",
xForwardedTLSClientCert: "foo",
xForwardedTLSClientCertInfo: "foo",
xForwardedPrefix: "foo",
xRealIP: "foo",
connection: "",
},

View file

@ -76,7 +76,7 @@ func NewMuxer() (*Muxer, error) {
// Match returns the handler of the first route matching the connection metadata,
// and whether the match is exactly from the rule HostSNI(*).
func (m Muxer) Match(meta ConnData) (tcp.Handler, bool) {
func (m *Muxer) Match(meta ConnData) (tcp.Handler, bool) {
for _, route := range m.routes {
if route.matchers.match(meta) {
return route.handler, route.catchAll

View file

@ -67,8 +67,8 @@ type ProviderAggregator struct {
}
// NewProviderAggregator returns an aggregate of all the providers configured in the static configuration.
func NewProviderAggregator(conf static.Providers) ProviderAggregator {
p := ProviderAggregator{
func NewProviderAggregator(conf static.Providers) *ProviderAggregator {
p := &ProviderAggregator{
providersThrottleDuration: time.Duration(conf.ProvidersThrottleDuration),
}
@ -168,12 +168,12 @@ func (p *ProviderAggregator) AddProvider(provider provider.Provider) error {
}
// Init the provider.
func (p ProviderAggregator) Init() error {
func (p *ProviderAggregator) Init() error {
return nil
}
// Provide calls the provide method of every providers.
func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
func (p *ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
if p.fileProvider != nil {
p.launchProvider(configurationChan, pool, p.fileProvider)
}
@ -193,7 +193,7 @@ func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, po
return nil
}
func (p ProviderAggregator) launchProvider(configurationChan chan<- dynamic.Message, pool *safe.Pool, prd provider.Provider) {
func (p *ProviderAggregator) launchProvider(configurationChan chan<- dynamic.Message, pool *safe.Pool, prd provider.Provider) {
jsonConf, err := redactor.RemoveCredentials(prd)
if err != nil {
log.Debug().Err(err).Msgf("Cannot marshal the provider configuration %T", prd)

View file

@ -15,8 +15,7 @@ import (
"github.com/traefik/traefik/v3/pkg/types"
)
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }
func TestDefaultRule(t *testing.T) {
testCases := []struct {
@ -67,7 +66,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -125,7 +124,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -175,7 +174,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -225,7 +224,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -281,7 +280,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -375,7 +374,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -436,7 +435,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "https://127.0.0.1:443",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -530,7 +529,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "https://127.0.0.2:444",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -615,7 +614,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -628,7 +627,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -695,7 +694,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -759,7 +758,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -826,7 +825,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -882,7 +881,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -939,7 +938,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -988,7 +987,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1050,7 +1049,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1102,7 +1101,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1115,7 +1114,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1297,7 +1296,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1352,7 +1351,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1433,7 +1432,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1501,7 +1500,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1585,7 +1584,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1649,7 +1648,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1727,7 +1726,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1797,7 +1796,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1853,7 +1852,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1910,7 +1909,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "h2c://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1961,7 +1960,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1974,7 +1973,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2207,7 +2206,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2274,7 +2273,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2710,7 +2709,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2801,7 +2800,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3019,7 +3018,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "https://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3033,7 +3032,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "https://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3319,7 +3318,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3495,7 +3494,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3508,7 +3507,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:81",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3611,7 +3610,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:81",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3691,7 +3690,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3704,7 +3703,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:81",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3803,7 +3802,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3816,7 +3815,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:81",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3829,7 +3828,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:82",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3842,7 +3841,7 @@ func TestFilterHealthStatuses(t *testing.T) {
URL: "http://127.0.0.1:83",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},

View file

@ -74,7 +74,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -137,7 +137,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -202,7 +202,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -259,7 +259,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -316,7 +316,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -379,7 +379,7 @@ func TestDynConfBuilder_DefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -613,7 +613,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -696,7 +696,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -709,7 +709,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -792,7 +792,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -856,7 +856,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -921,7 +921,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -978,7 +978,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1048,7 +1048,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1108,7 +1108,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1121,7 +1121,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1185,7 +1185,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1431,7 +1431,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1494,7 +1494,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1594,7 +1594,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1681,7 +1681,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1790,7 +1790,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1871,7 +1871,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1974,7 +1974,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2060,7 +2060,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2136,7 +2136,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2149,7 +2149,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2213,7 +2213,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2278,7 +2278,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "h2c://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2337,7 +2337,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2350,7 +2350,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2554,7 +2554,7 @@ func TestDynConfBuilder_build(t *testing.T) {
Services: map[string]*dynamic.Service{
"Test": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2819,7 +2819,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2894,7 +2894,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3368,7 +3368,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3549,7 +3549,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://192.168.0.1:8081",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3612,7 +3612,7 @@ func TestDynConfBuilder_build(t *testing.T) {
URL: "http://127.0.0.1:79",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -4031,6 +4031,4 @@ func TestDynConfBuilder_getIPAddress_swarm(t *testing.T) {
}
}
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }

View file

@ -14,8 +14,7 @@ import (
"github.com/traefik/traefik/v3/pkg/types"
)
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }
func TestDefaultRule(t *testing.T) {
testCases := []struct {
@ -69,7 +68,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://10.0.0.1:1337",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -127,7 +126,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -187,7 +186,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -239,7 +238,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -291,7 +290,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -349,7 +348,7 @@ func TestDefaultRule(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -558,7 +557,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -631,7 +630,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -644,7 +643,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -717,7 +716,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -776,7 +775,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -836,7 +835,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -888,7 +887,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -953,7 +952,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1008,7 +1007,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1021,7 +1020,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1080,7 +1079,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1291,7 +1290,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1349,7 +1348,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1439,7 +1438,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1516,7 +1515,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1610,7 +1609,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1681,7 +1680,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1769,7 +1768,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.3:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1846,7 +1845,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1912,7 +1911,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1925,7 +1924,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1984,7 +1983,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2044,7 +2043,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "h2c://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2104,7 +2103,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "h2c://127.0.0.1:8040",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2172,7 +2171,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:32124",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2185,7 +2184,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:32123",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2239,7 +2238,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2252,7 +2251,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2542,7 +2541,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2612,7 +2611,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3046,7 +3045,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3206,7 +3205,7 @@ func Test_buildConfiguration(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},

View file

@ -396,7 +396,7 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load
return &dynamic.Service{LoadBalancer: lb}, nil
}
func (c *configBuilder) makeServersTransportKey(parentNamespace string, serversTransportName string) (string, error) {
func (c configBuilder) makeServersTransportKey(parentNamespace string, serversTransportName string) (string, error) {
if serversTransportName == "" {
return "", nil
}

File diff suppressed because it is too large Load diff

View file

@ -128,8 +128,8 @@ func Test_parseServiceConfig(t *testing.T) {
},
ServersScheme: "protocol",
ServersTransport: "foobar@file",
PassHostHeader: Bool(true),
NativeLB: Bool(true),
PassHostHeader: pointer(true),
NativeLB: pointer(true),
},
},
},
@ -145,7 +145,7 @@ func Test_parseServiceConfig(t *testing.T) {
Path: String("/"),
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
},
},
},

View file

@ -0,0 +1,49 @@
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: ""
namespace: testing
spec:
rules:
- host: "*.foobar.com"
http:
paths:
- path: /bar
backend:
service:
name: service1
port:
number: 80
pathType: Prefix
---
kind: Service
apiVersion: v1
metadata:
name: service1
namespace: testing
spec:
ports:
- port: 80
clusterIP: 10.0.0.1
---
kind: EndpointSlice
apiVersion: discovery.k8s.io/v1
metadata:
name: service1-abc
namespace: testing
labels:
kubernetes.io/service-name: service1
addressType: IPv4
ports:
- port: 8080
name: ""
endpoints:
- addresses:
- 10.10.0.1
conditions:
ready: true

View file

@ -56,6 +56,9 @@ type Provider struct {
DisableClusterScopeResources bool `description:"Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services)." json:"disableClusterScopeResources,omitempty" toml:"disableClusterScopeResources,omitempty" yaml:"disableClusterScopeResources,omitempty" export:"true"`
NativeLBByDefault bool `description:"Defines whether to use Native Kubernetes load-balancing mode by default." json:"nativeLBByDefault,omitempty" toml:"nativeLBByDefault,omitempty" yaml:"nativeLBByDefault,omitempty" export:"true"`
// The default rule syntax is initialized with the configuration defined by the user with the core.DefaultRuleSyntax option.
DefaultRuleSyntax string `json:"-" toml:"-" yaml:"-" label:"-" file:"-"`
lastConfiguration safe.Safe
routerTransform k8s.RouterTransform
@ -336,7 +339,7 @@ func (p *Provider) loadConfigurationFromIngresses(ctx context.Context, client Cl
serviceName := provider.Normalize(ingress.Namespace + "-" + pa.Backend.Service.Name + "-" + portString)
conf.HTTP.Services[serviceName] = service
rt := loadRouter(rule, pa, rtConfig, serviceName)
rt := p.loadRouter(rule, pa, rtConfig, serviceName)
p.applyRouterTransform(ctxIngress, rt, ingress)
@ -432,100 +435,6 @@ func (p *Provider) shouldProcessIngress(ingress *netv1.Ingress, ingressClasses [
len(p.IngressClass) == 0 && ingress.Annotations[annotationKubernetesIngressClass] == traefikDefaultIngressClass
}
func buildHostRule(host string) string {
if strings.HasPrefix(host, "*.") {
host = strings.Replace(regexp.QuoteMeta(host), `\*\.`, `[a-zA-Z0-9-]+\.`, 1)
return fmt.Sprintf("HostRegexp(`^%s$`)", host)
}
return fmt.Sprintf("Host(`%s`)", host)
}
func getCertificates(ctx context.Context, ingress *netv1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
for _, t := range ingress.Spec.TLS {
if t.SecretName == "" {
log.Ctx(ctx).Debug().Msg("Skipping TLS sub-section: No secret name provided")
continue
}
configKey := ingress.Namespace + "-" + t.SecretName
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
secret, exists, err := k8sClient.GetSecret(ingress.Namespace, t.SecretName)
if err != nil {
return fmt.Errorf("failed to fetch secret %s/%s: %w", ingress.Namespace, t.SecretName, err)
}
if !exists {
return fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName)
}
cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName)
if err != nil {
return err
}
tlsConfigs[configKey] = &tls.CertAndStores{
Certificate: tls.Certificate{
CertFile: types.FileOrContent(cert),
KeyFile: types.FileOrContent(key),
},
}
}
}
return nil
}
func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) {
var missingEntries []string
tlsCrtData, tlsCrtExists := secret.Data["tls.crt"]
if !tlsCrtExists {
missingEntries = append(missingEntries, "tls.crt")
}
tlsKeyData, tlsKeyExists := secret.Data["tls.key"]
if !tlsKeyExists {
missingEntries = append(missingEntries, "tls.key")
}
if len(missingEntries) > 0 {
return "", "", fmt.Errorf("secret %s/%s is missing the following TLS data entries: %s",
namespace, secretName, strings.Join(missingEntries, ", "))
}
cert := string(tlsCrtData)
if cert == "" {
missingEntries = append(missingEntries, "tls.crt")
}
key := string(tlsKeyData)
if key == "" {
missingEntries = append(missingEntries, "tls.key")
}
if len(missingEntries) > 0 {
return "", "", fmt.Errorf("secret %s/%s contains the following empty TLS data entries: %s",
namespace, secretName, strings.Join(missingEntries, ", "))
}
return cert, key, nil
}
func getTLSConfig(tlsConfigs map[string]*tls.CertAndStores) []*tls.CertAndStores {
var secretNames []string
for secretName := range tlsConfigs {
secretNames = append(secretNames, secretName)
}
sort.Strings(secretNames)
var configs []*tls.CertAndStores
for _, secretName := range secretNames {
configs = append(configs, tlsConfigs[secretName])
}
return configs
}
func (p *Provider) loadService(client Client, namespace string, backend netv1.IngressBackend) (*dynamic.Service, error) {
if backend.Resource != nil {
// https://kubernetes.io/docs/concepts/services-networking/ingress/#resource-backend
@ -698,6 +607,152 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
return svc, nil
}
func (p *Provider) loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router {
rt := &dynamic.Router{
Service: serviceName,
}
if rtConfig != nil && rtConfig.Router != nil {
rt.RuleSyntax = rtConfig.Router.RuleSyntax
rt.Priority = rtConfig.Router.Priority
rt.EntryPoints = rtConfig.Router.EntryPoints
rt.Middlewares = rtConfig.Router.Middlewares
if rtConfig.Router.TLS != nil {
rt.TLS = rtConfig.Router.TLS
}
}
var rules []string
if len(rule.Host) > 0 {
if rt.RuleSyntax == "v2" || (rt.RuleSyntax == "" && p.DefaultRuleSyntax == "v2") {
rules = append(rules, buildHostRuleV2(rule.Host))
} else {
rules = append(rules, buildHostRule(rule.Host))
}
}
if len(pa.Path) > 0 {
matcher := defaultPathMatcher
if pa.PathType == nil || *pa.PathType == "" || *pa.PathType == netv1.PathTypeImplementationSpecific {
if rtConfig != nil && rtConfig.Router != nil && rtConfig.Router.PathMatcher != "" {
matcher = rtConfig.Router.PathMatcher
}
} else if *pa.PathType == netv1.PathTypeExact {
matcher = "Path"
}
rules = append(rules, fmt.Sprintf("%s(`%s`)", matcher, pa.Path))
}
rt.Rule = strings.Join(rules, " && ")
return rt
}
func buildHostRuleV2(host string) string {
if strings.HasPrefix(host, "*.") {
host = strings.Replace(host, "*.", "{subdomain:[a-zA-Z0-9-]+}.", 1)
return fmt.Sprintf("HostRegexp(`%s`)", host)
}
return fmt.Sprintf("Host(`%s`)", host)
}
func buildHostRule(host string) string {
if strings.HasPrefix(host, "*.") {
host = strings.Replace(regexp.QuoteMeta(host), `\*\.`, `[a-zA-Z0-9-]+\.`, 1)
return fmt.Sprintf("HostRegexp(`^%s$`)", host)
}
return fmt.Sprintf("Host(`%s`)", host)
}
func getCertificates(ctx context.Context, ingress *netv1.Ingress, k8sClient Client, tlsConfigs map[string]*tls.CertAndStores) error {
for _, t := range ingress.Spec.TLS {
if t.SecretName == "" {
log.Ctx(ctx).Debug().Msg("Skipping TLS sub-section: No secret name provided")
continue
}
configKey := ingress.Namespace + "-" + t.SecretName
if _, tlsExists := tlsConfigs[configKey]; !tlsExists {
secret, exists, err := k8sClient.GetSecret(ingress.Namespace, t.SecretName)
if err != nil {
return fmt.Errorf("failed to fetch secret %s/%s: %w", ingress.Namespace, t.SecretName, err)
}
if !exists {
return fmt.Errorf("secret %s/%s does not exist", ingress.Namespace, t.SecretName)
}
cert, key, err := getCertificateBlocks(secret, ingress.Namespace, t.SecretName)
if err != nil {
return err
}
tlsConfigs[configKey] = &tls.CertAndStores{
Certificate: tls.Certificate{
CertFile: types.FileOrContent(cert),
KeyFile: types.FileOrContent(key),
},
}
}
}
return nil
}
func getCertificateBlocks(secret *corev1.Secret, namespace, secretName string) (string, string, error) {
var missingEntries []string
tlsCrtData, tlsCrtExists := secret.Data["tls.crt"]
if !tlsCrtExists {
missingEntries = append(missingEntries, "tls.crt")
}
tlsKeyData, tlsKeyExists := secret.Data["tls.key"]
if !tlsKeyExists {
missingEntries = append(missingEntries, "tls.key")
}
if len(missingEntries) > 0 {
return "", "", fmt.Errorf("secret %s/%s is missing the following TLS data entries: %s",
namespace, secretName, strings.Join(missingEntries, ", "))
}
cert := string(tlsCrtData)
if cert == "" {
missingEntries = append(missingEntries, "tls.crt")
}
key := string(tlsKeyData)
if key == "" {
missingEntries = append(missingEntries, "tls.key")
}
if len(missingEntries) > 0 {
return "", "", fmt.Errorf("secret %s/%s contains the following empty TLS data entries: %s",
namespace, secretName, strings.Join(missingEntries, ", "))
}
return cert, key, nil
}
func getTLSConfig(tlsConfigs map[string]*tls.CertAndStores) []*tls.CertAndStores {
var secretNames []string
for secretName := range tlsConfigs {
secretNames = append(secretNames, secretName)
}
sort.Strings(secretNames)
var configs []*tls.CertAndStores
for _, secretName := range secretNames {
configs = append(configs, tlsConfigs[secretName])
}
return configs
}
func getNativeServiceAddress(service corev1.Service, svcPort corev1.ServicePort) (string, error) {
if service.Spec.ClusterIP == "None" {
return "", fmt.Errorf("no clusterIP on headless service: %s/%s", service.Namespace, service.Name)
@ -734,45 +789,6 @@ func makeRouterKeyWithHash(key, rule string) (string, error) {
return dupKey, nil
}
func loadRouter(rule netv1.IngressRule, pa netv1.HTTPIngressPath, rtConfig *RouterConfig, serviceName string) *dynamic.Router {
var rules []string
if len(rule.Host) > 0 {
rules = []string{buildHostRule(rule.Host)}
}
if len(pa.Path) > 0 {
matcher := defaultPathMatcher
if pa.PathType == nil || *pa.PathType == "" || *pa.PathType == netv1.PathTypeImplementationSpecific {
if rtConfig != nil && rtConfig.Router != nil && rtConfig.Router.PathMatcher != "" {
matcher = rtConfig.Router.PathMatcher
}
} else if *pa.PathType == netv1.PathTypeExact {
matcher = "Path"
}
rules = append(rules, fmt.Sprintf("%s(`%s`)", matcher, pa.Path))
}
rt := &dynamic.Router{
Rule: strings.Join(rules, " && "),
Service: serviceName,
}
if rtConfig != nil && rtConfig.Router != nil {
rt.RuleSyntax = rtConfig.Router.RuleSyntax
rt.Priority = rtConfig.Router.Priority
rt.EntryPoints = rtConfig.Router.EntryPoints
rt.Middlewares = rtConfig.Router.Middlewares
if rtConfig.Router.TLS != nil {
rt.TLS = rtConfig.Router.TLS
}
}
return rt
}
func throttleEvents(ctx context.Context, throttleDuration time.Duration, pool *safe.Pool, eventsChan <-chan interface{}) chan interface{} {
if throttleDuration == 0 {
return nil

View file

@ -22,7 +22,7 @@ import (
var _ provider.Provider = (*Provider)(nil)
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }
func String(v string) *string { return &v }
@ -34,6 +34,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
allowEmptyServices bool
disableIngressClassLookup bool
disableClusterScopeResources bool
defaultRuleSyntax string
}{
{
desc: "Empty ingresses",
@ -69,7 +70,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -119,7 +120,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -164,7 +165,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -200,7 +201,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -236,7 +237,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -272,7 +273,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -304,7 +305,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -336,7 +337,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-example-com-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -369,7 +370,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -405,7 +406,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -441,7 +442,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -457,7 +458,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"testing-service2-8082": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -490,7 +491,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -526,7 +527,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"default-backend": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -558,7 +559,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -590,7 +591,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -622,7 +623,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -658,7 +659,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -674,7 +675,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"testing-service1-carotte": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -706,7 +707,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -742,7 +743,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -758,7 +759,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
},
"toto-service1-tchouk": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -810,7 +811,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -840,7 +841,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-example-com-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -879,7 +880,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -911,7 +912,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -944,7 +945,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -978,7 +979,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"default-backend": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1010,7 +1011,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1082,7 +1083,39 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:8080",
Scheme: "",
Port: "",
},
},
},
},
},
},
},
},
{
desc: "Ingress with wildcard host syntax v2",
defaultRuleSyntax: "v2",
expected: &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-foobar-com-bar": {
Rule: "HostRegexp(`{subdomain:[a-zA-Z0-9-]+}.foobar.com`) && PathPrefix(`/bar`)",
Service: "testing-service1-80",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1117,7 +1150,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1147,7 +1180,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1176,7 +1209,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1205,7 +1238,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1234,7 +1267,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1263,7 +1296,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1292,7 +1325,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1324,7 +1357,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1356,7 +1389,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1385,7 +1418,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1440,7 +1473,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-foobar": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1481,7 +1514,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Services: map[string]*dynamic.Service{
"default-backend": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1508,6 +1541,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
AllowEmptyServices: test.allowEmptyServices,
DisableIngressClassLookup: test.disableIngressClassLookup,
DisableClusterScopeResources: test.disableClusterScopeResources,
DefaultRuleSyntax: test.defaultRuleSyntax,
}
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
@ -1548,7 +1582,7 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
Services: map[string]*dynamic.Service{
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1582,7 +1616,7 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
URL: "http://[2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b]:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1612,7 +1646,7 @@ func TestLoadConfigurationFromIngressesWithExternalNameServices(t *testing.T) {
URL: "http://[2001:0db8:3c4d:0015:0000:0000:1a2f:2a3b]:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1660,7 +1694,7 @@ func TestLoadConfigurationFromIngressesWithNativeLB(t *testing.T) {
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://10.0.0.1:8080",
@ -1709,7 +1743,7 @@ func TestLoadConfigurationFromIngressesWithNodePortLB(t *testing.T) {
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://172.16.4.4:32456",
@ -1946,7 +1980,7 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://10.0.0.1:8080",
@ -1973,7 +2007,7 @@ func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
"default-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: "http://10.0.0.1:8080",

View file

@ -15,8 +15,7 @@ import (
"github.com/traefik/traefik/v3/pkg/types"
)
func Bool(v bool) *bool { return &v }
func String(v string) *string { return &v }
func pointer[T any](v T) *T { return &v }
func Test_buildConfiguration(t *testing.T) {
provider := newProviderMock(mapToPairs(map[string]string{
@ -387,7 +386,7 @@ func Test_buildConfiguration(t *testing.T) {
"foobar",
"foobar",
},
ForceSlash: Bool(true),
ForceSlash: pointer(true),
},
},
"Middleware00": {
@ -430,7 +429,7 @@ func Test_buildConfiguration(t *testing.T) {
Cert: "foobar",
Key: "foobar",
InsecureSkipVerify: true,
CAOptional: Bool(true),
CAOptional: pointer(true),
},
TrustForwardHeader: true,
AuthResponseHeaders: []string{
@ -603,14 +602,14 @@ func Test_buildConfiguration(t *testing.T) {
"foobar",
"foobar",
},
SSLRedirect: Bool(true),
SSLTemporaryRedirect: Bool(true),
SSLHost: String("foobar"),
SSLRedirect: pointer(true),
SSLTemporaryRedirect: pointer(true),
SSLHost: pointer("foobar"),
SSLProxyHeaders: map[string]string{
"name1": "foobar",
"name0": "foobar",
},
SSLForceHost: Bool(true),
SSLForceHost: pointer(true),
STSSeconds: 42,
STSIncludeSubdomains: true,
STSPreload: true,
@ -624,7 +623,7 @@ func Test_buildConfiguration(t *testing.T) {
ContentSecurityPolicyReportOnly: "foobar",
PublicKey: "foobar",
ReferrerPolicy: "foobar",
FeaturePolicy: String("foobar"),
FeaturePolicy: pointer("foobar"),
PermissionsPolicy: "foobar",
IsDevelopment: true,
},
@ -665,13 +664,13 @@ func Test_buildConfiguration(t *testing.T) {
Interval: ptypes.Duration(time.Second),
Timeout: ptypes.Duration(time.Second),
Hostname: "foobar",
FollowRedirects: func(v bool) *bool { return &v }(true),
FollowRedirects: pointer(true),
Headers: map[string]string{
"name0": "foobar",
"name1": "foobar",
},
},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(time.Second),
},
@ -680,8 +679,8 @@ func Test_buildConfiguration(t *testing.T) {
"Service02": {
Mirroring: &dynamic.Mirroring{
Service: "foobar",
MirrorBody: func(v bool) *bool { return &v }(true),
MaxBodySize: func(v int64) *int64 { return &v }(42),
MirrorBody: pointer(true),
MaxBodySize: pointer[int64](42),
Mirrors: []dynamic.MirrorService{
{
Name: "foobar",
@ -699,11 +698,11 @@ func Test_buildConfiguration(t *testing.T) {
Services: []dynamic.WRRService{
{
Name: "foobar",
Weight: func(v int) *int { return &v }(42),
Weight: pointer(42),
},
{
Name: "foobar",
Weight: func(v int) *int { return &v }(42),
Weight: pointer(42),
},
},
Sticky: &dynamic.Sticky{
@ -788,7 +787,7 @@ func Test_buildConfiguration(t *testing.T) {
Services: map[string]*dynamic.TCPService{
"TCPService01": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
TerminationDelay: func(v int) *int { return &v }(42),
TerminationDelay: pointer(42),
Servers: []dynamic.TCPServer{
{Address: "foobar"},
{Address: "foobar"},
@ -800,11 +799,11 @@ func Test_buildConfiguration(t *testing.T) {
Services: []dynamic.TCPWRRService{
{
Name: "foobar",
Weight: func(v int) *int { return &v }(42),
Weight: pointer(42),
},
{
Name: "foobar",
Weight: func(v int) *int { return &v }(43),
Weight: pointer(43),
},
},
},

View file

@ -61,7 +61,7 @@ func Test_defaultRule(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -119,7 +119,7 @@ func Test_defaultRule(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -168,7 +168,7 @@ func Test_defaultRule(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -223,7 +223,7 @@ func Test_defaultRule(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -301,7 +301,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -368,7 +368,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://192.168.1.101:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -381,7 +381,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://192.168.1.102:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -448,7 +448,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -512,7 +512,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -579,7 +579,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -635,7 +635,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -692,7 +692,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -777,7 +777,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -839,7 +839,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -891,7 +891,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -904,7 +904,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1087,7 +1087,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1142,7 +1142,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1224,7 +1224,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1293,7 +1293,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1356,7 +1356,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1424,7 +1424,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1480,7 +1480,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1537,7 +1537,7 @@ func Test_buildConfig(t *testing.T) {
URL: "h2c://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1588,7 +1588,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1601,7 +1601,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:8080",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1800,7 +1800,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -1867,7 +1867,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2279,7 +2279,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2370,7 +2370,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2587,7 +2587,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2600,7 +2600,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.2:80",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2819,7 +2819,7 @@ func Test_buildConfig(t *testing.T) {
URL: "http://127.0.0.1:9999",
},
},
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -2906,7 +2906,7 @@ func Test_buildConfigAllowEmptyServicesTrue(t *testing.T) {
"Test": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: nil,
PassHostHeader: Bool(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
@ -3254,5 +3254,4 @@ func extractNamespacesFromProvider(providers []*Provider) []string {
return res
}
func Int(v int) *int { return &v }
func Bool(v bool) *bool { return &v }
func pointer[T any](v T) *T { return &v }

View file

@ -32,7 +32,7 @@ func New(staticCfg static.Configuration) *Provider {
}
// ThrottleDuration returns the throttle duration.
func (i Provider) ThrottleDuration() time.Duration {
func (i *Provider) ThrottleDuration() time.Duration {
return 0
}

View file

@ -171,7 +171,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if reqUpType != "" {
outReq.Header.Set("Connection", "Upgrade")
outReq.Header.Set("Upgrade", reqUpType)
if reqUpType == "websocket" {
if strings.EqualFold(reqUpType, "websocket") {
cleanWebSocketHeaders(&outReq.Header)
}
}
@ -353,6 +353,7 @@ type fasthttpHeader interface {
SetBytesV(key string, value []byte)
DelBytes(key []byte)
Del(key string)
ConnectionUpgrade() bool
}
// removeConnectionHeaders removes hop-by-hop headers listed in the "Connection" header of h.

View file

@ -2,7 +2,9 @@ package fast
import (
"bufio"
"crypto/sha1"
"crypto/tls"
"encoding/base64"
"errors"
"fmt"
"net"
@ -19,6 +21,34 @@ import (
"golang.org/x/net/websocket"
)
func TestWebSocketUpgradeCase(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
challengeKey := r.Header.Get("Sec-Websocket-Key")
hijacker, ok := w.(http.Hijacker)
require.True(t, ok)
c, _, err := hijacker.Hijack()
require.NoError(t, err)
// Force answer with "Connection: upgrade" in lowercase.
_, err = c.Write([]byte("HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: upgrade\r\nSec-WebSocket-Accept: " + computeAcceptKey(challengeKey) + "\r\n\n"))
require.NoError(t, err)
}))
defer srv.Close()
proxy := createProxyWithForwarder(t, srv.URL, createConnectionPool(srv.URL, nil))
proxyAddr := proxy.Listener.Addr().String()
_, conn, err := newWebsocketRequest(
withServer(proxyAddr),
withPath("/ws"),
).open()
require.NoError(t, err)
conn.Close()
}
func TestWebSocketTCPClose(t *testing.T) {
errChan := make(chan error, 1)
upgrader := gorillawebsocket.Upgrader{}
@ -691,3 +721,10 @@ func createProxyWithForwarder(t *testing.T, uri string, pool *connPool) *httptes
return srv
}
func computeAcceptKey(challengeKey string) string {
h := sha1.New() // #nosec G401 -- (CWE-326) https://datatracker.ietf.org/doc/html/rfc6455#page-54
h.Write([]byte(challengeKey))
h.Write([]byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}

View file

@ -1,7 +1,6 @@
package fast
import (
"bytes"
"context"
"fmt"
"io"
@ -100,7 +99,7 @@ func upgradeType(h http.Header) string {
}
func upgradeTypeFastHTTP(h fasthttpHeader) string {
if !bytes.Contains(h.Peek("Connection"), []byte("Upgrade")) {
if !h.ConnectionUpgrade() {
return ""
}

View file

@ -78,12 +78,12 @@ func init() {
Interval: ptypes.Duration(111 * time.Second),
Timeout: ptypes.Duration(111 * time.Second),
Hostname: "foo",
FollowRedirects: boolPtr(true),
FollowRedirects: pointer(true),
Headers: map[string]string{
"foo": "bar",
},
},
PassHostHeader: boolPtr(true),
PassHostHeader: pointer(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(111 * time.Second),
},
@ -100,7 +100,7 @@ func init() {
Services: []dynamic.WRRService{
{
Name: "foo",
Weight: intPtr(42),
Weight: pointer(42),
},
},
Sticky: &dynamic.Sticky{
@ -116,7 +116,7 @@ func init() {
"baz": {
Mirroring: &dynamic.Mirroring{
Service: "foo",
MaxBodySize: int64Ptr(42),
MaxBodySize: pointer[int64](42),
Mirrors: []dynamic.MirrorService{
{
Name: "foo",
@ -380,7 +380,7 @@ func init() {
Services: []dynamic.TCPWRRService{
{
Name: "foo",
Weight: intPtr(42),
Weight: pointer(42),
},
},
},
@ -427,7 +427,7 @@ func init() {
Services: []dynamic.UDPWRRService{
{
Name: "foo",
Weight: intPtr(42),
Weight: pointer(42),
},
},
},
@ -484,7 +484,7 @@ func TestAnonymize_dynamicConfiguration(t *testing.T) {
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
assert.JSONEq(t, expected, cleanJSON)
}
func TestSecure_dynamicConfiguration(t *testing.T) {
@ -501,7 +501,7 @@ func TestSecure_dynamicConfiguration(t *testing.T) {
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
assert.JSONEq(t, expected, cleanJSON)
}
func TestDo_staticConfiguration(t *testing.T) {
@ -950,17 +950,7 @@ func TestDo_staticConfiguration(t *testing.T) {
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
assert.JSONEq(t, expected, cleanJSON)
}
func boolPtr(value bool) *bool {
return &value
}
func intPtr(value int) *int {
return &value
}
func int64Ptr(value int64) *int64 {
return &value
}
func pointer[T any](v T) *T { return &v }

View file

@ -323,7 +323,7 @@ func TestListenProvidersThrottleProviderConfigReload(t *testing.T) {
})
}
providerAggregator := aggregator.ProviderAggregator{}
providerAggregator := &aggregator.ProviderAggregator{}
err := providerAggregator.AddProvider(pvd)
assert.NoError(t, err)
@ -507,7 +507,7 @@ func TestListenProvidersIgnoreSameConfig(t *testing.T) {
},
}
providerAggregator := aggregator.ProviderAggregator{}
providerAggregator := &aggregator.ProviderAggregator{}
err := providerAggregator.AddProvider(pvd)
assert.NoError(t, err)
@ -651,7 +651,7 @@ func TestListenProvidersIgnoreIntermediateConfigs(t *testing.T) {
},
}
providerAggregator := aggregator.ProviderAggregator{}
providerAggregator := &aggregator.ProviderAggregator{}
err := providerAggregator.AddProvider(pvd)
assert.NoError(t, err)

View file

@ -29,7 +29,7 @@ func isPostgres(br *bufio.Reader) (bool, error) {
if err != nil {
var opErr *net.OpError
if !errors.Is(err, io.EOF) && (!errors.As(err, &opErr) || !opErr.Timeout()) {
log.Error().Err(err).Msg("Error while Peeking first byte")
log.Debug().Err(err).Msg("Error while peeking first bytes")
}
return false, err
}

View file

@ -364,7 +364,7 @@ func clientHelloInfo(br *bufio.Reader) (*clientHello, error) {
if err != nil {
var opErr *net.OpError
if !errors.Is(err, io.EOF) && (!errors.As(err, &opErr) || !opErr.Timeout()) {
log.Error().Err(err).Msg("Error while Peeking first byte")
log.Debug().Err(err).Msg("Error while peeking first byte")
}
return nil, err
}
@ -390,7 +390,7 @@ func clientHelloInfo(br *bufio.Reader) (*clientHello, error) {
const recordHeaderLen = 5
hdr, err = br.Peek(recordHeaderLen)
if err != nil {
log.Error().Err(err).Msg("Error while Peeking hello")
log.Error().Err(err).Msg("Error while peeking client hello header")
return &clientHello{
peeked: getPeeked(br),
}, nil
@ -404,7 +404,7 @@ func clientHelloInfo(br *bufio.Reader) (*clientHello, error) {
helloBytes, err := br.Peek(recordHeaderLen + recLen)
if err != nil {
log.Error().Err(err).Msg("Error while Hello")
log.Error().Err(err).Msg("Error while peeking client hello bytes")
return &clientHello{
isTLS: true,
peeked: getPeeked(br),
@ -433,7 +433,7 @@ func clientHelloInfo(br *bufio.Reader) (*clientHello, error) {
func getPeeked(br *bufio.Reader) string {
peeked, err := br.Peek(br.Buffered())
if err != nil {
log.Error().Err(err).Msg("Could not get anything")
log.Error().Err(err).Msg("Error while peeking bytes")
return ""
}
return string(peeked)

View file

@ -625,17 +625,17 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati
handler = contenttype.DisableAutoDetection(handler)
debugConnection := os.Getenv(debugConnectionEnv) != ""
if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) {
handler = newKeepAliveMiddleware(handler, configuration.Transport.KeepAliveMaxRequests, configuration.Transport.KeepAliveMaxTime)
}
if withH2c {
handler = h2c.NewHandler(handler, &http2.Server{
MaxConcurrentStreams: uint32(configuration.HTTP2.MaxConcurrentStreams),
})
}
debugConnection := os.Getenv(debugConnectionEnv) != ""
if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) {
handler = newKeepAliveMiddleware(handler, configuration.Transport.KeepAliveMaxRequests, configuration.Transport.KeepAliveMaxTime)
}
serverHTTP := &http.Server{
Handler: handler,
ErrorLog: stdlog.New(logs.NoLevel(log.Logger, zerolog.DebugLevel), "", 0),

View file

@ -3,6 +3,7 @@ package server
import (
"bufio"
"context"
"crypto/tls"
"errors"
"io"
"net"
@ -17,6 +18,7 @@ import (
"github.com/traefik/traefik/v3/pkg/config/static"
tcprouter "github.com/traefik/traefik/v3/pkg/server/router/tcp"
"github.com/traefik/traefik/v3/pkg/tcp"
"golang.org/x/net/http2"
)
func TestShutdownHijacked(t *testing.T) {
@ -330,3 +332,53 @@ func TestKeepAliveMaxTime(t *testing.T) {
err = resp.Body.Close()
require.NoError(t, err)
}
func TestKeepAliveH2c(t *testing.T) {
epConfig := &static.EntryPointsTransport{}
epConfig.SetDefaults()
epConfig.KeepAliveMaxRequests = 1
entryPoint, err := NewTCPEntryPoint(context.Background(), "", &static.EntryPoint{
Address: ":0",
Transport: epConfig,
ForwardedHeaders: &static.ForwardedHeaders{},
HTTP2: &static.HTTP2Config{},
}, nil, nil)
require.NoError(t, err)
router, err := tcprouter.NewRouter()
require.NoError(t, err)
router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusOK)
}))
conn, err := startEntrypoint(entryPoint, router)
require.NoError(t, err)
http2Transport := &http2.Transport{
AllowHTTP: true,
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
return conn, nil
},
}
client := &http.Client{Transport: http2Transport}
resp, err := client.Get("http://" + entryPoint.listener.Addr().String())
require.NoError(t, err)
require.False(t, resp.Close)
err = resp.Body.Close()
require.NoError(t, err)
_, err = client.Get("http://" + entryPoint.listener.Addr().String())
require.Error(t, err)
// Unlike HTTP/1, where we can directly check `resp.Close`, HTTP/2 uses a different
// mechanism: it sends a GOAWAY frame when the connection is closing.
// We can only check the error type. The error received should be poll.ErrClosed from
// the `internal/poll` package, but we cannot directly reference the error type due to
// package restrictions. Since this error message ("use of closed network connection")
// is distinct and specific, we rely on its consistency, assuming it is stable and unlikely
// to change.
require.Contains(t, err.Error(), "use of closed network connection")
}

View file

@ -8,11 +8,6 @@ import (
"strings"
)
type serviceManager interface {
BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error)
LaunchHealthCheck(ctx context.Context)
}
// InternalHandlers is the internal HTTP handlers builder.
type InternalHandlers struct {
api http.Handler
@ -21,11 +16,10 @@ type InternalHandlers struct {
prometheus http.Handler
ping http.Handler
acmeHTTP http.Handler
serviceManager
}
// NewInternalHandlers creates a new InternalHandlers.
func NewInternalHandlers(next serviceManager, apiHandler, rest, metricsHandler, pingHandler, dashboard, acmeHTTP http.Handler) *InternalHandlers {
func NewInternalHandlers(apiHandler, rest, metricsHandler, pingHandler, dashboard, acmeHTTP http.Handler) *InternalHandlers {
return &InternalHandlers{
api: apiHandler,
dashboard: dashboard,
@ -33,14 +27,13 @@ func NewInternalHandlers(next serviceManager, apiHandler, rest, metricsHandler,
prometheus: metricsHandler,
ping: pingHandler,
acmeHTTP: acmeHTTP,
serviceManager: next,
}
}
// BuildHTTP builds an HTTP handler.
func (m *InternalHandlers) BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error) {
if !strings.HasSuffix(serviceName, "@internal") {
return m.serviceManager.BuildHTTP(rootCtx, serviceName)
return nil, nil
}
internalHandler, err := m.get(serviceName)

View file

@ -10,18 +10,20 @@ import (
"github.com/traefik/traefik/v3/pkg/config/dynamic"
)
func pointer[T any](v T) *T { return &v }
func TestBalancer(t *testing.T) {
balancer := New(nil, false)
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(3))
}), pointer(3))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
for range 4 {
@ -47,9 +49,9 @@ func TestBalancerOneServerZeroWeight(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), pointer(0))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
for range 3 {
@ -68,11 +70,11 @@ func TestBalancerNoServiceUp(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
}), Int(1))
}), pointer(1))
balancer.SetStatus(context.WithValue(context.Background(), serviceName, "parent"), "first", false)
balancer.SetStatus(context.WithValue(context.Background(), serviceName, "parent"), "second", false)
@ -89,11 +91,11 @@ func TestBalancerOneServerDown(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.WriteHeader(http.StatusInternalServerError)
}), Int(1))
}), pointer(1))
balancer.SetStatus(context.WithValue(context.Background(), serviceName, "parent"), "second", false)
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
@ -110,12 +112,12 @@ func TestBalancerDownThenUp(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.SetStatus(context.WithValue(context.Background(), serviceName, "parent"), "second", false)
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
@ -139,30 +141,30 @@ func TestBalancerPropagate(t *testing.T) {
balancer1.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer1.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer2 := New(nil, true)
balancer2.Add("third", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "third")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer2.Add("fourth", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "fourth")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
topBalancer := New(nil, true)
topBalancer.Add("balancer1", balancer1, Int(1))
topBalancer.Add("balancer1", balancer1, pointer(1))
_ = balancer1.RegisterStatusUpdater(func(up bool) {
topBalancer.SetStatus(context.WithValue(context.Background(), serviceName, "top"), "balancer1", up)
// TODO(mpl): if test gets flaky, add channel or something here to signal that
// propagation is done, and wait on it before sending request.
})
topBalancer.Add("balancer2", balancer2, Int(1))
topBalancer.Add("balancer2", balancer2, pointer(1))
_ = balancer2.RegisterStatusUpdater(func(up bool) {
topBalancer.SetStatus(context.WithValue(context.Background(), serviceName, "top"), "balancer2", up)
})
@ -209,8 +211,8 @@ func TestBalancerPropagate(t *testing.T) {
func TestBalancerAllServersZeroWeight(t *testing.T) {
balancer := New(nil, false)
balancer.Add("test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
balancer.Add("test2", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), Int(0))
balancer.Add("test", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), pointer(0))
balancer.Add("test2", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}), pointer(0))
recorder := httptest.NewRecorder()
balancer.ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/", nil))
@ -233,12 +235,12 @@ func TestSticky(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(2))
}), pointer(2))
recorder := &responseRecorder{
ResponseRecorder: httptest.NewRecorder(),
@ -275,12 +277,12 @@ func TestSticky_FallBack(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "first")
rw.WriteHeader(http.StatusOK)
}), Int(1))
}), pointer(1))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "second")
rw.WriteHeader(http.StatusOK)
}), Int(2))
}), pointer(2))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
@ -304,12 +306,12 @@ func TestBalancerBias(t *testing.T) {
balancer.Add("first", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "A")
rw.WriteHeader(http.StatusOK)
}), Int(11))
}), pointer(11))
balancer.Add("second", http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("server", "B")
rw.WriteHeader(http.StatusOK)
}), Int(3))
}), pointer(3))
recorder := &responseRecorder{ResponseRecorder: httptest.NewRecorder(), save: map[string]int{}}
@ -322,8 +324,6 @@ func TestBalancerBias(t *testing.T) {
assert.Equal(t, wantSequence, recorder.sequence)
}
func Int(v int) *int { return &v }
type responseRecorder struct {
*httptest.ResponseRecorder
save map[string]int

View file

@ -74,13 +74,12 @@ func NewManagerFactory(staticConfiguration static.Configuration, routinesPool *s
}
// Build creates a service manager.
func (f *ManagerFactory) Build(configuration *runtime.Configuration) *InternalHandlers {
svcManager := NewManager(configuration.Services, f.observabilityMgr, f.routinesPool, f.transportManager, f.proxyBuilder)
func (f *ManagerFactory) Build(configuration *runtime.Configuration) *Manager {
var apiHandler http.Handler
if f.api != nil {
apiHandler = f.api(configuration)
}
return NewInternalHandlers(svcManager, apiHandler, f.restHandler, f.metricsHandler, f.pingHandler, f.dashboardHandler, f.acmeHTTPHandler)
internalHandlers := NewInternalHandlers(apiHandler, f.restHandler, f.metricsHandler, f.pingHandler, f.dashboardHandler, f.acmeHTTPHandler)
return NewManager(configuration.Services, f.observabilityMgr, f.routinesPool, f.transportManager, f.proxyBuilder, internalHandlers)
}

View file

@ -46,12 +46,18 @@ type ProxyBuilder interface {
Update(configs map[string]*dynamic.ServersTransport)
}
// ServiceBuilder is a Service builder.
type ServiceBuilder interface {
BuildHTTP(rootCtx context.Context, serviceName string) (http.Handler, error)
}
// Manager The service manager.
type Manager struct {
routinePool *safe.Pool
observabilityMgr *middleware.ObservabilityMgr
transportManager httputil.TransportManager
proxyBuilder ProxyBuilder
serviceBuilders []ServiceBuilder
services map[string]http.Handler
configs map[string]*runtime.ServiceInfo
@ -60,12 +66,13 @@ type Manager struct {
}
// NewManager creates a new Manager.
func NewManager(configs map[string]*runtime.ServiceInfo, observabilityMgr *middleware.ObservabilityMgr, routinePool *safe.Pool, transportManager httputil.TransportManager, proxyBuilder ProxyBuilder) *Manager {
func NewManager(configs map[string]*runtime.ServiceInfo, observabilityMgr *middleware.ObservabilityMgr, routinePool *safe.Pool, transportManager httputil.TransportManager, proxyBuilder ProxyBuilder, serviceBuilders ...ServiceBuilder) *Manager {
return &Manager{
routinePool: routinePool,
observabilityMgr: observabilityMgr,
transportManager: transportManager,
proxyBuilder: proxyBuilder,
serviceBuilders: serviceBuilders,
services: make(map[string]http.Handler),
configs: configs,
healthCheckers: make(map[string]*healthcheck.ServiceHealthChecker),
@ -85,6 +92,18 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.H
return handler, nil
}
// Must be before we get configs to handle services without config.
for _, builder := range m.serviceBuilders {
handler, err := builder.BuildHTTP(rootCtx, serviceName)
if err != nil {
return nil, err
}
if handler != nil {
m.services[serviceName] = handler
return handler, nil
}
}
conf, ok := m.configs[serviceName]
if !ok {
return nil, fmt.Errorf("the service %q does not exist", serviceName)

View file

@ -20,6 +20,8 @@ import (
"github.com/traefik/traefik/v3/pkg/testhelpers"
)
func pointer[T any](v T) *T { return &v }
func TestGetLoadBalancer(t *testing.T) {
sm := Manager{
transportManager: &transportManagerMock{},
@ -235,7 +237,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
serviceName: "test",
service: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
PassHostHeader: func(v bool) *bool { return &v }(true),
PassHostHeader: pointer(true),
Servers: []dynamic.Server{
{
URL: serverPassHost.URL,
@ -253,7 +255,7 @@ func TestGetLoadBalancerServiceHandler(t *testing.T) {
desc: "PassHost doesn't pass the host instead of the IP",
serviceName: "test",
service: &dynamic.ServersLoadBalancer{
PassHostHeader: boolPtr(false),
PassHostHeader: pointer(false),
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
Servers: []dynamic.Server{
{
@ -448,6 +450,48 @@ func Test1xxResponses(t *testing.T) {
}
}
type serviceBuilderFunc func(ctx context.Context, serviceName string) (http.Handler, error)
func (s serviceBuilderFunc) BuildHTTP(ctx context.Context, serviceName string) (http.Handler, error) {
return s(ctx, serviceName)
}
type internalHandler struct{}
func (internalHandler) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {}
func TestManager_ServiceBuilders(t *testing.T) {
var internalHandler internalHandler
manager := NewManager(map[string]*runtime.ServiceInfo{
"test@test": {
Service: &dynamic.Service{
LoadBalancer: &dynamic.ServersLoadBalancer{},
},
},
}, nil, nil, &TransportManager{
roundTrippers: map[string]http.RoundTripper{
"default@internal": http.DefaultTransport,
},
}, nil, serviceBuilderFunc(func(rootCtx context.Context, serviceName string) (http.Handler, error) {
if strings.HasSuffix(serviceName, "@internal") {
return internalHandler, nil
}
return nil, nil
}))
h, err := manager.BuildHTTP(context.Background(), "test@internal")
require.NoError(t, err)
assert.Equal(t, internalHandler, h)
h, err = manager.BuildHTTP(context.Background(), "test@test")
require.NoError(t, err)
assert.NotNil(t, h)
_, err = manager.BuildHTTP(context.Background(), "wrong@test")
assert.Error(t, err)
}
func TestManager_Build(t *testing.T) {
testCases := []struct {
desc string

View file

@ -27,10 +27,6 @@ import (
"github.com/traefik/traefik/v3/pkg/types"
)
func Int32(i int32) *int32 {
return &i
}
// LocalhostCert is a PEM-encoded TLS cert
// for host example.com, www.example.com
// expiring at Jan 29 16:00:00 2084 GMT.
@ -128,7 +124,7 @@ func TestKeepConnectionWhenSameConfiguration(t *testing.T) {
rw.WriteHeader(http.StatusOK)
}))
connCount := Int32(0)
connCount := pointer[int32](0)
srv.Config.ConnState = func(conn net.Conn, state http.ConnState) {
if state == http.StateNew {
atomic.AddInt32(connCount, 1)

View file

@ -79,7 +79,7 @@ func (p *Proxy) ServeTCP(conn WriteCloser) {
<-errChan
}
func (p Proxy) dialBackend() (WriteCloser, error) {
func (p *Proxy) dialBackend() (WriteCloser, error) {
conn, err := p.dialer.Dial("tcp", p.address)
if err != nil {
return nil, err
@ -88,7 +88,7 @@ func (p Proxy) dialBackend() (WriteCloser, error) {
return conn.(WriteCloser), nil
}
func (p Proxy) connCopy(dst, src WriteCloser, errCh chan error) {
func (p *Proxy) connCopy(dst, src WriteCloser, errCh chan error) {
_, err := io.Copy(dst, src)
errCh <- err

View file

@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"net/url"
"os"
"sort"
"strings"
@ -45,13 +46,6 @@ var (
}
)
// Certificate holds a SSL cert/key pair
// Certs and Key could be either a file path, or the file content itself.
type Certificate struct {
CertFile types.FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"`
KeyFile types.FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"`
}
// Certificates defines traefik certificates type
// Certs and Keys could be either a file path, or the file content itself.
type Certificates []Certificate
@ -73,6 +67,13 @@ func (c Certificates) GetCertificates() []tls.Certificate {
return certs
}
// Certificate holds a SSL cert/key pair
// Certs and Key could be either a file path, or the file content itself.
type Certificate struct {
CertFile types.FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"`
KeyFile types.FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"`
}
// AppendCertificate appends a Certificate to a certificates map keyed by store name.
func (c *Certificate) AppendCertificate(certs map[string]map[string]*tls.Certificate, storeName string) error {
certContent, err := c.CertFile.Read()
@ -166,31 +167,6 @@ func (c *Certificate) GetCertificateFromBytes() (tls.Certificate, error) {
return cert, nil
}
// GetTruncatedCertificateName truncates the certificate name.
func (c *Certificate) GetTruncatedCertificateName() string {
certName := c.CertFile.String()
// Truncate certificate information only if it's a well formed certificate content with more than 50 characters
if !c.CertFile.IsPath() && strings.HasPrefix(certName, certificateHeader) && len(certName) > len(certificateHeader)+50 {
certName = strings.TrimPrefix(c.CertFile.String(), certificateHeader)[:50]
}
return certName
}
// String is the method to format the flag's value, part of the flag.Value interface.
// The String method's output will be used in diagnostics.
func (c *Certificates) String() string {
if len(*c) == 0 {
return ""
}
var result []string
for _, certificate := range *c {
result = append(result, certificate.CertFile.String()+","+certificate.KeyFile.String())
}
return strings.Join(result, ";")
}
// Set is the method to set the flag value, part of the flag.Value interface.
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
@ -209,9 +185,43 @@ func (c *Certificates) Set(value string) error {
return nil
}
// Type is type of the struct.
func (c *Certificates) Type() string {
return "certificates"
// GetTruncatedCertificateName truncates the certificate name.
func (c *Certificate) GetTruncatedCertificateName() string {
certName := c.CertFile.String()
// Truncate certificate information only if it's a well formed certificate content with more than 50 characters
if !c.CertFile.IsPath() && strings.HasPrefix(certName, certificateHeader) && len(certName) > len(certificateHeader)+50 {
certName = strings.TrimPrefix(c.CertFile.String(), certificateHeader)[:50]
}
return certName
}
// FileOrContent hold a file path or content.
type FileOrContent string
func (f FileOrContent) String() string {
return string(f)
}
// IsPath returns true if the FileOrContent is a file path, otherwise returns false.
func (f FileOrContent) IsPath() bool {
_, err := os.Stat(f.String())
return err == nil
}
func (f FileOrContent) Read() ([]byte, error) {
var content []byte
if f.IsPath() {
var err error
content, err = os.ReadFile(f.String())
if err != nil {
return nil, err
}
} else {
content = []byte(f)
}
return content, nil
}
// VerifyPeerCertificate verifies the chain certificates and their URI.

View file

@ -31,7 +31,7 @@ func NewCertificateStore() *CertificateStore {
}
}
func (c CertificateStore) getDefaultCertificateDomains() []string {
func (c *CertificateStore) getDefaultCertificateDomains() []string {
var allCerts []string
if c.DefaultCertificate == nil {
@ -58,7 +58,7 @@ func (c CertificateStore) getDefaultCertificateDomains() []string {
}
// GetAllDomains return a slice with all the certificate domain.
func (c CertificateStore) GetAllDomains() []string {
func (c *CertificateStore) GetAllDomains() []string {
allDomains := c.getDefaultCertificateDomains()
// Get dynamic certificates
@ -157,7 +157,7 @@ func (c *CertificateStore) GetCertificate(domains []string) *tls.Certificate {
}
// ResetCache clears the cache in the store.
func (c CertificateStore) ResetCache() {
func (c *CertificateStore) ResetCache() {
if c.CertCache != nil {
c.CertCache.Flush()
}

View file

@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
# example new bugfix v3.1.7
CurrentRef = "v3.1"
PreviousRef = "v3.1.6"
BaseBranch = "v3.1"
FutureCurrentRefName = "v3.1.7"
# example new bugfix v3.2.1
CurrentRef = "v3.2"
PreviousRef = "v3.2.0"
BaseBranch = "v3.2"
FutureCurrentRefName = "v3.2.1"
ThresholdPreviousRef = 10
ThresholdCurrentRef = 10