mirror of
https://github.com/caddyserver/caddy.git
synced 2026-05-27 09:12:31 -04:00
caddyhttp: Add MatchWithError to replace SetVar hack (#6596)
* caddyhttp: Add `MatchWithError` to replace SetVar hack * Error in IP matchers on TLS handshake not complete * Use MatchWithError everywhere possible * Move implementations to MatchWithError versions * Looser interface checking to allow fallback * CEL factories can return RequestMatcherWithError * Clarifying comment since it's subtle that an err is returned * Return 425 Too Early status in IP matchers * Keep AnyMatch signature the same for now * Apparently Deprecated can't be all-uppercase to get IDE linting * Linter
This commit is contained in:
@@ -173,7 +173,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
|
||||
@@ -313,12 +313,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 +340,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
|
||||
@@ -421,15 +431,18 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
switch m.TryPolicy {
|
||||
case "", tryPolicyFirstExist:
|
||||
for _, 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 {
|
||||
if info, exists := m.strictFileExists(fileSystem, c.fullpath); exists {
|
||||
setPlaceholders(c, info)
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -450,10 +463,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
}
|
||||
}
|
||||
if largestInfo == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
setPlaceholders(largest, largestInfo)
|
||||
return true
|
||||
return true, nil
|
||||
|
||||
case tryPolicySmallestSize:
|
||||
var smallestSize int64
|
||||
@@ -471,10 +484,10 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
}
|
||||
}
|
||||
if smallestInfo == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
setPlaceholders(smallest, smallestInfo)
|
||||
return true
|
||||
return true, nil
|
||||
|
||||
case tryPolicyMostRecentlyMod:
|
||||
var recent matchCandidate
|
||||
@@ -491,13 +504,13 @@ func (m MatchFile) selectFile(r *http.Request) (matched bool) {
|
||||
}
|
||||
}
|
||||
if recentInfo == nil {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
setPlaceholders(recent, recentInfo)
|
||||
return true
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// parseErrorCode checks if the input is a status
|
||||
@@ -703,7 +716,7 @@ const (
|
||||
|
||||
// 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)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user