Commit fd52570b by Marcus Efraimsson Committed by GitHub

API: Improve recovery middleware when response already been written (#22256)

Suppresses stacktrace in recovery middleware if error is
http.ErrAbortHandler.
Skips writing response error in recovery middleware if
resoonse have already been written.
Skips try rotate of auth token if response have already
been written.
Skips adding default response headers if response have
already been written.

Fixes #15728
Ref #18082

Co-Authored-By: Arve Knudsen <arve.knudsen@gmail.com>
parent 131610e8
......@@ -236,6 +236,11 @@ func initContextWithToken(authTokenService models.UserTokenService, ctx *models.
func rotateEndOfRequestFunc(ctx *models.ReqContext, authTokenService models.UserTokenService, token *models.UserToken) macaron.BeforeFunc {
return func(w macaron.ResponseWriter) {
// if response has already been written, skip.
if w.Written() {
return
}
// if the request is cancelled by the client we should not try
// to rotate the token since the client would not accept any result.
if ctx.Context.Req.Context().Err() == context.Canceled {
......@@ -273,6 +278,11 @@ func WriteSessionCookie(ctx *models.ReqContext, value string, maxLifetimeDays in
func AddDefaultResponseHeaders() macaron.Handler {
return func(ctx *macaron.Context) {
ctx.Resp.Before(func(w macaron.ResponseWriter) {
// if response has already been written, skip.
if w.Written() {
return
}
if !strings.HasPrefix(ctx.Req.URL.Path, "/api/datasources/proxy/") {
AddNoCacheHeaders(ctx.Resp)
}
......
......@@ -19,6 +19,7 @@ import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"runtime"
"gopkg.in/macaron.v1"
......@@ -102,8 +103,6 @@ func Recovery() macaron.Handler {
return func(c *macaron.Context) {
defer func() {
if err := recover(); err != nil {
stack := stack(3)
panicLogger := log.Root
// try to get request logger
if ctx, ok := c.Data["ctx"]; ok {
......@@ -111,8 +110,22 @@ func Recovery() macaron.Handler {
panicLogger = ctxTyped.Logger
}
// http.ErrAbortHandler is suppressed by default in the http package
// and used as a signal for aborting requests. Suppresses stacktrace
// since it doesn't add any important information.
if err == http.ErrAbortHandler {
panicLogger.Error("Request error", "error", err)
return
}
stack := stack(3)
panicLogger.Error("Request error", "error", err, "stack", string(stack))
// if response has already been written, skip.
if c.Written() {
return
}
c.Data["Title"] = "Server Error"
c.Data["AppSubUrl"] = setting.AppSubUrl
c.Data["Theme"] = setting.DefaultTheme
......
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