gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

gin.go (23011B)


      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 	"fmt"
      9 	"html/template"
     10 	"net"
     11 	"net/http"
     12 	"os"
     13 	"path"
     14 	"regexp"
     15 	"strings"
     16 	"sync"
     17 
     18 	"github.com/gin-gonic/gin/internal/bytesconv"
     19 	"github.com/gin-gonic/gin/render"
     20 	"golang.org/x/net/http2"
     21 	"golang.org/x/net/http2/h2c"
     22 )
     23 
     24 const defaultMultipartMemory = 32 << 20 // 32 MB
     25 
     26 var (
     27 	default404Body = []byte("404 page not found")
     28 	default405Body = []byte("405 method not allowed")
     29 )
     30 
     31 var defaultPlatform string
     32 
     33 var defaultTrustedCIDRs = []*net.IPNet{
     34 	{ // 0.0.0.0/0 (IPv4)
     35 		IP:   net.IP{0x0, 0x0, 0x0, 0x0},
     36 		Mask: net.IPMask{0x0, 0x0, 0x0, 0x0},
     37 	},
     38 	{ // ::/0 (IPv6)
     39 		IP:   net.IP{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
     40 		Mask: net.IPMask{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
     41 	},
     42 }
     43 
     44 var regSafePrefix = regexp.MustCompile("[^a-zA-Z0-9/-]+")
     45 var regRemoveRepeatedChar = regexp.MustCompile("/{2,}")
     46 
     47 // HandlerFunc defines the handler used by gin middleware as return value.
     48 type HandlerFunc func(*Context)
     49 
     50 // HandlersChain defines a HandlerFunc slice.
     51 type HandlersChain []HandlerFunc
     52 
     53 // Last returns the last handler in the chain. i.e. the last handler is the main one.
     54 func (c HandlersChain) Last() HandlerFunc {
     55 	if length := len(c); length > 0 {
     56 		return c[length-1]
     57 	}
     58 	return nil
     59 }
     60 
     61 // RouteInfo represents a request route's specification which contains method and path and its handler.
     62 type RouteInfo struct {
     63 	Method      string
     64 	Path        string
     65 	Handler     string
     66 	HandlerFunc HandlerFunc
     67 }
     68 
     69 // RoutesInfo defines a RouteInfo slice.
     70 type RoutesInfo []RouteInfo
     71 
     72 // Trusted platforms
     73 const (
     74 	// PlatformGoogleAppEngine when running on Google App Engine. Trust X-Appengine-Remote-Addr
     75 	// for determining the client's IP
     76 	PlatformGoogleAppEngine = "X-Appengine-Remote-Addr"
     77 	// PlatformCloudflare when using Cloudflare's CDN. Trust CF-Connecting-IP for determining
     78 	// the client's IP
     79 	PlatformCloudflare = "CF-Connecting-IP"
     80 )
     81 
     82 // Engine is the framework's instance, it contains the muxer, middleware and configuration settings.
     83 // Create an instance of Engine, by using New() or Default()
     84 type Engine struct {
     85 	RouterGroup
     86 
     87 	// RedirectTrailingSlash enables automatic redirection if the current route can't be matched but a
     88 	// handler for the path with (without) the trailing slash exists.
     89 	// For example if /foo/ is requested but a route only exists for /foo, the
     90 	// client is redirected to /foo with http status code 301 for GET requests
     91 	// and 307 for all other request methods.
     92 	RedirectTrailingSlash bool
     93 
     94 	// RedirectFixedPath if enabled, the router tries to fix the current request path, if no
     95 	// handle is registered for it.
     96 	// First superfluous path elements like ../ or // are removed.
     97 	// Afterwards the router does a case-insensitive lookup of the cleaned path.
     98 	// If a handle can be found for this route, the router makes a redirection
     99 	// to the corrected path with status code 301 for GET requests and 307 for
    100 	// all other request methods.
    101 	// For example /FOO and /..//Foo could be redirected to /foo.
    102 	// RedirectTrailingSlash is independent of this option.
    103 	RedirectFixedPath bool
    104 
    105 	// HandleMethodNotAllowed if enabled, the router checks if another method is allowed for the
    106 	// current route, if the current request can not be routed.
    107 	// If this is the case, the request is answered with 'Method Not Allowed'
    108 	// and HTTP status code 405.
    109 	// If no other Method is allowed, the request is delegated to the NotFound
    110 	// handler.
    111 	HandleMethodNotAllowed bool
    112 
    113 	// ForwardedByClientIP if enabled, client IP will be parsed from the request's headers that
    114 	// match those stored at `(*gin.Engine).RemoteIPHeaders`. If no IP was
    115 	// fetched, it falls back to the IP obtained from
    116 	// `(*gin.Context).Request.RemoteAddr`.
    117 	ForwardedByClientIP bool
    118 
    119 	// AppEngine was deprecated.
    120 	// Deprecated: USE `TrustedPlatform` WITH VALUE `gin.PlatformGoogleAppEngine` INSTEAD
    121 	// #726 #755 If enabled, it will trust some headers starting with
    122 	// 'X-AppEngine...' for better integration with that PaaS.
    123 	AppEngine bool
    124 
    125 	// UseRawPath if enabled, the url.RawPath will be used to find parameters.
    126 	UseRawPath bool
    127 
    128 	// UnescapePathValues if true, the path value will be unescaped.
    129 	// If UseRawPath is false (by default), the UnescapePathValues effectively is true,
    130 	// as url.Path gonna be used, which is already unescaped.
    131 	UnescapePathValues bool
    132 
    133 	// RemoveExtraSlash a parameter can be parsed from the URL even with extra slashes.
    134 	// See the PR #1817 and issue #1644
    135 	RemoveExtraSlash bool
    136 
    137 	// RemoteIPHeaders list of headers used to obtain the client IP when
    138 	// `(*gin.Engine).ForwardedByClientIP` is `true` and
    139 	// `(*gin.Context).Request.RemoteAddr` is matched by at least one of the
    140 	// network origins of list defined by `(*gin.Engine).SetTrustedProxies()`.
    141 	RemoteIPHeaders []string
    142 
    143 	// TrustedPlatform if set to a constant of value gin.Platform*, trusts the headers set by
    144 	// that platform, for example to determine the client IP
    145 	TrustedPlatform string
    146 
    147 	// MaxMultipartMemory value of 'maxMemory' param that is given to http.Request's ParseMultipartForm
    148 	// method call.
    149 	MaxMultipartMemory int64
    150 
    151 	// UseH2C enable h2c support.
    152 	UseH2C bool
    153 
    154 	// ContextWithFallback enable fallback Context.Deadline(), Context.Done(), Context.Err() and Context.Value() when Context.Request.Context() is not nil.
    155 	ContextWithFallback bool
    156 
    157 	delims           render.Delims
    158 	secureJSONPrefix string
    159 	HTMLRender       render.HTMLRender
    160 	FuncMap          template.FuncMap
    161 	allNoRoute       HandlersChain
    162 	allNoMethod      HandlersChain
    163 	noRoute          HandlersChain
    164 	noMethod         HandlersChain
    165 	pool             sync.Pool
    166 	trees            methodTrees
    167 	maxParams        uint16
    168 	maxSections      uint16
    169 	trustedProxies   []string
    170 	trustedCIDRs     []*net.IPNet
    171 }
    172 
    173 var _ IRouter = (*Engine)(nil)
    174 
    175 // New returns a new blank Engine instance without any middleware attached.
    176 // By default, the configuration is:
    177 // - RedirectTrailingSlash:  true
    178 // - RedirectFixedPath:      false
    179 // - HandleMethodNotAllowed: false
    180 // - ForwardedByClientIP:    true
    181 // - UseRawPath:             false
    182 // - UnescapePathValues:     true
    183 func New() *Engine {
    184 	debugPrintWARNINGNew()
    185 	engine := &Engine{
    186 		RouterGroup: RouterGroup{
    187 			Handlers: nil,
    188 			basePath: "/",
    189 			root:     true,
    190 		},
    191 		FuncMap:                template.FuncMap{},
    192 		RedirectTrailingSlash:  true,
    193 		RedirectFixedPath:      false,
    194 		HandleMethodNotAllowed: false,
    195 		ForwardedByClientIP:    true,
    196 		RemoteIPHeaders:        []string{"X-Forwarded-For", "X-Real-IP"},
    197 		TrustedPlatform:        defaultPlatform,
    198 		UseRawPath:             false,
    199 		RemoveExtraSlash:       false,
    200 		UnescapePathValues:     true,
    201 		MaxMultipartMemory:     defaultMultipartMemory,
    202 		trees:                  make(methodTrees, 0, 9),
    203 		delims:                 render.Delims{Left: "{{", Right: "}}"},
    204 		secureJSONPrefix:       "while(1);",
    205 		trustedProxies:         []string{"0.0.0.0/0", "::/0"},
    206 		trustedCIDRs:           defaultTrustedCIDRs,
    207 	}
    208 	engine.RouterGroup.engine = engine
    209 	engine.pool.New = func() any {
    210 		return engine.allocateContext(engine.maxParams)
    211 	}
    212 	return engine
    213 }
    214 
    215 // Default returns an Engine instance with the Logger and Recovery middleware already attached.
    216 func Default() *Engine {
    217 	debugPrintWARNINGDefault()
    218 	engine := New()
    219 	engine.Use(Logger(), Recovery())
    220 	return engine
    221 }
    222 
    223 func (engine *Engine) Handler() http.Handler {
    224 	if !engine.UseH2C {
    225 		return engine
    226 	}
    227 
    228 	h2s := &http2.Server{}
    229 	return h2c.NewHandler(engine, h2s)
    230 }
    231 
    232 func (engine *Engine) allocateContext(maxParams uint16) *Context {
    233 	v := make(Params, 0, maxParams)
    234 	skippedNodes := make([]skippedNode, 0, engine.maxSections)
    235 	return &Context{engine: engine, params: &v, skippedNodes: &skippedNodes}
    236 }
    237 
    238 // Delims sets template left and right delims and returns an Engine instance.
    239 func (engine *Engine) Delims(left, right string) *Engine {
    240 	engine.delims = render.Delims{Left: left, Right: right}
    241 	return engine
    242 }
    243 
    244 // SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON.
    245 func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
    246 	engine.secureJSONPrefix = prefix
    247 	return engine
    248 }
    249 
    250 // LoadHTMLGlob loads HTML files identified by glob pattern
    251 // and associates the result with HTML renderer.
    252 func (engine *Engine) LoadHTMLGlob(pattern string) {
    253 	left := engine.delims.Left
    254 	right := engine.delims.Right
    255 	templ := template.Must(template.New("").Delims(left, right).Funcs(engine.FuncMap).ParseGlob(pattern))
    256 
    257 	if IsDebugging() {
    258 		debugPrintLoadTemplate(templ)
    259 		engine.HTMLRender = render.HTMLDebug{Glob: pattern, FuncMap: engine.FuncMap, Delims: engine.delims}
    260 		return
    261 	}
    262 
    263 	engine.SetHTMLTemplate(templ)
    264 }
    265 
    266 // LoadHTMLFiles loads a slice of HTML files
    267 // and associates the result with HTML renderer.
    268 func (engine *Engine) LoadHTMLFiles(files ...string) {
    269 	if IsDebugging() {
    270 		engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims}
    271 		return
    272 	}
    273 
    274 	templ := template.Must(template.New("").Delims(engine.delims.Left, engine.delims.Right).Funcs(engine.FuncMap).ParseFiles(files...))
    275 	engine.SetHTMLTemplate(templ)
    276 }
    277 
    278 // SetHTMLTemplate associate a template with HTML renderer.
    279 func (engine *Engine) SetHTMLTemplate(templ *template.Template) {
    280 	if len(engine.trees) > 0 {
    281 		debugPrintWARNINGSetHTMLTemplate()
    282 	}
    283 
    284 	engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)}
    285 }
    286 
    287 // SetFuncMap sets the FuncMap used for template.FuncMap.
    288 func (engine *Engine) SetFuncMap(funcMap template.FuncMap) {
    289 	engine.FuncMap = funcMap
    290 }
    291 
    292 // NoRoute adds handlers for NoRoute. It returns a 404 code by default.
    293 func (engine *Engine) NoRoute(handlers ...HandlerFunc) {
    294 	engine.noRoute = handlers
    295 	engine.rebuild404Handlers()
    296 }
    297 
    298 // NoMethod sets the handlers called when Engine.HandleMethodNotAllowed = true.
    299 func (engine *Engine) NoMethod(handlers ...HandlerFunc) {
    300 	engine.noMethod = handlers
    301 	engine.rebuild405Handlers()
    302 }
    303 
    304 // Use attaches a global middleware to the router. i.e. the middleware attached through Use() will be
    305 // included in the handlers chain for every single request. Even 404, 405, static files...
    306 // For example, this is the right place for a logger or error management middleware.
    307 func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    308 	engine.RouterGroup.Use(middleware...)
    309 	engine.rebuild404Handlers()
    310 	engine.rebuild405Handlers()
    311 	return engine
    312 }
    313 
    314 func (engine *Engine) rebuild404Handlers() {
    315 	engine.allNoRoute = engine.combineHandlers(engine.noRoute)
    316 }
    317 
    318 func (engine *Engine) rebuild405Handlers() {
    319 	engine.allNoMethod = engine.combineHandlers(engine.noMethod)
    320 }
    321 
    322 func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {
    323 	assert1(path[0] == '/', "path must begin with '/'")
    324 	assert1(method != "", "HTTP method can not be empty")
    325 	assert1(len(handlers) > 0, "there must be at least one handler")
    326 
    327 	debugPrintRoute(method, path, handlers)
    328 
    329 	root := engine.trees.get(method)
    330 	if root == nil {
    331 		root = new(node)
    332 		root.fullPath = "/"
    333 		engine.trees = append(engine.trees, methodTree{method: method, root: root})
    334 	}
    335 	root.addRoute(path, handlers)
    336 
    337 	// Update maxParams
    338 	if paramsCount := countParams(path); paramsCount > engine.maxParams {
    339 		engine.maxParams = paramsCount
    340 	}
    341 
    342 	if sectionsCount := countSections(path); sectionsCount > engine.maxSections {
    343 		engine.maxSections = sectionsCount
    344 	}
    345 }
    346 
    347 // Routes returns a slice of registered routes, including some useful information, such as:
    348 // the http method, path and the handler name.
    349 func (engine *Engine) Routes() (routes RoutesInfo) {
    350 	for _, tree := range engine.trees {
    351 		routes = iterate("", tree.method, routes, tree.root)
    352 	}
    353 	return routes
    354 }
    355 
    356 func iterate(path, method string, routes RoutesInfo, root *node) RoutesInfo {
    357 	path += root.path
    358 	if len(root.handlers) > 0 {
    359 		handlerFunc := root.handlers.Last()
    360 		routes = append(routes, RouteInfo{
    361 			Method:      method,
    362 			Path:        path,
    363 			Handler:     nameOfFunction(handlerFunc),
    364 			HandlerFunc: handlerFunc,
    365 		})
    366 	}
    367 	for _, child := range root.children {
    368 		routes = iterate(path, method, routes, child)
    369 	}
    370 	return routes
    371 }
    372 
    373 // Run attaches the router to a http.Server and starts listening and serving HTTP requests.
    374 // It is a shortcut for http.ListenAndServe(addr, router)
    375 // Note: this method will block the calling goroutine indefinitely unless an error happens.
    376 func (engine *Engine) Run(addr ...string) (err error) {
    377 	defer func() { debugPrintError(err) }()
    378 
    379 	if engine.isUnsafeTrustedProxies() {
    380 		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
    381 			"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
    382 	}
    383 
    384 	address := resolveAddress(addr)
    385 	debugPrint("Listening and serving HTTP on %s\n", address)
    386 	err = http.ListenAndServe(address, engine.Handler())
    387 	return
    388 }
    389 
    390 func (engine *Engine) prepareTrustedCIDRs() ([]*net.IPNet, error) {
    391 	if engine.trustedProxies == nil {
    392 		return nil, nil
    393 	}
    394 
    395 	cidr := make([]*net.IPNet, 0, len(engine.trustedProxies))
    396 	for _, trustedProxy := range engine.trustedProxies {
    397 		if !strings.Contains(trustedProxy, "/") {
    398 			ip := parseIP(trustedProxy)
    399 			if ip == nil {
    400 				return cidr, &net.ParseError{Type: "IP address", Text: trustedProxy}
    401 			}
    402 
    403 			switch len(ip) {
    404 			case net.IPv4len:
    405 				trustedProxy += "/32"
    406 			case net.IPv6len:
    407 				trustedProxy += "/128"
    408 			}
    409 		}
    410 		_, cidrNet, err := net.ParseCIDR(trustedProxy)
    411 		if err != nil {
    412 			return cidr, err
    413 		}
    414 		cidr = append(cidr, cidrNet)
    415 	}
    416 	return cidr, nil
    417 }
    418 
    419 // SetTrustedProxies set a list of network origins (IPv4 addresses,
    420 // IPv4 CIDRs, IPv6 addresses or IPv6 CIDRs) from which to trust
    421 // request's headers that contain alternative client IP when
    422 // `(*gin.Engine).ForwardedByClientIP` is `true`. `TrustedProxies`
    423 // feature is enabled by default, and it also trusts all proxies
    424 // by default. If you want to disable this feature, use
    425 // Engine.SetTrustedProxies(nil), then Context.ClientIP() will
    426 // return the remote address directly.
    427 func (engine *Engine) SetTrustedProxies(trustedProxies []string) error {
    428 	engine.trustedProxies = trustedProxies
    429 	return engine.parseTrustedProxies()
    430 }
    431 
    432 // isUnsafeTrustedProxies checks if Engine.trustedCIDRs contains all IPs, it's not safe if it has (returns true)
    433 func (engine *Engine) isUnsafeTrustedProxies() bool {
    434 	return engine.isTrustedProxy(net.ParseIP("0.0.0.0")) || engine.isTrustedProxy(net.ParseIP("::"))
    435 }
    436 
    437 // parseTrustedProxies parse Engine.trustedProxies to Engine.trustedCIDRs
    438 func (engine *Engine) parseTrustedProxies() error {
    439 	trustedCIDRs, err := engine.prepareTrustedCIDRs()
    440 	engine.trustedCIDRs = trustedCIDRs
    441 	return err
    442 }
    443 
    444 // isTrustedProxy will check whether the IP address is included in the trusted list according to Engine.trustedCIDRs
    445 func (engine *Engine) isTrustedProxy(ip net.IP) bool {
    446 	if engine.trustedCIDRs == nil {
    447 		return false
    448 	}
    449 	for _, cidr := range engine.trustedCIDRs {
    450 		if cidr.Contains(ip) {
    451 			return true
    452 		}
    453 	}
    454 	return false
    455 }
    456 
    457 // validateHeader will parse X-Forwarded-For header and return the trusted client IP address
    458 func (engine *Engine) validateHeader(header string) (clientIP string, valid bool) {
    459 	if header == "" {
    460 		return "", false
    461 	}
    462 	items := strings.Split(header, ",")
    463 	for i := len(items) - 1; i >= 0; i-- {
    464 		ipStr := strings.TrimSpace(items[i])
    465 		ip := net.ParseIP(ipStr)
    466 		if ip == nil {
    467 			break
    468 		}
    469 
    470 		// X-Forwarded-For is appended by proxy
    471 		// Check IPs in reverse order and stop when find untrusted proxy
    472 		if (i == 0) || (!engine.isTrustedProxy(ip)) {
    473 			return ipStr, true
    474 		}
    475 	}
    476 	return "", false
    477 }
    478 
    479 // parseIP parse a string representation of an IP and returns a net.IP with the
    480 // minimum byte representation or nil if input is invalid.
    481 func parseIP(ip string) net.IP {
    482 	parsedIP := net.ParseIP(ip)
    483 
    484 	if ipv4 := parsedIP.To4(); ipv4 != nil {
    485 		// return ip in a 4-byte representation
    486 		return ipv4
    487 	}
    488 
    489 	// return ip in a 16-byte representation or nil
    490 	return parsedIP
    491 }
    492 
    493 // RunTLS attaches the router to a http.Server and starts listening and serving HTTPS (secure) requests.
    494 // It is a shortcut for http.ListenAndServeTLS(addr, certFile, keyFile, router)
    495 // Note: this method will block the calling goroutine indefinitely unless an error happens.
    496 func (engine *Engine) RunTLS(addr, certFile, keyFile string) (err error) {
    497 	debugPrint("Listening and serving HTTPS on %s\n", addr)
    498 	defer func() { debugPrintError(err) }()
    499 
    500 	if engine.isUnsafeTrustedProxies() {
    501 		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
    502 			"Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.")
    503 	}
    504 
    505 	err = http.ListenAndServeTLS(addr, certFile, keyFile, engine.Handler())
    506 	return
    507 }
    508 
    509 // RunUnix attaches the router to a http.Server and starts listening and serving HTTP requests
    510 // through the specified unix socket (i.e. a file).
    511 // Note: this method will block the calling goroutine indefinitely unless an error happens.
    512 func (engine *Engine) RunUnix(file string) (err error) {
    513 	debugPrint("Listening and serving HTTP on unix:/%s", file)
    514 	defer func() { debugPrintError(err) }()
    515 
    516 	if engine.isUnsafeTrustedProxies() {
    517 		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
    518 			"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
    519 	}
    520 
    521 	listener, err := net.Listen("unix", file)
    522 	if err != nil {
    523 		return
    524 	}
    525 	defer listener.Close()
    526 	defer os.Remove(file)
    527 
    528 	err = http.Serve(listener, engine.Handler())
    529 	return
    530 }
    531 
    532 // RunFd attaches the router to a http.Server and starts listening and serving HTTP requests
    533 // through the specified file descriptor.
    534 // Note: this method will block the calling goroutine indefinitely unless an error happens.
    535 func (engine *Engine) RunFd(fd int) (err error) {
    536 	debugPrint("Listening and serving HTTP on fd@%d", fd)
    537 	defer func() { debugPrintError(err) }()
    538 
    539 	if engine.isUnsafeTrustedProxies() {
    540 		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
    541 			"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
    542 	}
    543 
    544 	f := os.NewFile(uintptr(fd), fmt.Sprintf("fd@%d", fd))
    545 	listener, err := net.FileListener(f)
    546 	if err != nil {
    547 		return
    548 	}
    549 	defer listener.Close()
    550 	err = engine.RunListener(listener)
    551 	return
    552 }
    553 
    554 // RunListener attaches the router to a http.Server and starts listening and serving HTTP requests
    555 // through the specified net.Listener
    556 func (engine *Engine) RunListener(listener net.Listener) (err error) {
    557 	debugPrint("Listening and serving HTTP on listener what's bind with address@%s", listener.Addr())
    558 	defer func() { debugPrintError(err) }()
    559 
    560 	if engine.isUnsafeTrustedProxies() {
    561 		debugPrint("[WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\n" +
    562 			"Please check https://github.com/gin-gonic/gin/blob/master/docs/doc.md#dont-trust-all-proxies for details.")
    563 	}
    564 
    565 	err = http.Serve(listener, engine.Handler())
    566 	return
    567 }
    568 
    569 // ServeHTTP conforms to the http.Handler interface.
    570 func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    571 	c := engine.pool.Get().(*Context)
    572 	c.writermem.reset(w)
    573 	c.Request = req
    574 	c.reset()
    575 
    576 	engine.handleHTTPRequest(c)
    577 
    578 	engine.pool.Put(c)
    579 }
    580 
    581 // HandleContext re-enters a context that has been rewritten.
    582 // This can be done by setting c.Request.URL.Path to your new target.
    583 // Disclaimer: You can loop yourself to deal with this, use wisely.
    584 func (engine *Engine) HandleContext(c *Context) {
    585 	oldIndexValue := c.index
    586 	c.reset()
    587 	engine.handleHTTPRequest(c)
    588 
    589 	c.index = oldIndexValue
    590 }
    591 
    592 func (engine *Engine) handleHTTPRequest(c *Context) {
    593 	httpMethod := c.Request.Method
    594 	rPath := c.Request.URL.Path
    595 	unescape := false
    596 	if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 {
    597 		rPath = c.Request.URL.RawPath
    598 		unescape = engine.UnescapePathValues
    599 	}
    600 
    601 	if engine.RemoveExtraSlash {
    602 		rPath = cleanPath(rPath)
    603 	}
    604 
    605 	// Find root of the tree for the given HTTP method
    606 	t := engine.trees
    607 	for i, tl := 0, len(t); i < tl; i++ {
    608 		if t[i].method != httpMethod {
    609 			continue
    610 		}
    611 		root := t[i].root
    612 		// Find route in tree
    613 		value := root.getValue(rPath, c.params, c.skippedNodes, unescape)
    614 		if value.params != nil {
    615 			c.Params = *value.params
    616 		}
    617 		if value.handlers != nil {
    618 			c.handlers = value.handlers
    619 			c.fullPath = value.fullPath
    620 			c.Next()
    621 			c.writermem.WriteHeaderNow()
    622 			return
    623 		}
    624 		if httpMethod != http.MethodConnect && rPath != "/" {
    625 			if value.tsr && engine.RedirectTrailingSlash {
    626 				redirectTrailingSlash(c)
    627 				return
    628 			}
    629 			if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
    630 				return
    631 			}
    632 		}
    633 		break
    634 	}
    635 
    636 	if engine.HandleMethodNotAllowed {
    637 		for _, tree := range engine.trees {
    638 			if tree.method == httpMethod {
    639 				continue
    640 			}
    641 			if value := tree.root.getValue(rPath, nil, c.skippedNodes, unescape); value.handlers != nil {
    642 				c.handlers = engine.allNoMethod
    643 				serveError(c, http.StatusMethodNotAllowed, default405Body)
    644 				return
    645 			}
    646 		}
    647 	}
    648 	c.handlers = engine.allNoRoute
    649 	serveError(c, http.StatusNotFound, default404Body)
    650 }
    651 
    652 var mimePlain = []string{MIMEPlain}
    653 
    654 func serveError(c *Context, code int, defaultMessage []byte) {
    655 	c.writermem.status = code
    656 	c.Next()
    657 	if c.writermem.Written() {
    658 		return
    659 	}
    660 	if c.writermem.Status() == code {
    661 		c.writermem.Header()["Content-Type"] = mimePlain
    662 		_, err := c.Writer.Write(defaultMessage)
    663 		if err != nil {
    664 			debugPrint("cannot write message to writer during serve error: %v", err)
    665 		}
    666 		return
    667 	}
    668 	c.writermem.WriteHeaderNow()
    669 }
    670 
    671 func redirectTrailingSlash(c *Context) {
    672 	req := c.Request
    673 	p := req.URL.Path
    674 	if prefix := path.Clean(c.Request.Header.Get("X-Forwarded-Prefix")); prefix != "." {
    675 		prefix = regSafePrefix.ReplaceAllString(prefix, "")
    676 		prefix = regRemoveRepeatedChar.ReplaceAllString(prefix, "/")
    677 
    678 		p = prefix + "/" + req.URL.Path
    679 	}
    680 	req.URL.Path = p + "/"
    681 	if length := len(p); length > 1 && p[length-1] == '/' {
    682 		req.URL.Path = p[:length-1]
    683 	}
    684 	redirectRequest(c)
    685 }
    686 
    687 func redirectFixedPath(c *Context, root *node, trailingSlash bool) bool {
    688 	req := c.Request
    689 	rPath := req.URL.Path
    690 
    691 	if fixedPath, ok := root.findCaseInsensitivePath(cleanPath(rPath), trailingSlash); ok {
    692 		req.URL.Path = bytesconv.BytesToString(fixedPath)
    693 		redirectRequest(c)
    694 		return true
    695 	}
    696 	return false
    697 }
    698 
    699 func redirectRequest(c *Context) {
    700 	req := c.Request
    701 	rPath := req.URL.Path
    702 	rURL := req.URL.String()
    703 
    704 	code := http.StatusMovedPermanently // Permanent redirect, request with GET method
    705 	if req.Method != http.MethodGet {
    706 		code = http.StatusTemporaryRedirect
    707 	}
    708 	debugPrint("redirecting request %d: %s --> %s", code, rPath, rURL)
    709 	http.Redirect(c.Writer, req, rURL, code)
    710 	c.writermem.WriteHeaderNow()
    711 }