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
Implement headers middleware
Matthew Holt committed
May 20, 2019 at 15:46 UTC
d22f64e6d41117c242fc4ecd00179e68b8f118c5
4 files changed
+93
cmd/caddy2/main.go
+1
@@ -6,6 +6,7 @@ import (
6
// this is where modules get plugged in
7
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp"
8
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/caddylog"
9
+ _ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/headers"
10
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/reverseproxy"
11
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp/staticfiles"
12
_ "bitbucket.org/lightcodelabs/caddy2/modules/caddytls"
modules/caddyhttp/headers/headers.go
new
+82
@@ -0,0 +1,82 @@
1
+package headers
2
+
3
+import (
4
+ "net/http"
5
+ "strings"
6
+
7
+ "bitbucket.org/lightcodelabs/caddy2"
8
+ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp"
9
+)
10
+
11
+func init() {
12
+ caddy2.RegisterModule(caddy2.Module{
13
+ Name: "http.middleware.headers",
14
+ New: func() (interface{}, error) { return new(Headers), nil },
15
+ })
16
+}
17
+
18
+// Headers is a middleware which can mutate HTTP headers.
19
+type Headers struct {
20
+ Request HeaderOps
21
+ Response RespHeaderOps
22
+}
23
+
24
+// HeaderOps defines some operations to
25
+// perform on HTTP headers.
26
+type HeaderOps struct {
27
+ Add http.Header
28
+ Set http.Header
29
+ Delete []string
30
+}
31
+
32
+// RespHeaderOps is like HeaderOps, but
33
+// optionally deferred until response time.
34
+type RespHeaderOps struct {
35
+ HeaderOps
36
+ Deferred bool `json:"deferred"`
37
+}
38
+
39
+func (h Headers) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
40
+ apply(h.Request, r.Header)
41
+ if h.Response.Deferred {
42
+ w = &responseWriterWrapper{
43
+ ResponseWriterWrapper: &caddyhttp.ResponseWriterWrapper{ResponseWriter: w},
44
+ headerOps: h.Response.HeaderOps,
45
+ }
46
+ } else {
47
+ apply(h.Response.HeaderOps, w.Header())
48
+ }
49
+ return next.ServeHTTP(w, r)
50
+}
51
+
52
+func apply(ops HeaderOps, hdr http.Header) {
53
+ for fieldName, vals := range ops.Add {
54
+ for _, v := range vals {
55
+ hdr.Add(fieldName, v)
56
+ }
57
+ }
58
+ for fieldName, vals := range ops.Set {
59
+ hdr.Set(fieldName, strings.Join(vals, ","))
60
+ }
61
+ for _, fieldName := range ops.Delete {
62
+ hdr.Del(fieldName)
63
+ }
64
+}
65
+
66
+// responseWriterWrapper defers response header
67
+// operations until WriteHeader is called.
68
+type responseWriterWrapper struct {
69
+ *caddyhttp.ResponseWriterWrapper
70
+ headerOps HeaderOps
71
+}
72
+
73
+func (rww *responseWriterWrapper) WriteHeader(status int) {
74
+ apply(rww.headerOps, rww.ResponseWriterWrapper.Header())
75
+ rww.ResponseWriterWrapper.WriteHeader(status)
76
+}
77
+
78
+// Interface guards
79
+var (
80
+ _ caddyhttp.MiddlewareHandler = (*Headers)(nil)
81
+ _ caddyhttp.HTTPInterfaces = (*responseWriterWrapper)(nil)
82
+)
modules/caddyhttp/headers/headers_test.go
new
+7
@@ -0,0 +1,7 @@
1
+package headers
2
+
3
+import "testing"
4
+
5
+func TestReqHeaders(t *testing.T) {
6
+ // TODO: write tests
7
+}
modules/caddyhttp/staticfiles/matcher.go
+3
@@ -16,6 +16,8 @@ func init() {
16
})
17
}
18
19
+// FileMatcher is a matcher that can match requests
20
+// based on the local file system.
21
// TODO: Not sure how to do this well; we'd need the ability to
22
// hide files, etc...
23
// TODO: Also consider a feature to match directory that
@@ -29,6 +31,7 @@ type FileMatcher struct {
31
Flags []string `json:"flags"`
32
}
33
34
+// Match matches the request r against m.
35
func (m FileMatcher) Match(r *http.Request) bool {
36
// TODO: sanitize path
37
fullPath := filepath.Join(m.Root, m.Path)