caddyhttp: {http.request.body_base64} placeholder

This commit is contained in:
Francis Lavoie 2025-11-26 05:13:58 -05:00
parent 67a9e0657e
commit 4da83c95ec
No known key found for this signature in database
GPG key ID: 656DB341634BFCE1
2 changed files with 16 additions and 0 deletions

View file

@ -51,6 +51,7 @@ func init() {
// Placeholder | Description
// ------------|---------------
// `{http.request.body}` | The request body (⚠️ inefficient; use only for debugging)
// `{http.request.body_base64}` | The request body, base64-encoded (⚠️ for debugging)
// `{http.request.cookie.*}` | HTTP request cookie
// `{http.request.duration}` | Time up to now spent handling the request (after decoding headers from client)
// `{http.request.duration_ms}` | Same as 'duration', but in milliseconds.

View file

@ -229,6 +229,21 @@ func addHTTPVarsToReplacer(repl *caddy.Replacer, req *http.Request, w http.Respo
req.Body = io.NopCloser(buf) // replace real body with buffered data
return buf.String(), true
case "http.request.body_base64":
if req.Body == nil {
return "", true
}
// normally net/http will close the body for us, but since we
// are replacing it with a fake one, we have to ensure we close
// the real body ourselves when we're done
defer req.Body.Close()
// read the request body into a buffer (can't pool because we
// don't know its lifetime and would have to make a copy anyway)
buf := new(bytes.Buffer)
_, _ = io.Copy(buf, req.Body) // can't handle error, so just ignore it
req.Body = io.NopCloser(buf) // replace real body with buffered data
return base64.StdEncoding.EncodeToString(buf.Bytes()), true
// original request, before any internal changes
case "http.request.orig_method":
or, _ := req.Context().Value(OriginalRequestCtxKey).(http.Request)