-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
http.request placeholders not resolved in <find> of header directive #7109
Copy link
Copy link
Closed
Labels
good first issue 🐤Good for newcomersGood for newcomers
Description
1. Environment
1a. Operating system and version
% docker version
Client:
Version: 28.2.2
API version: 1.50
Go version: go1.24.3
Git commit: e6534b4
Built: Fri May 30 12:07:35 2025
OS/Arch: darwin/arm64
Context: desktop-linux
Server: Docker Desktop 4.42.1 (196648)
Engine:
Version: 28.2.2
API version: 1.50 (minimum version 1.24)
Go version: go1.24.3
Git commit: 45873be
Built: Fri May 30 12:07:27 2025
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.7.27
GitCommit: 05044ec0a9a75232cad458027ca83437aae3f4da
runc:
Version: 1.2.5
GitCommit: v1.2.5-0-g59923ef
docker-init:
Version: 0.19.0
GitCommit: de40ad0
1b. Caddy version
v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U=
2. Description
Attempting to use header directive in replace mode (<field> <find> <replace>), with placeholder used as <find>, results in no replacement being performed. Given the config below:
{
debug
}
localhost {
header X-Alt-Svc-Port "={http.request.local.port}="
header X-Alt-Svc-NewPort "={$CADDY_EXT_HTTP3_PORT:-443}="
# header Alt-Svc ":443" "TEST-1"
# header Alt-Svc ":443" "TEST-2-{http.request.local.port}"
# header Alt-Svc ":{http.request.local.port}" "TEST-3"
# header Alt-Svc "TEST-4-{http.request.local.port}"
respond "Hello, World!"
}
The results of curl -v -k https://localhost 2>&1 | grep alt-svc are as follows when subsequently uncommenting lines given:
# header Alt-Svc ":443" "TEST-1"
< alt-svc: h3="TEST-1"; ma=2592000
< x-alt-svc-newport: =8443=
< x-alt-svc-port: =443=
# header Alt-Svc ":443" "TEST-2-{http.request.local.port}"
< alt-svc: h3="TEST-2-443"; ma=2592000
< x-alt-svc-newport: =8443=
< x-alt-svc-port: =443=
# header Alt-Svc ":{http.request.local.port}" "TEST-3"
< alt-svc: h3=":443"; ma=2592000
< x-alt-svc-newport: =8443=
< x-alt-svc-port: =443=
#header Alt-Svc "TEST-4-{http.request.local.port}"
< alt-svc: TEST-4-443
< x-alt-svc-newport: =8443=
< x-alt-svc-port: =443=
It appears the value is available at this moment, as I can use it in <replace> as well
2b. Log output
% docker run -e CADDY_EXT_HTTP3_PORT=8443 -p 80:80 -p 443:443 -it -v "$(pwd)/docker/web-server/:/etc/caddy/:ro" caddy:latest
2025/07/02 08:35:09.396 INFO maxprocs: Leaving GOMAXPROCS=10: CPU quota undefined
2025/07/02 08:35:09.396 INFO GOMEMLIMIT is updated {"package": "github.com/KimMachineGun/automemlimit/memlimit", "GOMEMLIMIT": 18848965017, "previous": 9223372036854775807}
2025/07/02 08:35:09.397 INFO using config from file {"file": "/etc/caddy/Caddyfile"}
2025/07/02 08:35:09.398 INFO adapted config to JSON {"adapter": "caddyfile"}
2025/07/02 08:35:09.398 WARN Caddyfile input is not formatted; run 'caddy fmt --overwrite' to fix inconsistencies {"adapter": "caddyfile", "file": "/etc/caddy/Caddyfile", "line": 9}
2025/07/02 08:35:09.400 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//127.0.0.1:2019", "//localhost:2019", "//[::1]:2019"]}
2025/07/02 08:35:09.400 INFO http.auto_https server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2025/07/02 08:35:09.400 INFO http.auto_https enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2025/07/02 08:35:09.402 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0x4000702500"}
2025/07/02 08:35:09.409 DEBUG http.auto_https adjusted config {"tls": {"automation":{"policies":[{"subjects":["localhost"]},{}]}}, "http": {"servers":{"remaining_auto_https_redirects":{"listen":[":80"],"routes":[{},{}]},"srv0":{"listen":[":443"],"routes":[{"handle":[{"handler":"subroute","routes":[{"handle":[{"handler":"headers","response":{"set":{"X-Alt-Svc-Port":["={http.request.local.port}="]}}},{"handler":"headers","response":{"set":{"X-Alt-Svc-Newport":["=8443="]}}},{"handler":"headers","response":{"replace":{"Alt-Svc":[{"replace":"TEST-3","search_regexp":":{http.request.local.port}"}]}}},{"body":"Hello, World!","handler":"static_response"}]}]}],"terminal":true}],"tls_connection_policies":[{}],"automatic_https":{}}}}}
2025/07/02 08:35:09.409 DEBUG http starting server loop {"address": "[::]:80", "tls": false, "http3": false}
2025/07/02 08:35:09.409 WARN http HTTP/2 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2025/07/02 08:35:09.409 WARN http HTTP/3 skipped because it requires TLS {"network": "tcp", "addr": ":80"}
2025/07/02 08:35:09.409 INFO http.log server running {"name": "remaining_auto_https_redirects", "protocols": ["h1", "h2", "h3"]}
2025/07/02 08:35:09.409 DEBUG http starting server loop {"address": "[::]:443", "tls": true, "http3": false}
2025/07/02 08:35:09.409 INFO http enabling HTTP/3 listener {"addr": ":443"}
2025/07/02 08:35:09.409 INFO failed to sufficiently increase receive buffer size (was: 208 kiB, wanted: 7168 kiB, got: 416 kiB). See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details.
2025/07/02 08:35:09.410 INFO http.log server running {"name": "srv0", "protocols": ["h1", "h2", "h3"]}
2025/07/02 08:35:09.410 INFO http enabling automatic TLS certificate management {"domains": ["localhost"]}
2025/07/02 08:35:09.410 WARN pki.ca.local installing root certificate (you might be prompted for password) {"path": "storage:pki/authorities/local/root.crt"}
2025/07/02 08:35:09.411 INFO warning: "certutil" is not available, install "certutil" with "apt install libnss3-tools" or "yum install nss-tools" and try again
2025/07/02 08:35:09.411 INFO define JAVA_HOME environment variable to use the Java trust
2025/07/02 08:35:09.412 INFO tls cleaning storage unit {"storage": "FileStorage:/data/caddy"}
2025/07/02 08:35:09.412 INFO tls.obtain acquiring lock {"identifier": "localhost"}
2025/07/02 08:35:09.413 INFO tls.obtain lock acquired {"identifier": "localhost"}
2025/07/02 08:35:09.413 INFO tls.obtain obtaining certificate {"identifier": "localhost"}
2025/07/02 08:35:09.413 DEBUG events event {"name": "cert_obtaining", "id": "03f66c55-92fb-4cdf-9fbd-cdf5c95573c1", "origin": "tls", "data": {"identifier":"localhost"}}
2025/07/02 08:35:09.413 INFO tls finished cleaning storage units
2025/07/02 08:35:09.413 DEBUG tls created CSR {"identifiers": ["localhost"], "san_dns_names": ["localhost"], "san_emails": [], "common_name": "", "extra_extensions": 0}
2025/07/02 08:35:09.413 DEBUG tls.obtain trying issuer 1/1 {"issuer": "local"}
2025/07/02 08:35:09.413 DEBUG pki.ca.local using intermediate signer {"serial": "32491877551547616715895509392942500190", "not_before": "2025-07-02 08:35:09 +0000 UTC", "not_after": "2025-07-09 08:35:09 +0000 UTC"}
2025/07/02 08:35:09.416 INFO tls.obtain certificate obtained successfully {"identifier": "localhost", "issuer": "local"}
2025/07/02 08:35:09.416 DEBUG events event {"name": "cert_obtained", "id": "9ae8dcd9-b6f3-4f40-a0a6-d879d669c143", "origin": "tls", "data": {"certificate_path":"certificates/local/localhost/localhost.crt","csr_pem":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlIaE1JR0pBZ0VBTUFBd1dUQVRCZ2NxaGtqT1BRSUJCZ2dxaGtqT1BRTUJCd05DQUFRcUJHNnNIRFcvd284aAoyV2JiZS93OHgvT20vdUJXdHR2bTN2b1NZK3FubmhyeVdjWExZQ0NENW1CSHJWZkhPNExXVkprWTdiNUVnUEhUCkZVUmZHb2J1b0Njd0pRWUpLb1pJaHZjTkFRa09NUmd3RmpBVUJnTlZIUkVFRFRBTGdnbHNiMk5oYkdodmMzUXcKQ2dZSUtvWkl6ajBFQXdJRFJ3QXdSQUlnRzZmaEJTczc3YzFwNG1TY09yNGNnZVlCMGtyNkZ5SHBiamtWRzZRaAppcmtDSUZFcDEvVWNSdkJwTWhmQ3Noa3pxek80KzBjTHlMa0VFb1dsQmpxWEk1RTQKLS0tLS1FTkQgQ0VSVElGSUNBVEUgUkVRVUVTVC0tLS0tCg==","identifier":"localhost","issuer":"local","metadata_path":"certificates/local/localhost/localhost.json","private_key_path":"certificates/local/localhost/localhost.key","renewal":false,"storage_path":"certificates/local/localhost"}}
2025/07/02 08:35:09.416 INFO tls.obtain releasing lock {"identifier": "localhost"}
2025/07/02 08:35:09.416 DEBUG tls.cache added certificate to cache {"subjects": ["localhost"], "expiration": "2025/07/02 20:35:10.000", "managed": true, "issuer_key": "local", "hash": "6cd09a596957dd471ba6b95ca5671aa045ddc4a44a8246bffd3c0350b0a34c99", "cache_size": 1, "cache_capacity": 10000}
2025/07/02 08:35:09.416 DEBUG events event {"name": "cached_managed_cert", "id": "9bd9d154-5bc9-46fb-980e-9b2c75f3f05c", "origin": "tls", "data": {"sans":["localhost"]}}
2025/07/02 08:35:09.431 INFO certificate installed properly in linux trusts
2025/07/02 08:35:09.431 DEBUG events event {"name": "started", "id": "db1d9cec-392b-4d90-9268-ab1e2c858b2e", "origin": "", "data": null}
2025/07/02 08:35:09.432 INFO autosaved config (load with --resume flag) {"file": "/config/caddy/autosave.json"}
2025/07/02 08:35:09.432 INFO serving initial configuration
2025/07/02 08:35:21.273 DEBUG events event {"name": "tls_get_certificate", "id": "5ddae3b5-895b-4768-8890-71be87861548", "origin": "tls", "data": {"client_hello":{"CipherSuites":[4867,4866,4865,52393,52392,52394,49200,49196,49192,49188,49172,49162,159,107,57,65413,196,136,129,157,61,53,192,132,49199,49195,49191,49187,49171,49161,158,103,51,190,69,156,60,47,186,65,49169,49159,5,4,49170,49160,22,10,255],"ServerName":"localhost","SupportedCurves":[29,23,24,25],"SupportedPoints":"AA==","SignatureSchemes":[2054,1537,1539,2053,1281,1283,2052,1025,1027,513,515],"SupportedProtos":["h2","http/1.1"],"SupportedVersions":[772,771,770,769],"RemoteAddr":{"IP":"185.85.0.29","Port":29296,"Zone":""},"LocalAddr":{"IP":"172.17.0.6","Port":443,"Zone":""}}}}
2025/07/02 08:35:21.273 DEBUG tls.handshake choosing certificate {"identifier": "localhost", "num_choices": 1}
2025/07/02 08:35:21.273 DEBUG tls.handshake default certificate selection results {"identifier": "localhost", "subjects": ["localhost"], "managed": true, "issuer_key": "local", "hash": "6cd09a596957dd471ba6b95ca5671aa045ddc4a44a8246bffd3c0350b0a34c99"}
2025/07/02 08:35:21.273 DEBUG tls.handshake matched certificate in cache {"remote_ip": "185.85.0.29", "remote_port": "29296", "subjects": ["localhost"], "managed": true, "expiration": "2025/07/02 20:35:10.000", "hash": "6cd09a596957dd471ba6b95ca5671aa045ddc4a44a8246bffd3c0350b0a34c99"}
^C2025/07/02 08:35:25.376 INFO shutting down {"signal": "SIGINT"}
2025/07/02 08:35:25.376 WARN exiting; byeee!! 👋 {"signal": "SIGINT"}
2025/07/02 08:35:25.376 DEBUG events event {"name": "stopping", "id": "037ffe94-cf7d-4790-b0a5-bbd991568151", "origin": "", "data": null}
2025/07/02 08:35:25.376 INFO http servers shutting down with eternal grace period
2025/07/02 08:35:25.377 INFO admin stopped previous server {"address": "localhost:2019"}
2025/07/02 08:35:25.377 INFO shutdown complete {"signal": "SIGINT", "exit_code": 0}
2d. Workaround(s)
This was an attempt to replace port in Alt-Svc header instead of building the header from scratch, as discussed in #4996. Naturally crafting the header manually works as expected:
# header Alt-Svc "h3=\":{$CADDY_EXT_HTTP3_PORT:-443}\"; ma=2592000"
% curl -v -k https://localhost 2>&1 | grep alt-svc
< alt-svc: h3=":8443"; ma=2592000
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
good first issue 🐤Good for newcomersGood for newcomers