github.com/webonyx/up@v0.7.4-0.20180808230834-91b94e551323/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  // New headers handler.
    23  func New(c *up.Config, next http.Handler) (http.Handler, error) {
    24  	rulesFromFile, err := readFromFile(filename)
    25  	if err != nil {
    26  		return nil, errors.Wrap(err, "reading header file")
    27  	}
    28  
    29  	rules, err := header.Compile(header.Merge(rulesFromFile, c.Headers))
    30  	if err != nil {
    31  		return nil, errors.Wrap(err, "compiling header")
    32  	}
    33  
    34  	log.Debugf("header rules from _headers file: %d", len(rulesFromFile))
    35  	log.Debugf("header rules from up.json: %d", len(c.Headers))
    36  
    37  	h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    38  		fields := rules.Lookup(r.URL.Path)
    39  
    40  		for k, v := range fields {
    41  			w.Header().Set(k, v)
    42  		}
    43  
    44  		next.ServeHTTP(w, r)
    45  	})
    46  
    47  	return h, nil
    48  }
    49  
    50  // readFromFile reads from a Netlify style headers file.
    51  func readFromFile(path string) (header.Rules, error) {
    52  	rules := make(header.Rules)
    53  
    54  	f, err := os.Open(path)
    55  
    56  	if os.IsNotExist(err) {
    57  		return nil, nil
    58  	}
    59  
    60  	if err != nil {
    61  		return nil, errors.Wrap(err, "opening headers file")
    62  	}
    63  
    64  	defer f.Close()
    65  
    66  	h, err := hdr.Parse(f)
    67  	if err != nil {
    68  		return nil, errors.Wrap(err, "parsing")
    69  	}
    70  
    71  	for path, fields := range h {
    72  		rules[path] = make(header.Fields)
    73  		for name, vals := range fields {
    74  			rules[path][name] = vals[0]
    75  		}
    76  	}
    77  
    78  	return rules, nil
    79  }