2022-05-28 05:42:28 +03:00
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
2014-08-29 21:49:50 +04:00
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
2014-07-16 22:14:03 +04:00
package gin
import (
"errors"
2015-05-12 19:33:41 +03:00
"io"
2021-06-24 03:58:10 +03:00
"log"
2015-03-26 16:07:01 +03:00
"math"
2016-12-24 07:25:01 +03:00
"mime/multipart"
2015-07-01 21:48:21 +03:00
"net"
2014-07-16 22:14:03 +04:00
"net/http"
2015-08-27 11:04:50 +03:00
"net/url"
2017-07-16 06:42:08 +03:00
"os"
2022-10-16 04:45:08 +03:00
"path/filepath"
2014-12-21 15:42:48 +03:00
"strings"
2020-03-16 19:52:02 +03:00
"sync"
2015-05-18 22:26:29 +03:00
"time"
2015-03-23 06:39:53 +03:00
2017-06-28 00:17:02 +03:00
"github.com/gin-contrib/sse"
2015-03-23 06:39:53 +03:00
"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
2014-07-16 22:14:03 +04:00
)
2017-08-16 06:55:50 +03:00
// Content-Type MIME of the most common data formats.
2014-07-16 22:14:03 +04:00
const (
2015-04-08 15:24:49 +03: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 04:49:45 +03:00
MIMEYAML = binding . MIMEYAML
2022-05-28 03:34:43 +03:00
MIMETOML = binding . MIMETOML
2014-07-16 22:14:03 +04:00
)
2020-05-04 06:40:41 +03:00
// BodyBytesKey indicates a default body bytes key.
const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
2022-04-23 13:02:54 +03:00
// ContextKey is the key that a Context returns itself for.
const ContextKey = "_gin-gonic/gin/contextkey"
2021-07-06 11:37:14 +03:00
// abortIndex represents a typical value used in abort functions.
const abortIndex int8 = math . MaxInt8 >> 1
2014-07-16 22:14:03 +04: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-18 02:10:28 +04:00
writermem responseWriter
Request * http . Request
Writer ResponseWriter
2015-03-31 18:39:30 +03:00
2015-03-31 22:39:06 +03:00
Params Params
2015-05-07 12:30:01 +03:00
handlers HandlersChain
2015-03-31 18:39:30 +03:00
index int8
2019-05-26 03:20:21 +03:00
fullPath string
2015-03-31 18:39:30 +03:00
2021-10-23 06:58:57 +03:00
engine * Engine
params * Params
skippedNodes * [ ] skippedNode
2017-07-05 17:55:59 +03:00
2021-12-18 14:40:47 +03:00
// This mutex protects Keys map.
2020-05-03 15:39:34 +03:00
mu sync . RWMutex
2020-03-16 19:52:02 +03:00
2017-08-16 06:55:50 +03:00
// Keys is a key/value pair exclusively for the context of each request.
2022-03-21 04:43:17 +03:00
Keys map [ string ] any
2017-07-05 17:55:59 +03:00
2017-08-16 06:55:50 +03:00
// Errors is a list of errors attached to all the handlers/middlewares who used this context.
2017-07-05 17:55:59 +03:00
Errors errorMsgs
2017-08-16 06:55:50 +03:00
// Accepted defines a list of manually accepted formats for content negotiation.
2015-04-08 00:28:36 +03:00
Accepted [ ] string
2019-05-29 06:25:02 +03:00
2021-12-18 14:40:47 +03:00
// queryCache caches the query result from c.Request.URL.Query().
2019-05-29 06:25:02 +03:00
queryCache url . Values
2019-06-02 12:24:41 +03:00
2021-12-18 14:40:47 +03:00
// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
2019-06-02 12:24:41 +03:00
// or PUT body parameters.
formCache url . Values
2020-03-27 05:47:22 +03: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 22:14:03 +04:00
}
/************************************/
2014-10-08 23:37:26 +04:00
/********** CONTEXT CREATION ********/
2014-07-16 22:14:03 +04:00
/************************************/
2015-03-25 21:33:17 +03:00
func ( c * Context ) reset ( ) {
2015-04-07 13:22:38 +03:00
c . Writer = & c . writermem
2021-05-22 08:17:19 +03:00
c . Params = c . Params [ : 0 ]
2015-04-07 13:22:38 +03:00
c . handlers = nil
2014-07-16 22:14:03 +04:00
c . index = - 1
2020-05-03 15:39:34 +03:00
2019-05-26 03:20:21 +03:00
c . fullPath = ""
2015-04-07 13:22:38 +03:00
c . Keys = nil
2021-05-22 08:17:19 +03:00
c . Errors = c . Errors [ : 0 ]
2015-04-08 14:37:25 +03:00
c . Accepted = nil
2019-05-29 06:25:02 +03:00
c . queryCache = nil
2019-06-12 16:07:15 +03:00
c . formCache = nil
2022-04-17 07:41:59 +03:00
c . sameSite = 0
2021-05-22 08:17:19 +03:00
* c . params = ( * c . params ) [ : 0 ]
2021-10-23 06:58:57 +03:00
* c . skippedNodes = ( * c . skippedNodes ) [ : 0 ]
2014-10-08 23:37:26 +04:00
}
2014-07-16 22:14:03 +04:00
2015-07-02 21:24:54 +03:00
// Copy returns a copy of the current context that can be safely used outside the request's scope.
2017-02-01 17:47:50 +03:00
// This has to be used when the context has to be passed to a goroutine.
2014-07-16 22:14:03 +04:00
func ( c * Context ) Copy ( ) * Context {
2020-05-03 15:39:34 +03:00
cp := Context {
writermem : c . writermem ,
Request : c . Request ,
Params : c . Params ,
engine : c . engine ,
}
2015-04-09 13:15:02 +03:00
cp . writermem . ResponseWriter = nil
cp . Writer = & cp . writermem
2015-07-02 21:24:54 +03:00
cp . index = abortIndex
2014-07-16 22:14:03 +04:00
cp . handlers = nil
2022-03-21 04:43:17 +03:00
cp . Keys = map [ string ] any { }
2019-02-26 10:10:16 +03:00
for k , v := range c . Keys {
cp . Keys [ k ] = v
}
2019-05-27 09:04:30 +03:00
paramCopy := make ( [ ] Param , len ( cp . Params ) )
copy ( paramCopy , cp . Params )
cp . Params = paramCopy
2014-07-16 22:14:03 +04:00
return & cp
}
2017-07-11 18:28:08 +03:00
// HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()",
2017-08-16 06:55:50 +03:00
// this function will return "main.handleGetUsers".
2015-06-25 20:44:52 +03:00
func ( c * Context ) HandlerName ( ) string {
return nameOfFunction ( c . handlers . Last ( ) )
}
2019-02-26 07:15:40 +03: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 11:00:55 +03:00
// Handler returns the main handler.
func ( c * Context ) Handler ( ) HandlerFunc {
2017-06-13 05:50:42 +03:00
return c . handlers . Last ( )
2017-06-02 11:00:55 +03:00
}
2019-05-26 03:20:21 +03:00
// FullPath returns a matched route full path. For not found routes
// returns an empty string.
2022-08-15 16:38:20 +03:00
//
// router.GET("/user/:id", func(c *gin.Context) {
// c.FullPath() == "/user/:id" // true
// })
2019-05-26 03:20:21 +03:00
func ( c * Context ) FullPath ( ) string {
return c . fullPath
}
2014-10-08 23:37:26 +04:00
/************************************/
2015-05-28 04:22:34 +03:00
/*********** FLOW CONTROL ***********/
2014-10-08 23:37:26 +04:00
/************************************/
2015-07-03 21:12:01 +03:00
// Next should be used only inside middleware.
2014-07-16 22:14:03 +04:00
// It executes the pending handlers in the chain inside the calling handler.
2017-05-04 04:22:48 +03:00
// See example in GitHub.
2014-07-16 22:14:03 +04:00
func ( c * Context ) Next ( ) {
c . index ++
2019-01-18 04:57:06 +03:00
for c . index < int8 ( len ( c . handlers ) ) {
2014-07-16 22:14:03 +04:00
c . handlers [ c . index ] ( c )
2019-01-18 04:57:06 +03:00
c . index ++
2014-07-16 22:14:03 +04:00
}
}
2016-03-08 08:56:46 +03:00
// IsAborted returns true if the current context was aborted.
2015-05-28 04:22:34 +03:00
func ( c * Context ) IsAborted ( ) bool {
2015-07-02 21:24:54 +03:00
return c . index >= abortIndex
2015-05-28 04:22:34 +03:00
}
2015-10-27 20:26:05 +03:00
// Abort prevents pending handlers from being called. Note that this will not stop the current handler.
2017-07-11 18:28:08 +03: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 20:22:18 +03:00
// for this request are not called.
2014-10-08 23:37:26 +04:00
func ( c * Context ) Abort ( ) {
2015-07-02 21:24:54 +03:00
c . index = abortIndex
2014-07-16 22:14:03 +04:00
}
2015-07-02 21:24:54 +03:00
// AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
2017-05-04 04:22:48 +03:00
// For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
2014-10-08 23:37:26 +04:00
func ( c * Context ) AbortWithStatus ( code int ) {
2016-01-26 16:55:45 +03:00
c . Status ( code )
2016-04-14 19:02:29 +03:00
c . Writer . WriteHeaderNow ( )
2014-10-08 23:37:26 +04:00
c . Abort ( )
}
2017-07-11 18:28:08 +03: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 04:11:01 +03:00
// It also sets the Content-Type as "application/json".
2022-03-21 04:43:17 +03:00
func ( c * Context ) AbortWithStatusJSON ( code int , jsonObj any ) {
2017-02-14 04:11:01 +03:00
c . Abort ( )
c . JSON ( code , jsonObj )
}
2017-07-11 18:28:08 +03: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 04:22:34 +03:00
// See Context.Error() for more details.
2015-05-22 17:39:15 +03:00
func ( c * Context ) AbortWithError ( code int , err error ) * Error {
2014-10-08 23:37:26 +04:00
c . AbortWithStatus ( code )
2015-05-22 04:25:21 +03:00
return c . Error ( err )
2014-07-16 22:14:03 +04:00
}
2014-10-08 23:37:26 +04:00
/************************************/
/********* ERROR MANAGEMENT *********/
/************************************/
2017-07-06 04:28:16 +03:00
// Error attaches an error to the current context. The error is pushed to a list of errors.
2014-07-16 22:14:03 +04:00
// It's a good idea to call Error for each error that occurred during the resolution of a request.
2017-07-11 18:28:08 +03: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 03:04:22 +03:00
// Error will panic if err is nil.
2015-05-22 17:39:15 +03:00
func ( c * Context ) Error ( err error ) * Error {
2017-05-09 03:04:22 +03:00
if err == nil {
panic ( "err is nil" )
}
2018-08-05 08:29:26 +03:00
2021-09-21 10:22:21 +03:00
var parsedError * Error
ok := errors . As ( err , & parsedError )
2018-08-05 08:29:26 +03:00
if ! ok {
2015-05-22 17:39:15 +03:00
parsedError = & Error {
Err : err ,
Type : ErrorTypePrivate ,
}
2014-07-16 22:14:03 +04:00
}
2018-08-05 08:29:26 +03:00
2015-05-22 17:39:15 +03:00
c . Errors = append ( c . Errors , parsedError )
return parsedError
2014-07-16 22:14:03 +04:00
}
/************************************/
/******** METADATA MANAGEMENT********/
/************************************/
2017-05-04 04:22:48 +03:00
// Set is used to store a new key/value pair exclusively for this context.
2015-07-02 19:42:33 +03:00
// It also lazy initializes c.Keys if it was not used previously.
2022-03-21 04:43:17 +03:00
func ( c * Context ) Set ( key string , value any ) {
2020-05-03 15:39:34 +03:00
c . mu . Lock ( )
2014-07-16 22:14:03 +04:00
if c . Keys == nil {
2022-03-21 04:43:17 +03:00
c . Keys = make ( map [ string ] any )
2014-07-16 22:14:03 +04:00
}
2020-03-16 19:52:02 +03:00
2015-05-22 04:25:21 +03:00
c . Keys [ key ] = value
2020-05-03 15:39:34 +03:00
c . mu . Unlock ( )
2014-07-16 22:14:03 +04:00
}
2015-07-02 19:42:33 +03:00
// Get returns the value for the given key, ie: (value, true).
2021-11-11 03:07:55 +03:00
// If the value does not exist it returns (nil, false)
2022-03-21 04:43:17 +03:00
func ( c * Context ) Get ( key string ) ( value any , exists bool ) {
2020-05-03 15:39:34 +03:00
c . mu . RLock ( )
2016-09-09 12:37:22 +03:00
value , exists = c . Keys [ key ]
2020-05-03 15:39:34 +03:00
c . mu . RUnlock ( )
2015-05-22 04:25:21 +03:00
return
2014-07-16 22:14:03 +04:00
}
2016-04-15 02:16:46 +03:00
// MustGet returns the value for the given key if it exists, otherwise it panics.
2022-03-21 04:43:17 +03:00
func ( c * Context ) MustGet ( key string ) any {
2015-05-22 04:25:21 +03:00
if value , exists := c . Get ( key ) ; exists {
return value
2014-07-16 22:14:03 +04:00
}
2015-05-22 04:25:21 +03:00
panic ( "Key \"" + key + "\" does not exist" )
2014-07-16 22:14:03 +04:00
}
2017-06-02 04:00:04 +03: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 04:33:54 +03: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 04:00:04 +03: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.
2022-03-21 04:43:17 +03:00
func ( c * Context ) GetStringMap ( key string ) ( sm map [ string ] any ) {
2017-06-02 04:00:04 +03:00
if val , ok := c . Get ( key ) ; ok && val != nil {
2022-03-21 04:43:17 +03:00
sm , _ = val . ( map [ string ] any )
2017-06-02 04:00:04 +03:00
}
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 16:06:38 +03:00
/************************************/
/************ INPUT DATA ************/
/************************************/
2014-12-21 15:42:48 +03:00
2016-01-27 00:40:29 +03:00
// Param returns the value of the URL param.
// It is a shortcut for c.Params.ByName(key)
2022-08-15 16:38:20 +03:00
//
// router.GET("/user/:id", func(c *gin.Context) {
// // a GET request to /user/john
// id := c.Param("id") // id == "john"
// })
2015-05-26 13:35:05 +03:00
func ( c * Context ) Param ( key string ) string {
return c . Params . ByName ( key )
2015-05-05 16:06:38 +03:00
}
2014-12-21 15:42:48 +03:00
2021-09-07 05:08:45 +03:00
// AddParam adds param to context and
// replaces path param key with given value for e2e testing purposes
// Example Route: "/user/:id"
// AddParam("id", 1)
// Result: "/user/1"
func ( c * Context ) AddParam ( key , value string ) {
c . Params = append ( c . Params , Param { Key : key , Value : value } )
}
2016-01-29 04:42:19 +03:00
// Query returns the keyed url query value if it exists,
2017-05-04 04:22:48 +03:00
// otherwise it returns an empty string `("")`.
2016-01-29 04:42:19 +03:00
// It is shortcut for `c.Request.URL.Query().Get(key)`
2022-08-15 16:38:20 +03:00
//
// GET /path?id=1234&name=Manu&value=
// c.Query("id") == "1234"
// c.Query("name") == "Manu"
// c.Query("value") == ""
// c.Query("wtf") == ""
2021-08-22 04:29:51 +03:00
func ( c * Context ) Query ( key string ) ( value string ) {
value , _ = c . GetQuery ( key )
return
2015-05-05 16:06:38 +03:00
}
2014-12-21 15:42:48 +03:00
2016-01-29 04:42:19 +03:00
// DefaultQuery returns the keyed url query value if it exists,
2017-05-04 04:22:48 +03:00
// otherwise it returns the specified defaultValue string.
2016-01-29 04:42:19 +03:00
// See: Query() and GetQuery() for further information.
2022-08-15 16:38:20 +03:00
//
// GET /?name=Manu&lastname=
// c.DefaultQuery("name", "unknown") == "Manu"
// c.DefaultQuery("id", "none") == "none"
// c.DefaultQuery("lastname", "none") == ""
2015-05-26 13:08:33 +03:00
func ( c * Context ) DefaultQuery ( key , defaultValue string ) string {
2016-01-29 04:07:44 +03:00
if value , ok := c . GetQuery ( key ) ; ok {
2016-01-26 20:36:37 +03:00
return value
2015-05-05 16:06:38 +03:00
}
2015-05-09 04:35:31 +03:00
return defaultValue
2015-05-05 16:06:38 +03:00
}
2014-12-21 15:42:48 +03:00
2016-01-29 04:42:19 +03: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 04:22:48 +03:00
// otherwise it returns `("", false)`.
2016-01-29 04:42:19 +03:00
// It is shortcut for `c.Request.URL.Query().Get(key)`
2022-08-15 16:38:20 +03:00
//
// GET /?name=Manu&lastname=
// ("Manu", true) == c.GetQuery("name")
// ("", false) == c.GetQuery("id")
// ("", true) == c.GetQuery("lastname")
2016-01-29 04:07:44 +03:00
func ( c * Context ) GetQuery ( key string ) ( string , bool ) {
2016-03-30 03:54:21 +03:00
if values , ok := c . GetQueryArray ( key ) ; ok {
return values [ 0 ] , ok
2014-10-09 03:40:42 +04:00
}
2015-05-05 16:06:38 +03:00
return "" , false
2014-12-21 15:42:48 +03:00
}
2016-03-29 19:05:13 +03: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.
2021-08-22 04:29:51 +03:00
func ( c * Context ) QueryArray ( key string ) ( values [ ] string ) {
values , _ = c . GetQueryArray ( key )
return
2016-03-29 19:05:13 +03:00
}
2020-05-14 06:35:14 +03:00
func ( c * Context ) initQueryCache ( ) {
2019-05-29 06:25:02 +03:00
if c . queryCache == nil {
2020-08-08 15:32:19 +03:00
if c . Request != nil {
c . queryCache = c . Request . URL . Query ( )
} else {
c . queryCache = url . Values { }
}
2019-05-29 06:25:02 +03:00
}
2019-05-29 09:54:55 +03:00
}
2019-05-29 06:25:02 +03:00
2019-05-29 09:54:55 +03: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.
2021-08-22 04:29:51 +03:00
func ( c * Context ) GetQueryArray ( key string ) ( values [ ] string , ok bool ) {
2020-05-14 06:35:14 +03:00
c . initQueryCache ( )
2021-08-22 04:29:51 +03:00
values , ok = c . queryCache [ key ]
return
2014-12-21 15:42:48 +03:00
}
2018-08-06 07:07:11 +03:00
// QueryMap returns a map for a given query key.
2021-08-22 04:29:51 +03:00
func ( c * Context ) QueryMap ( key string ) ( dicts map [ string ] string ) {
dicts , _ = c . GetQueryMap ( key )
return
2018-08-06 07:07:11 +03:00
}
// 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 06:35:14 +03:00
c . initQueryCache ( )
2019-05-29 09:54:55 +03:00
return c . get ( c . queryCache , key )
2018-08-06 07:07:11 +03:00
}
2016-01-29 04:42:19 +03:00
// PostForm returns the specified key from a POST urlencoded form or multipart form
// when it exists, otherwise it returns an empty string `("")`.
2021-08-22 04:29:51 +03:00
func ( c * Context ) PostForm ( key string ) ( value string ) {
value , _ = c . GetPostForm ( key )
return
2016-01-29 04:42:19 +03:00
}
2016-04-15 02:16:46 +03:00
// DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
2016-01-29 04:42:19 +03: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:
2022-08-15 16:38:20 +03: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 04:07:44 +03:00
func ( c * Context ) GetPostForm ( key string ) ( string , bool ) {
2016-03-30 03:54:21 +03:00
if values , ok := c . GetPostFormArray ( key ) ; ok {
return values [ 0 ] , ok
2015-05-26 17:16:57 +03:00
}
2015-05-05 16:06:38 +03:00
return "" , false
2014-10-09 03:40:42 +04:00
}
2016-03-29 19:05:13 +03: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.
2021-08-22 04:29:51 +03:00
func ( c * Context ) PostFormArray ( key string ) ( values [ ] string ) {
values , _ = c . GetPostFormArray ( key )
return
2016-03-29 19:05:13 +03:00
}
2020-05-14 06:35:14 +03:00
func ( c * Context ) initFormCache ( ) {
2019-06-02 12:24:41 +03:00
if c . formCache == nil {
c . formCache = make ( url . Values )
req := c . Request
if err := req . ParseMultipartForm ( c . engine . MaxMultipartMemory ) ; err != nil {
2021-09-21 10:22:21 +03:00
if ! errors . Is ( err , http . ErrNotMultipart ) {
2019-06-02 12:24:41 +03:00
debugPrint ( "error on parse multipart form array: %v" , err )
}
}
c . formCache = req . PostForm
}
}
2016-03-29 19:05:13 +03: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.
2021-08-22 04:29:51 +03:00
func ( c * Context ) GetPostFormArray ( key string ) ( values [ ] string , ok bool ) {
2020-05-14 06:35:14 +03:00
c . initFormCache ( )
2021-08-22 04:29:51 +03:00
values , ok = c . formCache [ key ]
return
2014-10-09 03:40:42 +04:00
}
2018-08-06 07:07:11 +03:00
// PostFormMap returns a map for a given form key.
2021-08-22 04:29:51 +03:00
func ( c * Context ) PostFormMap ( key string ) ( dicts map [ string ] string ) {
dicts , _ = c . GetPostFormMap ( key )
return
2018-08-06 07:07:11 +03:00
}
// 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 06:35:14 +03:00
c . initFormCache ( )
2019-09-10 09:32:30 +03:00
return c . get ( c . formCache , key )
2018-08-06 07:07:11 +03:00
}
2022-11-08 14:54:48 +03:00
// get is an internal method and returns a map which satisfies conditions.
2018-08-06 07:07:11 +03:00
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 07:25:01 +03:00
// FormFile returns the first file for the provided form key.
func ( c * Context ) FormFile ( name string ) ( * multipart . FileHeader , error ) {
2018-10-22 18:01:14 +03:00
if c . Request . MultipartForm == nil {
if err := c . Request . ParseMultipartForm ( c . engine . MaxMultipartMemory ) ; err != nil {
return nil , err
}
}
2019-10-31 18:17:12 +03:00
f , fh , err := c . Request . FormFile ( name )
if err != nil {
return nil , err
}
f . Close ( )
2016-12-24 07:25:01 +03:00
return fh , err
}
// MultipartForm is the parsed multipart form, including file uploads.
func ( c * Context ) MultipartForm ( ) ( * multipart . Form , error ) {
2017-09-07 06:45:16 +03:00
err := c . Request . ParseMultipartForm ( c . engine . MaxMultipartMemory )
2016-12-24 07:25:01 +03:00
return c . Request . MultipartForm , err
}
2017-07-16 06:42:08 +03: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 ( )
2022-10-16 04:45:08 +03:00
if err = os . MkdirAll ( filepath . Dir ( dst ) , 0750 ) ; err != nil {
return err
}
2017-07-16 06:42:08 +03:00
out , err := os . Create ( dst )
if err != nil {
return err
}
defer out . Close ( )
2019-01-18 04:32:53 +03:00
_ , err = io . Copy ( out , src )
return err
2017-07-16 06:42:08 +03:00
}
2022-01-20 17:33:35 +03:00
// Bind checks the Method and Content-Type to select a binding engine automatically,
// Depending on the "Content-Type" header different bindings are used, for example:
2022-08-15 16:38:20 +03:00
//
// "application/json" --> JSON binding
// "application/xml" --> XML binding
//
2016-04-02 02:29:28 +03: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 19:42:33 +03:00
// It decodes the json payload into the struct specified as a pointer.
2017-12-20 04:32:39 +03:00
// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
2022-03-21 04:43:17 +03:00
func ( c * Context ) Bind ( obj any ) error {
2015-05-22 04:25:21 +03:00
b := binding . Default ( c . Request . Method , c . ContentType ( ) )
2017-06-28 01:46:35 +03:00
return c . MustBindWith ( obj , b )
2014-07-16 22:14:03 +04:00
}
2017-08-16 06:55:50 +03:00
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindJSON ( obj any ) error {
2017-06-28 01:46:35 +03:00
return c . MustBindWith ( obj , binding . JSON )
2014-07-16 22:14:03 +04:00
}
2018-08-17 04:12:15 +03:00
// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindXML ( obj any ) error {
2018-08-17 04:12:15 +03:00
return c . MustBindWith ( obj , binding . XML )
}
2017-08-16 06:55:50 +03:00
// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindQuery ( obj any ) error {
2017-07-19 10:50:05 +03:00
return c . MustBindWith ( obj , binding . Query )
}
2018-11-06 04:49:45 +03:00
// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindYAML ( obj any ) error {
2018-11-06 04:49:45 +03:00
return c . MustBindWith ( obj , binding . YAML )
}
2022-05-28 03:34:43 +03:00
// BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML).
func ( c * Context ) BindTOML ( obj interface { } ) error {
return c . MustBindWith ( obj , binding . TOML )
}
2019-06-27 07:47:45 +03:00
// BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindHeader ( obj any ) error {
2019-06-27 07:47:45 +03:00
return c . MustBindWith ( obj , binding . Header )
}
2018-12-12 18:40:29 +03:00
// BindUri binds the passed struct pointer using binding.Uri.
// It will abort the request with HTTP 400 if any error occurs.
2022-03-21 04:43:17 +03:00
func ( c * Context ) BindUri ( obj any ) error {
2018-12-12 18:40:29 +03:00
if err := c . ShouldBindUri ( obj ) ; err != nil {
2022-08-15 16:38:20 +03:00
c . AbortWithError ( http . StatusBadRequest , err ) . SetType ( ErrorTypeBind ) //nolint: errcheck
2018-12-12 18:40:29 +03:00
return err
}
return nil
}
2017-08-16 06:55:50 +03:00
// MustBindWith binds the passed struct pointer using the specified binding engine.
2018-11-05 09:17:04 +03:00
// It will abort the request with HTTP 400 if any error occurs.
2015-07-02 19:42:33 +03:00
// See the binding package.
2022-03-21 04:43:17 +03:00
func ( c * Context ) MustBindWith ( obj any , b binding . Binding ) error {
2018-12-12 18:40:29 +03:00
if err := c . ShouldBindWith ( obj , b ) ; err != nil {
2022-08-15 16:38:20 +03:00
c . AbortWithError ( http . StatusBadRequest , err ) . SetType ( ErrorTypeBind ) //nolint: errcheck
2018-12-12 18:40:29 +03:00
return err
2014-07-16 22:14:03 +04:00
}
2018-12-12 18:40:29 +03:00
return nil
2017-03-29 17:32:12 +03:00
}
2022-01-20 17:33:35 +03:00
// ShouldBind checks the Method and Content-Type to select a binding engine automatically,
// Depending on the "Content-Type" header different bindings are used, for example:
2022-08-15 16:38:20 +03:00
//
// "application/json" --> JSON binding
// "application/xml" --> XML binding
//
2017-10-23 12:14:09 +03:00
// 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.
2022-01-20 17:33:35 +03:00
// Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid.
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBind ( obj any ) error {
2017-10-23 12:14:09 +03:00
b := binding . Default ( c . Request . Method , c . ContentType ( ) )
return c . ShouldBindWith ( obj , b )
}
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindJSON ( obj any ) error {
2017-10-23 12:14:09 +03:00
return c . ShouldBindWith ( obj , binding . JSON )
}
2018-08-17 04:12:15 +03:00
// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindXML ( obj any ) error {
2018-08-17 04:12:15 +03:00
return c . ShouldBindWith ( obj , binding . XML )
}
2017-10-23 12:14:09 +03:00
// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindQuery ( obj any ) error {
2017-10-23 12:14:09 +03:00
return c . ShouldBindWith ( obj , binding . Query )
}
2018-11-06 04:49:45 +03:00
// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindYAML ( obj any ) error {
2018-11-06 04:49:45 +03:00
return c . ShouldBindWith ( obj , binding . YAML )
}
2022-05-28 03:34:43 +03:00
// ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML).
func ( c * Context ) ShouldBindTOML ( obj interface { } ) error {
return c . ShouldBindWith ( obj , binding . TOML )
}
2019-06-27 07:47:45 +03:00
// ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindHeader ( obj any ) error {
2019-06-27 07:47:45 +03:00
return c . ShouldBindWith ( obj , binding . Header )
}
2018-11-22 04:29:48 +03:00
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindUri ( obj any ) error {
2018-11-22 04:29:48 +03:00
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 06:55:50 +03:00
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
2017-03-29 17:32:12 +03:00
// See the binding package.
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindWith ( obj any , b binding . Binding ) error {
2017-03-29 17:32:12 +03:00
return b . Bind ( c . Request , obj )
2014-07-16 22:14:03 +04:00
}
2018-05-11 05:33:33 +03: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.
2022-03-21 04:43:17 +03:00
func ( c * Context ) ShouldBindBodyWith ( obj any , bb binding . BindingBody ) ( err error ) {
2018-05-11 05:33:33 +03:00
var body [ ] byte
if cb , ok := c . Get ( BodyBytesKey ) ; ok {
if cbb , ok := cb . ( [ ] byte ) ; ok {
body = cbb
}
}
if body == nil {
2022-11-17 17:35:55 +03:00
body , err = io . ReadAll ( c . Request . Body )
2018-05-11 05:33:33 +03:00
if err != nil {
return err
}
c . Set ( BodyBytesKey , body )
}
return bb . BindBody ( body , obj )
}
2021-10-24 03:34:03 +03:00
// ClientIP implements one best effort algorithm to return the real client IP.
2022-06-09 05:08:49 +03:00
// It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
2021-09-29 02:35:06 +03:00
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
// If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy,
2021-11-30 03:36:36 +03:00
// the remote IP (coming from Request.RemoteAddr) is returned.
2015-03-31 18:44:45 +03:00
func ( c * Context ) ClientIP ( ) string {
2021-10-24 03:34:03 +03:00
// Check if we're running on a trusted platform, continue running backwards if error
if c . engine . TrustedPlatform != "" {
// Developers can define their own header of Trusted Platform or use predefined constants
if addr := c . requestHeader ( c . engine . TrustedPlatform ) ; addr != "" {
2021-05-28 05:03:59 +03:00
return addr
}
2021-04-06 06:37:25 +03:00
}
2021-06-24 03:58:10 +03: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-12-03 09:49:16 +03:00
// 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 by Engine.SetTrustedProxies()
remoteIP := net . ParseIP ( c . RemoteIP ( ) )
2021-04-06 06:37:25 +03:00
if remoteIP == nil {
return ""
}
2021-12-03 09:49:16 +03:00
trusted := c . engine . isTrustedProxy ( remoteIP )
2021-04-06 06:37:25 +03:00
if trusted && c . engine . ForwardedByClientIP && c . engine . RemoteIPHeaders != nil {
for _ , headerName := range c . engine . RemoteIPHeaders {
2021-10-09 03:38:51 +03:00
ip , valid := c . engine . validateHeader ( c . requestHeader ( headerName ) )
2021-04-06 06:37:25 +03:00
if valid {
return ip
}
2016-08-30 18:58:39 +03:00
}
2014-10-09 03:40:42 +04:00
}
2021-04-06 06:37:25 +03:00
return remoteIP . String ( )
}
2016-12-05 13:21:59 +03:00
2021-04-06 06:37:25 +03:00
// RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
2021-12-03 09:49:16 +03:00
func ( c * Context ) RemoteIP ( ) string {
2021-04-06 06:37:25 +03:00
ip , _ , err := net . SplitHostPort ( strings . TrimSpace ( c . Request . RemoteAddr ) )
if err != nil {
2021-12-03 09:49:16 +03:00
return ""
2021-04-06 06:37:25 +03:00
}
2021-12-03 09:49:16 +03:00
return ip
2014-10-09 03:40:42 +04:00
}
2015-07-02 19:42:33 +03:00
// ContentType returns the Content-Type header of the request.
2015-03-31 18:44:45 +03:00
func ( c * Context ) ContentType ( ) string {
2015-06-04 14:15:22 +03:00
return filterFlags ( c . requestHeader ( "Content-Type" ) )
}
2017-01-02 11:05:30 +03: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 18:08:52 +03:00
strings . EqualFold ( c . requestHeader ( "Upgrade" ) , "websocket" ) {
2017-01-02 11:05:30 +03:00
return true
}
return false
}
2015-06-04 14:15:22 +03:00
func ( c * Context ) requestHeader ( key string ) string {
2017-08-26 07:53:27 +03:00
return c . Request . Header . Get ( key )
2014-07-16 22:14:03 +04:00
}
2014-10-08 23:37:26 +04:00
/************************************/
/******** RESPONSE RENDERING ********/
/************************************/
2017-08-16 06:55:50 +03:00
// bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
2017-01-09 18:24:48 +03:00
func bodyAllowedForStatus ( status int ) bool {
switch {
case status >= 100 && status <= 199 :
return false
2018-06-26 12:21:32 +03:00
case status == http . StatusNoContent :
2017-01-09 18:24:48 +03:00
return false
2018-06-26 12:21:32 +03:00
case status == http . StatusNotModified :
2017-01-09 18:24:48 +03:00
return false
}
return true
}
2017-07-28 03:50:58 +03:00
// Status sets the HTTP response code.
2016-01-26 16:55:45 +03:00
func ( c * Context ) Status ( code int ) {
2019-10-17 05:14:44 +03:00
c . Writer . WriteHeader ( code )
2016-01-26 16:55:45 +03:00
}
2021-11-11 03:07:55 +03:00
// Header is an intelligent shortcut for c.Writer.Header().Set(key, value).
2015-07-02 19:42:33 +03:00
// It writes a header in the response.
2015-05-28 04:22:34 +03:00
// If value == "", this method removes the header `c.Writer.Header().Del(key)`
2015-05-18 16:45:24 +03:00
func ( c * Context ) Header ( key , value string ) {
2017-11-12 08:24:51 +03:00
if value == "" {
2015-05-18 16:45:24 +03:00
c . Writer . Header ( ) . Del ( key )
2018-08-20 16:49:24 +03:00
return
2015-05-18 16:45:24 +03:00
}
2018-08-20 16:49:24 +03:00
c . Writer . Header ( ) . Set ( key , value )
2015-05-07 13:44:52 +03:00
}
2017-08-16 06:55:50 +03:00
// GetHeader returns value from request headers.
2017-03-24 15:43:23 +03:00
func ( c * Context ) GetHeader ( key string ) string {
return c . requestHeader ( key )
}
2022-01-02 09:04:07 +03:00
// GetRawData returns stream data.
2017-03-31 03:45:56 +03:00
func ( c * Context ) GetRawData ( ) ( [ ] byte , error ) {
2022-11-17 17:35:55 +03:00
return io . ReadAll ( c . Request . Body )
2017-03-31 03:45:56 +03:00
}
2020-03-27 05:47:22 +03:00
// SetSameSite with cookie
func ( c * Context ) SetSameSite ( samesite http . SameSite ) {
c . sameSite = samesite
}
2017-08-28 22:38:53 +03: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 05:47:22 +03:00
func ( c * Context ) SetCookie ( name , value string , maxAge int , path , domain string , secure , httpOnly bool ) {
2016-01-26 20:36:37 +03:00
if path == "" {
path = "/"
2015-08-27 11:04:50 +03:00
}
2016-01-28 02:35:09 +03:00
http . SetCookie ( c . Writer , & http . Cookie {
2016-01-26 20:36:37 +03:00
Name : name ,
Value : url . QueryEscape ( value ) ,
MaxAge : maxAge ,
Path : path ,
Domain : domain ,
2020-03-27 05:47:22 +03:00
SameSite : c . sameSite ,
2016-01-26 20:36:37 +03:00
Secure : secure ,
HttpOnly : httpOnly ,
2016-01-28 02:35:09 +03:00
} )
2015-08-27 11:04:50 +03:00
}
2017-08-28 22:38:53 +03: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 20:36:37 +03:00
func ( c * Context ) Cookie ( name string ) ( string , error ) {
2015-08-27 11:04:50 +03:00
cookie , err := c . Request . Cookie ( name )
if err != nil {
2015-10-02 13:37:51 +03:00
return "" , err
2015-08-27 11:04:50 +03:00
}
val , _ := url . QueryUnescape ( cookie . Value )
2015-10-02 13:37:51 +03:00
return val , nil
2015-08-27 11:04:50 +03:00
}
2018-09-15 10:21:54 +03:00
// Render writes the response headers and calls render.Render to render data.
2015-05-18 21:51:52 +03:00
func ( c * Context ) Render ( code int , r render . Render ) {
2016-01-26 16:55:45 +03:00
c . Status ( code )
2017-01-09 18:24:48 +03:00
if ! bodyAllowedForStatus ( code ) {
r . WriteContentType ( c . Writer )
c . Writer . WriteHeaderNow ( )
return
}
2015-06-04 06:25:21 +03:00
if err := r . Render ( c . Writer ) ; err != nil {
2016-01-26 20:35:04 +03:00
panic ( err )
2014-07-16 22:14:03 +04:00
}
}
2015-07-02 19:42:33 +03:00
// HTML renders the HTTP template specified by its file name.
2015-05-07 13:44:52 +03:00
// It also updates the HTTP code and sets the Content-Type as "text/html".
// See http://golang.org/doc/articles/wiki/
2022-03-21 04:43:17 +03:00
func ( c * Context ) HTML ( code int , name string , obj any ) {
2015-05-22 03:24:13 +03:00
instance := c . engine . HTMLRender . Instance ( name , obj )
2015-05-18 21:51:52 +03:00
c . Render ( code , instance )
2015-05-06 23:31:01 +03:00
}
2015-07-02 19:42:33 +03:00
// IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
2015-05-28 04:22:34 +03:00
// It also sets the Content-Type as "application/json".
2021-11-11 03:07:55 +03:00
// WARNING: we recommend using this only for development purposes since printing pretty JSON is
2015-05-28 04:22:34 +03:00
// more CPU and bandwidth consuming. Use Context.JSON() instead.
2022-03-21 04:43:17 +03:00
func ( c * Context ) IndentedJSON ( code int , obj any ) {
2015-05-18 21:51:52 +03:00
c . Render ( code , render . IndentedJSON { Data : obj } )
2014-07-16 22:14:03 +04:00
}
2017-07-07 20:21:30 +03: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".
2022-03-21 04:43:17 +03:00
func ( c * Context ) SecureJSON ( code int , obj any ) {
2020-05-05 08:55:57 +03:00
c . Render ( code , render . SecureJSON { Prefix : c . engine . secureJSONPrefix , Data : obj } )
2017-07-07 20:21:30 +03:00
}
2018-04-26 06:52:19 +03:00
// JSONP serializes the given struct as JSON into the response body.
2020-11-11 04:41:35 +03:00
// It adds padding to response body to request data from a server residing in a different domain than the client.
2018-04-26 06:52:19 +03:00
// It also sets the Content-Type as "application/javascript".
2022-03-21 04:43:17 +03:00
func ( c * Context ) JSONP ( code int , obj any ) {
2018-07-20 19:52:55 +03:00
callback := c . DefaultQuery ( "callback" , "" )
if callback == "" {
c . Render ( code , render . JSON { Data : obj } )
2018-08-20 16:49:24 +03:00
return
2018-07-20 19:52:55 +03:00
}
2018-08-20 16:49:24 +03:00
c . Render ( code , render . JsonpJSON { Callback : callback , Data : obj } )
2018-04-26 06:52:19 +03:00
}
2015-07-02 19:42:33 +03:00
// JSON serializes the given struct as JSON into the response body.
2014-07-16 22:14:03 +04:00
// It also sets the Content-Type as "application/json".
2022-03-21 04:43:17 +03:00
func ( c * Context ) JSON ( code int , obj any ) {
2017-01-09 18:24:48 +03:00
c . Render ( code , render . JSON { Data : obj } )
2014-07-16 22:14:03 +04:00
}
2018-07-03 12:17:08 +03: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".
2022-03-21 04:43:17 +03:00
func ( c * Context ) AsciiJSON ( code int , obj any ) {
2018-07-03 12:17:08 +03:00
c . Render ( code , render . AsciiJSON { Data : obj } )
}
2019-05-07 13:32:32 +03: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.
2022-03-21 04:43:17 +03:00
func ( c * Context ) PureJSON ( code int , obj any ) {
2019-05-07 13:32:32 +03:00
c . Render ( code , render . PureJSON { Data : obj } )
}
2015-07-02 19:42:33 +03:00
// XML serializes the given struct as XML into the response body.
2014-07-16 22:14:03 +04:00
// It also sets the Content-Type as "application/xml".
2022-03-21 04:43:17 +03:00
func ( c * Context ) XML ( code int , obj any ) {
2015-05-18 21:51:52 +03:00
c . Render ( code , render . XML { Data : obj } )
2014-07-16 22:14:03 +04:00
}
2016-04-15 00:47:49 +03:00
// YAML serializes the given struct as YAML into the response body.
2022-03-21 04:43:17 +03:00
func ( c * Context ) YAML ( code int , obj any ) {
2016-04-15 00:47:49 +03:00
c . Render ( code , render . YAML { Data : obj } )
}
2022-05-28 03:34:43 +03:00
// TOML serializes the given struct as TOML into the response body.
func ( c * Context ) TOML ( code int , obj interface { } ) {
c . Render ( code , render . TOML { Data : obj } )
}
2018-08-19 12:39:58 +03:00
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
2022-03-21 04:43:17 +03:00
func ( c * Context ) ProtoBuf ( code int , obj any ) {
2018-08-19 12:39:58 +03:00
c . Render ( code , render . ProtoBuf { Data : obj } )
}
2015-07-02 19:42:33 +03:00
// String writes the given string into the response body.
2022-03-21 04:43:17 +03:00
func ( c * Context ) String ( code int , format string , values ... any ) {
2017-01-09 18:24:48 +03:00
c . Render ( code , render . String { Format : format , Data : values } )
2015-03-08 19:50:58 +03:00
}
2021-11-11 03:07:55 +03:00
// Redirect returns an HTTP redirect to the specific location.
2014-08-02 19:06:09 +04:00
func ( c * Context ) Redirect ( code int , location string ) {
2015-05-18 21:51:52 +03:00
c . Render ( - 1 , render . Redirect {
2015-05-18 16:45:24 +03:00
Code : code ,
Location : location ,
Request : c . Request ,
} )
2014-07-29 02:48:02 +04:00
}
2015-07-02 21:24:54 +03:00
// Data writes some data into the body stream and updates the HTTP code.
2014-07-16 22:14:03 +04:00
func ( c * Context ) Data ( code int , contentType string , data [ ] byte ) {
2015-05-18 21:51:52 +03:00
c . Render ( code , render . Data {
2015-05-18 16:45:24 +03:00
ContentType : contentType ,
Data : data ,
} )
2014-07-16 22:14:03 +04:00
}
2014-07-17 04:01:42 +04:00
2018-05-12 06:00:42 +03: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 04:41:35 +03:00
// File writes the specified file into the body stream in an efficient way.
2014-07-17 04:01:42 +04:00
func ( c * Context ) File ( filepath string ) {
http . ServeFile ( c . Writer , c . Request , filepath )
}
2014-08-31 00:22:57 +04:00
2020-09-14 05:40:20 +03:00
// FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.
2020-03-07 05:23:33 +03: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 05:17:47 +03: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 ) {
2022-03-17 06:56:16 +03:00
if isASCII ( filename ) {
c . Writer . Header ( ) . Set ( "Content-Disposition" , ` attachment; filename=" ` + filename + ` " ` )
} else {
c . Writer . Header ( ) . Set ( "Content-Disposition" , ` attachment; filename*=UTF-8'' ` + url . QueryEscape ( filename ) )
}
2019-03-01 05:17:47 +03:00
http . ServeFile ( c . Writer , c . Request , filepath )
}
2015-07-02 21:24:54 +03:00
// SSEvent writes a Server-Sent Event into the body stream.
2022-03-21 04:43:17 +03:00
func ( c * Context ) SSEvent ( name string , message any ) {
2015-05-18 21:51:52 +03:00
c . Render ( - 1 , sse . Event {
2015-05-18 16:45:24 +03:00
Event : name ,
Data : message ,
} )
2015-05-12 19:33:41 +03:00
}
2019-03-02 18:07:37 +03: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 16:17:46 +03:00
w := c . Writer
clientGone := w . CloseNotify ( )
for {
select {
case <- clientGone :
2019-03-02 18:07:37 +03:00
return true
2015-05-12 16:17:46 +03:00
default :
2016-01-26 17:55:30 +03:00
keepOpen := step ( w )
2015-05-12 16:17:46 +03:00
w . Flush ( )
2016-01-26 17:55:30 +03:00
if ! keepOpen {
2019-03-02 18:07:37 +03:00
return false
2015-05-12 19:33:41 +03:00
}
2015-05-12 16:17:46 +03:00
}
}
}
2014-08-31 00:22:57 +04:00
/************************************/
/******** CONTENT NEGOTIATION *******/
/************************************/
2014-08-31 20:28:18 +04:00
2018-09-15 10:21:54 +03:00
// Negotiate contains all negotiations data.
2014-08-31 00:22:57 +04:00
type Negotiate struct {
Offered [ ] string
2015-05-18 21:52:26 +03:00
HTMLName string
2022-03-21 04:43:17 +03:00
HTMLData any
JSONData any
XMLData any
YAMLData any
Data any
2022-05-28 03:34:43 +03:00
TOMLData any
2014-08-31 00:22:57 +04:00
}
2021-11-26 11:38:10 +03:00
// Negotiate calls different Render according to acceptable Accept format.
2014-08-31 20:28:18 +04:00
func ( c * Context ) Negotiate ( code int , config Negotiate ) {
2014-08-31 20:41:11 +04:00
switch c . NegotiateFormat ( config . Offered ... ) {
2015-03-31 18:51:10 +03:00
case binding . MIMEJSON :
2014-08-31 20:28:18 +04:00
data := chooseData ( config . JSONData , config . Data )
2014-08-31 00:22:57 +04:00
c . JSON ( code , data )
2015-03-31 18:51:10 +03:00
case binding . MIMEHTML :
2014-08-31 20:28:18 +04:00
data := chooseData ( config . HTMLData , config . Data )
2015-05-18 21:52:26 +03:00
c . HTML ( code , config . HTMLName , data )
2014-08-31 00:22:57 +04:00
2015-03-31 18:51:10 +03:00
case binding . MIMEXML :
2014-08-31 20:28:18 +04:00
data := chooseData ( config . XMLData , config . Data )
2014-08-31 00:22:57 +04:00
c . XML ( code , data )
2014-08-31 20:28:18 +04:00
2020-02-06 09:50:21 +03:00
case binding . MIMEYAML :
data := chooseData ( config . YAMLData , config . Data )
c . YAML ( code , data )
2022-05-28 03:34:43 +03:00
case binding . MIMETOML :
data := chooseData ( config . TOMLData , config . Data )
c . TOML ( code , data )
2014-08-31 00:22:57 +04:00
default :
2022-08-15 16:38:20 +03:00
c . AbortWithError ( http . StatusNotAcceptable , errors . New ( "the accepted formats are not offered by the server" ) ) //nolint: errcheck
2014-08-31 00:22:57 +04:00
}
}
2018-09-15 10:21:54 +03:00
// NegotiateFormat returns an acceptable Accept format.
2014-08-31 00:22:57 +04:00
func ( c * Context ) NegotiateFormat ( offered ... string ) string {
2016-01-28 02:35:09 +03:00
assert1 ( len ( offered ) > 0 , "you must provide at least one offer" )
2015-04-08 00:28:36 +03:00
if c . Accepted == nil {
2015-06-04 14:15:22 +03:00
c . Accepted = parseAccept ( c . requestHeader ( "Accept" ) )
2014-08-31 00:22:57 +04:00
}
2015-04-08 00:28:36 +03:00
if len ( c . Accepted ) == 0 {
2014-08-31 00:22:57 +04:00
return offered [ 0 ]
2015-04-08 00:28:36 +03:00
}
for _ , accepted := range c . Accepted {
2020-01-07 04:19:49 +03:00
for _ , offer := range offered {
2019-03-01 05:03:14 +03: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 04:19:49 +03:00
if accepted [ i ] == '*' || offer [ i ] == '*' {
return offer
2019-03-01 05:03:14 +03:00
}
2020-01-07 04:19:49 +03:00
if accepted [ i ] != offer [ i ] {
2019-03-01 05:03:14 +03:00
break
}
}
if i == len ( accepted ) {
2020-01-07 04:19:49 +03:00
return offer
2014-08-31 00:22:57 +04:00
}
}
}
2015-04-08 00:28:36 +03:00
return ""
2014-08-31 00:22:57 +04:00
}
2018-09-15 10:21:54 +03:00
// SetAccepted sets Accept header data.
2014-08-31 00:22:57 +04:00
func ( c * Context ) SetAccepted ( formats ... string ) {
2015-04-08 00:28:36 +03:00
c . Accepted = formats
2014-08-31 00:22:57 +04:00
}
2015-05-18 22:26:29 +03:00
2019-01-09 04:32:44 +03:00
/************************************/
/***** GOLANG.ORG/X/NET/CONTEXT *****/
/************************************/
2021-07-31 19:46:53 +03:00
// Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
2019-01-09 04:32:44 +03:00
func ( c * Context ) Deadline ( ) ( deadline time . Time , ok bool ) {
2022-06-06 13:43:53 +03:00
if ! c . engine . ContextWithFallback || c . Request == nil || c . Request . Context ( ) == nil {
2021-07-31 19:46:53 +03:00
return
}
return c . Request . Context ( ) . Deadline ( )
2019-01-09 04:32:44 +03:00
}
2021-07-31 19:46:53 +03:00
// Done returns nil (chan which will wait forever) when c.Request has no Context.
2019-01-09 04:32:44 +03:00
func ( c * Context ) Done ( ) <- chan struct { } {
2022-06-06 13:43:53 +03:00
if ! c . engine . ContextWithFallback || c . Request == nil || c . Request . Context ( ) == nil {
2021-07-31 19:46:53 +03:00
return nil
}
return c . Request . Context ( ) . Done ( )
2019-01-09 04:32:44 +03:00
}
2021-07-31 19:46:53 +03:00
// Err returns nil when c.Request has no Context.
2019-01-09 04:32:44 +03:00
func ( c * Context ) Err ( ) error {
2022-06-06 13:43:53 +03:00
if ! c . engine . ContextWithFallback || c . Request == nil || c . Request . Context ( ) == nil {
2021-07-31 19:46:53 +03:00
return nil
}
return c . Request . Context ( ) . Err ( )
2019-01-09 04:32:44 +03:00
}
2018-06-28 12:08:09 +03: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.
2022-03-21 04:43:17 +03:00
func ( c * Context ) Value ( key any ) any {
2015-05-18 22:26:29 +03:00
if key == 0 {
return c . Request
}
2022-04-23 13:02:54 +03:00
if key == ContextKey {
return c
}
2015-05-18 22:26:29 +03:00
if keyAsString , ok := key . ( string ) ; ok {
2021-06-24 11:33:14 +03:00
if val , exists := c . Get ( keyAsString ) ; exists {
return val
}
2015-05-18 22:26:29 +03:00
}
2022-06-06 13:43:53 +03:00
if ! c . engine . ContextWithFallback || c . Request == nil || c . Request . Context ( ) == nil {
2021-06-24 11:33:14 +03:00
return nil
}
return c . Request . Context ( ) . Value ( key )
2014-08-31 00:22:57 +04:00
}