2014-08-18 08:41:43 +00:00
// Copyright 2014 beego Author. All Rights Reserved.
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// 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
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// 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.
2015-02-26 15:34:43 +00:00
package beego
2013-09-09 16:00:11 +00:00
import (
"fmt"
"html/template"
"net/http"
2015-02-26 15:34:43 +00:00
"reflect"
2013-09-09 16:00:11 +00:00
"runtime"
2013-09-11 09:00:39 +00:00
"strconv"
2015-02-26 15:34:43 +00:00
"strings"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/utils"
2013-09-09 16:00:11 +00:00
)
2015-02-26 15:34:43 +00:00
const (
errorTypeHandler = iota
errorTypeController
2013-09-11 08:31:18 +00:00
)
2015-02-26 15:34:43 +00:00
2013-09-09 16:00:11 +00:00
var tpl = `
2013-12-06 05:44:54 +00:00
< ! DOCTYPE html >
< html >
2013-09-09 16:00:11 +00:00
< head >
< meta http - equiv = "Content-Type" content = "text/html; charset=UTF-8" / >
< title > beego application error < / title >
< style >
html , body , body * { padding : 0 ; margin : 0 ; }
# header { background : # ffd ; border - bottom : solid 2 px # A31515 ; padding : 20 px 10 px ; }
# header h2 { }
# footer { border - top : solid 1 px # aaa ; padding : 5 px 10 px ; font - size : 12 px ; color : green ; }
# content { padding : 5 px ; }
# content . stack b { font - size : 13 px ; color : red ; }
# content . stack pre { padding - left : 10 px ; }
table { }
td . t { text - align : right ; padding - right : 5 px ; color : # 888 ; }
2013-12-06 05:44:54 +00:00
< / style >
2013-09-09 16:00:11 +00:00
< script type = "text/javascript" >
< / script >
2013-12-06 05:44:54 +00:00
< / head >
2013-09-09 16:00:11 +00:00
< body >
< div id = "header" >
< h2 > { { . AppError } } < / h2 >
< / div >
< div id = "content" >
< table >
< tr >
< td class = "t" > Request Method : < / td > < td > { { . RequestMethod } } < / td >
< / tr >
< tr >
< td class = "t" > Request URL : < / td > < td > { { . RequestURL } } < / td >
< / tr >
< tr >
< td class = "t" > RemoteAddr : < / td > < td > { { . RemoteAddr } } < / td >
< / tr >
< / table >
< div class = "stack" >
< b > Stack < / b >
< pre > { { . Stack } } < / pre >
< / div >
< / div >
< div id = "footer" >
< p > beego { { . BeegoVersion } } ( beego framework ) < / p >
< p > golang version : { { . GoVersion } } < / p >
< / div >
< / body >
2013-12-06 05:44:54 +00:00
< / html >
2013-09-09 16:00:11 +00:00
`
2014-01-17 08:03:01 +00:00
// render default application error page with error and stack string.
2015-02-26 15:34:43 +00:00
func showErr ( err interface { } , ctx * context . Context , Stack string ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( tpl )
data := make ( map [ string ] string )
data [ "AppError" ] = AppName + ":" + fmt . Sprint ( err )
2015-02-26 15:34:43 +00:00
data [ "RequestMethod" ] = ctx . Input . Method ( )
data [ "RequestURL" ] = ctx . Input . Uri ( )
data [ "RemoteAddr" ] = ctx . Input . IP ( )
2013-09-09 16:00:11 +00:00
data [ "Stack" ] = Stack
data [ "BeegoVersion" ] = VERSION
data [ "GoVersion" ] = runtime . Version ( )
2015-05-05 13:36:31 +00:00
ctx . ResponseWriter . WriteHeader ( 500 )
2015-02-26 15:34:43 +00:00
t . Execute ( ctx . ResponseWriter , data )
2013-09-09 16:00:11 +00:00
}
var errtpl = `
< ! DOCTYPE html >
< html lang = "en" >
< head >
< meta http - equiv = "Content-Type" content = "text/html; charset=UTF-8" >
< title > { { . Title } } < / title >
< style type = "text/css" >
* {
margin : 0 ;
padding : 0 ;
}
body {
background - color : # EFEFEF ;
font : .9 em "Lucida Sans Unicode" , "Lucida Grande" , sans - serif ;
}
# wrapper {
width : 600 px ;
margin : 40 px auto 0 ;
text - align : center ;
- moz - box - shadow : 5 px 5 px 10 px rgba ( 0 , 0 , 0 , 0.3 ) ;
- webkit - box - shadow : 5 px 5 px 10 px rgba ( 0 , 0 , 0 , 0.3 ) ;
box - shadow : 5 px 5 px 10 px rgba ( 0 , 0 , 0 , 0.3 ) ;
}
# wrapper h1 {
color : # FFF ;
text - align : center ;
margin - bottom : 20 px ;
}
# wrapper a {
display : block ;
font - size : .9 em ;
padding - top : 20 px ;
color : # FFF ;
text - decoration : none ;
text - align : center ;
}
# container {
width : 600 px ;
padding - bottom : 15 px ;
background - color : # FFFFFF ;
}
. navtop {
height : 40 px ;
background - color : # 24 B2EB ;
padding : 13 px ;
}
. content {
padding : 10 px 10 px 25 px ;
background : # FFFFFF ;
margin : ;
color : # 333 ;
}
a . button {
color : white ;
padding : 15 px 20 px ;
text - shadow : 1 px 1 px 0 # 00 A5FF ;
font - weight : bold ;
text - align : center ;
border : 1 px solid # 24 B2EB ;
margin : 0 px 200 px ;
clear : both ;
background - color : # 24 B2EB ;
border - radius : 100 px ;
- moz - border - radius : 100 px ;
- webkit - border - radius : 100 px ;
}
a . button : hover {
text - decoration : none ;
background - color : # 24 B2EB ;
}
< / style >
< / head >
< body >
< div id = "wrapper" >
< div id = "container" >
< div class = "navtop" >
< h1 > { { . Title } } < / h1 >
< / div >
< div id = "content" >
{ { . Content } }
< a href = "/" title = "Home" class = "button" > Go Home < / a > < br / >
2014-02-10 04:55:53 +00:00
< br > Powered by beego { { . BeegoVersion } }
2013-09-09 16:00:11 +00:00
< / div >
< / div >
< / div >
< / body >
< / html >
`
2015-02-26 15:34:43 +00:00
type errorInfo struct {
controllerType reflect . Type
handler http . HandlerFunc
method string
errorType int
}
2014-01-17 08:03:01 +00:00
// map of http handlers for each error string.
2015-02-26 15:34:43 +00:00
var ErrorMaps map [ string ] * errorInfo
2013-09-09 16:00:11 +00:00
func init ( ) {
2015-02-26 15:34:43 +00:00
ErrorMaps = make ( map [ string ] * errorInfo )
2013-09-09 16:00:11 +00:00
}
2015-02-26 15:49:24 +00:00
// show 401 unauthorized error.
func unauthorized ( rw http . ResponseWriter , r * http . Request ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
2015-02-26 15:49:24 +00:00
data [ "Title" ] = "Unauthorized"
data [ "Content" ] = template . HTML ( "<br>The page you have requested can't be authorized." +
2013-09-09 16:00:11 +00:00
"<br>Perhaps you are here because:" +
2014-01-02 14:54:15 +00:00
"<br><br><ul>" +
2015-02-26 15:49:24 +00:00
"<br>The credentials you supplied are incorrect" +
"<br>There are errors in the website address" +
2013-09-09 16:00:11 +00:00
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
2015-02-26 15:49:24 +00:00
// show 402 Payment Required
func paymentRequired ( rw http . ResponseWriter , r * http . Request ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
2015-02-26 15:49:24 +00:00
data [ "Title" ] = "Payment Required"
data [ "Content" ] = template . HTML ( "<br>The page you have requested Payment Required." +
2013-09-09 16:00:11 +00:00
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
2014-01-02 14:53:09 +00:00
"<br>The credentials you supplied are incorrect" +
"<br>There are errors in the website address" +
2013-09-09 16:00:11 +00:00
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
2014-01-17 08:03:01 +00:00
// show 403 forbidden error.
2015-02-26 15:49:24 +00:00
func forbidden ( rw http . ResponseWriter , r * http . Request ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Forbidden"
2014-01-02 14:53:09 +00:00
data [ "Content" ] = template . HTML ( "<br>The page you have requested is forbidden." +
2013-09-09 16:00:11 +00:00
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br>Your address may be blocked" +
"<br>The site may be disabled" +
"<br>You need to log in" +
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
2015-02-26 15:49:24 +00:00
// show 404 notfound error.
func notFound ( rw http . ResponseWriter , r * http . Request ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
2015-02-26 15:49:24 +00:00
data [ "Title" ] = "Page Not Found"
data [ "Content" ] = template . HTML ( "<br>The page you have requested has flown the coop." +
2013-09-09 16:00:11 +00:00
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
2015-02-26 15:49:24 +00:00
"<br>The page has moved" +
"<br>The page no longer exists" +
"<br>You were looking for your puppy and got lost" +
"<br>You like 404 pages" +
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
// show 405 Method Not Allowed
func methodNotAllowed ( rw http . ResponseWriter , r * http . Request ) {
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Method Not Allowed"
data [ "Content" ] = template . HTML ( "<br>The method you have requested Not Allowed." +
"<br>Perhaps you are here because:" +
"<br><br><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." +
2013-09-09 16:00:11 +00:00
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
2014-01-17 08:03:01 +00:00
// show 500 internal server error.
2015-02-26 15:49:24 +00:00
func internalServerError ( rw http . ResponseWriter , r * http . Request ) {
2013-09-09 16:00:11 +00:00
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Internal Server Error"
2014-01-02 14:53:09 +00:00
data [ "Content" ] = template . HTML ( "<br>The page you have requested is down right now." +
2013-09-09 16:00:11 +00:00
"<br><br><ul>" +
2014-01-02 14:53:09 +00:00
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>" )
2013-09-09 16:00:11 +00:00
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
2015-02-26 15:49:24 +00:00
// show 501 Not Implemented.
func notImplemented ( rw http . ResponseWriter , r * http . Request ) {
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Not Implemented"
data [ "Content" ] = template . HTML ( "<br>The page you have requested is Not Implemented." +
"<br><br><ul>" +
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
// show 502 Bad Gateway.
func badGateway ( rw http . ResponseWriter , r * http . Request ) {
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Bad Gateway"
data [ "Content" ] = template . HTML ( "<br>The page you have requested is down right now." +
"<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." +
"<br>Please try again later and report the error to the website administrator" +
"<br></ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
// show 503 service unavailable error.
func serviceUnavailable ( rw http . ResponseWriter , r * http . Request ) {
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Service Unavailable"
data [ "Content" ] = template . HTML ( "<br>The page you have requested is unavailable." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br><br>The page is overloaded" +
"<br>Please try again later." +
"</ul>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
}
// show 504 Gateway Timeout.
func gatewayTimeout ( rw http . ResponseWriter , r * http . Request ) {
t , _ := template . New ( "beegoerrortemp" ) . Parse ( errtpl )
data := make ( map [ string ] interface { } )
data [ "Title" ] = "Gateway Timeout"
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>" )
data [ "BeegoVersion" ] = VERSION
t . Execute ( rw , data )
2013-12-06 05:44:54 +00:00
}
2015-02-26 15:34:43 +00:00
// 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 {
errinfo := & errorInfo { }
errinfo . errorType = errorTypeHandler
errinfo . handler = h
errinfo . method = code
ErrorMaps [ code ] = errinfo
return BeeApp
}
// ErrorController registers ControllerInterface to each http err code string.
// usage:
// beego.ErrorHandler(&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 ++ {
if ! utils . InSlice ( rt . Method ( i ) . Name , exceptMethod ) && strings . HasPrefix ( rt . Method ( i ) . Name , "Error" ) {
errinfo := & errorInfo { }
errinfo . errorType = errorTypeController
errinfo . controllerType = ct
errinfo . method = rt . Method ( i ) . Name
errname := strings . TrimPrefix ( rt . Method ( i ) . Name , "Error" )
ErrorMaps [ errname ] = errinfo
}
}
return BeeApp
}
2014-01-17 08:03:01 +00:00
// show error string as simple text message.
// if error string is empty, show 500 error as default.
2015-02-26 15:34:43 +00:00
func exception ( errcode string , ctx * context . Context ) {
code , err := strconv . Atoi ( errcode )
if err != nil {
code = 503
}
2013-09-11 09:00:39 +00:00
if h , ok := ErrorMaps [ errcode ] ; ok {
2015-03-30 12:35:57 +00:00
executeError ( h , ctx , code )
2015-02-26 15:34:43 +00:00
return
} else if h , ok := ErrorMaps [ "503" ] ; ok {
2015-03-30 12:35:57 +00:00
executeError ( h , ctx , code )
2013-09-11 09:00:39 +00:00
return
2015-02-26 15:34:43 +00:00
} else {
2015-03-30 12:35:57 +00:00
ctx . ResponseWriter . WriteHeader ( code )
2015-02-26 15:34:43 +00:00
ctx . WriteString ( errcode )
2013-09-11 09:00:39 +00:00
}
2015-02-26 15:34:43 +00:00
}
2015-03-30 12:35:57 +00:00
func executeError ( err * errorInfo , ctx * context . Context , code int ) {
2015-02-26 15:34:43 +00:00
if err . errorType == errorTypeHandler {
err . handler ( ctx . ResponseWriter , ctx . Request )
return
2015-02-23 03:50:13 +00:00
}
2015-02-26 15:34:43 +00:00
if err . errorType == errorTypeController {
2015-03-30 12:35:57 +00:00
ctx . Output . SetStatus ( code )
2015-02-26 15:34:43 +00:00
//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 ( )
in := make ( [ ] reflect . Value , 0 )
method := vc . MethodByName ( err . method )
method . Call ( in )
//render template
2015-03-30 12:35:57 +00:00
if AutoRender {
if err := execController . Render ( ) ; err != nil {
panic ( err )
2015-02-26 15:34:43 +00:00
}
}
// finish all runrouter. release resource
execController . Finish ( )
2015-02-23 03:50:13 +00:00
}
2013-09-11 09:00:39 +00:00
}