0
Fork 0
mirror of https://github.com/caddyserver/caddy.git synced 2024-12-30 22:34:15 -05:00

try_files, rewrite: allow query string in try_files (fix #2891)

Also some minor cleanup/improvements discovered along the way
This commit is contained in:
Matthew Holt 2019-12-12 15:27:09 -07:00
parent 09a8517065
commit 5e9d81b507
No known key found for this signature in database
GPG key ID: 2A349DD577D586A5
4 changed files with 57 additions and 23 deletions

View file

@ -53,6 +53,8 @@ func RegisterDirective(dir string, setupFunc UnmarshalFunc) {
// RegisterHandlerDirective is like RegisterDirective, but for // RegisterHandlerDirective is like RegisterDirective, but for
// directives which specifically output only an HTTP handler. // directives which specifically output only an HTTP handler.
// Directives registered with this function will always have
// an optional matcher token as the first argument.
func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) { func RegisterHandlerDirective(dir string, setupFunc UnmarshalHandlerFunc) {
RegisterDirective(dir, func(h Helper) ([]ConfigValue, error) { RegisterDirective(dir, func(h Helper) ([]ConfigValue, error) {
if !h.Next() { if !h.Next() {
@ -117,7 +119,7 @@ func (h Helper) Caddyfiles() []string {
} }
// JSON converts val into JSON. Any errors are added to warnings. // JSON converts val into JSON. Any errors are added to warnings.
func (h Helper) JSON(val interface{}, warnings *[]caddyconfig.Warning) json.RawMessage { func (h Helper) JSON(val interface{}) json.RawMessage {
return caddyconfig.JSON(val, h.warnings) return caddyconfig.JSON(val, h.warnings)
} }
@ -135,9 +137,14 @@ func (h Helper) MatcherToken() (caddy.ModuleMap, bool, error) {
// NewRoute returns config values relevant to creating a new HTTP route. // NewRoute returns config values relevant to creating a new HTTP route.
func (h Helper) NewRoute(matcherSet caddy.ModuleMap, func (h Helper) NewRoute(matcherSet caddy.ModuleMap,
handler caddyhttp.MiddlewareHandler) []ConfigValue { handler caddyhttp.MiddlewareHandler) []ConfigValue {
mod, err := caddy.GetModule(caddy.GetModuleName(handler)) mod, err := caddy.GetModule(caddy.GetModuleID(handler))
if err != nil { if err != nil {
// TODO: append to warnings *h.warnings = append(*h.warnings, caddyconfig.Warning{
File: h.File(),
Line: h.Line(),
Message: err.Error(),
})
return nil
} }
var matcherSetsRaw []caddy.ModuleMap var matcherSetsRaw []caddy.ModuleMap
if matcherSet != nil { if matcherSet != nil {

View file

@ -15,6 +15,8 @@
package fileserver package fileserver
import ( import (
"strings"
"github.com/caddyserver/caddy/v2" "github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
"github.com/caddyserver/caddy/v2/modules/caddyhttp" "github.com/caddyserver/caddy/v2/modules/caddyhttp"
@ -98,7 +100,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
// //
// try_files <files...> // try_files <files...>
// //
// and is shorthand for: // and is basically shorthand for:
// //
// matcher:try_files { // matcher:try_files {
// file { // file {
@ -107,25 +109,55 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
// } // }
// rewrite match:try_files {http.matchers.file.relative}{http.request.uri.query_string} // rewrite match:try_files {http.matchers.file.relative}{http.request.uri.query_string}
// //
// If any of the files in the list have a query string, the query string will
// be ignored when checking for file existence, but will be augmented into
// the request's URI when rewriting the request.
func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) { func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) {
if !h.Next() { if !h.Next() {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
try := h.RemainingArgs() tryFiles := h.RemainingArgs()
if len(try) == 0 { if len(tryFiles) == 0 {
return nil, h.ArgErr() return nil, h.ArgErr()
} }
handler := rewrite.Rewrite{ // makeRoute returns a route that tries the files listed in try
URI: "{http.matchers.file.relative}{http.request.uri.query_string}", // and then rewrites to the matched file, and appends writeURIAppend
// to the end of the query string.
makeRoute := func(try []string, writeURIAppend string) []httpcaddyfile.ConfigValue {
handler := rewrite.Rewrite{
URI: "{http.matchers.file.relative}{http.request.uri.query_string}" + writeURIAppend,
}
matcherSet := caddy.ModuleMap{
"file": h.JSON(MatchFile{
TryFiles: try,
}),
}
return h.NewRoute(matcherSet, handler)
} }
matcherSet := caddy.ModuleMap{ var result []httpcaddyfile.ConfigValue
"file": h.JSON(MatchFile{
TryFiles: try, // if there are query strings in the list, we have to split into
}, nil), // a separate route for each item with a query string, because
// the rewrite is different for that item
var try []string
for _, item := range tryFiles {
if idx := strings.Index(item, "?"); idx >= 0 {
if len(try) > 0 {
result = append(result, makeRoute(try, "")...)
try = []string{}
}
result = append(result, makeRoute([]string{item[:idx]}, "&"+item[idx+1:])...)
continue
}
// accumulate consecutive non-query-string parameters
try = append(try, item)
}
if len(try) > 0 {
result = append(result, makeRoute(try, "")...)
} }
return h.NewRoute(matcherSet, handler), nil return result, nil
} }

View file

@ -125,12 +125,12 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
redirMatcherSet := caddy.ModuleMap{ redirMatcherSet := caddy.ModuleMap{
"file": h.JSON(fileserver.MatchFile{ "file": h.JSON(fileserver.MatchFile{
TryFiles: []string{"{http.request.uri.path}/index.php"}, TryFiles: []string{"{http.request.uri.path}/index.php"},
}, nil), }),
"not": h.JSON(caddyhttp.MatchNegate{ "not": h.JSON(caddyhttp.MatchNegate{
MatchersRaw: caddy.ModuleMap{ MatchersRaw: caddy.ModuleMap{
"path": h.JSON(caddyhttp.MatchPath{"*/"}, nil), "path": h.JSON(caddyhttp.MatchPath{"*/"}),
}, },
}, nil), }),
} }
redirHandler := caddyhttp.StaticResponse{ redirHandler := caddyhttp.StaticResponse{
StatusCode: caddyhttp.WeakString("308"), StatusCode: caddyhttp.WeakString("308"),
@ -145,7 +145,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
rewriteMatcherSet := caddy.ModuleMap{ rewriteMatcherSet := caddy.ModuleMap{
"file": h.JSON(fileserver.MatchFile{ "file": h.JSON(fileserver.MatchFile{
TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/index.php", "index.php"}, TryFiles: []string{"{http.request.uri.path}", "{http.request.uri.path}/index.php", "index.php"},
}, nil), }),
} }
rewriteHandler := rewrite.Rewrite{ rewriteHandler := rewrite.Rewrite{
URI: "{http.matchers.file.relative}{http.request.uri.query_string}", URI: "{http.matchers.file.relative}{http.request.uri.query_string}",
@ -159,7 +159,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
// route to actually reverse proxy requests to PHP files; // route to actually reverse proxy requests to PHP files;
// match only requests that are for PHP files // match only requests that are for PHP files
rpMatcherSet := caddy.ModuleMap{ rpMatcherSet := caddy.ModuleMap{
"path": h.JSON([]string{"*.php"}, nil), "path": h.JSON([]string{"*.php"}),
} }
// if the user specified a matcher token, use that // if the user specified a matcher token, use that

View file

@ -190,11 +190,6 @@ func (rep replacer) do(r *http.Request, repl caddy.Replacer) bool {
r.URL.Path = strings.Replace(oldPath, find, replace, lim) r.URL.Path = strings.Replace(oldPath, find, replace, lim)
r.URL.RawQuery = strings.Replace(oldQuery, find, replace, lim) r.URL.RawQuery = strings.Replace(oldQuery, find, replace, lim)
// changed := r.URL.Path != oldPath && r.URL.RawQuery != oldQuery
// if changed {
// r.RequestURI = r.URL.RequestURI()
// }
return r.URL.Path != oldPath && r.URL.RawQuery != oldQuery return r.URL.Path != oldPath && r.URL.RawQuery != oldQuery
} }