summaryrefslogtreecommitdiff
path: root/vendor/github.com/gin-gonic/gin/gin.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gin-gonic/gin/gin.go')
-rw-r--r--vendor/github.com/gin-gonic/gin/gin.go129
1 files changed, 95 insertions, 34 deletions
diff --git a/vendor/github.com/gin-gonic/gin/gin.go b/vendor/github.com/gin-gonic/gin/gin.go
index 58e76f41f..f9324299b 100644
--- a/vendor/github.com/gin-gonic/gin/gin.go
+++ b/vendor/github.com/gin-gonic/gin/gin.go
@@ -1,4 +1,4 @@
-// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
+// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
@@ -11,12 +11,13 @@ import (
"net/http"
"os"
"path"
- "reflect"
"strings"
"sync"
"github.com/gin-gonic/gin/internal/bytesconv"
"github.com/gin-gonic/gin/render"
+ "golang.org/x/net/http2"
+ "golang.org/x/net/http2/h2c"
)
const defaultMultipartMemory = 32 << 20 // 32 MB
@@ -28,15 +29,24 @@ var (
var defaultPlatform string
-var defaultTrustedCIDRs = []*net.IPNet{{IP: net.IP{0x0, 0x0, 0x0, 0x0}, Mask: net.IPMask{0x0, 0x0, 0x0, 0x0}}} // 0.0.0.0/0
+var defaultTrustedCIDRs = []*net.IPNet{
+ { // 0.0.0.0/0 (IPv4)
+ IP: net.IP{0x0, 0x0, 0x0, 0x0},
+ Mask: net.IPMask{0x0, 0x0, 0x0, 0x0},
+ },
+ { // ::/0 (IPv6)
+ IP: net.IP{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ Mask: net.IPMask{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ },
+}
// HandlerFunc defines the handler used by gin middleware as return value.
type HandlerFunc func(*Context)
-// HandlersChain defines a HandlerFunc array.
+// HandlersChain defines a HandlerFunc slice.
type HandlersChain []HandlerFunc
-// Last returns the last handler in the chain. ie. the last handler is the main one.
+// Last returns the last handler in the chain. i.e. the last handler is the main one.
func (c HandlersChain) Last() HandlerFunc {
if length := len(c); length > 0 {
return c[length-1]
@@ -52,15 +62,15 @@ type RouteInfo struct {
HandlerFunc HandlerFunc
}
-// RoutesInfo defines a RouteInfo array.
+// RoutesInfo defines a RouteInfo slice.
type RoutesInfo []RouteInfo
// Trusted platforms
const (
- // When running on Google App Engine. Trust X-Appengine-Remote-Addr
+ // PlatformGoogleAppEngine when running on Google App Engine. Trust X-Appengine-Remote-Addr
// for determining the client's IP
PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
- // When using Cloudflare's CDN. Trust CF-Connecting-IP for determining
+ // PlatformCloudflare when using Cloudflare's CDN. Trust CF-Connecting-IP for determining
// the client's IP
PlatformCloudflare = "CF-Connecting-IP"
)
@@ -70,14 +80,14 @@ const (
type Engine struct {
RouterGroup
- // Enables automatic redirection if the current route can't be matched but a
+ // RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
// handler for the path with (without) the trailing slash exists.
// For example if /foo/ is requested but a route only exists for /foo, the
// client is redirected to /foo with http status code 301 for GET requests
// and 307 for all other request methods.
RedirectTrailingSlash bool
- // If enabled, the router tries to fix the current request path, if no
+ // RedirectFixedPath if enabled, the router tries to fix the current request path, if no
// handle is registered for it.
// First superfluous path elements like ../ or // are removed.
// Afterwards the router does a case-insensitive lookup of the cleaned path.
@@ -88,7 +98,7 @@ type Engine struct {
// RedirectTrailingSlash is independent of this option.
RedirectFixedPath bool
- // If enabled, the router checks if another method is allowed for the
+ // HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the
// current route, if the current request can not be routed.
// If this is the case, the request is answered with 'Method Not Allowed'
// and HTTP status code 405.
@@ -96,21 +106,22 @@ type Engine struct {
// handler.
HandleMethodNotAllowed bool
- // If enabled, client IP will be parsed from the request's headers that
+ // ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that
// match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
// fetched, it falls back to the IP obtained from
// `(*gin.Context).Request.RemoteAddr`.
ForwardedByClientIP bool
- // DEPRECATED: USE `TrustedPlatform` WITH VALUE `gin.GoogleAppEngine` INSTEAD
+ // AppEngine was deprecated.
+ // Deprecated: USE `TrustedPlatform` WITH VALUE `gin.PlatformGoogleAppEngine` INSTEAD
// #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool
- // If enabled, the url.RawPath will be used to find parameters.
+ // UseRawPath if enabled, the url.RawPath will be used to find parameters.
UseRawPath bool
- // If true, the path value will be unescaped.
+ // UnescapePathValues if true, the path value will be unescaped.
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
// as url.Path gonna be used, which is already unescaped.
UnescapePathValues bool
@@ -119,20 +130,26 @@ type Engine struct {
// See the PR #1817 and issue #1644
RemoveExtraSlash bool
- // List of headers used to obtain the client IP when
+ // RemoteIPHeaders list of headers used to obtain the client IP when
// `(*gin.Engine).ForwardedByClientIP` is `true` and
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
RemoteIPHeaders []string
- // If set to a constant of value gin.Platform*, trusts the headers set by
+ // TrustedPlatform if set to a constant of value gin.Platform*, trusts the headers set by
// that platform, for example to determine the client IP
TrustedPlatform string
- // Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
+ // MaxMultipartMemory value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
// method call.
MaxMultipartMemory int64
+ // UseH2C enable h2c support.
+ UseH2C bool
+
+ // ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.
+ ContextWithFallback bool
+
delims render.Delims
secureJSONPrefix string
HTMLRender render.HTMLRender
@@ -152,7 +169,7 @@ type Engine struct {
var _ IRouter = &Engine{}
// New returns a new blank Engine instance without any middleware attached.
-// By default the configuration is:
+// By default, the configuration is:
// - RedirectTrailingSlash: true
// - RedirectFixedPath: false
// - HandleMethodNotAllowed: false
@@ -181,11 +198,11 @@ func New() *Engine {
trees: make(methodTrees, 0, 9),
delims: render.Delims{Left: "{{", Right: "}}"},
secureJSONPrefix: "while(1);",
- trustedProxies: []string{"0.0.0.0/0"},
+ trustedProxies: []string{"0.0.0.0/0", "::/0"},
trustedCIDRs: defaultTrustedCIDRs,
}
engine.RouterGroup.engine = engine
- engine.pool.New = func() interface{} {
+ engine.pool.New = func() any {
return engine.allocateContext()
}
return engine
@@ -199,13 +216,22 @@ func Default() *Engine {
return engine
}
+func (engine *Engine) Handler() http.Handler {
+ if !engine.UseH2C {
+ return engine
+ }
+
+ h2s := &http2.Server{}
+ return h2c.NewHandler(engine, h2s)
+}
+
func (engine *Engine) allocateContext() *Context {
v := make(Params, 0, engine.maxParams)
skippedNodes := make([]skippedNode, 0, engine.maxSections)
return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
}
-// Delims sets template left and right delims and returns a Engine instance.
+// Delims sets template left and right delims and returns an Engine instance.
func (engine *Engine) Delims(left, right string) *Engine {
engine.delims = render.Delims{Left: left, Right: right}
return engine
@@ -259,7 +285,7 @@ func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
engine.FuncMap = funcMap
}
-// NoRoute adds handlers for NoRoute. It return a 404 code by default.
+// NoRoute adds handlers for NoRoute. It returns a 404 code by default.
func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
engine.noRoute = handlers
engine.rebuild404Handlers()
@@ -271,7 +297,7 @@ func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
engine.rebuild405Handlers()
}
-// Use attaches a global middleware to the router. ie. the middleware attached though Use() will be
+// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
// included in the handlers chain for every single request. Even 404, 405, static files...
// For example, this is the right place for a logger or error management middleware.
func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
@@ -353,7 +379,7 @@ func (engine *Engine) Run(addr ...string) (err error) {
address := resolveAddress(addr)
debugPrint("Listening and serving HTTP on %s\n", address)
- err = http.ListenAndServe(address, engine)
+ err = http.ListenAndServe(address, engine.Handler())
return
}
@@ -399,9 +425,9 @@ func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
return engine.parseTrustedProxies()
}
-// isUnsafeTrustedProxies compares Engine.trustedCIDRs and defaultTrustedCIDRs, it's not safe if equal (returns true)
+// isUnsafeTrustedProxies checks if Engine.trustedCIDRs contains all IPs, it's not safe if it has (returns true)
func (engine *Engine) isUnsafeTrustedProxies() bool {
- return reflect.DeepEqual(engine.trustedCIDRs, defaultTrustedCIDRs)
+ return engine.isTrustedProxy(net.ParseIP("0.0.0.0")) || engine.isTrustedProxy(net.ParseIP("::"))
}
// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
@@ -411,6 +437,41 @@ func (engine *Engine) parseTrustedProxies() error {
return err
}
+// isTrustedProxy will check whether the IP address is included in the trusted list according to Engine.trustedCIDRs
+func (engine *Engine) isTrustedProxy(ip net.IP) bool {
+ if engine.trustedCIDRs == nil {
+ return false
+ }
+ for _, cidr := range engine.trustedCIDRs {
+ if cidr.Contains(ip) {
+ return true
+ }
+ }
+ return false
+}
+
+// validateHeader will parse X-Forwarded-For header and return the trusted client IP address
+func (engine *Engine) validateHeader(header string) (clientIP string, valid bool) {
+ if header == "" {
+ return "", false
+ }
+ items := strings.Split(header, ",")
+ for i := len(items) - 1; i >= 0; i-- {
+ ipStr := strings.TrimSpace(items[i])
+ ip := net.ParseIP(ipStr)
+ if ip == nil {
+ break
+ }
+
+ // X-Forwarded-For is appended by proxy
+ // Check IPs in reverse order and stop when find untrusted proxy
+ if (i == 0) || (!engine.isTrustedProxy(ip)) {
+ return ipStr, true
+ }
+ }
+ return "", false
+}
+
// parseIP parse a string representation of an IP and returns a net.IP with the
// minimum byte representation or nil if input is invalid.
func parseIP(ip string) net.IP {
@@ -437,12 +498,12 @@ func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
}
- err = http.ListenAndServeTLS(addr, certFile, keyFile, engine)
+ err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
return
}
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
-// through the specified unix socket (ie. a file).
+// through the specified unix socket (i.e. a file).
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func (engine *Engine) RunUnix(file string) (err error) {
debugPrint("Listening and serving HTTP on unix:/%s", file)
@@ -460,7 +521,7 @@ func (engine *Engine) RunUnix(file string) (err error) {
defer listener.Close()
defer os.Remove(file)
- err = http.Serve(listener, engine)
+ err = http.Serve(listener, engine.Handler())
return
}
@@ -497,7 +558,7 @@ func (engine *Engine) RunListener(listener net.Listener) (err error) {
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
}
- err = http.Serve(listener, engine)
+ err = http.Serve(listener, engine.Handler())
return
}
@@ -513,9 +574,9 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
engine.pool.Put(c)
}
-// HandleContext re-enter a context that has been rewritten.
+// HandleContext re-enters a context that has been rewritten.
// This can be done by setting c.Request.URL.Path to your new target.
-// Disclaimer: You can loop yourself to death with this, use wisely.
+// Disclaimer: You can loop yourself to deal with this, use wisely.
func (engine *Engine) HandleContext(c *Context) {
oldIndexValue := c.index
c.reset()
@@ -556,7 +617,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
c.writermem.WriteHeaderNow()
return
}
- if httpMethod != "CONNECT" && rPath != "/" {
+ if httpMethod != http.MethodConnect && rPath != "/" {
if value.tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return