diff options
author | Matt Holt <[email protected]> | 2024-12-20 10:55:02 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-20 10:55:02 -0700 |
commit | 86da4e8f56f3518bc053dd4f68a78c538a4aab5f (patch) | |
tree | baaf259e90a81d56bf8a2999809d396a02fe1ea9 /modules/caddyhttp/fileserver/matcher.go | |
parent | 130c868e95dfd1a8b1d39fd217bc6378f6b72ec0 (diff) | |
parent | ed1c594cdbddf89829eaf1174f414028577b432d (diff) | |
download | caddy-86da4e8f56f3518bc053dd4f68a78c538a4aab5f.tar.gz caddy-86da4e8f56f3518bc053dd4f68a78c538a4aab5f.zip |
Merge branch 'master' into transfer-encoding-matchtransfer-encoding-match
Diffstat (limited to 'modules/caddyhttp/fileserver/matcher.go')
-rw-r--r-- | modules/caddyhttp/fileserver/matcher.go | 86 |
1 files changed, 57 insertions, 29 deletions
diff --git a/modules/caddyhttp/fileserver/matcher.go b/modules/caddyhttp/fileserver/matcher.go index 71de1db29..2bc665d4f 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 @@ -173,7 +174,7 @@ func (m *MatchFile) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { func (MatchFile) CELLibrary(ctx caddy.Context) (cel.Library, error) { requestType := cel.ObjectType("http.Request") - matcherFactory := func(data ref.Val) (caddyhttp.RequestMatcher, error) { + matcherFactory := func(data ref.Val) (caddyhttp.RequestMatcherWithError, error) { values, err := caddyhttp.CELValueToMapStrList(data) if err != nil { return nil, err @@ -191,7 +192,7 @@ func (MatchFile) CELLibrary(ctx caddy.Context) (cel.Library, error) { var try_policy string if len(values["try_policy"]) > 0 { - root = values["try_policy"][0] + try_policy = values["try_policy"][0] } m := MatchFile{ @@ -296,6 +297,7 @@ func (m MatchFile) Validate() error { switch m.TryPolicy { case "", tryPolicyFirstExist, + tryPolicyFirstExistFallback, tryPolicyLargestSize, tryPolicySmallestSize, tryPolicyMostRecentlyMod: @@ -313,12 +315,22 @@ func (m MatchFile) Validate() error { // - http.matchers.file.type: file or directory // - http.matchers.file.remainder: Portion remaining after splitting file path (if configured) func (m MatchFile) Match(r *http.Request) bool { + match, err := m.selectFile(r) + if err != nil { + // nolint:staticcheck + caddyhttp.SetVar(r.Context(), caddyhttp.MatcherErrorVarKey, err) + } + return match +} + +// MatchWithError returns true if r matches m. +func (m MatchFile) MatchWithError(r *http.Request) (bool, error) { return m.selectFile(r) } // selectFile chooses a file according to m.TryPolicy by appending // the paths in m.TryFiles to m.Root, with placeholder replacements. -func (m MatchFile) selectFile(r *http.Request) (matched bool) { +func (m MatchFile) selectFile(r *http.Request) (bool, error) { repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) root := filepath.Clean(repl.ReplaceAll(m.Root, ".")) @@ -330,7 +342,7 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { if c := m.logger.Check(zapcore.ErrorLevel, "use of unregistered filesystem"); c != nil { c.Write(zap.String("fs", fsName)) } - return false + return false, nil } type matchCandidate struct { fullpath, relative, splitRemainder string @@ -405,13 +417,13 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { } // 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) @@ -419,17 +431,32 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { // 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. if err := parseErrorCode(pattern); err != nil { - caddyhttp.SetVar(r.Context(), caddyhttp.MatcherErrorVarKey, err) - return + return false, err } + 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) - return true + setPlaceholders(c, info.IsDir()) + return true, nil } } } @@ -450,10 +477,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { } } if largestInfo == nil { - return false + return false, nil } - setPlaceholders(largest, largestInfo) - return true + setPlaceholders(largest, largestInfo.IsDir()) + return true, nil case tryPolicySmallestSize: var smallestSize int64 @@ -471,10 +498,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { } } if smallestInfo == nil { - return false + return false, nil } - setPlaceholders(smallest, smallestInfo) - return true + setPlaceholders(smallest, smallestInfo.IsDir()) + return true, nil case tryPolicyMostRecentlyMod: var recent matchCandidate @@ -491,13 +518,13 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) { } } if recentInfo == nil { - return false + return false, nil } - setPlaceholders(recent, recentInfo) - return true + setPlaceholders(recent, recentInfo.IsDir()) + return true, nil } - return + return false, nil } // parseErrorCode checks if the input is a status @@ -695,15 +722,16 @@ 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 var ( - _ caddy.Validator = (*MatchFile)(nil) - _ caddyhttp.RequestMatcher = (*MatchFile)(nil) - _ caddyhttp.CELLibraryProducer = (*MatchFile)(nil) + _ caddy.Validator = (*MatchFile)(nil) + _ caddyhttp.RequestMatcherWithError = (*MatchFile)(nil) + _ caddyhttp.CELLibraryProducer = (*MatchFile)(nil) ) |