Move code to pkg
This commit is contained in:
parent
bd4c822670
commit
f1b085fa36
465 changed files with 656 additions and 680 deletions
343
pkg/server/middleware/middlewares.go
Normal file
343
pkg/server/middleware/middlewares.go
Normal file
|
@ -0,0 +1,343 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/containous/alice"
|
||||
"github.com/containous/traefik/pkg/config"
|
||||
"github.com/containous/traefik/pkg/middlewares/addprefix"
|
||||
"github.com/containous/traefik/pkg/middlewares/auth"
|
||||
"github.com/containous/traefik/pkg/middlewares/buffering"
|
||||
"github.com/containous/traefik/pkg/middlewares/chain"
|
||||
"github.com/containous/traefik/pkg/middlewares/circuitbreaker"
|
||||
"github.com/containous/traefik/pkg/middlewares/compress"
|
||||
"github.com/containous/traefik/pkg/middlewares/customerrors"
|
||||
"github.com/containous/traefik/pkg/middlewares/headers"
|
||||
"github.com/containous/traefik/pkg/middlewares/ipwhitelist"
|
||||
"github.com/containous/traefik/pkg/middlewares/maxconnection"
|
||||
"github.com/containous/traefik/pkg/middlewares/passtlsclientcert"
|
||||
"github.com/containous/traefik/pkg/middlewares/ratelimiter"
|
||||
"github.com/containous/traefik/pkg/middlewares/redirect"
|
||||
"github.com/containous/traefik/pkg/middlewares/replacepath"
|
||||
"github.com/containous/traefik/pkg/middlewares/replacepathregex"
|
||||
"github.com/containous/traefik/pkg/middlewares/retry"
|
||||
"github.com/containous/traefik/pkg/middlewares/stripprefix"
|
||||
"github.com/containous/traefik/pkg/middlewares/stripprefixregex"
|
||||
"github.com/containous/traefik/pkg/middlewares/tracing"
|
||||
"github.com/containous/traefik/pkg/server/internal"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type middlewareStackType int
|
||||
|
||||
const (
|
||||
middlewareStackKey middlewareStackType = iota
|
||||
)
|
||||
|
||||
// Builder the middleware builder
|
||||
type Builder struct {
|
||||
configs map[string]*config.Middleware
|
||||
serviceBuilder serviceBuilder
|
||||
}
|
||||
|
||||
type serviceBuilder interface {
|
||||
BuildHTTP(ctx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error)
|
||||
}
|
||||
|
||||
// NewBuilder creates a new Builder
|
||||
func NewBuilder(configs map[string]*config.Middleware, serviceBuilder serviceBuilder) *Builder {
|
||||
return &Builder{configs: configs, serviceBuilder: serviceBuilder}
|
||||
}
|
||||
|
||||
// BuildChain creates a middleware chain
|
||||
func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *alice.Chain {
|
||||
chain := alice.New()
|
||||
for _, name := range middlewares {
|
||||
middlewareName := internal.GetQualifiedName(ctx, name)
|
||||
|
||||
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
|
||||
constructorContext := internal.AddProviderInContext(ctx, middlewareName)
|
||||
if _, ok := b.configs[middlewareName]; !ok {
|
||||
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
|
||||
}
|
||||
|
||||
var err error
|
||||
if constructorContext, err = checkRecursivity(constructorContext, middlewareName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
constructor, err := b.buildConstructor(constructorContext, middlewareName, *b.configs[middlewareName])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error during instanciation of %s: %v", middlewareName, err)
|
||||
}
|
||||
return constructor(next)
|
||||
})
|
||||
}
|
||||
return &chain
|
||||
}
|
||||
|
||||
func checkRecursivity(ctx context.Context, middlewareName string) (context.Context, error) {
|
||||
currentStack, ok := ctx.Value(middlewareStackKey).([]string)
|
||||
if !ok {
|
||||
currentStack = []string{}
|
||||
}
|
||||
if inSlice(middlewareName, currentStack) {
|
||||
return ctx, fmt.Errorf("could not instantiate middleware %s: recursion detected in %s", middlewareName, strings.Join(append(currentStack, middlewareName), "->"))
|
||||
}
|
||||
return context.WithValue(ctx, middlewareStackKey, append(currentStack, middlewareName)), nil
|
||||
}
|
||||
|
||||
func (b *Builder) buildConstructor(ctx context.Context, middlewareName string, config config.Middleware) (alice.Constructor, error) {
|
||||
var middleware alice.Constructor
|
||||
badConf := errors.New("cannot create middleware %q: multi-types middleware not supported, consider declaring two different pieces of middleware instead")
|
||||
|
||||
// AddPrefix
|
||||
if config.AddPrefix != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return addprefix.New(ctx, next, *config.AddPrefix, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// BasicAuth
|
||||
if config.BasicAuth != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return auth.NewBasic(ctx, next, *config.BasicAuth, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// Buffering
|
||||
if config.Buffering != nil && config.MaxConn.Amount != 0 {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return buffering.New(ctx, next, *config.Buffering, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// Chain
|
||||
if config.Chain != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return chain.New(ctx, next, *config.Chain, b, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// CircuitBreaker
|
||||
if config.CircuitBreaker != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return circuitbreaker.New(ctx, next, *config.CircuitBreaker, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// Compress
|
||||
if config.Compress != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return compress.New(ctx, next, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// CustomErrors
|
||||
if config.Errors != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return customerrors.New(ctx, next, *config.Errors, b.serviceBuilder, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// DigestAuth
|
||||
if config.DigestAuth != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return auth.NewDigest(ctx, next, *config.DigestAuth, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// ForwardAuth
|
||||
if config.ForwardAuth != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return auth.NewForward(ctx, next, *config.ForwardAuth, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// Headers
|
||||
if config.Headers != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return headers.New(ctx, next, *config.Headers, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// IPWhiteList
|
||||
if config.IPWhiteList != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return ipwhitelist.New(ctx, next, *config.IPWhiteList, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// MaxConn
|
||||
if config.MaxConn != nil && config.MaxConn.Amount != 0 {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return maxconnection.New(ctx, next, *config.MaxConn, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// PassTLSClientCert
|
||||
if config.PassTLSClientCert != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return passtlsclientcert.New(ctx, next, *config.PassTLSClientCert, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// RateLimit
|
||||
if config.RateLimit != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return ratelimiter.New(ctx, next, *config.RateLimit, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// RedirectRegex
|
||||
if config.RedirectRegex != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return redirect.NewRedirectRegex(ctx, next, *config.RedirectRegex, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// RedirectScheme
|
||||
if config.RedirectScheme != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return redirect.NewRedirectScheme(ctx, next, *config.RedirectScheme, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// ReplacePath
|
||||
if config.ReplacePath != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return replacepath.New(ctx, next, *config.ReplacePath, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// ReplacePathRegex
|
||||
if config.ReplacePathRegex != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return replacepathregex.New(ctx, next, *config.ReplacePathRegex, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// Retry
|
||||
if config.Retry != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
// FIXME missing metrics / accessLog
|
||||
return retry.New(ctx, next, *config.Retry, retry.Listeners{}, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// StripPrefix
|
||||
if config.StripPrefix != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return stripprefix.New(ctx, next, *config.StripPrefix, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
// StripPrefixRegex
|
||||
if config.StripPrefixRegex != nil {
|
||||
if middleware == nil {
|
||||
middleware = func(next http.Handler) (http.Handler, error) {
|
||||
return stripprefixregex.New(ctx, next, *config.StripPrefixRegex, middlewareName)
|
||||
}
|
||||
} else {
|
||||
return nil, badConf
|
||||
}
|
||||
}
|
||||
|
||||
if middleware == nil {
|
||||
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
|
||||
}
|
||||
|
||||
return tracing.Wrap(ctx, middleware), nil
|
||||
}
|
||||
|
||||
func inSlice(element string, stack []string) bool {
|
||||
for _, value := range stack {
|
||||
if value == element {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
391
pkg/server/middleware/middlewares_test.go
Normal file
391
pkg/server/middleware/middlewares_test.go
Normal file
|
@ -0,0 +1,391 @@
|
|||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/containous/traefik/pkg/config"
|
||||
"github.com/containous/traefik/pkg/server/internal"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBuilder_buildConstructorCircuitBreaker(t *testing.T) {
|
||||
testConfig := map[string]*config.Middleware{
|
||||
"empty": {
|
||||
CircuitBreaker: &config.CircuitBreaker{
|
||||
Expression: "",
|
||||
},
|
||||
},
|
||||
"foo": {
|
||||
CircuitBreaker: &config.CircuitBreaker{
|
||||
Expression: "NetworkErrorRatio() > 0.5",
|
||||
},
|
||||
},
|
||||
}
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil)
|
||||
|
||||
emptyHandler := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
middlewareID string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "Should fail at creating a circuit breaker with an empty expression",
|
||||
expectedError: true,
|
||||
middlewareID: "empty",
|
||||
}, {
|
||||
desc: "Should create a circuit breaker with a valid expression",
|
||||
expectedError: false,
|
||||
middlewareID: "foo",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
constructor, err := middlewaresBuilder.buildConstructor(context.Background(), test.middlewareID, *testConfig[test.middlewareID])
|
||||
require.NoError(t, err)
|
||||
|
||||
middleware, err2 := constructor(emptyHandler)
|
||||
|
||||
if test.expectedError {
|
||||
require.Error(t, err2)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, middleware)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilder_BuildChainNilConfig(t *testing.T) {
|
||||
testConfig := map[string]*config.Middleware{
|
||||
"empty": {},
|
||||
}
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil)
|
||||
|
||||
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
|
||||
_, err := chain.Then(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestBuilder_BuildChainNonExistentChain(t *testing.T) {
|
||||
testConfig := map[string]*config.Middleware{
|
||||
"foobar": {},
|
||||
}
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil)
|
||||
|
||||
chain := middlewaresBuilder.BuildChain(context.Background(), []string{"empty"})
|
||||
_, err := chain.Then(nil)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestBuilder_buildConstructorAddPrefix(t *testing.T) {
|
||||
testConfig := map[string]*config.Middleware{
|
||||
"empty": {
|
||||
AddPrefix: &config.AddPrefix{
|
||||
Prefix: "",
|
||||
},
|
||||
},
|
||||
"foo": {
|
||||
AddPrefix: &config.AddPrefix{
|
||||
Prefix: "foo/",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
middlewaresBuilder := NewBuilder(testConfig, nil)
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
middlewareID string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
desc: "Should not create an empty AddPrefix middleware when given an empty prefix",
|
||||
middlewareID: "empty",
|
||||
expectedError: true,
|
||||
}, {
|
||||
desc: "Should create an AddPrefix middleware when given a valid configuration",
|
||||
middlewareID: "foo",
|
||||
expectedError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
constructor, err := middlewaresBuilder.buildConstructor(context.Background(), test.middlewareID, *testConfig[test.middlewareID])
|
||||
require.NoError(t, err)
|
||||
|
||||
middleware, err2 := constructor(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}))
|
||||
|
||||
if test.expectedError {
|
||||
require.Error(t, err2)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, middleware)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild_BuildChainWithContext(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
buildChain []string
|
||||
configuration map[string]*config.Middleware
|
||||
expected map[string]string
|
||||
contextProvider string
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
desc: "Simple middleware",
|
||||
buildChain: []string{"middleware-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
{
|
||||
desc: "Middleware that references a chain",
|
||||
buildChain: []string{"middleware-chain-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
"middleware-chain-1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"middleware-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
{
|
||||
desc: "Should prefix the middlewareName with the provider in the context",
|
||||
buildChain: []string{"middleware-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"provider-1.middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"provider-1.middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"provider-1.middleware-1": "value-middleware-1"},
|
||||
contextProvider: "provider-1",
|
||||
},
|
||||
{
|
||||
desc: "Should not prefix a qualified middlewareName with the provider in the context",
|
||||
buildChain: []string{"provider-1.middleware-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"provider-1.middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"provider-1.middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"provider-1.middleware-1": "value-middleware-1"},
|
||||
contextProvider: "provider-1",
|
||||
},
|
||||
{
|
||||
desc: "Should be context aware if a chain references another middleware",
|
||||
buildChain: []string{"provider-1.middleware-chain-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"provider-1.middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
"provider-1.middleware-chain-1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"middleware-1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
{
|
||||
desc: "Should handle nested chains with different context",
|
||||
buildChain: []string{"provider-1.middleware-chain-1", "middleware-chain-1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"provider-1.middleware-1": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"middleware-1": "value-middleware-1"},
|
||||
},
|
||||
},
|
||||
"provider-1.middleware-2": {
|
||||
Headers: &config.Headers{
|
||||
CustomRequestHeaders: map[string]string{"middleware-2": "value-middleware-2"},
|
||||
},
|
||||
},
|
||||
"provider-1.middleware-chain-1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"middleware-1"},
|
||||
},
|
||||
},
|
||||
"provider-1.middleware-chain-2": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"middleware-2"},
|
||||
},
|
||||
},
|
||||
"provider-2.middleware-chain-1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"provider-1.middleware-2", "provider-1.middleware-chain-2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: map[string]string{"middleware-1": "value-middleware-1", "middleware-2": "value-middleware-2"},
|
||||
contextProvider: "provider-2",
|
||||
},
|
||||
{
|
||||
desc: "Detects recursion in Middleware chain",
|
||||
buildChain: []string{"m1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"ok": {
|
||||
Retry: &config.Retry{},
|
||||
},
|
||||
"m1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m2"},
|
||||
},
|
||||
},
|
||||
"m2": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"ok", "m3"},
|
||||
},
|
||||
},
|
||||
"m3": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("could not instantiate middleware m1: recursion detected in m1->m2->m3->m1"),
|
||||
},
|
||||
{
|
||||
desc: "Detects recursion in Middleware chain",
|
||||
buildChain: []string{"provider.m1"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"provider2.ok": {
|
||||
Retry: &config.Retry{},
|
||||
},
|
||||
"provider.m1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"provider2.m2"},
|
||||
},
|
||||
},
|
||||
"provider2.m2": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"ok", "provider.m3"},
|
||||
},
|
||||
},
|
||||
"provider.m3": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("could not instantiate middleware provider.m1: recursion detected in provider.m1->provider2.m2->provider.m3->provider.m1"),
|
||||
},
|
||||
{
|
||||
buildChain: []string{"ok", "m0"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"ok": {
|
||||
Retry: &config.Retry{},
|
||||
},
|
||||
"m0": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("could not instantiate middleware m0: recursion detected in m0->m0"),
|
||||
},
|
||||
{
|
||||
desc: "Detects MiddlewareChain that references a Chain that references a Chain with a missing middleware",
|
||||
buildChain: []string{"m0"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"m0": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m1"},
|
||||
},
|
||||
},
|
||||
"m1": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m2"},
|
||||
},
|
||||
},
|
||||
"m2": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m3"},
|
||||
},
|
||||
},
|
||||
"m3": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("could not instantiate middleware m2: recursion detected in m0->m1->m2->m3->m2"),
|
||||
},
|
||||
{
|
||||
desc: "--",
|
||||
buildChain: []string{"m0"},
|
||||
configuration: map[string]*config.Middleware{
|
||||
"m0": {
|
||||
Chain: &config.Chain{
|
||||
Middlewares: []string{"m0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedError: errors.New("could not instantiate middleware m0: recursion detected in m0->m0"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
if len(test.contextProvider) > 0 {
|
||||
ctx = internal.AddProviderInContext(ctx, test.contextProvider+".foobar")
|
||||
}
|
||||
|
||||
builder := NewBuilder(test.configuration, nil)
|
||||
|
||||
result := builder.BuildChain(ctx, test.buildChain)
|
||||
|
||||
handlers, err := result.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }))
|
||||
if test.expectedError != nil {
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, test.expectedError.Error(), err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
recorder := httptest.NewRecorder()
|
||||
request, _ := http.NewRequest(http.MethodGet, "http://foo/", nil)
|
||||
handlers.ServeHTTP(recorder, request)
|
||||
|
||||
for key, value := range test.expected {
|
||||
assert.Equal(t, value, request.Header.Get(key))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue