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
http: A little more polish on rewrite handler and try_files directive
Matthew Holt committed
Jan 11, 2020 at 13:47 UTC
25dea2903e613534e00a2a4e305e0c8f2daeea8d
5 files changed
+51
-48
modules/caddyhttp/fileserver/caddyfile.go
+16
-12
@@ -107,11 +107,17 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
107
// try_files <files...>
108
// }
109
// }
110
-// rewrite @try_files {http.matchers.file.relative}{http.request.uri.query_string}
110
+// rewrite @try_files {http.matchers.file.relative}
111
//
112
-// If any of the files in the list have a query string, the query string will
113
-// be ignored when checking for file existence, but will be augmented into
114
-// the request's URI when rewriting the request.
112
+// This directive rewrites request paths only, preserving any other part
113
+// of the URI, unless the part is explicitly given in the file list. For
114
+// example, if any of the files in the list have a query string:
115
+//
116
+// try_files {path} index.php?{query}&p={path}
117
+//
118
+// then the query string will not be treated as part of the file name; and
119
+// if that file matches, the given query string will replace any query string
120
+// that already exists on the request URI.
121
func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
122
if !h.Next() {
123
return nil, h.ArgErr()
@@ -123,16 +129,14 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
129
}
130
131
// makeRoute returns a route that tries the files listed in try
126
- // and then rewrites to the matched file, and appends writeURIAppend
127
- // to the end of the query string.
128
- makeRoute := func(try []string, writeURIAppend string) []httpcaddyfile.ConfigValue {
132
+ // and then rewrites to the matched file; userQueryString is
133
+ // appended to the rewrite rule.
134
+ makeRoute := func(try []string, userQueryString string) []httpcaddyfile.ConfigValue {
135
handler := rewrite.Rewrite{
130
- URI: "{http.matchers.file.relative}{http.request.uri.query_string}" + writeURIAppend,
136
+ URI: "{http.matchers.file.relative}" + userQueryString,
137
}
138
matcherSet := caddy.ModuleMap{
133
- "file": h.JSON(MatchFile{
134
- TryFiles: try,
135
- }),
139
+ "file": h.JSON(MatchFile{TryFiles: try}),
140
}
141
return h.NewRoute(matcherSet, handler)
142
}
@@ -149,7 +153,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
153
result = append(result, makeRoute(try, "")...)
154
try = []string{}
155
}
152
- result = append(result, makeRoute([]string{item[:idx]}, "&"+item[idx+1:])...)
156
+ result = append(result, makeRoute([]string{item[:idx]}, item[idx:])...)
157
continue
158
}
159
// accumulate consecutive non-query-string parameters
modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+1
-1
@@ -149,7 +149,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
149
}),
150
}
151
rewriteHandler := rewrite.Rewrite{
152
- URI: "{http.matchers.file.relative}?{http.request.uri.query}",
152
+ URI: "{http.matchers.file.relative}",
153
}
154
rewriteRoute := caddyhttp.Route{
155
MatcherSetsRaw: []caddy.ModuleMap{rewriteMatcherSet},
modules/caddyhttp/rewrite/caddyfile.go
+4
-3
@@ -32,7 +32,8 @@ func init() {
32
//
33
// rewrite [<matcher>] <to>
34
//
35
-// The <to> parameter becomes the new URI.
35
+// Only URI components which are given in <to> will be set in the resulting URI.
36
+// See the docs for the rewrite handler for more information.
37
func parseCaddyfileRewrite(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
38
var rewr Rewrite
39
for h.Next() {
@@ -58,7 +59,7 @@ func parseCaddyfileStripPrefix(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHand
59
if !h.NextArg() {
60
return nil, h.ArgErr()
61
}
61
- rewr.StripPrefix = h.Val()
62
+ rewr.StripPathPrefix = h.Val()
63
if h.NextArg() {
64
return nil, h.ArgErr()
65
}
@@ -77,7 +78,7 @@ func parseCaddyfileStripSuffix(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHand
78
if !h.NextArg() {
79
return nil, h.ArgErr()
80
}
80
- rewr.StripSuffix = h.Val()
81
+ rewr.StripPathSuffix = h.Val()
82
if h.NextArg() {
83
return nil, h.ArgErr()
84
}
modules/caddyhttp/rewrite/rewrite.go
+24
-26
@@ -17,7 +17,6 @@ package rewrite
17
import (
18
"net/http"
19
"net/url"
20
- "strconv"
20
"strings"
21
22
"github.com/caddyserver/caddy/v2"
@@ -31,32 +30,40 @@ func init() {
30
31
// Rewrite is a middleware which can rewrite HTTP requests.
32
//
34
-// These rewrite properties are applied to a request in this order:
35
-// Method, URI, StripPrefix, StripSuffix, URISubstring.
36
-//
37
-// TODO: This module is still a WIP and may experience breaking changes.
33
+// The Method and URI properties are "setters": the request URI
34
+// will be set to the given values. Other properties are "modifiers":
35
+// they modify existing files but do not explicitly specify what the
36
+// result will be. It is atypical to combine the use of setters and
37
+// modifiers in a single rewrite.
38
type Rewrite struct {
39
// Changes the request's HTTP verb.
40
Method string `json:"method,omitempty"`
41
42
- // Changes the request's URI (path, query string, and fragment if present).
42
+ // Changes the request's URI, which consists of path and query string.
43
// Only components of the URI that are specified will be changed.
44
+ // For example, a value of "/foo.html" or "foo.html" will only change
45
+ // the path and will preserve any existing query string. Similarly, a
46
+ // value of "?a=b" will only change the query string and will not affect
47
+ // the path. Both can also be changed: "/foo?a=b" - this sets both the
48
+ // path and query string at the same time.
49
+ //
50
+ // You can also use placeholders. For example, to preserve the existing
51
+ // query string, you might use: "?{http.request.uri.query}&a=b". Any
52
+ // key-value pairs you add to the query string will not overwrite
53
+ // existing values.
54
+ //
55
+ // To clear the query string, explicitly set an empty one: "?"
56
URI string `json:"uri,omitempty"`
57
58
// Strips the given prefix from the beginning of the URI path.
47
- StripPrefix string `json:"strip_prefix,omitempty"`
59
+ StripPathPrefix string `json:"strip_path_prefix,omitempty"`
60
61
// Strips the given suffix from the end of the URI path.
50
- StripSuffix string `json:"strip_suffix,omitempty"`
62
+ StripPathSuffix string `json:"strip_path_suffix,omitempty"`
63
64
// Performs substring replacements on the URI.
65
URISubstring []replacer `json:"uri_substring,omitempty"`
66
55
- // If set to a 3xx HTTP status code and if the URI was rewritten (changed),
56
- // the handler will issue a simple HTTP redirect to the new URI using the
57
- // given status code.
58
- HTTPRedirect caddyhttp.WeakString `json:"http_redirect,omitempty"`
59
-
67
logger *zap.Logger
68
}
69
@@ -88,15 +95,6 @@ func (rewr Rewrite) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddy
95
zap.String("method", r.Method),
96
zap.String("uri", r.RequestURI),
97
)
91
- if rewr.HTTPRedirect != "" {
92
- statusCode, err := strconv.Atoi(repl.ReplaceAll(rewr.HTTPRedirect.String(), ""))
93
- if err != nil {
94
- return caddyhttp.Error(http.StatusInternalServerError, err)
95
- }
96
- w.Header().Set("Location", r.RequestURI)
97
- w.WriteHeader(statusCode)
98
- return nil
99
- }
98
}
99
100
return next.ServeHTTP(w, r)
@@ -148,12 +146,12 @@ func (rewr Rewrite) rewrite(r *http.Request, repl *caddy.Replacer, logger *zap.L
146
}
147
148
// strip path prefix or suffix
151
- if rewr.StripPrefix != "" {
152
- prefix := repl.ReplaceAll(rewr.StripPrefix, "")
149
+ if rewr.StripPathPrefix != "" {
150
+ prefix := repl.ReplaceAll(rewr.StripPathPrefix, "")
151
r.URL.Path = strings.TrimPrefix(r.URL.Path, prefix)
152
}
155
- if rewr.StripSuffix != "" {
156
- suffix := repl.ReplaceAll(rewr.StripSuffix, "")
153
+ if rewr.StripPathSuffix != "" {
154
+ suffix := repl.ReplaceAll(rewr.StripPathSuffix, "")
155
r.URL.Path = strings.TrimSuffix(r.URL.Path, suffix)
156
}
157
modules/caddyhttp/rewrite/rewrite_test.go
+6
-6
@@ -150,33 +150,33 @@ func TestRewrite(t *testing.T) {
150
},
151
152
{
153
- rule: Rewrite{StripPrefix: "/prefix"},
153
+ rule: Rewrite{StripPathPrefix: "/prefix"},
154
input: newRequest(t, "GET", "/foo/bar"),
155
expect: newRequest(t, "GET", "/foo/bar"),
156
},
157
{
158
- rule: Rewrite{StripPrefix: "/prefix"},
158
+ rule: Rewrite{StripPathPrefix: "/prefix"},
159
input: newRequest(t, "GET", "/prefix/foo/bar"),
160
expect: newRequest(t, "GET", "/foo/bar"),
161
},
162
{
163
- rule: Rewrite{StripPrefix: "/prefix"},
163
+ rule: Rewrite{StripPathPrefix: "/prefix"},
164
input: newRequest(t, "GET", "/foo/prefix/bar"),
165
expect: newRequest(t, "GET", "/foo/prefix/bar"),
166
},
167
168
{
169
- rule: Rewrite{StripSuffix: "/suffix"},
169
+ rule: Rewrite{StripPathSuffix: "/suffix"},
170
input: newRequest(t, "GET", "/foo/bar"),
171
expect: newRequest(t, "GET", "/foo/bar"),
172
},
173
{
174
- rule: Rewrite{StripSuffix: "suffix"},
174
+ rule: Rewrite{StripPathSuffix: "suffix"},
175
input: newRequest(t, "GET", "/foo/bar/suffix"),
176
expect: newRequest(t, "GET", "/foo/bar/"),
177
},
178
{
179
- rule: Rewrite{StripSuffix: "/suffix"},
179
+ rule: Rewrite{StripPathSuffix: "/suffix"},
180
input: newRequest(t, "GET", "/foo/suffix/bar"),
181
expect: newRequest(t, "GET", "/foo/suffix/bar"),
182
},