mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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.
This commit is contained in:
parent
b2fbb2691b
commit
0d85c63fff
@ -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)
|
||||
|
||||
// // 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)
|
||||
// }
|
||||
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"]
|
||||
}
|
||||
|
||||
c.JSON(500, resp)
|
||||
} else {
|
||||
c.HTML(500, "500")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
|
79
pkg/middleware/recovery_test.go
Normal file
79
pkg/middleware/recovery_test.go
Normal file
@ -0,0 +1,79 @@
|
||||
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)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user