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{