diff options
Diffstat (limited to 'src/util/http.go')
-rw-r--r-- | src/util/http.go | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/util/http.go b/src/util/http.go new file mode 100644 index 0000000..6c216cf --- /dev/null +++ b/src/util/http.go @@ -0,0 +1,63 @@ +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) + } +} |