@marcel91200 / caddy Mirror · read-only / commits / 005a11cf
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

headers: New 'request_header' directive; handle Host header specially

Before this change, only response headers could be manipulated with the Caddyfile's 'header' directive. Also handle the request Host header specially, since the Go standard library treats it separately from the other header fields...

Matthew Holt committed Sep 11, 2019 at 18:48 UTC 005a11cf4b0af5bfbbb72f8572681b327675541c
3 files changed +69 -16
caddyconfig/httpcaddyfile/directives.go
+1
@@ -30,6 +30,7 @@ var defaultDirectiveOrder = []string{
30 "rewrite",
31 "try_files",
32 "headers",
33 + "request_header",
34 "encode",
35 "templates",
36 "redir",
modules/caddyhttp/headers/caddyfile.go
+57 -16
@@ -24,9 +24,11 @@ import (
24
25 func init() {
26 httpcaddyfile.RegisterHandlerDirective("headers", parseCaddyfile)
27 + httpcaddyfile.RegisterHandlerDirective("request_header", parseReqHdrCaddyfile)
28 }
29
29 -// parseCaddyfile sets up the handler from Caddyfile tokens. Syntax:
30 +// parseCaddyfile sets up the handler for response headers from
31 +// Caddyfile tokens. Syntax:
32 //
33 // headers [<matcher>] [[+|-]<field> <value>] {
34 // [+][<field>] [<value>]
@@ -43,9 +45,11 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
45 if h.NextArg() {
46 hasArgs = true
47 field := h.Val()
46 - h.NextArg()
47 - value := h.Val()
48 - processCaddyfileLine(hdr, field, value)
48 + var value string
49 + if h.NextArg() {
50 + value = h.Val()
51 + }
52 + processCaddyfileLineRespHdr(hdr, field, value)
53 }
54
55 // if not, they should be in a block
@@ -58,31 +62,68 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
62 if h.NextArg() {
63 value = h.Val()
64 }
61 - processCaddyfileLine(hdr, field, value)
65 + processCaddyfileLineRespHdr(hdr, field, value)
66 }
67 }
68 return hdr, nil
69 }
70
67 -func processCaddyfileLine(hdr *Headers, field, value string) {
68 - if strings.HasPrefix(field, "+") {
69 - if hdr.Response == nil {
70 - hdr.Response = &RespHeaderOps{HeaderOps: new(HeaderOps)}
71 +// parseReqHdrCaddyfile sets up the handler for request headers
72 +// from Caddyfile tokens. Syntax:
73 +//
74 +// request_header [<matcher>] [[+|-]<field> <value>]
75 +//
76 +func parseReqHdrCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
77 + hdr := new(Headers)
78 + for h.Next() {
79 + if !h.NextArg() {
80 + return nil, h.ArgErr()
81 + }
82 + field := h.Val()
83 + var value string
84 + if h.NextArg() {
85 + value = h.Val()
86 + }
87 +
88 + if hdr.Request == nil {
89 + hdr.Request = new(HeaderOps)
90 + }
91 + if strings.HasPrefix(field, "+") {
92 + if hdr.Request.Add == nil {
93 + hdr.Request.Add = make(http.Header)
94 + }
95 + hdr.Request.Add.Set(field[1:], value)
96 + } else if strings.HasPrefix(field, "-") {
97 + hdr.Request.Delete = append(hdr.Request.Delete, field[1:])
98 + } else {
99 + if hdr.Request.Set == nil {
100 + hdr.Request.Set = make(http.Header)
101 + }
102 + hdr.Request.Set.Set(field, value)
103 + }
104 +
105 + if h.NextArg() {
106 + return nil, h.ArgErr()
107 + }
108 + }
109 + return hdr, nil
110 +}
111 +
112 +func processCaddyfileLineRespHdr(hdr *Headers, field, value string) {
113 + if hdr.Response == nil {
114 + hdr.Response = &RespHeaderOps{
115 + HeaderOps: new(HeaderOps),
116 + Deferred: true,
117 }
118 + }
119 + if strings.HasPrefix(field, "+") {
120 if hdr.Response.Add == nil {
121 hdr.Response.Add = make(http.Header)
122 }
123 hdr.Response.Add.Set(field[1:], value)
124 } else if strings.HasPrefix(field, "-") {
77 - if hdr.Response == nil {
78 - hdr.Response = &RespHeaderOps{HeaderOps: new(HeaderOps)}
79 - }
125 hdr.Response.Delete = append(hdr.Response.Delete, field[1:])
81 - hdr.Response.Deferred = true
126 } else {
83 - if hdr.Response == nil {
84 - hdr.Response = &RespHeaderOps{HeaderOps: new(HeaderOps)}
85 - }
127 if hdr.Response.Set == nil {
128 hdr.Response.Set = make(http.Header)
129 }
modules/caddyhttp/headers/headers.go
+11
@@ -58,7 +58,18 @@ type RespHeaderOps struct {
58
59 func (h Headers) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
60 repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer)
61 +
62 apply(h.Request, r.Header, repl)
63 +
64 + // request header's Host is handled specially by the
65 + // Go standard library, so if that header was changed,
66 + // change it in the Host field since the Header won't
67 + // be used
68 + if intendedHost := r.Header.Get("Host"); intendedHost != "" {
69 + r.Host = intendedHost
70 + r.Header.Del("Host")
71 + }
72 +
73 if h.Response != nil {
74 if h.Response.Deferred || h.Response.Require != nil {
75 w = &responseWriterWrapper{