@@ -90,6 +90,7 @@ type MatchFile struct {
90
90
// How to choose a file in TryFiles. Can be:
91
91
//
92
92
// - first_exist
93
+ // - first_exist_fallback
93
94
// - smallest_size
94
95
// - largest_size
95
96
// - most_recently_modified
@@ -415,22 +416,27 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
415
416
}
416
417
417
418
// setPlaceholders creates the placeholders for the matched file
418
- setPlaceholders := func (candidate matchCandidate , info fs. FileInfo ) {
419
+ setPlaceholders := func (candidate matchCandidate , isDir bool ) {
419
420
repl .Set ("http.matchers.file.relative" , filepath .ToSlash (candidate .relative ))
420
421
repl .Set ("http.matchers.file.absolute" , filepath .ToSlash (candidate .fullpath ))
421
422
repl .Set ("http.matchers.file.remainder" , filepath .ToSlash (candidate .splitRemainder ))
422
423
423
424
fileType := "file"
424
- if info . IsDir () {
425
+ if isDir {
425
426
fileType = "directory"
426
427
}
427
428
repl .Set ("http.matchers.file.type" , fileType )
428
429
}
429
430
430
431
// match file according to the configured policy
431
432
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 {
434
440
// If the pattern is a status code, emit an error,
435
441
// which short-circuits the middleware pipeline and
436
442
// writes an HTTP error response.
@@ -440,8 +446,15 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
440
446
441
447
candidates := makeCandidates (pattern )
442
448
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
+
443
456
if info , exists := m .strictFileExists (fileSystem , c .fullpath ); exists {
444
- setPlaceholders (c , info )
457
+ setPlaceholders (c , info . IsDir () )
445
458
return true , nil
446
459
}
447
460
}
@@ -465,7 +478,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
465
478
if largestInfo == nil {
466
479
return false , nil
467
480
}
468
- setPlaceholders (largest , largestInfo )
481
+ setPlaceholders (largest , largestInfo . IsDir () )
469
482
return true , nil
470
483
471
484
case tryPolicySmallestSize :
@@ -486,7 +499,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
486
499
if smallestInfo == nil {
487
500
return false , nil
488
501
}
489
- setPlaceholders (smallest , smallestInfo )
502
+ setPlaceholders (smallest , smallestInfo . IsDir () )
490
503
return true , nil
491
504
492
505
case tryPolicyMostRecentlyMod :
@@ -506,7 +519,7 @@ func (m MatchFile) selectFile(r *http.Request) (bool, error) {
506
519
if recentInfo == nil {
507
520
return false , nil
508
521
}
509
- setPlaceholders (recent , recentInfo )
522
+ setPlaceholders (recent , recentInfo . IsDir () )
510
523
return true , nil
511
524
}
512
525
@@ -708,10 +721,11 @@ var globSafeRepl = strings.NewReplacer(
708
721
)
709
722
710
723
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"
715
729
)
716
730
717
731
// Interface guards
0 commit comments