http/headers/headers.go
// Package headers provides header injection support.
package headers
import (
"net/http"
"os"
"github.com/apex/log"
"github.com/pkg/errors"
hdr "github.com/tj/go-headers"
"github.com/apex/up"
"github.com/apex/up/internal/header"
)
// TODO: document precedence and/or add options
// TODO: maybe allow storing _headers in Static.Dir?
// filename of headers file.
var filename = "_headers"
// New headers handler.
func New(c *up.Config, next http.Handler) (http.Handler, error) {
rulesFromFile, err := readFromFile(filename)
if err != nil {
return nil, errors.Wrap(err, "reading header file")
}
rules, err := header.Compile(header.Merge(rulesFromFile, c.Headers))
if err != nil {
return nil, errors.Wrap(err, "compiling header")
}
log.Debugf("header rules from _headers file: %d", len(rulesFromFile))
log.Debugf("header rules from up.json: %d", len(c.Headers))
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fields := rules.Lookup(r.URL.Path)
for k, v := range fields {
w.Header().Set(k, v)
}
next.ServeHTTP(w, r)
})
return h, nil
}
// readFromFile reads from a Netlify style headers file.
func readFromFile(path string) (header.Rules, error) {
rules := make(header.Rules)
f, err := os.Open(path)
if os.IsNotExist(err) {
return nil, nil
}
if err != nil {
return nil, errors.Wrap(err, "opening headers file")
}
defer f.Close()
h, err := hdr.Parse(f)
if err != nil {
return nil, errors.Wrap(err, "parsing")
}
for path, fields := range h {
rules[path] = make(header.Fields)
for name, vals := range fields {
rules[path][name] = vals[0]
}
}
return rules, nil
}