Files
caddy/caddytest/integration/map_test.go
T
gelsomino 256df3c8ad map: reject malformed destination placeholders (#8074)
Provision previously only checked for a single opening brace at the
start of a destination, so values like {result}suffix, {result, and
{result}} passed validation. strings.Trim(dest, "{}") then silently
stored a wrong placeholder name (e.g. result}suffix), making the
intended value unavailable.

Require the destination to be exactly one placeholder: a single
opening brace at the start, a single closing brace at the end, and a
non-empty name.

Fixes #8073
2026-09-28 22:19:51 +10:00

197 lines
4.4 KiB
Go

package integration
import (
"bytes"
"testing"
"github.com/caddyserver/caddy/v2/caddytest"
)
func TestMap(t *testing.T) {
// arrange
tester := caddytest.NewTester(t)
tester.InitServer(`{
skip_install_trust
admin localhost:2999
http_port 9080
https_port 9443
grace_period 1ns
}
localhost:9080 {
map {http.request.method} {dest-1} {dest-2} {
default unknown1 unknown2
~G(.)(.) G${1}${2}-called
POST post-called foobar
}
respond /version 200 {
body "hello from localhost {dest-1} {dest-2}"
}
}
`, "caddyfile")
// act and assert
tester.AssertGetResponse("http://localhost:9080/version", 200, "hello from localhost GET-called unknown2")
tester.AssertPostResponseBody("http://localhost:9080/version", []string{}, bytes.NewBuffer([]byte{}), 200, "hello from localhost post-called foobar")
}
func TestMapRespondWithDefault(t *testing.T) {
// arrange
tester := caddytest.NewTester(t)
tester.InitServer(`{
skip_install_trust
admin localhost:2999
http_port 9080
https_port 9443
}
localhost:9080 {
map {http.request.method} {dest-name} {
default unknown
GET get-called
}
respond /version 200 {
body "hello from localhost {dest-name}"
}
}
`, "caddyfile")
// act and assert
tester.AssertGetResponse("http://localhost:9080/version", 200, "hello from localhost get-called")
tester.AssertPostResponseBody("http://localhost:9080/version", []string{}, bytes.NewBuffer([]byte{}), 200, "hello from localhost unknown")
}
func TestMapInvalidDestination(t *testing.T) {
// see https://github.com/caddyserver/caddy/issues/8073
failureCases := []struct {
name string
destination string
expectedError string
}{
{
name: "trailing text",
destination: "{dest-name}suffix",
expectedError: "destination 0 must be a placeholder and only a placeholder, but got '{dest-name}suffix'",
},
{
name: "missing closing brace",
destination: "{dest-name",
expectedError: "destination 0 must be a placeholder and only a placeholder, but got '{dest-name'",
},
{
name: "double closing brace",
destination: "{dest-name}}",
expectedError: "destination 0 must be a placeholder and only a placeholder, but got '{dest-name}}'",
},
}
for _, tc := range failureCases {
t.Run(tc.name, func(t *testing.T) {
caddytest.AssertLoadError(t, `
{
skip_install_trust
admin localhost:2999
http_port 9080
https_port 9443
}
localhost:9080 {
map {http.request.uri.path} `+tc.destination+` {
/foo mapped
}
respond "{result}"
}
`, "caddyfile", tc.expectedError)
})
}
}
func TestMapAsJSON(t *testing.T) {
// arrange
tester := caddytest.NewTester(t)
tester.InitServer(`
{
"admin": {
"listen": "localhost:2999"
},
"apps": {
"pki": {
"certificate_authorities" : {
"local" : {
"install_trust": false
}
}
},
"http": {
"http_port": 9080,
"https_port": 9443,
"servers": {
"srv0": {
"listen": [
":9080"
],
"routes": [
{
"handle": [
{
"handler": "subroute",
"routes": [
{
"handle": [
{
"handler": "map",
"source": "{http.request.method}",
"destinations": ["{dest-name}"],
"defaults": ["unknown"],
"mappings": [
{
"input": "GET",
"outputs": ["get-called"]
},
{
"input": "POST",
"outputs": ["post-called"]
}
]
}
]
},
{
"handle": [
{
"body": "hello from localhost {dest-name}",
"handler": "static_response",
"status_code": 200
}
],
"match": [
{
"path": ["/version"]
}
]
}
]
}
],
"match": [
{
"host": ["localhost"]
}
],
"terminal": true
}
]
}
}
}
}
}`, "json")
tester.AssertGetResponse("http://localhost:9080/version", 200, "hello from localhost get-called")
tester.AssertPostResponseBody("http://localhost:9080/version", []string{}, bytes.NewBuffer([]byte{}), 200, "hello from localhost post-called")
}