github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/gin.go (about)

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