From 208f2ff93c1bd2c009e4b96f664c1808ede79f3a Mon Sep 17 00:00:00 2001 From: Matthew Holt Date: Sat, 19 Oct 2019 19:22:29 -0600 Subject: [PATCH] rewrite: Options to strip prefix/suffix and issue redirects Fixes #2011 --- modules/caddyhttp/rewrite/rewrite.go | 61 ++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/modules/caddyhttp/rewrite/rewrite.go b/modules/caddyhttp/rewrite/rewrite.go index f434a38a..7d4c6f70 100644 --- a/modules/caddyhttp/rewrite/rewrite.go +++ b/modules/caddyhttp/rewrite/rewrite.go @@ -15,8 +15,10 @@ package rewrite import ( + "fmt" "net/http" "net/url" + "strconv" "strings" "github.com/caddyserver/caddy/v2" @@ -29,9 +31,14 @@ func init() { // Rewrite is a middleware which can rewrite HTTP requests. type Rewrite struct { - Method string `json:"method,omitempty"` - URI string `json:"uri,omitempty"` - Rehandle bool `json:"rehandle,omitempty"` + Method string `json:"method,omitempty"` + URI string `json:"uri,omitempty"` + + StripPathPrefix string `json:"strip_path_prefix,omitempty"` + StripPathSuffix string `json:"strip_path_suffix,omitempty"` + + HTTPRedirect caddyhttp.WeakString `json:"http_redirect,omitempty"` + Rehandle bool `json:"rehandle,omitempty"` } // CaddyModule returns the Caddy module information. @@ -42,18 +49,28 @@ func (Rewrite) CaddyModule() caddy.ModuleInfo { } } +// Validate ensures rewr's configuration is valid. +func (rewr Rewrite) Validate() error { + if rewr.HTTPRedirect != "" && rewr.Rehandle { + return fmt.Errorf("cannot be configured to both write a redirect response and rehandle internally") + } + return nil +} + func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error { repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer) - var rehandleNeeded bool + var changed bool + // rewrite the method if rewr.Method != "" { method := r.Method r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, "")) if r.Method != method { - rehandleNeeded = true + changed = true } } + // rewrite the URI if rewr.URI != "" { oldURI := r.RequestURI newURI := repl.ReplaceAll(rewr.URI, "") @@ -73,14 +90,44 @@ func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy } if newURI != oldURI { - rehandleNeeded = true + changed = true } } - if rehandleNeeded && rewr.Rehandle { + // strip path prefix or suffix + if rewr.StripPathPrefix != "" { + prefix := repl.ReplaceAll(rewr.StripPathPrefix, "") + r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix) + newURI := r.URL.String() + if newURI != r.RequestURI { + changed = true + } + r.RequestURI = newURI + } + if rewr.StripPathSuffix != "" { + suffix := repl.ReplaceAll(rewr.StripPathSuffix, "") + r.URL.Path = strings.TrimSuffix(r.URL.Path, suffix) + newURI := r.URL.String() + if newURI != r.RequestURI { + changed = true + } + r.RequestURI = newURI + } + + if changed && rewr.Rehandle { return caddyhttp.ErrRehandle } + if changed && rewr.HTTPRedirect != "" { + statusCode, err := strconv.Atoi(repl.ReplaceAll(rewr.HTTPRedirect.String(), "")) + if err != nil { + return caddyhttp.Error(http.StatusInternalServerError, err) + } + w.Header().Set("Location", r.RequestURI) + w.WriteHeader(statusCode) + return nil + } + return next.ServeHTTP(w, r) }