rewrite: Options to strip prefix/suffix and issue redirects

Fixes #2011
This commit is contained in:
Matthew Holt 2019-10-19 19:22:29 -06:00
parent 19e834cf36
commit 208f2ff93c
No known key found for this signature in database
GPG Key ID: 2A349DD577D586A5
1 changed files with 54 additions and 7 deletions

View File

@ -15,8 +15,10 @@
package rewrite package rewrite
import ( import (
"fmt"
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings" "strings"
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
@ -29,9 +31,14 @@ func init() {
// Rewrite is a middleware which can rewrite HTTP requests. // Rewrite is a middleware which can rewrite HTTP requests.
type Rewrite struct { type Rewrite struct {
Method string `json:"method,omitempty"` Method string `json:"method,omitempty"`
URI string `json:"uri,omitempty"` URI string `json:"uri,omitempty"`
Rehandle bool `json:"rehandle,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. // 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 { func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer) repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer)
var rehandleNeeded bool var changed bool
// rewrite the method
if rewr.Method != "" { if rewr.Method != "" {
method := r.Method method := r.Method
r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, "")) r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, ""))
if r.Method != method { if r.Method != method {
rehandleNeeded = true changed = true
} }
} }
// rewrite the URI
if rewr.URI != "" { if rewr.URI != "" {
oldURI := r.RequestURI oldURI := r.RequestURI
newURI := repl.ReplaceAll(rewr.URI, "") newURI := repl.ReplaceAll(rewr.URI, "")
@ -73,14 +90,44 @@ func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
} }
if newURI != oldURI { 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 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) return next.ServeHTTP(w, r)
} }