Commit 0d85c63f by Daniel Lee

middleware: recovery handles panics in all handlers

Also, changes the order of the middleware so that recovery is after the
gzip middleware. Otherwise, a 200 OK is returned instead of a 500 error.
parent b2fbb269
......@@ -146,12 +146,13 @@ func (hs *HttpServer) newMacaron() *macaron.Macaron {
m := macaron.New()
m.Use(middleware.Logger())
m.Use(middleware.Recovery())
if setting.EnableGzip {
m.Use(middleware.Gziper())
}
m.Use(middleware.Recovery())
for _, route := range plugins.StaticRoutes {
pluginRoute := path.Join("/public/plugins/", route.PluginId)
hs.log.Debug("Plugins: Adding route", "route", pluginRoute, "dir", route.Directory)
......
......@@ -363,6 +363,7 @@ type scenarioContext struct {
respJson map[string]interface{}
handlerFunc handlerFunc
defaultHandler macaron.Handler
url string
req *http.Request
}
......
......@@ -123,23 +123,22 @@ func Recovery() macaron.Handler {
c.Data["ErrorMsg"] = string(stack)
}
c.HTML(500, "500")
ctx, ok := c.Data["ctx"].(*Context)
if ok && ctx.IsApiRequest() {
resp := make(map[string]interface{})
resp["message"] = "Internal Server Error - Check the Grafana server logs for the detailed error message."
if c.Data["ErrorMsg"] != nil {
resp["error"] = fmt.Sprintf("%v - %v", c.Data["Title"], c.Data["ErrorMsg"])
} else {
resp["error"] = c.Data["Title"]
}
// // Lookup the current responsewriter
// val := c.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
// res := val.Interface().(http.ResponseWriter)
//
// // respond with panic message while in development mode
// var body []byte
// if setting.Env == setting.DEV {
// res.Header().Set("Content-Type", "text/html")
// body = []byte(fmt.Sprintf(panicHtml, err, err, stack))
// }
//
// res.WriteHeader(http.StatusInternalServerError)
// if nil != body {
// res.Write(body)
// }
c.JSON(500, resp)
} else {
c.HTML(500, "500")
}
}
}()
......
package middleware
import (
"path/filepath"
"testing"
"github.com/go-macaron/session"
"github.com/grafana/grafana/pkg/bus"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/macaron.v1"
)
func TestRecoveryMiddleware(t *testing.T) {
Convey("Given an api route that panics", t, func() {
apiUrl := "/api/whatever"
recoveryScenario("recovery middleware should return json", apiUrl, func(sc *scenarioContext) {
sc.handlerFunc = PanicHandler
sc.fakeReq("GET", apiUrl).exec()
sc.req.Header.Add("content-type", "application/json")
So(sc.resp.Code, ShouldEqual, 500)
So(sc.respJson["message"], ShouldStartWith, "Internal Server Error - Check the Grafana server logs for the detailed error message.")
So(sc.respJson["error"], ShouldStartWith, "Server Error")
})
})
Convey("Given a non-api route that panics", t, func() {
apiUrl := "/whatever"
recoveryScenario("recovery middleware should return html", apiUrl, func(sc *scenarioContext) {
sc.handlerFunc = PanicHandler
sc.fakeReq("GET", apiUrl).exec()
So(sc.resp.Code, ShouldEqual, 500)
So(sc.resp.Header().Get("content-type"), ShouldEqual, "text/html; charset=UTF-8")
So(sc.resp.Body.String(), ShouldContainSubstring, "<title>Grafana - Error</title>")
})
})
}
func PanicHandler(c *Context) {
panic("Handler has panicked")
}
func recoveryScenario(desc string, url string, fn scenarioFunc) {
Convey(desc, func() {
defer bus.ClearBusHandlers()
sc := &scenarioContext{
url: url,
}
viewsPath, _ := filepath.Abs("../../public/views")
sc.m = macaron.New()
sc.m.Use(Recovery())
sc.m.Use(macaron.Renderer(macaron.RenderOptions{
Directory: viewsPath,
Delims: macaron.Delims{Left: "[[", Right: "]]"},
}))
sc.m.Use(GetContextHandler())
// mock out gc goroutine
startSessionGC = func() {}
sc.m.Use(Sessioner(&session.Options{}))
sc.m.Use(OrgRedirect())
sc.m.Use(AddDefaultResponseHeaders())
sc.defaultHandler = func(c *Context) {
sc.context = c
if sc.handlerFunc != nil {
sc.handlerFunc(sc.context)
}
}
sc.m.Get(url, sc.defaultHandler)
fn(sc)
})
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment