1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-26 05:21:30 +00:00

Merge pull request #1805 from JessonChan/abort_panic_bug

Abort panic bug
This commit is contained in:
astaxie 2016-03-23 10:22:32 +08:00
commit 6c0979c314
5 changed files with 207 additions and 135 deletions

View File

@ -77,6 +77,7 @@ func (ctx *Context) Redirect(status int, localurl string) {
// Abort stops this request. // Abort stops this request.
// if beego.ErrorMaps exists, panic body. // if beego.ErrorMaps exists, panic body.
func (ctx *Context) Abort(status int, body string) { func (ctx *Context) Abort(status int, body string) {
ctx.Output.SetStatus(status)
panic(body) panic(body)
} }

View File

@ -261,12 +261,13 @@ func (c *Controller) Abort(code string) {
// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
func (c *Controller) CustomAbort(status int, body string) { func (c *Controller) CustomAbort(status int, body string) {
c.Ctx.Output.Status = status
// first panic from ErrorMaps, is is user defined error functions. // first panic from ErrorMaps, is is user defined error functions.
if _, ok := ErrorMaps[body]; ok { if _, ok := ErrorMaps[body]; ok {
c.Ctx.Output.Status = status
panic(body) panic(body)
} }
// last panic user string // last panic user string
c.Ctx.ResponseWriter.WriteHeader(status)
c.Ctx.ResponseWriter.Write([]byte(body)) c.Ctx.ResponseWriter.Write([]byte(body))
panic(ErrAbort) panic(ErrAbort)
} }

213
error.go
View File

@ -210,159 +210,139 @@ var ErrorMaps = make(map[string]*errorInfo, 10)
// show 401 unauthorized error. // show 401 unauthorized error.
func unauthorized(rw http.ResponseWriter, r *http.Request) { func unauthorized(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 401,
"Title": http.StatusText(401), "<br>The page you have requested can't be authorized."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The page you have requested can't be authorized." + "<br>The credentials you supplied are incorrect"+
"<br>Perhaps you are here because:" + "<br>There are errors in the website address"+
"<br><br><ul>" + "</ul>",
"<br>The credentials you supplied are incorrect" + )
"<br>There are errors in the website address" +
"</ul>")
t.Execute(rw, data)
} }
// show 402 Payment Required // show 402 Payment Required
func paymentRequired(rw http.ResponseWriter, r *http.Request) { func paymentRequired(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 402,
"Title": http.StatusText(402), "<br>The page you have requested Payment Required."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The page you have requested Payment Required." + "<br>The credentials you supplied are incorrect"+
"<br>Perhaps you are here because:" + "<br>There are errors in the website address"+
"<br><br><ul>" + "</ul>",
"<br>The credentials you supplied are incorrect" + )
"<br>There are errors in the website address" +
"</ul>")
t.Execute(rw, data)
} }
// show 403 forbidden error. // show 403 forbidden error.
func forbidden(rw http.ResponseWriter, r *http.Request) { func forbidden(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 403,
"Title": http.StatusText(403), "<br>The page you have requested is forbidden."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The page you have requested is forbidden." + "<br>Your address may be blocked"+
"<br>Perhaps you are here because:" + "<br>The site may be disabled"+
"<br><br><ul>" + "<br>You need to log in"+
"<br>Your address may be blocked" + "</ul>",
"<br>The site may be disabled" + )
"<br>You need to log in" +
"</ul>")
t.Execute(rw, data)
} }
// show 404 notfound error. // show 404 not found error.
func notFound(rw http.ResponseWriter, r *http.Request) { func notFound(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 404,
"Title": http.StatusText(404), "<br>The page you have requested has flown the coop."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The page you have requested has flown the coop." + "<br>The page has moved"+
"<br>Perhaps you are here because:" + "<br>The page no longer exists"+
"<br><br><ul>" + "<br>You were looking for your puppy and got lost"+
"<br>The page has moved" + "<br>You like 404 pages"+
"<br>The page no longer exists" + "</ul>",
"<br>You were looking for your puppy and got lost" + )
"<br>You like 404 pages" +
"</ul>")
t.Execute(rw, data)
} }
// show 405 Method Not Allowed // show 405 Method Not Allowed
func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 405,
"Title": http.StatusText(405), "<br>The method you have requested Not Allowed."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The method you have requested Not Allowed." + "<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI"+
"<br>Perhaps you are here because:" + "<br>The response MUST include an Allow header containing a list of valid methods for the requested resource."+
"<br><br><ul>" + "</ul>",
"<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI" + )
"<br>The response MUST include an Allow header containing a list of valid methods for the requested resource." +
"</ul>")
t.Execute(rw, data)
} }
// show 500 internal server error. // show 500 internal server error.
func internalServerError(rw http.ResponseWriter, r *http.Request) { func internalServerError(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 500,
"Title": http.StatusText(500), "<br>The page you have requested is down right now."+
"BeegoVersion": VERSION, "<br><br><ul>"+
} "<br>Please try again later and report the error to the website administrator"+
data["Content"] = template.HTML("<br>The page you have requested is down right now." + "<br></ul>",
"<br><br><ul>" + )
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>")
t.Execute(rw, data)
} }
// show 501 Not Implemented. // show 501 Not Implemented.
func notImplemented(rw http.ResponseWriter, r *http.Request) { func notImplemented(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 501,
"Title": http.StatusText(504), "<br>The page you have requested is Not Implemented."+
"BeegoVersion": VERSION, "<br><br><ul>"+
} "<br>Please try again later and report the error to the website administrator"+
data["Content"] = template.HTML("<br>The page you have requested is Not Implemented." + "<br></ul>",
"<br><br><ul>" + )
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>")
t.Execute(rw, data)
} }
// show 502 Bad Gateway. // show 502 Bad Gateway.
func badGateway(rw http.ResponseWriter, r *http.Request) { func badGateway(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 502,
"Title": http.StatusText(502), "<br>The page you have requested is down right now."+
"BeegoVersion": VERSION, "<br><br><ul>"+
} "<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request."+
data["Content"] = template.HTML("<br>The page you have requested is down right now." + "<br>Please try again later and report the error to the website administrator"+
"<br><br><ul>" + "<br></ul>",
"<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request." + )
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>")
t.Execute(rw, data)
} }
// show 503 service unavailable error. // show 503 service unavailable error.
func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) responseError(rw, r,
data := map[string]interface{}{ 503,
"Title": http.StatusText(503), "<br>The page you have requested is unavailable."+
"BeegoVersion": VERSION, "<br>Perhaps you are here because:"+
} "<br><br><ul>"+
data["Content"] = template.HTML("<br>The page you have requested is unavailable." + "<br><br>The page is overloaded"+
"<br>Perhaps you are here because:" + "<br>Please try again later."+
"<br><br><ul>" + "</ul>",
"<br><br>The page is overloaded" + )
"<br>Please try again later." +
"</ul>")
t.Execute(rw, data)
} }
// show 504 Gateway Timeout. // show 504 Gateway Timeout.
func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
responseError(rw, r,
504,
"<br>The page you have requested is unavailable"+
"<br>Perhaps you are here because:"+
"<br><br><ul>"+
"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI."+
"<br>Please try again later."+
"</ul>",
)
}
func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) {
t, _ := template.New("beegoerrortemp").Parse(errtpl) t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := map[string]interface{}{ data := map[string]interface{}{
"Title": http.StatusText(504), "Title": http.StatusText(errCode),
"BeegoVersion": VERSION, "BeegoVersion": VERSION,
"Content": errContent,
} }
data["Content"] = template.HTML("<br>The page you have requested is unavailable." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI." +
"<br>Please try again later." +
"</ul>")
t.Execute(rw, data) t.Execute(rw, data)
} }
@ -408,7 +388,10 @@ func exception(errCode string, ctx *context.Context) {
if err == nil { if err == nil {
return v return v
} }
return 503 if ctx.Output.Status == 0 {
return 503
}
return ctx.Output.Status
} }
for _, ec := range []string{errCode, "503", "500"} { for _, ec := range []string{errCode, "503", "500"} {

88
error_test.go Normal file
View File

@ -0,0 +1,88 @@
// Copyright 2016 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package beego
import (
"net/http"
"net/http/httptest"
"strconv"
"strings"
"testing"
)
type errorTestController struct {
Controller
}
const parseCodeError = "parse code error"
func (ec *errorTestController) Get() {
errorCode, err := ec.GetInt("code")
if err != nil {
ec.Abort(parseCodeError)
}
if errorCode != 0 {
ec.CustomAbort(errorCode, ec.GetString("code"))
}
ec.Abort("404")
}
func TestErrorCode_01(t *testing.T) {
registerDefaultErrorHandler()
for k, _ := range ErrorMaps {
r, _ := http.NewRequest("GET", "/error?code="+k, nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/error", &errorTestController{})
handler.ServeHTTP(w, r)
code, _ := strconv.Atoi(k)
if w.Code != code {
t.Fail()
}
if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) {
t.Fail()
}
}
}
func TestErrorCode_02(t *testing.T) {
registerDefaultErrorHandler()
r, _ := http.NewRequest("GET", "/error?code=0", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/error", &errorTestController{})
handler.ServeHTTP(w, r)
if w.Code != 404 {
t.Fail()
}
}
func TestErrorCode_03(t *testing.T) {
registerDefaultErrorHandler()
r, _ := http.NewRequest("GET", "/error?code=panic", nil)
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/error", &errorTestController{})
handler.ServeHTTP(w, r)
if w.Code != 200 {
t.Fail()
}
if string(w.Body.Bytes()) != parseCodeError {
t.Fail()
}
}

View File

@ -842,27 +842,26 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) {
} }
if !BConfig.RecoverPanic { if !BConfig.RecoverPanic {
panic(err) panic(err)
} else { }
if BConfig.EnableErrorsShow { if BConfig.EnableErrorsShow {
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
exception(fmt.Sprint(err), context) exception(fmt.Sprint(err), context)
return return
}
} }
var stack string }
Critical("the request url is ", context.Input.URL()) var stack string
Critical("Handler crashed with error", err) Critical("the request url is ", context.Input.URL())
for i := 1; ; i++ { Critical("Handler crashed with error", err)
_, file, line, ok := runtime.Caller(i) for i := 1; ; i++ {
if !ok { _, file, line, ok := runtime.Caller(i)
break if !ok {
} break
Critical(fmt.Sprintf("%s:%d", file, line))
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
}
if BConfig.RunMode == DEV {
showErr(err, context, stack)
} }
Critical(fmt.Sprintf("%s:%d", file, line))
stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
}
if BConfig.RunMode == DEV {
showErr(err, context, stack)
} }
} }
} }