Skip to content

Commit efd9251

Browse files
authored
fileserver: Add first_exist_fallback strategy for try_files (#6699)
* feat: add first_exist_or_fallback strategy for try_files * fix tests * linter
1 parent b116dce commit efd9251

File tree

7 files changed

+40
-14
lines changed

7 files changed

+40
-14
lines changed

Diff for: caddytest/integration/caddyfile_adapt/php_fastcgi_handle_response.caddyfiletest

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"{http.request.uri.path}/index.php",
5959
"index.php"
6060
],
61+
"try_policy": "first_exist_fallback",
6162
"split_path": [
6263
".php"
6364
]

Diff for: caddytest/integration/caddyfile_adapt/php_fastcgi_matcher.caddyfiletest

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ php_fastcgi @test localhost:9000
7373
"{http.request.uri.path}",
7474
"{http.request.uri.path}/index.php",
7575
"index.php"
76-
]
76+
],
77+
"try_policy": "first_exist_fallback"
7778
}
7879
}
7980
]

Diff for: caddytest/integration/caddyfile_adapt/php_fastcgi_subdirectives.caddyfiletest

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ php_fastcgi localhost:9000 {
5959
"{http.request.uri.path}/index.php5",
6060
"index.php5"
6161
],
62+
"try_policy": "first_exist_fallback",
6263
"split_path": [
6364
".php",
6465
".php5"

Diff for: caddytest/integration/caddyfile_adapt/php_fastcgi_try_files_override_no_dir_index.caddyfiletest

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ php_fastcgi localhost:9000 {
3232
"{http.request.uri.path}",
3333
"index.php"
3434
],
35+
"try_policy": "first_exist_fallback",
3536
"split_path": [
3637
".php",
3738
".php5"

Diff for: modules/caddyhttp/fileserver/caddyfile.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ func parseTryFiles(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error)
274274
tryPolicy = h.Val()
275275

276276
switch tryPolicy {
277-
case tryPolicyFirstExist, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
277+
case tryPolicyFirstExist, tryPolicyFirstExistFallback, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod:
278278
default:
279279
return nil, h.Errf("unrecognized try policy: %s", tryPolicy)
280280
}

Diff for: modules/caddyhttp/fileserver/matcher.go

+26-12
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ type MatchFile struct {
9090
// How to choose a file in TryFiles. Can be:
9191
//
9292
// - first_exist
93+
// - first_exist_fallback
9394
// - smallest_size
9495
// - largest_size
9596
// - most_recently_modified
@@ -415,22 +416,27 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
415416
}
416417

417418
// setPlaceholders creates the placeholders for the matched file
418-
setPlaceholders := func(candidate matchCandidate, info fs.FileInfo) {
419+
setPlaceholders := func(candidate matchCandidate, isDir bool) {
419420
repl.Set("http.matchers.file.relative", filepath.ToSlash(candidate.relative))
420421
repl.Set("http.matchers.file.absolute", filepath.ToSlash(candidate.fullpath))
421422
repl.Set("http.matchers.file.remainder", filepath.ToSlash(candidate.splitRemainder))
422423

423424
fileType := "file"
424-
if info.IsDir() {
425+
if isDir {
425426
fileType = "directory"
426427
}
427428
repl.Set("http.matchers.file.type", fileType)
428429
}
429430

430431
// match file according to the configured policy
431432
switch m.TryPolicy {
432-
case "", tryPolicyFirstExist:
433-
for _, pattern := range m.TryFiles {
433+
case "", tryPolicyFirstExist, tryPolicyFirstExistFallback:
434+
maxI := -1
435+
if m.TryPolicy == tryPolicyFirstExistFallback {
436+
maxI = len(m.TryFiles) - 1
437+
}
438+
439+
for i, pattern := range m.TryFiles {
434440
// If the pattern is a status code, emit an error,
435441
// which short-circuits the middleware pipeline and
436442
// writes an HTTP error response.
@@ -440,8 +446,15 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
440446

441447
candidates := makeCandidates(pattern)
442448
for _, c := range candidates {
449+
// Skip the IO if using fallback policy and it's the latest item
450+
if i == maxI {
451+
setPlaceholders(c, false)
452+
453+
return true, nil
454+
}
455+
443456
if info, exists := m.strictFileExists(fileSystem, c.fullpath); exists {
444-
setPlaceholders(c, info)
457+
setPlaceholders(c, info.IsDir())
445458
return true, nil
446459
}
447460
}
@@ -465,7 +478,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
465478
if largestInfo == nil {
466479
return false, nil
467480
}
468-
setPlaceholders(largest, largestInfo)
481+
setPlaceholders(largest, largestInfo.IsDir())
469482
return true, nil
470483

471484
case tryPolicySmallestSize:
@@ -486,7 +499,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
486499
if smallestInfo == nil {
487500
return false, nil
488501
}
489-
setPlaceholders(smallest, smallestInfo)
502+
setPlaceholders(smallest, smallestInfo.IsDir())
490503
return true, nil
491504

492505
case tryPolicyMostRecentlyMod:
@@ -506,7 +519,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
506519
if recentInfo == nil {
507520
return false, nil
508521
}
509-
setPlaceholders(recent, recentInfo)
522+
setPlaceholders(recent, recentInfo.IsDir())
510523
return true, nil
511524
}
512525

@@ -708,10 +721,11 @@ var globSafeRepl = strings.NewReplacer(
708721
)
709722

710723
const (
711-
tryPolicyFirstExist = "first_exist"
712-
tryPolicyLargestSize = "largest_size"
713-
tryPolicySmallestSize = "smallest_size"
714-
tryPolicyMostRecentlyMod = "most_recently_modified"
724+
tryPolicyFirstExist = "first_exist"
725+
tryPolicyFirstExistFallback = "first_exist_fallback"
726+
tryPolicyLargestSize = "largest_size"
727+
tryPolicySmallestSize = "smallest_size"
728+
tryPolicyMostRecentlyMod = "most_recently_modified"
715729
)
716730

717731
// Interface guards

Diff for: modules/caddyhttp/reverseproxy/fastcgi/caddyfile.go

+8
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"encoding/json"
1919
"net/http"
2020
"strconv"
21+
"strings"
2122

2223
"github.com/caddyserver/caddy/v2"
2324
"github.com/caddyserver/caddy/v2/caddyconfig"
@@ -312,12 +313,18 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
312313
if indexFile != "off" {
313314
dirRedir := false
314315
dirIndex := "{http.request.uri.path}/" + indexFile
316+
tryPolicy := "first_exist_fallback"
315317

316318
// if tryFiles wasn't overridden, use a reasonable default
317319
if len(tryFiles) == 0 {
318320
tryFiles = []string{"{http.request.uri.path}", dirIndex, indexFile}
319321
dirRedir = true
320322
} else {
323+
if !strings.HasSuffix(tryFiles[len(tryFiles)-1], ".php") {
324+
// use first_exist strategy if the last file is not a PHP file
325+
tryPolicy = ""
326+
}
327+
321328
for _, tf := range tryFiles {
322329
if tf == dirIndex {
323330
dirRedir = true
@@ -357,6 +364,7 @@ func parsePHPFastCGI(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error
357364
rewriteMatcherSet := caddy.ModuleMap{
358365
"file": h.JSON(fileserver.MatchFile{
359366
TryFiles: tryFiles,
367+
TryPolicy: tryPolicy,
360368
SplitPath: extensions,
361369
}),
362370
}

0 commit comments

Comments
 (0)