diff options
author | Matthew Holt <[email protected]> | 2019-09-20 13:13:49 -0600 |
---|---|---|
committer | Matthew Holt <[email protected]> | 2019-09-20 13:13:49 -0600 |
commit | 2f684e42d5b8b78fe688b2f7e31d54d2333c0701 (patch) | |
tree | 41274f40173b2029d589b06601862ef08c3b209f /modules/caddyhttp/headers | |
parent | ba29f9d41d7951bde07dc2e0d6a1471c40bb7145 (diff) | |
download | caddy-2f684e42d5b8b78fe688b2f7e31d54d2333c0701.tar.gz caddy-2f684e42d5b8b78fe688b2f7e31d54d2333c0701.zip |
reverse_proxy/headers: Expose header replacement ability in Caddyfile
Adds header_up and header_down subdirectives to reverse_proxy
Diffstat (limited to 'modules/caddyhttp/headers')
-rw-r--r-- | modules/caddyhttp/headers/caddyfile.go | 98 |
1 files changed, 62 insertions, 36 deletions
diff --git a/modules/caddyhttp/headers/caddyfile.go b/modules/caddyhttp/headers/caddyfile.go index 2fd6f0636..c1444d0ea 100644 --- a/modules/caddyhttp/headers/caddyfile.go +++ b/modules/caddyhttp/headers/caddyfile.go @@ -30,26 +30,40 @@ func init() { // parseCaddyfile sets up the handler for response headers from // Caddyfile tokens. Syntax: // -// headers [<matcher>] [[+|-]<field> <value>] { -// [+][<field>] [<value>] -// [-<field>] +// headers [<matcher>] [[+|-]<field> [<value|regexp>] [<replacement>]] { +// [+]<field> [<value|regexp> [<replacement>]] +// -<field> // } // // Either a block can be opened or a single header field can be configured // in the first line, but not both in the same directive. func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { hdr := new(Handler) + + makeResponseOps := func() { + if hdr.Response == nil { + hdr.Response = &RespHeaderOps{ + HeaderOps: new(HeaderOps), + Deferred: true, + } + } + } + for h.Next() { // first see if headers are in the initial line var hasArgs bool if h.NextArg() { hasArgs = true field := h.Val() - var value string + var value, replacement string if h.NextArg() { value = h.Val() } - processCaddyfileLineRespHdr(hdr, field, value) + if h.NextArg() { + replacement = h.Val() + } + makeResponseOps() + CaddyfileHeaderOp(hdr.Response.HeaderOps, field, value, replacement) } // if not, they should be in a block @@ -58,20 +72,25 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) return nil, h.Err("cannot specify headers in both arguments and block") } field := h.Val() - var value string + var value, replacement string if h.NextArg() { value = h.Val() } - processCaddyfileLineRespHdr(hdr, field, value) + if h.NextArg() { + replacement = h.Val() + } + makeResponseOps() + CaddyfileHeaderOp(hdr.Response.HeaderOps, field, value, replacement) } } + return hdr, nil } // parseReqHdrCaddyfile sets up the handler for request headers // from Caddyfile tokens. Syntax: // -// request_header [<matcher>] [[+|-]<field> <value>] +// request_header [<matcher>] [[+|-]<field> [<value|regexp>] [<replacement>]] // func parseReqHdrCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { hdr := new(Handler) @@ -80,27 +99,18 @@ func parseReqHdrCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, return nil, h.ArgErr() } field := h.Val() - var value string + var value, replacement string if h.NextArg() { value = h.Val() } + if h.NextArg() { + replacement = h.Val() + } if hdr.Request == nil { hdr.Request = new(HeaderOps) } - if strings.HasPrefix(field, "+") { - if hdr.Request.Add == nil { - hdr.Request.Add = make(http.Header) - } - hdr.Request.Add.Set(field[1:], value) - } else if strings.HasPrefix(field, "-") { - hdr.Request.Delete = append(hdr.Request.Delete, field[1:]) - } else { - if hdr.Request.Set == nil { - hdr.Request.Set = make(http.Header) - } - hdr.Request.Set.Set(field, value) - } + CaddyfileHeaderOp(hdr.Request, field, value, replacement) if h.NextArg() { return nil, h.ArgErr() @@ -109,24 +119,40 @@ func parseReqHdrCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, return hdr, nil } -func processCaddyfileLineRespHdr(hdr *Handler, field, value string) { - if hdr.Response == nil { - hdr.Response = &RespHeaderOps{ - HeaderOps: new(HeaderOps), - Deferred: true, - } - } +// CaddyfileHeaderOp applies a new header operation according to +// 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 +// 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) { if strings.HasPrefix(field, "+") { - if hdr.Response.Add == nil { - hdr.Response.Add = make(http.Header) + if ops.Add == nil { + ops.Add = make(http.Header) } - hdr.Response.Add.Set(field[1:], value) + ops.Add.Set(field[1:], value) } else if strings.HasPrefix(field, "-") { - hdr.Response.Delete = append(hdr.Response.Delete, field[1:]) + ops.Delete = append(ops.Delete, field[1:]) } else { - if hdr.Response.Set == nil { - hdr.Response.Set = make(http.Header) + if replacement == "" { + if ops.Set == nil { + ops.Set = make(http.Header) + } + ops.Set.Set(field, value) + } else { + if ops.Replace == nil { + ops.Replace = make(map[string][]Replacement) + } + field = strings.TrimLeft(field, "+-") + ops.Replace[field] = append( + ops.Replace[field], + Replacement{ + SearchRegexp: value, + Replace: replacement, + }, + ) } - hdr.Response.Set.Set(field, value) } } |