mirror of
https://github.com/caddyserver/caddy.git
synced 2025-05-24 02:02:26 -04:00
reverseproxy: Fix active health check header canonicalization, refactor (#5446)
This commit is contained in:
parent
48598e1f2a
commit
335cd2e8a4
@ -24,7 +24,6 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
@ -106,6 +105,76 @@ type ActiveHealthChecks struct {
|
|||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Provision ensures that a is set up properly before use.
|
||||||
|
func (a *ActiveHealthChecks) Provision(ctx caddy.Context, h *Handler) error {
|
||||||
|
if !a.IsEnabled() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Canonicalize the header keys ahead of time, since
|
||||||
|
// JSON unmarshaled headers may be incorrect
|
||||||
|
cleaned := http.Header{}
|
||||||
|
for key, hdrs := range a.Headers {
|
||||||
|
for _, val := range hdrs {
|
||||||
|
cleaned.Add(key, val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a.Headers = cleaned
|
||||||
|
|
||||||
|
h.HealthChecks.Active.logger = h.logger.Named("health_checker.active")
|
||||||
|
|
||||||
|
timeout := time.Duration(a.Timeout)
|
||||||
|
if timeout == 0 {
|
||||||
|
timeout = 5 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Path != "" {
|
||||||
|
a.logger.Warn("the 'path' option is deprecated, please use 'uri' instead!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse the URI string (supports path and query)
|
||||||
|
if a.URI != "" {
|
||||||
|
parsedURI, err := url.Parse(a.URI)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.uri = parsedURI
|
||||||
|
}
|
||||||
|
|
||||||
|
a.httpClient = &http.Client{
|
||||||
|
Timeout: timeout,
|
||||||
|
Transport: h.Transport,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, upstream := range h.Upstreams {
|
||||||
|
// if there's an alternative port for health-check provided in the config,
|
||||||
|
// then use it, otherwise use the port of upstream.
|
||||||
|
if a.Port != 0 {
|
||||||
|
upstream.activeHealthCheckPort = a.Port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Interval == 0 {
|
||||||
|
a.Interval = caddy.Duration(30 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.ExpectBody != "" {
|
||||||
|
var err error
|
||||||
|
a.bodyRegexp, err = regexp.Compile(a.ExpectBody)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("expect_body: compiling regular expression: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsEnabled checks if the active health checks have
|
||||||
|
// the minimum config necessary to be enabled.
|
||||||
|
func (a *ActiveHealthChecks) IsEnabled() bool {
|
||||||
|
return a.Path != "" || a.URI != "" || a.Port != 0
|
||||||
|
}
|
||||||
|
|
||||||
// PassiveHealthChecks holds configuration related to passive
|
// PassiveHealthChecks holds configuration related to passive
|
||||||
// health checks (that is, health checks which occur during
|
// health checks (that is, health checks which occur during
|
||||||
// the normal flow of request proxying).
|
// the normal flow of request proxying).
|
||||||
@ -280,7 +349,7 @@ func (h *Handler) doActiveHealthCheck(dialInfo DialInfo, hostAddr string, upstre
|
|||||||
ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *req)
|
ctx = context.WithValue(ctx, caddyhttp.OriginalRequestCtxKey, *req)
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
for key, hdrs := range h.HealthChecks.Active.Headers {
|
for key, hdrs := range h.HealthChecks.Active.Headers {
|
||||||
if strings.ToLower(key) == "host" {
|
if key == "Host" {
|
||||||
req.Host = h.HealthChecks.Active.Headers.Get(key)
|
req.Host = h.HealthChecks.Active.Headers.Get(key)
|
||||||
} else {
|
} else {
|
||||||
req.Header[key] = hdrs
|
req.Header[key] = hdrs
|
||||||
|
@ -27,7 +27,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -355,56 +354,15 @@ func (h *Handler) Provision(ctx caddy.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if active health checks are enabled, configure them and start a worker
|
// if active health checks are enabled, configure them and start a worker
|
||||||
if h.HealthChecks.Active != nil && (h.HealthChecks.Active.Path != "" ||
|
if h.HealthChecks.Active != nil {
|
||||||
h.HealthChecks.Active.URI != "" ||
|
err := h.HealthChecks.Active.Provision(ctx, h)
|
||||||
h.HealthChecks.Active.Port != 0) {
|
if err != nil {
|
||||||
|
return err
|
||||||
h.HealthChecks.Active.logger = h.logger.Named("health_checker.active")
|
|
||||||
|
|
||||||
timeout := time.Duration(h.HealthChecks.Active.Timeout)
|
|
||||||
if timeout == 0 {
|
|
||||||
timeout = 5 * time.Second
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.HealthChecks.Active.Path != "" {
|
if h.HealthChecks.Active.IsEnabled() {
|
||||||
h.HealthChecks.Active.logger.Warn("the 'path' option is deprecated, please use 'uri' instead!")
|
go h.activeHealthChecker()
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse the URI string (supports path and query)
|
|
||||||
if h.HealthChecks.Active.URI != "" {
|
|
||||||
parsedURI, err := url.Parse(h.HealthChecks.Active.URI)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
h.HealthChecks.Active.uri = parsedURI
|
|
||||||
}
|
|
||||||
|
|
||||||
h.HealthChecks.Active.httpClient = &http.Client{
|
|
||||||
Timeout: timeout,
|
|
||||||
Transport: h.Transport,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, upstream := range h.Upstreams {
|
|
||||||
// if there's an alternative port for health-check provided in the config,
|
|
||||||
// then use it, otherwise use the port of upstream.
|
|
||||||
if h.HealthChecks.Active.Port != 0 {
|
|
||||||
upstream.activeHealthCheckPort = h.HealthChecks.Active.Port
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.HealthChecks.Active.Interval == 0 {
|
|
||||||
h.HealthChecks.Active.Interval = caddy.Duration(30 * time.Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
if h.HealthChecks.Active.ExpectBody != "" {
|
|
||||||
var err error
|
|
||||||
h.HealthChecks.Active.bodyRegexp, err = regexp.Compile(h.HealthChecks.Active.ExpectBody)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("expect_body: compiling regular expression: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go h.activeHealthChecker()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user