From 97a56d860a2254f4d9939746a33698b365d546d6 Mon Sep 17 00:00:00 2001 From: Francis Lavoie Date: Thu, 21 Mar 2024 13:29:32 -0400 Subject: [PATCH] caddyhttp: Allow `header` replacement with empty string (#6163) --- modules/caddyhttp/headers/caddyfile.go | 28 +++++++++++++-------- modules/caddyhttp/push/caddyfile.go | 6 ++--- modules/caddyhttp/reverseproxy/caddyfile.go | 13 +++++----- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/modules/caddyhttp/headers/caddyfile.go b/modules/caddyhttp/headers/caddyfile.go index 821c0d83..e55e9fab 100644 --- a/modules/caddyhttp/headers/caddyfile.go +++ b/modules/caddyhttp/headers/caddyfile.go @@ -68,12 +68,14 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) if h.NextArg() { hasArgs = true field := h.Val() - var value, replacement string + var value string + var replacement *string if h.NextArg() { value = h.Val() } if h.NextArg() { - replacement = h.Val() + arg := h.Val() + replacement = &arg } err := applyHeaderOp( handler.Response.HeaderOps, @@ -106,12 +108,14 @@ func parseCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19 field = strings.TrimSuffix(field, ":") - var value, replacement string + var value string + var replacement *string if h.NextArg() { value = h.Val() } if h.NextArg() { - replacement = h.Val() + arg := h.Val() + replacement = &arg } handlerToUse := handler @@ -170,12 +174,14 @@ func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, // https://caddy.community/t/v2-reverse-proxy-please-add-cors-example-to-the-docs/7349/19 field = strings.TrimSuffix(field, ":") - var value, replacement string + var value string + var replacement *string if h.NextArg() { value = h.Val() } if h.NextArg() { - replacement = h.Val() + arg := h.Val() + replacement = &arg if h.NextArg() { return nil, h.ArgErr() } @@ -200,15 +206,15 @@ func parseReqHdrCaddyfile(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, // field, value, and replacement. The field can be prefixed with // "+" or "-" to specify adding or removing; otherwise, the value // will be set (overriding any previous value). If replacement is -// non-empty, value will be treated as a regular expression which +// non-nil, value will be treated as a regular expression which // will be used to search and then replacement will be used to // complete the substring replacement; in that case, any + or - // prefix to field will be ignored. -func CaddyfileHeaderOp(ops *HeaderOps, field, value, replacement string) error { +func CaddyfileHeaderOp(ops *HeaderOps, field, value string, replacement *string) error { return applyHeaderOp(ops, nil, field, value, replacement) } -func applyHeaderOp(ops *HeaderOps, respHeaderOps *RespHeaderOps, field, value, replacement string) error { +func applyHeaderOp(ops *HeaderOps, respHeaderOps *RespHeaderOps, field, value string, replacement *string) error { switch { case strings.HasPrefix(field, "+"): // append if ops.Add == nil { @@ -238,7 +244,7 @@ func applyHeaderOp(ops *HeaderOps, respHeaderOps *RespHeaderOps, field, value, r } respHeaderOps.Set.Set(field, value) - case replacement != "": // replace + case replacement != nil: // replace // allow defer shortcut for replace syntax if strings.HasPrefix(field, ">") && respHeaderOps != nil { respHeaderOps.Deferred = true @@ -251,7 +257,7 @@ func applyHeaderOp(ops *HeaderOps, respHeaderOps *RespHeaderOps, field, value, r ops.Replace[field], Replacement{ SearchRegexp: value, - Replace: replacement, + Replace: *replacement, }, ) diff --git a/modules/caddyhttp/push/caddyfile.go b/modules/caddyhttp/push/caddyfile.go index 07f6ccea..f56db81f 100644 --- a/modules/caddyhttp/push/caddyfile.go +++ b/modules/caddyhttp/push/caddyfile.go @@ -73,11 +73,11 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) switch len(args) { case 1: - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], "", "") + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], "", nil) case 2: - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], "") + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], nil) case 3: - err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], args[2]) + err = headers.CaddyfileHeaderOp(&handler.Headers.HeaderOps, args[0], args[1], &args[2]) default: return nil, h.ArgErr() } diff --git a/modules/caddyhttp/reverseproxy/caddyfile.go b/modules/caddyhttp/reverseproxy/caddyfile.go index 93cc2956..9e0726be 100644 --- a/modules/caddyhttp/reverseproxy/caddyfile.go +++ b/modules/caddyhttp/reverseproxy/caddyfile.go @@ -683,7 +683,7 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { switch len(args) { case 1: - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], "", "") + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], "", nil) case 2: // some lint checks, I guess if strings.EqualFold(args[0], "host") && (args[1] == "{hostport}" || args[1] == "{http.request.hostport}") { @@ -698,9 +698,9 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if strings.EqualFold(args[0], "x-forwarded-host") && (args[1] == "{host}" || args[1] == "{http.request.host}" || args[1] == "{hostport}" || args[1] == "{http.request.hostport}") { caddy.Log().Named("caddyfile").Warn("Unnecessary header_up X-Forwarded-Host: the reverse proxy's default behavior is to pass headers to the upstream") } - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], "") + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], nil) case 3: - err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], args[2]) + err = headers.CaddyfileHeaderOp(h.Headers.Request, args[0], args[1], &args[2]) default: return d.ArgErr() } @@ -721,13 +721,14 @@ func (h *Handler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } args := d.RemainingArgs() + switch len(args) { case 1: - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], "", "") + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], "", nil) case 2: - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], "") + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], nil) case 3: - err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], args[2]) + err = headers.CaddyfileHeaderOp(h.Headers.Response.HeaderOps, args[0], args[1], &args[2]) default: return d.ArgErr() }