1
2
3
4
5 package gin
6
7 import (
8 "net/http"
9 "path"
10 "regexp"
11 "strings"
12 )
13
14 var (
15
16 regEnLetter = regexp.MustCompile("^[A-Z]+$")
17
18
19 anyMethods = []string{
20 http.MethodGet, http.MethodPost, http.MethodPut, http.MethodPatch,
21 http.MethodHead, http.MethodOptions, http.MethodDelete, http.MethodConnect,
22 http.MethodTrace,
23 }
24 )
25
26
27 type IRouter interface {
28 IRoutes
29 Group(string, ...HandlerFunc) *RouterGroup
30 }
31
32
33 type IRoutes interface {
34 Use(...HandlerFunc) IRoutes
35
36 Handle(string, string, ...HandlerFunc) IRoutes
37 Any(string, ...HandlerFunc) IRoutes
38 GET(string, ...HandlerFunc) IRoutes
39 POST(string, ...HandlerFunc) IRoutes
40 DELETE(string, ...HandlerFunc) IRoutes
41 PATCH(string, ...HandlerFunc) IRoutes
42 PUT(string, ...HandlerFunc) IRoutes
43 OPTIONS(string, ...HandlerFunc) IRoutes
44 HEAD(string, ...HandlerFunc) IRoutes
45 Match([]string, string, ...HandlerFunc) IRoutes
46
47 StaticFile(string, string) IRoutes
48 StaticFileFS(string, string, http.FileSystem) IRoutes
49 Static(string, string) IRoutes
50 StaticFS(string, http.FileSystem) IRoutes
51 }
52
53
54
55 type RouterGroup struct {
56 Handlers HandlersChain
57 basePath string
58 engine *Engine
59 root bool
60 }
61
62 var _ IRouter = (*RouterGroup)(nil)
63
64
65 func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
66 group.Handlers = append(group.Handlers, middleware...)
67 return group.returnObj()
68 }
69
70
71
72 func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup {
73 return &RouterGroup{
74 Handlers: group.combineHandlers(handlers),
75 basePath: group.calculateAbsolutePath(relativePath),
76 engine: group.engine,
77 }
78 }
79
80
81
82 func (group *RouterGroup) BasePath() string {
83 return group.basePath
84 }
85
86 func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes {
87 absolutePath := group.calculateAbsolutePath(relativePath)
88 handlers = group.combineHandlers(handlers)
89 group.engine.addRoute(httpMethod, absolutePath, handlers)
90 return group.returnObj()
91 }
92
93
94
95
96
97
98
99
100
101
102
103 func (group *RouterGroup) Handle(httpMethod, relativePath string, handlers ...HandlerFunc) IRoutes {
104 if matched := regEnLetter.MatchString(httpMethod); !matched {
105 panic("http method " + httpMethod + " is not valid")
106 }
107 return group.handle(httpMethod, relativePath, handlers)
108 }
109
110
111 func (group *RouterGroup) POST(relativePath string, handlers ...HandlerFunc) IRoutes {
112 return group.handle(http.MethodPost, relativePath, handlers)
113 }
114
115
116 func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes {
117 return group.handle(http.MethodGet, relativePath, handlers)
118 }
119
120
121 func (group *RouterGroup) DELETE(relativePath string, handlers ...HandlerFunc) IRoutes {
122 return group.handle(http.MethodDelete, relativePath, handlers)
123 }
124
125
126 func (group *RouterGroup) PATCH(relativePath string, handlers ...HandlerFunc) IRoutes {
127 return group.handle(http.MethodPatch, relativePath, handlers)
128 }
129
130
131 func (group *RouterGroup) PUT(relativePath string, handlers ...HandlerFunc) IRoutes {
132 return group.handle(http.MethodPut, relativePath, handlers)
133 }
134
135
136 func (group *RouterGroup) OPTIONS(relativePath string, handlers ...HandlerFunc) IRoutes {
137 return group.handle(http.MethodOptions, relativePath, handlers)
138 }
139
140
141 func (group *RouterGroup) HEAD(relativePath string, handlers ...HandlerFunc) IRoutes {
142 return group.handle(http.MethodHead, relativePath, handlers)
143 }
144
145
146
147 func (group *RouterGroup) Any(relativePath string, handlers ...HandlerFunc) IRoutes {
148 for _, method := range anyMethods {
149 group.handle(method, relativePath, handlers)
150 }
151
152 return group.returnObj()
153 }
154
155
156 func (group *RouterGroup) Match(methods []string, relativePath string, handlers ...HandlerFunc) IRoutes {
157 for _, method := range methods {
158 group.handle(method, relativePath, handlers)
159 }
160
161 return group.returnObj()
162 }
163
164
165
166 func (group *RouterGroup) StaticFile(relativePath, filepath string) IRoutes {
167 return group.staticFileHandler(relativePath, func(c *Context) {
168 c.File(filepath)
169 })
170 }
171
172
173
174
175 func (group *RouterGroup) StaticFileFS(relativePath, filepath string, fs http.FileSystem) IRoutes {
176 return group.staticFileHandler(relativePath, func(c *Context) {
177 c.FileFromFS(filepath, fs)
178 })
179 }
180
181 func (group *RouterGroup) staticFileHandler(relativePath string, handler HandlerFunc) IRoutes {
182 if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
183 panic("URL parameters can not be used when serving a static file")
184 }
185 group.GET(relativePath, handler)
186 group.HEAD(relativePath, handler)
187 return group.returnObj()
188 }
189
190
191
192
193
194
195
196
197 func (group *RouterGroup) Static(relativePath, root string) IRoutes {
198 return group.StaticFS(relativePath, Dir(root, false))
199 }
200
201
202
203 func (group *RouterGroup) StaticFS(relativePath string, fs http.FileSystem) IRoutes {
204 if strings.Contains(relativePath, ":") || strings.Contains(relativePath, "*") {
205 panic("URL parameters can not be used when serving a static folder")
206 }
207 handler := group.createStaticHandler(relativePath, fs)
208 urlPattern := path.Join(relativePath, "/*filepath")
209
210
211 group.GET(urlPattern, handler)
212 group.HEAD(urlPattern, handler)
213 return group.returnObj()
214 }
215
216 func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileSystem) HandlerFunc {
217 absolutePath := group.calculateAbsolutePath(relativePath)
218 fileServer := http.StripPrefix(absolutePath, http.FileServer(fs))
219
220 return func(c *Context) {
221 if _, noListing := fs.(*onlyFilesFS); noListing {
222 c.Writer.WriteHeader(http.StatusNotFound)
223 }
224
225 file := c.Param("filepath")
226
227 f, err := fs.Open(file)
228 if err != nil {
229 c.Writer.WriteHeader(http.StatusNotFound)
230 c.handlers = group.engine.noRoute
231
232 c.index = -1
233 return
234 }
235 f.Close()
236
237 fileServer.ServeHTTP(c.Writer, c.Request)
238 }
239 }
240
241 func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain {
242 finalSize := len(group.Handlers) + len(handlers)
243 assert1(finalSize < int(abortIndex), "too many handlers")
244 mergedHandlers := make(HandlersChain, finalSize)
245 copy(mergedHandlers, group.Handlers)
246 copy(mergedHandlers[len(group.Handlers):], handlers)
247 return mergedHandlers
248 }
249
250 func (group *RouterGroup) calculateAbsolutePath(relativePath string) string {
251 return joinPaths(group.basePath, relativePath)
252 }
253
254 func (group *RouterGroup) returnObj() IRoutes {
255 if group.root {
256 return group.engine
257 }
258 return group
259 }
260
View as plain text