summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-05-20 15:46:47 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2019-05-20 15:46:52 -0600
commitd22f64e6d41117c242fc4ecd00179e68b8f118c5 (patch)
treede059f4423337b6d58c6322c110eb6e928f1080e /modules
parent22995e5655b3d5117743d98bf5c7ba8ed335a2c5 (diff)
Implement headers middleware
Diffstat (limited to 'modules')
-rw-r--r--modules/caddyhttp/headers/headers.go82
-rw-r--r--modules/caddyhttp/headers/headers_test.go7
-rw-r--r--modules/caddyhttp/staticfiles/matcher.go3
3 files changed, 92 insertions, 0 deletions
diff --git a/modules/caddyhttp/headers/headers.go b/modules/caddyhttp/headers/headers.go
new file mode 100644
index 0000000..1826c7a
--- /dev/null
+++ b/modules/caddyhttp/headers/headers.go
@@ -0,0 +1,82 @@
+package headers
+
+import (
+ "net/http"
+ "strings"
+
+ "bitbucket.org/lightcodelabs/caddy2"
+ "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp"
+)
+
+func init() {
+ caddy2.RegisterModule(caddy2.Module{
+ Name: "http.middleware.headers",
+ New: func() (interface{}, error) { return new(Headers), nil },
+ })
+}
+
+// Headers is a middleware which can mutate HTTP headers.
+type Headers struct {
+ Request HeaderOps
+ Response RespHeaderOps
+}
+
+// HeaderOps defines some operations to
+// perform on HTTP headers.
+type HeaderOps struct {
+ Add http.Header
+ Set http.Header
+ Delete []string
+}
+
+// RespHeaderOps is like HeaderOps, but
+// optionally deferred until response time.
+type RespHeaderOps struct {
+ HeaderOps
+ Deferred bool `json:"deferred"`
+}
+
+func (h Headers) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
+ apply(h.Request, r.Header)
+ if h.Response.Deferred {
+ w = &responseWriterWrapper{
+ ResponseWriterWrapper: &caddyhttp.ResponseWriterWrapper{ResponseWriter: w},
+ headerOps: h.Response.HeaderOps,
+ }
+ } else {
+ apply(h.Response.HeaderOps, w.Header())
+ }
+ return next.ServeHTTP(w, r)
+}
+
+func apply(ops HeaderOps, hdr http.Header) {
+ for fieldName, vals := range ops.Add {
+ for _, v := range vals {
+ hdr.Add(fieldName, v)
+ }
+ }
+ for fieldName, vals := range ops.Set {
+ hdr.Set(fieldName, strings.Join(vals, ","))
+ }
+ for _, fieldName := range ops.Delete {
+ hdr.Del(fieldName)
+ }
+}
+
+// responseWriterWrapper defers response header
+// operations until WriteHeader is called.
+type responseWriterWrapper struct {
+ *caddyhttp.ResponseWriterWrapper
+ headerOps HeaderOps
+}
+
+func (rww *responseWriterWrapper) WriteHeader(status int) {
+ apply(rww.headerOps, rww.ResponseWriterWrapper.Header())
+ rww.ResponseWriterWrapper.WriteHeader(status)
+}
+
+// Interface guards
+var (
+ _ caddyhttp.MiddlewareHandler = (*Headers)(nil)
+ _ caddyhttp.HTTPInterfaces = (*responseWriterWrapper)(nil)
+)
diff --git a/modules/caddyhttp/headers/headers_test.go b/modules/caddyhttp/headers/headers_test.go
new file mode 100644
index 0000000..cb83d47
--- /dev/null
+++ b/modules/caddyhttp/headers/headers_test.go
@@ -0,0 +1,7 @@
+package headers
+
+import "testing"
+
+func TestReqHeaders(t *testing.T) {
+ // TODO: write tests
+}
diff --git a/modules/caddyhttp/staticfiles/matcher.go b/modules/caddyhttp/staticfiles/matcher.go
index cccf54b..9ce3f4c 100644
--- a/modules/caddyhttp/staticfiles/matcher.go
+++ b/modules/caddyhttp/staticfiles/matcher.go
@@ -16,6 +16,8 @@ func init() {
})
}
+// FileMatcher is a matcher that can match requests
+// based on the local file system.
// TODO: Not sure how to do this well; we'd need the ability to
// hide files, etc...
// TODO: Also consider a feature to match directory that
@@ -29,6 +31,7 @@ type FileMatcher struct {
Flags []string `json:"flags"`
}
+// Match matches the request r against m.
func (m FileMatcher) Match(r *http.Request) bool {
// TODO: sanitize path
fullPath := filepath.Join(m.Root, m.Path)