// Copyright 2014 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 web import ( "fmt" "html/template" "net/http" "reflect" "runtime" "strconv" "strings" "github.com/astaxie/beego/pkg" "github.com/astaxie/beego/pkg/infrastructure/utils" "github.com/astaxie/beego/pkg/server/web/context" ) const ( errorTypeHandler = iota errorTypeController ) var tpl = ` beego application error
Request Method: {{.RequestMethod}}
Request URL: {{.RequestURL}}
RemoteAddr: {{.RemoteAddr }}
Stack
{{.Stack}}
` // render default application error page with error and stack string. func showErr(err interface{}, ctx *context.Context, stack string) { t, _ := template.New("beegoerrortemp").Parse(tpl) data := map[string]string{ "AppError": fmt.Sprintf("%s:%v", BConfig.AppName, err), "RequestMethod": ctx.Input.Method(), "RequestURL": ctx.Input.URI(), "RemoteAddr": ctx.Input.IP(), "Stack": stack, "BeegoVersion": pkg.VERSION, "GoVersion": runtime.Version(), } t.Execute(ctx.ResponseWriter, data) } var errtpl = ` {{.Title}}
{{.Content}} Go Home

Powered by beego {{.BeegoVersion}}
` type errorInfo struct { controllerType reflect.Type handler http.HandlerFunc method string errorType int } // ErrorMaps holds map of http handlers for each error string. // there is 10 kinds default error(40x and 50x) var ErrorMaps = make(map[string]*errorInfo, 10) // show 401 unauthorized error. func unauthorized(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 401, "
The page you have requested can't be authorized."+ "
Perhaps you are here because:"+ "

", ) } // show 402 Payment Required func paymentRequired(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 402, "
The page you have requested Payment Required."+ "
Perhaps you are here because:"+ "

", ) } // show 403 forbidden error. func forbidden(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 403, "
The page you have requested is forbidden."+ "
Perhaps you are here because:"+ "

", ) } // show 422 missing xsrf token func missingxsrf(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 422, "
The page you have requested is forbidden."+ "
Perhaps you are here because:"+ "

", ) } // show 417 invalid xsrf token func invalidxsrf(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 417, "
The page you have requested is forbidden."+ "
Perhaps you are here because:"+ "

", ) } // show 404 not found error. func notFound(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 404, "
The page you have requested has flown the coop."+ "
Perhaps you are here because:"+ "

", ) } // show 405 Method Not Allowed func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 405, "
The method you have requested Not Allowed."+ "
Perhaps you are here because:"+ "

", ) } // show 500 internal server error. func internalServerError(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 500, "
The page you have requested is down right now."+ "

", ) } // show 501 Not Implemented. func notImplemented(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 501, "
The page you have requested is Not Implemented."+ "

", ) } // show 502 Bad Gateway. func badGateway(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 502, "
The page you have requested is down right now."+ "

", ) } // show 503 service unavailable error. func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 503, "
The page you have requested is unavailable."+ "
Perhaps you are here because:"+ "

", ) } // show 504 Gateway Timeout. func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 504, "
The page you have requested is unavailable"+ "
Perhaps you are here because:"+ "

", ) } // show 413 Payload Too Large func payloadTooLarge(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, 413, `
The page you have requested is unavailable.
Perhaps you are here because:

`, ) } func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) { t, _ := template.New("beegoerrortemp").Parse(errtpl) data := M{ "Title": http.StatusText(errCode), "BeegoVersion": pkg.VERSION, "Content": template.HTML(errContent), } t.Execute(rw, data) } // ErrorHandler registers http.HandlerFunc to each http err code string. // usage: // beego.ErrorHandler("404",NotFound) // beego.ErrorHandler("500",InternalServerError) func ErrorHandler(code string, h http.HandlerFunc) *App { ErrorMaps[code] = &errorInfo{ errorType: errorTypeHandler, handler: h, method: code, } return BeeApp } // ErrorController registers ControllerInterface to each http err code string. // usage: // beego.ErrorController(&controllers.ErrorController{}) func ErrorController(c ControllerInterface) *App { reflectVal := reflect.ValueOf(c) rt := reflectVal.Type() ct := reflect.Indirect(reflectVal).Type() for i := 0; i < rt.NumMethod(); i++ { methodName := rt.Method(i).Name if !utils.InSlice(methodName, exceptMethod) && strings.HasPrefix(methodName, "Error") { errName := strings.TrimPrefix(methodName, "Error") ErrorMaps[errName] = &errorInfo{ errorType: errorTypeController, controllerType: ct, method: methodName, } } } return BeeApp } // Exception Write HttpStatus with errCode and Exec error handler if exist. func Exception(errCode uint64, ctx *context.Context) { exception(strconv.FormatUint(errCode, 10), ctx) } // show error string as simple text message. // if error string is empty, show 503 or 500 error as default. func exception(errCode string, ctx *context.Context) { atoi := func(code string) int { v, err := strconv.Atoi(code) if err == nil { return v } if ctx.Output.Status == 0 { return 503 } return ctx.Output.Status } for _, ec := range []string{errCode, "503", "500"} { if h, ok := ErrorMaps[ec]; ok { executeError(h, ctx, atoi(ec)) return } } //if 50x error has been removed from errorMap ctx.ResponseWriter.WriteHeader(atoi(errCode)) ctx.WriteString(errCode) } func executeError(err *errorInfo, ctx *context.Context, code int) { //make sure to log the error in the access log LogAccess(ctx, nil, code) if err.errorType == errorTypeHandler { ctx.ResponseWriter.WriteHeader(code) err.handler(ctx.ResponseWriter, ctx.Request) return } if err.errorType == errorTypeController { ctx.Output.SetStatus(code) //Invoke the request handler vc := reflect.New(err.controllerType) execController, ok := vc.Interface().(ControllerInterface) if !ok { panic("controller is not ControllerInterface") } //call the controller init function execController.Init(ctx, err.controllerType.Name(), err.method, vc.Interface()) //call prepare function execController.Prepare() execController.URLMapping() method := vc.MethodByName(err.method) method.Call([]reflect.Value{}) //render template if BConfig.WebConfig.AutoRender { if err := execController.Render(); err != nil { panic(err) } } // finish all runrouter. release resource execController.Finish() } }