Merge branch v3.1 into v3.2

This commit is contained in:
kevinpollet 2024-10-24 11:26:40 +02:00
commit b22e081c7c
No known key found for this signature in database
GPG key ID: 0C9A5DDD1B292453
27 changed files with 528 additions and 331 deletions

View file

@ -8,7 +8,9 @@ import (
"net/http"
"slices"
"github.com/andybalholm/brotli"
"github.com/klauspost/compress/gzhttp"
"github.com/klauspost/compress/zstd"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"github.com/traefik/traefik/v3/pkg/middlewares"
"go.opentelemetry.io/otel/trace"
@ -94,12 +96,12 @@ func New(ctx context.Context, next http.Handler, conf dynamic.Compress, name str
var err error
c.zstdHandler, err = c.newCompressionHandler(zstdName, name)
c.zstdHandler, err = c.newZstdHandler(name)
if err != nil {
return nil, err
}
c.brotliHandler, err = c.newCompressionHandler(brotliName, name)
c.brotliHandler, err = c.newBrotliHandler(name)
if err != nil {
return nil, err
}
@ -190,13 +192,34 @@ func (c *compress) newGzipHandler() (http.Handler, error) {
return wrapper(c.next), nil
}
func (c *compress) newCompressionHandler(algo string, middlewareName string) (http.Handler, error) {
cfg := Config{MinSize: c.minSize, Algorithm: algo, MiddlewareName: middlewareName}
func (c *compress) newBrotliHandler(middlewareName string) (http.Handler, error) {
cfg := Config{MinSize: c.minSize, MiddlewareName: middlewareName}
if len(c.includes) > 0 {
cfg.IncludedContentTypes = c.includes
} else {
cfg.ExcludedContentTypes = c.excludes
}
return NewCompressionHandler(cfg, c.next)
newBrotliWriter := func(rw http.ResponseWriter) (CompressionWriter, string, error) {
return brotli.NewWriter(rw), brotliName, nil
}
return NewCompressionHandler(cfg, newBrotliWriter, c.next)
}
func (c *compress) newZstdHandler(middlewareName string) (http.Handler, error) {
cfg := Config{MinSize: c.minSize, MiddlewareName: middlewareName}
if len(c.includes) > 0 {
cfg.IncludedContentTypes = c.includes
} else {
cfg.ExcludedContentTypes = c.excludes
}
newZstdWriter := func(rw http.ResponseWriter) (CompressionWriter, string, error) {
writer, err := zstd.NewWriter(rw)
if err != nil {
return nil, "", fmt.Errorf("creating zstd writer: %w", err)
}
return writer, zstdName, nil
}
return NewCompressionHandler(cfg, newZstdWriter, c.next)
}

View file

@ -10,8 +10,6 @@ import (
"net/http"
"sync"
"github.com/andybalholm/brotli"
"github.com/klauspost/compress/zstd"
"github.com/traefik/traefik/v3/pkg/middlewares"
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
)
@ -24,6 +22,30 @@ const (
contentType = "Content-Type"
)
// CompressionWriter compresses the written bytes.
type CompressionWriter interface {
// Write data to the encoder.
// Input data will be buffered and as the buffer fills up
// content will be compressed and written to the output.
// When done writing, use Close to flush the remaining output
// and write CRC if requested.
Write(p []byte) (n int, err error)
// Flush will send the currently written data to output
// and block until everything has been written.
// This should only be used on rare occasions where pushing the currently queued data is critical.
Flush() error
// Close closes the underlying writers if/when appropriate.
// Note that the compressed writer should not be closed if we never used it,
// as it would otherwise send some extra "end of compression" bytes.
// Close also makes sure to flush whatever was left to write from the buffer.
Close() error
// Reset reinitializes the state of the encoder, allowing it to be reused.
Reset(w io.Writer)
}
// NewCompressionWriter returns a new CompressionWriter with its corresponding algorithm.
type NewCompressionWriter func(rw http.ResponseWriter) (CompressionWriter, string, error)
// Config is the Brotli handler configuration.
type Config struct {
// ExcludedContentTypes is the list of content types for which we should not compress.
@ -34,8 +56,6 @@ type Config struct {
IncludedContentTypes []string
// MinSize is the minimum size (in bytes) required to enable compression.
MinSize int
// Algorithm used for the compression (currently Brotli and Zstandard)
Algorithm string
// MiddlewareName use for logging purposes
MiddlewareName string
}
@ -46,15 +66,13 @@ type CompressionHandler struct {
excludedContentTypes []parsedContentType
includedContentTypes []parsedContentType
next http.Handler
writerPool sync.Pool
writerPool sync.Pool
newWriter NewCompressionWriter
}
// NewCompressionHandler returns a new compressing handler.
func NewCompressionHandler(cfg Config, next http.Handler) (http.Handler, error) {
if cfg.Algorithm == "" {
return nil, errors.New("compression algorithm undefined")
}
func NewCompressionHandler(cfg Config, newWriter NewCompressionWriter, next http.Handler) (http.Handler, error) {
if cfg.MinSize < 0 {
return nil, errors.New("minimum size must be greater than or equal to zero")
}
@ -88,6 +106,7 @@ func NewCompressionHandler(cfg Config, next http.Handler) (http.Handler, error)
excludedContentTypes: excludedContentTypes,
includedContentTypes: includedContentTypes,
next: next,
newWriter: newWriter,
}, nil
}
@ -117,70 +136,38 @@ func (c *CompressionHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request)
c.next.ServeHTTP(responseWriter, r)
}
type compression interface {
// Write data to the encoder.
// Input data will be buffered and as the buffer fills up
// content will be compressed and written to the output.
// When done writing, use Close to flush the remaining output
// and write CRC if requested.
Write(p []byte) (n int, err error)
// Flush will send the currently written data to output
// and block until everything has been written.
// This should only be used on rare occasions where pushing the currently queued data is critical.
Flush() error
// Close closes the underlying writers if/when appropriate.
// Note that the compressed writer should not be closed if we never used it,
// as it would otherwise send some extra "end of compression" bytes.
// Close also makes sure to flush whatever was left to write from the buffer.
Close() error
// Reset reinitializes the state of the encoder, allowing it to be reused.
Reset(w io.Writer)
}
type compressionWriter struct {
compression
alg string
}
func (c *CompressionHandler) getCompressionWriter(rw io.Writer) (*compressionWriter, error) {
if writer, ok := c.writerPool.Get().(*compressionWriter); ok {
writer.compression.Reset(rw)
func (c *CompressionHandler) getCompressionWriter(rw http.ResponseWriter) (*compressionWriterWrapper, error) {
if writer, ok := c.writerPool.Get().(*compressionWriterWrapper); ok {
writer.Reset(rw)
return writer, nil
}
return newCompressionWriter(c.cfg.Algorithm, rw)
writer, algo, err := c.newWriter(rw)
if err != nil {
return nil, fmt.Errorf("creating compression writer: %w", err)
}
return &compressionWriterWrapper{CompressionWriter: writer, algo: algo}, nil
}
func (c *CompressionHandler) putCompressionWriter(writer *compressionWriter) {
func (c *CompressionHandler) putCompressionWriter(writer *compressionWriterWrapper) {
writer.Reset(nil)
c.writerPool.Put(writer)
}
func newCompressionWriter(algo string, in io.Writer) (*compressionWriter, error) {
switch algo {
case brotliName:
return &compressionWriter{compression: brotli.NewWriter(in), alg: algo}, nil
case zstdName:
writer, err := zstd.NewWriter(in)
if err != nil {
return nil, fmt.Errorf("creating zstd writer: %w", err)
}
return &compressionWriter{compression: writer, alg: algo}, nil
default:
return nil, fmt.Errorf("unknown compression algo: %s", algo)
}
type compressionWriterWrapper struct {
CompressionWriter
algo string
}
func (c *compressionWriter) ContentEncoding() string {
return c.alg
func (c *compressionWriterWrapper) ContentEncoding() string {
return c.algo
}
// TODO: check whether we want to implement content-type sniffing (as gzip does)
// TODO: check whether we should support Accept-Ranges (as gzip does, see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Ranges)
type responseWriter struct {
rw http.ResponseWriter
compressionWriter *compressionWriter
compressionWriter *compressionWriterWrapper
minSize int
excludedContentTypes []parsedContentType

View file

@ -162,7 +162,7 @@ func Test_NoBody(t *testing.T) {
require.NoError(t, err)
})
h := mustNewCompressionHandler(t, Config{MinSize: 1024, Algorithm: zstdName}, next)
h := mustNewCompressionHandler(t, Config{MinSize: 1024}, zstdName, next)
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set(acceptEncoding, "zstd")
@ -181,8 +181,7 @@ func Test_NoBody(t *testing.T) {
func Test_MinSize(t *testing.T) {
cfg := Config{
MinSize: 128,
Algorithm: zstdName,
MinSize: 128,
}
var bodySize int
@ -197,7 +196,7 @@ func Test_MinSize(t *testing.T) {
}
})
h := mustNewCompressionHandler(t, cfg, next)
h := mustNewCompressionHandler(t, cfg, zstdName, next)
req, _ := http.NewRequest(http.MethodGet, "/whatever", &bytes.Buffer{})
req.Header.Add(acceptEncoding, "zstd")
@ -224,7 +223,7 @@ func Test_MultipleWriteHeader(t *testing.T) {
rw.WriteHeader(http.StatusNotFound)
})
h := mustNewCompressionHandler(t, Config{MinSize: 1024, Algorithm: zstdName}, next)
h := mustNewCompressionHandler(t, Config{MinSize: 1024}, zstdName, next)
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set(acceptEncoding, "zstd")
@ -239,12 +238,14 @@ func Test_FlushBeforeWrite(t *testing.T) {
testCases := []struct {
desc string
cfg Config
algo string
readerBuilder func(io.Reader) (io.Reader, error)
acceptEncoding string
}{
{
desc: "brotli",
cfg: Config{MinSize: 1024, Algorithm: brotliName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: brotliName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return brotli.NewReader(reader), nil
},
@ -252,7 +253,8 @@ func Test_FlushBeforeWrite(t *testing.T) {
},
{
desc: "zstd",
cfg: Config{MinSize: 1024, Algorithm: zstdName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: zstdName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return zstd.NewReader(reader)
},
@ -272,7 +274,7 @@ func Test_FlushBeforeWrite(t *testing.T) {
require.NoError(t, err)
})
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, next))
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, test.algo, next))
defer srv.Close()
req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody)
@ -302,12 +304,14 @@ func Test_FlushAfterWrite(t *testing.T) {
testCases := []struct {
desc string
cfg Config
algo string
readerBuilder func(io.Reader) (io.Reader, error)
acceptEncoding string
}{
{
desc: "brotli",
cfg: Config{MinSize: 1024, Algorithm: brotliName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: brotliName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return brotli.NewReader(reader), nil
},
@ -315,7 +319,8 @@ func Test_FlushAfterWrite(t *testing.T) {
},
{
desc: "zstd",
cfg: Config{MinSize: 1024, Algorithm: zstdName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: zstdName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return zstd.NewReader(reader)
},
@ -338,7 +343,7 @@ func Test_FlushAfterWrite(t *testing.T) {
}
})
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, next))
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, test.algo, next))
defer srv.Close()
req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody)
@ -368,12 +373,14 @@ func Test_FlushAfterWriteNil(t *testing.T) {
testCases := []struct {
desc string
cfg Config
algo string
readerBuilder func(io.Reader) (io.Reader, error)
acceptEncoding string
}{
{
desc: "brotli",
cfg: Config{MinSize: 1024, Algorithm: brotliName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: brotliName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return brotli.NewReader(reader), nil
},
@ -381,7 +388,8 @@ func Test_FlushAfterWriteNil(t *testing.T) {
},
{
desc: "zstd",
cfg: Config{MinSize: 1024, Algorithm: zstdName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: zstdName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return zstd.NewReader(reader)
},
@ -400,7 +408,7 @@ func Test_FlushAfterWriteNil(t *testing.T) {
rw.(http.Flusher).Flush()
})
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, next))
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, test.algo, next))
defer srv.Close()
req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody)
@ -430,12 +438,14 @@ func Test_FlushAfterAllWrites(t *testing.T) {
testCases := []struct {
desc string
cfg Config
algo string
readerBuilder func(io.Reader) (io.Reader, error)
acceptEncoding string
}{
{
desc: "brotli",
cfg: Config{MinSize: 1024, Algorithm: brotliName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: brotliName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return brotli.NewReader(reader), nil
},
@ -443,7 +453,8 @@ func Test_FlushAfterAllWrites(t *testing.T) {
},
{
desc: "zstd",
cfg: Config{MinSize: 1024, Algorithm: zstdName, MiddlewareName: "Test"},
cfg: Config{MinSize: 1024, MiddlewareName: "Test"},
algo: zstdName,
readerBuilder: func(reader io.Reader) (io.Reader, error) {
return zstd.NewReader(reader)
},
@ -461,7 +472,7 @@ func Test_FlushAfterAllWrites(t *testing.T) {
rw.(http.Flusher).Flush()
})
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, next))
srv := httptest.NewServer(mustNewCompressionHandler(t, test.cfg, test.algo, next))
defer srv.Close()
req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody)
@ -556,7 +567,6 @@ func Test_ExcludedContentTypes(t *testing.T) {
cfg := Config{
MinSize: 1024,
ExcludedContentTypes: test.excludedContentTypes,
Algorithm: zstdName,
}
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -568,7 +578,7 @@ func Test_ExcludedContentTypes(t *testing.T) {
require.NoError(t, err)
})
h := mustNewCompressionHandler(t, cfg, next)
h := mustNewCompressionHandler(t, cfg, zstdName, next)
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
req.Header.Set(acceptEncoding, zstdName)
@ -667,7 +677,6 @@ func Test_IncludedContentTypes(t *testing.T) {
cfg := Config{
MinSize: 1024,
IncludedContentTypes: test.includedContentTypes,
Algorithm: zstdName,
}
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -679,7 +688,7 @@ func Test_IncludedContentTypes(t *testing.T) {
require.NoError(t, err)
})
h := mustNewCompressionHandler(t, cfg, next)
h := mustNewCompressionHandler(t, cfg, zstdName, next)
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
req.Header.Set(acceptEncoding, zstdName)
@ -778,7 +787,6 @@ func Test_FlushExcludedContentTypes(t *testing.T) {
cfg := Config{
MinSize: 1024,
ExcludedContentTypes: test.excludedContentTypes,
Algorithm: zstdName,
}
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -803,7 +811,7 @@ func Test_FlushExcludedContentTypes(t *testing.T) {
}
})
h := mustNewCompressionHandler(t, cfg, next)
h := mustNewCompressionHandler(t, cfg, zstdName, next)
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
req.Header.Set(acceptEncoding, zstdName)
@ -903,7 +911,6 @@ func Test_FlushIncludedContentTypes(t *testing.T) {
cfg := Config{
MinSize: 1024,
IncludedContentTypes: test.includedContentTypes,
Algorithm: zstdName,
}
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -928,7 +935,7 @@ func Test_FlushIncludedContentTypes(t *testing.T) {
}
})
h := mustNewCompressionHandler(t, cfg, next)
h := mustNewCompressionHandler(t, cfg, zstdName, next)
req, _ := http.NewRequest(http.MethodGet, "/whatever", nil)
req.Header.Set(acceptEncoding, zstdName)
@ -959,10 +966,26 @@ func Test_FlushIncludedContentTypes(t *testing.T) {
}
}
func mustNewCompressionHandler(t *testing.T, cfg Config, next http.Handler) http.Handler {
func mustNewCompressionHandler(t *testing.T, cfg Config, algo string, next http.Handler) http.Handler {
t.Helper()
w, err := NewCompressionHandler(cfg, next)
var writer NewCompressionWriter
switch algo {
case zstdName:
writer = func(rw http.ResponseWriter) (CompressionWriter, string, error) {
writer, err := zstd.NewWriter(rw)
require.NoError(t, err)
return writer, zstdName, nil
}
case brotliName:
writer = func(rw http.ResponseWriter) (CompressionWriter, string, error) {
return brotli.NewWriter(rw), brotliName, nil
}
default:
assert.Failf(t, "unknown compression algorithm: %s", algo)
}
w, err := NewCompressionHandler(cfg, writer, next)
require.NoError(t, err)
return w
@ -981,7 +1004,7 @@ func newTestBrotliHandler(t *testing.T, body []byte) http.Handler {
require.NoError(t, err)
})
return mustNewCompressionHandler(t, Config{MinSize: 1024, Algorithm: brotliName, MiddlewareName: "Compress"}, next)
return mustNewCompressionHandler(t, Config{MinSize: 1024, MiddlewareName: "Compress"}, brotliName, next)
}
func newTestZstandardHandler(t *testing.T, body []byte) http.Handler {
@ -997,7 +1020,7 @@ func newTestZstandardHandler(t *testing.T, body []byte) http.Handler {
require.NoError(t, err)
})
return mustNewCompressionHandler(t, Config{MinSize: 1024, Algorithm: zstdName, MiddlewareName: "Compress"}, next)
return mustNewCompressionHandler(t, Config{MinSize: 1024, MiddlewareName: "Compress"}, zstdName, next)
}
func Test_ParseContentType_equals(t *testing.T) {

View file

@ -312,19 +312,9 @@ func (p *Provider) getClient() (*lego.Client, error) {
}
err = client.Challenge.SetDNS01Provider(provider,
dns01.CondOption(len(p.DNSChallenge.Resolvers) > 0, dns01.AddRecursiveNameservers(p.DNSChallenge.Resolvers)),
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
if p.DNSChallenge.DelayBeforeCheck > 0 {
logger.Debug().Msgf("Delaying %d rather than validating DNS propagation now.", p.DNSChallenge.DelayBeforeCheck)
time.Sleep(time.Duration(p.DNSChallenge.DelayBeforeCheck))
}
if p.DNSChallenge.DisablePropagationCheck {
return true, nil
}
return check(fqdn, value)
}),
dns01.CondOption(len(p.DNSChallenge.Resolvers) > 0,
dns01.AddRecursiveNameservers(p.DNSChallenge.Resolvers)),
dns01.PropagationWait(time.Duration(p.DNSChallenge.DelayBeforeCheck), p.DNSChallenge.DisablePropagationCheck),
)
if err != nil {
return nil, err

View file

@ -54,4 +54,9 @@ spec:
extensionRef:
group: traefik.io
kind: Middleware
name: my-middleware
name: my-first-middleware
- type: ExtensionRef
extensionRef:
group: traefik.io
kind: Middleware
name: my-second-middleware

View file

@ -384,39 +384,58 @@ func (p *Provider) loadHTTPBackendRef(namespace string, backendRef gatev1.HTTPBa
}
func (p *Provider) loadMiddlewares(conf *dynamic.Configuration, namespace, routerName string, filters []gatev1.HTTPRouteFilter, pathMatch *gatev1.HTTPPathMatch) ([]string, error) {
type namedMiddleware struct {
Name string
Config *dynamic.Middleware
}
pm := ptr.Deref(pathMatch, gatev1.HTTPPathMatch{
Type: ptr.To(gatev1.PathMatchPathPrefix),
Value: ptr.To("/"),
})
middlewares := make(map[string]*dynamic.Middleware)
var middlewares []namedMiddleware
for i, filter := range filters {
name := fmt.Sprintf("%s-%s-%d", routerName, strings.ToLower(string(filter.Type)), i)
switch filter.Type {
case gatev1.HTTPRouteFilterRequestRedirect:
middlewares[name] = createRequestRedirect(filter.RequestRedirect, pm)
middlewares = append(middlewares, namedMiddleware{
name,
createRequestRedirect(filter.RequestRedirect, pm),
})
case gatev1.HTTPRouteFilterRequestHeaderModifier:
middlewares[name] = createRequestHeaderModifier(filter.RequestHeaderModifier)
middlewares = append(middlewares, namedMiddleware{
name,
createRequestHeaderModifier(filter.RequestHeaderModifier),
})
case gatev1.HTTPRouteFilterResponseHeaderModifier:
middlewares[name] = createResponseHeaderModifier(filter.ResponseHeaderModifier)
middlewares = append(middlewares, namedMiddleware{
name,
createResponseHeaderModifier(filter.ResponseHeaderModifier),
})
case gatev1.HTTPRouteFilterExtensionRef:
name, middleware, err := p.loadHTTPRouteFilterExtensionRef(namespace, filter.ExtensionRef)
if err != nil {
return nil, fmt.Errorf("loading ExtensionRef filter %s: %w", filter.Type, err)
}
middlewares[name] = middleware
middlewares = append(middlewares, namedMiddleware{
name,
middleware,
})
case gatev1.HTTPRouteFilterURLRewrite:
var err error
middleware, err := createURLRewrite(filter.URLRewrite, pm)
if err != nil {
return nil, fmt.Errorf("invalid filter %s: %w", filter.Type, err)
}
middlewares[name] = middleware
middlewares = append(middlewares, namedMiddleware{
name,
middleware,
})
default:
// As per the spec: https://gateway-api.sigs.k8s.io/api-types/httproute/#filters-optional
@ -428,12 +447,11 @@ func (p *Provider) loadMiddlewares(conf *dynamic.Configuration, namespace, route
}
var middlewareNames []string
for name, middleware := range middlewares {
if middleware != nil {
conf.HTTP.Middlewares[name] = middleware
for _, m := range middlewares {
if m.Config != nil {
conf.HTTP.Middlewares[m.Name] = m.Config
}
middlewareNames = append(middlewareNames, name)
middlewareNames = append(middlewareNames, m.Name)
}
return middlewareNames, nil

View file

@ -2963,7 +2963,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
entryPoints map[string]Entrypoint
}{
{
desc: "HTTPRoute with ExtensionRef filter",
desc: "ExtensionRef filter",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, nil, nil
@ -2991,7 +2991,10 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"},
Middlewares: []string{
"default-my-first-middleware",
"default-my-second-middleware",
},
},
},
Middlewares: map[string]*dynamic.Middleware{},
@ -3029,7 +3032,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
},
},
{
desc: "HTTPRoute with ExtensionRef filter and create middleware",
desc: "ExtensionRef filter with middleware creation",
groupKindFilterFuncs: map[string]map[string]BuildFilterFunc{
traefikv1alpha1.GroupName: {"Middleware": func(name, namespace string) (string, *dynamic.Middleware, error) {
return namespace + "-" + name, &dynamic.Middleware{Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}}, nil
@ -3057,11 +3060,15 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
Rule: "Host(`foo.com`) && Path(`/bar`)",
Priority: 100008,
RuleSyntax: "v3",
Middlewares: []string{"default-my-middleware"},
Middlewares: []string{
"default-my-first-middleware",
"default-my-second-middleware",
},
},
},
Middlewares: map[string]*dynamic.Middleware{
"default-my-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
"default-my-first-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
"default-my-second-middleware": {Headers: &dynamic.Headers{CustomRequestHeaders: map[string]string{"Test-Header": "Test"}}},
},
Services: map[string]*dynamic.Service{
"default-http-app-1-my-gateway-web-0-1c0cf64bde37d9d0df06-wrr": {
@ -3097,7 +3104,7 @@ func TestLoadHTTPRoutes_filterExtensionRef(t *testing.T) {
},
},
{
desc: "ExtensionRef filter: Unknown",
desc: "Unknown ExtensionRef filter",
entryPoints: map[string]Entrypoint{"web": {
Address: ":80",
}},