summaryrefslogtreecommitdiff
path: root/src/util/http.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/http.go')
-rw-r--r--src/util/http.go63
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)
+ }
+}