mirror of
https://github.com/traefik/traefik.git
synced 2025-05-05 15:33:01 +00:00
Merge branch v3.3 into master
This commit is contained in:
commit
ec38a0675f
38
CHANGELOG.md
38
CHANGELOG.md
@ -1,3 +1,41 @@
|
|||||||
|
## [v3.3.5](https://github.com/traefik/traefik/tree/v3.3.5) (2025-03-31)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.4...v3.3.5)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[k8s/gatewayapi]** Set scheme to https with BackendTLSPolicy ([#11586](https://github.com/traefik/traefik/pull/11586) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[middleware]** Revert compress middleware algorithms priority to v2 behavior ([#11641](https://github.com/traefik/traefik/pull/11641) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[middleware]** Do not abort request when response content-type is malformed ([#11628](https://github.com/traefik/traefik/pull/11628) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[middleware]** Compress data on flush when compression is not started ([#11583](https://github.com/traefik/traefik/pull/11583) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[middleware]** Add back forwarded headers section in FAQ ([#11606](https://github.com/traefik/traefik/pull/11606) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- New Routing Reference Documentation ([#11330](https://github.com/traefik/traefik/pull/11330) by [sheddy-traefik](https://github.com/sheddy-traefik))
|
||||||
|
|
||||||
|
**Misc:**
|
||||||
|
- Merge branch v2.11 into v3.3 ([#11644](https://github.com/traefik/traefik/pull/11644) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Merge branch v2.11 into v3.3 ([#11594](https://github.com/traefik/traefik/pull/11594) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
|
## [v2.11.22](https://github.com/traefik/traefik/tree/v2.11.22) (2025-03-31)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.11.21...v2.11.22)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[ecs,logs]** Bump AWS SDK to v2 ([#11359](https://github.com/traefik/traefik/pull/11359) by [Juneezee](https://github.com/Juneezee))
|
||||||
|
- **[logs,tls]** Error level log for configuration-related TLS errors with backends ([#11611](https://github.com/traefik/traefik/pull/11611) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[rules]** Allow underscore character in HostSNI matcher ([#11557](https://github.com/traefik/traefik/pull/11557) by [rohitlohar45](https://github.com/rohitlohar45))
|
||||||
|
- **[server]** Bump github.com/vulcand/oxy/v2 to v2.0.3 ([#11649](https://github.com/traefik/traefik/pull/11649) by [adamvduke](https://github.com/adamvduke))
|
||||||
|
- **[server]** Bump golang.org/x/net to v0.37.0 ([#11632](https://github.com/traefik/traefik/pull/11632) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- **[webui]** Change boolean module properties default value to undefined ([#11639](https://github.com/traefik/traefik/pull/11639) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- Bump github.com/golang-jwt/jwt to v4.5.2 and v5.2.2 ([#11634](https://github.com/traefik/traefik/pull/11634) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Bump github.com/redis/go-redis/v9 to v9.6.3 ([#11633](https://github.com/traefik/traefik/pull/11633) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Bump golang.org/x/net to v0.36.0 ([#11608](https://github.com/traefik/traefik/pull/11608) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
- Bump github.com/go-jose/go-jose/v4 to v4.0.5 ([#11571](https://github.com/traefik/traefik/pull/11571) by [kevinpollet](https://github.com/kevinpollet))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[accesslogs]** Remove documentation for OriginStatusLine and DownstreamStatusLine accessLogs fields ([#11599](https://github.com/traefik/traefik/pull/11599) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
- **[middleware]** Clarifies that retry middleware uses TCP, not HTTP status codes ([#11603](https://github.com/traefik/traefik/pull/11603) by [geraldcroes](https://github.com/geraldcroes))
|
||||||
|
- **[redis]** Add tip for dynamic configuration updates of Redis ([#11577](https://github.com/traefik/traefik/pull/11577) by [Alanxtl](https://github.com/Alanxtl))
|
||||||
|
- Add Security Support ([#11610](https://github.com/traefik/traefik/pull/11610) by [nmengin](https://github.com/nmengin))
|
||||||
|
|
||||||
## [v3.3.4](https://github.com/traefik/traefik/tree/v3.3.4) (2025-02-25)
|
## [v3.3.4](https://github.com/traefik/traefik/tree/v3.3.4) (2025-02-25)
|
||||||
[All Commits](https://github.com/traefik/traefik/compare/v3.3.3...v3.3.4)
|
[All Commits](https://github.com/traefik/traefik/compare/v3.3.3...v3.3.4)
|
||||||
|
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
"github.com/traefik/traefik/v3/cmd"
|
"github.com/traefik/traefik/v3/cmd"
|
||||||
"github.com/traefik/traefik/v3/cmd/healthcheck"
|
"github.com/traefik/traefik/v3/cmd/healthcheck"
|
||||||
cmdVersion "github.com/traefik/traefik/v3/cmd/version"
|
cmdVersion "github.com/traefik/traefik/v3/cmd/version"
|
||||||
_ "github.com/traefik/traefik/v3/init"
|
|
||||||
tcli "github.com/traefik/traefik/v3/pkg/cli"
|
tcli "github.com/traefik/traefik/v3/pkg/cli"
|
||||||
"github.com/traefik/traefik/v3/pkg/collector"
|
"github.com/traefik/traefik/v3/pkg/collector"
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
|
@ -14,8 +14,8 @@ RUN apk --no-cache --no-progress add \
|
|||||||
ruby-json \
|
ruby-json \
|
||||||
zlib-dev
|
zlib-dev
|
||||||
|
|
||||||
RUN gem install nokogiri --version 1.16.8 --no-document -- --use-system-libraries
|
RUN gem install nokogiri --version 1.18.6 --no-document -- --use-system-libraries
|
||||||
RUN gem install html-proofer --version 5.0.7 --no-document -- --use-system-libraries
|
RUN gem install html-proofer --version 5.0.10 --no-document -- --use-system-libraries
|
||||||
|
|
||||||
# After Ruby, some NodeJS YAY!
|
# After Ruby, some NodeJS YAY!
|
||||||
RUN apk --no-cache --no-progress add \
|
RUN apk --no-cache --no-progress add \
|
||||||
|
@ -4,25 +4,31 @@
|
|||||||
|
|
||||||
Below is a non-exhaustive list of versions and their maintenance status:
|
Below is a non-exhaustive list of versions and their maintenance status:
|
||||||
|
|
||||||
| Version | Release Date | Community Support |
|
| Version | Release Date | Active Support | Security Support |
|
||||||
|---------|--------------|--------------------|
|
|---------|--------------|--------------------|-------------------|
|
||||||
| 3.3 | Jan 06, 2025 | Yes |
|
| 3.3 | Jan 06, 2025 | Yes | Yes |
|
||||||
| 3.2 | Oct 28, 2024 | Ended Jan 06, 2025 |
|
| 3.2 | Oct 28, 2024 | Ended Jan 06, 2025 | No |
|
||||||
| 3.1 | Jul 15, 2024 | Ended Oct 28, 2024 |
|
| 3.1 | Jul 15, 2024 | Ended Oct 28, 2024 | No |
|
||||||
| 3.0 | Apr 29, 2024 | Ended Jul 15, 2024 |
|
| 3.0 | Apr 29, 2024 | Ended Jul 15, 2024 | No |
|
||||||
| 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 |
|
| 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 | Ends Feb 01, 2026 |
|
||||||
| 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 |
|
| 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 | No |
|
||||||
| 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 |
|
| 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 | No |
|
||||||
| 2.8 | Jun 29, 2022 | Ended Oct 03, 2022 |
|
| 2.8 | Jun 29, 2022 | Ended Oct 03, 2022 | No |
|
||||||
| 2.7 | May 24, 2022 | Ended Jun 29, 2022 |
|
| 2.7 | May 24, 2022 | Ended Jun 29, 2022 | No |
|
||||||
| 2.6 | Jan 24, 2022 | Ended May 24, 2022 |
|
| 2.6 | Jan 24, 2022 | Ended May 24, 2022 | No |
|
||||||
| 2.5 | Aug 17, 2021 | Ended Jan 24, 2022 |
|
| 2.5 | Aug 17, 2021 | Ended Jan 24, 2022 | No |
|
||||||
| 2.4 | Jan 19, 2021 | Ended Aug 17, 2021 |
|
| 2.4 | Jan 19, 2021 | Ended Aug 17, 2021 | No |
|
||||||
| 2.3 | Sep 23, 2020 | Ended Jan 19, 2021 |
|
| 2.3 | Sep 23, 2020 | Ended Jan 19, 2021 | No |
|
||||||
| 2.2 | Mar 25, 2020 | Ended Sep 23, 2020 |
|
| 2.2 | Mar 25, 2020 | Ended Sep 23, 2020 | No |
|
||||||
| 2.1 | Dec 11, 2019 | Ended Mar 25, 2020 |
|
| 2.1 | Dec 11, 2019 | Ended Mar 25, 2020 | No |
|
||||||
| 2.0 | Sep 16, 2019 | Ended Dec 11, 2019 |
|
| 2.0 | Sep 16, 2019 | Ended Dec 11, 2019 | No |
|
||||||
| 1.7 | Sep 24, 2018 | Ended Dec 31, 2021 |
|
| 1.7 | Sep 24, 2018 | Ended Dec 31, 2021 | No |
|
||||||
|
|
||||||
|
??? example "Active Support / Security Support"
|
||||||
|
|
||||||
|
- **Active support**: Receives any bug fixes.
|
||||||
|
|
||||||
|
- **Security support**: Receives only critical bug and security fixes.
|
||||||
|
|
||||||
This page is maintained and updated periodically to reflect our roadmap and any decisions affecting the end of support for Traefik Proxy.
|
This page is maintained and updated periodically to reflect our roadmap and any decisions affecting the end of support for Traefik Proxy.
|
||||||
|
|
||||||
|
@ -143,6 +143,21 @@ To take into account the new certificate contents, the update of the dynamic con
|
|||||||
One way to achieve that, is to trigger a file notification,
|
One way to achieve that, is to trigger a file notification,
|
||||||
for example, by using the `touch` command on the configuration file.
|
for example, by using the `touch` command on the configuration file.
|
||||||
|
|
||||||
|
## What Are the Forwarded Headers When Proxying HTTP Requests?
|
||||||
|
|
||||||
|
By default, the following headers are automatically added when proxying requests:
|
||||||
|
|
||||||
|
| Property | HTTP Header |
|
||||||
|
|---------------------------|----------------------------|
|
||||||
|
| Client's IP | X-Forwarded-For, X-Real-Ip |
|
||||||
|
| Host | X-Forwarded-Host |
|
||||||
|
| Port | X-Forwarded-Port |
|
||||||
|
| Protocol | X-Forwarded-Proto |
|
||||||
|
| Proxy Server's Hostname | X-Forwarded-Server |
|
||||||
|
|
||||||
|
For more details,
|
||||||
|
please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation.
|
||||||
|
|
||||||
## How Traefik is Storing and Serving TLS Certificates?
|
## How Traefik is Storing and Serving TLS Certificates?
|
||||||
|
|
||||||
### Storing TLS Certificates
|
### Storing TLS Certificates
|
||||||
|
@ -264,10 +264,10 @@ http:
|
|||||||
|
|
||||||
### `encodings`
|
### `encodings`
|
||||||
|
|
||||||
_Optional, Default="zstd, br, gzip"_
|
_Optional, Default="gzip, br, zstd"_
|
||||||
|
|
||||||
`encodings` specifies the list of supported compression encodings.
|
`encodings` specifies the list of supported compression encodings.
|
||||||
At least one encoding value must be specified, and valid entries are `zstd` (Zstandard), `br` (Brotli), and `gzip` (Gzip).
|
At least one encoding value must be specified, and valid entries are `gzip` (Gzip), `br` (Brotli), and `zstd` (Zstandard).
|
||||||
The order of the list also sets the priority, the top entry has the highest priority.
|
The order of the list also sets the priority, the top entry has the highest priority.
|
||||||
|
|
||||||
```yaml tab="Docker & Swarm"
|
```yaml tab="Docker & Swarm"
|
||||||
|
@ -12,8 +12,11 @@ Retrying until it Succeeds
|
|||||||
TODO: add schema
|
TODO: add schema
|
||||||
-->
|
-->
|
||||||
|
|
||||||
The Retry middleware reissues requests a given number of times to a backend server if that server does not reply.
|
The Retry middleware reissues requests a given number of times when it cannot contact the backend service.
|
||||||
As soon as the server answers, the middleware stops retrying, regardless of the response status.
|
This applies at the transport level (TCP).
|
||||||
|
If the service does not respond to the initial connection attempt, the middleware retries.
|
||||||
|
However, once the service responds, regardless of the HTTP status code, the middleware considers it operational and stops retrying.
|
||||||
|
This means that the retry mechanism does not handle HTTP errors; it only retries when there is no response at the TCP level.
|
||||||
The Retry middleware has an optional configuration to enable an exponential backoff.
|
The Retry middleware has an optional configuration to enable an exponential backoff.
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
@ -188,6 +188,16 @@ and will be removed in the next major version.
|
|||||||
In `v3.3.4`, the OpenTelemetry Request Duration metric (named `traefik_(entrypoint|router|service)_request_duration_seconds`) unit has been changed from milliseconds to seconds.
|
In `v3.3.4`, the OpenTelemetry Request Duration metric (named `traefik_(entrypoint|router|service)_request_duration_seconds`) unit has been changed from milliseconds to seconds.
|
||||||
To be consistent with the naming and other metrics providers, the metric now reports the duration in seconds.
|
To be consistent with the naming and other metrics providers, the metric now reports the duration in seconds.
|
||||||
|
|
||||||
|
## v3.3.5
|
||||||
|
|
||||||
|
### Compress Middleware
|
||||||
|
|
||||||
|
In `v3.3.5`, the compress middleware `encodings` option default value is now `gzip, br, zstd`.
|
||||||
|
This change helps the algorithm selection to favor the `gzip` algorithm over the other algorithms.
|
||||||
|
|
||||||
|
It impacts requests that do not specify their preferred algorithm,
|
||||||
|
or has no order preference, in the `Accept-Encoding` header.
|
||||||
|
|
||||||
## v3.3 to v3.4
|
## v3.3 to v3.4
|
||||||
|
|
||||||
### Kubernetes CRD Provider
|
### Kubernetes CRD Provider
|
||||||
|
@ -256,9 +256,7 @@ accessLog:
|
|||||||
| `OriginDuration` | The time taken (in nanoseconds) by the origin server ('upstream') to return its response. |
|
| `OriginDuration` | The time taken (in nanoseconds) by the origin server ('upstream') to return its response. |
|
||||||
| `OriginContentSize` | The content length specified by the origin server, or 0 if unspecified. |
|
| `OriginContentSize` | The content length specified by the origin server, or 0 if unspecified. |
|
||||||
| `OriginStatus` | The HTTP status code returned by the origin server. If the request was handled by this Traefik instance (e.g. with a redirect), then this value will be absent (0). |
|
| `OriginStatus` | The HTTP status code returned by the origin server. If the request was handled by this Traefik instance (e.g. with a redirect), then this value will be absent (0). |
|
||||||
| `OriginStatusLine` | `OriginStatus` + Status code explanation |
|
|
||||||
| `DownstreamStatus` | The HTTP status code returned to the client. |
|
| `DownstreamStatus` | The HTTP status code returned to the client. |
|
||||||
| `DownstreamStatusLine` | `DownstreamStatus` + Status code explanation |
|
|
||||||
| `DownstreamContentSize` | The number of bytes in the response entity returned to the client. This is in addition to the "Content-Length" header, which may be present in the origin response. |
|
| `DownstreamContentSize` | The number of bytes in the response entity returned to the client. This is in addition to the "Content-Length" header, which may be present in the origin response. |
|
||||||
| `RequestCount` | The number of requests received since the Traefik instance started. |
|
| `RequestCount` | The number of requests received since the Traefik instance started. |
|
||||||
| `GzipRatio` | The response body compression ratio achieved. |
|
| `GzipRatio` | The response body compression ratio achieved. |
|
||||||
|
22
go.mod
22
go.mod
@ -29,7 +29,7 @@ require (
|
|||||||
github.com/golang/protobuf v1.5.4
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/google/go-github/v28 v28.1.1
|
github.com/google/go-github/v28 v28.1.1
|
||||||
github.com/gorilla/mux v1.8.1
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.3
|
||||||
github.com/hashicorp/consul/api v1.26.1
|
github.com/hashicorp/consul/api v1.26.1
|
||||||
github.com/hashicorp/go-hclog v1.6.3
|
github.com/hashicorp/go-hclog v1.6.3
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
@ -75,7 +75,7 @@ require (
|
|||||||
github.com/unrolled/render v1.0.2
|
github.com/unrolled/render v1.0.2
|
||||||
github.com/unrolled/secure v1.0.9
|
github.com/unrolled/secure v1.0.9
|
||||||
github.com/valyala/fasthttp v1.58.0
|
github.com/valyala/fasthttp v1.58.0
|
||||||
github.com/vulcand/oxy/v2 v2.0.0
|
github.com/vulcand/oxy/v2 v2.0.3
|
||||||
github.com/vulcand/predicate v1.2.0
|
github.com/vulcand/predicate v1.2.0
|
||||||
github.com/yuin/gopher-lua v1.1.1
|
github.com/yuin/gopher-lua v1.1.1
|
||||||
go.opentelemetry.io/collector/pdata v1.10.0
|
go.opentelemetry.io/collector/pdata v1.10.0
|
||||||
@ -96,10 +96,10 @@ require (
|
|||||||
go.opentelemetry.io/otel/sdk/metric v1.28.0
|
go.opentelemetry.io/otel/sdk/metric v1.28.0
|
||||||
go.opentelemetry.io/otel/trace v1.32.0
|
go.opentelemetry.io/otel/trace v1.32.0
|
||||||
golang.org/x/mod v0.22.0
|
golang.org/x/mod v0.22.0
|
||||||
golang.org/x/net v0.33.0
|
golang.org/x/net v0.37.0
|
||||||
golang.org/x/sync v0.10.0
|
golang.org/x/sync v0.12.0
|
||||||
golang.org/x/sys v0.29.0
|
golang.org/x/sys v0.31.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.23.0
|
||||||
golang.org/x/time v0.8.0
|
golang.org/x/time v0.8.0
|
||||||
golang.org/x/tools v0.28.0
|
golang.org/x/tools v0.28.0
|
||||||
google.golang.org/grpc v1.67.1
|
google.golang.org/grpc v1.67.1
|
||||||
@ -210,8 +210,8 @@ require (
|
|||||||
github.com/goccy/go-json v0.10.4 // indirect
|
github.com/goccy/go-json v0.10.4 // indirect
|
||||||
github.com/gofrs/flock v0.12.1 // indirect
|
github.com/gofrs/flock v0.12.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
@ -290,6 +290,7 @@ require (
|
|||||||
github.com/nrdcg/nodion v0.1.0 // indirect
|
github.com/nrdcg/nodion v0.1.0 // indirect
|
||||||
github.com/nrdcg/porkbun v0.4.0 // indirect
|
github.com/nrdcg/porkbun v0.4.0 // indirect
|
||||||
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
github.com/nzdjb/go-metaname v1.0.0 // indirect
|
||||||
|
github.com/onsi/ginkgo v1.16.5 // indirect
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
@ -357,15 +358,16 @@ require (
|
|||||||
go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 // indirect
|
go.opentelemetry.io/contrib/propagators/jaeger v1.28.0 // indirect
|
||||||
go.opentelemetry.io/contrib/propagators/ot v1.28.0 // indirect
|
go.opentelemetry.io/contrib/propagators/ot v1.28.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/ratelimit v0.3.0 // indirect
|
go.uber.org/ratelimit v0.3.0 // indirect
|
||||||
go.uber.org/zap v1.26.0 // indirect
|
go.uber.org/zap v1.26.0 // indirect
|
||||||
golang.org/x/arch v0.4.0 // indirect
|
golang.org/x/arch v0.4.0 // indirect
|
||||||
golang.org/x/crypto v0.32.0 // indirect
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
|
||||||
golang.org/x/oauth2 v0.24.0 // indirect
|
golang.org/x/oauth2 v0.24.0 // indirect
|
||||||
golang.org/x/term v0.28.0 // indirect
|
golang.org/x/term v0.30.0 // indirect
|
||||||
google.golang.org/api v0.214.0 // indirect
|
google.golang.org/api v0.214.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect
|
||||||
|
46
go.sum
46
go.sum
@ -452,10 +452,10 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq
|
|||||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
@ -561,8 +561,8 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+
|
|||||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf h1:C1GPyPJrOlJlIrcaBBiBpDsqZena2Ks8spa5xZqr1XQ=
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf h1:C1GPyPJrOlJlIrcaBBiBpDsqZena2Ks8spa5xZqr1XQ=
|
||||||
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA=
|
github.com/gravitational/trace v1.1.16-0.20220114165159-14a9a7dd6aaf/go.mod h1:zXqxTI6jXDdKnlf8s+nT+3c8LrwUEy3yNpO4XJL90lA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
@ -929,8 +929,9 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
|||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||||
@ -1230,8 +1231,8 @@ github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4
|
|||||||
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
|
github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
|
github.com/volcengine/volc-sdk-golang v1.0.189 h1:VMDTHWYXakXJtZqPYn0As/h4eB0c4imvyru6mIp+o60=
|
||||||
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
|
github.com/volcengine/volc-sdk-golang v1.0.189/go.mod h1:u0VtPvlXWpXDTmc9IHkaW1q+5Jjwus4oAqRhNMDRInE=
|
||||||
github.com/vulcand/oxy/v2 v2.0.0 h1:V+scHhd2xBjO8ojBRgxCM+OdZxRA/YTs8M70w5tdNy8=
|
github.com/vulcand/oxy/v2 v2.0.3 h1:CPWVPfW4hVZXzwwiQzpFidbnJKpahjPHezM+7TkZRNw=
|
||||||
github.com/vulcand/oxy/v2 v2.0.0/go.mod h1:uIAz3sYafO7i+V3SC8oDlMn/lt1i9aWcyXuXqVswKzE=
|
github.com/vulcand/oxy/v2 v2.0.3/go.mod h1:k3t+xjyqmXVh88FdFDbYmUKMEvNpaejvBW14es6H70A=
|
||||||
github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50=
|
github.com/vulcand/predicate v1.2.0 h1:uFsW1gcnnR7R+QTID+FVcs0sSYlIGntoGOTb3rQJt50=
|
||||||
github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA=
|
github.com/vulcand/predicate v1.2.0/go.mod h1:VipoNYXny6c8N381zGUWkjuuNHiRbeAZhE7Qm9c+2GA=
|
||||||
github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
|
github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8=
|
||||||
@ -1335,8 +1336,9 @@ go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeX
|
|||||||
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
|
||||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
@ -1390,8 +1392,8 @@ golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIi
|
|||||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
@ -1492,8 +1494,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
|||||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -1515,8 +1517,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -1607,8 +1609,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@ -1619,8 +1621,8 @@ golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
|||||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
|
||||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@ -1637,8 +1639,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
|||||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
21
init/init.go
21
init/init.go
@ -1,21 +0,0 @@
|
|||||||
package init
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This makes use of the GODEBUG flag `http2xconnect` to deactivate the connect setting for HTTP2 by default.
|
|
||||||
// This type of upgrade is yet incompatible with `net/http` http1 reverse proxy.
|
|
||||||
// Please see https://github.com/golang/go/issues/71128#issuecomment-2574193636.
|
|
||||||
func init() {
|
|
||||||
goDebug := os.Getenv("GODEBUG")
|
|
||||||
if strings.Contains(goDebug, "http2xconnect") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(goDebug) > 0 {
|
|
||||||
goDebug += ","
|
|
||||||
}
|
|
||||||
os.Setenv("GODEBUG", goDebug+"http2xconnect=0")
|
|
||||||
}
|
|
@ -190,7 +190,7 @@ type Compress struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compress) SetDefaults() {
|
func (c *Compress) SetDefaults() {
|
||||||
c.Encodings = []string{"zstd", "br", "gzip"}
|
c.Encodings = []string{"gzip", "br", "zstd"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
@ -23,57 +23,44 @@ type Encoding struct {
|
|||||||
Weight float64
|
Weight float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCompressionEncoding(acceptEncoding []string, defaultEncoding string, supportedEncodings []string) string {
|
func (c *compress) getCompressionEncoding(acceptEncoding []string) string {
|
||||||
if defaultEncoding == "" {
|
// RFC says: An Accept-Encoding header field with a field value that is empty implies that the user agent does not want any content coding in response.
|
||||||
if slices.Contains(supportedEncodings, brotliName) {
|
// https://datatracker.ietf.org/doc/html/rfc9110#name-accept-encoding
|
||||||
// Keeps the pre-existing default inside Traefik if brotli is a supported encoding.
|
if len(acceptEncoding) == 1 && acceptEncoding[0] == "" {
|
||||||
defaultEncoding = brotliName
|
|
||||||
} else if len(supportedEncodings) > 0 {
|
|
||||||
// Otherwise use the first supported encoding.
|
|
||||||
defaultEncoding = supportedEncodings[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
encodings, hasWeight := parseAcceptEncoding(acceptEncoding, supportedEncodings)
|
|
||||||
|
|
||||||
if hasWeight {
|
|
||||||
if len(encodings) == 0 {
|
|
||||||
return identityName
|
return identityName
|
||||||
}
|
}
|
||||||
|
|
||||||
encoding := encodings[0]
|
acceptableEncodings := parseAcceptableEncodings(acceptEncoding, c.supportedEncodings)
|
||||||
|
|
||||||
if encoding.Type == identityName && encoding.Weight == 0 {
|
// An empty Accept-Encoding header field would have been handled earlier.
|
||||||
|
// If empty, it means no encoding is supported, we do not encode.
|
||||||
|
if len(acceptableEncodings) == 0 {
|
||||||
|
// TODO: return 415 status code instead of deactivating the compression, if the backend was not to compress as well.
|
||||||
return notAcceptable
|
return notAcceptable
|
||||||
}
|
}
|
||||||
|
|
||||||
if encoding.Type == wildcardName && encoding.Weight == 0 {
|
slices.SortFunc(acceptableEncodings, func(a, b Encoding) int {
|
||||||
return notAcceptable
|
if a.Weight == b.Weight {
|
||||||
|
// At same weight, we want to prioritize based on the encoding priority.
|
||||||
|
// the lower the index, the higher the priority.
|
||||||
|
return cmp.Compare(c.supportedEncodings[a.Type], c.supportedEncodings[b.Type])
|
||||||
|
}
|
||||||
|
return cmp.Compare(b.Weight, a.Weight)
|
||||||
|
})
|
||||||
|
|
||||||
|
if acceptableEncodings[0].Type == wildcardName {
|
||||||
|
if c.defaultEncoding == "" {
|
||||||
|
return c.encodings[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
if encoding.Type == wildcardName {
|
return c.defaultEncoding
|
||||||
return defaultEncoding
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return encoding.Type
|
return acceptableEncodings[0].Type
|
||||||
}
|
|
||||||
|
|
||||||
for _, dt := range supportedEncodings {
|
|
||||||
if slices.ContainsFunc(encodings, func(e Encoding) bool { return e.Type == dt }) {
|
|
||||||
return dt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if slices.ContainsFunc(encodings, func(e Encoding) bool { return e.Type == wildcardName }) {
|
|
||||||
return defaultEncoding
|
|
||||||
}
|
|
||||||
|
|
||||||
return identityName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseAcceptEncoding(acceptEncoding, supportedEncodings []string) ([]Encoding, bool) {
|
func parseAcceptableEncodings(acceptEncoding []string, supportedEncodings map[string]int) []Encoding {
|
||||||
var encodings []Encoding
|
var encodings []Encoding
|
||||||
var hasWeight bool
|
|
||||||
|
|
||||||
for _, line := range acceptEncoding {
|
for _, line := range acceptEncoding {
|
||||||
for _, item := range strings.Split(strings.ReplaceAll(line, " ", ""), ",") {
|
for _, item := range strings.Split(strings.ReplaceAll(line, " ", ""), ",") {
|
||||||
@ -82,9 +69,7 @@ func parseAcceptEncoding(acceptEncoding, supportedEncodings []string) ([]Encodin
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(supportedEncodings, parsed[0]) &&
|
if _, ok := supportedEncodings[parsed[0]]; !ok {
|
||||||
parsed[0] != identityName &&
|
|
||||||
parsed[0] != wildcardName {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +79,13 @@ func parseAcceptEncoding(acceptEncoding, supportedEncodings []string) ([]Encodin
|
|||||||
if len(parsed) > 1 && strings.HasPrefix(parsed[1], "q=") {
|
if len(parsed) > 1 && strings.HasPrefix(parsed[1], "q=") {
|
||||||
w, _ := strconv.ParseFloat(strings.TrimPrefix(parsed[1], "q="), 64)
|
w, _ := strconv.ParseFloat(strings.TrimPrefix(parsed[1], "q="), 64)
|
||||||
|
|
||||||
|
// If the weight is 0, the encoding is not acceptable.
|
||||||
|
// We can skip the encoding.
|
||||||
|
if w == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
weight = w
|
weight = w
|
||||||
hasWeight = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
encodings = append(encodings, Encoding{
|
encodings = append(encodings, Encoding{
|
||||||
@ -105,9 +95,5 @@ func parseAcceptEncoding(acceptEncoding, supportedEncodings []string) ([]Encodin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.SortFunc(encodings, func(a, b Encoding) int {
|
return encodings
|
||||||
return cmp.Compare(b.Weight, a.Weight)
|
|
||||||
})
|
|
||||||
|
|
||||||
return encodings, hasWeight
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package compress
|
package compress
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_getCompressionEncoding(t *testing.T) {
|
func Test_getCompressionEncoding(t *testing.T) {
|
||||||
@ -15,14 +18,19 @@ func Test_getCompressionEncoding(t *testing.T) {
|
|||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "br > gzip (no weight)",
|
desc: "Empty Accept-Encoding",
|
||||||
acceptEncoding: []string{"gzip, br"},
|
acceptEncoding: []string{""},
|
||||||
expected: brotliName,
|
expected: identityName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "zstd > br > gzip (no weight)",
|
desc: "gzip > br (no weight)",
|
||||||
acceptEncoding: []string{"zstd, gzip, br"},
|
acceptEncoding: []string{"gzip, br"},
|
||||||
expected: zstdName,
|
expected: gzipName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "gzip > br > zstd (no weight)",
|
||||||
|
acceptEncoding: []string{"gzip, br, zstd"},
|
||||||
|
expected: gzipName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "known compression encoding (no weight)",
|
desc: "known compression encoding (no weight)",
|
||||||
@ -32,24 +40,34 @@ func Test_getCompressionEncoding(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "unknown compression encoding (no weight), no encoding",
|
desc: "unknown compression encoding (no weight), no encoding",
|
||||||
acceptEncoding: []string{"compress, rar"},
|
acceptEncoding: []string{"compress, rar"},
|
||||||
expected: identityName,
|
expected: notAcceptable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "wildcard return the default compression encoding",
|
desc: "wildcard returns the default compression encoding",
|
||||||
acceptEncoding: []string{"*"},
|
acceptEncoding: []string{"*"},
|
||||||
|
expected: gzipName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "wildcard returns the custom default compression encoding",
|
||||||
|
acceptEncoding: []string{"*"},
|
||||||
|
defaultEncoding: brotliName,
|
||||||
expected: brotliName,
|
expected: brotliName,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
desc: "wildcard return the custom default compression encoding",
|
|
||||||
acceptEncoding: []string{"*"},
|
|
||||||
defaultEncoding: "foo",
|
|
||||||
expected: "foo",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
desc: "follows weight",
|
desc: "follows weight",
|
||||||
acceptEncoding: []string{"br;q=0.8, gzip;q=1.0, *;q=0.1"},
|
acceptEncoding: []string{"br;q=0.8, gzip;q=1.0, *;q=0.1"},
|
||||||
expected: gzipName,
|
expected: gzipName,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "identity with higher weight is preferred",
|
||||||
|
acceptEncoding: []string{"br;q=0.8, identity;q=1.0"},
|
||||||
|
expected: identityName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "identity with equal weight is not preferred",
|
||||||
|
acceptEncoding: []string{"br;q=0.8, identity;q=0.8"},
|
||||||
|
expected: brotliName,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "ignore unknown compression encoding",
|
desc: "ignore unknown compression encoding",
|
||||||
acceptEncoding: []string{"compress;q=1.0, gzip;q=0.5"},
|
acceptEncoding: []string{"compress;q=1.0, gzip;q=0.5"},
|
||||||
@ -93,6 +111,33 @@ func Test_getCompressionEncoding(t *testing.T) {
|
|||||||
supportedEncodings: []string{gzipName, brotliName},
|
supportedEncodings: []string{gzipName, brotliName},
|
||||||
expected: gzipName,
|
expected: gzipName,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Zero weights, no compression",
|
||||||
|
acceptEncoding: []string{"br;q=0, gzip;q=0, zstd;q=0"},
|
||||||
|
expected: notAcceptable,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Zero weights, default encoding, no compression",
|
||||||
|
acceptEncoding: []string{"br;q=0, gzip;q=0, zstd;q=0"},
|
||||||
|
defaultEncoding: "br",
|
||||||
|
expected: notAcceptable,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Same weight, first supported encoding",
|
||||||
|
acceptEncoding: []string{"br;q=1.0, gzip;q=1.0, zstd;q=1.0"},
|
||||||
|
expected: gzipName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Same weight, first supported encoding, order has no effect",
|
||||||
|
acceptEncoding: []string{"br;q=1.0, zstd;q=1.0, gzip;q=1.0"},
|
||||||
|
expected: gzipName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Same weight, first supported encoding, defaultEncoding has no effect",
|
||||||
|
acceptEncoding: []string{"br;q=1.0, zstd;q=1.0, gzip;q=1.0"},
|
||||||
|
defaultEncoding: "br",
|
||||||
|
expected: gzipName,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
@ -103,7 +148,18 @@ func Test_getCompressionEncoding(t *testing.T) {
|
|||||||
test.supportedEncodings = defaultSupportedEncodings
|
test.supportedEncodings = defaultSupportedEncodings
|
||||||
}
|
}
|
||||||
|
|
||||||
encoding := getCompressionEncoding(test.acceptEncoding, test.defaultEncoding, test.supportedEncodings)
|
conf := dynamic.Compress{
|
||||||
|
Encodings: test.supportedEncodings,
|
||||||
|
DefaultEncoding: test.defaultEncoding,
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := New(context.Background(), nil, conf, "test")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
c, ok := h.(*compress)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
encoding := c.getCompressionEncoding(test.acceptEncoding)
|
||||||
|
|
||||||
assert.Equal(t, test.expected, encoding)
|
assert.Equal(t, test.expected, encoding)
|
||||||
})
|
})
|
||||||
@ -147,7 +203,6 @@ func Test_parseAcceptEncoding(t *testing.T) {
|
|||||||
{Type: zstdName, Weight: 1},
|
{Type: zstdName, Weight: 1},
|
||||||
{Type: gzipName, Weight: 1},
|
{Type: gzipName, Weight: 1},
|
||||||
{Type: brotliName, Weight: 1},
|
{Type: brotliName, Weight: 1},
|
||||||
{Type: wildcardName, Weight: 0},
|
|
||||||
},
|
},
|
||||||
assertWeight: assert.True,
|
assertWeight: assert.True,
|
||||||
},
|
},
|
||||||
@ -157,7 +212,6 @@ func Test_parseAcceptEncoding(t *testing.T) {
|
|||||||
supportedEncodings: []string{zstdName},
|
supportedEncodings: []string{zstdName},
|
||||||
expected: []Encoding{
|
expected: []Encoding{
|
||||||
{Type: zstdName, Weight: 1},
|
{Type: zstdName, Weight: 1},
|
||||||
{Type: wildcardName, Weight: 0},
|
|
||||||
},
|
},
|
||||||
assertWeight: assert.True,
|
assertWeight: assert.True,
|
||||||
},
|
},
|
||||||
@ -188,7 +242,6 @@ func Test_parseAcceptEncoding(t *testing.T) {
|
|||||||
expected: []Encoding{
|
expected: []Encoding{
|
||||||
{Type: gzipName, Weight: 1},
|
{Type: gzipName, Weight: 1},
|
||||||
{Type: identityName, Weight: 0.5},
|
{Type: identityName, Weight: 0.5},
|
||||||
{Type: wildcardName, Weight: 0},
|
|
||||||
},
|
},
|
||||||
assertWeight: assert.True,
|
assertWeight: assert.True,
|
||||||
},
|
},
|
||||||
@ -198,7 +251,6 @@ func Test_parseAcceptEncoding(t *testing.T) {
|
|||||||
supportedEncodings: []string{"br"},
|
supportedEncodings: []string{"br"},
|
||||||
expected: []Encoding{
|
expected: []Encoding{
|
||||||
{Type: identityName, Weight: 0.5},
|
{Type: identityName, Weight: 0.5},
|
||||||
{Type: wildcardName, Weight: 0},
|
|
||||||
},
|
},
|
||||||
assertWeight: assert.True,
|
assertWeight: assert.True,
|
||||||
},
|
},
|
||||||
@ -212,10 +264,11 @@ func Test_parseAcceptEncoding(t *testing.T) {
|
|||||||
test.supportedEncodings = defaultSupportedEncodings
|
test.supportedEncodings = defaultSupportedEncodings
|
||||||
}
|
}
|
||||||
|
|
||||||
aes, hasWeight := parseAcceptEncoding(test.values, test.supportedEncodings)
|
supportedEncodings := buildSupportedEncodings(test.supportedEncodings)
|
||||||
|
|
||||||
|
aes := parseAcceptableEncodings(test.values, supportedEncodings)
|
||||||
|
|
||||||
assert.Equal(t, test.expected, aes)
|
assert.Equal(t, test.expected, aes)
|
||||||
test.assertWeight(t, hasWeight)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ const typeName = "Compress"
|
|||||||
// See https://github.com/klauspost/compress/blob/9559b037e79ad673c71f6ef7c732c00949014cd2/gzhttp/compress.go#L47.
|
// See https://github.com/klauspost/compress/blob/9559b037e79ad673c71f6ef7c732c00949014cd2/gzhttp/compress.go#L47.
|
||||||
const defaultMinSize = 1024
|
const defaultMinSize = 1024
|
||||||
|
|
||||||
var defaultSupportedEncodings = []string{zstdName, brotliName, gzipName}
|
var defaultSupportedEncodings = []string{gzipName, brotliName, zstdName}
|
||||||
|
|
||||||
// Compress is a middleware that allows to compress the response.
|
// Compress is a middleware that allows to compress the response.
|
||||||
type compress struct {
|
type compress struct {
|
||||||
@ -33,6 +33,8 @@ type compress struct {
|
|||||||
minSize int
|
minSize int
|
||||||
encodings []string
|
encodings []string
|
||||||
defaultEncoding string
|
defaultEncoding string
|
||||||
|
// supportedEncodings is a map of supported encodings and their priority.
|
||||||
|
supportedEncodings map[string]int
|
||||||
|
|
||||||
brotliHandler http.Handler
|
brotliHandler http.Handler
|
||||||
gzipHandler http.Handler
|
gzipHandler http.Handler
|
||||||
@ -92,6 +94,7 @@ func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name str
|
|||||||
minSize: minSize,
|
minSize: minSize,
|
||||||
encodings: conf.Encodings,
|
encodings: conf.Encodings,
|
||||||
defaultEncoding: conf.DefaultEncoding,
|
defaultEncoding: conf.DefaultEncoding,
|
||||||
|
supportedEncodings: buildSupportedEncodings(conf.Encodings),
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -114,6 +117,19 @@ func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name str
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildSupportedEncodings(encodings []string) map[string]int {
|
||||||
|
supportedEncodings := map[string]int{
|
||||||
|
// the most permissive first.
|
||||||
|
wildcardName: -1,
|
||||||
|
// the less permissive last.
|
||||||
|
identityName: len(encodings),
|
||||||
|
}
|
||||||
|
for i, encoding := range encodings {
|
||||||
|
supportedEncodings[encoding] = i
|
||||||
|
}
|
||||||
|
return supportedEncodings
|
||||||
|
}
|
||||||
|
|
||||||
func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
||||||
logger := middlewares.GetLogger(req.Context(), c.name, typeName)
|
logger := middlewares.GetLogger(req.Context(), c.name, typeName)
|
||||||
|
|
||||||
@ -149,7 +165,7 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.chooseHandler(getCompressionEncoding(acceptEncoding, c.defaultEncoding, c.encodings), rw, req)
|
c.chooseHandler(c.getCompressionEncoding(acceptEncoding), rw, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.Request) {
|
func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -39,9 +39,14 @@ func TestNegotiation(t *testing.T) {
|
|||||||
expEncoding: "",
|
expEncoding: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
// In this test, the default encodings are defaulted to gzip, brotli, and zstd,
|
||||||
|
// which make gzip the default encoding, and will be selected.
|
||||||
|
// However, the klauspost/compress gzhttp handler does not compress when Accept-Encoding: * is set.
|
||||||
|
// Until klauspost/compress gzhttp package supports the asterisk,
|
||||||
|
// we will not support it when selecting the gzip encoding.
|
||||||
desc: "accept any header",
|
desc: "accept any header",
|
||||||
acceptEncHeader: "*",
|
acceptEncHeader: "*",
|
||||||
expEncoding: brotliName,
|
expEncoding: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "gzip accept header",
|
desc: "gzip accept header",
|
||||||
@ -66,7 +71,7 @@ func TestNegotiation(t *testing.T) {
|
|||||||
{
|
{
|
||||||
desc: "multi accept header list, prefer br",
|
desc: "multi accept header list, prefer br",
|
||||||
acceptEncHeader: "gzip, br",
|
acceptEncHeader: "gzip, br",
|
||||||
expEncoding: brotliName,
|
expEncoding: gzipName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "zstd accept header",
|
desc: "zstd accept header",
|
||||||
@ -78,15 +83,20 @@ func TestNegotiation(t *testing.T) {
|
|||||||
acceptEncHeader: "zstd;q=0.9, br;q=0.8, gzip;q=0.6",
|
acceptEncHeader: "zstd;q=0.9, br;q=0.8, gzip;q=0.6",
|
||||||
expEncoding: zstdName,
|
expEncoding: zstdName,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "multi accept header, prefer brotli",
|
||||||
|
acceptEncHeader: "gzip;q=0.8, br;q=1.0, zstd;q=0.7",
|
||||||
|
expEncoding: brotliName,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "multi accept header, prefer gzip",
|
desc: "multi accept header, prefer gzip",
|
||||||
acceptEncHeader: "gzip;q=1.0, br;q=0.8, zstd;q=0.7",
|
acceptEncHeader: "gzip;q=1.0, br;q=0.8, zstd;q=0.7",
|
||||||
expEncoding: gzipName,
|
expEncoding: gzipName,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "multi accept header list, prefer zstd",
|
desc: "multi accept header list, prefer gzip",
|
||||||
acceptEncHeader: "gzip, br, zstd",
|
acceptEncHeader: "gzip, br, zstd",
|
||||||
expEncoding: zstdName,
|
expEncoding: gzipName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,6 +200,28 @@ func TestShouldNotCompressWhenNoAcceptEncodingHeader(t *testing.T) {
|
|||||||
assert.EqualValues(t, rw.Body.Bytes(), fakeBody)
|
assert.EqualValues(t, rw.Body.Bytes(), fakeBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmptyAcceptEncoding(t *testing.T) {
|
||||||
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
|
req.Header.Add(acceptEncodingHeader, "")
|
||||||
|
|
||||||
|
fakeBody := generateBytes(gzhttp.DefaultMinSize)
|
||||||
|
next := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||||
|
_, err := rw.Write(fakeBody)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(rw, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
handler, err := New(context.Background(), next, dynamic.Compress{Encodings: defaultSupportedEncodings}, "testing")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
handler.ServeHTTP(rw, req)
|
||||||
|
|
||||||
|
assert.Empty(t, rw.Header().Get(contentEncodingHeader))
|
||||||
|
assert.Empty(t, rw.Header().Get(varyHeader))
|
||||||
|
assert.EqualValues(t, rw.Body.Bytes(), fakeBody)
|
||||||
|
}
|
||||||
|
|
||||||
func TestShouldNotCompressWhenIdentityAcceptEncodingHeader(t *testing.T) {
|
func TestShouldNotCompressWhenIdentityAcceptEncodingHeader(t *testing.T) {
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
req.Header.Set(acceptEncodingHeader, "identity")
|
req.Header.Set(acceptEncodingHeader, "identity")
|
||||||
|
@ -233,8 +233,12 @@ func (r *responseWriter) Write(p []byte) (int, error) {
|
|||||||
// Disable compression according to user wishes in excludedContentTypes or includedContentTypes.
|
// Disable compression according to user wishes in excludedContentTypes or includedContentTypes.
|
||||||
if ct := r.rw.Header().Get(contentType); ct != "" {
|
if ct := r.rw.Header().Get(contentType); ct != "" {
|
||||||
mediaType, params, err := mime.ParseMediaType(ct)
|
mediaType, params, err := mime.ParseMediaType(ct)
|
||||||
|
// To align the behavior with the klauspost handler for Gzip,
|
||||||
|
// if the MIME type is not parsable the compression is disabled.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, fmt.Errorf("parsing content-type media type: %w", err)
|
r.compressionDisabled = true
|
||||||
|
r.rw.WriteHeader(r.statusCode)
|
||||||
|
return r.rw.Write(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(r.includedContentTypes) > 0 {
|
if len(r.includedContentTypes) > 0 {
|
||||||
|
@ -577,6 +577,11 @@ func Test_ExcludedContentTypes(t *testing.T) {
|
|||||||
contentType: "",
|
contentType: "",
|
||||||
expCompression: true,
|
expCompression: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME malformed",
|
||||||
|
contentType: "application/json;charset=UTF-8;charset=utf-8",
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "MIME match",
|
desc: "MIME match",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
@ -687,6 +692,11 @@ func Test_IncludedContentTypes(t *testing.T) {
|
|||||||
contentType: "",
|
contentType: "",
|
||||||
expCompression: true,
|
expCompression: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "MIME malformed",
|
||||||
|
contentType: "application/json;charset=UTF-8;charset=utf-8",
|
||||||
|
expCompression: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "MIME match",
|
desc: "MIME match",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
|
@ -67,7 +67,7 @@ func clientIP(tree *matchersTree, clientIP ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostOrIP = regexp.MustCompile(`^[[:alnum:]\.\-\:]+$`)
|
var hostOrIP = regexp.MustCompile(`^[[:word:]\.\-\:]+$`)
|
||||||
|
|
||||||
// hostSNI checks if the SNI Host of the connection match the matcher host.
|
// hostSNI checks if the SNI Host of the connection match the matcher host.
|
||||||
func hostSNI(tree *matchersTree, hosts ...string) error {
|
func hostSNI(tree *matchersTree, hosts ...string) error {
|
||||||
|
@ -133,6 +133,12 @@ func Test_HostSNI(t *testing.T) {
|
|||||||
serverName: "foo.example.com",
|
serverName: "foo.example.com",
|
||||||
match: true,
|
match: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Matching hosts with subdomains with _",
|
||||||
|
rule: "HostSNI(`foo_bar.example.com`)",
|
||||||
|
serverName: "foo_bar.example.com",
|
||||||
|
match: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range testCases {
|
for _, test := range testCases {
|
||||||
|
@ -690,6 +690,11 @@ func Test_HostSNIV2(t *testing.T) {
|
|||||||
ruleHosts: []string{"foo.bar"},
|
ruleHosts: []string{"foo.bar"},
|
||||||
serverName: "foo.bar",
|
serverName: "foo.bar",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "Matching hosts with subdomains with _",
|
||||||
|
ruleHosts: []string{"foo_bar.example.com"},
|
||||||
|
serverName: "foo_bar.example.com",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "Matching IPv4",
|
desc: "Matching IPv4",
|
||||||
ruleHosts: []string{"127.0.0.1"},
|
ruleHosts: []string{"127.0.0.1"},
|
||||||
|
@ -2,6 +2,7 @@ package httputil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
@ -112,7 +113,13 @@ func ErrorHandlerWithContext(ctx context.Context, w http.ResponseWriter, err err
|
|||||||
statusCode := ComputeStatusCode(err)
|
statusCode := ComputeStatusCode(err)
|
||||||
|
|
||||||
logger := log.Ctx(ctx)
|
logger := log.Ctx(ctx)
|
||||||
|
|
||||||
|
// Log the error with error level if it is a TLS error related to configuration.
|
||||||
|
if isTLSConfigError(err) {
|
||||||
|
logger.Error().Err(err).Msgf("%d %s", statusCode, statusText(statusCode))
|
||||||
|
} else {
|
||||||
logger.Debug().Err(err).Msgf("%d %s", statusCode, statusText(statusCode))
|
logger.Debug().Err(err).Msgf("%d %s", statusCode, statusText(statusCode))
|
||||||
|
}
|
||||||
|
|
||||||
w.WriteHeader(statusCode)
|
w.WriteHeader(statusCode)
|
||||||
if _, werr := w.Write([]byte(statusText(statusCode))); werr != nil {
|
if _, werr := w.Write([]byte(statusText(statusCode))); werr != nil {
|
||||||
@ -127,6 +134,22 @@ func statusText(statusCode int) string {
|
|||||||
return http.StatusText(statusCode)
|
return http.StatusText(statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isTLSConfigError returns true if the error is a TLS error which is related to configuration.
|
||||||
|
// We assume that if the error is a tls.RecordHeaderError or a tls.CertificateVerificationError,
|
||||||
|
// it is related to configuration, because the client should not send a TLS request to a non-TLS server,
|
||||||
|
// and the client configuration should allow to verify the server certificate.
|
||||||
|
func isTLSConfigError(err error) bool {
|
||||||
|
// tls.RecordHeaderError is returned when the client sends a TLS request to a non-TLS server.
|
||||||
|
var recordHeaderErr tls.RecordHeaderError
|
||||||
|
if errors.As(err, &recordHeaderErr) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// tls.CertificateVerificationError is returned when the server certificate cannot be verified.
|
||||||
|
var certVerificationErr *tls.CertificateVerificationError
|
||||||
|
return errors.As(err, &certVerificationErr)
|
||||||
|
}
|
||||||
|
|
||||||
// ComputeStatusCode computes the HTTP status code according to the given error.
|
// ComputeStatusCode computes the HTTP status code according to the given error.
|
||||||
func ComputeStatusCode(err error) int {
|
func ComputeStatusCode(err error) int {
|
||||||
switch {
|
switch {
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
package httputil
|
package httputil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
"github.com/traefik/traefik/v3/pkg/testhelpers"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -100,3 +103,46 @@ func Test_directorBuilder(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_isTLSConfigError(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
desc string
|
||||||
|
err error
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
desc: "nil",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TLS ECHRejectionError",
|
||||||
|
err: &tls.ECHRejectionError{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TLS AlertError",
|
||||||
|
err: tls.AlertError(0),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "Random error",
|
||||||
|
err: errors.New("random error"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TLS RecordHeaderError",
|
||||||
|
err: tls.RecordHeaderError{},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc: "TLS CertificateVerificationError",
|
||||||
|
err: &tls.CertificateVerificationError{},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
actual := isTLSConfigError(test.err)
|
||||||
|
require.Equal(t, test.expected, actual)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,11 +4,11 @@ RepositoryName = "traefik"
|
|||||||
OutputType = "file"
|
OutputType = "file"
|
||||||
FileName = "traefik_changelog.md"
|
FileName = "traefik_changelog.md"
|
||||||
|
|
||||||
# example new bugfix v3.3.4
|
# example new bugfix v3.3.5
|
||||||
CurrentRef = "v3.3"
|
CurrentRef = "v3.3"
|
||||||
PreviousRef = "v3.3.3"
|
PreviousRef = "v3.3.4"
|
||||||
BaseBranch = "v3.3"
|
BaseBranch = "v3.3"
|
||||||
FutureCurrentRefName = "v3.3.4"
|
FutureCurrentRefName = "v3.3.5"
|
||||||
|
|
||||||
ThresholdPreviousRef = 10
|
ThresholdPreviousRef = 10
|
||||||
ThresholdCurrentRef = 10
|
ThresholdCurrentRef = 10
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
dense: Boolean,
|
dense: { type: Boolean, default: undefined },
|
||||||
classNames: Array[String],
|
classNames: Array[String],
|
||||||
list: Array[Object]
|
list: Array[Object]
|
||||||
}
|
}
|
||||||
|
@ -138,7 +138,7 @@ export default {
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: { type: Object, default: undefined, required: false },
|
data: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isDense () {
|
isDense () {
|
||||||
|
@ -1634,7 +1634,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: Array[Object],
|
data: Array[Object],
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
protocol () {
|
protocol () {
|
||||||
|
@ -71,7 +71,7 @@ export default {
|
|||||||
name: 'PanelMirroringServices',
|
name: 'PanelMirroringServices',
|
||||||
props: {
|
props: {
|
||||||
data: { type: Object, default: undefined, required: false },
|
data: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isDense () {
|
isDense () {
|
||||||
|
@ -103,8 +103,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: { type: Object, default: undefined, required: false },
|
data: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean,
|
dense: { type: Boolean, default: undefined },
|
||||||
hasStatus: Boolean
|
hasStatus: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isDense () {
|
isDense () {
|
||||||
|
@ -156,7 +156,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
data: { type: Object, default: undefined, required: false },
|
data: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isDense () {
|
isDense () {
|
||||||
|
@ -67,7 +67,7 @@ export default defineComponent({
|
|||||||
components: {},
|
components: {},
|
||||||
props: {
|
props: {
|
||||||
data: { type: Object, default: undefined, required: false },
|
data: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isDense () {
|
isDense () {
|
||||||
|
@ -56,7 +56,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
sticky: { type: Object, default: undefined, required: false },
|
sticky: { type: Object, default: undefined, required: false },
|
||||||
dense: Boolean
|
dense: { type: Boolean, default: undefined }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user