2016-05-30 16:08:09 +02:00
package iris
//taken from net/http
const (
StatusContinue = 100
StatusSwitchingProtocols = 101
StatusOK = 200
StatusCreated = 201
StatusAccepted = 202
StatusNonAuthoritativeInfo = 203
StatusNoContent = 204
StatusResetContent = 205
StatusPartialContent = 206
StatusMultipleChoices = 300
StatusMovedPermanently = 301
StatusFound = 302
StatusSeeOther = 303
StatusNotModified = 304
StatusUseProxy = 305
StatusTemporaryRedirect = 307
StatusBadRequest = 400
StatusUnauthorized = 401
StatusPaymentRequired = 402
StatusForbidden = 403
StatusNotFound = 404
StatusMethodNotAllowed = 405
StatusNotAcceptable = 406
StatusProxyAuthRequired = 407
StatusRequestTimeout = 408
StatusConflict = 409
StatusGone = 410
StatusLengthRequired = 411
StatusPreconditionFailed = 412
StatusRequestEntityTooLarge = 413
StatusRequestURITooLong = 414
StatusUnsupportedMediaType = 415
StatusRequestedRangeNotSatisfiable = 416
StatusExpectationFailed = 417
StatusTeapot = 418
StatusPreconditionRequired = 428
StatusTooManyRequests = 429
StatusRequestHeaderFieldsTooLarge = 431
StatusUnavailableForLegalReasons = 451
StatusInternalServerError = 500
StatusNotImplemented = 501
StatusBadGateway = 502
StatusServiceUnavailable = 503
StatusGatewayTimeout = 504
StatusHTTPVersionNotSupported = 505
StatusNetworkAuthenticationRequired = 511
)
var statusText = map [ int ] string {
StatusContinue : "Continue" ,
StatusSwitchingProtocols : "Switching Protocols" ,
StatusOK : "OK" ,
StatusCreated : "Created" ,
StatusAccepted : "Accepted" ,
StatusNonAuthoritativeInfo : "Non-Authoritative Information" ,
StatusNoContent : "No Content" ,
StatusResetContent : "Reset Content" ,
StatusPartialContent : "Partial Content" ,
StatusMultipleChoices : "Multiple Choices" ,
StatusMovedPermanently : "Moved Permanently" ,
StatusFound : "Found" ,
StatusSeeOther : "See Other" ,
StatusNotModified : "Not Modified" ,
StatusUseProxy : "Use Proxy" ,
StatusTemporaryRedirect : "Temporary Redirect" ,
StatusBadRequest : "Bad Request" ,
StatusUnauthorized : "Unauthorized" ,
StatusPaymentRequired : "Payment Required" ,
StatusForbidden : "Forbidden" ,
StatusNotFound : "Not Found" ,
StatusMethodNotAllowed : "Method Not Allowed" ,
StatusNotAcceptable : "Not Acceptable" ,
StatusProxyAuthRequired : "Proxy Authentication Required" ,
StatusRequestTimeout : "Request Timeout" ,
StatusConflict : "Conflict" ,
StatusGone : "Gone" ,
StatusLengthRequired : "Length Required" ,
StatusPreconditionFailed : "Precondition Failed" ,
StatusRequestEntityTooLarge : "Request Entity Too Large" ,
StatusRequestURITooLong : "Request URI Too Long" ,
StatusUnsupportedMediaType : "Unsupported Media Type" ,
StatusRequestedRangeNotSatisfiable : "Requested Range Not Satisfiable" ,
StatusExpectationFailed : "Expectation Failed" ,
StatusTeapot : "I'm a teapot" ,
StatusPreconditionRequired : "Precondition Required" ,
StatusTooManyRequests : "Too Many Requests" ,
StatusRequestHeaderFieldsTooLarge : "Request Header Fields Too Large" ,
StatusUnavailableForLegalReasons : "Unavailable For Legal Reasons" ,
StatusInternalServerError : "Internal Server Error" ,
StatusNotImplemented : "Not Implemented" ,
StatusBadGateway : "Bad Gateway" ,
StatusServiceUnavailable : "Service Unavailable" ,
StatusGatewayTimeout : "Gateway Timeout" ,
StatusHTTPVersionNotSupported : "HTTP Version Not Supported" ,
StatusNetworkAuthenticationRequired : "Network Authentication Required" ,
}
// StatusText returns a text for the HTTP status code. It returns the empty
// string if the code is unknown.
func StatusText ( code int ) string {
return statusText [ code ]
}
//
type (
// HTTPErrorHandler is just an object which stores a http status code and a handler
HTTPErrorHandler struct {
code int
handler HandlerFunc
}
// HTTPErrorContainer is the struct which contains the handlers which will execute if http error occurs
// One struct per Server instance, the meaning of this is that the developer can change the default error message and replace them with his/her own completely custom handlers
//
// Example of usage:
// iris.OnError(405, func (ctx *iris.Context){ c.SendStatus(405,"Method not allowed!!!")})
// and inside the handler which you have access to the current Context:
// ctx.EmitError(405)
HTTPErrorContainer struct {
// Errors contains all the httperrorhandlers
Errors [ ] * HTTPErrorHandler
}
)
// HTTPErrorHandlerFunc creates a handler which is responsible to send a particular error to the client
func HTTPErrorHandlerFunc ( statusCode int , message string ) HandlerFunc {
return func ( ctx * Context ) {
ctx . SetStatusCode ( statusCode )
ctx . SetBodyString ( message )
}
}
// GetCode returns the http status code value
func ( e * HTTPErrorHandler ) GetCode ( ) int {
return e . code
}
// GetHandler returns the handler which is type of HandlerFunc
func ( e * HTTPErrorHandler ) GetHandler ( ) HandlerFunc {
return e . handler
}
// SetHandler sets the handler (type of HandlerFunc) to this particular ErrorHandler
func ( e * HTTPErrorHandler ) SetHandler ( h HandlerFunc ) {
e . handler = h
}
// defaultHTTPErrors creates and returns an instance of HTTPErrorContainer with default handlers
func defaultHTTPErrors ( ) * HTTPErrorContainer {
httperrors := new ( HTTPErrorContainer )
httperrors . Errors = make ( [ ] * HTTPErrorHandler , 0 )
httperrors . OnError ( StatusNotFound , HTTPErrorHandlerFunc ( StatusNotFound , statusText [ StatusNotFound ] ) )
httperrors . OnError ( StatusInternalServerError , HTTPErrorHandlerFunc ( StatusInternalServerError , statusText [ StatusInternalServerError ] ) )
return httperrors
}
// GetByCode returns the error handler by it's http status code
func ( he * HTTPErrorContainer ) GetByCode ( httpStatus int ) * HTTPErrorHandler {
if he != nil {
for _ , h := range he . Errors {
if h . GetCode ( ) == httpStatus {
return h
}
}
}
return nil
}
// OnError Registers a handler for a specific http error status
func ( he * HTTPErrorContainer ) OnError ( httpStatus int , handler HandlerFunc ) {
if httpStatus == StatusOK {
return
}
if errH := he . GetByCode ( httpStatus ) ; errH != nil {
errH . SetHandler ( handler )
} else {
he . Errors = append ( he . Errors , & HTTPErrorHandler { code : httpStatus , handler : handler } )
}
}
///TODO: the errors must have .Next too, as middlewares inside the Context, if I let it as it is then we have problem
// we cannot set a logger and a custom handler at one error because now the error handler takes only one handelrFunc and executes there from here...
// EmitError executes the handler of the given error http status code
func ( he * HTTPErrorContainer ) EmitError ( errCode int , ctx * Context ) {
2016-06-02 04:05:54 +02:00
ctx . ResetBody ( )
2016-05-30 16:08:09 +02:00
if errHandler := he . GetByCode ( errCode ) ; errHandler != nil {
ctx . SetStatusCode ( errCode ) // for any case, user can change it after if want to
errHandler . GetHandler ( ) . Serve ( ctx )
} else {
//if no error is registed, then register it with the default http error text, and re-run the Emit
he . OnError ( errCode , func ( c * Context ) {
c . SetStatusCode ( errCode )
c . SetBodyString ( StatusText ( errCode ) )
} )
he . EmitError ( errCode , ctx )
}
}
// OnNotFound sets the handler for http status 404,
// default is a response with text: 'Not Found' and status: 404
func ( he * HTTPErrorContainer ) OnNotFound ( handlerFunc HandlerFunc ) {
he . OnError ( StatusNotFound , handlerFunc )
}
// OnPanic sets the handler for http status 500,
// default is a response with text: The server encountered an unexpected condition which prevented it from fulfilling the request. and status: 500
func ( he * HTTPErrorContainer ) OnPanic ( handlerFunc HandlerFunc ) {
he . OnError ( StatusInternalServerError , handlerFunc )
}