From d8f22700e6ef11c15abdb674429aab3c01bb164b Mon Sep 17 00:00:00 2001 From: Aziz Rmadi Date: Sat, 2 Dec 2023 20:04:02 -0600 Subject: [PATCH 1/3] 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) } } From 4f0b4eab94c93bb20779836b6a5fbc14a2d36f28 Mon Sep 17 00:00:00 2001 From: armadi1809 Date: Thu, 7 Dec 2023 22:43:44 -0600 Subject: [PATCH 2/3] Added tests to the handle_error directive --- caddyconfig/httpcaddyfile/builtins.go | 8 +- caddyconfig/httpcaddyfile/httptype.go | 3 + .../caddyfile_adapt/error_range_codes.txt | 113 +++++++++++++ .../error_range_simple_codes.txt | 156 +++++++++++++++++ .../caddyfile_adapt/error_simple_codes.txt | 113 +++++++++++++ .../caddyfile_adapt/error_sort.txt | 158 ++++++++++++++++++ caddytest/integration/caddyfile_test.go | 88 ++++++++++ 7 files changed, 634 insertions(+), 5 deletions(-) create mode 100644 caddytest/integration/caddyfile_adapt/error_range_codes.txt create mode 100644 caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt create mode 100644 caddytest/integration/caddyfile_adapt/error_simple_codes.txt create mode 100644 caddytest/integration/caddyfile_adapt/error_sort.txt diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 7d86c52cdd7..2f44862dcf9 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -844,7 +844,6 @@ func parseHandle(h Helper) (caddyhttp.MiddlewareHandler, error) { } func parseHandleErrors(h Helper) ([]ConfigValue, error) { - h.Next() args := h.RemainingArgs() expression := "" @@ -865,17 +864,16 @@ func parseHandleErrors(h Helper) ([]ConfigValue, error) { if len(codes) > 0 { if expression != "" { expression += " || " - } else { - expression += "{http.error.status_code} in [" + strings.Join(codes, ", ") + "]" } + expression += "{http.error.status_code} in [" + strings.Join(codes, ", ") + "]" } - //Reset cursor position to get ready for ParseSegmentAsSubroute + // 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 + // If no arguments present reset the cursor position to get ready for ParseSegmentAsSubroute h.Prev() } diff --git a/caddyconfig/httpcaddyfile/httptype.go b/caddyconfig/httpcaddyfile/httptype.go index 447e28a9d8e..fe7df194c0b 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -785,6 +785,9 @@ func (st *ServerType) serversFromPairings( sr := val.Value.(*caddyhttp.Subroute) routeMatcherSet := sr.Routes[0].MatcherSetsRaw sr.Routes[0].MatcherSetsRaw = []caddy.ModuleMap{} + if routeMatcherSet == nil { + routeMatcherSet = matcherSetsEnc + } srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, routeMatcherSet, p, warnings) } } diff --git a/caddytest/integration/caddyfile_adapt/error_range_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_codes.txt new file mode 100644 index 00000000000..447824d0942 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/error_range_codes.txt @@ -0,0 +1,113 @@ +{ + http_port 3010 +} +localhost:3010 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } +} +---------- +{ + "apps": { + "http": { + "http_port": 3010, + "servers": { + "srv0": { + "listen": [ + ":3010" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Not found", + "handler": "error", + "status_code": 404 + } + ], + "match": [ + { + "path": [ + "/hidden*" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ], + "errors": { + "routes": [ + { + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Error in the [400 .. 499] range", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt new file mode 100644 index 00000000000..4649671a961 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt @@ -0,0 +1,156 @@ +{ + http_port 2099 +} +localhost:2099 { + root * /srv + error /private* "Unauthorized" 410 + error /threehundred* "Moved Permanently" 301 + error /internalerr* "Internal Server Error" 500 + + handle_errors 500 3xx { + respond "Error code is equal to 500 or in the [300..399] range" + } + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } +} +---------- +{ + "apps": { + "http": { + "http_port": 2099, + "servers": { + "srv0": { + "listen": [ + ":2099" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Moved Permanently", + "handler": "error", + "status_code": 301 + } + ], + "match": [ + { + "path": [ + "/threehundred*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Internal Server Error", + "handler": "error", + "status_code": 500 + } + ], + "match": [ + { + "path": [ + "/internalerr*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ], + "errors": { + "routes": [ + { + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Error in the [400 .. 499] range", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + }, + { + "match": [ + { + "expression": "{http.error.status_code} \u003e= 300 \u0026\u0026 {http.error.status_code} \u003c= 399 || {http.error.status_code} in [500]" + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Error code is equal to 500 or in the [300..399] range", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/error_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_simple_codes.txt new file mode 100644 index 00000000000..dccc35a602e --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/error_simple_codes.txt @@ -0,0 +1,113 @@ +{ + http_port 3010 +} +localhost:3010 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + + handle_errors 404 410 { + respond "404 or 410 error" + } +} +---------- +{ + "apps": { + "http": { + "http_port": 3010, + "servers": { + "srv0": { + "listen": [ + ":3010" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Not found", + "handler": "error", + "status_code": 404 + } + ], + "match": [ + { + "path": [ + "/hidden*" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ], + "errors": { + "routes": [ + { + "match": [ + { + "expression": "{http.error.status_code} in [404, 410]" + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "404 or 410 error", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/error_sort.txt b/caddytest/integration/caddyfile_adapt/error_sort.txt new file mode 100644 index 00000000000..578c8582802 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/error_sort.txt @@ -0,0 +1,158 @@ +{ + http_port 2099 +} +localhost:2099 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + error /internalerr* "Internal Server Error" 500 + + handle_errors { + respond "Fallback route: code outside the [400..499] range" + } + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } +} +---------- +{ + "apps": { + "http": { + "http_port": 2099, + "servers": { + "srv0": { + "listen": [ + ":2099" + ], + "routes": [ + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Internal Server Error", + "handler": "error", + "status_code": 500 + } + ], + "match": [ + { + "path": [ + "/internalerr*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Not found", + "handler": "error", + "status_code": 404 + } + ], + "match": [ + { + "path": [ + "/hidden*" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ], + "errors": { + "routes": [ + { + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Error in the [400 .. 499] range", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + }, + { + "match": [ + { + "host": [ + "localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "Fallback route: code outside the [400..499] range", + "handler": "static_response" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } + } +} diff --git a/caddytest/integration/caddyfile_test.go b/caddytest/integration/caddyfile_test.go index 0db7e794787..f9a98fb3855 100644 --- a/caddytest/integration/caddyfile_test.go +++ b/caddytest/integration/caddyfile_test.go @@ -496,3 +496,91 @@ func TestUriReplace(t *testing.T) { tester.AssertGetResponse("http://localhost:9080/endpoint?test={%20content%20}", 200, "test=%7B%20content%20%7D") } +func TestHandleErrorSimpleCodes(t *testing.T) { + tester := caddytest.NewTester(t) + tester.InitServer(`{ + admin localhost:2999 + http_port 9080 + } + localhost:9080 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + + handle_errors 404 410 { + respond "404 or 410 error" + } + }`, "caddyfile") + // act and assert + tester.AssertGetResponse("http://localhost:9080/private", 410, "404 or 410 error") + tester.AssertGetResponse("http://localhost:9080/hidden", 404, "404 or 410 error") +} + +func TestHandleErrorRange(t *testing.T) { + tester := caddytest.NewTester(t) + tester.InitServer(`{ + admin localhost:2999 + http_port 9080 + } + localhost:9080 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } + }`, "caddyfile") + // act and assert + tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range") + tester.AssertGetResponse("http://localhost:9080/hidden", 404, "Error in the [400 .. 499] range") +} + +func TestHandleErrorSort(t *testing.T) { + tester := caddytest.NewTester(t) + tester.InitServer(`{ + admin localhost:2999 + http_port 9080 + } + localhost:9080 { + root * /srv + error /private* "Unauthorized" 410 + error /hidden* "Not found" 404 + error /internalerr* "Internal Server Error" 500 + + handle_errors { + respond "Fallback route: code outside the [400..499] range" + } + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } + }`, "caddyfile") + // act and assert + tester.AssertGetResponse("http://localhost:9080/internalerr", 500, "Fallback route: code outside the [400..499] range") + tester.AssertGetResponse("http://localhost:9080/hidden", 404, "Error in the [400 .. 499] range") +} + +func TestHandleErrorRangeAndCodes(t *testing.T) { + tester := caddytest.NewTester(t) + tester.InitServer(`{ + admin localhost:2999 + http_port 9080 + } + localhost:9080 { + root * /srv + error /private* "Unauthorized" 410 + error /threehundred* "Moved Permanently" 301 + error /internalerr* "Internal Server Error" 500 + + handle_errors 500 3xx { + respond "Error code is equal to 500 or in the [300..399] range" + } + handle_errors 4xx { + respond "Error in the [400 .. 499] range" + } + }`, "caddyfile") + // act and assert + tester.AssertGetResponse("http://localhost:9080/internalerr", 500, "Error code is equal to 500 or in the [300..399] range") + tester.AssertGetResponse("http://localhost:9080/threehundred", 301, "Error code is equal to 500 or in the [300..399] range") + tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range") +} From b46f7e89c52b2009c3763e912904aa3ce42e39d6 Mon Sep 17 00:00:00 2001 From: armadi1809 Date: Sun, 10 Dec 2023 20:57:21 -0600 Subject: [PATCH 3/3] Included host matchers for error routes --- caddyconfig/httpcaddyfile/builtins.go | 15 +- caddyconfig/httpcaddyfile/directives.go | 1 - caddyconfig/httpcaddyfile/httptype.go | 9 +- .../error_multi_site_blocks.txt | 245 ++++++++++++++++++ .../caddyfile_adapt/error_range_codes.txt | 9 +- .../error_range_simple_codes.txt | 31 +-- .../caddyfile_adapt/error_simple_codes.txt | 9 +- .../caddyfile_adapt/error_sort.txt | 28 +- 8 files changed, 300 insertions(+), 47 deletions(-) create mode 100644 caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt diff --git a/caddyconfig/httpcaddyfile/builtins.go b/caddyconfig/httpcaddyfile/builtins.go index 2f44862dcf9..bf95a361698 100644 --- a/caddyconfig/httpcaddyfile/builtins.go +++ b/caddyconfig/httpcaddyfile/builtins.go @@ -851,15 +851,26 @@ func parseHandleErrors(h Helper) ([]ConfigValue, error) { expression = "" codes := []string{} for _, val := range args { + if len(val) != 3 { + return nil, h.Errf("bad status value '%s'", val) + } if strings.HasSuffix(val, "xx") { val = val[:1] + _, err := strconv.Atoi(val) + if err != nil { + return nil, h.Errf("bad status value '%s': %v", val, err) + } if expression != "" { expression += " || " } expression += fmt.Sprintf("{http.error.status_code} >= %s00 && {http.error.status_code} <= %s99", val, val) - } else { - codes = append(codes, val) + continue + } + _, err := strconv.Atoi(val) + if err != nil { + return nil, h.Errf("bad status value '%s': %v", val, err) } + codes = append(codes, val) } if len(codes) > 0 { if expression != "" { diff --git a/caddyconfig/httpcaddyfile/directives.go b/caddyconfig/httpcaddyfile/directives.go index bf2cdeae689..58da2bd791c 100644 --- a/caddyconfig/httpcaddyfile/directives.go +++ b/caddyconfig/httpcaddyfile/directives.go @@ -70,7 +70,6 @@ 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 fe7df194c0b..066df3014f7 100644 --- a/caddyconfig/httpcaddyfile/httptype.go +++ b/caddyconfig/httpcaddyfile/httptype.go @@ -781,15 +781,12 @@ func (st *ServerType) serversFromPairings( } return true }) + errorsSubroute := &caddyhttp.Subroute{} for _, val := range errorSubrouteVals { sr := val.Value.(*caddyhttp.Subroute) - routeMatcherSet := sr.Routes[0].MatcherSetsRaw - sr.Routes[0].MatcherSetsRaw = []caddy.ModuleMap{} - if routeMatcherSet == nil { - routeMatcherSet = matcherSetsEnc - } - srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, sr, routeMatcherSet, p, warnings) + errorsSubroute.Routes = append(errorsSubroute.Routes, sr.Routes...) } + srv.Errors.Routes = appendSubrouteToRouteList(srv.Errors.Routes, errorsSubroute, matcherSetsEnc, p, warnings) } // add log associations diff --git a/caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt b/caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt new file mode 100644 index 00000000000..0e84a13c2d3 --- /dev/null +++ b/caddytest/integration/caddyfile_adapt/error_multi_site_blocks.txt @@ -0,0 +1,245 @@ +foo.localhost { + root * /srv + error /private* "Unauthorized" 410 + error /fivehundred* "Internal Server Error" 500 + + handle_errors 5xx { + respond "Error In range [500 .. 599]" + } + handle_errors 410 { + respond "404 or 410 error" + } +} + +bar.localhost { + root * /srv + error /private* "Unauthorized" 410 + error /fivehundred* "Internal Server Error" 500 + + handle_errors 5xx { + respond "Error In range [500 .. 599] from second site" + } + handle_errors 410 { + respond "404 or 410 error from second site" + } +} +---------- +{ + "apps": { + "http": { + "servers": { + "srv0": { + "listen": [ + ":443" + ], + "routes": [ + { + "match": [ + { + "host": [ + "foo.localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Internal Server Error", + "handler": "error", + "status_code": 500 + } + ], + "match": [ + { + "path": [ + "/fivehundred*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + } + ] + } + ], + "terminal": true + }, + { + "match": [ + { + "host": [ + "bar.localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "handler": "vars", + "root": "/srv" + } + ] + }, + { + "handle": [ + { + "error": "Internal Server Error", + "handler": "error", + "status_code": 500 + } + ], + "match": [ + { + "path": [ + "/fivehundred*" + ] + } + ] + }, + { + "handle": [ + { + "error": "Unauthorized", + "handler": "error", + "status_code": 410 + } + ], + "match": [ + { + "path": [ + "/private*" + ] + } + ] + } + ] + } + ], + "terminal": true + } + ], + "errors": { + "routes": [ + { + "match": [ + { + "host": [ + "foo.localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "404 or 410 error", + "handler": "static_response" + } + ], + "match": [ + { + "expression": "{http.error.status_code} in [410]" + } + ] + }, + { + "handle": [ + { + "body": "Error In range [500 .. 599]", + "handler": "static_response" + } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 500 \u0026\u0026 {http.error.status_code} \u003c= 599" + } + ] + } + ] + } + ], + "terminal": true + }, + { + "match": [ + { + "host": [ + "bar.localhost" + ] + } + ], + "handle": [ + { + "handler": "subroute", + "routes": [ + { + "handle": [ + { + "body": "404 or 410 error from second site", + "handler": "static_response" + } + ], + "match": [ + { + "expression": "{http.error.status_code} in [410]" + } + ] + }, + { + "handle": [ + { + "body": "Error In range [500 .. 599] from second site", + "handler": "static_response" + } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 500 \u0026\u0026 {http.error.status_code} \u003c= 599" + } + ] + } + ] + } + ], + "terminal": true + } + ] + } + } + } + } + } +} diff --git a/caddytest/integration/caddyfile_adapt/error_range_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_codes.txt index 447824d0942..46b70c8e384 100644 --- a/caddytest/integration/caddyfile_adapt/error_range_codes.txt +++ b/caddytest/integration/caddyfile_adapt/error_range_codes.txt @@ -84,7 +84,9 @@ localhost:3010 { { "match": [ { - "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + "host": [ + "localhost" + ] } ], "handle": [ @@ -97,6 +99,11 @@ localhost:3010 { "body": "Error in the [400 .. 499] range", "handler": "static_response" } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } ] } ] diff --git a/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt index 4649671a961..70158830c26 100644 --- a/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt +++ b/caddytest/integration/caddyfile_adapt/error_range_simple_codes.txt @@ -104,7 +104,9 @@ localhost:2099 { { "match": [ { - "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + "host": [ + "localhost" + ] } ], "handle": [ @@ -117,29 +119,24 @@ localhost:2099 { "body": "Error in the [400 .. 499] range", "handler": "static_response" } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } ] - } - ] - } - ], - "terminal": true - }, - { - "match": [ - { - "expression": "{http.error.status_code} \u003e= 300 \u0026\u0026 {http.error.status_code} \u003c= 399 || {http.error.status_code} in [500]" - } - ], - "handle": [ - { - "handler": "subroute", - "routes": [ + }, { "handle": [ { "body": "Error code is equal to 500 or in the [300..399] range", "handler": "static_response" } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 300 \u0026\u0026 {http.error.status_code} \u003c= 399 || {http.error.status_code} in [500]" + } ] } ] diff --git a/caddytest/integration/caddyfile_adapt/error_simple_codes.txt b/caddytest/integration/caddyfile_adapt/error_simple_codes.txt index dccc35a602e..5ac5863e32d 100644 --- a/caddytest/integration/caddyfile_adapt/error_simple_codes.txt +++ b/caddytest/integration/caddyfile_adapt/error_simple_codes.txt @@ -84,7 +84,9 @@ localhost:3010 { { "match": [ { - "expression": "{http.error.status_code} in [404, 410]" + "host": [ + "localhost" + ] } ], "handle": [ @@ -97,6 +99,11 @@ localhost:3010 { "body": "404 or 410 error", "handler": "static_response" } + ], + "match": [ + { + "expression": "{http.error.status_code} in [404, 410]" + } ] } ] diff --git a/caddytest/integration/caddyfile_adapt/error_sort.txt b/caddytest/integration/caddyfile_adapt/error_sort.txt index 578c8582802..63701cccba9 100644 --- a/caddytest/integration/caddyfile_adapt/error_sort.txt +++ b/caddytest/integration/caddyfile_adapt/error_sort.txt @@ -104,7 +104,9 @@ localhost:2099 { { "match": [ { - "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + "host": [ + "localhost" + ] } ], "handle": [ @@ -117,25 +119,13 @@ localhost:2099 { "body": "Error in the [400 .. 499] range", "handler": "static_response" } + ], + "match": [ + { + "expression": "{http.error.status_code} \u003e= 400 \u0026\u0026 {http.error.status_code} \u003c= 499" + } ] - } - ] - } - ], - "terminal": true - }, - { - "match": [ - { - "host": [ - "localhost" - ] - } - ], - "handle": [ - { - "handler": "subroute", - "routes": [ + }, { "handle": [ {