...

Source file src/github.com/gin-gonic/gin/context.go

Documentation: github.com/gin-gonic/gin

     1  // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
     2  // Use of this source code is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gin
     6  
     7  import (
     8  	"errors"
     9  	"io"
    10  	"log"
    11  	"math"
    12  	"mime/multipart"
    13  	"net"
    14  	"net/http"
    15  	"net/url"
    16  	"os"
    17  	"path/filepath"
    18  	"strings"
    19  	"sync"
    20  	"time"
    21  
    22  	"github.com/gin-contrib/sse"
    23  	"github.com/gin-gonic/gin/binding"
    24  	"github.com/gin-gonic/gin/render"
    25  )
    26  
    27  // Content-Type MIME of the most common data formats.
    28  const (
    29  	MIMEJSON              = binding.MIMEJSON
    30  	MIMEHTML              = binding.MIMEHTML
    31  	MIMEXML               = binding.MIMEXML
    32  	MIMEXML2              = binding.MIMEXML2
    33  	MIMEPlain             = binding.MIMEPlain
    34  	MIMEPOSTForm          = binding.MIMEPOSTForm
    35  	MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
    36  	MIMEYAML              = binding.MIMEYAML
    37  	MIMETOML              = binding.MIMETOML
    38  )
    39  
    40  // BodyBytesKey indicates a default body bytes key.
    41  const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
    42  
    43  // ContextKey is the key that a Context returns itself for.
    44  const ContextKey = "_gin-gonic/gin/contextkey"
    45  
    46  // abortIndex represents a typical value used in abort functions.
    47  const abortIndex int8 = math.MaxInt8 >> 1
    48  
    49  // Context is the most important part of gin. It allows us to pass variables between middleware,
    50  // manage the flow, validate the JSON of a request and render a JSON response for example.
    51  type Context struct {
    52  	writermem responseWriter
    53  	Request   *http.Request
    54  	Writer    ResponseWriter
    55  
    56  	Params   Params
    57  	handlers HandlersChain
    58  	index    int8
    59  	fullPath string
    60  
    61  	engine       *Engine
    62  	params       *Params
    63  	skippedNodes *[]skippedNode
    64  
    65  	// This mutex protects Keys map.
    66  	mu sync.RWMutex
    67  
    68  	// Keys is a key/value pair exclusively for the context of each request.
    69  	Keys map[string]any
    70  
    71  	// Errors is a list of errors attached to all the handlers/middlewares who used this context.
    72  	Errors errorMsgs
    73  
    74  	// Accepted defines a list of manually accepted formats for content negotiation.
    75  	Accepted []string
    76  
    77  	// queryCache caches the query result from c.Request.URL.Query().
    78  	queryCache url.Values
    79  
    80  	// formCache caches c.Request.PostForm, which contains the parsed form data from POST, PATCH,
    81  	// or PUT body parameters.
    82  	formCache url.Values
    83  
    84  	// SameSite allows a server to define a cookie attribute making it impossible for
    85  	// the browser to send this cookie along with cross-site requests.
    86  	sameSite http.SameSite
    87  }
    88  
    89  /************************************/
    90  /********** CONTEXT CREATION ********/
    91  /************************************/
    92  
    93  func (c *Context) reset() {
    94  	c.Writer = &c.writermem
    95  	c.Params = c.Params[:0]
    96  	c.handlers = nil
    97  	c.index = -1
    98  
    99  	c.fullPath = ""
   100  	c.Keys = nil
   101  	c.Errors = c.Errors[:0]
   102  	c.Accepted = nil
   103  	c.queryCache = nil
   104  	c.formCache = nil
   105  	c.sameSite = 0
   106  	*c.params = (*c.params)[:0]
   107  	*c.skippedNodes = (*c.skippedNodes)[:0]
   108  }
   109  
   110  // Copy returns a copy of the current context that can be safely used outside the request's scope.
   111  // This has to be used when the context has to be passed to a goroutine.
   112  func (c *Context) Copy() *Context {
   113  	cp := Context{
   114  		writermem: c.writermem,
   115  		Request:   c.Request,
   116  		Params:    c.Params,
   117  		engine:    c.engine,
   118  	}
   119  	cp.writermem.ResponseWriter = nil
   120  	cp.Writer = &cp.writermem
   121  	cp.index = abortIndex
   122  	cp.handlers = nil
   123  	cp.Keys = map[string]any{}
   124  	for k, v := range c.Keys {
   125  		cp.Keys[k] = v
   126  	}
   127  	paramCopy := make([]Param, len(cp.Params))
   128  	copy(paramCopy, cp.Params)
   129  	cp.Params = paramCopy
   130  	return &cp
   131  }
   132  
   133  // HandlerName returns the main handler's name. For example if the handler is "handleGetUsers()",
   134  // this function will return "main.handleGetUsers".
   135  func (c *Context) HandlerName() string {
   136  	return nameOfFunction(c.handlers.Last())
   137  }
   138  
   139  // HandlerNames returns a list of all registered handlers for this context in descending order,
   140  // following the semantics of HandlerName()
   141  func (c *Context) HandlerNames() []string {
   142  	hn := make([]string, 0, len(c.handlers))
   143  	for _, val := range c.handlers {
   144  		hn = append(hn, nameOfFunction(val))
   145  	}
   146  	return hn
   147  }
   148  
   149  // Handler returns the main handler.
   150  func (c *Context) Handler() HandlerFunc {
   151  	return c.handlers.Last()
   152  }
   153  
   154  // FullPath returns a matched route full path. For not found routes
   155  // returns an empty string.
   156  //
   157  //	router.GET("/user/:id", func(c *gin.Context) {
   158  //	    c.FullPath() == "/user/:id" // true
   159  //	})
   160  func (c *Context) FullPath() string {
   161  	return c.fullPath
   162  }
   163  
   164  /************************************/
   165  /*********** FLOW CONTROL ***********/
   166  /************************************/
   167  
   168  // Next should be used only inside middleware.
   169  // It executes the pending handlers in the chain inside the calling handler.
   170  // See example in GitHub.
   171  func (c *Context) Next() {
   172  	c.index++
   173  	for c.index < int8(len(c.handlers)) {
   174  		c.handlers[c.index](c)
   175  		c.index++
   176  	}
   177  }
   178  
   179  // IsAborted returns true if the current context was aborted.
   180  func (c *Context) IsAborted() bool {
   181  	return c.index >= abortIndex
   182  }
   183  
   184  // Abort prevents pending handlers from being called. Note that this will not stop the current handler.
   185  // Let's say you have an authorization middleware that validates that the current request is authorized.
   186  // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
   187  // for this request are not called.
   188  func (c *Context) Abort() {
   189  	c.index = abortIndex
   190  }
   191  
   192  // AbortWithStatus calls `Abort()` and writes the headers with the specified status code.
   193  // For example, a failed attempt to authenticate a request could use: context.AbortWithStatus(401).
   194  func (c *Context) AbortWithStatus(code int) {
   195  	c.Status(code)
   196  	c.Writer.WriteHeaderNow()
   197  	c.Abort()
   198  }
   199  
   200  // AbortWithStatusJSON calls `Abort()` and then `JSON` internally.
   201  // This method stops the chain, writes the status code and return a JSON body.
   202  // It also sets the Content-Type as "application/json".
   203  func (c *Context) AbortWithStatusJSON(code int, jsonObj any) {
   204  	c.Abort()
   205  	c.JSON(code, jsonObj)
   206  }
   207  
   208  // AbortWithError calls `AbortWithStatus()` and `Error()` internally.
   209  // This method stops the chain, writes the status code and pushes the specified error to `c.Errors`.
   210  // See Context.Error() for more details.
   211  func (c *Context) AbortWithError(code int, err error) *Error {
   212  	c.AbortWithStatus(code)
   213  	return c.Error(err)
   214  }
   215  
   216  /************************************/
   217  /********* ERROR MANAGEMENT *********/
   218  /************************************/
   219  
   220  // Error attaches an error to the current context. The error is pushed to a list of errors.
   221  // It's a good idea to call Error for each error that occurred during the resolution of a request.
   222  // A middleware can be used to collect all the errors and push them to a database together,
   223  // print a log, or append it in the HTTP response.
   224  // Error will panic if err is nil.
   225  func (c *Context) Error(err error) *Error {
   226  	if err == nil {
   227  		panic("err is nil")
   228  	}
   229  
   230  	var parsedError *Error
   231  	ok := errors.As(err, &parsedError)
   232  	if !ok {
   233  		parsedError = &Error{
   234  			Err:  err,
   235  			Type: ErrorTypePrivate,
   236  		}
   237  	}
   238  
   239  	c.Errors = append(c.Errors, parsedError)
   240  	return parsedError
   241  }
   242  
   243  /************************************/
   244  /******** METADATA MANAGEMENT********/
   245  /************************************/
   246  
   247  // Set is used to store a new key/value pair exclusively for this context.
   248  // It also lazy initializes  c.Keys if it was not used previously.
   249  func (c *Context) Set(key string, value any) {
   250  	c.mu.Lock()
   251  	defer c.mu.Unlock()
   252  	if c.Keys == nil {
   253  		c.Keys = make(map[string]any)
   254  	}
   255  
   256  	c.Keys[key] = value
   257  }
   258  
   259  // Get returns the value for the given key, ie: (value, true).
   260  // If the value does not exist it returns (nil, false)
   261  func (c *Context) Get(key string) (value any, exists bool) {
   262  	c.mu.RLock()
   263  	defer c.mu.RUnlock()
   264  	value, exists = c.Keys[key]
   265  	return
   266  }
   267  
   268  // MustGet returns the value for the given key if it exists, otherwise it panics.
   269  func (c *Context) MustGet(key string) any {
   270  	if value, exists := c.Get(key); exists {
   271  		return value
   272  	}
   273  	panic("Key \"" + key + "\" does not exist")
   274  }
   275  
   276  // GetString returns the value associated with the key as a string.
   277  func (c *Context) GetString(key string) (s string) {
   278  	if val, ok := c.Get(key); ok && val != nil {
   279  		s, _ = val.(string)
   280  	}
   281  	return
   282  }
   283  
   284  // GetBool returns the value associated with the key as a boolean.
   285  func (c *Context) GetBool(key string) (b bool) {
   286  	if val, ok := c.Get(key); ok && val != nil {
   287  		b, _ = val.(bool)
   288  	}
   289  	return
   290  }
   291  
   292  // GetInt returns the value associated with the key as an integer.
   293  func (c *Context) GetInt(key string) (i int) {
   294  	if val, ok := c.Get(key); ok && val != nil {
   295  		i, _ = val.(int)
   296  	}
   297  	return
   298  }
   299  
   300  // GetInt64 returns the value associated with the key as an integer.
   301  func (c *Context) GetInt64(key string) (i64 int64) {
   302  	if val, ok := c.Get(key); ok && val != nil {
   303  		i64, _ = val.(int64)
   304  	}
   305  	return
   306  }
   307  
   308  // GetUint returns the value associated with the key as an unsigned integer.
   309  func (c *Context) GetUint(key string) (ui uint) {
   310  	if val, ok := c.Get(key); ok && val != nil {
   311  		ui, _ = val.(uint)
   312  	}
   313  	return
   314  }
   315  
   316  // GetUint64 returns the value associated with the key as an unsigned integer.
   317  func (c *Context) GetUint64(key string) (ui64 uint64) {
   318  	if val, ok := c.Get(key); ok && val != nil {
   319  		ui64, _ = val.(uint64)
   320  	}
   321  	return
   322  }
   323  
   324  // GetFloat64 returns the value associated with the key as a float64.
   325  func (c *Context) GetFloat64(key string) (f64 float64) {
   326  	if val, ok := c.Get(key); ok && val != nil {
   327  		f64, _ = val.(float64)
   328  	}
   329  	return
   330  }
   331  
   332  // GetTime returns the value associated with the key as time.
   333  func (c *Context) GetTime(key string) (t time.Time) {
   334  	if val, ok := c.Get(key); ok && val != nil {
   335  		t, _ = val.(time.Time)
   336  	}
   337  	return
   338  }
   339  
   340  // GetDuration returns the value associated with the key as a duration.
   341  func (c *Context) GetDuration(key string) (d time.Duration) {
   342  	if val, ok := c.Get(key); ok && val != nil {
   343  		d, _ = val.(time.Duration)
   344  	}
   345  	return
   346  }
   347  
   348  // GetStringSlice returns the value associated with the key as a slice of strings.
   349  func (c *Context) GetStringSlice(key string) (ss []string) {
   350  	if val, ok := c.Get(key); ok && val != nil {
   351  		ss, _ = val.([]string)
   352  	}
   353  	return
   354  }
   355  
   356  // GetStringMap returns the value associated with the key as a map of interfaces.
   357  func (c *Context) GetStringMap(key string) (sm map[string]any) {
   358  	if val, ok := c.Get(key); ok && val != nil {
   359  		sm, _ = val.(map[string]any)
   360  	}
   361  	return
   362  }
   363  
   364  // GetStringMapString returns the value associated with the key as a map of strings.
   365  func (c *Context) GetStringMapString(key string) (sms map[string]string) {
   366  	if val, ok := c.Get(key); ok && val != nil {
   367  		sms, _ = val.(map[string]string)
   368  	}
   369  	return
   370  }
   371  
   372  // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
   373  func (c *Context) GetStringMapStringSlice(key string) (smss map[string][]string) {
   374  	if val, ok := c.Get(key); ok && val != nil {
   375  		smss, _ = val.(map[string][]string)
   376  	}
   377  	return
   378  }
   379  
   380  /************************************/
   381  /************ INPUT DATA ************/
   382  /************************************/
   383  
   384  // Param returns the value of the URL param.
   385  // It is a shortcut for c.Params.ByName(key)
   386  //
   387  //	router.GET("/user/:id", func(c *gin.Context) {
   388  //	    // a GET request to /user/john
   389  //	    id := c.Param("id") // id == "/john"
   390  //	    // a GET request to /user/john/
   391  //	    id := c.Param("id") // id == "/john/"
   392  //	})
   393  func (c *Context) Param(key string) string {
   394  	return c.Params.ByName(key)
   395  }
   396  
   397  // AddParam adds param to context and
   398  // replaces path param key with given value for e2e testing purposes
   399  // Example Route: "/user/:id"
   400  // AddParam("id", 1)
   401  // Result: "/user/1"
   402  func (c *Context) AddParam(key, value string) {
   403  	c.Params = append(c.Params, Param{Key: key, Value: value})
   404  }
   405  
   406  // Query returns the keyed url query value if it exists,
   407  // otherwise it returns an empty string `("")`.
   408  // It is shortcut for `c.Request.URL.Query().Get(key)`
   409  //
   410  //	    GET /path?id=1234&name=Manu&value=
   411  //		   c.Query("id") == "1234"
   412  //		   c.Query("name") == "Manu"
   413  //		   c.Query("value") == ""
   414  //		   c.Query("wtf") == ""
   415  func (c *Context) Query(key string) (value string) {
   416  	value, _ = c.GetQuery(key)
   417  	return
   418  }
   419  
   420  // DefaultQuery returns the keyed url query value if it exists,
   421  // otherwise it returns the specified defaultValue string.
   422  // See: Query() and GetQuery() for further information.
   423  //
   424  //	GET /?name=Manu&lastname=
   425  //	c.DefaultQuery("name", "unknown") == "Manu"
   426  //	c.DefaultQuery("id", "none") == "none"
   427  //	c.DefaultQuery("lastname", "none") == ""
   428  func (c *Context) DefaultQuery(key, defaultValue string) string {
   429  	if value, ok := c.GetQuery(key); ok {
   430  		return value
   431  	}
   432  	return defaultValue
   433  }
   434  
   435  // GetQuery is like Query(), it returns the keyed url query value
   436  // if it exists `(value, true)` (even when the value is an empty string),
   437  // otherwise it returns `("", false)`.
   438  // It is shortcut for `c.Request.URL.Query().Get(key)`
   439  //
   440  //	GET /?name=Manu&lastname=
   441  //	("Manu", true) == c.GetQuery("name")
   442  //	("", false) == c.GetQuery("id")
   443  //	("", true) == c.GetQuery("lastname")
   444  func (c *Context) GetQuery(key string) (string, bool) {
   445  	if values, ok := c.GetQueryArray(key); ok {
   446  		return values[0], ok
   447  	}
   448  	return "", false
   449  }
   450  
   451  // QueryArray returns a slice of strings for a given query key.
   452  // The length of the slice depends on the number of params with the given key.
   453  func (c *Context) QueryArray(key string) (values []string) {
   454  	values, _ = c.GetQueryArray(key)
   455  	return
   456  }
   457  
   458  func (c *Context) initQueryCache() {
   459  	if c.queryCache == nil {
   460  		if c.Request != nil {
   461  			c.queryCache = c.Request.URL.Query()
   462  		} else {
   463  			c.queryCache = url.Values{}
   464  		}
   465  	}
   466  }
   467  
   468  // GetQueryArray returns a slice of strings for a given query key, plus
   469  // a boolean value whether at least one value exists for the given key.
   470  func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
   471  	c.initQueryCache()
   472  	values, ok = c.queryCache[key]
   473  	return
   474  }
   475  
   476  // QueryMap returns a map for a given query key.
   477  func (c *Context) QueryMap(key string) (dicts map[string]string) {
   478  	dicts, _ = c.GetQueryMap(key)
   479  	return
   480  }
   481  
   482  // GetQueryMap returns a map for a given query key, plus a boolean value
   483  // whether at least one value exists for the given key.
   484  func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
   485  	c.initQueryCache()
   486  	return c.get(c.queryCache, key)
   487  }
   488  
   489  // PostForm returns the specified key from a POST urlencoded form or multipart form
   490  // when it exists, otherwise it returns an empty string `("")`.
   491  func (c *Context) PostForm(key string) (value string) {
   492  	value, _ = c.GetPostForm(key)
   493  	return
   494  }
   495  
   496  // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
   497  // when it exists, otherwise it returns the specified defaultValue string.
   498  // See: PostForm() and GetPostForm() for further information.
   499  func (c *Context) DefaultPostForm(key, defaultValue string) string {
   500  	if value, ok := c.GetPostForm(key); ok {
   501  		return value
   502  	}
   503  	return defaultValue
   504  }
   505  
   506  // GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded
   507  // form or multipart form when it exists `(value, true)` (even when the value is an empty string),
   508  // otherwise it returns ("", false).
   509  // For example, during a PATCH request to update the user's email:
   510  //
   511  //	    email=mail@example.com  -->  ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"
   512  //		   email=                  -->  ("", true) := GetPostForm("email") // set email to ""
   513  //	                            -->  ("", false) := GetPostForm("email") // do nothing with email
   514  func (c *Context) GetPostForm(key string) (string, bool) {
   515  	if values, ok := c.GetPostFormArray(key); ok {
   516  		return values[0], ok
   517  	}
   518  	return "", false
   519  }
   520  
   521  // PostFormArray returns a slice of strings for a given form key.
   522  // The length of the slice depends on the number of params with the given key.
   523  func (c *Context) PostFormArray(key string) (values []string) {
   524  	values, _ = c.GetPostFormArray(key)
   525  	return
   526  }
   527  
   528  func (c *Context) initFormCache() {
   529  	if c.formCache == nil {
   530  		c.formCache = make(url.Values)
   531  		req := c.Request
   532  		if err := req.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
   533  			if !errors.Is(err, http.ErrNotMultipart) {
   534  				debugPrint("error on parse multipart form array: %v", err)
   535  			}
   536  		}
   537  		c.formCache = req.PostForm
   538  	}
   539  }
   540  
   541  // GetPostFormArray returns a slice of strings for a given form key, plus
   542  // a boolean value whether at least one value exists for the given key.
   543  func (c *Context) GetPostFormArray(key string) (values []string, ok bool) {
   544  	c.initFormCache()
   545  	values, ok = c.formCache[key]
   546  	return
   547  }
   548  
   549  // PostFormMap returns a map for a given form key.
   550  func (c *Context) PostFormMap(key string) (dicts map[string]string) {
   551  	dicts, _ = c.GetPostFormMap(key)
   552  	return
   553  }
   554  
   555  // GetPostFormMap returns a map for a given form key, plus a boolean value
   556  // whether at least one value exists for the given key.
   557  func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
   558  	c.initFormCache()
   559  	return c.get(c.formCache, key)
   560  }
   561  
   562  // get is an internal method and returns a map which satisfies conditions.
   563  func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) {
   564  	dicts := make(map[string]string)
   565  	exist := false
   566  	for k, v := range m {
   567  		if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key {
   568  			if j := strings.IndexByte(k[i+1:], ']'); j >= 1 {
   569  				exist = true
   570  				dicts[k[i+1:][:j]] = v[0]
   571  			}
   572  		}
   573  	}
   574  	return dicts, exist
   575  }
   576  
   577  // FormFile returns the first file for the provided form key.
   578  func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
   579  	if c.Request.MultipartForm == nil {
   580  		if err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory); err != nil {
   581  			return nil, err
   582  		}
   583  	}
   584  	f, fh, err := c.Request.FormFile(name)
   585  	if err != nil {
   586  		return nil, err
   587  	}
   588  	f.Close()
   589  	return fh, err
   590  }
   591  
   592  // MultipartForm is the parsed multipart form, including file uploads.
   593  func (c *Context) MultipartForm() (*multipart.Form, error) {
   594  	err := c.Request.ParseMultipartForm(c.engine.MaxMultipartMemory)
   595  	return c.Request.MultipartForm, err
   596  }
   597  
   598  // SaveUploadedFile uploads the form file to specific dst.
   599  func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error {
   600  	src, err := file.Open()
   601  	if err != nil {
   602  		return err
   603  	}
   604  	defer src.Close()
   605  
   606  	if err = os.MkdirAll(filepath.Dir(dst), 0750); err != nil {
   607  		return err
   608  	}
   609  
   610  	out, err := os.Create(dst)
   611  	if err != nil {
   612  		return err
   613  	}
   614  	defer out.Close()
   615  
   616  	_, err = io.Copy(out, src)
   617  	return err
   618  }
   619  
   620  // Bind checks the Method and Content-Type to select a binding engine automatically,
   621  // Depending on the "Content-Type" header different bindings are used, for example:
   622  //
   623  //	"application/json" --> JSON binding
   624  //	"application/xml"  --> XML binding
   625  //
   626  // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
   627  // It decodes the json payload into the struct specified as a pointer.
   628  // It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
   629  func (c *Context) Bind(obj any) error {
   630  	b := binding.Default(c.Request.Method, c.ContentType())
   631  	return c.MustBindWith(obj, b)
   632  }
   633  
   634  // BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
   635  func (c *Context) BindJSON(obj any) error {
   636  	return c.MustBindWith(obj, binding.JSON)
   637  }
   638  
   639  // BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
   640  func (c *Context) BindXML(obj any) error {
   641  	return c.MustBindWith(obj, binding.XML)
   642  }
   643  
   644  // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
   645  func (c *Context) BindQuery(obj any) error {
   646  	return c.MustBindWith(obj, binding.Query)
   647  }
   648  
   649  // BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
   650  func (c *Context) BindYAML(obj any) error {
   651  	return c.MustBindWith(obj, binding.YAML)
   652  }
   653  
   654  // BindTOML is a shortcut for c.MustBindWith(obj, binding.TOML).
   655  func (c *Context) BindTOML(obj any) error {
   656  	return c.MustBindWith(obj, binding.TOML)
   657  }
   658  
   659  // BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
   660  func (c *Context) BindHeader(obj any) error {
   661  	return c.MustBindWith(obj, binding.Header)
   662  }
   663  
   664  // BindUri binds the passed struct pointer using binding.Uri.
   665  // It will abort the request with HTTP 400 if any error occurs.
   666  func (c *Context) BindUri(obj any) error {
   667  	if err := c.ShouldBindUri(obj); err != nil {
   668  		c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck
   669  		return err
   670  	}
   671  	return nil
   672  }
   673  
   674  // MustBindWith binds the passed struct pointer using the specified binding engine.
   675  // It will abort the request with HTTP 400 if any error occurs.
   676  // See the binding package.
   677  func (c *Context) MustBindWith(obj any, b binding.Binding) error {
   678  	if err := c.ShouldBindWith(obj, b); err != nil {
   679  		c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) //nolint: errcheck
   680  		return err
   681  	}
   682  	return nil
   683  }
   684  
   685  // ShouldBind checks the Method and Content-Type to select a binding engine automatically,
   686  // Depending on the "Content-Type" header different bindings are used, for example:
   687  //
   688  //	"application/json" --> JSON binding
   689  //	"application/xml"  --> XML binding
   690  //
   691  // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
   692  // It decodes the json payload into the struct specified as a pointer.
   693  // Like c.Bind() but this method does not set the response status code to 400 or abort if input is not valid.
   694  func (c *Context) ShouldBind(obj any) error {
   695  	b := binding.Default(c.Request.Method, c.ContentType())
   696  	return c.ShouldBindWith(obj, b)
   697  }
   698  
   699  // ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
   700  func (c *Context) ShouldBindJSON(obj any) error {
   701  	return c.ShouldBindWith(obj, binding.JSON)
   702  }
   703  
   704  // ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
   705  func (c *Context) ShouldBindXML(obj any) error {
   706  	return c.ShouldBindWith(obj, binding.XML)
   707  }
   708  
   709  // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
   710  func (c *Context) ShouldBindQuery(obj any) error {
   711  	return c.ShouldBindWith(obj, binding.Query)
   712  }
   713  
   714  // ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
   715  func (c *Context) ShouldBindYAML(obj any) error {
   716  	return c.ShouldBindWith(obj, binding.YAML)
   717  }
   718  
   719  // ShouldBindTOML is a shortcut for c.ShouldBindWith(obj, binding.TOML).
   720  func (c *Context) ShouldBindTOML(obj any) error {
   721  	return c.ShouldBindWith(obj, binding.TOML)
   722  }
   723  
   724  // ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
   725  func (c *Context) ShouldBindHeader(obj any) error {
   726  	return c.ShouldBindWith(obj, binding.Header)
   727  }
   728  
   729  // ShouldBindUri binds the passed struct pointer using the specified binding engine.
   730  func (c *Context) ShouldBindUri(obj any) error {
   731  	m := make(map[string][]string)
   732  	for _, v := range c.Params {
   733  		m[v.Key] = []string{v.Value}
   734  	}
   735  	return binding.Uri.BindUri(m, obj)
   736  }
   737  
   738  // ShouldBindWith binds the passed struct pointer using the specified binding engine.
   739  // See the binding package.
   740  func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
   741  	return b.Bind(c.Request, obj)
   742  }
   743  
   744  // ShouldBindBodyWith is similar with ShouldBindWith, but it stores the request
   745  // body into the context, and reuse when it is called again.
   746  //
   747  // NOTE: This method reads the body before binding. So you should use
   748  // ShouldBindWith for better performance if you need to call only once.
   749  func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error) {
   750  	var body []byte
   751  	if cb, ok := c.Get(BodyBytesKey); ok {
   752  		if cbb, ok := cb.([]byte); ok {
   753  			body = cbb
   754  		}
   755  	}
   756  	if body == nil {
   757  		body, err = io.ReadAll(c.Request.Body)
   758  		if err != nil {
   759  			return err
   760  		}
   761  		c.Set(BodyBytesKey, body)
   762  	}
   763  	return bb.BindBody(body, obj)
   764  }
   765  
   766  // ClientIP implements one best effort algorithm to return the real client IP.
   767  // It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
   768  // If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
   769  // If the headers are not syntactically valid OR the remote IP does not correspond to a trusted proxy,
   770  // the remote IP (coming from Request.RemoteAddr) is returned.
   771  func (c *Context) ClientIP() string {
   772  	// Check if we're running on a trusted platform, continue running backwards if error
   773  	if c.engine.TrustedPlatform != "" {
   774  		// Developers can define their own header of Trusted Platform or use predefined constants
   775  		if addr := c.requestHeader(c.engine.TrustedPlatform); addr != "" {
   776  			return addr
   777  		}
   778  	}
   779  
   780  	// Legacy "AppEngine" flag
   781  	if c.engine.AppEngine {
   782  		log.Println(`The AppEngine flag is going to be deprecated. Please check issues #2723 and #2739 and use 'TrustedPlatform: gin.PlatformGoogleAppEngine' instead.`)
   783  		if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" {
   784  			return addr
   785  		}
   786  	}
   787  
   788  	// It also checks if the remoteIP is a trusted proxy or not.
   789  	// In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks
   790  	// defined by Engine.SetTrustedProxies()
   791  	remoteIP := net.ParseIP(c.RemoteIP())
   792  	if remoteIP == nil {
   793  		return ""
   794  	}
   795  	trusted := c.engine.isTrustedProxy(remoteIP)
   796  
   797  	if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil {
   798  		for _, headerName := range c.engine.RemoteIPHeaders {
   799  			ip, valid := c.engine.validateHeader(c.requestHeader(headerName))
   800  			if valid {
   801  				return ip
   802  			}
   803  		}
   804  	}
   805  	return remoteIP.String()
   806  }
   807  
   808  // RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port).
   809  func (c *Context) RemoteIP() string {
   810  	ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr))
   811  	if err != nil {
   812  		return ""
   813  	}
   814  	return ip
   815  }
   816  
   817  // ContentType returns the Content-Type header of the request.
   818  func (c *Context) ContentType() string {
   819  	return filterFlags(c.requestHeader("Content-Type"))
   820  }
   821  
   822  // IsWebsocket returns true if the request headers indicate that a websocket
   823  // handshake is being initiated by the client.
   824  func (c *Context) IsWebsocket() bool {
   825  	if strings.Contains(strings.ToLower(c.requestHeader("Connection")), "upgrade") &&
   826  		strings.EqualFold(c.requestHeader("Upgrade"), "websocket") {
   827  		return true
   828  	}
   829  	return false
   830  }
   831  
   832  func (c *Context) requestHeader(key string) string {
   833  	return c.Request.Header.Get(key)
   834  }
   835  
   836  /************************************/
   837  /******** RESPONSE RENDERING ********/
   838  /************************************/
   839  
   840  // bodyAllowedForStatus is a copy of http.bodyAllowedForStatus non-exported function.
   841  func bodyAllowedForStatus(status int) bool {
   842  	switch {
   843  	case status >= 100 && status <= 199:
   844  		return false
   845  	case status == http.StatusNoContent:
   846  		return false
   847  	case status == http.StatusNotModified:
   848  		return false
   849  	}
   850  	return true
   851  }
   852  
   853  // Status sets the HTTP response code.
   854  func (c *Context) Status(code int) {
   855  	c.Writer.WriteHeader(code)
   856  }
   857  
   858  // Header is an intelligent shortcut for c.Writer.Header().Set(key, value).
   859  // It writes a header in the response.
   860  // If value == "", this method removes the header `c.Writer.Header().Del(key)`
   861  func (c *Context) Header(key, value string) {
   862  	if value == "" {
   863  		c.Writer.Header().Del(key)
   864  		return
   865  	}
   866  	c.Writer.Header().Set(key, value)
   867  }
   868  
   869  // GetHeader returns value from request headers.
   870  func (c *Context) GetHeader(key string) string {
   871  	return c.requestHeader(key)
   872  }
   873  
   874  // GetRawData returns stream data.
   875  func (c *Context) GetRawData() ([]byte, error) {
   876  	return io.ReadAll(c.Request.Body)
   877  }
   878  
   879  // SetSameSite with cookie
   880  func (c *Context) SetSameSite(samesite http.SameSite) {
   881  	c.sameSite = samesite
   882  }
   883  
   884  // SetCookie adds a Set-Cookie header to the ResponseWriter's headers.
   885  // The provided cookie must have a valid Name. Invalid cookies may be
   886  // silently dropped.
   887  func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
   888  	if path == "" {
   889  		path = "/"
   890  	}
   891  	http.SetCookie(c.Writer, &http.Cookie{
   892  		Name:     name,
   893  		Value:    url.QueryEscape(value),
   894  		MaxAge:   maxAge,
   895  		Path:     path,
   896  		Domain:   domain,
   897  		SameSite: c.sameSite,
   898  		Secure:   secure,
   899  		HttpOnly: httpOnly,
   900  	})
   901  }
   902  
   903  // Cookie returns the named cookie provided in the request or
   904  // ErrNoCookie if not found. And return the named cookie is unescaped.
   905  // If multiple cookies match the given name, only one cookie will
   906  // be returned.
   907  func (c *Context) Cookie(name string) (string, error) {
   908  	cookie, err := c.Request.Cookie(name)
   909  	if err != nil {
   910  		return "", err
   911  	}
   912  	val, _ := url.QueryUnescape(cookie.Value)
   913  	return val, nil
   914  }
   915  
   916  // Render writes the response headers and calls render.Render to render data.
   917  func (c *Context) Render(code int, r render.Render) {
   918  	c.Status(code)
   919  
   920  	if !bodyAllowedForStatus(code) {
   921  		r.WriteContentType(c.Writer)
   922  		c.Writer.WriteHeaderNow()
   923  		return
   924  	}
   925  
   926  	if err := r.Render(c.Writer); err != nil {
   927  		// Pushing error to c.Errors
   928  		_ = c.Error(err)
   929  		c.Abort()
   930  	}
   931  }
   932  
   933  // HTML renders the HTTP template specified by its file name.
   934  // It also updates the HTTP code and sets the Content-Type as "text/html".
   935  // See http://golang.org/doc/articles/wiki/
   936  func (c *Context) HTML(code int, name string, obj any) {
   937  	instance := c.engine.HTMLRender.Instance(name, obj)
   938  	c.Render(code, instance)
   939  }
   940  
   941  // IndentedJSON serializes the given struct as pretty JSON (indented + endlines) into the response body.
   942  // It also sets the Content-Type as "application/json".
   943  // WARNING: we recommend using this only for development purposes since printing pretty JSON is
   944  // more CPU and bandwidth consuming. Use Context.JSON() instead.
   945  func (c *Context) IndentedJSON(code int, obj any) {
   946  	c.Render(code, render.IndentedJSON{Data: obj})
   947  }
   948  
   949  // SecureJSON serializes the given struct as Secure JSON into the response body.
   950  // Default prepends "while(1)," to response body if the given struct is array values.
   951  // It also sets the Content-Type as "application/json".
   952  func (c *Context) SecureJSON(code int, obj any) {
   953  	c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
   954  }
   955  
   956  // JSONP serializes the given struct as JSON into the response body.
   957  // It adds padding to response body to request data from a server residing in a different domain than the client.
   958  // It also sets the Content-Type as "application/javascript".
   959  func (c *Context) JSONP(code int, obj any) {
   960  	callback := c.DefaultQuery("callback", "")
   961  	if callback == "" {
   962  		c.Render(code, render.JSON{Data: obj})
   963  		return
   964  	}
   965  	c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
   966  }
   967  
   968  // JSON serializes the given struct as JSON into the response body.
   969  // It also sets the Content-Type as "application/json".
   970  func (c *Context) JSON(code int, obj any) {
   971  	c.Render(code, render.JSON{Data: obj})
   972  }
   973  
   974  // AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
   975  // It also sets the Content-Type as "application/json".
   976  func (c *Context) AsciiJSON(code int, obj any) {
   977  	c.Render(code, render.AsciiJSON{Data: obj})
   978  }
   979  
   980  // PureJSON serializes the given struct as JSON into the response body.
   981  // PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
   982  func (c *Context) PureJSON(code int, obj any) {
   983  	c.Render(code, render.PureJSON{Data: obj})
   984  }
   985  
   986  // XML serializes the given struct as XML into the response body.
   987  // It also sets the Content-Type as "application/xml".
   988  func (c *Context) XML(code int, obj any) {
   989  	c.Render(code, render.XML{Data: obj})
   990  }
   991  
   992  // YAML serializes the given struct as YAML into the response body.
   993  func (c *Context) YAML(code int, obj any) {
   994  	c.Render(code, render.YAML{Data: obj})
   995  }
   996  
   997  // TOML serializes the given struct as TOML into the response body.
   998  func (c *Context) TOML(code int, obj any) {
   999  	c.Render(code, render.TOML{Data: obj})
  1000  }
  1001  
  1002  // ProtoBuf serializes the given struct as ProtoBuf into the response body.
  1003  func (c *Context) ProtoBuf(code int, obj any) {
  1004  	c.Render(code, render.ProtoBuf{Data: obj})
  1005  }
  1006  
  1007  // String writes the given string into the response body.
  1008  func (c *Context) String(code int, format string, values ...any) {
  1009  	c.Render(code, render.String{Format: format, Data: values})
  1010  }
  1011  
  1012  // Redirect returns an HTTP redirect to the specific location.
  1013  func (c *Context) Redirect(code int, location string) {
  1014  	c.Render(-1, render.Redirect{
  1015  		Code:     code,
  1016  		Location: location,
  1017  		Request:  c.Request,
  1018  	})
  1019  }
  1020  
  1021  // Data writes some data into the body stream and updates the HTTP code.
  1022  func (c *Context) Data(code int, contentType string, data []byte) {
  1023  	c.Render(code, render.Data{
  1024  		ContentType: contentType,
  1025  		Data:        data,
  1026  	})
  1027  }
  1028  
  1029  // DataFromReader writes the specified reader into the body stream and updates the HTTP code.
  1030  func (c *Context) DataFromReader(code int, contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string) {
  1031  	c.Render(code, render.Reader{
  1032  		Headers:       extraHeaders,
  1033  		ContentType:   contentType,
  1034  		ContentLength: contentLength,
  1035  		Reader:        reader,
  1036  	})
  1037  }
  1038  
  1039  // File writes the specified file into the body stream in an efficient way.
  1040  func (c *Context) File(filepath string) {
  1041  	http.ServeFile(c.Writer, c.Request, filepath)
  1042  }
  1043  
  1044  // FileFromFS writes the specified file from http.FileSystem into the body stream in an efficient way.
  1045  func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
  1046  	defer func(old string) {
  1047  		c.Request.URL.Path = old
  1048  	}(c.Request.URL.Path)
  1049  
  1050  	c.Request.URL.Path = filepath
  1051  
  1052  	http.FileServer(fs).ServeHTTP(c.Writer, c.Request)
  1053  }
  1054  
  1055  var quoteEscaper = strings.NewReplacer("\\", "\\\\", `"`, "\\\"")
  1056  
  1057  func escapeQuotes(s string) string {
  1058  	return quoteEscaper.Replace(s)
  1059  }
  1060  
  1061  // FileAttachment writes the specified file into the body stream in an efficient way
  1062  // On the client side, the file will typically be downloaded with the given filename
  1063  func (c *Context) FileAttachment(filepath, filename string) {
  1064  	if isASCII(filename) {
  1065  		c.Writer.Header().Set("Content-Disposition", `attachment; filename="`+escapeQuotes(filename)+`"`)
  1066  	} else {
  1067  		c.Writer.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
  1068  	}
  1069  	http.ServeFile(c.Writer, c.Request, filepath)
  1070  }
  1071  
  1072  // SSEvent writes a Server-Sent Event into the body stream.
  1073  func (c *Context) SSEvent(name string, message any) {
  1074  	c.Render(-1, sse.Event{
  1075  		Event: name,
  1076  		Data:  message,
  1077  	})
  1078  }
  1079  
  1080  // Stream sends a streaming response and returns a boolean
  1081  // indicates "Is client disconnected in middle of stream"
  1082  func (c *Context) Stream(step func(w io.Writer) bool) bool {
  1083  	w := c.Writer
  1084  	clientGone := w.CloseNotify()
  1085  	for {
  1086  		select {
  1087  		case <-clientGone:
  1088  			return true
  1089  		default:
  1090  			keepOpen := step(w)
  1091  			w.Flush()
  1092  			if !keepOpen {
  1093  				return false
  1094  			}
  1095  		}
  1096  	}
  1097  }
  1098  
  1099  /************************************/
  1100  /******** CONTENT NEGOTIATION *******/
  1101  /************************************/
  1102  
  1103  // Negotiate contains all negotiations data.
  1104  type Negotiate struct {
  1105  	Offered  []string
  1106  	HTMLName string
  1107  	HTMLData any
  1108  	JSONData any
  1109  	XMLData  any
  1110  	YAMLData any
  1111  	Data     any
  1112  	TOMLData any
  1113  }
  1114  
  1115  // Negotiate calls different Render according to acceptable Accept format.
  1116  func (c *Context) Negotiate(code int, config Negotiate) {
  1117  	switch c.NegotiateFormat(config.Offered...) {
  1118  	case binding.MIMEJSON:
  1119  		data := chooseData(config.JSONData, config.Data)
  1120  		c.JSON(code, data)
  1121  
  1122  	case binding.MIMEHTML:
  1123  		data := chooseData(config.HTMLData, config.Data)
  1124  		c.HTML(code, config.HTMLName, data)
  1125  
  1126  	case binding.MIMEXML:
  1127  		data := chooseData(config.XMLData, config.Data)
  1128  		c.XML(code, data)
  1129  
  1130  	case binding.MIMEYAML:
  1131  		data := chooseData(config.YAMLData, config.Data)
  1132  		c.YAML(code, data)
  1133  
  1134  	case binding.MIMETOML:
  1135  		data := chooseData(config.TOMLData, config.Data)
  1136  		c.TOML(code, data)
  1137  
  1138  	default:
  1139  		c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck
  1140  	}
  1141  }
  1142  
  1143  // NegotiateFormat returns an acceptable Accept format.
  1144  func (c *Context) NegotiateFormat(offered ...string) string {
  1145  	assert1(len(offered) > 0, "you must provide at least one offer")
  1146  
  1147  	if c.Accepted == nil {
  1148  		c.Accepted = parseAccept(c.requestHeader("Accept"))
  1149  	}
  1150  	if len(c.Accepted) == 0 {
  1151  		return offered[0]
  1152  	}
  1153  	for _, accepted := range c.Accepted {
  1154  		for _, offer := range offered {
  1155  			// According to RFC 2616 and RFC 2396, non-ASCII characters are not allowed in headers,
  1156  			// therefore we can just iterate over the string without casting it into []rune
  1157  			i := 0
  1158  			for ; i < len(accepted) && i < len(offer); i++ {
  1159  				if accepted[i] == '*' || offer[i] == '*' {
  1160  					return offer
  1161  				}
  1162  				if accepted[i] != offer[i] {
  1163  					break
  1164  				}
  1165  			}
  1166  			if i == len(accepted) {
  1167  				return offer
  1168  			}
  1169  		}
  1170  	}
  1171  	return ""
  1172  }
  1173  
  1174  // SetAccepted sets Accept header data.
  1175  func (c *Context) SetAccepted(formats ...string) {
  1176  	c.Accepted = formats
  1177  }
  1178  
  1179  /************************************/
  1180  /***** GOLANG.ORG/X/NET/CONTEXT *****/
  1181  /************************************/
  1182  
  1183  // hasRequestContext returns whether c.Request has Context and fallback.
  1184  func (c *Context) hasRequestContext() bool {
  1185  	hasFallback := c.engine != nil && c.engine.ContextWithFallback
  1186  	hasRequestContext := c.Request != nil && c.Request.Context() != nil
  1187  	return hasFallback && hasRequestContext
  1188  }
  1189  
  1190  // Deadline returns that there is no deadline (ok==false) when c.Request has no Context.
  1191  func (c *Context) Deadline() (deadline time.Time, ok bool) {
  1192  	if !c.hasRequestContext() {
  1193  		return
  1194  	}
  1195  	return c.Request.Context().Deadline()
  1196  }
  1197  
  1198  // Done returns nil (chan which will wait forever) when c.Request has no Context.
  1199  func (c *Context) Done() <-chan struct{} {
  1200  	if !c.hasRequestContext() {
  1201  		return nil
  1202  	}
  1203  	return c.Request.Context().Done()
  1204  }
  1205  
  1206  // Err returns nil when c.Request has no Context.
  1207  func (c *Context) Err() error {
  1208  	if !c.hasRequestContext() {
  1209  		return nil
  1210  	}
  1211  	return c.Request.Context().Err()
  1212  }
  1213  
  1214  // Value returns the value associated with this context for key, or nil
  1215  // if no value is associated with key. Successive calls to Value with
  1216  // the same key returns the same result.
  1217  func (c *Context) Value(key any) any {
  1218  	if key == 0 {
  1219  		return c.Request
  1220  	}
  1221  	if key == ContextKey {
  1222  		return c
  1223  	}
  1224  	if keyAsString, ok := key.(string); ok {
  1225  		if val, exists := c.Get(keyAsString); exists {
  1226  			return val
  1227  		}
  1228  	}
  1229  	if !c.hasRequestContext() {
  1230  		return nil
  1231  	}
  1232  	return c.Request.Context().Value(key)
  1233  }
  1234  

View as plain text