package middlewares import ( "context" "errors" "fmt" "net/http" "github.com/rs/zerolog/log" "github.com/traefik/traefik/v3/pkg/config/dynamic" "github.com/vulcand/oxy/v2/utils" ) // GetSourceExtractor returns the SourceExtractor function corresponding to the given sourceMatcher. // It defaults to a RemoteAddrStrategy IPStrategy if need be. // It returns an error if more than one source criterion is provided. func GetSourceExtractor(ctx context.Context, sourceMatcher *dynamic.SourceCriterion) (utils.SourceExtractor, error) { if sourceMatcher != nil { if sourceMatcher.IPStrategy != nil && sourceMatcher.RequestHeaderName != "" { return nil, errors.New("iPStrategy and RequestHeaderName are mutually exclusive") } if sourceMatcher.IPStrategy != nil && sourceMatcher.RequestHost { return nil, errors.New("iPStrategy and RequestHost are mutually exclusive") } if sourceMatcher.RequestHeaderName != "" && sourceMatcher.RequestHost { return nil, errors.New("requestHost and RequestHeaderName are mutually exclusive") } } if sourceMatcher == nil || sourceMatcher.IPStrategy == nil && sourceMatcher.RequestHeaderName == "" && !sourceMatcher.RequestHost { sourceMatcher = &dynamic.SourceCriterion{ IPStrategy: &dynamic.IPStrategy{}, } } logger := log.Ctx(ctx) if sourceMatcher.IPStrategy != nil { strategy, err := sourceMatcher.IPStrategy.Get() if err != nil { return nil, err } logger.Debug().Msg("Using IPStrategy") return utils.ExtractorFunc(func(req *http.Request) (string, int64, error) { return strategy.GetIP(req), 1, nil }), nil } if sourceMatcher.RequestHeaderName != "" { logger.Debug().Msg("Using RequestHeaderName") return utils.NewExtractor(fmt.Sprintf("request.header.%s", sourceMatcher.RequestHeaderName)) } if sourceMatcher.RequestHost { logger.Debug().Msg("Using RequestHost") return utils.NewExtractor("request.host") } return nil, errors.New("no SourceCriterion criterion defined") }