summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/caddyhttp/fileserver/matcher.go51
-rw-r--r--modules/caddyhttp/fileserver/matcher_test.go8
-rw-r--r--modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go20
3 files changed, 51 insertions, 28 deletions
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(),
diff --git a/modules/caddyhttp/fileserver/matcher_test.go b/modules/caddyhttp/fileserver/matcher_test.go
index ddd4f78..e319907 100644
--- a/modules/caddyhttp/fileserver/matcher_test.go
+++ b/modules/caddyhttp/fileserver/matcher_test.go
@@ -206,9 +206,13 @@ func TestPHPFileMatcher(t *testing.T) {
func TestFirstSplit(t *testing.T) {
m := MatchFile{SplitPath: []string{".php"}}
- actual := m.firstSplit("index.PHP/somewhere")
+ actual, remainder := m.firstSplit("index.PHP/somewhere")
expected := "index.PHP"
+ expectedRemainder := "/somewhere"
if actual != expected {
- t.Errorf("Expected %s but got %s", expected, actual)
+ t.Errorf("Expected split %s but got %s", expected, actual)
+ }
+ if remainder != expectedRemainder {
+ t.Errorf("Expected remainder %s but got %s", expectedRemainder, remainder)
}
}
diff --git a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
index de6d0a4..0976437 100644
--- a/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
+++ b/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go
@@ -195,19 +195,27 @@ func (t Transport) buildEnv(r *http.Request) (map[string]string, error) {
}
fpath := r.URL.Path
+ scriptName := fpath
+ docURI := fpath
// split "actual path" from "path info" if configured
- var docURI, pathInfo string
+ var pathInfo string
if splitPos := t.splitPos(fpath); splitPos > -1 {
docURI = fpath[:splitPos]
pathInfo = fpath[splitPos:]
- } else {
- docURI = fpath
+
+ // Strip PATH_INFO from SCRIPT_NAME
+ scriptName = strings.TrimSuffix(scriptName, pathInfo)
}
- scriptName := fpath
- // Strip PATH_INFO from SCRIPT_NAME
- scriptName = strings.TrimSuffix(scriptName, pathInfo)
+ // Try to grab the path remainder from a file matcher
+ // if we didn't get a split result here.
+ // See https://github.com/caddyserver/caddy/issues/3718
+ if pathInfo == "" {
+ if remainder, ok := repl.GetString("http.matchers.file.remainder"); ok {
+ pathInfo = remainder
+ }
+ }
// SCRIPT_FILENAME is the absolute path of SCRIPT_NAME
scriptFilename := filepath.Join(root, scriptName)