package util import ( "bytes" "fmt" "log" "net/http" "runtime" "strconv" ) type httpResponseBuffer struct { inner http.ResponseWriter buf bytes.Buffer status int } func (o *httpResponseBuffer) Header() http.Header { return o.inner.Header() } func (o *httpResponseBuffer) Write(data []byte) (int, error) { return o.buf.Write(data) } func (o *httpResponseBuffer) WriteHeader(status int) { o.status = status } type SaneHTTPHandler struct { Inner http.Handler } func (h SaneHTTPHandler) ServeHTTP(out http.ResponseWriter, in *http.Request) { HTTPHandlerFuncWrapper(out, in, h.Inner.ServeHTTP) } func HTTPHandlerFuncWrapper(out http.ResponseWriter, in *http.Request, fn http.HandlerFunc) { buf := httpResponseBuffer{ inner: out, status: http.StatusOK, } ok := true func() { defer func() { if r := recover(); r != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] st := fmt.Sprintf("%[1]T(%#[1]v) => %[1]v\n\n%[2]s", r, string(buf)) log.Printf("panic serving %v\n\n%s", in.URL, st) http.Error(out, fmt.Sprintf("500 Internal Server Error:\n\n%s", st), 500) ok = false } }() fn(&buf, in) }() if ok { out.Header().Set("Content-Length", strconv.Itoa(buf.buf.Len())) out.WriteHeader(buf.status) buf.buf.WriteTo(out) } }