2014-08-29 17:49:50 +00:00
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
2014-07-16 18:14:03 +00:00
package gin
import (
"errors"
2015-05-12 16:33:41 +00:00
"io"
2015-03-26 13:07:01 +00:00
"math"
2014-07-16 18:14:03 +00:00
"net/http"
2014-12-21 12:42:48 +00:00
"strings"
2015-05-18 19:26:29 +00:00
"time"
2015-03-23 03:39:53 +00:00
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
2015-05-18 13:45:24 +00:00
"github.com/manucorporat/sse"
2015-05-05 13:06:38 +00:00
"golang.org/x/net/context"
2014-07-16 18:14:03 +00:00
)
const (
2015-04-08 12:24:49 +00:00
MIMEJSON = binding . MIMEJSON
MIMEHTML = binding . MIMEHTML
MIMEXML = binding . MIMEXML
MIMEXML2 = binding . MIMEXML2
MIMEPlain = binding . MIMEPlain
MIMEPOSTForm = binding . MIMEPOSTForm
MIMEMultipartPOSTForm = binding . MIMEMultipartPOSTForm
2014-07-16 18:14:03 +00:00
)
2015-03-26 03:27:34 +00:00
const AbortIndex = math . MaxInt8 / 2
2014-07-16 18:14:03 +00:00
// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
type Context struct {
2014-07-17 22:10:28 +00:00
writermem responseWriter
Request * http . Request
Writer ResponseWriter
2015-03-31 15:39:30 +00:00
2015-03-31 19:39:06 +00:00
Params Params
2015-05-07 09:30:01 +00:00
handlers HandlersChain
2015-03-31 15:39:30 +00:00
index int8
2015-05-22 00:24:13 +00:00
engine * Engine
2015-03-31 15:39:30 +00:00
Keys map [ string ] interface { }
Errors errorMsgs
2015-04-07 21:28:36 +00:00
Accepted [ ] string
2014-07-16 18:14:03 +00:00
}
2015-05-26 14:16:57 +00:00
var _ context . Context = & Context { }
2014-07-16 18:14:03 +00:00
/************************************/
2014-10-08 19:37:26 +00:00
/********** CONTEXT CREATION ********/
2014-07-16 18:14:03 +00:00
/************************************/
2015-03-25 18:33:17 +00:00
func ( c * Context ) reset ( ) {
2015-04-07 10:22:38 +00:00
c . Writer = & c . writermem
c . Params = c . Params [ 0 : 0 ]
c . handlers = nil
2014-07-16 18:14:03 +00:00
c . index = - 1
2015-04-07 10:22:38 +00:00
c . Keys = nil
2014-07-17 22:29:20 +00:00
c . Errors = c . Errors [ 0 : 0 ]
2015-04-08 11:37:25 +00:00
c . Accepted = nil
2014-10-08 19:37:26 +00:00
}
2014-07-16 18:14:03 +00:00
func ( c * Context ) Copy ( ) * Context {
var cp Context = * c
2015-04-09 10:15:02 +00:00
cp . writermem . ResponseWriter = nil
cp . Writer = & cp . writermem
2014-07-16 18:14:03 +00:00
cp . index = AbortIndex
cp . handlers = nil
return & cp
}
2014-10-08 19:37:26 +00:00
/************************************/
2015-05-28 01:22:34 +00:00
/*********** FLOW CONTROL ***********/
2014-10-08 19:37:26 +00:00
/************************************/
2014-07-16 18:14:03 +00:00
// Next should be used only in the middlewares.
// It executes the pending handlers in the chain inside the calling handler.
// See example in github.
func ( c * Context ) Next ( ) {
c . index ++
s := int8 ( len ( c . handlers ) )
for ; c . index < s ; c . index ++ {
c . handlers [ c . index ] ( c )
}
}
2015-05-28 01:22:34 +00:00
// Returns if the currect context was aborted.
func ( c * Context ) IsAborted ( ) bool {
return c . index == AbortIndex
}
// Stops the system to continue calling the pending handlers in the chain.
// Let's say you have an authorization middleware that validates if the request is authorized
// if the authorization fails (the password does not match). This method (Abort()) should be called
// in order to stop the execution of the actual handler.
2014-10-08 19:37:26 +00:00
func ( c * Context ) Abort ( ) {
2014-07-16 18:14:03 +00:00
c . index = AbortIndex
}
2015-05-28 01:22:34 +00:00
// It calls Abort() and writes the headers with the specified status code.
// For example, a failed attempt to authentificate a request could use: context.AbortWithStatus(401).
2014-10-08 19:37:26 +00:00
func ( c * Context ) AbortWithStatus ( code int ) {
c . Writer . WriteHeader ( code )
c . Abort ( )
}
2015-05-28 01:22:34 +00:00
// It calls AbortWithStatus() and Error() internally. This method stops the chain, writes the status code and
// pushes the specified error to `c.Errors`.
// See Context.Error() for more details.
2015-05-22 14:39:15 +00:00
func ( c * Context ) AbortWithError ( code int , err error ) * Error {
2014-10-08 19:37:26 +00:00
c . AbortWithStatus ( code )
2015-05-22 01:25:21 +00:00
return c . Error ( err )
2014-07-16 18:14:03 +00:00
}
2014-10-08 19:37:26 +00:00
/************************************/
/********* ERROR MANAGEMENT *********/
/************************************/
2014-07-16 18:14:03 +00:00
// Attaches an error to the current context. The error is pushed to a list of errors.
// It's a good idea to call Error for each error that occurred during the resolution of a request.
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
2015-05-22 14:39:15 +00:00
func ( c * Context ) Error ( err error ) * Error {
var parsedError * Error
switch err . ( type ) {
case * Error :
parsedError = err . ( * Error )
default :
parsedError = & Error {
Err : err ,
Type : ErrorTypePrivate ,
}
2014-07-16 18:14:03 +00:00
}
2015-05-22 14:39:15 +00:00
c . Errors = append ( c . Errors , parsedError )
return parsedError
2014-07-16 18:14:03 +00:00
}
/************************************/
/******** METADATA MANAGEMENT********/
/************************************/
2015-05-28 01:22:34 +00:00
// Sets a new pair key/value just for this context.
// It also lazy initializes the hashmap if it was not used previously.
2015-05-22 01:25:21 +00:00
func ( c * Context ) Set ( key string , value interface { } ) {
2014-07-16 18:14:03 +00:00
if c . Keys == nil {
c . Keys = make ( map [ string ] interface { } )
}
2015-05-22 01:25:21 +00:00
c . Keys [ key ] = value
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Returns the value for the given key, ie: (value, true).
// If the value does not exists it returns (nil, false)
2015-05-22 01:25:21 +00:00
func ( c * Context ) Get ( key string ) ( value interface { } , exists bool ) {
2014-07-16 18:14:03 +00:00
if c . Keys != nil {
2015-05-22 01:25:21 +00:00
value , exists = c . Keys [ key ]
2014-07-16 18:14:03 +00:00
}
2015-05-22 01:25:21 +00:00
return
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Returns the value for the given key if it exists, otherwise it panics.
2014-07-16 18:14:03 +00:00
func ( c * Context ) MustGet ( key string ) interface { } {
2015-05-22 01:25:21 +00:00
if value , exists := c . Get ( key ) ; exists {
return value
2014-07-16 18:14:03 +00:00
}
2015-05-22 01:25:21 +00:00
panic ( "Key \"" + key + "\" does not exist" )
2014-07-16 18:14:03 +00:00
}
2015-05-05 13:06:38 +00:00
/************************************/
/************ INPUT DATA ************/
/************************************/
2014-12-21 12:42:48 +00:00
2015-05-29 19:03:41 +00:00
// Shortcut for c.Request.URL.Query().Get(key)
2015-05-26 10:08:33 +00:00
func ( c * Context ) Query ( key string ) ( va string ) {
va , _ = c . query ( key )
2015-05-05 13:06:38 +00:00
return
2014-12-21 12:42:48 +00:00
}
2015-05-29 19:03:41 +00:00
// Shortcut for c.Request.PostFormValue(key)
2015-05-26 10:08:33 +00:00
func ( c * Context ) PostForm ( key string ) ( va string ) {
va , _ = c . postForm ( key )
2015-05-05 13:06:38 +00:00
return
}
2014-12-21 12:42:48 +00:00
2015-05-29 19:03:41 +00:00
// Shortcut for c.Params.ByName(key)
2015-05-26 10:35:05 +00:00
func ( c * Context ) Param ( key string ) string {
return c . Params . ByName ( key )
2015-05-05 13:06:38 +00:00
}
2014-12-21 12:42:48 +00:00
2015-05-26 10:08:33 +00:00
func ( c * Context ) DefaultPostForm ( key , defaultValue string ) string {
if va , ok := c . postForm ( key ) ; ok {
2015-05-05 13:06:38 +00:00
return va
2014-12-21 12:42:48 +00:00
}
2015-05-09 01:35:31 +00:00
return defaultValue
2015-05-05 13:06:38 +00:00
}
2014-12-21 12:42:48 +00:00
2015-05-26 10:08:33 +00:00
func ( c * Context ) DefaultQuery ( key , defaultValue string ) string {
if va , ok := c . query ( key ) ; ok {
2015-05-05 13:06:38 +00:00
return va
}
2015-05-09 01:35:31 +00:00
return defaultValue
2015-05-05 13:06:38 +00:00
}
2014-12-21 12:42:48 +00:00
2015-05-26 10:08:33 +00:00
func ( c * Context ) query ( key string ) ( string , bool ) {
2015-05-05 13:06:38 +00:00
req := c . Request
2015-05-26 10:08:33 +00:00
if values , ok := req . URL . Query ( ) [ key ] ; ok && len ( values ) > 0 {
2015-05-05 13:06:38 +00:00
return values [ 0 ] , true
2014-10-08 23:40:42 +00:00
}
2015-05-05 13:06:38 +00:00
return "" , false
2014-12-21 12:42:48 +00:00
}
2015-05-26 10:08:33 +00:00
func ( c * Context ) postForm ( key string ) ( string , bool ) {
2015-05-05 13:06:38 +00:00
req := c . Request
2015-05-26 14:16:57 +00:00
req . ParseMultipartForm ( 32 << 20 ) // 32 MB
2015-05-26 14:31:05 +00:00
if values := req . PostForm [ key ] ; len ( values ) > 0 {
2015-05-05 13:06:38 +00:00
return values [ 0 ] , true
}
2015-05-26 14:31:05 +00:00
if req . MultipartForm != nil && req . MultipartForm . File != nil {
if values := req . MultipartForm . Value [ key ] ; len ( values ) > 0 {
return values [ 0 ] , true
}
2015-05-26 14:16:57 +00:00
}
2015-05-05 13:06:38 +00:00
return "" , false
2014-10-08 23:40:42 +00:00
}
2014-07-16 18:14:03 +00:00
// This function checks the Content-Type to select a binding engine automatically,
// Depending the "Content-Type" header different bindings are used:
// "application/json" --> JSON binding
// "application/xml" --> XML binding
// else --> returns an error
// if Parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. It decodes the json payload into the struct specified as a pointer.Like ParseBody() but this method also writes a 400 error if the json is not valid.
2015-05-22 01:25:21 +00:00
func ( c * Context ) Bind ( obj interface { } ) error {
b := binding . Default ( c . Request . Method , c . ContentType ( ) )
2014-07-16 18:14:03 +00:00
return c . BindWith ( obj , b )
}
2015-05-28 01:22:34 +00:00
// Shortcut for c.Bind(obj, binding.JSON)
2015-05-22 01:25:21 +00:00
func ( c * Context ) BindJSON ( obj interface { } ) error {
return c . BindWith ( obj , binding . JSON )
2014-07-16 18:14:03 +00:00
}
2015-05-22 01:25:21 +00:00
func ( c * Context ) BindWith ( obj interface { } , b binding . Binding ) error {
2014-07-16 18:14:03 +00:00
if err := b . Bind ( c . Request , obj ) ; err != nil {
2015-05-22 14:39:15 +00:00
c . AbortWithError ( 400 , err ) . SetType ( ErrorTypeBind )
2015-05-22 01:25:21 +00:00
return err
2014-07-16 18:14:03 +00:00
}
2015-05-22 01:25:21 +00:00
return nil
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Best effort algoritm to return the real client IP, it parses
// X-Real-IP and X-Forwarded-For in order to work properly with reverse-proxies such us: nginx or haproxy.
2015-03-31 15:44:45 +00:00
func ( c * Context ) ClientIP ( ) string {
2015-05-24 13:35:08 +00:00
clientIP := strings . TrimSpace ( c . Request . Header . Get ( "X-Real-IP" ) )
2015-03-31 15:44:45 +00:00
if len ( clientIP ) > 0 {
return clientIP
2014-12-21 12:42:48 +00:00
}
2015-03-31 15:44:45 +00:00
clientIP = c . Request . Header . Get ( "X-Forwarded-For" )
2015-05-24 13:35:08 +00:00
clientIP = strings . TrimSpace ( strings . Split ( clientIP , "," ) [ 0 ] )
2015-03-31 15:44:45 +00:00
if len ( clientIP ) > 0 {
2015-05-24 13:35:08 +00:00
return clientIP
2014-10-08 23:40:42 +00:00
}
2015-05-24 13:35:08 +00:00
return strings . TrimSpace ( c . Request . RemoteAddr )
2014-10-08 23:40:42 +00:00
}
2015-03-31 15:44:45 +00:00
func ( c * Context ) ContentType ( ) string {
return filterFlags ( c . Request . Header . Get ( "Content-Type" ) )
2014-07-16 18:14:03 +00:00
}
2014-10-08 19:37:26 +00:00
/************************************/
/******** RESPONSE RENDERING ********/
/************************************/
2015-05-28 01:22:34 +00:00
// Intelligent shortcut for c.Writer.Header().Set(key, value)
// it writes a header in the response.
// If value == "", this method removes the header `c.Writer.Header().Del(key)`
2015-05-18 13:45:24 +00:00
func ( c * Context ) Header ( key , value string ) {
if len ( value ) == 0 {
c . Writer . Header ( ) . Del ( key )
} else {
c . Writer . Header ( ) . Set ( key , value )
}
2015-05-07 10:44:52 +00:00
}
2015-05-18 18:51:52 +00:00
func ( c * Context ) Render ( code int , r render . Render ) {
2015-05-30 12:45:13 +00:00
c . writermem . WriteHeader ( code )
2015-05-18 14:09:15 +00:00
if err := r . Write ( c . Writer ) ; err != nil {
2015-05-18 13:45:24 +00:00
debugPrintError ( err )
2015-05-22 14:39:15 +00:00
c . AbortWithError ( 500 , err ) . SetType ( ErrorTypeRender )
2014-07-16 18:14:03 +00:00
}
}
2015-05-07 10:44:52 +00:00
// Renders the HTTP template specified by its file name.
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
func ( c * Context ) HTML ( code int , name string , obj interface { } ) {
2015-05-22 00:24:13 +00:00
instance := c . engine . HTMLRender . Instance ( name , obj )
2015-05-18 18:51:52 +00:00
c . Render ( code , instance )
2015-05-06 20:31:01 +00:00
}
2015-05-28 01:22:34 +00:00
// Serializes the given struct as pretty JSON (indented + endlines) into the response body.
// It also sets the Content-Type as "application/json".
// WARNING: we recommend to use this only for development propuses since printing pretty JSON is
// more CPU and bandwidth consuming. Use Context.JSON() instead.
2015-05-06 20:31:01 +00:00
func ( c * Context ) IndentedJSON ( code int , obj interface { } ) {
2015-05-18 18:51:52 +00:00
c . Render ( code , render . IndentedJSON { Data : obj } )
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Serializes the given struct as JSON into the response body.
2014-07-16 18:14:03 +00:00
// It also sets the Content-Type as "application/json".
func ( c * Context ) JSON ( code int , obj interface { } ) {
2015-05-18 18:51:52 +00:00
c . Render ( code , render . JSON { Data : obj } )
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Serializes the given struct as XML into the response body.
2014-07-16 18:14:03 +00:00
// It also sets the Content-Type as "application/xml".
func ( c * Context ) XML ( code int , obj interface { } ) {
2015-05-18 18:51:52 +00:00
c . Render ( code , render . XML { Data : obj } )
2014-07-16 18:14:03 +00:00
}
2015-05-28 01:22:34 +00:00
// Writes the given string into the response body.
2014-07-16 18:14:03 +00:00
func ( c * Context ) String ( code int , format string , values ... interface { } ) {
2015-05-18 18:51:52 +00:00
c . Render ( code , render . String {
2015-05-18 13:45:24 +00:00
Format : format ,
Data : values } ,
)
2015-03-08 16:50:58 +00:00
}
2014-07-28 22:51:34 +00:00
// Returns a HTTP redirect to the specific location.
2014-08-02 15:06:09 +00:00
func ( c * Context ) Redirect ( code int , location string ) {
2015-05-18 18:51:52 +00:00
c . Render ( - 1 , render . Redirect {
2015-05-18 13:45:24 +00:00
Code : code ,
Location : location ,
Request : c . Request ,
} )
2014-07-28 22:48:02 +00:00
}
2014-07-16 18:14:03 +00:00
// Writes some data into the body stream and updates the HTTP code.
func ( c * Context ) Data ( code int , contentType string , data [ ] byte ) {
2015-05-18 18:51:52 +00:00
c . Render ( code , render . Data {
2015-05-18 13:45:24 +00:00
ContentType : contentType ,
Data : data ,
} )
2014-07-16 18:14:03 +00:00
}
2014-07-17 00:01:42 +00:00
2015-05-28 01:22:34 +00:00
// Writes the specified file into the body stream in a efficient way.
2014-07-17 00:01:42 +00:00
func ( c * Context ) File ( filepath string ) {
http . ServeFile ( c . Writer , c . Request , filepath )
}
2014-08-30 20:22:57 +00:00
2015-05-12 16:33:41 +00:00
func ( c * Context ) SSEvent ( name string , message interface { } ) {
2015-05-18 18:51:52 +00:00
c . Render ( - 1 , sse . Event {
2015-05-18 13:45:24 +00:00
Event : name ,
Data : message ,
} )
2015-05-12 16:33:41 +00:00
}
func ( c * Context ) Stream ( step func ( w io . Writer ) bool ) {
2015-05-12 13:17:46 +00:00
w := c . Writer
clientGone := w . CloseNotify ( )
for {
select {
case <- clientGone :
return
default :
2015-05-12 16:33:41 +00:00
keepopen := step ( w )
2015-05-12 13:17:46 +00:00
w . Flush ( )
2015-05-12 16:33:41 +00:00
if ! keepopen {
return
}
2015-05-12 13:17:46 +00:00
}
}
}
2014-08-30 20:22:57 +00:00
/************************************/
/******** CONTENT NEGOTIATION *******/
/************************************/
2014-08-31 16:28:18 +00:00
2014-08-30 20:22:57 +00:00
type Negotiate struct {
Offered [ ] string
2015-05-18 18:52:26 +00:00
HTMLName string
2014-08-31 16:28:18 +00:00
HTMLData interface { }
JSONData interface { }
XMLData interface { }
Data interface { }
2014-08-30 20:22:57 +00:00
}
2014-08-31 16:28:18 +00:00
func ( c * Context ) Negotiate ( code int , config Negotiate ) {
2014-08-31 16:41:11 +00:00
switch c . NegotiateFormat ( config . Offered ... ) {
2015-03-31 15:51:10 +00:00
case binding . MIMEJSON :
2014-08-31 16:28:18 +00:00
data := chooseData ( config . JSONData , config . Data )
2014-08-30 20:22:57 +00:00
c . JSON ( code , data )
2015-03-31 15:51:10 +00:00
case binding . MIMEHTML :
2014-08-31 16:28:18 +00:00
data := chooseData ( config . HTMLData , config . Data )
2015-05-18 18:52:26 +00:00
c . HTML ( code , config . HTMLName , data )
2014-08-30 20:22:57 +00:00
2015-03-31 15:51:10 +00:00
case binding . MIMEXML :
2014-08-31 16:28:18 +00:00
data := chooseData ( config . XMLData , config . Data )
2014-08-30 20:22:57 +00:00
c . XML ( code , data )
2014-08-31 16:28:18 +00:00
2014-08-30 20:22:57 +00:00
default :
2015-05-22 01:25:21 +00:00
c . AbortWithError ( http . StatusNotAcceptable , errors . New ( "the accepted formats are not offered by the server" ) )
2014-08-30 20:22:57 +00:00
}
}
func ( c * Context ) NegotiateFormat ( offered ... string ) string {
2014-08-31 16:41:11 +00:00
if len ( offered ) == 0 {
panic ( "you must provide at least one offer" )
}
2015-04-07 21:28:36 +00:00
if c . Accepted == nil {
c . Accepted = parseAccept ( c . Request . Header . Get ( "Accept" ) )
2014-08-30 20:22:57 +00:00
}
2015-04-07 21:28:36 +00:00
if len ( c . Accepted ) == 0 {
2014-08-30 20:22:57 +00:00
return offered [ 0 ]
2015-04-07 21:28:36 +00:00
}
for _ , accepted := range c . Accepted {
for _ , offert := range offered {
if accepted == offert {
return offert
2014-08-30 20:22:57 +00:00
}
}
}
2015-04-07 21:28:36 +00:00
return ""
2014-08-30 20:22:57 +00:00
}
func ( c * Context ) SetAccepted ( formats ... string ) {
2015-04-07 21:28:36 +00:00
c . Accepted = formats
2014-08-30 20:22:57 +00:00
}
2015-05-18 19:26:29 +00:00
2015-05-22 01:25:21 +00:00
/************************************/
2015-05-26 10:35:05 +00:00
/***** GOLANG.ORG/X/NET/CONTEXT *****/
2015-05-22 01:25:21 +00:00
/************************************/
2015-05-18 19:26:29 +00:00
func ( c * Context ) Deadline ( ) ( deadline time . Time , ok bool ) {
return
}
func ( c * Context ) Done ( ) <- chan struct { } {
return nil
}
func ( c * Context ) Err ( ) error {
return nil
}
func ( c * Context ) Value ( key interface { } ) interface { } {
if key == 0 {
return c . Request
}
if keyAsString , ok := key . ( string ) ; ok {
val , _ := c . Get ( keyAsString )
return val
}
return nil
2014-08-30 20:22:57 +00:00
}