@marcel91200 / caddy Mirror · read-only / commits / 208f2ff9
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

rewrite: Options to strip prefix/suffix and issue redirects

Fixes #2011

Matthew Holt committed Oct 19, 2019 at 19:22 UTC 208f2ff93c1bd2c009e4b96f664c1808ede79f3a
1 file changed +54 -7
modules/caddyhttp/rewrite/rewrite.go
+54 -7
@@ -15,8 +15,10 @@
15 package rewrite
16
17 import (
18 + "fmt"
19 "net/http"
20 "net/url"
21 + "strconv"
22 "strings"
23
24 "github.com/caddyserver/caddy/v2"
@@ -29,9 +31,14 @@ func init() {
31
32 // Rewrite is a middleware which can rewrite HTTP requests.
33 type Rewrite struct {
32 - Method string `json:"method,omitempty"`
33 - URI string `json:"uri,omitempty"`
34 - Rehandle bool `json:"rehandle,omitempty"`
34 + Method string `json:"method,omitempty"`
35 + URI string `json:"uri,omitempty"`
36 +
37 + StripPathPrefix string `json:"strip_path_prefix,omitempty"`
38 + StripPathSuffix string `json:"strip_path_suffix,omitempty"`
39 +
40 + HTTPRedirect caddyhttp.WeakString `json:"http_redirect,omitempty"`
41 + Rehandle bool `json:"rehandle,omitempty"`
42 }
43
44 // CaddyModule returns the Caddy module information.
@@ -42,18 +49,28 @@ func (Rewrite) CaddyModule() caddy.ModuleInfo {
49 }
50 }
51
52 +// Validate ensures rewr's configuration is valid.
53 +func (rewr Rewrite) Validate() error {
54 + if rewr.HTTPRedirect != "" && rewr.Rehandle {
55 + return fmt.Errorf("cannot be configured to both write a redirect response and rehandle internally")
56 + }
57 + return nil
58 +}
59 +
60 func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
61 repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer)
47 - var rehandleNeeded bool
62 + var changed bool
63
64 + // rewrite the method
65 if rewr.Method != "" {
66 method := r.Method
67 r.Method = strings.ToUpper(repl.ReplaceAll(rewr.Method, ""))
68 if r.Method != method {
53 - rehandleNeeded = true
69 + changed = true
70 }
71 }
72
73 + // rewrite the URI
74 if rewr.URI != "" {
75 oldURI := r.RequestURI
76 newURI := repl.ReplaceAll(rewr.URI, "")
@@ -73,14 +90,44 @@ func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
90 }
91
92 if newURI != oldURI {
76 - rehandleNeeded = true
93 + changed = true
94 }
95 }
96
80 - if rehandleNeeded && rewr.Rehandle {
97 + // strip path prefix or suffix
98 + if rewr.StripPathPrefix != "" {
99 + prefix := repl.ReplaceAll(rewr.StripPathPrefix, "")
100 + r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix)
101 + newURI := r.URL.String()
102 + if newURI != r.RequestURI {
103 + changed = true
104 + }
105 + r.RequestURI = newURI
106 + }
107 + if rewr.StripPathSuffix != "" {
108 + suffix := repl.ReplaceAll(rewr.StripPathSuffix, "")
109 + r.URL.Path = strings.TrimSuffix(r.URL.Path, suffix)
110 + newURI := r.URL.String()
111 + if newURI != r.RequestURI {
112 + changed = true
113 + }
114 + r.RequestURI = newURI
115 + }
116 +
117 + if changed && rewr.Rehandle {
118 return caddyhttp.ErrRehandle
119 }
120
121 + if changed && rewr.HTTPRedirect != "" {
122 + statusCode, err := strconv.Atoi(repl.ReplaceAll(rewr.HTTPRedirect.String(), ""))
123 + if err != nil {
124 + return caddyhttp.Error(http.StatusInternalServerError, err)
125 + }
126 + w.Header().Set("Location", r.RequestURI)
127 + w.WriteHeader(statusCode)
128 + return nil
129 + }
130 +
131 return next.ServeHTTP(w, r)
132 }
133