mirror of
https://github.com/traefik/traefik
synced 2026-02-03 08:50:32 +00:00
Merge current v2.11 into v3.6
This commit is contained in:
@@ -7,7 +7,7 @@ on:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.24'
|
GO_VERSION: '1.24'
|
||||||
GOLANGCI_LINT_VERSION: v2.0.2
|
GOLANGCI_LINT_VERSION: v2.8.0
|
||||||
MISSPELL_VERSION: v0.7.0
|
MISSPELL_VERSION: v0.7.0
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|||||||
+20
-2
@@ -36,6 +36,7 @@ linters:
|
|||||||
- nilnil # Not relevant
|
- nilnil # Not relevant
|
||||||
- nlreturn # Not relevant
|
- nlreturn # Not relevant
|
||||||
- noctx # Too strict
|
- noctx # Too strict
|
||||||
|
- noinlineerr # Too strict
|
||||||
- nonamedreturns # Too strict
|
- nonamedreturns # Too strict
|
||||||
- paralleltest # Not relevant
|
- paralleltest # Not relevant
|
||||||
- prealloc # Too many false-positive.
|
- prealloc # Too many false-positive.
|
||||||
@@ -47,6 +48,7 @@ linters:
|
|||||||
- varnamelen # Not relevant
|
- varnamelen # Not relevant
|
||||||
- wrapcheck # Too strict
|
- wrapcheck # Too strict
|
||||||
- wsl # Too strict
|
- wsl # Too strict
|
||||||
|
- wsl_v5 # Too strict
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
depguard:
|
depguard:
|
||||||
@@ -295,15 +297,31 @@ linters:
|
|||||||
source: 'errors.New\("Nomad provider'
|
source: 'errors.New\("Nomad provider'
|
||||||
text: 'ST1005: error strings should not be capitalized'
|
text: 'ST1005: error strings should not be capitalized'
|
||||||
- path: (.+)\.go
|
- path: (.+)\.go
|
||||||
text: 'struct-tag: unknown option ''inline'' in JSON tag'
|
text: 'omitzero: Omitempty has no effect on nested struct field'
|
||||||
|
linters:
|
||||||
|
- modernize
|
||||||
|
- path: (.+)\.go
|
||||||
|
text: 'struct-tag: unknown option "inline" in json tag'
|
||||||
linters:
|
linters:
|
||||||
- revive
|
- revive
|
||||||
- path: (.+)\.go
|
- path: (.+)\.go
|
||||||
text: 'struct-tag: unknown option ''omitzero'' in TOML tag'
|
text: 'struct-tag: unknown option "omitzero" in toml tag'
|
||||||
|
linters:
|
||||||
|
- revive
|
||||||
|
- path: (pkg/types/.+|pkg/api/.+|pkg/observability/types/.+)\.go
|
||||||
|
text: 'var-naming: avoid meaningless package names'
|
||||||
|
linters:
|
||||||
|
- revive
|
||||||
|
- path: (pkg/muxer/http/.+|pkg/provider/http/.+)\.go
|
||||||
|
text: 'var-naming: avoid package names that conflict with Go standard library package names'
|
||||||
linters:
|
linters:
|
||||||
- revive
|
- revive
|
||||||
- path: (.+)\.go$
|
- path: (.+)\.go$
|
||||||
text: 'SA1019: http.CloseNotifier has been deprecated' # FIXME must be fixed
|
text: 'SA1019: http.CloseNotifier has been deprecated' # FIXME must be fixed
|
||||||
|
- path: (.+)\.go$
|
||||||
|
text: 'SA1019: dynamic.(TCPIPWhiteList|IPWhiteList) is deprecated: please use IPAllowList instead.'
|
||||||
|
- path: (.+)\.go$
|
||||||
|
text: 'SA1019: middlewareTCP.Spec.IPWhiteList is deprecated: please use IPAllowList instead.'
|
||||||
- path: (.+)\.go$
|
- path: (.+)\.go$
|
||||||
text: 'SA1019: cfg.(SSLRedirect|SSLTemporaryRedirect|SSLHost|SSLForceHost|FeaturePolicy) is deprecated'
|
text: 'SA1019: cfg.(SSLRedirect|SSLTemporaryRedirect|SSLHost|SSLForceHost|FeaturePolicy) is deprecated'
|
||||||
- path: (.+)\.go$
|
- path: (.+)\.go$
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
// TraefikCmdConfiguration wraps the static configuration and extra parameters.
|
// TraefikCmdConfiguration wraps the static configuration and extra parameters.
|
||||||
type TraefikCmdConfiguration struct {
|
type TraefikCmdConfiguration struct {
|
||||||
static.Configuration `export:"true"`
|
static.Configuration `export:"true"`
|
||||||
|
|
||||||
// ConfigFile is the path to the configuration file.
|
// ConfigFile is the path to the configuration file.
|
||||||
ConfigFile string `description:"Configuration file to use. If specified all other flags are ignored." export:"true"`
|
ConfigFile string `description:"Configuration file to use. If specified all other flags are ignored." export:"true"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ func run(dest string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.WriteFile(filepath.Join(dest, "marshaler.go"), []byte(fmt.Sprintf(marsh, destPkg)), 0o666)
|
return os.WriteFile(filepath.Join(dest, "marshaler.go"), fmt.Appendf(nil, marsh, destPkg), 0o666)
|
||||||
}
|
}
|
||||||
|
|
||||||
func cleanType(typ types.Type, base string) string {
|
func cleanType(typ types.Type, base string) string {
|
||||||
|
|||||||
@@ -373,6 +373,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
@@ -584,6 +585,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
ProxyProtocol defines the PROXY protocol configuration.
|
ProxyProtocol defines the PROXY protocol configuration.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
||||||
|
|
||||||
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
||||||
properties:
|
properties:
|
||||||
version:
|
version:
|
||||||
@@ -606,6 +608,7 @@ spec:
|
|||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
|
|
||||||
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
@@ -626,6 +629,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
enum:
|
enum:
|
||||||
- v3
|
- v3
|
||||||
@@ -1060,6 +1064,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
||||||
be automatically set to a value derived from the contents of the response.
|
be automatically set to a value derived from the contents of the response.
|
||||||
|
|
||||||
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
@@ -2212,8 +2217,9 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||||
This middleware accepts/refuses connections based on the client IP.
|
This middleware accepts/refuses connections based on the client IP.
|
||||||
Deprecated: please use IPAllowList instead.
|
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
||||||
|
|
||||||
|
Deprecated: please use IPAllowList instead.
|
||||||
properties:
|
properties:
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the allowed IPs (or ranges of
|
description: SourceRange defines the allowed IPs (or ranges of
|
||||||
@@ -2370,6 +2376,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
@@ -2524,6 +2531,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
@@ -2659,6 +2667,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||||
It is enabled automatically when minVersion or maxVersion is set.
|
It is enabled automatically when minVersion or maxVersion is set.
|
||||||
|
|
||||||
Deprecated: https://github.com/golang/go/issues/45430
|
Deprecated: https://github.com/golang/go/issues/45430
|
||||||
type: boolean
|
type: boolean
|
||||||
sniStrict:
|
sniStrict:
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
---
|
|
||||||
apiVersion: apiextensions.k8s.io/v1
|
|
||||||
kind: CustomResourceDefinition
|
|
||||||
metadata:
|
|
||||||
annotations:
|
|
||||||
controller-gen.kubebuilder.io/version: v0.16.1
|
|
||||||
name: tlsoptions.traefik.containo.us
|
|
||||||
spec:
|
|
||||||
group: traefik.containo.us
|
|
||||||
names:
|
|
||||||
kind: TLSOption
|
|
||||||
listKind: TLSOptionList
|
|
||||||
plural: tlsoptions
|
|
||||||
singular: tlsoption
|
|
||||||
scope: Namespaced
|
|
||||||
versions:
|
|
||||||
- name: v1alpha1
|
|
||||||
schema:
|
|
||||||
openAPIV3Schema:
|
|
||||||
description: |-
|
|
||||||
TLSOption is the CRD implementation of a Traefik TLS Option, allowing to configure some parameters of the TLS connection.
|
|
||||||
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#tls-options
|
|
||||||
properties:
|
|
||||||
apiVersion:
|
|
||||||
description: |-
|
|
||||||
APIVersion defines the versioned schema of this representation of an object.
|
|
||||||
Servers should convert recognized schemas to the latest internal value, and
|
|
||||||
may reject unrecognized values.
|
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
|
||||||
type: string
|
|
||||||
kind:
|
|
||||||
description: |-
|
|
||||||
Kind is a string value representing the REST resource this object represents.
|
|
||||||
Servers may infer this from the endpoint the client submits requests to.
|
|
||||||
Cannot be updated.
|
|
||||||
In CamelCase.
|
|
||||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
|
||||||
type: string
|
|
||||||
metadata:
|
|
||||||
type: object
|
|
||||||
spec:
|
|
||||||
description: TLSOptionSpec defines the desired state of a TLSOption.
|
|
||||||
properties:
|
|
||||||
alpnProtocols:
|
|
||||||
description: |-
|
|
||||||
ALPNProtocols defines the list of supported application level protocols for the TLS handshake, in order of preference.
|
|
||||||
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#alpn-protocols
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
cipherSuites:
|
|
||||||
description: |-
|
|
||||||
CipherSuites defines the list of supported cipher suites for TLS versions up to TLS 1.2.
|
|
||||||
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#cipher-suites
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
clientAuth:
|
|
||||||
description: ClientAuth defines the server's policy for TLS Client
|
|
||||||
Authentication.
|
|
||||||
properties:
|
|
||||||
clientAuthType:
|
|
||||||
description: ClientAuthType defines the client authentication
|
|
||||||
type to apply.
|
|
||||||
enum:
|
|
||||||
- NoClientCert
|
|
||||||
- RequestClientCert
|
|
||||||
- RequireAnyClientCert
|
|
||||||
- VerifyClientCertIfGiven
|
|
||||||
- RequireAndVerifyClientCert
|
|
||||||
type: string
|
|
||||||
secretNames:
|
|
||||||
description: SecretNames defines the names of the referenced Kubernetes
|
|
||||||
Secret storing certificate details.
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
type: object
|
|
||||||
curvePreferences:
|
|
||||||
description: |-
|
|
||||||
CurvePreferences defines the preferred elliptic curves.
|
|
||||||
More info: https://doc.traefik.io/traefik/v2.11/https/tls/#curve-preferences
|
|
||||||
items:
|
|
||||||
type: string
|
|
||||||
type: array
|
|
||||||
maxVersion:
|
|
||||||
description: |-
|
|
||||||
MaxVersion defines the maximum TLS version that Traefik will accept.
|
|
||||||
Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13.
|
|
||||||
Default: None.
|
|
||||||
type: string
|
|
||||||
minVersion:
|
|
||||||
description: |-
|
|
||||||
MinVersion defines the minimum TLS version that Traefik will accept.
|
|
||||||
Possible values: VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13.
|
|
||||||
Default: VersionTLS10.
|
|
||||||
type: string
|
|
||||||
preferServerCipherSuites:
|
|
||||||
description: |-
|
|
||||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
|
||||||
It is enabled automatically when minVersion or maxVersion is set.
|
|
||||||
Deprecated: https://github.com/golang/go/issues/45430
|
|
||||||
type: boolean
|
|
||||||
sniStrict:
|
|
||||||
description: SniStrict defines whether Traefik allows connections
|
|
||||||
from clients connections that do not specify a server_name extension.
|
|
||||||
type: boolean
|
|
||||||
type: object
|
|
||||||
required:
|
|
||||||
- metadata
|
|
||||||
- spec
|
|
||||||
type: object
|
|
||||||
served: true
|
|
||||||
storage: true
|
|
||||||
@@ -374,6 +374,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
ProxyProtocol defines the PROXY protocol configuration.
|
ProxyProtocol defines the PROXY protocol configuration.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
||||||
|
|
||||||
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
||||||
properties:
|
properties:
|
||||||
version:
|
version:
|
||||||
@@ -145,6 +146,7 @@ spec:
|
|||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
|
|
||||||
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
@@ -165,6 +167,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
enum:
|
enum:
|
||||||
- v3
|
- v3
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
||||||
be automatically set to a value derived from the contents of the response.
|
be automatically set to a value derived from the contents of the response.
|
||||||
|
|
||||||
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
|
|||||||
@@ -69,8 +69,9 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||||
This middleware accepts/refuses connections based on the client IP.
|
This middleware accepts/refuses connections based on the client IP.
|
||||||
Deprecated: please use IPAllowList instead.
|
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
||||||
|
|
||||||
|
Deprecated: please use IPAllowList instead.
|
||||||
properties:
|
properties:
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the allowed IPs (or ranges of
|
description: SourceRange defines the allowed IPs (or ranges of
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||||
It is enabled automatically when minVersion or maxVersion is set.
|
It is enabled automatically when minVersion or maxVersion is set.
|
||||||
|
|
||||||
Deprecated: https://github.com/golang/go/issues/45430
|
Deprecated: https://github.com/golang/go/issues/45430
|
||||||
type: boolean
|
type: boolean
|
||||||
sniStrict:
|
sniStrict:
|
||||||
|
|||||||
@@ -245,8 +245,7 @@ func digestParts(resp *http.Response) map[string]string {
|
|||||||
result := map[string]string{}
|
result := map[string]string{}
|
||||||
if len(resp.Header["Www-Authenticate"]) > 0 {
|
if len(resp.Header["Www-Authenticate"]) > 0 {
|
||||||
wantedHeaders := []string{"nonce", "realm", "qop", "opaque"}
|
wantedHeaders := []string{"nonce", "realm", "qop", "opaque"}
|
||||||
responseHeaders := strings.Split(resp.Header["Www-Authenticate"][0], ",")
|
for r := range strings.SplitSeq(resp.Header["Www-Authenticate"][0], ",") {
|
||||||
for _, r := range responseHeaders {
|
|
||||||
for _, w := range wantedHeaders {
|
for _, w := range wantedHeaders {
|
||||||
if strings.Contains(r, w) {
|
if strings.Contains(r, w) {
|
||||||
result[w] = strings.Split(r, `"`)[1]
|
result[w] = strings.Split(r, `"`)[1]
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
// ACME test suites.
|
// ACME test suites.
|
||||||
type AcmeSuite struct {
|
type AcmeSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
pebbleIP string
|
pebbleIP string
|
||||||
fakeDNSServer *dns.Server
|
fakeDNSServer *dns.Server
|
||||||
}
|
}
|
||||||
@@ -63,11 +64,6 @@ const (
|
|||||||
wildcardDomain = "*.acme.wtf"
|
wildcardDomain = "*.acme.wtf"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *AcmeSuite) getAcmeURL() string {
|
|
||||||
return fmt.Sprintf("https://%s/dir",
|
|
||||||
net.JoinHostPort(s.pebbleIP, "14000"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupPebbleRootCA() (*http.Transport, error) {
|
func setupPebbleRootCA() (*http.Transport, error) {
|
||||||
path, err := filepath.Abs("fixtures/acme/ssl/pebble.minica.pem")
|
path, err := filepath.Abs("fixtures/acme/ssl/pebble.minica.pem")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -540,3 +536,8 @@ func (s *AcmeSuite) retrieveAcmeCertificate(testCase acmeTestCase) {
|
|||||||
assert.Equal(s.T(), sub.expectedAlgorithm, gotPublicKeyAlgorithm)
|
assert.Equal(s.T(), sub.expectedAlgorithm, gotPublicKeyAlgorithm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *AcmeSuite) getAcmeURL() string {
|
||||||
|
return fmt.Sprintf("https://%s/dir",
|
||||||
|
net.JoinHostPort(s.pebbleIP, "14000"))
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
type ConsulCatalogSuite struct {
|
type ConsulCatalogSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
consulClient *api.Client
|
consulClient *api.Client
|
||||||
consulAgentClient *api.Client
|
consulAgentClient *api.Client
|
||||||
consulURL string
|
consulURL string
|
||||||
@@ -53,47 +54,6 @@ func (s *ConsulCatalogSuite) TearDownSuite() {
|
|||||||
s.BaseSuite.TearDownSuite()
|
s.BaseSuite.TearDownSuite()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
|
||||||
return try.Do(15*time.Second, func() error {
|
|
||||||
leader, err := s.consulClient.Status().Leader()
|
|
||||||
|
|
||||||
if err != nil || len(leader) == 0 {
|
|
||||||
return fmt.Errorf("leader not found. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsulCatalogSuite) waitForConnectCA() error {
|
|
||||||
return try.Do(15*time.Second, func() error {
|
|
||||||
caroots, _, err := s.consulClient.Connect().CARoots(nil)
|
|
||||||
|
|
||||||
if err != nil || len(caroots.Roots) == 0 {
|
|
||||||
return fmt.Errorf("connect CA not fully initialized. %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsulCatalogSuite) registerService(reg *api.AgentServiceRegistration, onAgent bool) error {
|
|
||||||
client := s.consulClient
|
|
||||||
if onAgent {
|
|
||||||
client = s.consulAgentClient
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.Agent().ServiceRegister(reg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsulCatalogSuite) deregisterService(id string, onAgent bool) error {
|
|
||||||
client := s.consulClient
|
|
||||||
if onAgent {
|
|
||||||
client = s.consulAgentClient
|
|
||||||
}
|
|
||||||
return client.Agent().ServiceDeregister(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings() {
|
func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings() {
|
||||||
reg1 := &api.AgentServiceRegistration{
|
reg1 := &api.AgentServiceRegistration{
|
||||||
ID: "whoami1",
|
ID: "whoami1",
|
||||||
@@ -837,3 +797,44 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware() {
|
|||||||
err = s.deregisterService("whoami1", false)
|
err = s.deregisterService("whoami1", false)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||||
|
return try.Do(15*time.Second, func() error {
|
||||||
|
leader, err := s.consulClient.Status().Leader()
|
||||||
|
|
||||||
|
if err != nil || len(leader) == 0 {
|
||||||
|
return fmt.Errorf("leader not found. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConsulCatalogSuite) waitForConnectCA() error {
|
||||||
|
return try.Do(15*time.Second, func() error {
|
||||||
|
caroots, _, err := s.consulClient.Connect().CARoots(nil)
|
||||||
|
|
||||||
|
if err != nil || len(caroots.Roots) == 0 {
|
||||||
|
return fmt.Errorf("connect CA not fully initialized. %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConsulCatalogSuite) registerService(reg *api.AgentServiceRegistration, onAgent bool) error {
|
||||||
|
client := s.consulClient
|
||||||
|
if onAgent {
|
||||||
|
client = s.consulAgentClient
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.Agent().ServiceRegister(reg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ConsulCatalogSuite) deregisterService(id string, onAgent bool) error {
|
||||||
|
client := s.consulClient
|
||||||
|
if onAgent {
|
||||||
|
client = s.consulAgentClient
|
||||||
|
}
|
||||||
|
return client.Agent().ServiceDeregister(id)
|
||||||
|
}
|
||||||
|
|||||||
+11
-10
@@ -25,6 +25,7 @@ import (
|
|||||||
// Consul test suites.
|
// Consul test suites.
|
||||||
type ConsulSuite struct {
|
type ConsulSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
kvClient store.Store
|
kvClient store.Store
|
||||||
consulURL string
|
consulURL string
|
||||||
}
|
}
|
||||||
@@ -162,16 +163,6 @@ func (s *ConsulSuite) TestSimpleConfiguration() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ConsulSuite) assertWhoami(host string, expectedStatusCode int) {
|
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
req.Host = host
|
|
||||||
|
|
||||||
resp, err := try.ResponseUntilStatusCode(req, 15*time.Second, expectedStatusCode)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ConsulSuite) TestDeleteRootKey() {
|
func (s *ConsulSuite) TestDeleteRootKey() {
|
||||||
// This test case reproduce the issue: https://github.com/traefik/traefik/issues/8092
|
// This test case reproduce the issue: https://github.com/traefik/traefik/issues/8092
|
||||||
|
|
||||||
@@ -220,3 +211,13 @@ func (s *ConsulSuite) TestDeleteRootKey() {
|
|||||||
s.assertWhoami("kv1.localhost", http.StatusNotFound)
|
s.assertWhoami("kv1.localhost", http.StatusNotFound)
|
||||||
s.assertWhoami("kv2.localhost", http.StatusNotFound)
|
s.assertWhoami("kv2.localhost", http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ConsulSuite) assertWhoami(host string, expectedStatusCode int) {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
req.Host = host
|
||||||
|
|
||||||
|
resp, err := try.ResponseUntilStatusCode(req, 15*time.Second, expectedStatusCode)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (s *DockerSuite) TestDefaultDockerContainers() {
|
|||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
var version map[string]interface{}
|
var version map[string]any
|
||||||
|
|
||||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||||
@@ -145,7 +145,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels() {
|
|||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
var version map[string]interface{}
|
var version map[string]any
|
||||||
|
|
||||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||||
@@ -203,7 +203,7 @@ func (s *DockerSuite) TestRestartDockerContainers() {
|
|||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
var version map[string]interface{}
|
var version map[string]any
|
||||||
|
|
||||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const traefikTestOTLPLogFile = "traefik_otlp.log"
|
|||||||
// DualLoggingSuite tests that both OTLP and stdout logging can work together.
|
// DualLoggingSuite tests that both OTLP and stdout logging can work together.
|
||||||
type DualLoggingSuite struct {
|
type DualLoggingSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
otlpLogs []string
|
otlpLogs []string
|
||||||
collector *httptest.Server
|
collector *httptest.Server
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import (
|
|||||||
// ErrorPagesSuite test suites.
|
// ErrorPagesSuite test suites.
|
||||||
type ErrorPagesSuite struct {
|
type ErrorPagesSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
ErrorPageIP string
|
ErrorPageIP string
|
||||||
BackendIP string
|
BackendIP string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
// etcd test suites.
|
// etcd test suites.
|
||||||
type EtcdSuite struct {
|
type EtcdSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
kvClient store.Store
|
kvClient store.Store
|
||||||
etcdAddr string
|
etcdAddr string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/http/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
@@ -585,6 +586,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
ProxyProtocol defines the PROXY protocol configuration.
|
ProxyProtocol defines the PROXY protocol configuration.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/service/#proxy-protocol
|
||||||
|
|
||||||
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
Deprecated: ProxyProtocol will not be supported in future APIVersions, please use ServersTransport to configure ProxyProtocol instead.
|
||||||
properties:
|
properties:
|
||||||
version:
|
version:
|
||||||
@@ -607,6 +609,7 @@ spec:
|
|||||||
hence fully terminating the connection.
|
hence fully terminating the connection.
|
||||||
It is a duration in milliseconds, defaulting to 100.
|
It is a duration in milliseconds, defaulting to 100.
|
||||||
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
A negative value means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
|
|
||||||
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
Deprecated: TerminationDelay will not be supported in future APIVersions, please use ServersTransport to configure the TerminationDelay instead.
|
||||||
type: integer
|
type: integer
|
||||||
tls:
|
tls:
|
||||||
@@ -627,6 +630,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
Syntax defines the router's rule syntax.
|
Syntax defines the router's rule syntax.
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/routing/rules-and-priority/#rulesyntax
|
||||||
|
|
||||||
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
Deprecated: Please do not use this field and rewrite the router rules to use the v3 syntax.
|
||||||
enum:
|
enum:
|
||||||
- v3
|
- v3
|
||||||
@@ -1061,6 +1065,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
||||||
be automatically set to a value derived from the contents of the response.
|
be automatically set to a value derived from the contents of the response.
|
||||||
|
|
||||||
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
||||||
type: boolean
|
type: boolean
|
||||||
type: object
|
type: object
|
||||||
@@ -2213,8 +2218,9 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||||
This middleware accepts/refuses connections based on the client IP.
|
This middleware accepts/refuses connections based on the client IP.
|
||||||
Deprecated: please use IPAllowList instead.
|
|
||||||
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
More info: https://doc.traefik.io/traefik/v3.6/reference/routing-configuration/tcp/middlewares/ipwhitelist/
|
||||||
|
|
||||||
|
Deprecated: please use IPAllowList instead.
|
||||||
properties:
|
properties:
|
||||||
sourceRange:
|
sourceRange:
|
||||||
description: SourceRange defines the allowed IPs (or ranges of
|
description: SourceRange defines the allowed IPs (or ranges of
|
||||||
@@ -2371,6 +2377,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
@@ -2525,6 +2532,7 @@ spec:
|
|||||||
rootCAsSecrets:
|
rootCAsSecrets:
|
||||||
description: |-
|
description: |-
|
||||||
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
RootCAsSecrets defines a list of CA secret used to validate self-signed certificate.
|
||||||
|
|
||||||
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
Deprecated: RootCAsSecrets is deprecated, please use the RootCAs option instead.
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
@@ -2660,6 +2668,7 @@ spec:
|
|||||||
description: |-
|
description: |-
|
||||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||||
It is enabled automatically when minVersion or maxVersion is set.
|
It is enabled automatically when minVersion or maxVersion is set.
|
||||||
|
|
||||||
Deprecated: https://github.com/golang/go/issues/45430
|
Deprecated: https://github.com/golang/go/issues/45430
|
||||||
type: boolean
|
type: boolean
|
||||||
sniStrict:
|
sniStrict:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
// HealthCheck test suites.
|
// HealthCheck test suites.
|
||||||
type HealthCheckSuite struct {
|
type HealthCheckSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoami1IP string
|
whoami1IP string
|
||||||
whoami2IP string
|
whoami2IP string
|
||||||
whoami3IP string
|
whoami3IP string
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
|
|||||||
s.RegisterService(&_Greeter_serviceDesc, srv)
|
s.RegisterService(&_Greeter_serviceDesc, srv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
func _Greeter_SayHello_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) {
|
||||||
in := new(HelloRequest)
|
in := new(HelloRequest)
|
||||||
if err := dec(in); err != nil {
|
if err := dec(in); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -199,13 +199,13 @@ func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(in
|
|||||||
Server: srv,
|
Server: srv,
|
||||||
FullMethod: "/helloworld.Greeter/SayHello",
|
FullMethod: "/helloworld.Greeter/SayHello",
|
||||||
}
|
}
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
handler := func(ctx context.Context, req any) (any, error) {
|
||||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||||
}
|
}
|
||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _Greeter_StreamExample_Handler(srv interface{}, stream grpc.ServerStream) error {
|
func _Greeter_StreamExample_Handler(srv any, stream grpc.ServerStream) error {
|
||||||
m := new(StreamExampleRequest)
|
m := new(StreamExampleRequest)
|
||||||
if err := stream.RecvMsg(m); err != nil {
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+34
-34
@@ -877,40 +877,6 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithTlsConfigurationDeletion()
|
|||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
|
||||||
func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName string) {
|
|
||||||
file, err := os.OpenFile("./"+confFileName, os.O_WRONLY, os.ModeExclusive)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
defer func() {
|
|
||||||
file.Close()
|
|
||||||
}()
|
|
||||||
err = file.Truncate(0)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
// If certificate file is not provided, just truncate the configuration file
|
|
||||||
if len(certFileName) > 0 {
|
|
||||||
tlsConf := dynamic.Configuration{
|
|
||||||
TLS: &dynamic.TLSConfiguration{
|
|
||||||
Certificates: []*traefiktls.CertAndStores{
|
|
||||||
{
|
|
||||||
Certificate: traefiktls.Certificate{
|
|
||||||
CertFile: types.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
|
||||||
KeyFile: types.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var confBuffer bytes.Buffer
|
|
||||||
err := toml.NewEncoder(&confBuffer).Encode(tlsConf)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
_, err = file.Write(confBuffer.Bytes())
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HTTPSSuite) TestEntryPointHttpsRedirectAndPathModification() {
|
func (s *HTTPSSuite) TestEntryPointHttpsRedirectAndPathModification() {
|
||||||
file := s.adaptFile("fixtures/https/https_redirect.toml", struct{}{})
|
file := s.adaptFile("fixtures/https/https_redirect.toml", struct{}{})
|
||||||
s.traefikCmd(withConfigFile(file))
|
s.traefikCmd(withConfigFile(file))
|
||||||
@@ -1177,6 +1143,40 @@ func (s *HTTPSSuite) TestWithInvalidTLSOption() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
||||||
|
func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName string) {
|
||||||
|
file, err := os.OpenFile("./"+confFileName, os.O_WRONLY, os.ModeExclusive)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
defer func() {
|
||||||
|
file.Close()
|
||||||
|
}()
|
||||||
|
err = file.Truncate(0)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
// If certificate file is not provided, just truncate the configuration file
|
||||||
|
if len(certFileName) > 0 {
|
||||||
|
tlsConf := dynamic.Configuration{
|
||||||
|
TLS: &dynamic.TLSConfiguration{
|
||||||
|
Certificates: []*traefiktls.CertAndStores{
|
||||||
|
{
|
||||||
|
Certificate: traefiktls.Certificate{
|
||||||
|
CertFile: types.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||||
|
KeyFile: types.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var confBuffer bytes.Buffer
|
||||||
|
err := toml.NewEncoder(&confBuffer).Encode(tlsConf)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
_, err = file.Write(confBuffer.Bytes())
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SimpleSuite) TestMaxConcurrentStream() {
|
func (s *SimpleSuite) TestMaxConcurrentStream() {
|
||||||
file := s.adaptFile("fixtures/https/max_concurrent_stream.toml", struct{}{})
|
file := s.adaptFile("fixtures/https/max_concurrent_stream.toml", struct{}{})
|
||||||
|
|
||||||
|
|||||||
@@ -71,45 +71,12 @@ type composeDeploy struct {
|
|||||||
|
|
||||||
type BaseSuite struct {
|
type BaseSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
containers map[string]testcontainers.Container
|
containers map[string]testcontainers.Container
|
||||||
network *testcontainers.DockerNetwork
|
network *testcontainers.DockerNetwork
|
||||||
hostIP string
|
hostIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseSuite) waitForTraefik(containerName string) {
|
|
||||||
time.Sleep(1 * time.Second)
|
|
||||||
|
|
||||||
// Wait for Traefik to turn ready.
|
|
||||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseSuite) displayTraefikLogFile(path string) {
|
|
||||||
if s.T().Failed() {
|
|
||||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
|
||||||
content, errRead := os.ReadFile(path)
|
|
||||||
// TODO TestName
|
|
||||||
// fmt.Printf("%s: Traefik logs: \n", c.TestName())
|
|
||||||
fmt.Print("Traefik logs: \n")
|
|
||||||
if errRead == nil {
|
|
||||||
fmt.Println(string(content))
|
|
||||||
} else {
|
|
||||||
fmt.Println(errRead)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// fmt.Printf("%s: No Traefik logs.\n", c.TestName())
|
|
||||||
fmt.Print("No Traefik logs.\n")
|
|
||||||
}
|
|
||||||
errRemove := os.Remove(path)
|
|
||||||
if errRemove != nil {
|
|
||||||
fmt.Println(errRemove)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *BaseSuite) SetupSuite() {
|
func (s *BaseSuite) SetupSuite() {
|
||||||
if isDockerDesktop(s.T()) {
|
if isDockerDesktop(s.T()) {
|
||||||
_, err := os.Stat(tailscaleSecretFilePath)
|
_, err := os.Stat(tailscaleSecretFilePath)
|
||||||
@@ -409,7 +376,7 @@ func (s *BaseSuite) displayTraefikLog(output *bytes.Buffer) {
|
|||||||
if output == nil || output.Len() == 0 {
|
if output == nil || output.Len() == 0 {
|
||||||
log.Info().Msg("No Traefik logs.")
|
log.Info().Msg("No Traefik logs.")
|
||||||
} else {
|
} else {
|
||||||
for _, line := range strings.Split(output.String(), "\n") {
|
for line := range strings.SplitSeq(output.String(), "\n") {
|
||||||
log.Info().Msg(line)
|
log.Info().Msg(line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -425,7 +392,7 @@ func (s *BaseSuite) getDockerHost() string {
|
|||||||
return dockerHost
|
return dockerHost
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *BaseSuite) adaptFile(path string, tempObjects interface{}) string {
|
func (s *BaseSuite) adaptFile(path string, tempObjects any) string {
|
||||||
// Load file
|
// Load file
|
||||||
tmpl, err := template.ParseFiles(path)
|
tmpl, err := template.ParseFiles(path)
|
||||||
require.NoError(s.T(), err)
|
require.NoError(s.T(), err)
|
||||||
@@ -513,3 +480,37 @@ func (s *BaseSuite) composeExec(service string, args ...string) string {
|
|||||||
|
|
||||||
return string(content)
|
return string(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *BaseSuite) waitForTraefik(containerName string) {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
// Wait for Traefik to turn ready.
|
||||||
|
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BaseSuite) displayTraefikLogFile(path string) {
|
||||||
|
if s.T().Failed() {
|
||||||
|
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||||
|
content, errRead := os.ReadFile(path)
|
||||||
|
// TODO TestName
|
||||||
|
// fmt.Printf("%s: Traefik logs: \n", c.TestName())
|
||||||
|
fmt.Print("Traefik logs: \n")
|
||||||
|
if errRead == nil {
|
||||||
|
fmt.Println(string(content))
|
||||||
|
} else {
|
||||||
|
fmt.Println(errRead)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// fmt.Printf("%s: No Traefik logs.\n", c.TestName())
|
||||||
|
fmt.Print("No Traefik logs.\n")
|
||||||
|
}
|
||||||
|
errRemove := os.Remove(path)
|
||||||
|
if errRemove != nil {
|
||||||
|
fmt.Println(errRemove)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package integration
|
package integration
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import (
|
|||||||
|
|
||||||
type ProxyProtocolSuite struct {
|
type ProxyProtocolSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoamiIP string
|
whoamiIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,15 +126,16 @@ func proxyProtoRequest(address string, version byte) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the response from the server
|
// Read the response from the server
|
||||||
var content string
|
var content strings.Builder
|
||||||
scanner := bufio.NewScanner(conn)
|
scanner := bufio.NewScanner(conn)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
content += scanner.Text() + "\n"
|
content.WriteString(scanner.Text())
|
||||||
|
content.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
if scanner.Err() != nil {
|
if scanner.Err() != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return content, nil
|
return content.String(), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
type RateLimitSuite struct {
|
type RateLimitSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
ServerIP string
|
ServerIP string
|
||||||
RedisEndpoint string
|
RedisEndpoint string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
// Redis test suites.
|
// Redis test suites.
|
||||||
type RedisSentinelSuite struct {
|
type RedisSentinelSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
kvClient store.Store
|
kvClient store.Store
|
||||||
redisEndpoints []string
|
redisEndpoints []string
|
||||||
}
|
}
|
||||||
@@ -75,36 +76,6 @@ func (s *RedisSentinelSuite) TearDownSuite() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RedisSentinelSuite) setupSentinelConfiguration(ports []string) {
|
|
||||||
for i, port := range ports {
|
|
||||||
templateValue := struct{ SentinelPort string }{SentinelPort: port}
|
|
||||||
|
|
||||||
// Load file
|
|
||||||
templateFile := "resources/compose/config/sentinel_template.conf"
|
|
||||||
tmpl, err := template.ParseFiles(templateFile)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
folder, prefix := filepath.Split(templateFile)
|
|
||||||
|
|
||||||
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
|
|
||||||
tmpFile, err := os.Create(fileName)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
defer tmpFile.Close()
|
|
||||||
|
|
||||||
err = tmpFile.Chmod(0o666)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
model := structs.Map(templateValue)
|
|
||||||
model["SelfFilename"] = tmpFile.Name()
|
|
||||||
|
|
||||||
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
|
|
||||||
err = tmpFile.Sync()
|
|
||||||
require.NoError(s.T(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
||||||
file := s.adaptFile("fixtures/redis/sentinel.toml", struct{ RedisAddress string }{
|
file := s.adaptFile("fixtures/redis/sentinel.toml", struct{ RedisAddress string }{
|
||||||
RedisAddress: strings.Join(s.redisEndpoints, `","`),
|
RedisAddress: strings.Join(s.redisEndpoints, `","`),
|
||||||
@@ -201,3 +172,33 @@ func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
|||||||
log.Info().Msg(text)
|
log.Info().Msg(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RedisSentinelSuite) setupSentinelConfiguration(ports []string) {
|
||||||
|
for i, port := range ports {
|
||||||
|
templateValue := struct{ SentinelPort string }{SentinelPort: port}
|
||||||
|
|
||||||
|
// Load file
|
||||||
|
templateFile := "resources/compose/config/sentinel_template.conf"
|
||||||
|
tmpl, err := template.ParseFiles(templateFile)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
folder, prefix := filepath.Split(templateFile)
|
||||||
|
|
||||||
|
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
|
||||||
|
tmpFile, err := os.Create(fileName)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
defer tmpFile.Close()
|
||||||
|
|
||||||
|
err = tmpFile.Chmod(0o666)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
model := structs.Map(templateValue)
|
||||||
|
model["SelfFilename"] = tmpFile.Name()
|
||||||
|
|
||||||
|
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
|
||||||
|
err = tmpFile.Sync()
|
||||||
|
require.NoError(s.T(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
// Redis test suites.
|
// Redis test suites.
|
||||||
type RedisSuite struct {
|
type RedisSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
kvClient store.Store
|
kvClient store.Store
|
||||||
redisEndpoints []string
|
redisEndpoints []string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
|
|
||||||
type RestSuite struct {
|
type RestSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoamiAddr string
|
whoamiAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
type RetrySuite struct {
|
type RetrySuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoamiIP string
|
whoamiIP string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
// TCPHealthCheckSuite test suite for TCP health checks.
|
// TCPHealthCheckSuite test suite for TCP health checks.
|
||||||
type TCPHealthCheckSuite struct {
|
type TCPHealthCheckSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoamitcp1IP string
|
whoamitcp1IP string
|
||||||
whoamitcp2IP string
|
whoamitcp2IP string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
type TracingSuite struct {
|
type TracingSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
whoamiIP string
|
whoamiIP string
|
||||||
whoamiPort int
|
whoamiPort int
|
||||||
tempoIP string
|
tempoIP string
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const (
|
|||||||
type timedAction func(timeout time.Duration, operation DoCondition) error
|
type timedAction func(timeout time.Duration, operation DoCondition) error
|
||||||
|
|
||||||
// Sleep pauses the current goroutine for at least the duration d.
|
// Sleep pauses the current goroutine for at least the duration d.
|
||||||
|
//
|
||||||
// Deprecated: Use only when use another Try[...] functions is not possible.
|
// Deprecated: Use only when use another Try[...] functions is not possible.
|
||||||
func Sleep(d time.Duration) {
|
func Sleep(d time.Duration) {
|
||||||
d = applyCIMultiplier(d)
|
d = applyCIMultiplier(d)
|
||||||
@@ -92,10 +93,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
|
|||||||
panic("timeout must be larger than zero")
|
panic("timeout must be larger than zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
interval := time.Duration(math.Ceil(float64(timeout) / 15.0))
|
interval := min(time.Duration(math.Ceil(float64(timeout)/15.0)), maxInterval)
|
||||||
if interval > maxInterval {
|
|
||||||
interval = maxInterval
|
|
||||||
}
|
|
||||||
|
|
||||||
timeout = applyCIMultiplier(timeout)
|
timeout = applyCIMultiplier(timeout)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
// Zk test suites.
|
// Zk test suites.
|
||||||
type ZookeeperSuite struct {
|
type ZookeeperSuite struct {
|
||||||
BaseSuite
|
BaseSuite
|
||||||
|
|
||||||
kvClient store.Store
|
kvClient store.Store
|
||||||
zookeeperAddr string
|
zookeeperAddr string
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -196,7 +196,7 @@ type errWriter struct {
|
|||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ew *errWriter) writeln(a ...interface{}) {
|
func (ew *errWriter) writeln(a ...any) {
|
||||||
if ew.err != nil {
|
if ew.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-11
@@ -84,13 +84,7 @@ func (c *searchCriterion) filterMiddleware(mns []string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, mn := range mns {
|
return slices.Contains(mns, c.MiddlewareName)
|
||||||
if c.MiddlewareName == mn {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func pagination(request *http.Request, maximum int) (pageInfo, error) {
|
func pagination(request *http.Request, maximum int) (pageInfo, error) {
|
||||||
@@ -109,10 +103,7 @@ func pagination(request *http.Request, maximum int) (pageInfo, error) {
|
|||||||
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
endIndex := startIndex + perPage
|
endIndex := min(startIndex+perPage, maximum)
|
||||||
if endIndex >= maximum {
|
|
||||||
endIndex = maximum
|
|
||||||
}
|
|
||||||
|
|
||||||
nextPage := 1
|
nextPage := 1
|
||||||
if page*perPage < maximum {
|
if page*perPage < maximum {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ func init() {
|
|||||||
expvar.Publish("Goroutines2", expvar.Func(goroutines))
|
expvar.Publish("Goroutines2", expvar.Func(goroutines))
|
||||||
}
|
}
|
||||||
|
|
||||||
func goroutines() interface{} {
|
func goroutines() any {
|
||||||
return runtime.NumGoroutine()
|
return runtime.NumGoroutine()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -30,11 +30,13 @@ func writeError(rw http.ResponseWriter, msg string, code int) {
|
|||||||
|
|
||||||
type serviceInfoRepresentation struct {
|
type serviceInfoRepresentation struct {
|
||||||
*runtime.ServiceInfo
|
*runtime.ServiceInfo
|
||||||
|
|
||||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcpServiceInfoRepresentation struct {
|
type tcpServiceInfoRepresentation struct {
|
||||||
*runtime.TCPServiceInfo
|
*runtime.TCPServiceInfo
|
||||||
|
|
||||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +166,7 @@ func getProviderName(id string) string {
|
|||||||
return strings.SplitN(id, "@", 2)[1]
|
return strings.SplitN(id, "@", 2)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractType(element interface{}) string {
|
func extractType(element any) string {
|
||||||
v := reflect.ValueOf(element).Elem()
|
v := reflect.ValueOf(element).Elem()
|
||||||
for i := range v.NumField() {
|
for i := range v.NumField() {
|
||||||
field := v.Field(i)
|
field := v.Field(i)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
type entryPointRepresentation struct {
|
type entryPointRepresentation struct {
|
||||||
*static.EntryPoint
|
*static.EntryPoint
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ func TestHandler_EntryPoints(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if *updateExpected {
|
if *updateExpected {
|
||||||
var results interface{}
|
var results any
|
||||||
err := json.Unmarshal(contents, &results)
|
err := json.Unmarshal(contents, &results)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
|
|
||||||
type routerRepresentation struct {
|
type routerRepresentation struct {
|
||||||
*runtime.RouterInfo
|
*runtime.RouterInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -34,6 +35,7 @@ func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresen
|
|||||||
|
|
||||||
type serviceRepresentation struct {
|
type serviceRepresentation struct {
|
||||||
*runtime.ServiceInfo
|
*runtime.ServiceInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
@@ -52,6 +54,7 @@ func newServiceRepresentation(name string, si *runtime.ServiceInfo) serviceRepre
|
|||||||
|
|
||||||
type middlewareRepresentation struct {
|
type middlewareRepresentation struct {
|
||||||
*runtime.MiddlewareInfo
|
*runtime.MiddlewareInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
|
|||||||
@@ -1028,7 +1028,7 @@ func TestHandler_HTTP(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if *updateExpected {
|
if *updateExpected {
|
||||||
var results interface{}
|
var results any
|
||||||
err := json.Unmarshal(contents, &results)
|
err := json.Unmarshal(contents, &results)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func TestHandler_Overview(t *testing.T) {
|
|||||||
KubernetesCRD: &crd.Provider{},
|
KubernetesCRD: &crd.Provider{},
|
||||||
Rest: &rest.Provider{},
|
Rest: &rest.Provider{},
|
||||||
Plugin: map[string]static.PluginConf{
|
Plugin: map[string]static.PluginConf{
|
||||||
"test": map[string]interface{}{},
|
"test": map[string]any{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -292,7 +292,7 @@ func TestHandler_Overview(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if *updateExpected {
|
if *updateExpected {
|
||||||
var results interface{}
|
var results any
|
||||||
err := json.Unmarshal(contents, &results)
|
err := json.Unmarshal(contents, &results)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
type tcpRouterRepresentation struct {
|
type tcpRouterRepresentation struct {
|
||||||
*runtime.TCPRouterInfo
|
*runtime.TCPRouterInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -29,6 +30,7 @@ func newTCPRouterRepresentation(name string, rt *runtime.TCPRouterInfo) tcpRoute
|
|||||||
|
|
||||||
type tcpServiceRepresentation struct {
|
type tcpServiceRepresentation struct {
|
||||||
*runtime.TCPServiceInfo
|
*runtime.TCPServiceInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
@@ -47,6 +49,7 @@ func newTCPServiceRepresentation(name string, si *runtime.TCPServiceInfo) tcpSer
|
|||||||
|
|
||||||
type tcpMiddlewareRepresentation struct {
|
type tcpMiddlewareRepresentation struct {
|
||||||
*runtime.TCPMiddlewareInfo
|
*runtime.TCPMiddlewareInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
|
|||||||
@@ -964,7 +964,7 @@ func TestHandler_TCP(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if *updateExpected {
|
if *updateExpected {
|
||||||
var results interface{}
|
var results any
|
||||||
err := json.Unmarshal(contents, &results)
|
err := json.Unmarshal(contents, &results)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ func TestHandler_GetMiddleware(t *testing.T) {
|
|||||||
middlewareName string
|
middlewareName string
|
||||||
conf runtime.Configuration
|
conf runtime.Configuration
|
||||||
expectedStatus int
|
expectedStatus int
|
||||||
expected interface{}
|
expected any
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Middleware not found",
|
desc: "Middleware not found",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import (
|
|||||||
|
|
||||||
type udpRouterRepresentation struct {
|
type udpRouterRepresentation struct {
|
||||||
*runtime.UDPRouterInfo
|
*runtime.UDPRouterInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
}
|
}
|
||||||
@@ -29,6 +30,7 @@ func newUDPRouterRepresentation(name string, rt *runtime.UDPRouterInfo) udpRoute
|
|||||||
|
|
||||||
type udpServiceRepresentation struct {
|
type udpServiceRepresentation struct {
|
||||||
*runtime.UDPServiceInfo
|
*runtime.UDPServiceInfo
|
||||||
|
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Provider string `json:"provider,omitempty"`
|
Provider string `json:"provider,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
|
|||||||
@@ -594,7 +594,7 @@ func TestHandler_UDP(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
if *updateExpected {
|
if *updateExpected {
|
||||||
var results interface{}
|
var results any
|
||||||
err := json.Unmarshal(contents, &results)
|
err := json.Unmarshal(contents, &results)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ func logDeprecations(arguments []string) (bool, error) {
|
|||||||
if filePath != "" {
|
if filePath != "" {
|
||||||
// We don't rely on the Parser file loader here to avoid issues with unknown fields.
|
// We don't rely on the Parser file loader here to avoid issues with unknown fields.
|
||||||
// Parse file content into a generic map.
|
// Parse file content into a generic map.
|
||||||
var fileConfig map[string]interface{}
|
var fileConfig map[string]any
|
||||||
if err := file.Decode(filePath, &fileConfig); err != nil {
|
if err := file.Decode(filePath, &fileConfig); err != nil {
|
||||||
return false, fmt.Errorf("decoding configuration file %s: %w", filePath, err)
|
return false, fmt.Errorf("decoding configuration file %s: %w", filePath, err)
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ func logDeprecations(arguments []string) (bool, error) {
|
|||||||
if len(vars) > 0 {
|
if len(vars) > 0 {
|
||||||
// We don't rely on the Parser env loader here to avoid issues with unknown fields.
|
// We don't rely on the Parser env loader here to avoid issues with unknown fields.
|
||||||
// Decode environment variables to a generic map.
|
// Decode environment variables to a generic map.
|
||||||
var envConfig map[string]interface{}
|
var envConfig map[string]any
|
||||||
if err := env.Decode(vars, env.DefaultNamePrefix, &envConfig); err != nil {
|
if err := env.Decode(vars, env.DefaultNamePrefix, &envConfig); err != nil {
|
||||||
return false, fmt.Errorf("decoding environment variables: %w", err)
|
return false, fmt.Errorf("decoding environment variables: %w", err)
|
||||||
}
|
}
|
||||||
@@ -130,9 +130,9 @@ func logDeprecations(arguments []string) (bool, error) {
|
|||||||
|
|
||||||
// flattenToLabels recursively flattens a nested map into label key-value pairs.
|
// flattenToLabels recursively flattens a nested map into label key-value pairs.
|
||||||
// Example: {"experimental": {"http3": true}} -> {"traefik.experimental.http3": "true"}.
|
// Example: {"experimental": {"http3": true}} -> {"traefik.experimental.http3": "true"}.
|
||||||
func flattenToLabels(config interface{}, currKey string, labels map[string]string) {
|
func flattenToLabels(config any, currKey string, labels map[string]string) {
|
||||||
switch v := config.(type) {
|
switch v := config.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
for key, value := range v {
|
for key, value := range v {
|
||||||
newKey := key
|
newKey := key
|
||||||
if currKey != "" {
|
if currKey != "" {
|
||||||
@@ -140,7 +140,7 @@ func flattenToLabels(config interface{}, currKey string, labels map[string]strin
|
|||||||
}
|
}
|
||||||
flattenToLabels(value, newKey, labels)
|
flattenToLabels(value, newKey, labels)
|
||||||
}
|
}
|
||||||
case []interface{}:
|
case []any:
|
||||||
for i, item := range v {
|
for i, item := range v {
|
||||||
newKey := currKey + "[" + strconv.Itoa(i) + "]"
|
newKey := currKey + "[" + strconv.Itoa(i) + "]"
|
||||||
flattenToLabels(item, newKey, labels)
|
flattenToLabels(item, newKey, labels)
|
||||||
@@ -168,7 +168,7 @@ func parseDeprecatedConfig(labels map[string]string) (*configuration, error) {
|
|||||||
|
|
||||||
// Filter unknown nodes and check for deprecated options.
|
// Filter unknown nodes and check for deprecated options.
|
||||||
config := &configuration{}
|
config := &configuration{}
|
||||||
filterUnknownNodes(reflect.TypeOf(config), node)
|
filterUnknownNodes(reflect.TypeFor[*configuration](), node)
|
||||||
|
|
||||||
// If no config remains we can return without error, to allow other loaders to proceed.
|
// If no config remains we can return without error, to allow other loaders to proceed.
|
||||||
if node == nil || len(node.Children) == 0 {
|
if node == nil || len(node.Children) == 0 {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (f *FileLoader) Load(args []string, cmd *cli.Command) (bool, error) {
|
|||||||
|
|
||||||
// loadConfigFiles tries to decode the given configuration file and all default locations for the configuration file.
|
// loadConfigFiles tries to decode the given configuration file and all default locations for the configuration file.
|
||||||
// It stops as soon as decoding one of them is successful.
|
// It stops as soon as decoding one of them is successful.
|
||||||
func loadConfigFiles(configFile string, element interface{}) (string, error) {
|
func loadConfigFiles(configFile string, element any) (string, error) {
|
||||||
finder := cli.Finder{
|
finder := cli.Finder{
|
||||||
BasePaths: []string{"/etc/traefik/traefik", "$XDG_CONFIG_HOME/traefik", "$HOME/.config/traefik", "./traefik"},
|
BasePaths: []string{"/etc/traefik/traefik", "$XDG_CONFIG_HOME/traefik", "$HOME/.config/traefik", "./traefik"},
|
||||||
Extensions: []string{"toml", "yaml", "yml"},
|
Extensions: []string{"toml", "yaml", "yml"},
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Hydrate hydrates a configuration.
|
// Hydrate hydrates a configuration.
|
||||||
func Hydrate(element interface{}) error {
|
func Hydrate(element any) error {
|
||||||
field := reflect.ValueOf(element)
|
field := reflect.ValueOf(element)
|
||||||
return fill(field)
|
return fill(field)
|
||||||
}
|
}
|
||||||
@@ -81,7 +81,7 @@ func fill(field reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTyped(field reflect.Value, i interface{}) {
|
func setTyped(field reflect.Value, i any) {
|
||||||
baseValue := reflect.ValueOf(i)
|
baseValue := reflect.ValueOf(i)
|
||||||
if field.Kind().String() == field.Type().String() {
|
if field.Kind().String() == field.Type().String() {
|
||||||
field.Set(baseValue)
|
field.Set(baseValue)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func TestDeepCopy(t *testing.T) {
|
|||||||
|
|
||||||
cfgDeepCopy := cfg.DeepCopy()
|
cfgDeepCopy := cfg.DeepCopy()
|
||||||
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
|
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
|
||||||
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
|
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg)) //nolint:modernize // Comparing runtime types of two values.
|
||||||
assert.Equal(t, cfgDeepCopy, cfg)
|
assert.Equal(t, cfgDeepCopy, cfg)
|
||||||
|
|
||||||
// Update cfg
|
// Update cfg
|
||||||
@@ -32,6 +32,6 @@ func TestDeepCopy(t *testing.T) {
|
|||||||
assert.Equal(t, cfgCopy, cfg)
|
assert.Equal(t, cfgCopy, cfg)
|
||||||
|
|
||||||
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
|
assert.NotEqual(t, reflect.ValueOf(cfgDeepCopy), reflect.ValueOf(cfg))
|
||||||
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg))
|
assert.Equal(t, reflect.TypeOf(cfgDeepCopy), reflect.TypeOf(cfg)) //nolint:modernize // Comparing runtime types of two values.
|
||||||
assert.NotEqual(t, cfgDeepCopy, cfg)
|
assert.NotEqual(t, cfgDeepCopy, cfg)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ type GrpcWeb struct {
|
|||||||
type ContentType struct {
|
type ContentType struct {
|
||||||
// AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
// AutoDetect specifies whether to let the `Content-Type` header, if it has not been set by the backend,
|
||||||
// be automatically set to a value derived from the contents of the response.
|
// be automatically set to a value derived from the contents of the response.
|
||||||
|
//
|
||||||
// Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
// Deprecated: AutoDetect option is deprecated, Content-Type middleware is only meant to be used to enable the content-type detection, please remove any usage of this option.
|
||||||
AutoDetect *bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty" export:"true"`
|
AutoDetect *bool `json:"autoDetect,omitempty" toml:"autoDetect,omitempty" yaml:"autoDetect,omitempty" export:"true"`
|
||||||
}
|
}
|
||||||
@@ -481,6 +482,7 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
|||||||
// IPWhiteList holds the IP whitelist middleware configuration.
|
// IPWhiteList holds the IP whitelist middleware configuration.
|
||||||
// This middleware limits allowed requests based on the client IP.
|
// This middleware limits allowed requests based on the client IP.
|
||||||
// More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/ipwhitelist/
|
// More info: https://doc.traefik.io/traefik/v3.6/middlewares/http/ipwhitelist/
|
||||||
|
//
|
||||||
// Deprecated: please use IPAllowList instead.
|
// Deprecated: please use IPAllowList instead.
|
||||||
type IPWhiteList struct {
|
type IPWhiteList struct {
|
||||||
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required.
|
// SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required.
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ func TestPluginConf_DeepCopy_mapOfStruct(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPluginConf_DeepCopy_map(t *testing.T) {
|
func TestPluginConf_DeepCopy_map(t *testing.T) {
|
||||||
m := map[string]interface{}{
|
m := map[string]any{
|
||||||
"name": "bar",
|
"name": "bar",
|
||||||
}
|
}
|
||||||
p := PluginConf{
|
p := PluginConf{
|
||||||
"config": map[string]interface{}{
|
"config": map[string]any{
|
||||||
"foo": m,
|
"foo": m,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ func TestPluginConf_DeepCopy_map(t *testing.T) {
|
|||||||
|
|
||||||
func TestPluginConf_DeepCopy_panic(t *testing.T) {
|
func TestPluginConf_DeepCopy_panic(t *testing.T) {
|
||||||
p := &PluginConf{
|
p := &PluginConf{
|
||||||
"config": map[string]interface{}{
|
"config": map[string]any{
|
||||||
"foo": &Foo{Name: "gigi"},
|
"foo": &Foo{Name: "gigi"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ type TCPServersLoadBalancer struct {
|
|||||||
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
Servers []TCPServer `json:"servers,omitempty" toml:"servers,omitempty" yaml:"servers,omitempty" label-slice-as-struct:"server" export:"true"`
|
||||||
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty" export:"true"`
|
ServersTransport string `json:"serversTransport,omitempty" toml:"serversTransport,omitempty" yaml:"serversTransport,omitempty" export:"true"`
|
||||||
// ProxyProtocol holds the PROXY Protocol configuration.
|
// ProxyProtocol holds the PROXY Protocol configuration.
|
||||||
|
//
|
||||||
// Deprecated: use ServersTransport to configure ProxyProtocol instead.
|
// Deprecated: use ServersTransport to configure ProxyProtocol instead.
|
||||||
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
ProxyProtocol *ProxyProtocol `json:"proxyProtocol,omitempty" toml:"proxyProtocol,omitempty" yaml:"proxyProtocol,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||||
// TerminationDelay, corresponds to the deadline that the proxy sets, after one
|
// TerminationDelay, corresponds to the deadline that the proxy sets, after one
|
||||||
@@ -95,6 +96,7 @@ type TCPServersLoadBalancer struct {
|
|||||||
// connection, to close the reading capability as well, hence fully terminating the
|
// connection, to close the reading capability as well, hence fully terminating the
|
||||||
// connection. It is a duration in milliseconds, defaulting to 100. A negative value
|
// connection. It is a duration in milliseconds, defaulting to 100. A negative value
|
||||||
// means an infinite deadline (i.e. the reading capability is never closed).
|
// means an infinite deadline (i.e. the reading capability is never closed).
|
||||||
|
//
|
||||||
// Deprecated: use ServersTransport to configure the TerminationDelay instead.
|
// Deprecated: use ServersTransport to configure the TerminationDelay instead.
|
||||||
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty" export:"true"`
|
TerminationDelay *int `json:"terminationDelay,omitempty" toml:"terminationDelay,omitempty" yaml:"terminationDelay,omitempty" export:"true"`
|
||||||
HealthCheck *TCPServerHealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
HealthCheck *TCPServerHealthCheck `json:"healthCheck,omitempty" toml:"healthCheck,omitempty" yaml:"healthCheck,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"`
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ type TCPInFlightConn struct {
|
|||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
// TCPIPWhiteList holds the TCP IPWhiteList middleware configuration.
|
// TCPIPWhiteList holds the TCP IPWhiteList middleware configuration.
|
||||||
|
//
|
||||||
// Deprecated: please use IPAllowList instead.
|
// Deprecated: please use IPAllowList instead.
|
||||||
type TCPIPWhiteList struct {
|
type TCPIPWhiteList struct {
|
||||||
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
// SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation).
|
||||||
|
|||||||
+2
-2
@@ -13,7 +13,7 @@ import (
|
|||||||
// KV pairs -> tree of untyped nodes
|
// KV pairs -> tree of untyped nodes
|
||||||
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
|
// untyped nodes -> nodes augmented with metadata such as kind (inferred from element)
|
||||||
// "typed" nodes -> typed element.
|
// "typed" nodes -> typed element.
|
||||||
func Decode(pairs []*store.KVPair, element interface{}, rootName string) error {
|
func Decode(pairs []*store.KVPair, element any, rootName string) error {
|
||||||
if element == nil {
|
if element == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ func Decode(pairs []*store.KVPair, element interface{}, rootName string) error {
|
|||||||
return parser.Fill(element, node, parser.FillerOpts{AllowSliceAsStruct: false})
|
return parser.Fill(element, node, parser.FillerOpts{AllowSliceAsStruct: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRootFieldNames(rootName string, element interface{}) []string {
|
func getRootFieldNames(rootName string, element any) []string {
|
||||||
if element == nil {
|
if element == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,6 @@ func EncodeConfiguration(conf *dynamic.Configuration) (map[string]string, error)
|
|||||||
|
|
||||||
// Decode converts the labels to an element.
|
// Decode converts the labels to an element.
|
||||||
// labels -> [ node -> node + metadata (type) ] -> element (node).
|
// labels -> [ node -> node + metadata (type) ] -> element (node).
|
||||||
func Decode(labels map[string]string, element interface{}, filters ...string) error {
|
func Decode(labels map[string]string, element any, filters ...string) error {
|
||||||
return parser.Decode(labels, element, parser.DefaultRootName, filters...)
|
return parser.Decode(labels, element, parser.DefaultRootName, filters...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -74,6 +75,7 @@ func unique(src []string) []string {
|
|||||||
// RouterInfo holds information about a currently running HTTP router.
|
// RouterInfo holds information about a currently running HTTP router.
|
||||||
type RouterInfo struct {
|
type RouterInfo struct {
|
||||||
*dynamic.Router // dynamic configuration
|
*dynamic.Router // dynamic configuration
|
||||||
|
|
||||||
// Err contains all the errors that occurred during router's creation.
|
// Err contains all the errors that occurred during router's creation.
|
||||||
Err []string `json:"error,omitempty"`
|
Err []string `json:"error,omitempty"`
|
||||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||||
@@ -91,10 +93,8 @@ type RouterInfo struct {
|
|||||||
// AddError adds err to r.Err, if it does not already exist.
|
// AddError adds err to r.Err, if it does not already exist.
|
||||||
// If critical is set, r is marked as disabled.
|
// If critical is set, r is marked as disabled.
|
||||||
func (r *RouterInfo) AddError(err error, critical bool) {
|
func (r *RouterInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range r.Err {
|
if slices.Contains(r.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Err = append(r.Err, err.Error())
|
r.Err = append(r.Err, err.Error())
|
||||||
@@ -112,6 +112,7 @@ func (r *RouterInfo) AddError(err error, critical bool) {
|
|||||||
// MiddlewareInfo holds information about a currently running middleware.
|
// MiddlewareInfo holds information about a currently running middleware.
|
||||||
type MiddlewareInfo struct {
|
type MiddlewareInfo struct {
|
||||||
*dynamic.Middleware // dynamic configuration
|
*dynamic.Middleware // dynamic configuration
|
||||||
|
|
||||||
// Err contains all the errors that occurred during service creation.
|
// Err contains all the errors that occurred during service creation.
|
||||||
Err []string `json:"error,omitempty"`
|
Err []string `json:"error,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
@@ -121,10 +122,8 @@ type MiddlewareInfo struct {
|
|||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
// If critical is set, m is marked as disabled.
|
// If critical is set, m is marked as disabled.
|
||||||
func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range m.Err {
|
if slices.Contains(m.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Err = append(m.Err, err.Error())
|
m.Err = append(m.Err, err.Error())
|
||||||
@@ -142,6 +141,7 @@ func (m *MiddlewareInfo) AddError(err error, critical bool) {
|
|||||||
// ServiceInfo holds information about a currently running service.
|
// ServiceInfo holds information about a currently running service.
|
||||||
type ServiceInfo struct {
|
type ServiceInfo struct {
|
||||||
*dynamic.Service // dynamic configuration
|
*dynamic.Service // dynamic configuration
|
||||||
|
|
||||||
// Err contains all the errors that occurred during service creation.
|
// Err contains all the errors that occurred during service creation.
|
||||||
Err []string `json:"error,omitempty"`
|
Err []string `json:"error,omitempty"`
|
||||||
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
||||||
@@ -157,10 +157,8 @@ type ServiceInfo struct {
|
|||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
// If critical is set, s is marked as disabled.
|
// If critical is set, s is marked as disabled.
|
||||||
func (s *ServiceInfo) AddError(err error, critical bool) {
|
func (s *ServiceInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range s.Err {
|
if slices.Contains(s.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Err = append(s.Err, err.Error())
|
s.Err = append(s.Err, err.Error())
|
||||||
@@ -197,9 +195,5 @@ func (s *ServiceInfo) GetAllStatus() map[string]string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
allStatus := make(map[string]string, len(s.serverStatus))
|
return maps.Clone(s.serverStatus)
|
||||||
for k, v := range s.serverStatus {
|
|
||||||
allStatus[k] = v
|
|
||||||
}
|
|
||||||
return allStatus
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -49,8 +50,9 @@ func (c *Configuration) GetTCPRoutersByEntryPoints(ctx context.Context, entryPoi
|
|||||||
|
|
||||||
// TCPRouterInfo holds information about a currently running TCP router.
|
// TCPRouterInfo holds information about a currently running TCP router.
|
||||||
type TCPRouterInfo struct {
|
type TCPRouterInfo struct {
|
||||||
*dynamic.TCPRouter // dynamic configuration
|
*dynamic.TCPRouter // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
|
||||||
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
@@ -61,10 +63,8 @@ type TCPRouterInfo struct {
|
|||||||
// AddError adds err to r.Err, if it does not already exist.
|
// AddError adds err to r.Err, if it does not already exist.
|
||||||
// If critical is set, r is marked as disabled.
|
// If critical is set, r is marked as disabled.
|
||||||
func (r *TCPRouterInfo) AddError(err error, critical bool) {
|
func (r *TCPRouterInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range r.Err {
|
if slices.Contains(r.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Err = append(r.Err, err.Error())
|
r.Err = append(r.Err, err.Error())
|
||||||
@@ -81,8 +81,9 @@ func (r *TCPRouterInfo) AddError(err error, critical bool) {
|
|||||||
|
|
||||||
// TCPServiceInfo holds information about a currently running TCP service.
|
// TCPServiceInfo holds information about a currently running TCP service.
|
||||||
type TCPServiceInfo struct {
|
type TCPServiceInfo struct {
|
||||||
*dynamic.TCPService // dynamic configuration
|
*dynamic.TCPService // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
|
||||||
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
@@ -96,10 +97,8 @@ type TCPServiceInfo struct {
|
|||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
// If critical is set, s is marked as disabled.
|
// If critical is set, s is marked as disabled.
|
||||||
func (s *TCPServiceInfo) AddError(err error, critical bool) {
|
func (s *TCPServiceInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range s.Err {
|
if slices.Contains(s.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Err = append(s.Err, err.Error())
|
s.Err = append(s.Err, err.Error())
|
||||||
@@ -135,15 +134,14 @@ func (s *TCPServiceInfo) GetAllStatus() map[string]string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
allStatus := make(map[string]string, len(s.serverStatus))
|
allStatus := make(map[string]string, len(s.serverStatus))
|
||||||
for k, v := range s.serverStatus {
|
maps.Copy(allStatus, s.serverStatus)
|
||||||
allStatus[k] = v
|
|
||||||
}
|
|
||||||
return allStatus
|
return allStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCPMiddlewareInfo holds information about a currently running middleware.
|
// TCPMiddlewareInfo holds information about a currently running middleware.
|
||||||
type TCPMiddlewareInfo struct {
|
type TCPMiddlewareInfo struct {
|
||||||
*dynamic.TCPMiddleware // dynamic configuration
|
*dynamic.TCPMiddleware // dynamic configuration
|
||||||
|
|
||||||
// Err contains all the errors that occurred during service creation.
|
// Err contains all the errors that occurred during service creation.
|
||||||
Err []string `json:"error,omitempty"`
|
Err []string `json:"error,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
@@ -153,10 +151,8 @@ type TCPMiddlewareInfo struct {
|
|||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
// If critical is set, m is marked as disabled.
|
// If critical is set, m is marked as disabled.
|
||||||
func (m *TCPMiddlewareInfo) AddError(err error, critical bool) {
|
func (m *TCPMiddlewareInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range m.Err {
|
if slices.Contains(m.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Err = append(m.Err, err.Error())
|
m.Err = append(m.Err, err.Error())
|
||||||
|
|||||||
@@ -54,8 +54,9 @@ func (c *Configuration) GetUDPRoutersByEntryPoints(ctx context.Context, entryPoi
|
|||||||
|
|
||||||
// UDPRouterInfo holds information about a currently running UDP router.
|
// UDPRouterInfo holds information about a currently running UDP router.
|
||||||
type UDPRouterInfo struct {
|
type UDPRouterInfo struct {
|
||||||
*dynamic.UDPRouter // dynamic configuration
|
*dynamic.UDPRouter // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
|
||||||
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the router is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
@@ -66,10 +67,8 @@ type UDPRouterInfo struct {
|
|||||||
// AddError adds err to r.Err, if it does not already exist.
|
// AddError adds err to r.Err, if it does not already exist.
|
||||||
// If critical is set, r is marked as disabled.
|
// If critical is set, r is marked as disabled.
|
||||||
func (r *UDPRouterInfo) AddError(err error, critical bool) {
|
func (r *UDPRouterInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range r.Err {
|
if slices.Contains(r.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Err = append(r.Err, err.Error())
|
r.Err = append(r.Err, err.Error())
|
||||||
@@ -86,8 +85,9 @@ func (r *UDPRouterInfo) AddError(err error, critical bool) {
|
|||||||
|
|
||||||
// UDPServiceInfo holds information about a currently running UDP service.
|
// UDPServiceInfo holds information about a currently running UDP service.
|
||||||
type UDPServiceInfo struct {
|
type UDPServiceInfo struct {
|
||||||
*dynamic.UDPService // dynamic configuration
|
*dynamic.UDPService // dynamic configuration
|
||||||
Err []string `json:"error,omitempty"` // initialization error
|
|
||||||
|
Err []string `json:"error,omitempty"` // initialization error
|
||||||
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
// Status reports whether the service is disabled, in a warning state, or all good (enabled).
|
||||||
// If not in "enabled" state, the reason for it should be in the list of Err.
|
// If not in "enabled" state, the reason for it should be in the list of Err.
|
||||||
// It is the caller's responsibility to set the initial status.
|
// It is the caller's responsibility to set the initial status.
|
||||||
@@ -98,10 +98,8 @@ type UDPServiceInfo struct {
|
|||||||
// AddError adds err to s.Err, if it does not already exist.
|
// AddError adds err to s.Err, if it does not already exist.
|
||||||
// If critical is set, s is marked as disabled.
|
// If critical is set, s is marked as disabled.
|
||||||
func (s *UDPServiceInfo) AddError(err error, critical bool) {
|
func (s *UDPServiceInfo) AddError(err error, critical bool) {
|
||||||
for _, value := range s.Err {
|
if slices.Contains(s.Err, err.Error()) {
|
||||||
if value == err.Error() {
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Err = append(s.Err, err.Error())
|
s.Err = append(s.Err, err.Error())
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package static
|
package static
|
||||||
|
|
||||||
// PluginConf holds the plugin configuration.
|
// PluginConf holds the plugin configuration.
|
||||||
type PluginConf map[string]interface{}
|
type PluginConf map[string]any
|
||||||
|
|||||||
@@ -393,21 +393,6 @@ func (c *Configuration) SetEffectiveConfiguration() {
|
|||||||
c.initACMEProvider()
|
c.initACMEProvider()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Configuration) hasUserDefinedEntrypoint() bool {
|
|
||||||
return len(c.EntryPoints) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Configuration) initACMEProvider() {
|
|
||||||
for _, resolver := range c.CertificatesResolvers {
|
|
||||||
if resolver.ACME != nil {
|
|
||||||
resolver.ACME.CAServer = getSafeACMECAServer(resolver.ACME.CAServer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := logs.NoLevel(log.Logger, zerolog.DebugLevel).With().Str("lib", "lego").Logger()
|
|
||||||
legolog.Logger = logs.NewLogrusWrapper(logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateConfiguration validate that configuration is coherent.
|
// ValidateConfiguration validate that configuration is coherent.
|
||||||
func (c *Configuration) ValidateConfiguration() error {
|
func (c *Configuration) ValidateConfiguration() error {
|
||||||
for name, resolver := range c.CertificatesResolvers {
|
for name, resolver := range c.CertificatesResolvers {
|
||||||
@@ -494,6 +479,21 @@ func (c *Configuration) ValidateConfiguration() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) hasUserDefinedEntrypoint() bool {
|
||||||
|
return len(c.EntryPoints) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Configuration) initACMEProvider() {
|
||||||
|
for _, resolver := range c.CertificatesResolvers {
|
||||||
|
if resolver.ACME != nil {
|
||||||
|
resolver.ACME.CAServer = getSafeACMECAServer(resolver.ACME.CAServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger := logs.NoLevel(log.Logger, zerolog.DebugLevel).With().Str("lib", "lego").Logger()
|
||||||
|
legolog.Logger = logs.NewLogrusWrapper(logger)
|
||||||
|
}
|
||||||
|
|
||||||
func getSafeACMECAServer(caServerSrc string) string {
|
func getSafeACMECAServer(caServerSrc string) string {
|
||||||
if len(caServerSrc) == 0 {
|
if len(caServerSrc) == 0 {
|
||||||
return DefaultAcmeCAServer
|
return DefaultAcmeCAServer
|
||||||
|
|||||||
@@ -391,7 +391,7 @@ func (p *PassiveServiceHealthChecker) WrapHandler(ctx context.Context, next http
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need to guarantee that only one goroutine (request) will update the status and create a timer for the target.
|
// We need to guarantee that only one goroutine (request) will update the status and create a timer for the target.
|
||||||
_, _, _ = p.timersGroup.Do(targetURL, func() (interface{}, error) {
|
_, _, _ = p.timersGroup.Do(targetURL, func() (any, error) {
|
||||||
// A timer is already running for this target;
|
// A timer is already running for this target;
|
||||||
// it means that the target is already considered unhealthy.
|
// it means that the target is already considered unhealthy.
|
||||||
if _, ok := p.timers.Load(targetURL); ok {
|
if _, ok := p.timers.Load(targetURL); ok {
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ type testLoadBalancer struct {
|
|||||||
// RWMutex needed due to parallel test execution: Both the system-under-test
|
// RWMutex needed due to parallel test execution: Both the system-under-test
|
||||||
// and the test assertions reference the counters.
|
// and the test assertions reference the counters.
|
||||||
*sync.RWMutex
|
*sync.RWMutex
|
||||||
|
|
||||||
numRemovedServers int
|
numRemovedServers int
|
||||||
numUpsertedServers int
|
numUpsertedServers int
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
// If operation() takes more than MinJobInterval, Reset() is called in NextBackOff().
|
// If operation() takes more than MinJobInterval, Reset() is called in NextBackOff().
|
||||||
type BackOff struct {
|
type BackOff struct {
|
||||||
*backoff.ExponentialBackOff
|
*backoff.ExponentialBackOff
|
||||||
|
|
||||||
MinJobInterval time.Duration
|
MinJobInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func TestConcatFieldHandler_ServeHTTP(t *testing.T) {
|
func TestConcatFieldHandler_ServeHTTP(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
existingValue interface{}
|
existingValue any
|
||||||
newValue string
|
newValue string
|
||||||
expectedResult string
|
expectedResult string
|
||||||
}{
|
}{
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CoreLogData holds the fields computed from the request/response.
|
// CoreLogData holds the fields computed from the request/response.
|
||||||
type CoreLogData map[string]interface{}
|
type CoreLogData map[string]any
|
||||||
|
|
||||||
// LogData is the data captured by the middleware so that it can be logged.
|
// LogData is the data captured by the middleware so that it can be logged.
|
||||||
type LogData struct {
|
type LogData struct {
|
||||||
|
|||||||
@@ -74,20 +74,6 @@ type Handler struct {
|
|||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
// AliceConstructor returns an alice.Constructor that wraps the Handler (conditionally) in a middleware chain.
|
|
||||||
func (h *Handler) AliceConstructor() alice.Constructor {
|
|
||||||
return func(next http.Handler) (http.Handler, error) {
|
|
||||||
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
|
||||||
if h == nil {
|
|
||||||
next.ServeHTTP(rw, req)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
h.ServeHTTP(rw, req, next)
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHandler creates a new Handler.
|
// NewHandler creates a new Handler.
|
||||||
func NewHandler(ctx context.Context, config *otypes.AccessLog) (*Handler, error) {
|
func NewHandler(ctx context.Context, config *otypes.AccessLog) (*Handler, error) {
|
||||||
var file io.WriteCloser = noopCloser{os.Stdout}
|
var file io.WriteCloser = noopCloser{os.Stdout}
|
||||||
@@ -183,28 +169,18 @@ func NewHandler(ctx context.Context, config *otypes.AccessLog) (*Handler, error)
|
|||||||
return logHandler, nil
|
return logHandler, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func openAccessLogFile(filePath string) (*os.File, error) {
|
// AliceConstructor returns an alice.Constructor that wraps the Handler (conditionally) in a middleware chain.
|
||||||
dir := filepath.Dir(filePath)
|
func (h *Handler) AliceConstructor() alice.Constructor {
|
||||||
|
return func(next http.Handler) (http.Handler, error) {
|
||||||
|
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||||
|
if h == nil {
|
||||||
|
next.ServeHTTP(rw, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
h.ServeHTTP(rw, req, next)
|
||||||
return nil, fmt.Errorf("failed to create log path %s: %w", dir, err)
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error opening file %s: %w", filePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return file, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogData gets the request context object that contains logging data.
|
|
||||||
// This creates data as the request passes through the middleware chain.
|
|
||||||
func GetLogData(req *http.Request) *LogData {
|
|
||||||
if ld, ok := req.Context().Value(DataTableKey).(*LogData); ok {
|
|
||||||
return ld
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http.Handler) {
|
||||||
@@ -335,23 +311,6 @@ func (h *Handler) Rotate() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func silentSplitHostPort(value string) (host, port string) {
|
|
||||||
host, port, err := net.SplitHostPort(value)
|
|
||||||
if err != nil {
|
|
||||||
return value, "-"
|
|
||||||
}
|
|
||||||
return host, port
|
|
||||||
}
|
|
||||||
|
|
||||||
func usernameIfPresent(theURL *url.URL) string {
|
|
||||||
if theURL.User != nil {
|
|
||||||
if name := theURL.User.Username(); name != "" {
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "-"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logging handler to log frontend name, backend name, and elapsed time.
|
// Logging handler to log frontend name, backend name, and elapsed time.
|
||||||
func (h *Handler) logTheRoundTrip(ctx context.Context, logDataTable *LogData) {
|
func (h *Handler) logTheRoundTrip(ctx context.Context, logDataTable *LogData) {
|
||||||
core := logDataTable.Core
|
core := logDataTable.Core
|
||||||
@@ -458,6 +417,47 @@ func (h *Handler) keepAccessLog(statusCode, retryAttempts int, duration time.Dur
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLogData gets the request context object that contains logging data.
|
||||||
|
// This creates data as the request passes through the middleware chain.
|
||||||
|
func GetLogData(req *http.Request) *LogData {
|
||||||
|
if ld, ok := req.Context().Value(DataTableKey).(*LogData); ok {
|
||||||
|
return ld
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func openAccessLogFile(filePath string) (*os.File, error) {
|
||||||
|
dir := filepath.Dir(filePath)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create log path %s: %w", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o664)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error opening file %s: %w", filePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return file, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func silentSplitHostPort(value string) (host, port string) {
|
||||||
|
host, port, err := net.SplitHostPort(value)
|
||||||
|
if err != nil {
|
||||||
|
return value, "-"
|
||||||
|
}
|
||||||
|
return host, port
|
||||||
|
}
|
||||||
|
|
||||||
|
func usernameIfPresent(theURL *url.URL) string {
|
||||||
|
if theURL.User != nil {
|
||||||
|
if name := theURL.User.Username(); name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "-"
|
||||||
|
}
|
||||||
|
|
||||||
var requestCounter uint64 // Request ID
|
var requestCounter uint64 // Request ID
|
||||||
|
|
||||||
func nextRequestCount() uint64 {
|
func nextRequestCount() uint64 {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (f *GenericCLFLogFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|||||||
return b.Bytes(), err
|
return b.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) interface{} {
|
func toLog(fields logrus.Fields, key, defaultValue string, quoted bool) any {
|
||||||
if v, ok := fields[key]; ok {
|
if v, ok := fields[key]; ok {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return defaultValue
|
return defaultValue
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ func TestCommonLogFormatter_Format(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
data map[string]interface{}
|
data map[string]any
|
||||||
expectedLog string
|
expectedLog string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "DownstreamStatus & DownstreamContentSize are nil",
|
name: "DownstreamStatus & DownstreamContentSize are nil",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -41,7 +41,7 @@ func TestCommonLogFormatter_Format(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all data",
|
name: "all data",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -62,7 +62,7 @@ func TestCommonLogFormatter_Format(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all data with local time",
|
name: "all data with local time",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartLocal: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartLocal: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -106,12 +106,12 @@ func TestGenericCLFLogFormatter_Format(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
data map[string]interface{}
|
data map[string]any
|
||||||
expectedLog string
|
expectedLog string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "DownstreamStatus & DownstreamContentSize are nil",
|
name: "DownstreamStatus & DownstreamContentSize are nil",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -132,7 +132,7 @@ func TestGenericCLFLogFormatter_Format(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all data",
|
name: "all data",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -153,7 +153,7 @@ func TestGenericCLFLogFormatter_Format(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "all data with local time",
|
name: "all data with local time",
|
||||||
data: map[string]interface{}{
|
data: map[string]any{
|
||||||
StartLocal: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
StartLocal: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||||
Duration: 123 * time.Second,
|
Duration: 123 * time.Second,
|
||||||
ClientHost: "10.0.0.1",
|
ClientHost: "10.0.0.1",
|
||||||
@@ -199,7 +199,7 @@ func Test_toLog(t *testing.T) {
|
|||||||
fieldName string
|
fieldName string
|
||||||
defaultValue string
|
defaultValue string
|
||||||
quoted bool
|
quoted bool
|
||||||
expectedLog interface{}
|
expectedLog any
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Should return int 1",
|
desc: "Should return int 1",
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ func lineCount(t *testing.T, fileName string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for _, line := range strings.Split(string(fileContents), "\n") {
|
for line := range strings.SplitSeq(string(fileContents), "\n") {
|
||||||
if strings.TrimSpace(line) == "" {
|
if strings.TrimSpace(line) == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -439,32 +439,32 @@ func TestLoggerGenericCLFWithBufferingSize(t *testing.T) {
|
|||||||
assertValidGenericCLFLogData(t, expectedLog, logData)
|
assertValidGenericCLFLogData(t, expectedLog, logData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertString(exp string) func(t *testing.T, actual interface{}) {
|
func assertString(exp string) func(t *testing.T, actual any) {
|
||||||
return func(t *testing.T, actual interface{}) {
|
return func(t *testing.T, actual any) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
assert.Equal(t, exp, actual)
|
assert.Equal(t, exp, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertNotEmpty() func(t *testing.T, actual interface{}) {
|
func assertNotEmpty() func(t *testing.T, actual any) {
|
||||||
return func(t *testing.T, actual interface{}) {
|
return func(t *testing.T, actual any) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
assert.NotEmpty(t, actual)
|
assert.NotEmpty(t, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertFloat64(exp float64) func(t *testing.T, actual interface{}) {
|
func assertFloat64(exp float64) func(t *testing.T, actual any) {
|
||||||
return func(t *testing.T, actual interface{}) {
|
return func(t *testing.T, actual any) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
assert.InDelta(t, exp, actual, delta)
|
assert.InDelta(t, exp, actual, delta)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertFloat64NotZero() func(t *testing.T, actual interface{}) {
|
func assertFloat64NotZero() func(t *testing.T, actual any) {
|
||||||
return func(t *testing.T, actual interface{}) {
|
return func(t *testing.T, actual any) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
assert.NotZero(t, actual)
|
assert.NotZero(t, actual)
|
||||||
@@ -477,7 +477,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
config *otypes.AccessLog
|
config *otypes.AccessLog
|
||||||
tls bool
|
tls bool
|
||||||
tracing bool
|
tracing bool
|
||||||
expected map[string]func(t *testing.T, value interface{})
|
expected map[string]func(t *testing.T, value any)
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "default config without tracing",
|
desc: "default config without tracing",
|
||||||
@@ -485,7 +485,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
FilePath: "",
|
FilePath: "",
|
||||||
Format: JSONFormat,
|
Format: JSONFormat,
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
RequestContentSize: assertFloat64(0),
|
RequestContentSize: assertFloat64(0),
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
RequestAddr: assertString(testHostname),
|
RequestAddr: assertString(testHostname),
|
||||||
@@ -525,7 +525,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
Format: JSONFormat,
|
Format: JSONFormat,
|
||||||
},
|
},
|
||||||
tracing: true,
|
tracing: true,
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
RequestContentSize: assertFloat64(0),
|
RequestContentSize: assertFloat64(0),
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
RequestAddr: assertString(testHostname),
|
RequestAddr: assertString(testHostname),
|
||||||
@@ -567,7 +567,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
Format: JSONFormat,
|
Format: JSONFormat,
|
||||||
},
|
},
|
||||||
tls: true,
|
tls: true,
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
RequestContentSize: assertFloat64(0),
|
RequestContentSize: assertFloat64(0),
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
RequestAddr: assertString(testHostname),
|
RequestAddr: assertString(testHostname),
|
||||||
@@ -612,7 +612,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
DefaultMode: "drop",
|
DefaultMode: "drop",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
@@ -633,7 +633,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
@@ -651,7 +651,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"time": assertNotEmpty(),
|
"time": assertNotEmpty(),
|
||||||
@@ -678,7 +678,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
@@ -704,7 +704,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value any){
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
@@ -730,7 +730,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
logData, err := os.ReadFile(logFilePath)
|
logData, err := os.ReadFile(logFilePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
jsonData := make(map[string]interface{})
|
jsonData := make(map[string]any)
|
||||||
err = json.Unmarshal(logData, &jsonData)
|
err = json.Unmarshal(logData, &jsonData)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@@ -744,7 +744,7 @@ func TestLoggerJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestLogger_AbortedRequest(t *testing.T) {
|
func TestLogger_AbortedRequest(t *testing.T) {
|
||||||
expected := map[string]func(t *testing.T, value interface{}){
|
expected := map[string]func(t *testing.T, value any){
|
||||||
RequestContentSize: assertFloat64(0),
|
RequestContentSize: assertFloat64(0),
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
RequestAddr: assertString(testHostname),
|
RequestAddr: assertString(testHostname),
|
||||||
@@ -787,7 +787,7 @@ func TestLogger_AbortedRequest(t *testing.T) {
|
|||||||
logData, err := os.ReadFile(config.FilePath)
|
logData, err := os.ReadFile(config.FilePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
jsonData := make(map[string]interface{})
|
jsonData := make(map[string]any)
|
||||||
err = json.Unmarshal(logData, &jsonData)
|
err = json.Unmarshal(logData, &jsonData)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func RemoveConnectionHeaders(req *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range req.Header[connectionHeader] {
|
for _, f := range req.Header[connectionHeader] {
|
||||||
for _, sf := range strings.Split(f, ",") {
|
for sf := range strings.SplitSeq(f, ",") {
|
||||||
if sf = textproto.TrimString(sf); sf != "" {
|
if sf = textproto.TrimString(sf); sf != "" {
|
||||||
req.Header.Del(sf)
|
req.Header.Del(sf)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,20 +96,6 @@ func (c *Capture) Reset(next http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Capture) renew(rw http.ResponseWriter, req *http.Request) (http.ResponseWriter, *http.Request) {
|
|
||||||
ctx := context.WithValue(req.Context(), capturedData, c)
|
|
||||||
newReq := req.WithContext(ctx)
|
|
||||||
|
|
||||||
if newReq.Body != nil {
|
|
||||||
readCounter := &readCounter{source: newReq.Body}
|
|
||||||
c.rr = readCounter
|
|
||||||
newReq.Body = readCounter
|
|
||||||
}
|
|
||||||
c.crw = &captureResponseWriter{rw: rw}
|
|
||||||
|
|
||||||
return c.crw, newReq
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Capture) ResponseSize() int64 {
|
func (c *Capture) ResponseSize() int64 {
|
||||||
return c.crw.Size()
|
return c.crw.Size()
|
||||||
}
|
}
|
||||||
@@ -127,6 +113,20 @@ func (c *Capture) RequestSize() int64 {
|
|||||||
return c.rr.size
|
return c.rr.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Capture) renew(rw http.ResponseWriter, req *http.Request) (http.ResponseWriter, *http.Request) {
|
||||||
|
ctx := context.WithValue(req.Context(), capturedData, c)
|
||||||
|
newReq := req.WithContext(ctx)
|
||||||
|
|
||||||
|
if newReq.Body != nil {
|
||||||
|
readCounter := &readCounter{source: newReq.Body}
|
||||||
|
c.rr = readCounter
|
||||||
|
newReq.Body = readCounter
|
||||||
|
}
|
||||||
|
c.crw = &captureResponseWriter{rw: rw}
|
||||||
|
|
||||||
|
return c.crw, newReq
|
||||||
|
}
|
||||||
|
|
||||||
type readCounter struct {
|
type readCounter struct {
|
||||||
// source ReadCloser from where the request body is read.
|
// source ReadCloser from where the request body is read.
|
||||||
source io.ReadCloser
|
source io.ReadCloser
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ func parseAcceptableEncodings(acceptEncoding []string, supportedEncodings map[st
|
|||||||
var encodings []Encoding
|
var encodings []Encoding
|
||||||
|
|
||||||
for _, line := range acceptEncoding {
|
for _, line := range acceptEncoding {
|
||||||
for _, item := range strings.Split(strings.ReplaceAll(line, " ", ""), ",") {
|
for item := range strings.SplitSeq(strings.ReplaceAll(line, " ", ""), ",") {
|
||||||
parsed := strings.SplitN(item, ";", 2)
|
parsed := strings.SplitN(item, ";", 2)
|
||||||
if len(parsed) == 0 {
|
if len(parsed) == 0 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -167,6 +167,10 @@ func (c *compress) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
c.chooseHandler(c.getCompressionEncoding(acceptEncoding), rw, req)
|
c.chooseHandler(c.getCompressionEncoding(acceptEncoding), rw, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *compress) GetTracingInformation() (string, string) {
|
||||||
|
return c.name, typeName
|
||||||
|
}
|
||||||
|
|
||||||
func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.Request) {
|
func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.Request) {
|
||||||
switch typ {
|
switch typ {
|
||||||
case zstdName:
|
case zstdName:
|
||||||
@@ -180,10 +184,6 @@ func (c *compress) chooseHandler(typ string, rw http.ResponseWriter, req *http.R
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *compress) GetTracingInformation() (string, string) {
|
|
||||||
return c.name, typeName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *compress) newGzipHandler() (http.Handler, error) {
|
func (c *compress) newGzipHandler() (http.Handler, error) {
|
||||||
var wrapper func(http.Handler) http.HandlerFunc
|
var wrapper func(http.Handler) http.HandlerFunc
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -156,6 +156,7 @@ func (c *CompressionHandler) putCompressionWriter(writer *compressionWriterWrapp
|
|||||||
|
|
||||||
type compressionWriterWrapper struct {
|
type compressionWriterWrapper struct {
|
||||||
CompressionWriter
|
CompressionWriter
|
||||||
|
|
||||||
algo string
|
algo string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -874,10 +874,7 @@ func Test_FlushExcludedContentTypes(t *testing.T) {
|
|||||||
for len(tb) > 0 {
|
for len(tb) > 0 {
|
||||||
// Write 100 bytes per run
|
// Write 100 bytes per run
|
||||||
// Detection should not be affected (we send 100 bytes)
|
// Detection should not be affected (we send 100 bytes)
|
||||||
toWrite := 100
|
toWrite := min(100, len(tb))
|
||||||
if toWrite > len(tb) {
|
|
||||||
toWrite = len(tb)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := rw.Write(tb[:toWrite])
|
_, err := rw.Write(tb[:toWrite])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -998,10 +995,7 @@ func Test_FlushIncludedContentTypes(t *testing.T) {
|
|||||||
for len(tb) > 0 {
|
for len(tb) > 0 {
|
||||||
// Write 100 bytes per run
|
// Write 100 bytes per run
|
||||||
// Detection should not be affected (we send 100 bytes)
|
// Detection should not be affected (we send 100 bytes)
|
||||||
toWrite := 100
|
toWrite := min(100, len(tb))
|
||||||
if toWrite > len(tb) {
|
|
||||||
toWrite = len(tb)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := rw.Write(tb[:toWrite])
|
_, err := rw.Write(tb[:toWrite])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -198,16 +199,6 @@ func (cc *codeCatcher) Header() http.Header {
|
|||||||
return cc.headerMap
|
return cc.headerMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *codeCatcher) getCode() int {
|
|
||||||
return cc.code
|
|
||||||
}
|
|
||||||
|
|
||||||
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
|
|
||||||
// and for which the response should be deferred to the error handler.
|
|
||||||
func (cc *codeCatcher) isFilteredCode() bool {
|
|
||||||
return cc.caughtFilteredCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *codeCatcher) Write(buf []byte) (int, error) {
|
func (cc *codeCatcher) Write(buf []byte) (int, error) {
|
||||||
// If WriteHeader was already called from the caller, this is a NOOP.
|
// If WriteHeader was already called from the caller, this is a NOOP.
|
||||||
// Otherwise, cc.code is actually a 200 here.
|
// Otherwise, cc.code is actually a 200 here.
|
||||||
@@ -233,9 +224,7 @@ func (cc *codeCatcher) WriteHeader(code int) {
|
|||||||
if code >= 100 && code <= 199 {
|
if code >= 100 && code <= 199 {
|
||||||
// Multiple informational status codes can be used,
|
// Multiple informational status codes can be used,
|
||||||
// so here the copy is not appending the values to not repeat them.
|
// so here the copy is not appending the values to not repeat them.
|
||||||
for k, v := range cc.Header() {
|
maps.Copy(cc.responseWriter.Header(), cc.Header())
|
||||||
cc.responseWriter.Header()[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
cc.responseWriter.WriteHeader(code)
|
cc.responseWriter.WriteHeader(code)
|
||||||
return
|
return
|
||||||
@@ -253,9 +242,8 @@ func (cc *codeCatcher) WriteHeader(code int) {
|
|||||||
|
|
||||||
// The copy is not appending the values,
|
// The copy is not appending the values,
|
||||||
// to not repeat them in case any informational status code has been written.
|
// to not repeat them in case any informational status code has been written.
|
||||||
for k, v := range cc.Header() {
|
maps.Copy(cc.responseWriter.Header(), cc.Header())
|
||||||
cc.responseWriter.Header()[k] = v
|
|
||||||
}
|
|
||||||
cc.responseWriter.WriteHeader(cc.code)
|
cc.responseWriter.WriteHeader(cc.code)
|
||||||
cc.headersSent = true
|
cc.headersSent = true
|
||||||
}
|
}
|
||||||
@@ -288,6 +276,16 @@ func (cc *codeCatcher) Flush() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cc *codeCatcher) getCode() int {
|
||||||
|
return cc.code
|
||||||
|
}
|
||||||
|
|
||||||
|
// isFilteredCode returns whether the codeCatcher received a response code among the ones it is watching,
|
||||||
|
// and for which the response should be deferred to the error handler.
|
||||||
|
func (cc *codeCatcher) isFilteredCode() bool {
|
||||||
|
return cc.caughtFilteredCode
|
||||||
|
}
|
||||||
|
|
||||||
// codeModifier forwards a response back to the client,
|
// codeModifier forwards a response back to the client,
|
||||||
// while enforcing a given response code.
|
// while enforcing a given response code.
|
||||||
type codeModifier struct {
|
type codeModifier struct {
|
||||||
@@ -343,17 +341,14 @@ func (r *codeModifier) WriteHeader(code int) {
|
|||||||
if code >= 100 && code <= 199 {
|
if code >= 100 && code <= 199 {
|
||||||
// Multiple informational status codes can be used,
|
// Multiple informational status codes can be used,
|
||||||
// so here the copy is not appending the values to not repeat them.
|
// so here the copy is not appending the values to not repeat them.
|
||||||
for k, v := range r.headerMap {
|
maps.Copy(r.responseWriter.Header(), r.headerMap)
|
||||||
r.responseWriter.Header()[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
r.responseWriter.WriteHeader(code)
|
r.responseWriter.WriteHeader(code)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range r.headerMap {
|
maps.Copy(r.responseWriter.Header(), r.headerMap)
|
||||||
r.responseWriter.Header()[k] = v
|
|
||||||
}
|
|
||||||
r.responseWriter.WriteHeader(r.code)
|
r.responseWriter.WriteHeader(r.code)
|
||||||
r.headerSent = true
|
r.headerSent = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,18 +81,11 @@ func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []strin
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XForwarded) isTrustedIP(ip string) bool {
|
|
||||||
if x.ipChecker == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return x.ipChecker.IsAuthorized(ip) == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has {zone} information in it,
|
// removeIPv6Zone removes the zone if the given IP is an ipv6 address and it has {zone} information in it,
|
||||||
// like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692".
|
// like "[fe80::d806:a55d:eb1b:49cc%vEthernet (vmxnet3 Ethernet Adapter - Virtual Switch)]:64692".
|
||||||
func removeIPv6Zone(clientIP string) string {
|
func removeIPv6Zone(clientIP string) string {
|
||||||
if idx := strings.Index(clientIP, "%"); idx != -1 {
|
if before, _, found := strings.Cut(clientIP, "%"); found {
|
||||||
return clientIP[:idx]
|
return before
|
||||||
}
|
}
|
||||||
return clientIP
|
return clientIP
|
||||||
}
|
}
|
||||||
@@ -138,6 +131,28 @@ func forwardedPort(req *http.Request) string {
|
|||||||
return "80"
|
return "80"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServeHTTP implements http.Handler.
|
||||||
|
func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
|
||||||
|
for _, h := range xHeaders {
|
||||||
|
unsafeHeader(r.Header).Del(h)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x.rewrite(r)
|
||||||
|
|
||||||
|
x.removeConnectionHeaders(r)
|
||||||
|
|
||||||
|
x.next.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *XForwarded) isTrustedIP(ip string) bool {
|
||||||
|
if x.ipChecker == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return x.ipChecker.IsAuthorized(ip) == nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *XForwarded) rewrite(outreq *http.Request) {
|
func (x *XForwarded) rewrite(outreq *http.Request) {
|
||||||
if clientIP, _, err := net.SplitHostPort(outreq.RemoteAddr); err == nil {
|
if clientIP, _, err := net.SplitHostPort(outreq.RemoteAddr); err == nil {
|
||||||
clientIP = removeIPv6Zone(clientIP)
|
clientIP = removeIPv6Zone(clientIP)
|
||||||
@@ -186,21 +201,6 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServeHTTP implements http.Handler.
|
|
||||||
func (x *XForwarded) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if !x.insecure && !x.isTrustedIP(r.RemoteAddr) {
|
|
||||||
for _, h := range xHeaders {
|
|
||||||
unsafeHeader(r.Header).Del(h)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x.rewrite(r)
|
|
||||||
|
|
||||||
x.removeConnectionHeaders(r)
|
|
||||||
|
|
||||||
x.next.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
|
func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
|
||||||
var reqUpType string
|
var reqUpType string
|
||||||
if httpguts.HeaderValuesContainsToken(req.Header[connection], upgrade) {
|
if httpguts.HeaderValuesContainsToken(req.Header[connection], upgrade) {
|
||||||
@@ -209,7 +209,7 @@ func (x *XForwarded) removeConnectionHeaders(req *http.Request) {
|
|||||||
|
|
||||||
var connectionHopByHopHeaders []string
|
var connectionHopByHopHeaders []string
|
||||||
for _, f := range req.Header[connection] {
|
for _, f := range req.Header[connection] {
|
||||||
for _, sf := range strings.Split(f, ",") {
|
for sf := range strings.SplitSeq(f, ",") {
|
||||||
if sf = textproto.TrimString(sf); sf != "" {
|
if sf = textproto.TrimString(sf); sf != "" {
|
||||||
// Connection header cannot dictate to remove X- headers managed by Traefik,
|
// Connection header cannot dictate to remove X- headers managed by Traefik,
|
||||||
// as per rfc7230 https://datatracker.ietf.org/doc/html/rfc7230#section-6.1,
|
// as per rfc7230 https://datatracker.ietf.org/doc/html/rfc7230#section-6.1,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package headermodifier
|
package headermodifier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -105,9 +106,7 @@ func TestRequestHeaderModifier(t *testing.T) {
|
|||||||
handler := NewRequestHeaderModifier(t.Context(), next, test.config, "foo-request-header-modifier")
|
handler := NewRequestHeaderModifier(t.Context(), next, test.config, "foo-request-header-modifier")
|
||||||
|
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
for h, v := range test.requestHeaders {
|
maps.Copy(req.Header, test.requestHeaders)
|
||||||
req.Header[h] = v
|
|
||||||
}
|
|
||||||
resp := httptest.NewRecorder()
|
resp := httptest.NewRecorder()
|
||||||
|
|
||||||
handler.ServeHTTP(resp, req)
|
handler.ServeHTTP(resp, req)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package headermodifier
|
package headermodifier
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -107,9 +108,7 @@ func TestResponseHeaderModifier(t *testing.T) {
|
|||||||
|
|
||||||
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
req := testhelpers.MustNewRequest(http.MethodGet, "http://localhost", nil)
|
||||||
resp := httptest.NewRecorder()
|
resp := httptest.NewRecorder()
|
||||||
for k, v := range test.responseHeaders {
|
maps.Copy(resp.Header(), test.responseHeaders)
|
||||||
resp.Header()[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
handler.ServeHTTP(resp, req)
|
handler.ServeHTTP(resp, req)
|
||||||
|
|
||||||
|
|||||||
@@ -64,27 +64,6 @@ func (s *Header) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// modifyCustomRequestHeaders sets or deletes custom request headers.
|
|
||||||
func (s *Header) modifyCustomRequestHeaders(req *http.Request) {
|
|
||||||
// Loop through Custom request headers
|
|
||||||
for header, value := range s.headers.CustomRequestHeaders {
|
|
||||||
switch {
|
|
||||||
// Handling https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b.
|
|
||||||
case value == "" && header == forward.XForwardedFor:
|
|
||||||
req.Header[header] = nil
|
|
||||||
|
|
||||||
case value == "":
|
|
||||||
req.Header.Del(header)
|
|
||||||
|
|
||||||
case strings.EqualFold(header, "Host"):
|
|
||||||
req.Host = value
|
|
||||||
|
|
||||||
default:
|
|
||||||
req.Header.Set(header, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostRequestModifyResponseHeaders set or delete response headers.
|
// PostRequestModifyResponseHeaders set or delete response headers.
|
||||||
// This method is called AFTER the response is generated from the backend
|
// This method is called AFTER the response is generated from the backend
|
||||||
// and can merge/override headers from the backend response.
|
// and can merge/override headers from the backend response.
|
||||||
@@ -134,6 +113,27 @@ func (s *Header) PostRequestModifyResponseHeaders(res *http.Response) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modifyCustomRequestHeaders sets or deletes custom request headers.
|
||||||
|
func (s *Header) modifyCustomRequestHeaders(req *http.Request) {
|
||||||
|
// Loop through Custom request headers
|
||||||
|
for header, value := range s.headers.CustomRequestHeaders {
|
||||||
|
switch {
|
||||||
|
// Handling https://github.com/golang/go/commit/ecdbffd4ec68b509998792f120868fec319de59b.
|
||||||
|
case value == "" && header == forward.XForwardedFor:
|
||||||
|
req.Header[header] = nil
|
||||||
|
|
||||||
|
case value == "":
|
||||||
|
req.Header.Del(header)
|
||||||
|
|
||||||
|
case strings.EqualFold(header, "Host"):
|
||||||
|
req.Host = value
|
||||||
|
|
||||||
|
default:
|
||||||
|
req.Header.Set(header, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// processCorsHeaders processes the incoming request,
|
// processCorsHeaders processes the incoming request,
|
||||||
// and returns if it is a preflight request.
|
// and returns if it is a preflight request.
|
||||||
// If not a preflight, it handles the preRequestModifyCorsResponseHeaders.
|
// If not a preflight, it handles the preRequestModifyCorsResponseHeaders.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ func DetailedTracingEnabled(ctx context.Context) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetStatusErrorf flags the span as in error and log an event.
|
// SetStatusErrorf flags the span as in error and log an event.
|
||||||
func SetStatusErrorf(ctx context.Context, format string, args ...interface{}) {
|
func SetStatusErrorf(ctx context.Context, format string, args ...any) {
|
||||||
if span := trace.SpanFromContext(ctx); span != nil {
|
if span := trace.SpanFromContext(ctx); span != nil {
|
||||||
span.SetStatus(codes.Error, fmt.Sprintf(format, args...))
|
span.SetStatus(codes.Error, fmt.Sprintf(format, args...))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ func newStatusCodeRecorder(rw http.ResponseWriter, status int) *statusCodeRecord
|
|||||||
|
|
||||||
type statusCodeRecorder struct {
|
type statusCodeRecorder struct {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
|
|
||||||
status int
|
status int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Rediser interface {
|
type Rediser interface {
|
||||||
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
|
Eval(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd
|
||||||
EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd
|
EvalSha(ctx context.Context, sha1 string, keys []string, args ...any) *redis.Cmd
|
||||||
ScriptExists(ctx context.Context, hashes ...string) *redis.BoolSliceCmd
|
ScriptExists(ctx context.Context, hashes ...string) *redis.BoolSliceCmd
|
||||||
ScriptLoad(ctx context.Context, script string) *redis.StringCmd
|
ScriptLoad(ctx context.Context, script string) *redis.StringCmd
|
||||||
Del(ctx context.Context, keys ...string) *redis.IntCmd
|
Del(ctx context.Context, keys ...string) *redis.IntCmd
|
||||||
|
|
||||||
EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd
|
EvalRO(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd
|
||||||
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd
|
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...any) *redis.Cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:dupword
|
//nolint:dupword
|
||||||
|
|||||||
@@ -61,10 +61,7 @@ func New(ctx context.Context, next http.Handler, config dynamic.RateLimit, name
|
|||||||
return nil, fmt.Errorf("getting source extractor: %w", err)
|
return nil, fmt.Errorf("getting source extractor: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
burst := config.Burst
|
burst := max(config.Burst, 1)
|
||||||
if burst < 1 {
|
|
||||||
burst = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
period := time.Duration(config.Period)
|
period := time.Duration(config.Period)
|
||||||
if period < 0 {
|
if period < 0 {
|
||||||
|
|||||||
@@ -300,11 +300,8 @@ func TestInMemoryRateLimit(t *testing.T) {
|
|||||||
stop := time.Now()
|
stop := time.Now()
|
||||||
elapsed := stop.Sub(start)
|
elapsed := stop.Sub(start)
|
||||||
|
|
||||||
burst := test.config.Burst
|
// actual default value if burst < 1
|
||||||
if burst < 1 {
|
burst := max(test.config.Burst, 1)
|
||||||
// actual default value
|
|
||||||
burst = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
period := time.Duration(test.config.Period)
|
period := time.Duration(test.config.Period)
|
||||||
if period == 0 {
|
if period == 0 {
|
||||||
@@ -510,11 +507,8 @@ func TestRedisRateLimit(t *testing.T) {
|
|||||||
stop := time.Now()
|
stop := time.Now()
|
||||||
elapsed := stop.Sub(start)
|
elapsed := stop.Sub(start)
|
||||||
|
|
||||||
burst := test.config.Burst
|
// actual default value
|
||||||
if burst < 1 {
|
burst := max(test.config.Burst, 1)
|
||||||
// actual default value
|
|
||||||
burst = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
period := time.Duration(test.config.Period)
|
period := time.Duration(test.config.Period)
|
||||||
if period == 0 {
|
if period == 0 {
|
||||||
@@ -570,7 +564,7 @@ func newMockRedisClient(ttl int) Rediser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRedisClient) EvalSha(ctx context.Context, _ string, keys []string, args ...interface{}) *redis.Cmd {
|
func (m *mockRedisClient) EvalSha(ctx context.Context, _ string, keys []string, args ...any) *redis.Cmd {
|
||||||
state := lua.NewState()
|
state := lua.NewState()
|
||||||
defer state.Close()
|
defer state.Close()
|
||||||
|
|
||||||
@@ -641,7 +635,7 @@ func (m *mockRedisClient) EvalSha(ctx context.Context, _ string, keys []string,
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
var resultSlice []interface{}
|
var resultSlice []any
|
||||||
resultTable.ForEach(func(_ lua.LValue, value lua.LValue) {
|
resultTable.ForEach(func(_ lua.LValue, value lua.LValue) {
|
||||||
valueNbr, ok := value.(lua.LNumber)
|
valueNbr, ok := value.(lua.LNumber)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -661,7 +655,7 @@ func (m *mockRedisClient) EvalSha(ctx context.Context, _ string, keys []string,
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRedisClient) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd {
|
func (m *mockRedisClient) Eval(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd {
|
||||||
return m.EvalSha(ctx, script, keys, args...)
|
return m.EvalSha(ctx, script, keys, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -677,11 +671,11 @@ func (m *mockRedisClient) Del(ctx context.Context, keys ...string) *redis.IntCmd
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRedisClient) EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *redis.Cmd {
|
func (m *mockRedisClient) EvalRO(ctx context.Context, script string, keys []string, args ...any) *redis.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockRedisClient) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *redis.Cmd {
|
func (m *mockRedisClient) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...any) *redis.Cmd {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (r *redisLimiter) evaluateScript(ctx context.Context, key string) (bool, *t
|
|||||||
return true, nil, nil
|
return true, nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
params := []interface{}{
|
params := []any{
|
||||||
float64(r.rate / 1000000),
|
float64(r.rate / 1000000),
|
||||||
r.burst,
|
r.burst,
|
||||||
r.ttl,
|
r.ttl,
|
||||||
@@ -103,7 +103,7 @@ func (r *redisLimiter) evaluateScript(ctx context.Context, key string) (bool, *t
|
|||||||
return false, nil, fmt.Errorf("running script: %w", err)
|
return false, nil, fmt.Errorf("running script: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
values := v.([]interface{})
|
values := v.([]any)
|
||||||
ok, err := strconv.ParseBool(values[0].(string))
|
ok, err := strconv.ParseBool(values[0].(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, nil, fmt.Errorf("parsing ok value from redis rate lua script: %w", err)
|
return false, nil, fmt.Errorf("parsing ok value from redis rate lua script: %w", err)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func recoverFunc(rw recoveryResponseWriter, req *http.Request) {
|
|||||||
|
|
||||||
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
|
// https://github.com/golang/go/blob/a0d6420d8be2ae7164797051ec74fa2a2df466a1/src/net/http/server.go#L1761-L1775
|
||||||
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
|
// https://github.com/golang/go/blob/c33153f7b416c03983324b3e8f869ce1116d84bc/src/net/http/httputil/reverseproxy.go#L284
|
||||||
func shouldLogPanic(panicValue interface{}) bool {
|
func shouldLogPanic(panicValue any) bool {
|
||||||
//nolint:errorlint // false-positive because panicValue is an interface.
|
//nolint:errorlint // false-positive because panicValue is an interface.
|
||||||
return panicValue != nil && panicValue != http.ErrAbortHandler
|
return panicValue != nil && panicValue != http.ErrAbortHandler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -249,10 +250,7 @@ func (r *responseWriter) WriteHeader(code int) {
|
|||||||
// to write headers to the backend : we are not going to perform any further retry.
|
// to write headers to the backend : we are not going to perform any further retry.
|
||||||
// So it is now safe to alter current response headers with headers collected during
|
// So it is now safe to alter current response headers with headers collected during
|
||||||
// the latest try before writing headers to client.
|
// the latest try before writing headers to client.
|
||||||
headers := r.responseWriter.Header()
|
maps.Copy(r.responseWriter.Header(), r.headers)
|
||||||
for header, value := range r.headers {
|
|
||||||
headers[header] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
r.responseWriter.WriteHeader(code)
|
r.responseWriter.WriteHeader(code)
|
||||||
|
|
||||||
|
|||||||
@@ -184,13 +184,7 @@ func header(tree *matchersTree, headers ...string) error {
|
|||||||
key, value := http.CanonicalHeaderKey(headers[0]), headers[1]
|
key, value := http.CanonicalHeaderKey(headers[0]), headers[1]
|
||||||
|
|
||||||
tree.matcher = func(req *http.Request) bool {
|
tree.matcher = func(req *http.Request) bool {
|
||||||
for _, headerValue := range req.Header[key] {
|
return slices.Contains(req.Header[key], value)
|
||||||
if headerValue == value {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -205,13 +199,7 @@ func headerRegexp(tree *matchersTree, headers ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree.matcher = func(req *http.Request) bool {
|
tree.matcher = func(req *http.Request) bool {
|
||||||
for _, headerValue := range req.Header[key] {
|
return slices.ContainsFunc(req.Header[key], re.MatchString)
|
||||||
if re.MatchString(headerValue) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ type MatcherFunc func(*http.Request) bool
|
|||||||
|
|
||||||
// Muxer handles routing with rules.
|
// Muxer handles routing with rules.
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
routes routes
|
routes routes
|
||||||
|
|
||||||
parser SyntaxParser
|
parser SyntaxParser
|
||||||
defaultHandler http.Handler
|
defaultHandler http.Handler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package tcp
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@@ -37,13 +38,7 @@ func alpn(tree *matchersTree, protos ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree.matcher = func(meta ConnData) bool {
|
tree.matcher = func(meta ConnData) bool {
|
||||||
for _, alpnProto := range meta.alpnProtos {
|
return slices.Contains(meta.alpnProtos, proto)
|
||||||
if alpnProto == proto {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -56,10 +57,8 @@ func alpnV2(tree *matchersTree, protos ...string) error {
|
|||||||
|
|
||||||
tree.matcher = func(meta ConnData) bool {
|
tree.matcher = func(meta ConnData) bool {
|
||||||
for _, proto := range meta.alpnProtos {
|
for _, proto := range meta.alpnProtos {
|
||||||
for _, filter := range protos {
|
if slices.Contains(protos, proto) {
|
||||||
if proto == filter {
|
return true
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func GetRulePriority(rule string) int {
|
|||||||
// AddRoute adds a new route, associated to the given handler, at the given
|
// AddRoute adds a new route, associated to the given handler, at the given
|
||||||
// priority, to the muxer.
|
// priority, to the muxer.
|
||||||
func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler tcp.Handler) error {
|
func (m *Muxer) AddRoute(rule string, syntax string, priority int, handler tcp.Handler) error {
|
||||||
var parse interface{}
|
var parse any
|
||||||
var err error
|
var err error
|
||||||
var matcherFuncs map[string]func(*matchersTree, ...string) error
|
var matcherFuncs map[string]func(*matchersTree, ...string) error
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
|
|
||||||
func NewAWSWrapper(logger zerolog.Logger) logging.LoggerFunc {
|
func NewAWSWrapper(logger zerolog.Logger) logging.LoggerFunc {
|
||||||
if logger.GetLevel() > zerolog.DebugLevel {
|
if logger.GetLevel() > zerolog.DebugLevel {
|
||||||
return func(classification logging.Classification, format string, args ...interface{}) {}
|
return func(classification logging.Classification, format string, args ...any) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return func(classification logging.Classification, format string, args ...interface{}) {
|
return func(classification logging.Classification, format string, args ...any) {
|
||||||
logger.Debug().CallerSkipFrame(2).MsgFunc(msgFunc(args...))
|
logger.Debug().CallerSkipFrame(2).MsgFunc(msgFunc(args...))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user