From c92e374cd9d1a72f5c0eb56f918ea48c537409ac Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Thu, 23 Jan 2025 16:05:17 -0500 Subject: [PATCH 1/8] add Transport override option for active health checks --- .../caddyhttp/reverseproxy/healthchecks.go | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index f0ffee5b8f7..6365e7754cd 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -90,6 +90,9 @@ type ActiveHealthChecks struct { // this value is ignored. Port int `json:"port,omitempty"` + // The transport to use for health checks. If not set, the handler's transport is used + Transport http.RoundTripper `json:"transport,omitempty"` + // HTTP headers to set on health check requests. Headers http.Header `json:"headers,omitempty"` @@ -175,9 +178,14 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { a.uri = parsedURI } + // Use handler's transport if no active one set + if a.Transport == nil { + a.Transport = h.Transport + } + a.httpClient = &http.Client{ Timeout: timeout, - Transport: h.Transport, + Transport: a.Transport, CheckRedirect: func(req *http.Request, via []*http.Request) error { if !a.FollowRedirects { return http.ErrUseLastResponse @@ -393,12 +401,17 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ u.Host = net.JoinHostPort(host, port) } - // this is kind of a hacky way to know if we should use HTTPS, but whatever - if tt, ok := h.Transport.(TLSTransport); ok && tt.TLSEnabled() { + // this is kind of a hacky way to know if we should use HTTPS + transport := h.HealthChecks.Active.Transport + if transport == nil { + transport = h.Transport + } + + if tt, ok := transport.(TLSTransport); ok && tt.TLSEnabled() { u.Scheme = "https" // if the port is in the except list, flip back to HTTP - if ht, ok := h.Transport.(*HTTPTransport); ok && slices.Contains(ht.TLS.ExceptPorts, port) { + if ht, ok := transport.(*HTTPTransport); ok && slices.Contains(ht.TLS.ExceptPorts, port) { u.Scheme = "http" } } From d2762c840559ee2989b8a0a149318cb89f004f86 Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:12:14 -0500 Subject: [PATCH 2/8] load module & initialize RoundTripper - barebones --- modules/caddyhttp/reverseproxy/healthchecks.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 6365e7754cd..6bf7fd69f63 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -90,7 +90,10 @@ type ActiveHealthChecks struct { // this value is ignored. Port int `json:"port,omitempty"` - // The transport to use for health checks. If not set, the handler's transport is used + + // Configures the method of transport for the active health checker. + // The default transport is the handler's transport + TransportRaw json.RawMessage `json:"transport,omitempty"` Transport http.RoundTripper `json:"transport,omitempty"` // HTTP headers to set on health check requests. @@ -177,9 +180,15 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { } a.uri = parsedURI } - + // Use handler's transport if no active one set - if a.Transport == nil { + if a.TransportRaw != nil { + mod, err := ctx.LoadModule(a, "TransportRaw") + if err != nil { + return fmt.Errorf("loading transport: %v", err) + } + a.Transport = mod.(http.RoundTripper) + } else { a.Transport = h.Transport } From be406bc4c9089dd586799cd8dbaddfcbed1cdfeb Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:19:21 -0500 Subject: [PATCH 3/8] add namespace --- modules/caddyhttp/reverseproxy/healthchecks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 6bf7fd69f63..aed31221255 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -93,7 +93,7 @@ type ActiveHealthChecks struct { // Configures the method of transport for the active health checker. // The default transport is the handler's transport - TransportRaw json.RawMessage `json:"transport,omitempty"` + TransportRaw json.RawMessage `json:"transport,omitempty" caddy:"namespace=http.reverse_proxy.health_checks.active.transport inline_key=protocol"` Transport http.RoundTripper `json:"transport,omitempty"` // HTTP headers to set on health check requests. From 7a805e8d6bd7ae1c70b39b882d3ce8c1e1eee8a7 Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:21:28 -0500 Subject: [PATCH 4/8] transport not exported for active health check --- modules/caddyhttp/reverseproxy/healthchecks.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index aed31221255..982c1ec39bd 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -94,7 +94,6 @@ type ActiveHealthChecks struct { // Configures the method of transport for the active health checker. // The default transport is the handler's transport TransportRaw json.RawMessage `json:"transport,omitempty" caddy:"namespace=http.reverse_proxy.health_checks.active.transport inline_key=protocol"` - Transport http.RoundTripper `json:"transport,omitempty"` // HTTP headers to set on health check requests. Headers http.Header `json:"headers,omitempty"` @@ -134,6 +133,7 @@ type ActiveHealthChecks struct { // body of a healthy backend. ExpectBody string `json:"expect_body,omitempty"` + transport http.RoundTripper `json:"transport,omitempty"` uri *url.URL httpClient *http.Client bodyRegexp *regexp.Regexp @@ -187,14 +187,14 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { if err != nil { return fmt.Errorf("loading transport: %v", err) } - a.Transport = mod.(http.RoundTripper) + a.transport = mod.(http.RoundTripper) } else { - a.Transport = h.Transport + a.transport = h.Transport } a.httpClient = &http.Client{ Timeout: timeout, - Transport: a.Transport, + Transport: a.transport, CheckRedirect: func(req *http.Request, via []*http.Request) error { if !a.FollowRedirects { return http.ErrUseLastResponse From f4bb176184b9c3d26e1aeacc9b7e9523bd36ab9c Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:24:15 -0500 Subject: [PATCH 5/8] exclude --- modules/caddyhttp/reverseproxy/healthchecks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 982c1ec39bd..705afd78fef 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -133,7 +133,7 @@ type ActiveHealthChecks struct { // body of a healthy backend. ExpectBody string `json:"expect_body,omitempty"` - transport http.RoundTripper `json:"transport,omitempty"` + transport http.RoundTripper `json:"-"`` uri *url.URL httpClient *http.Client bodyRegexp *regexp.Regexp From 01831049a306ce3dbdc2d159799aaff4268c9004 Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:26:29 -0500 Subject: [PATCH 6/8] fix namespace --- modules/caddyhttp/reverseproxy/healthchecks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 705afd78fef..0f1edc25fcc 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -93,8 +93,8 @@ type ActiveHealthChecks struct { // Configures the method of transport for the active health checker. // The default transport is the handler's transport - TransportRaw json.RawMessage `json:"transport,omitempty" caddy:"namespace=http.reverse_proxy.health_checks.active.transport inline_key=protocol"` - + TransportRaw json.RawMessage `json:"transport,omitempty" caddy:"namespace=http.reverse_proxy.transport inline_key=protocol"` + // HTTP headers to set on health check requests. Headers http.Header `json:"headers,omitempty"` From d6d9e9e8c83272fe6da410d295f8d8b633773198 Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:34:46 -0500 Subject: [PATCH 7/8] exported, but not serialized --- modules/caddyhttp/reverseproxy/healthchecks.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 0f1edc25fcc..6d74f9c82eb 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -133,7 +133,7 @@ type ActiveHealthChecks struct { // body of a healthy backend. ExpectBody string `json:"expect_body,omitempty"` - transport http.RoundTripper `json:"-"`` + Transport http.RoundTripper `json:"-"`` uri *url.URL httpClient *http.Client bodyRegexp *regexp.Regexp @@ -187,14 +187,14 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { if err != nil { return fmt.Errorf("loading transport: %v", err) } - a.transport = mod.(http.RoundTripper) + a.Transport = mod.(http.RoundTripper) } else { - a.transport = h.Transport + a.Transport = h.Transport } a.httpClient = &http.Client{ Timeout: timeout, - Transport: a.transport, + Transport: a.Transport, CheckRedirect: func(req *http.Request, via []*http.Request) error { if !a.FollowRedirects { return http.ErrUseLastResponse From cb23087f6dda4f2a0adfbd8ae5fd5b8c4f465ef3 Mon Sep 17 00:00:00 2001 From: ab14-tech <> Date: Fri, 24 Jan 2025 12:59:24 -0500 Subject: [PATCH 8/8] unexported transport works --- modules/caddyhttp/reverseproxy/healthchecks.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/caddyhttp/reverseproxy/healthchecks.go b/modules/caddyhttp/reverseproxy/healthchecks.go index 6d74f9c82eb..2556fd6ccf1 100644 --- a/modules/caddyhttp/reverseproxy/healthchecks.go +++ b/modules/caddyhttp/reverseproxy/healthchecks.go @@ -133,7 +133,7 @@ type ActiveHealthChecks struct { // body of a healthy backend. ExpectBody string `json:"expect_body,omitempty"` - Transport http.RoundTripper `json:"-"`` + transport http.RoundTripper `json:"-"`` uri *url.URL httpClient *http.Client bodyRegexp *regexp.Regexp @@ -187,14 +187,14 @@ func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error { if err != nil { return fmt.Errorf("loading transport: %v", err) } - a.Transport = mod.(http.RoundTripper) + a.transport = mod.(http.RoundTripper) } else { - a.Transport = h.Transport + a.transport = h.Transport } a.httpClient = &http.Client{ Timeout: timeout, - Transport: a.Transport, + Transport: a.transport, CheckRedirect: func(req *http.Request, via []*http.Request) error { if !a.FollowRedirects { return http.ErrUseLastResponse @@ -411,7 +411,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, networ } // this is kind of a hacky way to know if we should use HTTPS - transport := h.HealthChecks.Active.Transport + transport := h.HealthChecks.Active.transport if transport == nil { transport = h.Transport }