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"
2019-03-01 02:17:47 +00:00
"fmt"
2015-05-12 16:33:41 +00:00
"io"
2017-03-31 00:45:56 +00:00
"io/ioutil"
2021-06-24 00:58:10 +00:00
"log"
2015-03-26 13:07:01 +00:00
"math"
2016-12-24 04:25:01 +00:00
"mime/multipart"
2015-07-01 18:48:21 +00:00
"net"
2014-07-16 18:14:03 +00:00
"net/http"
2015-08-27 08:04:50 +00:00
"net/url"
2017-07-16 03:42:08 +00:00
"os"
2014-12-21 12:42:48 +00:00
"strings"
2020-03-16 16:52:02 +00:00
"sync"
2015-05-18 19:26:29 +00:00
"time"
2015-03-23 03:39:53 +00:00
2017-06-27 21:17:02 +00:00
"github.com/gin-contrib/sse"
2015-03-23 03:39:53 +00:00
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
2014-07-16 18:14:03 +00:00
)
2017-08-16 03:55:50 +00:00
// Content-Type MIME of the most common data formats.
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
2018-11-06 01:49:45 +00:00
MIMEYAML = binding . MIMEYAML
2014-07-16 18:14:03 +00:00
)
2020-05-04 03:40:41 +00:00
// BodyBytesKey indicates a default body bytes key.
const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
2021-07-06 08:37:14 +00:00
// abortIndex represents a typical value used in abort functions.
const abortIndex int8 = math . MaxInt8 >> 1
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
2019-05-26 00:20:21 +00:00
fullPath string
2015-03-31 15:39:30 +00:00
2017-07-05 14:55:59 +00:00
engine * Engine
2020-05-10 05:22:25 +00:00
params * Params
2017-07-05 14:55:59 +00:00
2020-03-16 16:52:02 +00:00
// This mutex protect Keys map
2020-05-03 12:39:34 +00:00
mu sync . RWMutex
2020-03-16 16:52:02 +00:00
2017-08-16 03:55:50 +00:00
// Keys is a key/value pair exclusively for the context of each request.
2017-07-05 14:55:59 +00:00
Keys map [ string ] interface { }
2017-08-16 03:55:50 +00:00
// Errors is a list of errors attached to all the handlers/middlewares who used this context.
2017-07-05 14:55:59 +00:00
Errors errorMsgs
2017-08-16 03:55:50 +00:00
// Accepted defines a list of manually accepted formats for content negotiation.
2015-04-07 21:28:36 +00:00
Accepted [ ] string
2019-05-29 03:25:02 +00:00
2019-06-02 09:24:41 +00:00
// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
2019-05-29 03:25:02 +00:00
queryCache url . Values
2019-06-02 09:24:41 +00:00
// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
// or PUT body parameters.
formCache url . Values
2020-03-27 02:47:22 +00:00
// SameSite allows a server to define a cookie attribute making it impossible for
// the browser to send this cookie along with cross-site requests.
sameSite http . SameSite
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
2021-05-22 05:17:19 +00:00
c . Params = c . Params [ : 0 ]
2015-04-07 10:22:38 +00:00
c . handlers = nil
2014-07-16 18:14:03 +00:00
c . index = - 1
2020-05-03 12:39:34 +00:00
2019-05-26 00:20:21 +00:00
c . fullPath = ""
2015-04-07 10:22:38 +00:00
c . Keys = nil
2021-05-22 05:17:19 +00:00
c . Errors = c . Errors [ : 0 ]
2015-04-08 11:37:25 +00:00
c . Accepted = nil
2019-05-29 03:25:02 +00:00
c . queryCache = nil
2019-06-12 13:07:15 +00:00
c . formCache = nil
2021-05-22 05:17:19 +00:00
* c . params = ( * c . params ) [ : 0 ]
2014-10-08 19:37:26 +00:00
}
2014-07-16 18:14:03 +00:00
2015-07-02 18:24:54 +00:00
// Copy returns a copy of the current context that can be safely used outside the request's scope.
2017-02-01 14:47:50 +00:00
// This has to be used when the context has to be passed to a goroutine.
2014-07-16 18:14:03 +00:00
func ( c * Context ) Copy ( ) * Context {
2020-05-03 12:39:34 +00:00
cp := Context {
writermem : c . writermem ,
Request : c . Request ,
Params : c . Params ,
engine : c . engine ,
}
2015-04-09 10:15:02 +00:00
cp . writermem . ResponseWriter = nil
cp . Writer = & cp . writermem
2015-07-02 18:24:54 +00:00
cp . index = abortIndex
2014-07-16 18:14:03 +00:00
cp . handlers = nil
2019-02-26 07:10:16 +00:00
cp . Keys = map [ string ] interface { } { }
for k , v := range c . Keys {
cp . Keys [ k ] = v
}
2019-05-27 06:04:30 +00:00
paramCopy := make ( [ ] Param , len ( cp . Params ) )
copy ( paramCopy , cp . Params )
cp . Params = paramCopy
2014-07-16 18:14:03 +00:00
return & cp
}
2017-07-11 15:28:08 +00:00
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()",
2017-08-16 03:55:50 +00:00
// this function will return "main.handleGetUsers".
2015-06-25 17:44:52 +00:00
func ( c * Context ) HandlerName ( ) string {
return nameOfFunction ( c . handlers . Last ( ) )
}
2019-02-26 04:15:40 +00:00
// HandlerNames returns a list of all registered handlers for this context in descending order,
// following the semantics of HandlerName()
func ( c * Context ) HandlerNames ( ) [ ] string {
hn := make ( [ ] string , 0 , len ( c . handlers ) )
for _ , val := range c . handlers {
hn = append ( hn , nameOfFunction ( val ) )
}
return hn
}
2017-06-02 08:00:55 +00:00
// Handler returns the main handler.
func ( c * Context ) Handler ( ) HandlerFunc {
2017-06-13 02:50:42 +00:00
return c . handlers . Last ( )
2017-06-02 08:00:55 +00:00
}
2019-05-26 00:20:21 +00:00
// FullPath returns a matched route full path. For not found routes
// returns an empty string.
// router.GET("/user/:id", func(c *gin.Context) {
// c.FullPath() == "/user/:id" // true
// })
func ( c * Context ) FullPath ( ) string {
return c . fullPath
}
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
/************************************/
2015-07-03 18:12:01 +00:00
// Next should be used only inside middleware.
2014-07-16 18:14:03 +00:00
// It executes the pending handlers in the chain inside the calling handler.
2017-05-04 01:22:48 +00:00
// See example in GitHub.
2014-07-16 18:14:03 +00:00
func ( c * Context ) Next ( ) {
c . index ++
2019-01-18 01:57:06 +00:00
for c . index < int8 ( len ( c . handlers ) ) {
2014-07-16 18:14:03 +00:00
c . handlers [ c . index ] ( c )
2019-01-18 01:57:06 +00:00
c . index ++
2014-07-16 18:14:03 +00:00
}
}
2016-03-08 05:56:46 +00:00
// IsAborted returns true if the current context was aborted.
2015-05-28 01:22:34 +00:00
func ( c * Context ) IsAborted ( ) bool {
2015-07-02 18:24:54 +00:00
return c . index >= abortIndex
2015-05-28 01:22:34 +00:00
}
2015-10-27 17:26:05 +00:00
// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
2017-07-11 15:28:08 +00:00
// Let's say you have an authorization middleware that validates that the current request is authorized.
// If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
2015-10-27 17:22:18 +00:00
// for this request are not called.
2014-10-08 19:37:26 +00:00
func ( c * Context ) Abort ( ) {
2015-07-02 18:24:54 +00:00
c . index = abortIndex
2014-07-16 18:14:03 +00:00
}
2015-07-02 18:24:54 +00:00
// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
2017-05-04 01:22:48 +00:00
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
2014-10-08 19:37:26 +00:00
func ( c * Context ) AbortWithStatus ( code int ) {
2016-01-26 13:55:45 +00:00
c . Status ( code )
2016-04-14 16:02:29 +00:00
c . Writer . WriteHeaderNow ( )
2014-10-08 19:37:26 +00:00
c . Abort ( )
}
2017-07-11 15:28:08 +00:00
// AbortWithStatusJSON calls `Abort()` and then `JSON` internally.
// This method stops the chain, writes the status code and return a JSON body.
2017-02-14 01:11:01 +00:00
// It also sets the Content-Type as "application/json".
func ( c * Context ) AbortWithStatusJSON ( code int , jsonObj interface { } ) {
c . Abort ( )
c . JSON ( code , jsonObj )
}
2017-07-11 15:28:08 +00:00
// AbortWithError calls `AbortWithStatus()` and `Error()` internally.
// This method stops the chain, writes the status code and pushes the specified error to `c.Errors`.
2015-05-28 01:22:34 +00:00
// 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 *********/
/************************************/
2017-07-06 01:28:16 +00:00
// Error attaches an error to the current context. The error is pushed to a list of errors.
2014-07-16 18:14:03 +00:00
// It's a good idea to call Error for each error that occurred during the resolution of a request.
2017-07-11 15:28:08 +00:00
// 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.
2017-05-09 00:04:22 +00:00
// Error will panic if err is nil.
2015-05-22 14:39:15 +00:00
func ( c * Context ) Error ( err error ) * Error {
2017-05-09 00:04:22 +00:00
if err == nil {
panic ( "err is nil" )
}
2018-08-05 05:29:26 +00:00
parsedError , ok := err . ( * Error )
if ! ok {
2015-05-22 14:39:15 +00:00
parsedError = & Error {
Err : err ,
Type : ErrorTypePrivate ,
}
2014-07-16 18:14:03 +00:00
}
2018-08-05 05:29:26 +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********/
/************************************/
2017-05-04 01:22:48 +00:00
// Set is used to store a new key/value pair exclusively for this context.
2015-07-02 16:42:33 +00:00
// It also lazy initializes c.Keys if it was not used previously.
2015-05-22 01:25:21 +00:00
func ( c * Context ) Set ( key string , value interface { } ) {
2020-05-03 12:39:34 +00:00
c . mu . Lock ( )
2014-07-16 18:14:03 +00:00
if c . Keys == nil {
c . Keys = make ( map [ string ] interface { } )
}
2020-03-16 16:52:02 +00:00
2015-05-22 01:25:21 +00:00
c . Keys [ key ] = value
2020-05-03 12:39:34 +00:00
c . mu . Unlock ( )
2014-07-16 18:14:03 +00:00
}
2015-07-02 16:42:33 +00:00
// Get returns the value for the given key, ie: (value, true).
2015-05-28 01:22:34 +00:00
// 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 ) {
2020-05-03 12:39:34 +00:00
c . mu . RLock ( )
2016-09-09 09:37:22 +00:00
value , exists = c . Keys [ key ]
2020-05-03 12:39:34 +00:00
c . mu . RUnlock ( )
2015-05-22 01:25:21 +00:00
return
2014-07-16 18:14:03 +00:00
}
2016-04-14 23:16:46 +00:00
// MustGet 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
}
2017-06-02 01:00:04 +00:00
// GetString returns the value associated with the key as a string.
func ( c * Context ) GetString ( key string ) ( s string ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
s , _ = val . ( string )
}
return
}
// GetBool returns the value associated with the key as a boolean.
func ( c * Context ) GetBool ( key string ) ( b bool ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
b , _ = val . ( bool )
}
return
}
// GetInt returns the value associated with the key as an integer.
func ( c * Context ) GetInt ( key string ) ( i int ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
i , _ = val . ( int )
}
return
}
// GetInt64 returns the value associated with the key as an integer.
func ( c * Context ) GetInt64 ( key string ) ( i64 int64 ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
i64 , _ = val . ( int64 )
}
return
}
2020-09-01 01:33:54 +00:00
// GetUint returns the value associated with the key as an unsigned integer.
func ( c * Context ) GetUint ( key string ) ( ui uint ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
ui , _ = val . ( uint )
}
return
}
// GetUint64 returns the value associated with the key as an unsigned integer.
func ( c * Context ) GetUint64 ( key string ) ( ui64 uint64 ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
ui64 , _ = val . ( uint64 )
}
return
}
2017-06-02 01:00:04 +00:00
// GetFloat64 returns the value associated with the key as a float64.
func ( c * Context ) GetFloat64 ( key string ) ( f64 float64 ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
f64 , _ = val . ( float64 )
}
return
}
// GetTime returns the value associated with the key as time.
func ( c * Context ) GetTime ( key string ) ( t time . Time ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
t , _ = val . ( time . Time )
}
return
}
// GetDuration returns the value associated with the key as a duration.
func ( c * Context ) GetDuration ( key string ) ( d time . Duration ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
d , _ = val . ( time . Duration )
}
return
}
// GetStringSlice returns the value associated with the key as a slice of strings.
func ( c * Context ) GetStringSlice ( key string ) ( ss [ ] string ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
ss , _ = val . ( [ ] string )
}
return
}
// GetStringMap returns the value associated with the key as a map of interfaces.
func ( c * Context ) GetStringMap ( key string ) ( sm map [ string ] interface { } ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
sm , _ = val . ( map [ string ] interface { } )
}
return
}
// GetStringMapString returns the value associated with the key as a map of strings.
func ( c * Context ) GetStringMapString ( key string ) ( sms map [ string ] string ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
sms , _ = val . ( map [ string ] string )
}
return
}
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
func ( c * Context ) GetStringMapStringSlice ( key string ) ( smss map [ string ] [ ] string ) {
if val , ok := c . Get ( key ) ; ok && val != nil {
smss , _ = val . ( map [ string ] [ ] string )
}
return
}
2015-05-05 13:06:38 +00:00
/************************************/
/************ INPUT DATA ************/
/************************************/
2014-12-21 12:42:48 +00:00
2016-01-26 21:40:29 +00:00
// Param returns the value of the URL param.
// It is a shortcut for c.Params.ByName(key)
2017-07-11 15:28:08 +00:00
// router.GET("/user/:id", func(c *gin.Context) {
// // a GET request to /user/john
// id := c.Param("id") // id == "john"
// })
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
2016-01-29 01:42:19 +00:00
// Query returns the keyed url query value if it exists,
2017-05-04 01:22:48 +00:00
// otherwise it returns an empty string `("")`.
2016-01-29 01:42:19 +00:00
// It is shortcut for `c.Request.URL.Query().Get(key)`
2017-07-11 15:28:08 +00:00
// GET /path?id=1234&name=Manu&value=
// c.Query("id") == "1234"
// c.Query("name") == "Manu"
// c.Query("value") == ""
// c.Query("wtf") == ""
2016-01-29 01:42:19 +00:00
func ( c * Context ) Query ( key string ) string {
value , _ := c . GetQuery ( key )
return value
2015-05-05 13:06:38 +00:00
}
2014-12-21 12:42:48 +00:00
2016-01-29 01:42:19 +00:00
// DefaultQuery returns the keyed url query value if it exists,
2017-05-04 01:22:48 +00:00
// otherwise it returns the specified defaultValue string.
2016-01-29 01:42:19 +00:00
// See: Query() and GetQuery() for further information.
2017-07-11 15:28:08 +00:00
// GET /?name=Manu&lastname=
// c.DefaultQuery("name", "unknown") == "Manu"
// c.DefaultQuery("id", "none") == "none"
// c.DefaultQuery("lastname", "none") == ""
2015-05-26 10:08:33 +00:00
func ( c * Context ) DefaultQuery ( key , defaultValue string ) string {
2016-01-29 01:07:44 +00:00
if value , ok := c . GetQuery ( key ) ; ok {
2016-01-26 17:36:37 +00:00
return value
2015-05-05 13:06:38 +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
2016-01-29 01:42:19 +00:00
// GetQuery is like Query(), it returns the keyed url query value
// if it exists `(value, true)` (even when the value is an empty string),
2017-05-04 01:22:48 +00:00
// otherwise it returns `("", false)`.
2016-01-29 01:42:19 +00:00
// It is shortcut for `c.Request.URL.Query().Get(key)`
2017-07-11 15:28:08 +00:00
// GET /?name=Manu&lastname=
// ("Manu", true) == c.GetQuery("name")
// ("", false) == c.GetQuery("id")
// ("", true) == c.GetQuery("lastname")
2016-01-29 01:07:44 +00:00
func ( c * Context ) GetQuery ( key string ) ( string , bool ) {
2016-03-30 00:54:21 +00:00
if values , ok := c . GetQueryArray ( key ) ; ok {
return values [ 0 ] , ok
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
}
2016-03-29 16:05:13 +00:00
// QueryArray returns a slice of strings for a given query key.
// The length of the slice depends on the number of params with the given key.
func ( c * Context ) QueryArray ( key string ) [ ] string {
values , _ := c . GetQueryArray ( key )
return values
}
2020-05-14 03:35:14 +00:00
func ( c * Context ) initQueryCache ( ) {
2019-05-29 03:25:02 +00:00
if c . queryCache == nil {
2020-08-08 12:32:19 +00:00
if c . Request != nil {
c . queryCache = c . Request . URL . Query ( )
} else {
c . queryCache = url . Values { }
}
2019-05-29 03:25:02 +00:00
}
2019-05-29 06:54:55 +00:00
}
2019-05-29 03:25:02 +00:00
2019-05-29 06:54:55 +00:00
// GetQueryArray returns a slice of strings for a given query key, plus
// a boolean value whether at least one value exists for the given key.
func ( c * Context ) GetQueryArray ( key string ) ( [ ] string , bool ) {
2020-05-14 03:35:14 +00:00
c . initQueryCache ( )
2019-05-29 03:25:02 +00:00
if values , ok := c . queryCache [ key ] ; ok && len ( values ) > 0 {
2016-03-29 16:05:13 +00:00
return values , true
2014-10-08 23:40:42 +00:00
}
2016-03-29 16:05:13 +00:00
return [ ] string { } , false
2014-12-21 12:42:48 +00:00
}
2018-08-06 04:07:11 +00:00
// QueryMap returns a map for a given query key.
func ( c * Context ) QueryMap ( key string ) map [ string ] string {
dicts , _ := c . GetQueryMap ( key )
return dicts
}
// GetQueryMap returns a map for a given query key, plus a boolean value
// whether at least one value exists for the given key.
func ( c * Context ) GetQueryMap ( key string ) ( map [ string ] string , bool ) {
2020-05-14 03:35:14 +00:00
c . initQueryCache ( )
2019-05-29 06:54:55 +00:00
return c . get ( c . queryCache , key )
2018-08-06 04:07:11 +00:00
}
2016-01-29 01:42:19 +00:00
// PostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns an empty string `("")`.
func ( c * Context ) PostForm ( key string ) string {
value , _ := c . GetPostForm ( key )
return value
}
2016-04-14 23:16:46 +00:00
// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
2016-01-29 01:42:19 +00:00
// when it exists, otherwise it returns the specified defaultValue string.
// See: PostForm() and GetPostForm() for further information.
func ( c * Context ) DefaultPostForm ( key , defaultValue string ) string {
if value , ok := c . GetPostForm ( key ) ; ok {
return value
}
return defaultValue
}
// GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded
// form or multipart form when it exists `(value, true)` (even when the value is an empty string),
// otherwise it returns ("", false).
// For example, during a PATCH request to update the user's email:
2017-07-11 15:28:08 +00:00
// email=mail@example.com --> ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"
// email= --> ("", true) := GetPostForm("email") // set email to ""
// --> ("", false) := GetPostForm("email") // do nothing with email
2016-01-29 01:07:44 +00:00
func ( c * Context ) GetPostForm ( key string ) ( string , bool ) {
2016-03-30 00:54:21 +00:00
if values , ok := c . GetPostFormArray ( key ) ; ok {
return values [ 0 ] , ok
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
}
2016-03-29 16:05:13 +00:00
// PostFormArray returns a slice of strings for a given form key.
// The length of the slice depends on the number of params with the given key.
func ( c * Context ) PostFormArray ( key string ) [ ] string {
values , _ := c . GetPostFormArray ( key )
return values
}
2020-05-14 03:35:14 +00:00
func ( c * Context ) initFormCache ( ) {
2019-06-02 09:24:41 +00:00
if c . formCache == nil {
c . formCache = make ( url . Values )
req := c . Request
if err := req . ParseMultipartForm ( c . engine . MaxMultipartMemory ) ; err != nil {
if err != http . ErrNotMultipart {
debugPrint ( "error on parse multipart form array: %v" , err )
}
}
c . formCache = req . PostForm
}
}
2016-03-29 16:05:13 +00:00
// GetPostFormArray returns a slice of strings for a given form key, plus
// a boolean value whether at least one value exists for the given key.
func ( c * Context ) GetPostFormArray ( key string ) ( [ ] string , bool ) {
2020-05-14 03:35:14 +00:00
c . initFormCache ( )
2019-06-02 09:24:41 +00:00
if values := c . formCache [ key ] ; len ( values ) > 0 {
2016-03-29 16:05:13 +00:00
return values , true
2015-05-05 13:06:38 +00:00
}
2016-03-29 16:05:13 +00:00
return [ ] string { } , false
2014-10-08 23:40:42 +00:00
}
2018-08-06 04:07:11 +00:00
// PostFormMap returns a map for a given form key.
func ( c * Context ) PostFormMap ( key string ) map [ string ] string {
dicts , _ := c . GetPostFormMap ( key )
return dicts
}
// GetPostFormMap returns a map for a given form key, plus a boolean value
// whether at least one value exists for the given key.
func ( c * Context ) GetPostFormMap ( key string ) ( map [ string ] string , bool ) {
2020-05-14 03:35:14 +00:00
c . initFormCache ( )
2019-09-10 06:32:30 +00:00
return c . get ( c . formCache , key )
2018-08-06 04:07:11 +00:00
}
// get is an internal method and returns a map which satisfy conditions.
func ( c * Context ) get ( m map [ string ] [ ] string , key string ) ( map [ string ] string , bool ) {
dicts := make ( map [ string ] string )
exist := false
for k , v := range m {
if i := strings . IndexByte ( k , '[' ) ; i >= 1 && k [ 0 : i ] == key {
if j := strings . IndexByte ( k [ i + 1 : ] , ']' ) ; j >= 1 {
exist = true
dicts [ k [ i + 1 : ] [ : j ] ] = v [ 0 ]
}
}
}
return dicts , exist
}
2016-12-24 04:25:01 +00:00
// FormFile returns the first file for the provided form key.
func ( c * Context ) FormFile ( name string ) ( * multipart . FileHeader , error ) {
2018-10-22 15:01:14 +00:00
if c . Request . MultipartForm == nil {
if err := c . Request . ParseMultipartForm ( c . engine . MaxMultipartMemory ) ; err != nil {
return nil , err
}
}
2019-10-31 15:17:12 +00:00
f , fh , err := c . Request . FormFile ( name )
if err != nil {
return nil , err
}
f . Close ( )
2016-12-24 04:25:01 +00:00
return fh , err
}
// MultipartForm is the parsed multipart form, including file uploads.
func ( c * Context ) MultipartForm ( ) ( * multipart . Form , error ) {
2017-09-07 03:45:16 +00:00
err := c . Request . ParseMultipartForm ( c . engine . MaxMultipartMemory )
2016-12-24 04:25:01 +00:00
return c . Request . MultipartForm , err
}
2017-07-16 03:42:08 +00:00
// SaveUploadedFile uploads the form file to specific dst.
func ( c * Context ) SaveUploadedFile ( file * multipart . FileHeader , dst string ) error {
src , err := file . Open ( )
if err != nil {
return err
}
defer src . Close ( )
out , err := os . Create ( dst )
if err != nil {
return err
}
defer out . Close ( )
2019-01-18 01:32:53 +00:00
_ , err = io . Copy ( out , src )
return err
2017-07-16 03:42:08 +00:00
}
2015-07-02 16:42:33 +00:00
// Bind checks the Content-Type to select a binding engine automatically,
2014-07-16 18:14:03 +00:00
// Depending the "Content-Type" header different bindings are used:
2017-07-11 15:28:08 +00:00
// "application/json" --> JSON binding
// "application/xml" --> XML binding
2017-12-20 01:32:39 +00:00
// otherwise --> returns an error.
2016-04-01 23:29:28 +00:00
// It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
2015-07-02 16:42:33 +00:00
// It decodes the json payload into the struct specified as a pointer.
2017-12-20 01:32:39 +00:00
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input 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 ( ) )
2017-06-27 22:46:35 +00:00
return c . MustBindWith ( obj , b )
2014-07-16 18:14:03 +00:00
}
2017-08-16 03:55:50 +00:00
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
2015-05-22 01:25:21 +00:00
func ( c * Context ) BindJSON ( obj interface { } ) error {
2017-06-27 22:46:35 +00:00
return c . MustBindWith ( obj , binding . JSON )
2014-07-16 18:14:03 +00:00
}
2018-08-17 01:12:15 +00:00
// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
func ( c * Context ) BindXML ( obj interface { } ) error {
return c . MustBindWith ( obj , binding . XML )
}
2017-08-16 03:55:50 +00:00
// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
2017-07-19 07:50:05 +00:00
func ( c * Context ) BindQuery ( obj interface { } ) error {
return c . MustBindWith ( obj , binding . Query )
}
2018-11-06 01:49:45 +00:00
// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
func ( c * Context ) BindYAML ( obj interface { } ) error {
return c . MustBindWith ( obj , binding . YAML )
}
2019-06-27 04:47:45 +00:00
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
func ( c * Context ) BindHeader ( obj interface { } ) error {
return c . MustBindWith ( obj , binding . Header )
}
2018-12-12 15:40:29 +00:00
// BindUri binds the passed struct pointer using binding.Uri.
// It will abort the request with HTTP 400 if any error occurs.
func ( c * Context ) BindUri ( obj interface { } ) error {
if err := c . ShouldBindUri ( obj ) ; err != nil {
2019-01-18 01:32:53 +00:00
c . AbortWithError ( http . StatusBadRequest , err ) . SetType ( ErrorTypeBind ) // nolint: errcheck
2018-12-12 15:40:29 +00:00
return err
}
return nil
}
2017-08-16 03:55:50 +00:00
// MustBindWith binds the passed struct pointer using the specified binding engine.
2018-11-05 06:17:04 +00:00
// It will abort the request with HTTP 400 if any error occurs.
2015-07-02 16:42:33 +00:00
// See the binding package.
2018-12-12 15:40:29 +00:00
func ( c * Context ) MustBindWith ( obj interface { } , b binding . Binding ) error {
if err := c . ShouldBindWith ( obj , b ) ; err != nil {
2019-01-18 01:32:53 +00:00
c . AbortWithError ( http . StatusBadRequest , err ) . SetType ( ErrorTypeBind ) // nolint: errcheck
2018-12-12 15:40:29 +00:00
return err
2014-07-16 18:14:03 +00:00
}
2018-12-12 15:40:29 +00:00
return nil
2017-03-29 14:32:12 +00:00
}
2017-10-23 09:14:09 +00:00
// ShouldBind 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
// otherwise --> returns an error
// It 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 c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
func ( c * Context ) ShouldBind ( obj interface { } ) error {
b := binding . Default ( c . Request . Method , c . ContentType ( ) )
return c . ShouldBindWith ( obj , b )
}
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
func ( c * Context ) ShouldBindJSON ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . JSON )
}
2018-08-17 01:12:15 +00:00
// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
func ( c * Context ) ShouldBindXML ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . XML )
}
2017-10-23 09:14:09 +00:00
// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
func ( c * Context ) ShouldBindQuery ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . Query )
}
2018-11-06 01:49:45 +00:00
// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
func ( c * Context ) ShouldBindYAML ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . YAML )
}
2019-06-27 04:47:45 +00:00
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
func ( c * Context ) ShouldBindHeader ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . Header )
}
2018-11-22 01:29:48 +00:00
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
func ( c * Context ) ShouldBindUri ( obj interface { } ) error {
m := make ( map [ string ] [ ] string )
for _ , v := range c . Params {
m [ v . Key ] = [ ] string { v . Value }
}
return binding . Uri . BindUri ( m , obj )
}
2017-08-16 03:55:50 +00:00
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
2017-03-29 14:32:12 +00:00
// See the binding package.
func ( c * Context ) ShouldBindWith ( obj interface { } , b binding . Binding ) error {
return b . Bind ( c . Request , obj )
2014-07-16 18:14:03 +00:00
}
2018-05-11 02:33:33 +00:00
// ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
// body into the context, and reuse when it is called again.
//
// NOTE: This method reads the body before binding. So you should use
// ShouldBindWith for better performance if you need to call only once.
2018-11-22 01:29:48 +00:00
func ( c * Context ) ShouldBindBodyWith ( obj interface { } , bb binding . BindingBody ) ( err error ) {
2018-05-11 02:33:33 +00:00
var body [ ] byte
if cb , ok := c . Get ( BodyBytesKey ) ; ok {
if cbb , ok := cb . ( [ ] byte ) ; ok {
body = cbb
}
}
if body == nil {
body , err = ioutil . ReadAll ( c . Request . Body )
if err != nil {
return err
}
c . Set ( BodyBytesKey , body )
}
return bb . BindBody ( body , obj )
}
2021-04-06 03:37:25 +00:00
// ClientIP implements a best effort algorithm to return the real client IP.
// It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
// If it's it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
// If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy,
// the remote IP (coming form Request.RemoteAddr) is returned.
2015-03-31 15:44:45 +00:00
func ( c * Context ) ClientIP ( ) string {
2021-07-02 01:58:43 +00:00
// Check if we're running on a trusted platform
2021-06-24 00:58:10 +00:00
switch c . engine . TrustedPlatform {
case PlatformGoogleAppEngine :
2021-04-06 03:37:25 +00:00
if addr := c . requestHeader ( "X-Appengine-Remote-Addr" ) ; addr != "" {
return addr
2015-06-07 11:51:13 +00:00
}
2021-06-24 00:58:10 +00:00
case PlatformCloudflare :
2021-05-28 02:03:59 +00:00
if addr := c . requestHeader ( "CF-Connecting-IP" ) ; addr != "" {
return addr
}
2021-04-06 03:37:25 +00:00
}
2021-06-24 00:58:10 +00:00
// Legacy "AppEngine" flag
if c . engine . AppEngine {
log . Println ( ` The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead. ` )
if addr := c . requestHeader ( "X-Appengine-Remote-Addr" ) ; addr != "" {
return addr
}
}
2021-04-06 03:37:25 +00:00
remoteIP , trusted := c . RemoteIP ( )
if remoteIP == nil {
return ""
}
if trusted && c . engine . ForwardedByClientIP && c . engine . RemoteIPHeaders != nil {
for _ , headerName := range c . engine . RemoteIPHeaders {
ip , valid := validateHeader ( c . requestHeader ( headerName ) )
if valid {
return ip
}
2016-08-30 15:58:39 +00:00
}
2014-10-08 23:40:42 +00:00
}
2021-04-06 03:37:25 +00:00
return remoteIP . String ( )
}
2016-12-05 10:21:59 +00:00
2021-04-06 03:37:25 +00:00
// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
// It also checks if the remoteIP is a trusted proxy or not.
// In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks
// defined in Engine.TrustedProxies
func ( c * Context ) RemoteIP ( ) ( net . IP , bool ) {
ip , _ , err := net . SplitHostPort ( strings . TrimSpace ( c . Request . RemoteAddr ) )
if err != nil {
return nil , false
}
remoteIP := net . ParseIP ( ip )
if remoteIP == nil {
return nil , false
}
if c . engine . trustedCIDRs != nil {
for _ , cidr := range c . engine . trustedCIDRs {
if cidr . Contains ( remoteIP ) {
return remoteIP , true
}
2016-12-05 10:21:59 +00:00
}
}
2021-04-06 03:37:25 +00:00
return remoteIP , false
}
func validateHeader ( header string ) ( clientIP string , valid bool ) {
if header == "" {
return "" , false
2015-07-01 18:48:21 +00:00
}
2021-04-06 03:37:25 +00:00
items := strings . Split ( header , "," )
for i , ipStr := range items {
ipStr = strings . TrimSpace ( ipStr )
ip := net . ParseIP ( ipStr )
if ip == nil {
return "" , false
}
2016-12-05 10:21:59 +00:00
2021-04-06 03:37:25 +00:00
// We need to return the first IP in the list, but,
// we should not early return since we need to validate that
// the rest of the header is syntactically valid
if i == 0 {
clientIP = ipStr
valid = true
}
}
return
2014-10-08 23:40:42 +00:00
}
2015-07-02 16:42:33 +00:00
// ContentType returns the Content-Type header of the request.
2015-03-31 15:44:45 +00:00
func ( c * Context ) ContentType ( ) string {
2015-06-04 11:15:22 +00:00
return filterFlags ( c . requestHeader ( "Content-Type" ) )
}
2017-01-02 08:05:30 +00:00
// IsWebsocket returns true if the request headers indicate that a websocket
// handshake is being initiated by the client.
func ( c * Context ) IsWebsocket ( ) bool {
if strings . Contains ( strings . ToLower ( c . requestHeader ( "Connection" ) ) , "upgrade" ) &&
2019-05-21 15:08:52 +00:00
strings . EqualFold ( c . requestHeader ( "Upgrade" ) , "websocket" ) {
2017-01-02 08:05:30 +00:00
return true
}
return false
}
2015-06-04 11:15:22 +00:00
func ( c * Context ) requestHeader ( key string ) string {
2017-08-26 04:53:27 +00:00
return c . Request . Header . Get ( key )
2014-07-16 18:14:03 +00:00
}
2014-10-08 19:37:26 +00:00
/************************************/
/******** RESPONSE RENDERING ********/
/************************************/
2017-08-16 03:55:50 +00:00
// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
2017-01-09 15:24:48 +00:00
func bodyAllowedForStatus ( status int ) bool {
switch {
case status >= 100 && status <= 199 :
return false
2018-06-26 09:21:32 +00:00
case status == http . StatusNoContent :
2017-01-09 15:24:48 +00:00
return false
2018-06-26 09:21:32 +00:00
case status == http . StatusNotModified :
2017-01-09 15:24:48 +00:00
return false
}
return true
}
2017-07-28 00:50:58 +00:00
// Status sets the HTTP response code.
2016-01-26 13:55:45 +00:00
func ( c * Context ) Status ( code int ) {
2019-10-17 02:14:44 +00:00
c . Writer . WriteHeader ( code )
2016-01-26 13:55:45 +00:00
}
2017-08-16 03:55:50 +00:00
// Header is a intelligent shortcut for c.Writer.Header().Set(key, value).
2015-07-02 16:42:33 +00:00
// It writes a header in the response.
2015-05-28 01:22:34 +00:00
// 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 ) {
2017-11-12 05:24:51 +00:00
if value == "" {
2015-05-18 13:45:24 +00:00
c . Writer . Header ( ) . Del ( key )
2018-08-20 13:49:24 +00:00
return
2015-05-18 13:45:24 +00:00
}
2018-08-20 13:49:24 +00:00
c . Writer . Header ( ) . Set ( key , value )
2015-05-07 10:44:52 +00:00
}
2017-08-16 03:55:50 +00:00
// GetHeader returns value from request headers.
2017-03-24 12:43:23 +00:00
func ( c * Context ) GetHeader ( key string ) string {
return c . requestHeader ( key )
}
2017-08-16 03:55:50 +00:00
// GetRawData return stream data.
2017-03-31 00:45:56 +00:00
func ( c * Context ) GetRawData ( ) ( [ ] byte , error ) {
return ioutil . ReadAll ( c . Request . Body )
}
2020-03-27 02:47:22 +00:00
// SetSameSite with cookie
func ( c * Context ) SetSameSite ( samesite http . SameSite ) {
c . sameSite = samesite
}
2017-08-28 19:38:53 +00:00
// SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
2020-03-27 02:47:22 +00:00
func ( c * Context ) SetCookie ( name , value string , maxAge int , path , domain string , secure , httpOnly bool ) {
2016-01-26 17:36:37 +00:00
if path == "" {
path = "/"
2015-08-27 08:04:50 +00:00
}
2016-01-27 23:35:09 +00:00
http . SetCookie ( c . Writer , & http . Cookie {
2016-01-26 17:36:37 +00:00
Name : name ,
Value : url . QueryEscape ( value ) ,
MaxAge : maxAge ,
Path : path ,
Domain : domain ,
2020-03-27 02:47:22 +00:00
SameSite : c . sameSite ,
2016-01-26 17:36:37 +00:00
Secure : secure ,
HttpOnly : httpOnly ,
2016-01-27 23:35:09 +00:00
} )
2015-08-27 08:04:50 +00:00
}
2017-08-28 19:38:53 +00:00
// Cookie returns the named cookie provided in the request or
// ErrNoCookie if not found. And return the named cookie is unescaped.
// If multiple cookies match the given name, only one cookie will
// be returned.
2016-01-26 17:36:37 +00:00
func ( c * Context ) Cookie ( name string ) ( string , error ) {
2015-08-27 08:04:50 +00:00
cookie , err := c . Request . Cookie ( name )
if err != nil {
2015-10-02 10:37:51 +00:00
return "" , err
2015-08-27 08:04:50 +00:00
}
val , _ := url . QueryUnescape ( cookie . Value )
2015-10-02 10:37:51 +00:00
return val , nil
2015-08-27 08:04:50 +00:00
}
2018-09-15 07:21:54 +00:00
// Render writes the response headers and calls render.Render to render data.
2015-05-18 18:51:52 +00:00
func ( c * Context ) Render ( code int , r render . Render ) {
2016-01-26 13:55:45 +00:00
c . Status ( code )
2017-01-09 15:24:48 +00:00
if ! bodyAllowedForStatus ( code ) {
r . WriteContentType ( c . Writer )
c . Writer . WriteHeaderNow ( )
return
}
2015-06-04 03:25:21 +00:00
if err := r . Render ( c . Writer ) ; err != nil {
2016-01-26 17:35:04 +00:00
panic ( err )
2014-07-16 18:14:03 +00:00
}
}
2015-07-02 16:42:33 +00:00
// HTML renders the HTTP template specified by its file name.
2015-05-07 10:44:52 +00:00
// 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-07-02 16:42:33 +00:00
// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
2015-05-28 01:22:34 +00:00
// It also sets the Content-Type as "application/json".
2017-05-04 01:22:48 +00:00
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
2015-05-28 01:22:34 +00:00
// 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
}
2017-07-07 17:21:30 +00:00
// SecureJSON serializes the given struct as Secure JSON into the response body.
// Default prepends "while(1)," to response body if the given struct is array values.
// It also sets the Content-Type as "application/json".
func ( c * Context ) SecureJSON ( code int , obj interface { } ) {
2020-05-05 05:55:57 +00:00
c . Render ( code , render . SecureJSON { Prefix : c . engine . secureJSONPrefix , Data : obj } )
2017-07-07 17:21:30 +00:00
}
2018-04-26 03:52:19 +00:00
// JSONP serializes the given struct as JSON into the response body.
2020-11-11 01:41:35 +00:00
// It adds padding to response body to request data from a server residing in a different domain than the client.
2018-04-26 03:52:19 +00:00
// It also sets the Content-Type as "application/javascript".
func ( c * Context ) JSONP ( code int , obj interface { } ) {
2018-07-20 16:52:55 +00:00
callback := c . DefaultQuery ( "callback" , "" )
if callback == "" {
c . Render ( code , render . JSON { Data : obj } )
2018-08-20 13:49:24 +00:00
return
2018-07-20 16:52:55 +00:00
}
2018-08-20 13:49:24 +00:00
c . Render ( code , render . JsonpJSON { Callback : callback , Data : obj } )
2018-04-26 03:52:19 +00:00
}
2015-07-02 16:42:33 +00:00
// JSON 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 { } ) {
2017-01-09 15:24:48 +00:00
c . Render ( code , render . JSON { Data : obj } )
2014-07-16 18:14:03 +00:00
}
2018-07-03 09:17:08 +00:00
// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
// It also sets the Content-Type as "application/json".
func ( c * Context ) AsciiJSON ( code int , obj interface { } ) {
c . Render ( code , render . AsciiJSON { Data : obj } )
}
2019-05-07 10:32:32 +00:00
// PureJSON serializes the given struct as JSON into the response body.
// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
func ( c * Context ) PureJSON ( code int , obj interface { } ) {
c . Render ( code , render . PureJSON { Data : obj } )
}
2015-07-02 16:42:33 +00:00
// XML 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
}
2016-04-14 21:47:49 +00:00
// YAML serializes the given struct as YAML into the response body.
func ( c * Context ) YAML ( code int , obj interface { } ) {
c . Render ( code , render . YAML { Data : obj } )
}
2018-08-19 09:39:58 +00:00
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
func ( c * Context ) ProtoBuf ( code int , obj interface { } ) {
c . Render ( code , render . ProtoBuf { Data : obj } )
}
2015-07-02 16:42:33 +00:00
// String 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 { } ) {
2017-01-09 15:24:48 +00:00
c . Render ( code , render . String { Format : format , Data : values } )
2015-03-08 16:50:58 +00:00
}
2015-07-02 16:42:33 +00:00
// Redirect 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
}
2015-07-02 18:24:54 +00:00
// Data writes some data into the body stream and updates the HTTP code.
2014-07-16 18:14:03 +00:00
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
2018-05-12 03:00:42 +00:00
// DataFromReader writes the specified reader into the body stream and updates the HTTP code.
func ( c * Context ) DataFromReader ( code int , contentLength int64 , contentType string , reader io . Reader , extraHeaders map [ string ] string ) {
c . Render ( code , render . Reader {
Headers : extraHeaders ,
ContentType : contentType ,
ContentLength : contentLength ,
Reader : reader ,
} )
}
2020-11-11 01:41:35 +00:00
// File writes the specified file into the body stream in an 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
2020-09-14 02:40:20 +00:00
// FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.
2020-03-07 02:23:33 +00:00
func ( c * Context ) FileFromFS ( filepath string , fs http . FileSystem ) {
defer func ( old string ) {
c . Request . URL . Path = old
} ( c . Request . URL . Path )
c . Request . URL . Path = filepath
http . FileServer ( fs ) . ServeHTTP ( c . Writer , c . Request )
}
2019-03-01 02:17:47 +00:00
// FileAttachment writes the specified file into the body stream in an efficient way
// On the client side, the file will typically be downloaded with the given filename
func ( c * Context ) FileAttachment ( filepath , filename string ) {
2020-09-25 01:45:17 +00:00
c . Writer . Header ( ) . Set ( "Content-Disposition" , fmt . Sprintf ( "attachment; filename=\"%s\"" , filename ) )
2019-03-01 02:17:47 +00:00
http . ServeFile ( c . Writer , c . Request , filepath )
}
2015-07-02 18:24:54 +00:00
// SSEvent writes a Server-Sent Event into the body stream.
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
}
2019-03-02 15:07:37 +00:00
// Stream sends a streaming response and returns a boolean
// indicates "Is client disconnected in middle of stream"
func ( c * Context ) Stream ( step func ( w io . Writer ) bool ) bool {
2015-05-12 13:17:46 +00:00
w := c . Writer
clientGone := w . CloseNotify ( )
for {
select {
case <- clientGone :
2019-03-02 15:07:37 +00:00
return true
2015-05-12 13:17:46 +00:00
default :
2016-01-26 14:55:30 +00:00
keepOpen := step ( w )
2015-05-12 13:17:46 +00:00
w . Flush ( )
2016-01-26 14:55:30 +00:00
if ! keepOpen {
2019-03-02 15:07:37 +00:00
return false
2015-05-12 16:33:41 +00:00
}
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
2018-09-15 07:21:54 +00:00
// Negotiate contains all negotiations data.
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 { }
2020-02-06 06:50:21 +00:00
YAMLData interface { }
2014-08-31 16:28:18 +00:00
Data interface { }
2014-08-30 20:22:57 +00:00
}
2018-09-15 07:21:54 +00:00
// Negotiate calls different Render according acceptable Accept format.
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
2020-02-06 06:50:21 +00:00
case binding . MIMEYAML :
data := chooseData ( config . YAMLData , config . Data )
c . YAML ( code , data )
2014-08-30 20:22:57 +00:00
default :
2019-01-18 01:32:53 +00:00
c . AbortWithError ( http . StatusNotAcceptable , errors . New ( "the accepted formats are not offered by the server" ) ) // nolint: errcheck
2014-08-30 20:22:57 +00:00
}
}
2018-09-15 07:21:54 +00:00
// NegotiateFormat returns an acceptable Accept format.
2014-08-30 20:22:57 +00:00
func ( c * Context ) NegotiateFormat ( offered ... string ) string {
2016-01-27 23:35:09 +00:00
assert1 ( len ( offered ) > 0 , "you must provide at least one offer" )
2015-04-07 21:28:36 +00:00
if c . Accepted == nil {
2015-06-04 11:15:22 +00:00
c . Accepted = parseAccept ( c . requestHeader ( "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 {
2020-01-07 01:19:49 +00:00
for _ , offer := range offered {
2019-03-01 02:03:14 +00:00
// According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers,
// therefore we can just iterate over the string without casting it into []rune
i := 0
for ; i < len ( accepted ) ; i ++ {
2020-01-07 01:19:49 +00:00
if accepted [ i ] == '*' || offer [ i ] == '*' {
return offer
2019-03-01 02:03:14 +00:00
}
2020-01-07 01:19:49 +00:00
if accepted [ i ] != offer [ i ] {
2019-03-01 02:03:14 +00:00
break
}
}
if i == len ( accepted ) {
2020-01-07 01:19:49 +00:00
return offer
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
}
2018-09-15 07:21:54 +00:00
// SetAccepted sets Accept header data.
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
2019-01-09 01:32:44 +00:00
/************************************/
/***** GOLANG.ORG/X/NET/CONTEXT *****/
/************************************/
2021-07-31 16:46:53 +00:00
// Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
2019-01-09 01:32:44 +00:00
func ( c * Context ) Deadline ( ) ( deadline time . Time , ok bool ) {
2021-07-31 16:46:53 +00:00
if c . Request == nil || c . Request . Context ( ) == nil {
return
}
return c . Request . Context ( ) . Deadline ( )
2019-01-09 01:32:44 +00:00
}
2021-07-31 16:46:53 +00:00
// Done returns nil (chan which will wait forever) when c.Request has no Context.
2019-01-09 01:32:44 +00:00
func ( c * Context ) Done ( ) <- chan struct { } {
2021-07-31 16:46:53 +00:00
if c . Request == nil || c . Request . Context ( ) == nil {
return nil
}
return c . Request . Context ( ) . Done ( )
2019-01-09 01:32:44 +00:00
}
2021-07-31 16:46:53 +00:00
// Err returns nil when c.Request has no Context.
2019-01-09 01:32:44 +00:00
func ( c * Context ) Err ( ) error {
2021-07-31 16:46:53 +00:00
if c . Request == nil || c . Request . Context ( ) == nil {
return nil
}
return c . Request . Context ( ) . Err ( )
2019-01-09 01:32:44 +00:00
}
2018-06-28 09:08:09 +00:00
// Value returns the value associated with this context for key, or nil
// if no value is associated with key. Successive calls to Value with
// the same key returns the same result.
2015-05-18 19:26:29 +00:00
func ( c * Context ) Value ( key interface { } ) interface { } {
if key == 0 {
return c . Request
}
if keyAsString , ok := key . ( string ) ; ok {
2021-06-24 08:33:14 +00:00
if val , exists := c . Get ( keyAsString ) ; exists {
return val
}
2015-05-18 19:26:29 +00:00
}
2021-06-24 08:33:14 +00:00
if c . Request == nil || c . Request . Context ( ) == nil {
return nil
}
return c . Request . Context ( ) . Value ( key )
2014-08-30 20:22:57 +00:00
}