github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/routergroup.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  	"github.com/hellobchain/newcryptosm/http"
     9  	"path"
    10  	"regexp"
    11  	"strings"
    12  )
    13  
    14  // IRouter defines all router handle interface includes single and group router.
    15  type IRouter interface {
    16  	IRoutes
    17  	Group(string, ...HandlerFunc) *RouterGroup
    18  }
    19  
    20  // IRoutes defines all router handle interface.
    21  type IRoutes interface {
    22  	Use(...HandlerFunc) IRoutes
    23  
    24  	Handle(string, string, ...HandlerFunc) IRoutes
    25  	Any(string, ...HandlerFunc) IRoutes
    26  	GET(string, ...HandlerFunc) IRoutes
    27  	POST(string, ...HandlerFunc) IRoutes
    28  	DELETE(string, ...HandlerFunc) IRoutes
    29  	PATCH(string, ...HandlerFunc) IRoutes
    30  	PUT(string, ...HandlerFunc) IRoutes
    31  	OPTIONS(string, ...HandlerFunc) IRoutes
    32  	HEAD(string, ...HandlerFunc) IRoutes
    33  
    34  	StaticFile(string, string) IRoutes
    35  	Static(string, string) IRoutes
    36  	StaticFS(string, http.FileSystem) IRoutes
    37  }
    38  
    39  // RouterGroup is used internally to configure router, a RouterGroup is associated with
    40  // a prefix and an array of handlers (middleware).
    41  type RouterGroup struct {
    42  	Handlers HandlersChain
    43  	basePath string
    44  	engine   *Engine
    45  	root     bool
    46  }
    47  
    48  var _ IRouter = &RouterGroup{}
    49  
    50  // Use adds middleware to the group, see example code in GitHub.
    51  func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    52  	group.Handlers = append(group.Handlers, middleware...)
    53  	return group.returnObj()
    54  }
    55  
    56  // Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix.
    57  // For example, all the routes that use a common middleware for authorization could be grouped.
    58  func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
    59  	return &RouterGroup{
    60  		Handlers: group.combineHandlers(handlers),
    61  		basePath: group.calculateAbsolutePath(relativePath),
    62  		engine:   group.engine,
    63  	}
    64  }
    65  
    66  // BasePath returns the base path of router group.
    67  // For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api".
    68  func (group *RouterGroup) BasePath() string {
    69  	return group.basePath
    70  }
    71  
    72  func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
    73  	absolutePath := group.calculateAbsolutePath(relativePath)
    74  	handlers = group.combineHandlers(handlers)
    75  	group.engine.addRoute(httpMethod, absolutePath, handlers)
    76  	return group.returnObj()
    77  }
    78  
    79  // Handle registers a new request handle and middleware with the given path and method.
    80  // The last handler should be the real handler, the other ones should be middleware that can and should be shared among different routes.
    81  // See the example code in GitHub.
    82  //
    83  // For GET, POST, PUT, PATCH and DELETE requests the respective shortcut
    84  // functions can be used.
    85  //
    86  // This function is intended for bulk loading and to allow the usage of less
    87  // frequently used, non-standardized or custom methods (e.g. for internal
    88  // communication with a proxy).
    89  func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
    90  	if matches, err := regexp.MatchString("^[A-Z]+$", httpMethod); !matches || err != nil {
    91  		panic("http method " + httpMethod + " is not valid")
    92  	}
    93  	return group.handle(httpMethod, relativePath, handlers)
    94  }
    95  
    96  // POST is a shortcut for router.Handle("POST", path, handle).
    97  func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes {
    98  	return group.handle(http.MethodPost, relativePath, handlers)
    99  }
   100  
   101  // GET is a shortcut for router.Handle("GET", path, handle).
   102  func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
   103  	return group.handle(http.MethodGet, relativePath, handlers)
   104  }
   105  
   106  // DELETE is a shortcut for router.Handle("DELETE", path, handle).
   107  func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
   108  	return group.handle(http.MethodDelete, relativePath, handlers)
   109  }
   110  
   111  // PATCH is a shortcut for router.Handle("PATCH", path, handle).
   112  func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
   113  	return group.handle(http.MethodPatch, relativePath, handlers)
   114  }
   115  
   116  // PUT is a shortcut for router.Handle("PUT", path, handle).
   117  func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
   118  	return group.handle(http.MethodPut, relativePath, handlers)
   119  }
   120  
   121  // OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle).
   122  func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
   123  	return group.handle(http.MethodOptions, relativePath, handlers)
   124  }
   125  
   126  // HEAD is a shortcut for router.Handle("HEAD", path, handle).
   127  func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
   128  	return group.handle(http.MethodHead, relativePath, handlers)
   129  }
   130  
   131  // Any registers a route that matches all the HTTP methods.
   132  // GET, POST, PUT, PATCH, HEAD, OPTIONS, DELETE, CONNECT, TRACE.
   133  func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes {
   134  	group.handle(http.MethodGet, relativePath, handlers)
   135  	group.handle(http.MethodPost, relativePath, handlers)
   136  	group.handle(http.MethodPut, relativePath, handlers)
   137  	group.handle(http.MethodPatch, relativePath, handlers)
   138  	group.handle(http.MethodHead, relativePath, handlers)
   139  	group.handle(http.MethodOptions, relativePath, handlers)
   140  	group.handle(http.MethodDelete, relativePath, handlers)
   141  	group.handle(http.MethodConnect, relativePath, handlers)
   142  	group.handle(http.MethodTrace, relativePath, handlers)
   143  	return group.returnObj()
   144  }
   145  
   146  // StaticFile registers a single route in order to serve a single file of the local filesystem.
   147  // router.StaticFile("favicon.ico", "./resources/favicon.ico")
   148  func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
   149  	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
   150  		panic("URL parameters can not be used when serving a static file")
   151  	}
   152  	handler := func(c *Context) {
   153  		c.File(filepath)
   154  	}
   155  	group.GET(relativePath, handler)
   156  	group.HEAD(relativePath, handler)
   157  	return group.returnObj()
   158  }
   159  
   160  // Static serves files from the given file system root.
   161  // Internally a http.FileServer is used, therefore http.NotFound is used instead
   162  // of the Router's NotFound handler.
   163  // To use the operating system's file system implementation,
   164  // use :
   165  //     router.Static("/static", "/var/www")
   166  func (group *RouterGroup) Static(relativePath, root string) IRoutes {
   167  	return group.StaticFS(relativePath, Dir(root, false))
   168  }
   169  
   170  // StaticFS works just like `Static()` but a custom `http.FileSystem` can be used instead.
   171  // Gin by default user: gin.Dir()
   172  func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
   173  	if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
   174  		panic("URL parameters can not be used when serving a static folder")
   175  	}
   176  	handler := group.createStaticHandler(relativePath, fs)
   177  	urlPattern := path.Join(relativePath, "/*filepath")
   178  
   179  	// Register GET and HEAD handlers
   180  	group.GET(urlPattern, handler)
   181  	group.HEAD(urlPattern, handler)
   182  	return group.returnObj()
   183  }
   184  
   185  func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
   186  	absolutePath := group.calculateAbsolutePath(relativePath)
   187  	fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
   188  
   189  	return func(c *Context) {
   190  		if _, noListing := fs.(*onlyFilesFS); noListing {
   191  			c.Writer.WriteHeader(http.StatusNotFound)
   192  		}
   193  
   194  		file := c.Param("filepath")
   195  		// Check if file exists and/or if we have permission to access it
   196  		f, err := fs.Open(file)
   197  		if err != nil {
   198  			c.Writer.WriteHeader(http.StatusNotFound)
   199  			c.handlers = group.engine.noRoute
   200  			// Reset index
   201  			c.index = -1
   202  			return
   203  		}
   204  		f.Close()
   205  
   206  		fileServer.ServeHTTP(c.Writer, c.Request)
   207  	}
   208  }
   209  
   210  func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
   211  	finalSize := len(group.Handlers) + len(handlers)
   212  	if finalSize >= int(abortIndex) {
   213  		panic("too many handlers")
   214  	}
   215  	mergedHandlers := make(HandlersChain, finalSize)
   216  	copy(mergedHandlers, group.Handlers)
   217  	copy(mergedHandlers[len(group.Handlers):], handlers)
   218  	return mergedHandlers
   219  }
   220  
   221  func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
   222  	return joinPaths(group.basePath, relativePath)
   223  }
   224  
   225  func (group *RouterGroup) returnObj() IRoutes {
   226  	if group.root {
   227  		return group.engine
   228  	}
   229  	return group
   230  }