aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--caddytest/integration/caddyfile_adapt/reverse_proxy_health_reqbody.caddyfiletest40
-rw-r--r--modules/caddyhttp/reverseproxy/caddyfile.go31
-rw-r--r--modules/caddyhttp/reverseproxy/healthchecks.go19
3 files changed, 78 insertions, 12 deletions
diff --git a/caddytest/integration/caddyfile_adapt/reverse_proxy_health_reqbody.caddyfiletest b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_reqbody.caddyfiletest
new file mode 100644
index 000000000..ae5a6791e
--- /dev/null
+++ b/caddytest/integration/caddyfile_adapt/reverse_proxy_health_reqbody.caddyfiletest
@@ -0,0 +1,40 @@
+:8884
+
+reverse_proxy 127.0.0.1:65535 {
+ health_uri /health
+ health_request_body "test body"
+}
+----------
+{
+ "apps": {
+ "http": {
+ "servers": {
+ "srv0": {
+ "listen": [
+ ":8884"
+ ],
+ "routes": [
+ {
+ "handle": [
+ {
+ "handler": "reverse_proxy",
+ "health_checks": {
+ "active": {
+ "body": "test body",
+ "uri": "/health"
+ }
+ },
+ "upstreams": [
+ {
+ "dial": "127.0.0.1:65535"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+}
diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go
index 4ca5d0e0d..cd0e5d949 100644
--- a/modules/caddyhttp/reverseproxy/caddyfile.go
+++ b/modules/caddyhttp/reverseproxy/caddyfile.go
@@ -69,19 +69,20 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
// lb_retry_match <request-matcher>
//
// # active health checking
-// health_uri <uri>
-// health_port <port>
-// health_interval <interval>
-// health_passes <num>
-// health_fails <num>
-// health_timeout <duration>
-// health_status <status>
-// health_body <regexp>
+// health_uri <uri>
+// health_port <port>
+// health_interval <interval>
+// health_passes <num>
+// health_fails <num>
+// health_timeout <duration>
+// health_status <status>
+// health_body <regexp>
+// health_method <value>
+// health_request_body <value>
// health_follow_redirects
// health_headers {
// <field> [<values...>]
// }
-// health_method <value>
//
// # passive health checking
// fail_duration <duration>
@@ -425,6 +426,18 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
}
h.HealthChecks.Active.Method = d.Val()
+ case "health_request_body":
+ if !d.NextArg() {
+ return d.ArgErr()
+ }
+ if h.HealthChecks == nil {
+ h.HealthChecks = new(HealthChecks)
+ }
+ if h.HealthChecks.Active == nil {
+ h.HealthChecks.Active = new(ActiveHealthChecks)
+ }
+ h.HealthChecks.Active.Body = d.Val()
+
case "health_interval":
if !d.NextArg() {
return d.ArgErr()
diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go
index 3b5a6a3af..efa1dbf09 100644
--- a/modules/caddyhttp/reverseproxy/healthchecks.go
+++ b/modules/caddyhttp/reverseproxy/healthchecks.go
@@ -24,6 +24,7 @@ import (
"regexp"
"runtime/debug"
"strconv"
+ "strings"
"time"
"go.uber.org/zap"
@@ -93,6 +94,9 @@ type ActiveHealthChecks struct {
// The HTTP method to use for health checks (default "GET").
Method string `json:"method,omitempty"`
+ // The body to send with the health check request.
+ Body string `json:"body,omitempty"`
+
// Whether to follow HTTP redirects in response to active health checks (default off).
FollowRedirects bool `json:"follow_redirects,omitempty"`
@@ -396,6 +400,16 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
u.Path = h.HealthChecks.Active.Path
}
+ // replacer used for both body and headers. Only globals (env vars, system info, etc.) are available
+ repl := caddy.NewReplacer()
+
+ // if body is provided, create a reader for it, otherwise nil
+ var requestBody io.Reader
+ if h.HealthChecks.Active.Body != "" {
+ // set body, using replacer
+ requestBody = strings.NewReader(repl.ReplaceAll(h.HealthChecks.Active.Body, ""))
+ }
+
// attach dialing information to this request, as well as context values that
// may be expected by handlers of this request
ctx := h.ctx.Context
@@ -403,15 +417,14 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ
ctx = context.WithValue(ctx, caddyhttp.VarsCtxKey, map[string]any{
dialInfoVarKey: dialInfo,
})
- req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), nil)
+ req, err := http.NewRequestWithContext(ctx, h.HealthChecks.Active.Method, u.String(), requestBody)
if err != nil {
return fmt.Errorf("making request: %v", err)
}
ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *req)
req = req.WithContext(ctx)
- // set headers, using a replacer with only globals (env vars, system info, etc.)
- repl := caddy.NewReplacer()
+ // set headers, using replacer
repl.Set("http.reverse_proxy.active.target_upstream", networkAddr)
for key, vals := range h.HealthChecks.Active.Headers {
key = repl.ReplaceAll(key, "")