httpcaddyfile: Prevent error handler from overriding sub-handler matchers (#6999)

Fixes: #6957
pull/6772/head^2
Youness Farini 2025-06-06 18:46:39 +01:00 committed by GitHub
parent 7099892958
commit 092913a7a5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 440 additions and 35 deletions

View File

@ -15,6 +15,7 @@
package httpcaddyfile
import (
"encoding/json"
"fmt"
"html"
"net/http"
@ -843,13 +844,18 @@ func parseHandleErrors(h Helper) ([]ConfigValue, error) {
return nil, h.Errf("segment was not parsed as a subroute")
}
// wrap the subroutes
wrappingRoute := caddyhttp.Route{
HandlersRaw: []json.RawMessage{caddyconfig.JSONModuleObject(subroute, "handler", "subroute", nil)},
}
subroute = &caddyhttp.Subroute{
Routes: []caddyhttp.Route{wrappingRoute},
}
if expression != "" {
statusMatcher := caddy.ModuleMap{
"expression": h.JSON(caddyhttp.MatchExpression{Expr: expression}),
}
for i := range subroute.Routes {
subroute.Routes[i].MatcherSetsRaw = []caddy.ModuleMap{statusMatcher}
}
subroute.Routes[0].MatcherSetsRaw = []caddy.ModuleMap{statusMatcher}
}
return []ConfigValue{
{

View File

@ -101,6 +101,11 @@ example.com {
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
@ -126,6 +131,10 @@ example.com {
}
]
}
]
}
]
}
],
"terminal": true
}

View File

@ -159,6 +159,11 @@ bar.localhost {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -168,6 +173,10 @@ bar.localhost {
"body": "404 or 410 error",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
@ -175,12 +184,21 @@ bar.localhost {
}
]
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "Error In range [500 .. 599]",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
@ -202,6 +220,11 @@ bar.localhost {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -211,6 +234,10 @@ bar.localhost {
"body": "404 or 410 error from second site",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
@ -218,12 +245,21 @@ bar.localhost {
}
]
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "Error In range [500 .. 599] from second site",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{

View File

@ -90,6 +90,11 @@ localhost:3010 {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -99,6 +104,10 @@ localhost:3010 {
"body": "Error in the [400 .. 499] range",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{

View File

@ -110,6 +110,11 @@ localhost:2099 {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -119,6 +124,10 @@ localhost:2099 {
"body": "Error in the [400 .. 499] range",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
@ -126,12 +135,21 @@ localhost:2099 {
}
]
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "Error code is equal to 500 or in the [300..399] range",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{

View File

@ -90,6 +90,11 @@ localhost:3010 {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -99,6 +104,10 @@ localhost:3010 {
"body": "404 or 410 error",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{

View File

@ -110,6 +110,11 @@ localhost:2099 {
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
@ -119,6 +124,10 @@ localhost:2099 {
"body": "Error in the [400 .. 499] range",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
@ -126,6 +135,11 @@ localhost:2099 {
}
]
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
@ -136,6 +150,10 @@ localhost:2099 {
}
]
}
]
}
]
}
],
"terminal": true
}

View File

@ -0,0 +1,260 @@
{
http_port 2099
}
localhost:2099 {
root * /var/www/
file_server
handle_errors 404 {
handle /en/* {
respond "not found" 404
}
handle /es/* {
respond "no encontrado"
}
handle {
respond "default not found"
}
}
handle_errors {
handle /en/* {
respond "English error"
}
handle /es/* {
respond "Spanish error"
}
handle {
respond "Default error"
}
}
}
----------
{
"apps": {
"http": {
"http_port": 2099,
"servers": {
"srv0": {
"listen": [
":2099"
],
"routes": [
{
"match": [
{
"host": [
"localhost"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "vars",
"root": "/var/www/"
},
{
"handler": "file_server",
"hide": [
"./Caddyfile"
]
}
]
}
]
}
],
"terminal": true
}
],
"errors": {
"routes": [
{
"match": [
{
"host": [
"localhost"
]
}
],
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"group": "group3",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "not found",
"handler": "static_response",
"status_code": 404
}
]
}
]
}
],
"match": [
{
"path": [
"/en/*"
]
}
]
},
{
"group": "group3",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "no encontrado",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
"path": [
"/es/*"
]
}
]
},
{
"group": "group3",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "default not found",
"handler": "static_response"
}
]
}
]
}
]
}
]
}
],
"match": [
{
"expression": "{http.error.status_code} in [404]"
}
]
},
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"group": "group8",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "English error",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
"path": [
"/en/*"
]
}
]
},
{
"group": "group8",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "Spanish error",
"handler": "static_response"
}
]
}
]
}
],
"match": [
{
"path": [
"/es/*"
]
}
]
},
{
"group": "group8",
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"body": "Default error",
"handler": "static_response"
}
]
}
]
}
]
}
]
}
]
}
]
}
],
"terminal": true
}
]
}
}
}
}
}
}

View File

@ -782,6 +782,46 @@ func TestHandleErrorRangeAndCodes(t *testing.T) {
tester.AssertGetResponse("http://localhost:9080/private", 410, "Error in the [400 .. 499] range")
}
func TestHandleErrorSubHandlers(t *testing.T) {
tester := caddytest.NewTester(t)
tester.InitServer(`{
admin localhost:2999
http_port 9080
}
localhost:9080 {
root * /srv
file_server
error /*/internalerr* "Internal Server Error" 500
handle_errors 404 {
handle /en/* {
respond "not found" 404
}
handle /es/* {
respond "no encontrado" 404
}
handle {
respond "default not found"
}
}
handle_errors {
handle {
respond "Default error"
}
handle /en/* {
respond "English error"
}
}
}
`, "caddyfile")
// act and assert
tester.AssertGetResponse("http://localhost:9080/en/notfound", 404, "not found")
tester.AssertGetResponse("http://localhost:9080/es/notfound", 404, "no encontrado")
tester.AssertGetResponse("http://localhost:9080/notfound", 404, "default not found")
tester.AssertGetResponse("http://localhost:9080/es/internalerr", 500, "Default error")
tester.AssertGetResponse("http://localhost:9080/en/internalerr", 500, "English error")
}
func TestInvalidSiteAddressesAsDirectives(t *testing.T) {
type testCase struct {
config, expectedError string