traefik/pkg/server/middleware/middlewares.go

404 lines
12 KiB
Go
Raw Normal View History

2018-11-14 09:18:03 +00:00
package middleware
import (
"context"
2019-04-01 13:30:07 +00:00
"errors"
2018-11-14 09:18:03 +00:00
"fmt"
"net/http"
"reflect"
"strings"
2018-11-14 09:18:03 +00:00
"github.com/containous/alice"
"github.com/rs/zerolog/log"
2023-02-03 14:24:05 +00:00
"github.com/traefik/traefik/v3/pkg/config/runtime"
"github.com/traefik/traefik/v3/pkg/middlewares/addprefix"
"github.com/traefik/traefik/v3/pkg/middlewares/auth"
"github.com/traefik/traefik/v3/pkg/middlewares/buffering"
"github.com/traefik/traefik/v3/pkg/middlewares/chain"
"github.com/traefik/traefik/v3/pkg/middlewares/circuitbreaker"
"github.com/traefik/traefik/v3/pkg/middlewares/compress"
"github.com/traefik/traefik/v3/pkg/middlewares/contenttype"
"github.com/traefik/traefik/v3/pkg/middlewares/customerrors"
"github.com/traefik/traefik/v3/pkg/middlewares/grpcweb"
"github.com/traefik/traefik/v3/pkg/middlewares/headers"
"github.com/traefik/traefik/v3/pkg/middlewares/inflightreq"
"github.com/traefik/traefik/v3/pkg/middlewares/ipallowlist"
"github.com/traefik/traefik/v3/pkg/middlewares/ipwhitelist"
2024-03-12 08:48:04 +00:00
"github.com/traefik/traefik/v3/pkg/middlewares/observability"
2023-02-03 14:24:05 +00:00
"github.com/traefik/traefik/v3/pkg/middlewares/passtlsclientcert"
"github.com/traefik/traefik/v3/pkg/middlewares/ratelimiter"
"github.com/traefik/traefik/v3/pkg/middlewares/redirect"
"github.com/traefik/traefik/v3/pkg/middlewares/replacepath"
"github.com/traefik/traefik/v3/pkg/middlewares/replacepathregex"
"github.com/traefik/traefik/v3/pkg/middlewares/retry"
"github.com/traefik/traefik/v3/pkg/middlewares/stripprefix"
"github.com/traefik/traefik/v3/pkg/middlewares/stripprefixregex"
"github.com/traefik/traefik/v3/pkg/server/provider"
2018-11-14 09:18:03 +00:00
)
type middlewareStackType int
const (
middlewareStackKey middlewareStackType = iota
)
2020-05-11 10:06:07 +00:00
// Builder the middleware builder.
2018-11-14 09:18:03 +00:00
type Builder struct {
configs map[string]*runtime.MiddlewareInfo
2020-09-07 11:58:03 +00:00
pluginBuilder PluginsBuilder
2018-11-14 09:18:03 +00:00
serviceBuilder serviceBuilder
}
type serviceBuilder interface {
BuildHTTP(ctx context.Context, serviceName string) (http.Handler, error)
2018-11-14 09:18:03 +00:00
}
2020-05-11 10:06:07 +00:00
// NewBuilder creates a new Builder.
2020-09-07 11:58:03 +00:00
func NewBuilder(configs map[string]*runtime.MiddlewareInfo, serviceBuilder serviceBuilder, pluginBuilder PluginsBuilder) *Builder {
2020-04-20 16:36:34 +00:00
return &Builder{configs: configs, serviceBuilder: serviceBuilder, pluginBuilder: pluginBuilder}
2018-11-14 09:18:03 +00:00
}
2020-05-11 10:06:07 +00:00
// BuildChain creates a middleware chain.
func (b *Builder) BuildChain(ctx context.Context, middlewares []string) *alice.Chain {
2018-11-14 09:18:03 +00:00
chain := alice.New()
for _, name := range middlewares {
middlewareName := provider.GetQualifiedName(ctx, name)
chain = chain.Append(func(next http.Handler) (http.Handler, error) {
constructorContext := provider.AddInContext(ctx, middlewareName)
if midInf, ok := b.configs[middlewareName]; !ok || midInf.Middleware == nil {
return nil, fmt.Errorf("middleware %q does not exist", middlewareName)
}
var err error
2019-04-01 13:30:07 +00:00
if constructorContext, err = checkRecursion(constructorContext, middlewareName); err != nil {
b.configs[middlewareName].AddError(err, true)
return nil, err
}
2018-11-14 09:18:03 +00:00
constructor, err := b.buildConstructor(constructorContext, middlewareName)
if err != nil {
b.configs[middlewareName].AddError(err, true)
return nil, err
}
handler, err := constructor(next)
if err != nil {
b.configs[middlewareName].AddError(err, true)
return nil, err
}
return handler, nil
})
}
return &chain
}
2019-04-01 13:30:07 +00:00
func checkRecursion(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), "->"))
2018-11-14 09:18:03 +00:00
}
return context.WithValue(ctx, middlewareStackKey, append(currentStack, middlewareName)), nil
2018-11-14 09:18:03 +00:00
}
2020-05-11 10:06:07 +00:00
// it is the responsibility of the caller to make sure that b.configs[middlewareName].Middleware exists.
func (b *Builder) buildConstructor(ctx context.Context, middlewareName string) (alice.Constructor, error) {
config := b.configs[middlewareName]
2019-09-03 13:22:05 +00:00
if config == nil || config.Middleware == nil {
return nil, fmt.Errorf("invalid middleware %q configuration", middlewareName)
}
2018-11-14 09:18:03 +00:00
var middleware alice.Constructor
2019-04-01 13:30:07 +00:00
badConf := errors.New("cannot create middleware: multi-types middleware not supported, consider declaring two different pieces of middleware instead")
2018-11-14 09:18:03 +00:00
// AddPrefix
if config.AddPrefix != nil {
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return addprefix.New(ctx, next, *config.AddPrefix, middlewareName)
2018-11-14 09:18:03 +00:00
}
}
// BasicAuth
if config.BasicAuth != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return auth.NewBasic(ctx, next, *config.BasicAuth, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// Buffering
2019-09-03 13:02:05 +00:00
if config.Buffering != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return buffering.New(ctx, next, *config.Buffering, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// Chain
if config.Chain != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-09-10 14:12:05 +00:00
var qualifiedNames []string
for _, name := range config.Chain.Middlewares {
qualifiedNames = append(qualifiedNames, provider.GetQualifiedName(ctx, name))
2019-09-10 14:12:05 +00:00
}
config.Chain.Middlewares = qualifiedNames
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return chain.New(ctx, next, *config.Chain, b, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// CircuitBreaker
if config.CircuitBreaker != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return circuitbreaker.New(ctx, next, *config.CircuitBreaker, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// Compress
if config.Compress != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return compress.New(ctx, next, *config.Compress, middlewareName)
2019-04-01 13:30:07 +00:00
}
2018-11-14 09:18:03 +00:00
}
// ContentType
if config.ContentType != nil {
if middleware != nil {
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
return contenttype.New(ctx, next, *config.ContentType, middlewareName)
}
}
2018-11-14 09:18:03 +00:00
// CustomErrors
if config.Errors != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return customerrors.New(ctx, next, *config.Errors, b.serviceBuilder, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// DigestAuth
if config.DigestAuth != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return auth.NewDigest(ctx, next, *config.DigestAuth, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// ForwardAuth
if config.ForwardAuth != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return auth.NewForward(ctx, next, *config.ForwardAuth, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// GrpcWeb
if config.GrpcWeb != nil {
if middleware != nil {
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
return grpcweb.New(ctx, next, *config.GrpcWeb, middlewareName), nil
}
}
2018-11-14 09:18:03 +00:00
// Headers
if config.Headers != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return headers.New(ctx, next, *config.Headers, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// IPWhiteList
if config.IPWhiteList != nil {
qualifiedName := provider.GetQualifiedName(ctx, middlewareName)
log.Warn().Msgf("Middleware %q of type IPWhiteList is deprecated, please use IPAllowList instead.", qualifiedName)
if middleware != nil {
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
return ipwhitelist.New(ctx, next, *config.IPWhiteList, middlewareName)
}
}
2022-10-26 15:16:05 +00:00
// IPAllowList
if config.IPAllowList != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
2022-10-26 15:16:05 +00:00
return ipallowlist.New(ctx, next, *config.IPAllowList, middlewareName)
2019-04-01 13:30:07 +00:00
}
2018-11-14 09:18:03 +00:00
}
// InFlightReq
2019-09-03 13:02:05 +00:00
if config.InFlightReq != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return inflightreq.New(ctx, next, *config.InFlightReq, middlewareName)
2019-04-01 13:30:07 +00:00
}
2018-11-14 09:18:03 +00:00
}
// PassTLSClientCert
if config.PassTLSClientCert != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return passtlsclientcert.New(ctx, next, *config.PassTLSClientCert, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// RateLimit
if config.RateLimit != nil {
if middleware != nil {
return nil, badConf
}
middleware = func(next http.Handler) (http.Handler, error) {
return ratelimiter.New(ctx, next, *config.RateLimit, middlewareName)
}
}
2018-11-14 09:18:03 +00:00
// RedirectRegex
if config.RedirectRegex != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return redirect.NewRedirectRegex(ctx, next, *config.RedirectRegex, middlewareName)
}
}
// RedirectScheme
if config.RedirectScheme != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return redirect.NewRedirectScheme(ctx, next, *config.RedirectScheme, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// ReplacePath
if config.ReplacePath != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return replacepath.New(ctx, next, *config.ReplacePath, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// ReplacePathRegex
if config.ReplacePathRegex != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return replacepathregex.New(ctx, next, *config.ReplacePathRegex, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// Retry
if config.Retry != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
2022-08-31 06:24:08 +00:00
// TODO missing metrics / accessLog
2019-04-01 13:30:07 +00:00
return retry.New(ctx, next, *config.Retry, retry.Listeners{}, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// StripPrefix
if config.StripPrefix != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return stripprefix.New(ctx, next, *config.StripPrefix, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
// StripPrefixRegex
if config.StripPrefixRegex != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2018-11-14 09:18:03 +00:00
return nil, badConf
}
2019-04-01 13:30:07 +00:00
middleware = func(next http.Handler) (http.Handler, error) {
return stripprefixregex.New(ctx, next, *config.StripPrefixRegex, middlewareName)
}
2018-11-14 09:18:03 +00:00
}
2020-04-20 16:36:34 +00:00
// Plugin
if config.Plugin != nil && !reflect.ValueOf(b.pluginBuilder).IsNil() { // Using "reflect" because "b.pluginBuilder" is an interface.
2020-04-20 16:36:34 +00:00
if middleware != nil {
return nil, badConf
}
pluginType, rawPluginConfig, err := findPluginConfig(config.Plugin)
if err != nil {
return nil, fmt.Errorf("plugin: %w", err)
2020-04-20 16:36:34 +00:00
}
2020-09-07 11:58:03 +00:00
plug, err := b.pluginBuilder.Build(pluginType, rawPluginConfig, middlewareName)
2020-04-20 16:36:34 +00:00
if err != nil {
return nil, fmt.Errorf("plugin: %w", err)
2020-04-20 16:36:34 +00:00
}
middleware = func(next http.Handler) (http.Handler, error) {
return newTraceablePlugin(ctx, middlewareName, plug, next)
2020-04-20 16:36:34 +00:00
}
}
if middleware == nil {
return nil, fmt.Errorf("invalid middleware %q configuration: invalid middleware type or middleware does not exist", middlewareName)
}
// The tracing middleware is a NOOP if tracing is not setup on the middleware chain.
// Hence, regarding internal resources' observability deactivation,
// this would not enable tracing.
2024-03-12 08:48:04 +00:00
return observability.WrapMiddleware(ctx, middleware), nil
2018-11-14 09:18:03 +00:00
}
func inSlice(element string, stack []string) bool {
for _, value := range stack {
if value == element {
return true
}
}
return false
}