aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules
diff options
context:
space:
mode:
authorKévin Dunglas <[email protected]>2024-12-03 13:44:49 +0100
committerGitHub <[email protected]>2024-12-03 05:44:49 -0700
commitefd9251ad38a4fd9f7d900445400ac3c8e564c28 (patch)
treeae1457e6da8202688c67a1a47f67119e25423f31 /modules
parentb116dcea3d022cd2b060a978c499ac17e5d0a2e1 (diff)
downloadcaddy-efd9251ad38a4fd9f7d900445400ac3c8e564c28.tar.gz
caddy-efd9251ad38a4fd9f7d900445400ac3c8e564c28.zip
fileserver: Add `first_exist_fallback` strategy for `try_files` (#6699)
* feat: add first_exist_or_fallback strategy for try_files * fix tests * linter
Diffstat (limited to 'modules')
-rw-r--r--modules/caddyhttp/fileserver/caddyfile.go2
-rw-r--r--modules/caddyhttp/fileserver/matcher.go38
-rw-r--r--modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go8
3 files changed, 35 insertions, 13 deletions
diff --git a/modules/caddyhttp/fileserver/caddyfile.go b/modules/caddyhttp/fileserver/caddyfile.go
index dbe2b2e56..86c26ea35 100644
--- a/modules/caddyhttp/fileserver/caddyfile.go
+++ b/modules/caddyhttp/fileserver/caddyfile.go
@@ -274,7 +274,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
tryPolicy = h.Val()
switch tryPolicy {
- case tryPolicyFirstExist, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
+ case tryPolicyFirstExist, tryPolicyFirstExistFallback, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
default:
return nil, h.Errf("unrecognized try policy: %s", tryPolicy)
}
diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go
index c42907491..a8b4a3035 100644
--- a/modules/caddyhttp/fileserver/matcher.go
+++ b/modules/caddyhttp/fileserver/matcher.go
@@ -90,6 +90,7 @@ type MatchFile struct {
// How to choose a file in TryFiles. Can be:
//
// - first_exist
+ // - first_exist_fallback
// - smallest_size
// - largest_size
// - most_recently_modified
@@ -415,13 +416,13 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
}
// setPlaceholders creates the placeholders for the matched file
- setPlaceholders := func(candidate matchCandidate, info fs.FileInfo) {
+ setPlaceholders := func(candidate matchCandidate, isDir bool) {
repl.Set("http.matchers.file.relative", filepath.ToSlash(candidate.relative))
repl.Set("http.matchers.file.absolute", filepath.ToSlash(candidate.fullpath))
repl.Set("http.matchers.file.remainder", filepath.ToSlash(candidate.splitRemainder))
fileType := "file"
- if info.IsDir() {
+ if isDir {
fileType = "directory"
}
repl.Set("http.matchers.file.type", fileType)
@@ -429,8 +430,13 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
// match file according to the configured policy
switch m.TryPolicy {
- case "", tryPolicyFirstExist:
- for _, pattern := range m.TryFiles {
+ case "", tryPolicyFirstExist, tryPolicyFirstExistFallback:
+ maxI := -1
+ if m.TryPolicy == tryPolicyFirstExistFallback {
+ maxI = len(m.TryFiles) - 1
+ }
+
+ for i, pattern := range m.TryFiles {
// If the pattern is a status code, emit an error,
// which short-circuits the middleware pipeline and
// writes an HTTP error response.
@@ -440,8 +446,15 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
candidates := makeCandidates(pattern)
for _, c := range candidates {
+ // Skip the IO if using fallback policy and it's the latest item
+ if i == maxI {
+ setPlaceholders(c, false)
+
+ return true, nil
+ }
+
if info, exists := m.strictFileExists(fileSystem, c.fullpath); exists {
- setPlaceholders(c, info)
+ setPlaceholders(c, info.IsDir())
return true, nil
}
}
@@ -465,7 +478,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
if largestInfo == nil {
return false, nil
}
- setPlaceholders(largest, largestInfo)
+ setPlaceholders(largest, largestInfo.IsDir())
return true, nil
case tryPolicySmallestSize:
@@ -486,7 +499,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
if smallestInfo == nil {
return false, nil
}
- setPlaceholders(smallest, smallestInfo)
+ setPlaceholders(smallest, smallestInfo.IsDir())
return true, nil
case tryPolicyMostRecentlyMod:
@@ -506,7 +519,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
if recentInfo == nil {
return false, nil
}
- setPlaceholders(recent, recentInfo)
+ setPlaceholders(recent, recentInfo.IsDir())
return true, nil
}
@@ -708,10 +721,11 @@ var globSafeRepl = strings.NewReplacer(
)
const (
- tryPolicyFirstExist = "first_exist"
- tryPolicyLargestSize = "largest_size"
- tryPolicySmallestSize = "smallest_size"
- tryPolicyMostRecentlyMod = "most_recently_modified"
+ tryPolicyFirstExist = "first_exist"
+ tryPolicyFirstExistFallback = "first_exist_fallback"
+ tryPolicyLargestSize = "largest_size"
+ tryPolicySmallestSize = "smallest_size"
+ tryPolicyMostRecentlyMod = "most_recently_modified"
)
// Interface guards
diff --git a/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go b/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
index e0a0dc5f2..6fe7df3fd 100644
--- a/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
@@ -18,6 +18,7 @@ import (
"encoding/json"
"net/http"
"strconv"
+ "strings"
"github.com/caddyserver/caddy/v2"
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -312,12 +313,18 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
if indexFile != "off" {
dirRedir := false
dirIndex := "{http.request.uri.path}/" + indexFile
+ tryPolicy := "first_exist_fallback"
// if tryFiles wasn't overridden, use a reasonable default
if len(tryFiles) == 0 {
tryFiles = []string{"{http.request.uri.path}", dirIndex, indexFile}
dirRedir = true
} else {
+ if !strings.HasSuffix(tryFiles[len(tryFiles)-1], ".php") {
+ // use first_exist strategy if the last file is not a PHP file
+ tryPolicy = ""
+ }
+
for _, tf := range tryFiles {
if tf == dirIndex {
dirRedir = true
@@ -357,6 +364,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
rewriteMatcherSet := caddy.ModuleMap{
"file": h.JSON(fileserver.MatchFile{
TryFiles: tryFiles,
+ TryPolicy: tryPolicy,
SplitPath: extensions,
}),
}