diff --git a/request.go b/request.go index 73fe121..bcc075b 100644 --- a/request.go +++ b/request.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" "strconv" + "strings" "github.com/dunglas/httpsfv" "github.com/yosida95/uritemplate/v3" @@ -89,3 +90,17 @@ func ParseRequest(r *http.Request, template *uritemplate.Template) (*Request, er } return &Request{Target: fmt.Sprintf("%s:%d", targetHost, targetPort)}, nil } + +// PathFromTemplate extracts the HTTP path from a URI template, +// such that it can be used in a http.ServeMux. +func PathFromTemplate(t *uritemplate.Template) (string, error) { + u, err := url.Parse(t.Raw()) + if err != nil { + return "", err + } + path := strings.ReplaceAll(strings.ReplaceAll(u.Path, "/{target_host}", ""), "/{target_port}", "") + if path != u.Path && len(path) > 0 && path[len(path)-1] != '/' { + path = path + "/" + } + return path, nil +} diff --git a/request_test.go b/request_test.go index 12202af..62c5d2c 100644 --- a/request_test.go +++ b/request_test.go @@ -65,3 +65,32 @@ func TestRequestParsing(t *testing.T) { require.Equal(t, http.StatusBadRequest, err.(*RequestParseError).HTTPStatus) }) } + +func TestPathFromTemplate(t *testing.T) { + for _, tc := range []struct { + name, template, expected string + }{ + { + "variables as URL parameters", + "https://localhost:1234/masque?h={target_host}&p={target_port}", + "/masque", + }, + { + "variables in URL paths", + "https://localhost:1234/masque/{target_host}/{target_port}", + "/masque/", // needs to have a trailing / + }, + { + "variables in URL paths, no trailing /", + "https://localhost:1234/masque/{target_host}/{target_port}/", + "/masque/", + }, + } { + t.Run(tc.name, func(t *testing.T) { + temp := uritemplate.MustNew(tc.template) + path, err := PathFromTemplate(temp) + require.NoError(t, err) + require.Equal(t, tc.expected, path) + }) + } +}