@marcel91200 / caddy Mirror · read-only / commits / d22f64e6
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

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)