From 6e9ac248dd5c2f7a4cd4e37ff277a86c18085be6 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Fri, 4 Dec 2020 19:12:13 -0500 Subject: fastcgi: Set PATH_INFO to file matcher remainder as fallback (#3739) * fastcgi: Set PATH_INFO to file matcher remainder as fallback * fastcgi: Avoid changing scriptName when not necessary * Stylistic tweaks Co-authored-by: Matthew Holt --- modules/caddyhttp/fileserver/matcher.go | 51 ++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 20 deletions(-) (limited to 'modules/caddyhttp/fileserver/matcher.go') diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go index c103b03..44ef9ed 100644 --- a/modules/caddyhttp/fileserver/matcher.go +++ b/modules/caddyhttp/fileserver/matcher.go @@ -44,6 +44,8 @@ func init() { // of the matched file. // - `{http.matchers.file.type}` Set to "directory" if // the matched file is a directory, "file" otherwise. +// - `{http.matchers.file.remainder}` Set to the remainder +// of the path if the path was split by `split_path`. type MatchFile struct { // The root directory, used for creating absolute // file paths, and required when working with @@ -155,11 +157,12 @@ func (m MatchFile) Validate() error { } // Match returns true if r matches m. Returns true -// if a file was matched. If so, three placeholders +// if a file was matched. If so, four placeholders // will be available: // - http.matchers.file.relative // - http.matchers.file.absolute // - http.matchers.file.type +// - http.matchers.file.remainder func (m MatchFile) Match(r *http.Request) bool { return m.selectFile(r) } @@ -179,19 +182,20 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { } // common preparation of the file into parts - prepareFilePath := func(file string) (string, string) { - suffix := m.firstSplit(path.Clean(repl.ReplaceAll(file, ""))) + prepareFilePath := func(file string) (suffix, fullpath, remainder string) { + suffix, remainder = m.firstSplit(path.Clean(repl.ReplaceAll(file, ""))) if strings.HasSuffix(file, "/") { suffix += "/" } - fullpath := sanitizedPathJoin(root, suffix) - return suffix, fullpath + fullpath = sanitizedPathJoin(root, suffix) + return } // sets up the placeholders for the matched file - setPlaceholders := func(info os.FileInfo, rel string, abs string) { + setPlaceholders := func(info os.FileInfo, rel string, abs string, remainder string) { repl.Set("http.matchers.file.relative", rel) repl.Set("http.matchers.file.absolute", abs) + repl.Set("http.matchers.file.remainder", remainder) fileType := "file" if info.IsDir() { @@ -203,9 +207,9 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { switch m.TryPolicy { case "", tryPolicyFirstExist: for _, f := range m.TryFiles { - suffix, fullpath := prepareFilePath(f) + suffix, fullpath, remainder := prepareFilePath(f) if info, exists := strictFileExists(fullpath); exists { - setPlaceholders(info, suffix, fullpath) + setPlaceholders(info, suffix, fullpath, remainder) return true } } @@ -214,52 +218,58 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { var largestSize int64 var largestFilename string var largestSuffix string + var remainder string var info os.FileInfo for _, f := range m.TryFiles { - suffix, fullpath := prepareFilePath(f) + suffix, fullpath, splitRemainder := prepareFilePath(f) info, err := os.Stat(fullpath) if err == nil && info.Size() > largestSize { largestSize = info.Size() largestFilename = fullpath largestSuffix = suffix + remainder = splitRemainder } } - setPlaceholders(info, largestSuffix, largestFilename) + setPlaceholders(info, largestSuffix, largestFilename, remainder) return true case tryPolicySmallestSize: var smallestSize int64 var smallestFilename string var smallestSuffix string + var remainder string var info os.FileInfo for _, f := range m.TryFiles { - suffix, fullpath := prepareFilePath(f) + suffix, fullpath, splitRemainder := prepareFilePath(f) info, err := os.Stat(fullpath) if err == nil && (smallestSize == 0 || info.Size() < smallestSize) { smallestSize = info.Size() smallestFilename = fullpath smallestSuffix = suffix + remainder = splitRemainder } } - setPlaceholders(info, smallestSuffix, smallestFilename) + setPlaceholders(info, smallestSuffix, smallestFilename, remainder) return true case tryPolicyMostRecentlyMod: var recentDate time.Time var recentFilename string var recentSuffix string + var remainder string var info os.FileInfo for _, f := range m.TryFiles { - suffix, fullpath := prepareFilePath(f) + suffix, fullpath, splitRemainder := prepareFilePath(f) info, err := os.Stat(fullpath) if err == nil && (recentDate.IsZero() || info.ModTime().After(recentDate)) { recentDate = info.ModTime() recentFilename = fullpath recentSuffix = suffix + remainder = splitRemainder } } - setPlaceholders(info, recentSuffix, recentFilename) + setPlaceholders(info, recentSuffix, recentFilename, remainder) return true } @@ -297,10 +307,11 @@ func strictFileExists(file string) (os.FileInfo, bool) { // 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 { +// return values are the first piece of the path that +// ends with the split substring and the remainder. +// If the path cannot be split, the path is returned +// as-is (with no remainder). +func (m MatchFile) firstSplit(path string) (splitPart, remainder string) { for _, split := range m.SplitPath { if idx := indexFold(path, split); idx > -1 { pos := idx + len(split) @@ -308,10 +319,10 @@ func (m MatchFile) firstSplit(path string) string { if pos != len(path) && !strings.HasPrefix(path[pos:], "/") { continue } - return path[:pos] + return path[:pos], path[pos:] } } - return path + return path, "" } // There is no strings.IndexFold() function like there is strings.EqualFold(), -- cgit v1.2.3