summaryrefslogtreecommitdiff
path: root/modules/caddyhttp/fileserver/matcher.go
diff options
context:
space:
mode:
authorFrancis Lavoie <lavofr@gmail.com>2020-04-27 16:46:46 -0400
committerGitHub <noreply@github.com>2020-04-27 14:46:46 -0600
commit5ae1a5617c4bb1deef22cb3658ee581bb7dbf367 (patch)
tree84bb5582a6b1f961ad670f290d020b747ff26cee /modules/caddyhttp/fileserver/matcher.go
parent83c85c53f583906e438bb9eb30fc0ab57bf59108 (diff)
caddyhttp: Add split_path to file matcher (used by php_fastcgi) (#3302)
* matcher: Add `split_path` option to file matcher; used in php_fastcgi * matcher: Skip try_files split if not the final part of the filename * matcher: Add MatchFile tests * matcher: Clarify SplitPath godoc
Diffstat (limited to 'modules/caddyhttp/fileserver/matcher.go')
-rw-r--r--modules/caddyhttp/fileserver/matcher.go44
1 files changed, 40 insertions, 4 deletions
diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go
index 1915fb7..1beb8ba 100644
--- a/modules/caddyhttp/fileserver/matcher.go
+++ b/modules/caddyhttp/fileserver/matcher.go
@@ -68,6 +68,17 @@ type MatchFile struct {
//
// Default is first_exist.
TryPolicy string `json:"try_policy,omitempty"`
+
+ // A list of delimiters to use to split the path in two
+ // when trying files. If empty, no splitting will
+ // occur, and the path will be tried as-is. For each
+ // split value, the left-hand side of the split,
+ // including the split value, will be the path tried.
+ // For example, the path `/remote.php/dav/` using the
+ // split value `.php` would try the file `/remote.php`.
+ // Each delimiter must appear at the end of a URI path
+ // component in order to be used as a split delimiter.
+ SplitPath []string `json:"split_path,omitempty"`
}
// CaddyModule returns the Caddy module information.
@@ -105,6 +116,11 @@ func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
return d.ArgErr()
}
m.TryPolicy = d.Val()
+ case "split":
+ m.SplitPath = d.RemainingArgs()
+ if len(m.SplitPath) == 0 {
+ return d.ArgErr()
+ }
}
}
}
@@ -167,7 +183,7 @@ func (m MatchFile) selectFile(r *http.Request) (rel, abs string, matched bool) {
switch m.TryPolicy {
case "", tryPolicyFirstExist:
for _, f := range m.TryFiles {
- suffix := path.Clean(repl.ReplaceAll(f, ""))
+ suffix := m.firstSplit(path.Clean(repl.ReplaceAll(f, "")))
fullpath := sanitizedPathJoin(root, suffix)
if strictFileExists(fullpath) {
return suffix, fullpath, true
@@ -179,7 +195,7 @@ func (m MatchFile) selectFile(r *http.Request) (rel, abs string, matched bool) {
var largestFilename string
var largestSuffix string
for _, f := range m.TryFiles {
- suffix := path.Clean(repl.ReplaceAll(f, ""))
+ suffix := m.firstSplit(path.Clean(repl.ReplaceAll(f, "")))
fullpath := sanitizedPathJoin(root, suffix)
info, err := os.Stat(fullpath)
if err == nil && info.Size() > largestSize {
@@ -195,7 +211,7 @@ func (m MatchFile) selectFile(r *http.Request) (rel, abs string, matched bool) {
var smallestFilename string
var smallestSuffix string
for _, f := range m.TryFiles {
- suffix := path.Clean(repl.ReplaceAll(f, ""))
+ suffix := m.firstSplit(path.Clean(repl.ReplaceAll(f, "")))
fullpath := sanitizedPathJoin(root, suffix)
info, err := os.Stat(fullpath)
if err == nil && (smallestSize == 0 || info.Size() < smallestSize) {
@@ -211,7 +227,7 @@ func (m MatchFile) selectFile(r *http.Request) (rel, abs string, matched bool) {
var recentFilename string
var recentSuffix string
for _, f := range m.TryFiles {
- suffix := path.Clean(repl.ReplaceAll(f, ""))
+ suffix := m.firstSplit(path.Clean(repl.ReplaceAll(f, "")))
fullpath := sanitizedPathJoin(root, suffix)
info, err := os.Stat(fullpath)
if err == nil &&
@@ -256,6 +272,26 @@ func strictFileExists(file string) bool {
return !stat.IsDir()
}
+// firstSplit returns the first result where the path
+// can be split in two by a value in m.SplitPath. The
+// result is the first piece of the path that ends with
+// in the split value. Returns the path as-is if the
+// path cannot be split.
+func (m MatchFile) firstSplit(path string) string {
+ lowerPath := strings.ToLower(path)
+ for _, split := range m.SplitPath {
+ if idx := strings.Index(lowerPath, strings.ToLower(split)); idx > -1 {
+ pos := idx + len(split)
+ // skip the split if it's not the final part of the filename
+ if pos != len(path) && !strings.HasPrefix(path[pos:], "/") {
+ continue
+ }
+ return path[:pos]
+ }
+ }
+ return path
+}
+
const (
tryPolicyFirstExist = "first_exist"
tryPolicyLargestSize = "largest_size"