From d8f22700e6ef11c15abdb674429aab3c01bb164b Mon Sep 17 00:00:00 2001 From: Aziz Rmadi Date: Sat, 2 Dec 2023 20:04:02 -0600 Subject: [PATCH] added optional status code argument to handle_errors directive --- caddyconfig/httpcaddyfile/builtins.go | 50 ++++++++++++++++++++++++- caddyconfig/httpcaddyfile/directives.go | 1 + caddyconfig/httpcaddyfile/httptype.go | 11 +++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 3b56e0739a9..7d86c52cdd7 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -844,10 +844,58 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) { } func parseHandleErrors(h Helper) ([]ConfigValue, error) { - subroute, err := ParseSegmentAsSubroute(h) + + h.Next() + args := h.RemainingArgs() + expression := "" + if len(args) > 0 { + expression = "" + codes := []string{} + for _, val := range args { + if strings.HasSuffix(val, "xx") { + val = val[:1] + if expression != "" { + expression += " || " + } + expression += fmt.Sprintf("{http.error.status_code} >= %s00 && {http.error.status_code} <= %s99", val, val) + } else { + codes = append(codes, val) + } + } + if len(codes) > 0 { + if expression != "" { + expression += " || " + } else { + expression += "{http.error.status_code} in [" + strings.Join(codes, ", ") + "]" + } + } + //Reset cursor position to get ready for ParseSegmentAsSubroute + h.Reset() + h.Next() + h.RemainingArgs() + h.Prev() + } else { + //If no arguments present reset the cursor position to get ready for ParseSegmentAsSubroute + h.Prev() + } + + handler, err := ParseSegmentAsSubroute(h) if err != nil { return nil, err } + subroute, ok := handler.(*caddyhttp.Subroute) + if !ok { + return nil, h.Errf("segment was not parsed as a subroute") + } + + if expression != "" { + statusMatcher := caddy.ModuleMap{ + "expression": h.JSON(caddyhttp.MatchExpression{Expr: expression}), + } + for i := range subroute.Routes { + subroute.Routes[i].MatcherSetsRaw = []caddy.ModuleMap{statusMatcher} + } + } return []ConfigValue{ { Class: "error_route", diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index 58da2bd791c..bf2cdeae689 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -70,6 +70,7 @@ var directiveOrder = []string{ "handle", "handle_path", "route", + "handle_errors", // handlers that typically respond to requests "abort", diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index bc2b125ef1e..447e28a9d8e 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -774,9 +774,18 @@ func (st *ServerType) serversFromPairings( if srv.Errors == nil { srv.Errors = new(caddyhttp.HTTPErrorConfig) } + sort.SliceStable(errorSubrouteVals, func(i, j int) bool { + sri, srj := errorSubrouteVals[i].Value.(*caddyhttp.Subroute), errorSubrouteVals[j].Value.(*caddyhttp.Subroute) + if len(sri.Routes[0].MatcherSetsRaw) == 0 && len(srj.Routes[0].MatcherSetsRaw) != 0 { + return false + } + return true + }) for _, val := range errorSubrouteVals { sr := val.Value.(*caddyhttp.Subroute) - srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, matcherSetsEnc, p, warnings) + routeMatcherSet := sr.Routes[0].MatcherSetsRaw + sr.Routes[0].MatcherSetsRaw = []caddy.ModuleMap{} + srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, routeMatcherSet, p, warnings) } }