diff --git a/pkg/filter/headerlookup/headerlookup.go b/pkg/filter/headerlookup/headerlookup.go index 51ce5c0bc8..52b8da2aa7 100644 --- a/pkg/filter/headerlookup/headerlookup.go +++ b/pkg/filter/headerlookup/headerlookup.go @@ -21,6 +21,7 @@ import ( "context" "fmt" "net/http" + "regexp" "strings" "time" @@ -55,6 +56,7 @@ type ( spec *Spec etcdPrefix string headerKey string + pathRegExp *regexp.Regexp cache *lru.Cache cluster cluster.Cluster @@ -71,13 +73,15 @@ type ( // Spec defines header key and etcd prefix that form etcd key like /custom-data/{etcdPrefix}/{headerKey's value}. // This /custom-data/{etcdPrefix}/{headerKey's value} is retrieved from etcd and HeaderSetters extract keys from the // from the retrieved etcd item. - // When AppendPath is true, the path (without leading slash) is appended to the etcd key in following format: - // /custom-data/{etcdPrefix}/{headerKey's value}-{path} . For example, for path "/bananas", the etcd key is + // When PathRegExp is defined, PathRegExp is used with `regexp.FindStringSubmatch` to identify a group from path. + // The first captured group is appended to the etcd key in following format: + // /custom-data/{etcdPrefix}/{headerKey's value}-{regex group} . For example, for path + // "/api/bananas/33" and pathRegExp: "^/api/([a-z]+)/[0-9]*", the group "bananas" is extracted and etcd key is // /custom-data/{etcdPrefix}/{headerKey's value}-bananas. Spec struct { HeaderKey string `yaml:"headerKey" jsonschema:"required"` EtcdPrefix string `yaml:"etcdPrefix" jsonschema:"required"` - AppendPath bool `yaml:"appendPath" jsonschema:"omitempty"` + PathRegExp string `yaml:"pathRegExp" jsonschema:"omitempty"` HeaderSetters []*HeaderSetterSpec `yaml:"headerSetters" jsonschema:"required"` } ) @@ -101,6 +105,10 @@ func (spec Spec) Validate() error { return fmt.Errorf("headerSetters[i].headerKey is required") } } + + if _, err := regexp.Compile(spec.PathRegExp); err != nil { + return err + } return nil } @@ -134,6 +142,7 @@ func (hl *HeaderLookup) Init(filterSpec *httppipeline.FilterSpec) { hl.headerKey = http.CanonicalHeaderKey(hl.spec.HeaderKey) hl.cache, _ = lru.New(cacheSize) hl.stopCtx, hl.cancel = context.WithCancel(context.Background()) + hl.pathRegExp = regexp.MustCompile(hl.spec.PathRegExp) hl.watchChanges() } @@ -253,8 +262,11 @@ func (hl *HeaderLookup) handle(ctx httpcontext.HTTPContext) string { logger.Warnf("request does not have header '%s'", hl.spec.HeaderKey) return "" } - if hl.spec.AppendPath { - headerVal = headerVal + "-" + strings.TrimPrefix(ctx.Request().Path(), "/") + if hl.spec.PathRegExp != "" { + path := ctx.Request().Path() + if match := hl.pathRegExp.FindStringSubmatch(path); match != nil && len(match) > 1 { + headerVal = headerVal + "-" + match[1] + } } headersToAdd, err := hl.lookup(headerVal) if err != nil { diff --git a/pkg/filter/headerlookup/headerlookup_test.go b/pkg/filter/headerlookup/headerlookup_test.go index 4248f1eb19..0859d79abf 100644 --- a/pkg/filter/headerlookup/headerlookup_test.go +++ b/pkg/filter/headerlookup/headerlookup_test.go @@ -114,6 +114,16 @@ headerKey: "X-AUTH-USER" etcdPrefix: "/credentials/" headerSetters: - headerKey: "X-ext-id" +`, + ` +name: headerLookup +kind: HeaderLookup +headerKey: "X-AUTH-USER" +pathRegExp: "**" +etcdPrefix: "/credentials/" +headerSetters: + - headerKey: "X-ext-id" + etcdKey: "ext-id" `, } @@ -266,7 +276,7 @@ name: headerLookup kind: HeaderLookup headerKey: "X-AUTH-USER" etcdPrefix: "credentials/" -appendPath: true +pathRegExp: "^/api/([a-z]+)/[0-9]*" headerSetters: - etcdKey: "ext-id" headerKey: "user-ext-id" @@ -291,17 +301,20 @@ extra-entry: "extra" check(err) ctx, header := prepareCtxAndHeader() - header.Set("X-AUTH-USER", "bob") + hl.Handle(ctx) // path does not match + if header.Get("user-ext-id") != "" { + t.Errorf("failed") + } ctx.MockedRequest.MockedPath = func() string { - return "/bananas" + return "/api/bananas/9281" } hl.Handle(ctx) if header.Get("user-ext-id") != "333" { t.Errorf("failed") } ctx.MockedRequest.MockedPath = func() string { - return "/pearls" + return "/api/pearls/" } hl.Handle(ctx) if header.Get("user-ext-id") != "4444" {