diff options
author | 2021-11-27 15:26:58 +0100 | |
---|---|---|
committer | 2021-11-27 15:26:58 +0100 | |
commit | 182b4eea73881c611a0f519576aa6ad2aa6799c2 (patch) | |
tree | 230fac469690fcee8797b13585e739be148d4789 /vendor/github.com/gin-gonic/gin/context.go | |
parent | Require confirmed email when checking oauth token (#332) (diff) | |
download | gotosocial-182b4eea73881c611a0f519576aa6ad2aa6799c2.tar.xz |
Update dependencies (#333)
Diffstat (limited to 'vendor/github.com/gin-gonic/gin/context.go')
-rw-r--r-- | vendor/github.com/gin-gonic/gin/context.go | 167 |
1 files changed, 75 insertions, 92 deletions
diff --git a/vendor/github.com/gin-gonic/gin/context.go b/vendor/github.com/gin-gonic/gin/context.go index 62849488b..220d1bc7b 100644 --- a/vendor/github.com/gin-gonic/gin/context.go +++ b/vendor/github.com/gin-gonic/gin/context.go @@ -40,8 +40,7 @@ const ( // BodyBytesKey indicates a default body bytes key. const BodyBytesKey = "_gin-gonic/gin/bodybyteskey" -// abortIndex represents a typical value used in abort functions. -const abortIndex int8 = math.MaxInt8 >> 1 +const abortIndex int8 = math.MaxInt8 / 2 // 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. @@ -55,8 +54,9 @@ type Context struct { index int8 fullPath string - engine *Engine - params *Params + engine *Engine + params *Params + skippedNodes *[]skippedNode // This mutex protect Keys map mu sync.RWMutex @@ -88,17 +88,18 @@ type Context struct { func (c *Context) reset() { c.Writer = &c.writermem - c.Params = c.Params[:0] + c.Params = c.Params[0:0] c.handlers = nil c.index = -1 c.fullPath = "" c.Keys = nil - c.Errors = c.Errors[:0] + c.Errors = c.Errors[0:0] c.Accepted = nil c.queryCache = nil c.formCache = nil *c.params = (*c.params)[:0] + *c.skippedNodes = (*c.skippedNodes)[:0] } // Copy returns a copy of the current context that can be safely used outside the request's scope. @@ -383,15 +384,6 @@ func (c *Context) Param(key string) string { return c.Params.ByName(key) } -// 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}) -} - // Query returns the keyed url query value if it exists, // otherwise it returns an empty string `("")`. // It is shortcut for `c.Request.URL.Query().Get(key)` @@ -400,9 +392,9 @@ func (c *Context) AddParam(key, value string) { // c.Query("name") == "Manu" // c.Query("value") == "" // c.Query("wtf") == "" -func (c *Context) Query(key string) (value string) { - value, _ = c.GetQuery(key) - return +func (c *Context) Query(key string) string { + value, _ := c.GetQuery(key) + return value } // DefaultQuery returns the keyed url query value if it exists, @@ -436,9 +428,9 @@ func (c *Context) GetQuery(key string) (string, bool) { // QueryArray returns a slice of strings for a given query key. // The length of the slice depends on the number of params with the given key. -func (c *Context) QueryArray(key string) (values []string) { - values, _ = c.GetQueryArray(key) - return +func (c *Context) QueryArray(key string) []string { + values, _ := c.GetQueryArray(key) + return values } func (c *Context) initQueryCache() { @@ -453,16 +445,18 @@ func (c *Context) initQueryCache() { // GetQueryArray returns a slice of strings for a given query key, plus // a boolean value whether at least one value exists for the given key. -func (c *Context) GetQueryArray(key string) (values []string, ok bool) { +func (c *Context) GetQueryArray(key string) ([]string, bool) { c.initQueryCache() - values, ok = c.queryCache[key] - return + if values, ok := c.queryCache[key]; ok && len(values) > 0 { + return values, true + } + return []string{}, false } // QueryMap returns a map for a given query key. -func (c *Context) QueryMap(key string) (dicts map[string]string) { - dicts, _ = c.GetQueryMap(key) - return +func (c *Context) QueryMap(key string) map[string]string { + dicts, _ := c.GetQueryMap(key) + return dicts } // GetQueryMap returns a map for a given query key, plus a boolean value @@ -474,9 +468,9 @@ func (c *Context) GetQueryMap(key string) (map[string]string, bool) { // PostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns an empty string `("")`. -func (c *Context) PostForm(key string) (value string) { - value, _ = c.GetPostForm(key) - return +func (c *Context) PostForm(key string) string { + value, _ := c.GetPostForm(key) + return value } // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form @@ -505,9 +499,9 @@ func (c *Context) GetPostForm(key string) (string, bool) { // PostFormArray returns a slice of strings for a given form key. // The length of the slice depends on the number of params with the given key. -func (c *Context) PostFormArray(key string) (values []string) { - values, _ = c.GetPostFormArray(key) - return +func (c *Context) PostFormArray(key string) []string { + values, _ := c.GetPostFormArray(key) + return values } func (c *Context) initFormCache() { @@ -525,16 +519,18 @@ func (c *Context) initFormCache() { // GetPostFormArray returns a slice of strings for a given form key, plus // a boolean value whether at least one value exists for the given key. -func (c *Context) GetPostFormArray(key string) (values []string, ok bool) { +func (c *Context) GetPostFormArray(key string) ([]string, bool) { c.initFormCache() - values, ok = c.formCache[key] - return + if values := c.formCache[key]; len(values) > 0 { + return values, true + } + return []string{}, false } // PostFormMap returns a map for a given form key. -func (c *Context) PostFormMap(key string) (dicts map[string]string) { - dicts, _ = c.GetPostFormMap(key) - return +func (c *Context) PostFormMap(key string) map[string]string { + dicts, _ := c.GetPostFormMap(key) + return dicts } // GetPostFormMap returns a map for a given form key, plus a boolean value @@ -732,20 +728,16 @@ func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (e return bb.BindBody(body, obj) } -// ClientIP implements a best effort algorithm to return the real client IP. +// ClientIP implements one best effort algorithm to return the real client IP. // It called c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not. -// If it's it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]). -// If the headers are nots syntactically valid OR the remote IP does not correspong to a trusted proxy, +// 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, // the remote IP (coming form Request.RemoteAddr) is returned. func (c *Context) ClientIP() string { - // Check if we're running on a trusted platform - switch c.engine.TrustedPlatform { - case PlatformGoogleAppEngine: - if addr := c.requestHeader("X-Appengine-Remote-Addr"); addr != "" { - return addr - } - case PlatformCloudflare: - if addr := c.requestHeader("CF-Connecting-IP"); addr != "" { + // 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 != "" { return addr } } @@ -765,7 +757,7 @@ func (c *Context) ClientIP() string { if trusted && c.engine.ForwardedByClientIP && c.engine.RemoteIPHeaders != nil { for _, headerName := range c.engine.RemoteIPHeaders { - ip, valid := validateHeader(c.requestHeader(headerName)) + ip, valid := c.engine.validateHeader(c.requestHeader(headerName)) if valid { return ip } @@ -774,10 +766,21 @@ func (c *Context) ClientIP() string { return remoteIP.String() } +func (e *Engine) isTrustedProxy(ip net.IP) bool { + if e.trustedCIDRs != nil { + for _, cidr := range e.trustedCIDRs { + if cidr.Contains(ip) { + return true + } + } + } + return false +} + // RemoteIP parses the IP from Request.RemoteAddr, normalizes and returns the IP (without the port). // It also checks if the remoteIP is a trusted proxy or not. // In order to perform this validation, it will see if the IP is contained within at least one of the CIDR blocks -// defined in Engine.TrustedProxies +// defined by Engine.SetTrustedProxies() func (c *Context) RemoteIP() (net.IP, bool) { ip, _, err := net.SplitHostPort(strings.TrimSpace(c.Request.RemoteAddr)) if err != nil { @@ -788,35 +791,25 @@ func (c *Context) RemoteIP() (net.IP, bool) { return nil, false } - if c.engine.trustedCIDRs != nil { - for _, cidr := range c.engine.trustedCIDRs { - if cidr.Contains(remoteIP) { - return remoteIP, true - } - } - } - - return remoteIP, false + return remoteIP, c.engine.isTrustedProxy(remoteIP) } -func validateHeader(header string) (clientIP string, valid bool) { +func (e *Engine) validateHeader(header string) (clientIP string, valid bool) { if header == "" { return "", false } items := strings.Split(header, ",") - for i, ipStr := range items { - ipStr = strings.TrimSpace(ipStr) + for i := len(items) - 1; i >= 0; i-- { + ipStr := strings.TrimSpace(items[i]) ip := net.ParseIP(ipStr) if ip == nil { return "", false } - // We need to return the first IP in the list, but, - // we should not early return since we need to validate that - // the rest of the header is syntactically valid - if i == 0 { - clientIP = ipStr - valid = true + // X-Forwarded-For is appended by proxy + // Check IPs in reverse order and stop when find untrusted proxy + if (i == 0) || (!e.isTrustedProxy(ip)) { + return ipStr, true } } return @@ -1166,28 +1159,22 @@ func (c *Context) SetAccepted(formats ...string) { /***** GOLANG.ORG/X/NET/CONTEXT *****/ /************************************/ -// Deadline returns that there is no deadline (ok==false) when c.Request has no Context. +// Deadline always returns that there is no deadline (ok==false), +// maybe you want to use Request.Context().Deadline() instead. func (c *Context) Deadline() (deadline time.Time, ok bool) { - if c.Request == nil || c.Request.Context() == nil { - return - } - return c.Request.Context().Deadline() + return } -// Done returns nil (chan which will wait forever) when c.Request has no Context. +// Done always returns nil (chan which will wait forever), +// if you want to abort your work when the connection was closed +// you should use Request.Context().Done() instead. func (c *Context) Done() <-chan struct{} { - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Done() + return nil } -// Err returns nil when c.Request has no Context. +// Err always returns nil, maybe you want to use Request.Context().Err() instead. func (c *Context) Err() error { - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Err() + return nil } // Value returns the value associated with this context for key, or nil @@ -1198,12 +1185,8 @@ func (c *Context) Value(key interface{}) interface{} { return c.Request } if keyAsString, ok := key.(string); ok { - if val, exists := c.Get(keyAsString); exists { - return val - } + val, _ := c.Get(keyAsString) + return val } - if c.Request == nil || c.Request.Context() == nil { - return nil - } - return c.Request.Context().Value(key) + return nil } |