Skip to content

Commit

Permalink
feat: add first_exist_or_fallback strategy for try_files
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Nov 18, 2024
1 parent b3ce260 commit 381d5e8
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 13 deletions.
2 changes: 1 addition & 1 deletion modules/caddyhttp/fileserver/caddyfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
tryPolicy = h.Val()

switch tryPolicy {
case tryPolicyFirstExist, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
case tryPolicyFirstExist, tryPolicyFirstExistOrFallback, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
default:
return nil, h.Errf("unrecognized try policy: %s", tryPolicy)
}
Expand Down
37 changes: 25 additions & 12 deletions modules/caddyhttp/fileserver/matcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ type MatchFile struct {
// How to choose a file in TryFiles. Can be:
//
// - first_exist
// - first_exist_or_fallback
// - smallest_size
// - largest_size
// - most_recently_modified
Expand Down Expand Up @@ -415,22 +416,27 @@ 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)
}

// match file according to the configured policy
switch m.TryPolicy {
case "", tryPolicyFirstExist:
for _, pattern := range m.TryFiles {
case "", tryPolicyFirstExist, tryPolicyFirstExistOrFallback:
var maxI int
if m.TryPolicy == tryPolicyFirstExistOrFallback {
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.
Expand All @@ -440,8 +446,14 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {

candidates := makeCandidates(pattern)
for _, c := range candidates {
if m.TryPolicy == tryPolicyFirstExistOrFallback && 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
}
}
Expand All @@ -465,7 +477,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:
Expand All @@ -486,7 +498,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:
Expand All @@ -506,7 +518,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
}

Expand Down Expand Up @@ -708,10 +720,11 @@ var globSafeRepl = strings.NewReplacer(
)

const (
tryPolicyFirstExist = "first_exist"
tryPolicyLargestSize = "largest_size"
tryPolicySmallestSize = "smallest_size"
tryPolicyMostRecentlyMod = "most_recently_modified"
tryPolicyFirstExist = "first_exist"
tryPolicyFirstExistOrFallback = "first_exist_or_fallback"
tryPolicyLargestSize = "largest_size"
tryPolicySmallestSize = "smallest_size"
tryPolicyMostRecentlyMod = "most_recently_modified"
)

// Interface guards
Expand Down
1 change: 1 addition & 0 deletions modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
rewriteMatcherSet := caddy.ModuleMap{
"file": h.JSON(fileserver.MatchFile{
TryFiles: tryFiles,
TryPolicy: "first_exist_or_fallback",
SplitPath: extensions,
}),
}
Expand Down

0 comments on commit 381d5e8

Please sign in to comment.