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
try_files, rewrite: allow query string in try_files (fix #2891)
Also some minor cleanup/improvements discovered along the way
Matthew Holt committed
Dec 12, 2019 at 15:27 UTC
5e9d81b507e0beb46b3812e21566bfef79c87af4
4 files changed
+57
-23
caddyconfig/httpcaddyfile/directives.go
+10
-3
@@ -53,6 +53,8 @@ func RegisterDirective(dir string, setupFunc UnmarshalFunc) {
53
54
// RegisterHandlerDirective is like RegisterDirective, but for
55
// directives which specifically output only an HTTP handler.
56
+// Directives registered with this function will always have
57
+// an optional matcher token as the first argument.
58
func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
59
RegisterDirective(dir, func(h Helper) ([]ConfigValue, error) {
60
if !h.Next() {
@@ -117,7 +119,7 @@ func (h Helper) Caddyfiles() []string {
119
}
120
121
// JSON converts val into JSON. Any errors are added to warnings.
120
-func (h Helper) JSON(val interface{}, warnings *[]caddyconfig.Warning) json.RawMessage {
122
+func (h Helper) JSON(val interface{}) json.RawMessage {
123
return caddyconfig.JSON(val, h.warnings)
124
}
125
@@ -135,9 +137,14 @@ func (h Helper) MatcherToken() (caddy.ModuleMap, bool, error) {
137
// NewRoute returns config values relevant to creating a new HTTP route.
138
func (h Helper) NewRoute(matcherSet caddy.ModuleMap,
139
handler caddyhttp.MiddlewareHandler) []ConfigValue {
138
- mod, err := caddy.GetModule(caddy.GetModuleName(handler))
140
+ mod, err := caddy.GetModule(caddy.GetModuleID(handler))
141
if err != nil {
140
- // TODO: append to warnings
142
+ *h.warnings = append(*h.warnings, caddyconfig.Warning{
143
+ File: h.File(),
144
+ Line: h.Line(),
145
+ Message: err.Error(),
146
+ })
147
+ return nil
148
}
149
var matcherSetsRaw []caddy.ModuleMap
150
if matcherSet != nil {
modules/caddyhttp/fileserver/caddyfile.go
+42
-10
@@ -15,6 +15,8 @@
15
package fileserver
16
17
import (
18
+ "strings"
19
+
20
"github.com/caddyserver/caddy/v2"
21
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
22
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
@@ -98,7 +100,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
100
//
101
// try_files <files...>
102
//
101
-// and is shorthand for:
103
+// and is basically shorthand for:
104
//
105
// matcher:try_files {
106
// file {
@@ -107,25 +109,55 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
109
// }
110
// rewrite match:try_files {http.matchers.file.relative}{http.request.uri.query_string}
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.
115
func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
116
if !h.Next() {
117
return nil, h.ArgErr()
118
}
119
115
- try := h.RemainingArgs()
116
- if len(try) == 0 {
120
+ tryFiles := h.RemainingArgs()
121
+ if len(tryFiles) == 0 {
122
return nil, h.ArgErr()
123
}
124
120
- handler := rewrite.Rewrite{
121
- URI: "{http.matchers.file.relative}{http.request.uri.query_string}",
125
+ // 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 {
129
+ handler := rewrite.Rewrite{
130
+ URI: "{http.matchers.file.relative}{http.request.uri.query_string}" + writeURIAppend,
131
+ }
132
+ matcherSet := caddy.ModuleMap{
133
+ "file": h.JSON(MatchFile{
134
+ TryFiles: try,
135
+ }),
136
+ }
137
+ return h.NewRoute(matcherSet, handler)
138
}
139
124
- matcherSet := caddy.ModuleMap{
125
- "file": h.JSON(MatchFile{
126
- TryFiles: try,
127
- }, nil),
140
+ var result []httpcaddyfile.ConfigValue
141
+
142
+ // if there are query strings in the list, we have to split into
143
+ // a separate route for each item with a query string, because
144
+ // the rewrite is different for that item
145
+ var try []string
146
+ for _, item := range tryFiles {
147
+ if idx := strings.Index(item, "?"); idx >= 0 {
148
+ if len(try) > 0 {
149
+ result = append(result, makeRoute(try, "")...)
150
+ try = []string{}
151
+ }
152
+ result = append(result, makeRoute([]string{item[:idx]}, "&"+item[idx+1:])...)
153
+ continue
154
+ }
155
+ // accumulate consecutive non-query-string parameters
156
+ try = append(try, item)
157
+ }
158
+ if len(try) > 0 {
159
+ result = append(result, makeRoute(try, "")...)
160
}
161
130
- return h.NewRoute(matcherSet, handler), nil
162
+ return result, nil
163
}
modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+5
-5
@@ -125,12 +125,12 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
125
redirMatcherSet := caddy.ModuleMap{
126
"file": h.JSON(fileserver.MatchFile{
127
TryFiles: []string{"{http.request.uri.path}/index.php"},
128
- }, nil),
128
+ }),
129
"not": h.JSON(caddyhttp.MatchNegate{
130
MatchersRaw: caddy.ModuleMap{
131
- "path": h.JSON(caddyhttp.MatchPath{"*/"}, nil),
131
+ "path": h.JSON(caddyhttp.MatchPath{"*/"}),
132
},
133
- }, nil),
133
+ }),
134
}
135
redirHandler := caddyhttp.StaticResponse{
136
StatusCode: caddyhttp.WeakString("308"),
@@ -145,7 +145,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
145
rewriteMatcherSet := caddy.ModuleMap{
146
"file": h.JSON(fileserver.MatchFile{
147
TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/index.php", "index.php"},
148
- }, nil),
148
+ }),
149
}
150
rewriteHandler := rewrite.Rewrite{
151
URI: "{http.matchers.file.relative}{http.request.uri.query_string}",
@@ -159,7 +159,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
159
// route to actually reverse proxy requests to PHP files;
160
// match only requests that are for PHP files
161
rpMatcherSet := caddy.ModuleMap{
162
- "path": h.JSON([]string{"*.php"}, nil),
162
+ "path": h.JSON([]string{"*.php"}),
163
}
164
165
// if the user specified a matcher token, use that
modules/caddyhttp/rewrite/rewrite.go
-5
@@ -190,11 +190,6 @@ func (rep replacer) do(r *http.Request, repl caddy.Replacer) bool {
190
r.URL.Path = strings.Replace(oldPath, find, replace, lim)
191
r.URL.RawQuery = strings.Replace(oldQuery, find, replace, lim)
192
193
- // changed := r.URL.Path != oldPath && r.URL.RawQuery != oldQuery
194
- // if changed {
195
- // r.RequestURI = r.URL.RequestURI()
196
- // }
197
-
193
return r.URL.Path != oldPath && r.URL.RawQuery != oldQuery
194
}
195