prose/errorCatcher.go

74 lines
1.6 KiB
Go

package main
import (
"net/http"
"strconv"
"github.com/aymerick/raymond"
)
// errorCatcher is a wrapper for http.ResponseWriter that
// captures 4xx and 5xx status codes and handles them in
// a custom manner
type errorCatcher struct {
req *http.Request
res http.ResponseWriter
errorTpl *raymond.Template
notFoundTpl *raymond.Template
handledError bool
}
func (ec *errorCatcher) Header() http.Header {
return ec.res.Header()
}
func (ec *errorCatcher) Write(buf []byte) (int, error) {
// if we have already sent a response, pretend that this was successful
if ec.handledError {
return len(buf), nil
}
return ec.res.Write(buf)
}
func (ec *errorCatcher) WriteHeader(statusCode int) {
if ec.handledError {
return
}
if statusCode == 404 {
ctx := map[string]string{
"path": ec.req.URL.Path,
}
page, err := ec.notFoundTpl.Exec(ctx)
// if we don't have a page to write, return before
// we toggle the flag so we fall back to the original
// error page
if err != nil {
return
}
ec.res.Header().Add("content-type", "text/html")
ec.res.WriteHeader(statusCode)
ec.res.Write([]byte(page))
ec.handledError = true
return
}
if statusCode >= 400 && statusCode < 600 {
ctx := map[string]string{
"code": strconv.Itoa(statusCode),
}
page, err := ec.errorTpl.Exec(ctx)
// if we don't have a page to write, return before
// we toggle the flag so we fall back to the original
// error page
if err != nil {
return
}
ec.res.Header().Add("content-type", "text/html")
ec.res.WriteHeader(statusCode)
ec.res.Write([]byte(page))
ec.handledError = true
return
}
ec.res.WriteHeader(statusCode)
}