github.com/suedadam/up@v0.1.12/http/headers/headers.go (about) 1 // Package headers provides header injection support. 2 package headers 3 4 import ( 5 "net/http" 6 "os" 7 8 "github.com/apex/log" 9 "github.com/pkg/errors" 10 hdr "github.com/tj/go-headers" 11 12 "github.com/apex/up" 13 "github.com/apex/up/internal/header" 14 ) 15 16 // TODO: document precedence and/or add options 17 // TODO: maybe allow storing _headers in Static.Dir? 18 19 // filename of headers file. 20 var filename = "_headers" 21 22 // Headers handler injects headers. 23 type Headers struct { 24 next http.Handler 25 rules *header.Matcher 26 } 27 28 // New headers handler. 29 func New(c *up.Config, next http.Handler) (http.Handler, error) { 30 rulesFromFile, err := readFromFile(filename) 31 if err != nil { 32 return nil, errors.Wrap(err, "reading header file") 33 } 34 35 rules, err := header.Compile(header.Merge(rulesFromFile, c.Headers)) 36 if err != nil { 37 return nil, errors.Wrap(err, "compiling header") 38 } 39 40 log.Debugf("header rules from _headers file: %d", len(rulesFromFile)) 41 log.Debugf("header rules from up.json: %d", len(c.Headers)) 42 43 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 44 fields := rules.Lookup(r.URL.Path) 45 46 for k, v := range fields { 47 w.Header().Set(k, v) 48 } 49 50 next.ServeHTTP(w, r) 51 }) 52 53 return h, nil 54 } 55 56 // readFromFile reads from a Netlify style headers file. 57 func readFromFile(path string) (header.Rules, error) { 58 rules := make(header.Rules) 59 60 f, err := os.Open(path) 61 62 if os.IsNotExist(err) { 63 return nil, nil 64 } 65 66 if err != nil { 67 return nil, errors.Wrap(err, "opening headers file") 68 } 69 70 defer f.Close() 71 72 h, err := hdr.Parse(f) 73 if err != nil { 74 return nil, errors.Wrap(err, "parsing") 75 } 76 77 for path, fields := range h { 78 rules[path] = make(header.Fields) 79 for name, vals := range fields { 80 rules[path][name] = vals[0] 81 } 82 } 83 84 return rules, nil 85 }