From 95c035060f66577f52158312c75ca379d7ddc21e Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Wed, 13 Oct 2021 17:58:20 -0600 Subject: [PATCH] map: Fix regex mappings It didn't really make sense how we were doing them before. See https://caddy.community/t/map-directive-and-regular-expressions/13866/6?u=matt --- modules/caddyhttp/map/map.go | 6 +- modules/caddyhttp/map/map_test.go | 96 +++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 modules/caddyhttp/map/map_test.go diff --git a/modules/caddyhttp/map/map.go b/modules/caddyhttp/map/map.go index a0e07687..670a55bd 100644 --- a/modules/caddyhttp/map/map.go +++ b/modules/caddyhttp/map/map.go @@ -136,7 +136,11 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt if output := m.Outputs[destIdx]; output == nil { continue } else { - output = m.re.ReplaceAllString(input, m.Outputs[destIdx].(string)) + var result []byte + for _, submatches := range m.re.FindAllStringSubmatchIndex(input, -1) { + result = m.re.ExpandString(result, m.Outputs[destIdx].(string), input, submatches) + } + output = string(result) return output, true } } diff --git a/modules/caddyhttp/map/map_test.go b/modules/caddyhttp/map/map_test.go new file mode 100644 index 00000000..59e5c5ef --- /dev/null +++ b/modules/caddyhttp/map/map_test.go @@ -0,0 +1,96 @@ +package maphandler + +import ( + "context" + "net/http" + "net/http/httptest" + "reflect" + "testing" + + "github.com/caddyserver/caddy/v2" + "github.com/caddyserver/caddy/v2/modules/caddyhttp" +) + +func TestHandler(t *testing.T) { + for i, tc := range []struct { + handler Handler + reqPath string + expect map[string]interface{} + }{ + { + reqPath: "/foo", + handler: Handler{ + Source: "{http.request.uri.path}", + Destinations: []string{"{output}"}, + Mappings: []Mapping{ + { + Input: "/foo", + Outputs: []interface{}{"FOO"}, + }, + }, + }, + expect: map[string]interface{}{ + "output": "FOO", + }, + }, + { + reqPath: "/abcdef", + handler: Handler{ + Source: "{http.request.uri.path}", + Destinations: []string{"{output}"}, + Mappings: []Mapping{ + { + InputRegexp: "(/abc)", + Outputs: []interface{}{"ABC"}, + }, + }, + }, + expect: map[string]interface{}{ + "output": "ABC", + }, + }, + { + reqPath: "/ABCxyzDEF", + handler: Handler{ + Source: "{http.request.uri.path}", + Destinations: []string{"{output}"}, + Mappings: []Mapping{ + { + InputRegexp: "(xyz)", + Outputs: []interface{}{"...${1}..."}, + }, + }, + }, + expect: map[string]interface{}{ + "output": "...xyz...", + }, + }, + } { + if err := tc.handler.Provision(caddy.Context{}); err != nil { + t.Fatalf("Test %d: Provisioning handler: %v", i, err) + } + + req, err := http.NewRequest(http.MethodGet, tc.reqPath, nil) + if err != nil { + t.Fatalf("Test %d: Creating request: %v", i, err) + } + repl := caddyhttp.NewTestReplacer(req) + ctx := context.WithValue(req.Context(), caddy.ReplacerCtxKey, repl) + req = req.WithContext(ctx) + + rr := httptest.NewRecorder() + noop := caddyhttp.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) error { return nil }) + + if err := tc.handler.ServeHTTP(rr, req, noop); err != nil { + t.Errorf("Test %d: Handler returned error: %v", i, err) + continue + } + + for key, expected := range tc.expect { + actual, _ := repl.Get(key) + if !reflect.DeepEqual(actual, expected) { + t.Errorf("Test %d: Expected %#v but got %#v for {%s}", i, expected, actual, key) + } + } + } +}