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 }