github.com/jalateras/up@v0.1.5/http/errorpages/errorpages.go (about) 1 // Package errorpages provides default and customizable 2 // error pages, via error.html, 5xx.html, or 500.html 3 // for example. 4 package errorpages 5 6 import ( 7 "io" 8 "net/http" 9 10 "github.com/pkg/errors" 11 accept "github.com/timewasted/go-accept-headers" 12 13 "github.com/apex/up" 14 "github.com/apex/up/internal/errorpage" 15 "github.com/apex/up/internal/logs" 16 "github.com/apex/up/internal/util" 17 ) 18 19 // log context. 20 var ctx = logs.Plugin("errorpages") 21 22 // response wrapper. 23 type response struct { 24 http.ResponseWriter 25 config *up.Config 26 pages errorpage.Pages 27 header bool 28 ignore bool 29 } 30 31 // WriteHeader implementation. 32 func (r *response) WriteHeader(code int) { 33 w := r.ResponseWriter 34 35 r.header = true 36 page := r.pages.Match(code) 37 38 if page == nil { 39 ctx.Debugf("did not match %d", code) 40 w.WriteHeader(code) 41 return 42 } 43 44 ctx.Debugf("matched %d with %q", code, page.Name) 45 46 data := struct { 47 StatusText string 48 StatusCode int 49 Variables map[string]interface{} 50 }{ 51 StatusText: http.StatusText(code), 52 StatusCode: code, 53 Variables: r.config.ErrorPages.Variables, 54 } 55 56 html, err := page.Render(data) 57 if err != nil { 58 ctx.WithError(err).Error("rendering error page") 59 http.Error(w, "Error rendering error page.", http.StatusInternalServerError) 60 return 61 } 62 63 r.ignore = true 64 util.ClearHeader(w.Header()) 65 w.Header().Set("Vary", "Accept") 66 w.Header().Set("Content-Type", "text/html; charset=utf-8") 67 w.WriteHeader(code) 68 io.WriteString(w, html) 69 } 70 71 // Write implementation. 72 func (r *response) Write(b []byte) (int, error) { 73 if r.ignore { 74 return len(b), nil 75 } 76 77 if !r.header { 78 r.WriteHeader(200) 79 return r.Write(b) 80 } 81 82 return r.ResponseWriter.Write(b) 83 } 84 85 // Errors handles error page support. 86 type Errors struct { 87 next http.Handler 88 pages errorpage.Pages 89 } 90 91 // New error pages handler. 92 func New(c *up.Config, next http.Handler) (http.Handler, error) { 93 pages, err := errorpage.Load(c.ErrorPages.Dir) 94 if err != nil { 95 return nil, errors.Wrap(err, "loading error pages") 96 } 97 98 h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 99 mime, _ := accept.Negotiate(r.Header.Get("Accept"), "text/html") 100 101 if mime == "" { 102 next.ServeHTTP(w, r) 103 return 104 } 105 106 res := &response{ResponseWriter: w, pages: pages, config: c} 107 next.ServeHTTP(res, r) 108 }) 109 110 return h, nil 111 }