2022-05-28 02:42:28 +00:00
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
2014-08-29 17:49:50 +00:00
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
2014-06-17 23:42:34 +00:00
package gin
import (
2018-11-06 02:28:51 +00:00
"fmt"
2014-06-17 23:42:34 +00:00
"html/template"
2015-05-18 22:45:08 +00:00
"net"
2014-06-17 23:42:34 +00:00
"net/http"
2015-05-18 22:45:08 +00:00
"os"
2019-02-27 11:56:29 +00:00
"path"
2023-02-19 13:25:48 +00:00
"regexp"
2021-04-06 03:37:25 +00:00
"strings"
2014-07-06 19:09:23 +00:00
"sync"
2015-03-23 03:41:29 +00:00
2020-01-17 16:32:50 +00:00
"github.com/gin-gonic/gin/internal/bytesconv"
2015-03-23 03:41:29 +00:00
"github.com/gin-gonic/gin/render"
2022-02-05 13:13:20 +00:00
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
2014-06-17 23:42:34 +00:00
)
2018-09-17 07:08:11 +00:00
const defaultMultipartMemory = 32 << 20 // 32 MB
2015-05-22 14:55:16 +00:00
2017-09-28 14:54:37 +00:00
var (
2020-05-04 03:40:41 +00:00
default404Body = [ ] byte ( "404 page not found" )
default405Body = [ ] byte ( "405 method not allowed" )
2017-09-28 14:54:37 +00:00
)
2014-06-17 23:42:34 +00:00
2021-06-24 00:58:10 +00:00
var defaultPlatform string
2020-05-04 03:40:41 +00:00
2021-12-03 06:49:16 +00:00
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 } ,
} ,
}
2021-10-06 01:37:25 +00:00
2023-02-19 13:25:48 +00:00
var regSafePrefix = regexp . MustCompile ( "[^a-zA-Z0-9/-]+" )
var regRemoveRepeatedChar = regexp . MustCompile ( "/{2,}" )
2018-09-15 07:21:54 +00:00
// HandlerFunc defines the handler used by gin middleware as return value.
2015-06-26 14:05:09 +00:00
type HandlerFunc func ( * Context )
2018-09-15 07:21:54 +00:00
2021-12-15 15:27:23 +00:00
// HandlersChain defines a HandlerFunc slice.
2015-06-26 14:05:09 +00:00
type HandlersChain [ ] HandlerFunc
2021-12-05 00:41:25 +00:00
// Last returns the last handler in the chain. i.e. the last handler is the main one.
2015-06-26 14:05:09 +00:00
func ( c HandlersChain ) Last ( ) HandlerFunc {
2017-07-06 14:49:54 +00:00
if length := len ( c ) ; length > 0 {
2015-06-26 14:05:09 +00:00
return c [ length - 1 ]
}
return nil
}
2018-09-15 07:21:54 +00:00
// RouteInfo represents a request route's specification which contains method and path and its handler.
2017-07-05 07:47:36 +00:00
type RouteInfo struct {
2018-10-23 02:56:33 +00:00
Method string
Path string
Handler string
HandlerFunc HandlerFunc
2017-07-05 07:47:36 +00:00
}
2014-06-17 23:42:34 +00:00
2021-12-05 00:41:25 +00:00
// RoutesInfo defines a RouteInfo slice.
2017-07-05 07:47:36 +00:00
type RoutesInfo [ ] RouteInfo
2021-06-24 00:58:10 +00:00
// Trusted platforms
const (
2022-03-23 13:35:09 +00:00
// PlatformGoogleAppEngine when running on Google App Engine. Trust X-Appengine-Remote-Addr
2021-06-24 00:58:10 +00:00
// for determining the client's IP
2021-10-24 00:34:03 +00:00
PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
2022-03-23 13:35:09 +00:00
// PlatformCloudflare when using Cloudflare's CDN. Trust CF-Connecting-IP for determining
2021-06-24 00:58:10 +00:00
// the client's IP
2021-10-24 00:34:03 +00:00
PlatformCloudflare = "CF-Connecting-IP"
2021-06-24 00:58:10 +00:00
)
2017-07-05 07:47:36 +00:00
// Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
// Create an instance of Engine, by using New() or Default()
type Engine struct {
RouterGroup
2022-03-23 13:35:09 +00:00
// RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
2017-07-05 07:47:36 +00:00
// 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
2022-03-23 13:35:09 +00:00
// RedirectFixedPath if enabled, the router tries to fix the current request path, if no
2017-07-05 07:47:36 +00:00
// 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.
// If a handle can be found for this route, the router makes a redirection
// to the corrected path with status code 301 for GET requests and 307 for
// all other request methods.
// For example /FOO and /..//Foo could be redirected to /foo.
// RedirectTrailingSlash is independent of this option.
RedirectFixedPath bool
2022-03-23 13:35:09 +00:00
// HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the
2017-07-05 07:47:36 +00:00
// 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.
// If no other Method is allowed, the request is delegated to the NotFound
// handler.
HandleMethodNotAllowed bool
2022-03-23 13:35:09 +00:00
// ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that
2021-04-06 03:37:25 +00:00
// 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
2022-03-23 13:35:09 +00:00
// AppEngine was deprecated.
// Deprecated: USE `TrustedPlatform` WITH VALUE `gin.PlatformGoogleAppEngine` INSTEAD
2021-07-04 02:37:13 +00:00
// #726 #755 If enabled, it will trust some headers starting with
// 'X-AppEngine...' for better integration with that PaaS.
AppEngine bool
2022-03-23 13:35:09 +00:00
// UseRawPath if enabled, the url.RawPath will be used to find parameters.
2021-07-04 02:37:13 +00:00
UseRawPath bool
2022-03-23 13:35:09 +00:00
// UnescapePathValues if true, the path value will be unescaped.
2021-07-04 02:37:13 +00:00
// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
// as url.Path gonna be used, which is already unescaped.
UnescapePathValues bool
// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
// See the PR #1817 and issue #1644
RemoveExtraSlash bool
2022-03-23 13:35:09 +00:00
// RemoteIPHeaders list of headers used to obtain the client IP when
2021-04-06 03:37:25 +00:00
// `(*gin.Engine).ForwardedByClientIP` is `true` and
// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
2021-10-06 01:37:25 +00:00
// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
2021-04-06 03:37:25 +00:00
RemoteIPHeaders [ ] string
2022-03-23 13:35:09 +00:00
// TrustedPlatform if set to a constant of value gin.Platform*, trusts the headers set by
2021-06-24 00:58:10 +00:00
// that platform, for example to determine the client IP
TrustedPlatform string
2022-03-23 13:35:09 +00:00
// MaxMultipartMemory value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
2017-09-07 03:45:16 +00:00
// method call.
MaxMultipartMemory int64
2017-11-29 02:50:14 +00:00
2022-03-23 13:35:09 +00:00
// UseH2C enable h2c support.
2022-02-05 13:13:20 +00:00
UseH2C bool
2022-06-06 10:43:53 +00:00
// ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.
ContextWithFallback bool
2017-11-29 02:50:14 +00:00
delims render . Delims
2020-05-05 05:55:57 +00:00
secureJSONPrefix string
2017-11-29 02:50:14 +00:00
HTMLRender render . HTMLRender
FuncMap template . FuncMap
allNoRoute HandlersChain
allNoMethod HandlersChain
noRoute HandlersChain
noMethod HandlersChain
pool sync . Pool
trees methodTrees
2020-05-10 05:22:25 +00:00
maxParams uint16
2021-10-23 03:58:57 +00:00
maxSections uint16
2021-10-06 01:37:25 +00:00
trustedProxies [ ] string
2021-04-06 03:37:25 +00:00
trustedCIDRs [ ] * net . IPNet
2017-07-05 07:47:36 +00:00
}
2014-06-17 23:42:34 +00:00
2022-10-19 16:49:19 +00:00
var _ IRouter = ( * Engine ) ( nil )
2015-06-26 14:01:35 +00:00
2015-07-02 18:24:54 +00:00
// New returns a new blank Engine instance without any middleware attached.
2021-12-03 06:49:51 +00:00
// By default, the configuration is:
2015-07-02 18:24:54 +00:00
// - RedirectTrailingSlash: true
// - RedirectFixedPath: false
// - HandleMethodNotAllowed: false
// - ForwardedByClientIP: true
2017-02-28 10:29:41 +00:00
// - UseRawPath: false
// - UnescapePathValues: true
2014-07-06 19:09:23 +00:00
func New ( ) * Engine {
2015-07-02 18:24:54 +00:00
debugPrintWARNINGNew ( )
2015-03-31 19:39:06 +00:00
engine := & Engine {
2015-04-07 10:22:38 +00:00
RouterGroup : RouterGroup {
2015-05-16 16:08:19 +00:00
Handlers : nil ,
2015-07-08 02:27:23 +00:00
basePath : "/" ,
2015-06-10 23:02:38 +00:00
root : true ,
2015-04-07 10:22:38 +00:00
} ,
2017-06-30 19:22:40 +00:00
FuncMap : template . FuncMap { } ,
2015-03-31 19:39:06 +00:00
RedirectTrailingSlash : true ,
2015-05-30 12:45:13 +00:00
RedirectFixedPath : false ,
HandleMethodNotAllowed : false ,
2015-06-07 11:51:13 +00:00
ForwardedByClientIP : true ,
2021-04-06 03:37:25 +00:00
RemoteIPHeaders : [ ] string { "X-Forwarded-For" , "X-Real-IP" } ,
2021-06-24 00:58:10 +00:00
TrustedPlatform : defaultPlatform ,
2017-02-28 10:29:41 +00:00
UseRawPath : false ,
2019-11-28 16:02:02 +00:00
RemoveExtraSlash : false ,
2017-02-28 10:29:41 +00:00
UnescapePathValues : true ,
2017-09-07 03:45:16 +00:00
MaxMultipartMemory : defaultMultipartMemory ,
2015-06-07 11:51:13 +00:00
trees : make ( methodTrees , 0 , 9 ) ,
2017-08-02 15:00:10 +00:00
delims : render . Delims { Left : "{{" , Right : "}}" } ,
2020-05-05 05:55:57 +00:00
secureJSONPrefix : "while(1);" ,
2022-05-28 00:14:35 +00:00
trustedProxies : [ ] string { "0.0.0.0/0" , "::/0" } ,
2021-10-06 01:37:25 +00:00
trustedCIDRs : defaultTrustedCIDRs ,
2015-03-31 19:39:06 +00:00
}
2015-04-07 10:22:38 +00:00
engine . RouterGroup . engine = engine
2022-03-21 01:43:17 +00:00
engine . pool . New = func ( ) any {
2022-11-06 09:08:11 +00:00
return engine . allocateContext ( engine . maxParams )
2014-07-02 18:17:57 +00:00
}
2014-06-17 23:42:34 +00:00
return engine
}
2015-07-02 18:24:54 +00:00
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
2014-06-17 23:42:34 +00:00
func Default ( ) * Engine {
2017-09-29 03:58:57 +00:00
debugPrintWARNINGDefault ( )
2014-06-17 23:42:34 +00:00
engine := New ( )
2016-01-26 17:35:56 +00:00
engine . Use ( Logger ( ) , Recovery ( ) )
2014-06-17 23:42:34 +00:00
return engine
}
2022-02-05 13:13:20 +00:00
func ( engine * Engine ) Handler ( ) http . Handler {
if ! engine . UseH2C {
return engine
}
h2s := & http2 . Server { }
return h2c . NewHandler ( engine , h2s )
}
2022-11-06 09:08:11 +00:00
func ( engine * Engine ) allocateContext ( maxParams uint16 ) * Context {
v := make ( Params , 0 , maxParams )
2021-10-23 03:58:57 +00:00
skippedNodes := make ( [ ] skippedNode , 0 , engine . maxSections )
return & Context { engine : engine , params : & v , skippedNodes : & skippedNodes }
2015-03-25 18:33:17 +00:00
}
2021-12-02 10:00:24 +00:00
// Delims sets template left and right delims and returns an Engine instance.
2017-05-29 08:03:49 +00:00
func ( engine * Engine ) Delims ( left , right string ) * Engine {
2017-08-02 15:00:10 +00:00
engine . delims = render . Delims { Left : left , Right : right }
2017-05-29 08:03:49 +00:00
return engine
}
2020-05-05 05:55:57 +00:00
// SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON.
2017-07-07 17:21:30 +00:00
func ( engine * Engine ) SecureJsonPrefix ( prefix string ) * Engine {
2020-05-05 05:55:57 +00:00
engine . secureJSONPrefix = prefix
2017-07-07 17:21:30 +00:00
return engine
}
2017-12-29 09:10:28 +00:00
// LoadHTMLGlob loads HTML files identified by glob pattern
// and associates the result with HTML renderer.
2014-07-15 15:41:56 +00:00
func ( engine * Engine ) LoadHTMLGlob ( pattern string ) {
2017-09-28 14:54:37 +00:00
left := engine . delims . Left
right := engine . delims . Right
2018-07-02 03:06:56 +00:00
templ := template . Must ( template . New ( "" ) . Delims ( left , right ) . Funcs ( engine . FuncMap ) . ParseGlob ( pattern ) )
2017-09-28 14:54:37 +00:00
2014-10-08 19:37:26 +00:00
if IsDebugging ( ) {
2018-07-02 03:06:56 +00:00
debugPrintLoadTemplate ( templ )
2017-06-30 19:22:40 +00:00
engine . HTMLRender = render . HTMLDebug { Glob : pattern , FuncMap : engine . FuncMap , Delims : engine . delims }
2017-07-18 01:11:53 +00:00
return
2014-08-20 23:04:35 +00:00
}
2017-07-19 12:49:18 +00:00
2017-07-18 01:11:53 +00:00
engine . SetHTMLTemplate ( templ )
2014-07-15 15:41:56 +00:00
}
2017-12-29 09:10:28 +00:00
// LoadHTMLFiles loads a slice of HTML files
// and associates the result with HTML renderer.
2014-07-15 15:41:56 +00:00
func ( engine * Engine ) LoadHTMLFiles ( files ... string ) {
2014-10-08 19:37:26 +00:00
if IsDebugging ( ) {
2017-06-30 19:22:40 +00:00
engine . HTMLRender = render . HTMLDebug { Files : files , FuncMap : engine . FuncMap , Delims : engine . delims }
2017-07-18 01:11:53 +00:00
return
2014-08-20 23:04:35 +00:00
}
2017-07-19 12:49:18 +00:00
2017-07-18 01:11:53 +00:00
templ := template . Must ( template . New ( "" ) . Delims ( engine . delims . Left , engine . delims . Right ) . Funcs ( engine . FuncMap ) . ParseFiles ( files ... ) )
engine . SetHTMLTemplate ( templ )
2014-08-20 23:04:35 +00:00
}
2017-12-29 09:10:28 +00:00
// SetHTMLTemplate associate a template with HTML renderer.
2014-08-20 23:04:35 +00:00
func ( engine * Engine ) SetHTMLTemplate ( templ * template . Template ) {
2015-06-12 16:09:44 +00:00
if len ( engine . trees ) > 0 {
2015-07-02 18:24:54 +00:00
debugPrintWARNINGSetHTMLTemplate ( )
2015-06-12 16:09:44 +00:00
}
2017-05-29 08:03:49 +00:00
2017-06-30 19:22:40 +00:00
engine . HTMLRender = render . HTMLProduction { Template : templ . Funcs ( engine . FuncMap ) }
}
2017-12-29 09:10:28 +00:00
// SetFuncMap sets the FuncMap used for template.FuncMap.
2017-06-30 19:22:40 +00:00
func ( engine * Engine ) SetFuncMap ( funcMap template . FuncMap ) {
engine . FuncMap = funcMap
2014-06-17 23:42:34 +00:00
}
2021-12-02 10:00:24 +00:00
// NoRoute adds handlers for NoRoute. It returns a 404 code by default.
2014-07-17 21:42:23 +00:00
func ( engine * Engine ) NoRoute ( handlers ... HandlerFunc ) {
2014-07-17 22:29:44 +00:00
engine . noRoute = handlers
2014-10-08 19:37:26 +00:00
engine . rebuild404Handlers ( )
2014-07-17 22:29:44 +00:00
}
2021-09-29 11:26:02 +00:00
// NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true.
2015-03-08 23:37:27 +00:00
func ( engine * Engine ) NoMethod ( handlers ... HandlerFunc ) {
engine . noMethod = handlers
engine . rebuild405Handlers ( )
}
2021-12-02 10:00:24 +00:00
// Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
2015-05-29 19:03:41 +00:00
// 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.
2015-08-16 16:38:13 +00:00
func ( engine * Engine ) Use ( middleware ... HandlerFunc ) IRoutes {
2015-07-03 18:12:01 +00:00
engine . RouterGroup . Use ( middleware ... )
2014-10-08 19:37:26 +00:00
engine . rebuild404Handlers ( )
2015-03-08 23:37:27 +00:00
engine . rebuild405Handlers ( )
2015-06-10 23:02:38 +00:00
return engine
2014-10-08 19:37:26 +00:00
}
func ( engine * Engine ) rebuild404Handlers ( ) {
2015-03-25 15:53:58 +00:00
engine . allNoRoute = engine . combineHandlers ( engine . noRoute )
2015-03-08 23:37:27 +00:00
}
func ( engine * Engine ) rebuild405Handlers ( ) {
2015-03-25 15:53:58 +00:00
engine . allNoMethod = engine . combineHandlers ( engine . noMethod )
2014-06-17 23:42:34 +00:00
}
2015-05-19 21:22:35 +00:00
func ( engine * Engine ) addRoute ( method , path string , handlers HandlersChain ) {
2016-01-27 23:35:09 +00:00
assert1 ( path [ 0 ] == '/' , "path must begin with '/'" )
2017-09-28 16:22:35 +00:00
assert1 ( method != "" , "HTTP method can not be empty" )
2016-01-27 23:35:09 +00:00
assert1 ( len ( handlers ) > 0 , "there must be at least one handler" )
2015-04-09 10:15:02 +00:00
2016-01-27 23:35:09 +00:00
debugPrintRoute ( method , path , handlers )
2020-05-10 05:22:25 +00:00
2015-06-03 23:54:36 +00:00
root := engine . trees . get ( method )
2015-03-31 19:39:06 +00:00
if root == nil {
root = new ( node )
2019-05-26 00:20:21 +00:00
root . fullPath = "/"
2016-01-27 23:35:09 +00:00
engine . trees = append ( engine . trees , methodTree { method : method , root : root } )
2015-03-31 19:39:06 +00:00
}
root . addRoute ( path , handlers )
2020-05-10 05:22:25 +00:00
// Update maxParams
if paramsCount := countParams ( path ) ; paramsCount > engine . maxParams {
engine . maxParams = paramsCount
}
2021-10-23 03:58:57 +00:00
if sectionsCount := countSections ( path ) ; sectionsCount > engine . maxSections {
engine . maxSections = sectionsCount
}
2015-03-08 23:37:27 +00:00
}
2015-07-02 18:24:54 +00:00
// Routes returns a slice of registered routes, including some useful information, such as:
// the http method, path and the handler name.
2015-06-18 15:17:22 +00:00
func ( engine * Engine ) Routes ( ) ( routes RoutesInfo ) {
2015-06-07 02:20:39 +00:00
for _ , tree := range engine . trees {
2015-06-07 11:49:36 +00:00
routes = iterate ( "" , tree . method , routes , tree . root )
2015-06-07 02:20:39 +00:00
}
return routes
}
2015-06-18 15:17:22 +00:00
func iterate ( path , method string , routes RoutesInfo , root * node ) RoutesInfo {
2015-06-07 02:20:39 +00:00
path += root . path
2015-06-07 11:49:36 +00:00
if len ( root . handlers ) > 0 {
2018-10-23 02:56:33 +00:00
handlerFunc := root . handlers . Last ( )
2015-06-07 11:49:36 +00:00
routes = append ( routes , RouteInfo {
2018-10-23 02:56:33 +00:00
Method : method ,
Path : path ,
Handler : nameOfFunction ( handlerFunc ) ,
HandlerFunc : handlerFunc ,
2015-06-07 11:49:36 +00:00
} )
2015-06-07 02:20:39 +00:00
}
2015-07-02 16:42:33 +00:00
for _ , child := range root . children {
routes = iterate ( path , method , routes , child )
2015-06-07 02:20:39 +00:00
}
return routes
}
2015-07-02 18:24:54 +00:00
// Run attaches the router to a http.Server and starts listening and serving HTTP requests.
2015-05-29 19:03:41 +00:00
// It is a shortcut for http.ListenAndServe(addr, router)
2015-11-04 08:03:57 +00:00
// Note: this method will block the calling goroutine indefinitely unless an error happens.
2015-08-16 14:19:51 +00:00
func ( engine * Engine ) Run ( addr ... string ) ( err error ) {
2015-05-18 22:45:08 +00:00
defer func ( ) { debugPrintError ( err ) } ( )
2015-05-09 01:34:43 +00:00
2021-10-06 01:37:25 +00:00
if engine . isUnsafeTrustedProxies ( ) {
debugPrint ( "[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details." )
2021-04-06 03:37:25 +00:00
}
2021-05-25 05:47:35 +00:00
2015-08-16 14:19:51 +00:00
address := resolveAddress ( addr )
debugPrint ( "Listening and serving HTTP on %s\n" , address )
2022-02-05 13:13:20 +00:00
err = http . ListenAndServe ( address , engine . Handler ( ) )
2015-05-09 01:34:43 +00:00
return
2015-04-07 10:22:38 +00:00
}
2021-04-06 03:37:25 +00:00
func ( engine * Engine ) prepareTrustedCIDRs ( ) ( [ ] * net . IPNet , error ) {
2021-10-06 01:37:25 +00:00
if engine . trustedProxies == nil {
2021-04-06 03:37:25 +00:00
return nil , nil
}
2021-10-06 01:37:25 +00:00
cidr := make ( [ ] * net . IPNet , 0 , len ( engine . trustedProxies ) )
for _ , trustedProxy := range engine . trustedProxies {
2021-04-06 03:37:25 +00:00
if ! strings . Contains ( trustedProxy , "/" ) {
ip := parseIP ( trustedProxy )
if ip == nil {
return cidr , & net . ParseError { Type : "IP address" , Text : trustedProxy }
}
switch len ( ip ) {
case net . IPv4len :
trustedProxy += "/32"
case net . IPv6len :
trustedProxy += "/128"
}
}
_ , cidrNet , err := net . ParseCIDR ( trustedProxy )
if err != nil {
return cidr , err
}
cidr = append ( cidr , cidrNet )
}
return cidr , nil
}
2021-10-06 01:37:25 +00:00
// SetTrustedProxies set a list of network origins (IPv4 addresses,
// IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust
// request's headers that contain alternative client IP when
// `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies`
// feature is enabled by default, and it also trusts all proxies
// by default. If you want to disable this feature, use
// Engine.SetTrustedProxies(nil), then Context.ClientIP() will
// return the remote address directly.
2021-05-25 05:47:35 +00:00
func ( engine * Engine ) SetTrustedProxies ( trustedProxies [ ] string ) error {
2021-10-06 01:37:25 +00:00
engine . trustedProxies = trustedProxies
2021-05-25 05:47:35 +00:00
return engine . parseTrustedProxies ( )
}
2021-12-03 06:49:16 +00:00
// isUnsafeTrustedProxies checks if Engine.trustedCIDRs contains all IPs, it's not safe if it has (returns true)
2021-10-06 01:37:25 +00:00
func ( engine * Engine ) isUnsafeTrustedProxies ( ) bool {
2021-12-03 06:49:16 +00:00
return engine . isTrustedProxy ( net . ParseIP ( "0.0.0.0" ) ) || engine . isTrustedProxy ( net . ParseIP ( "::" ) )
2021-10-06 01:37:25 +00:00
}
// parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
2021-05-25 05:47:35 +00:00
func ( engine * Engine ) parseTrustedProxies ( ) error {
trustedCIDRs , err := engine . prepareTrustedCIDRs ( )
engine . trustedCIDRs = trustedCIDRs
return err
}
2021-12-03 06:49:16 +00:00
// 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
}
2021-04-06 03:37:25 +00:00
// 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 {
parsedIP := net . ParseIP ( ip )
if ipv4 := parsedIP . To4 ( ) ; ipv4 != nil {
// return ip in a 4-byte representation
return ipv4
}
// return ip in a 16-byte representation or nil
return parsedIP
}
2015-07-02 18:24:54 +00:00
// RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
2015-05-29 19:03:41 +00:00
// It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
2015-11-04 08:03:57 +00:00
// Note: this method will block the calling goroutine indefinitely unless an error happens.
2017-08-14 04:21:05 +00:00
func ( engine * Engine ) RunTLS ( addr , certFile , keyFile string ) ( err error ) {
2015-04-07 10:22:38 +00:00
debugPrint ( "Listening and serving HTTPS on %s\n" , addr )
2015-05-18 22:45:08 +00:00
defer func ( ) { debugPrintError ( err ) } ( )
2015-05-09 01:34:43 +00:00
2021-10-06 01:37:25 +00:00
if engine . isUnsafeTrustedProxies ( ) {
debugPrint ( "[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details." )
2021-05-25 05:47:35 +00:00
}
2022-02-05 13:13:20 +00:00
err = http . ListenAndServeTLS ( addr , certFile , keyFile , engine . Handler ( ) )
2015-05-09 01:34:43 +00:00
return
2015-04-07 10:22:38 +00:00
}
2015-07-02 18:24:54 +00:00
// RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
2021-12-02 10:00:24 +00:00
// through the specified unix socket (i.e. a file).
2015-11-04 08:03:57 +00:00
// Note: this method will block the calling goroutine indefinitely unless an error happens.
2015-05-18 22:45:08 +00:00
func ( engine * Engine ) RunUnix ( file string ) ( err error ) {
debugPrint ( "Listening and serving HTTP on unix:/%s" , file )
defer func ( ) { debugPrintError ( err ) } ( )
2021-10-06 01:37:25 +00:00
if engine . isUnsafeTrustedProxies ( ) {
debugPrint ( "[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
2023-04-26 03:18:22 +00:00
"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details." )
2021-05-25 05:47:35 +00:00
}
2015-05-18 22:48:19 +00:00
listener , err := net . Listen ( "unix" , file )
2015-05-18 22:45:08 +00:00
if err != nil {
return
}
defer listener . Close ( )
2020-03-16 14:36:15 +00:00
defer os . Remove ( file )
2022-02-05 13:13:20 +00:00
err = http . Serve ( listener , engine . Handler ( ) )
2015-05-18 22:45:08 +00:00
return
}
2018-11-06 02:28:51 +00:00
// RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified file descriptor.
// Note: this method will block the calling goroutine indefinitely unless an error happens.
func ( engine * Engine ) RunFd ( fd int ) ( err error ) {
debugPrint ( "Listening and serving HTTP on fd@%d" , fd )
defer func ( ) { debugPrintError ( err ) } ( )
2021-10-06 01:37:25 +00:00
if engine . isUnsafeTrustedProxies ( ) {
debugPrint ( "[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
2023-04-26 03:18:22 +00:00
"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details." )
2021-05-25 05:47:35 +00:00
}
2018-11-06 02:28:51 +00:00
f := os . NewFile ( uintptr ( fd ) , fmt . Sprintf ( "fd@%d" , fd ) )
listener , err := net . FileListener ( f )
if err != nil {
return
}
defer listener . Close ( )
2019-09-30 01:12:22 +00:00
err = engine . RunListener ( listener )
return
}
// RunListener attaches the router to a http.Server and starts listening and serving HTTP requests
// through the specified net.Listener
func ( engine * Engine ) RunListener ( listener net . Listener ) ( err error ) {
debugPrint ( "Listening and serving HTTP on listener what's bind with address@%s" , listener . Addr ( ) )
defer func ( ) { debugPrintError ( err ) } ( )
2021-05-25 05:47:35 +00:00
2021-10-06 01:37:25 +00:00
if engine . isUnsafeTrustedProxies ( ) {
debugPrint ( "[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
2023-04-26 03:18:22 +00:00
"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details." )
2021-05-25 05:47:35 +00:00
}
2022-02-05 13:13:20 +00:00
err = http . Serve ( listener , engine . Handler ( ) )
2018-11-06 02:28:51 +00:00
return
}
2017-07-06 01:28:16 +00:00
// ServeHTTP conforms to the http.Handler interface.
2015-03-31 19:39:06 +00:00
func ( engine * Engine ) ServeHTTP ( w http . ResponseWriter , req * http . Request ) {
2015-05-18 18:50:46 +00:00
c := engine . pool . Get ( ) . ( * Context )
c . writermem . reset ( w )
c . Request = req
c . reset ( )
2015-04-07 10:22:38 +00:00
2015-05-28 01:22:34 +00:00
engine . handleHTTPRequest ( c )
2015-05-18 18:50:46 +00:00
engine . pool . Put ( c )
2015-04-07 10:22:38 +00:00
}
2021-12-05 00:41:25 +00:00
// HandleContext re-enters a context that has been rewritten.
2018-05-30 01:19:04 +00:00
// This can be done by setting c.Request.URL.Path to your new target.
2021-12-05 00:41:25 +00:00
// Disclaimer: You can loop yourself to deal with this, use wisely.
2017-02-10 14:44:55 +00:00
func ( engine * Engine ) HandleContext ( c * Context ) {
2019-02-18 01:35:08 +00:00
oldIndexValue := c . index
2017-02-10 14:44:55 +00:00
c . reset ( )
engine . handleHTTPRequest ( c )
2019-02-18 01:35:08 +00:00
c . index = oldIndexValue
2017-02-10 14:44:55 +00:00
}
2017-09-28 14:54:37 +00:00
func ( engine * Engine ) handleHTTPRequest ( c * Context ) {
httpMethod := c . Request . Method
2019-03-05 01:41:37 +00:00
rPath := c . Request . URL . Path
2017-08-25 01:00:49 +00:00
unescape := false
2017-09-28 14:54:37 +00:00
if engine . UseRawPath && len ( c . Request . URL . RawPath ) > 0 {
2019-03-05 01:41:37 +00:00
rPath = c . Request . URL . RawPath
2017-02-28 10:29:41 +00:00
unescape = engine . UnescapePathValues
}
2019-11-28 16:02:02 +00:00
if engine . RemoveExtraSlash {
rPath = cleanPath ( rPath )
}
2015-04-07 10:22:38 +00:00
// Find root of the tree for the given HTTP method
2015-05-29 19:03:28 +00:00
t := engine . trees
for i , tl := 0 , len ( t ) ; i < tl ; i ++ {
2018-08-12 13:17:57 +00:00
if t [ i ] . method != httpMethod {
continue
}
root := t [ i ] . root
// Find route in tree
2021-10-23 03:58:57 +00:00
value := root . getValue ( rPath , c . params , c . skippedNodes , unescape )
2020-05-10 05:22:25 +00:00
if value . params != nil {
c . Params = * value . params
}
2019-05-26 00:20:21 +00:00
if value . handlers != nil {
c . handlers = value . handlers
c . fullPath = value . fullPath
2018-08-12 13:17:57 +00:00
c . Next ( )
c . writermem . WriteHeaderNow ( )
return
}
2021-07-09 02:30:44 +00:00
if httpMethod != http . MethodConnect && rPath != "/" {
2019-05-26 00:20:21 +00:00
if value . tsr && engine . RedirectTrailingSlash {
2018-08-12 13:17:57 +00:00
redirectTrailingSlash ( c )
2015-04-07 10:22:38 +00:00
return
2017-06-13 03:36:05 +00:00
}
2018-08-12 13:17:57 +00:00
if engine . RedirectFixedPath && redirectFixedPath ( c , root , engine . RedirectFixedPath ) {
return
2015-04-07 10:22:38 +00:00
}
2015-03-31 19:39:06 +00:00
}
2018-08-12 13:17:57 +00:00
break
2015-03-31 19:39:06 +00:00
}
2015-04-07 10:22:38 +00:00
if engine . HandleMethodNotAllowed {
2015-05-29 19:03:28 +00:00
for _ , tree := range engine . trees {
2018-08-12 13:17:57 +00:00
if tree . method == httpMethod {
continue
}
2021-10-23 03:58:57 +00:00
if value := tree . root . getValue ( rPath , nil , c . skippedNodes , unescape ) ; value . handlers != nil {
2018-08-12 13:17:57 +00:00
c . handlers = engine . allNoMethod
serveError ( c , http . StatusMethodNotAllowed , default405Body )
return
2015-04-07 10:22:38 +00:00
}
}
}
2017-09-28 14:54:37 +00:00
c . handlers = engine . allNoRoute
2018-06-26 09:21:32 +00:00
serveError ( c , http . StatusNotFound , default404Body )
2014-06-17 23:42:34 +00:00
}
2015-05-30 13:55:19 +00:00
var mimePlain = [ ] string { MIMEPlain }
func serveError ( c * Context , code int , defaultMessage [ ] byte ) {
c . writermem . status = code
c . Next ( )
2018-08-12 13:17:57 +00:00
if c . writermem . Written ( ) {
return
}
if c . writermem . Status ( ) == code {
c . writermem . Header ( ) [ "Content-Type" ] = mimePlain
2019-01-18 01:32:53 +00:00
_ , err := c . Writer . Write ( defaultMessage )
if err != nil {
debugPrint ( "cannot write message to writer during serve error: %v" , err )
}
2018-08-12 13:17:57 +00:00
return
2015-05-30 13:55:19 +00:00
}
2018-08-12 13:17:57 +00:00
c . writermem . WriteHeaderNow ( )
2015-05-30 13:55:19 +00:00
}
func redirectTrailingSlash ( c * Context ) {
2015-04-07 10:22:38 +00:00
req := c . Request
2019-02-27 11:56:29 +00:00
p := req . URL . Path
if prefix := path . Clean ( c . Request . Header . Get ( "X-Forwarded-Prefix" ) ) ; prefix != "." {
2023-02-19 13:25:48 +00:00
prefix = regSafePrefix . ReplaceAllString ( prefix , "" )
prefix = regRemoveRepeatedChar . ReplaceAllString ( prefix , "/" )
2023-02-17 02:00:19 +00:00
2019-02-27 11:56:29 +00:00
p = prefix + "/" + req . URL . Path
}
req . URL . Path = p + "/"
if length := len ( p ) ; length > 1 && p [ length - 1 ] == '/' {
req . URL . Path = p [ : length - 1 ]
2015-05-30 13:55:19 +00:00
}
2019-11-26 00:19:30 +00:00
redirectRequest ( c )
2015-05-30 13:55:19 +00:00
}
func redirectFixedPath ( c * Context , root * node , trailingSlash bool ) bool {
req := c . Request
2019-03-05 01:41:37 +00:00
rPath := req . URL . Path
2015-05-30 13:55:19 +00:00
2019-03-05 01:41:37 +00:00
if fixedPath , ok := root . findCaseInsensitivePath ( cleanPath ( rPath ) , trailingSlash ) ; ok {
2020-01-17 16:32:50 +00:00
req . URL . Path = bytesconv . BytesToString ( fixedPath )
2019-11-26 00:19:30 +00:00
redirectRequest ( c )
2015-04-07 10:22:38 +00:00
return true
}
return false
2014-06-17 23:42:34 +00:00
}
2019-11-26 00:19:30 +00:00
func redirectRequest ( c * Context ) {
req := c . Request
rPath := req . URL . Path
rURL := req . URL . String ( )
code := http . StatusMovedPermanently // Permanent redirect, request with GET method
2019-11-28 23:50:49 +00:00
if req . Method != http . MethodGet {
2019-11-26 00:19:30 +00:00
code = http . StatusTemporaryRedirect
}
debugPrint ( "redirecting request %d: %s --> %s" , code , rPath , rURL )
http . Redirect ( c . Writer , req , rURL , code )
c . writermem . WriteHeaderNow ( )
}