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"
2022-09-02 09:44:08 +00:00
"reflect"
2019-01-15 13:28:04 +00:00
"strings"
2018-11-14 09:18:03 +00:00
"github.com/containous/alice"
2024-01-11 09:40:06 +00:00
"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"
2024-01-11 09:40:06 +00:00
"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
)
2019-01-15 13:28:04 +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 {
2019-07-15 15:04:04 +00:00
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 {
2020-09-01 16:16:04 +00:00
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.
2019-01-15 13:28:04 +00:00
func ( b * Builder ) BuildChain ( ctx context . Context , middlewares [ ] string ) * alice . Chain {
2018-11-14 09:18:03 +00:00
chain := alice . New ( )
2019-01-30 15:24:07 +00:00
for _ , name := range middlewares {
2020-01-27 09:40:05 +00:00
middlewareName := provider . GetQualifiedName ( ctx , name )
2019-01-18 14:18:04 +00:00
2019-01-15 13:28:04 +00:00
chain = chain . Append ( func ( next http . Handler ) ( http . Handler , error ) {
2020-01-27 09:40:05 +00:00
constructorContext := provider . AddInContext ( ctx , middlewareName )
2019-05-16 08:58:06 +00:00
if midInf , ok := b . configs [ middlewareName ] ; ! ok || midInf . Middleware == nil {
2019-01-18 14:18:04 +00:00
return nil , fmt . Errorf ( "middleware %q does not exist" , middlewareName )
}
2019-01-15 13:28:04 +00:00
var err error
2019-04-01 13:30:07 +00:00
if constructorContext , err = checkRecursion ( constructorContext , middlewareName ) ; err != nil {
2019-07-19 14:42:04 +00:00
b . configs [ middlewareName ] . AddError ( err , true )
2019-01-15 13:28:04 +00:00
return nil , err
}
2018-11-14 09:18:03 +00:00
2019-05-16 08:58:06 +00:00
constructor , err := b . buildConstructor ( constructorContext , middlewareName )
2019-01-15 13:28:04 +00:00
if err != nil {
2019-07-19 14:42:04 +00:00
b . configs [ middlewareName ] . AddError ( err , true )
2019-05-16 08:58:06 +00:00
return nil , err
}
handler , err := constructor ( next )
if err != nil {
2019-07-19 14:42:04 +00:00
b . configs [ middlewareName ] . AddError ( err , true )
2019-05-16 08:58:06 +00:00
return nil , err
2019-01-15 13:28:04 +00:00
}
2019-05-16 08:58:06 +00:00
return handler , nil
2019-01-15 13:28:04 +00:00
} )
}
return & chain
}
2019-04-01 13:30:07 +00:00
func checkRecursion ( ctx context . Context , middlewareName string ) ( context . Context , error ) {
2019-01-15 13:28:04 +00:00
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
}
2019-01-15 13:28:04 +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.
2019-05-16 08:58:06 +00:00
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
2019-09-25 16:20:04 +00:00
var qualifiedNames [ ] string
for _ , name := range config . Chain . Middlewares {
2020-01-27 09:40:05 +00:00
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 ) {
2019-10-31 10:36:05 +00:00
return compress . New ( ctx , next , * config . Compress , middlewareName )
2019-04-01 13:30:07 +00:00
}
2018-11-14 09:18:03 +00:00
}
2020-01-21 17:06:03 +00:00
// ContentType
if config . ContentType != nil {
if middleware != nil {
return nil , badConf
}
middleware = func ( next http . Handler ) ( http . Handler , error ) {
2024-01-29 16:32:05 +00:00
return contenttype . New ( ctx , next , * config . ContentType , middlewareName )
2020-01-21 17:06:03 +00:00
}
}
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
}
2022-10-27 15:34:06 +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
}
2024-01-11 09:40:06 +00:00
// IPWhiteList
if config . IPWhiteList != nil {
2024-01-29 16:32:05 +00:00
qualifiedName := provider . GetQualifiedName ( ctx , middlewareName )
log . Warn ( ) . Msgf ( "Middleware %q of type IPWhiteList is deprecated, please use IPAllowList instead." , qualifiedName )
2024-01-11 09:40:06 +00:00
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
}
2019-08-26 10:20:06 +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 ) {
2019-08-26 10:20:06 +00:00
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
2019-08-26 10:20:06 +00:00
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
2019-01-22 07:30:04 +00:00
// RedirectRegex
if config . RedirectRegex != nil {
2019-04-01 13:30:07 +00:00
if middleware != nil {
2019-01-22 07:30:04 +00:00
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 )
}
2019-01-22 07:30:04 +00:00
}
// 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
2022-09-02 09:44:08 +00:00
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 {
2021-05-11 14:14:10 +00:00
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 {
2021-05-11 14:14:10 +00:00
return nil , fmt . Errorf ( "plugin: %w" , err )
2020-04-20 16:36:34 +00:00
}
middleware = func ( next http . Handler ) ( http . Handler , error ) {
2023-07-20 13:02:07 +00:00
return newTraceablePlugin ( ctx , middlewareName , plug , next )
2020-04-20 16:36:34 +00:00
}
}
2019-01-18 14:18:04 +00:00
if middleware == nil {
2019-09-26 08:04:04 +00:00
return nil , fmt . Errorf ( "invalid middleware %q configuration: invalid middleware type or middleware does not exist" , middlewareName )
2019-01-18 14:18:04 +00:00
}
2024-01-30 15:28:05 +00:00
// 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
}
2019-01-15 13:28:04 +00:00
func inSlice ( element string , stack [ ] string ) bool {
for _ , value := range stack {
if value == element {
return true
}
}
return false
}