From 0385e601901f60531913f592dbb2be5e5d4fac9a Mon Sep 17 00:00:00 2001 From: Matt Jaffee Date: Tue, 18 Jul 2017 16:41:43 -0700 Subject: [PATCH 1/2] add recovery in top level handler --- handler.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/handler.go b/handler.go index bffb36947..d6b9c4d0c 100644 --- a/handler.go +++ b/handler.go @@ -29,6 +29,7 @@ import ( "net/http" _ "net/http/pprof" "os" + "runtime/debug" "strconv" "strings" "time" @@ -138,6 +139,16 @@ func (h *Handler) methodNotAllowedHandler(w http.ResponseWriter, r *http.Request // ServeHTTP handles an HTTP request. func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + defer func() { + if err := recover(); err != nil { + w.WriteHeader(http.StatusInternalServerError) + stack := debug.Stack() + msg := "PANIC: %s\n%s" + fmt.Fprintf(h.LogOutput, msg, err, stack) + fmt.Fprintf(w, msg, err, stack) + } + }() + t := time.Now() h.Router.ServeHTTP(w, r) dif := time.Since(t) From 24fc4a254d6a09067346600b2c61fef1d5358621 Mon Sep 17 00:00:00 2001 From: Matt Jaffee Date: Tue, 18 Jul 2017 17:04:26 -0700 Subject: [PATCH 2/2] add test for panic recovery --- handler_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/handler_test.go b/handler_test.go index b96b755fc..eb3bc9da1 100644 --- a/handler_test.go +++ b/handler_test.go @@ -32,6 +32,30 @@ import ( "github.com/pilosa/pilosa/test" ) +func TestHandlerPanics(t *testing.T) { + h := test.NewHandler() + buf := &bytes.Buffer{} + h.Handler.LogOutput = buf + + w := httptest.NewRecorder() + // will panic since Handler has no Holder set up + h.ServeHTTP(w, test.MustNewHTTPRequest("GET", "/index/taxi", nil)) + bufbytes, err := ioutil.ReadAll(buf) + if err != nil { + t.Fatalf("reading all logoutput: %v", err) + } + if !bytes.Contains(bufbytes, []byte("PANIC: runtime error: invalid memory address or nil pointer dereference")) { + t.Fatalf("expected panic in log, but got: %s", bufbytes) + } + if w.Code != http.StatusInternalServerError { + t.Fatalf("expected internal server error, but got: %v", w.Code) + } + bodyBytes := w.Body.Bytes() + if !bytes.Contains(bodyBytes, []byte("PANIC: runtime error: invalid memory address or nil pointer dereference")) { + t.Fatalf("response to client should have panic, but got %s", bodyBytes) + } +} + // Ensure the handler returns "not found" for invalid paths. func TestHandler_NotFound(t *testing.T) { hldr := test.MustOpenHolder()