4
4
package web
5
5
6
6
import (
7
- "fmt"
8
7
"net/http"
9
8
"net/url"
10
9
"reflect"
11
- "regexp"
12
10
"strings"
13
11
14
- "code.gitea.io/gitea/modules/container"
15
12
"code.gitea.io/gitea/modules/htmlutil"
16
13
"code.gitea.io/gitea/modules/reqctx"
17
14
"code.gitea.io/gitea/modules/setting"
18
- "code.gitea.io/gitea/modules/util"
19
15
"code.gitea.io/gitea/modules/web/middleware"
20
16
21
17
"gitea.com/go-chi/binding"
@@ -45,7 +41,7 @@ func GetForm(dataStore reqctx.RequestDataStore) any {
45
41
46
42
// Router defines a route based on chi's router
47
43
type Router struct {
48
- chiRouter chi.Router
44
+ chiRouter * chi.Mux
49
45
curGroupPrefix string
50
46
curMiddlewares []any
51
47
}
@@ -97,16 +93,21 @@ func isNilOrFuncNil(v any) bool {
97
93
return r .Kind () == reflect .Func && r .IsNil ()
98
94
}
99
95
100
- func ( r * Router ) wrapMiddlewareAndHandler (h []any ) ([]func (http.Handler ) http.Handler , http.HandlerFunc ) {
101
- handlerProviders := make ([]func (http.Handler ) http.Handler , 0 , len (r . curMiddlewares )+ len (h )+ 1 )
102
- for _ , m := range r . curMiddlewares {
96
+ func wrapMiddlewareAndHandler (curMiddlewares , h []any ) ([]func (http.Handler ) http.Handler , http.HandlerFunc ) {
97
+ handlerProviders := make ([]func (http.Handler ) http.Handler , 0 , len (curMiddlewares )+ len (h )+ 1 )
98
+ for _ , m := range curMiddlewares {
103
99
if ! isNilOrFuncNil (m ) {
104
100
handlerProviders = append (handlerProviders , toHandlerProvider (m ))
105
101
}
106
102
}
107
- for _ , m := range h {
103
+ if len (h ) == 0 {
104
+ panic ("no endpoint handler provided" )
105
+ }
106
+ for i , m := range h {
108
107
if ! isNilOrFuncNil (m ) {
109
108
handlerProviders = append (handlerProviders , toHandlerProvider (m ))
109
+ } else if i == len (h )- 1 {
110
+ panic ("endpoint handler can't be nil" )
110
111
}
111
112
}
112
113
middlewares := handlerProviders [:len (handlerProviders )- 1 ]
@@ -121,7 +122,7 @@ func (r *Router) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Ha
121
122
// Methods adds the same handlers for multiple http "methods" (separated by ",").
122
123
// If any method is invalid, the lower level router will panic.
123
124
func (r * Router ) Methods (methods , pattern string , h ... any ) {
124
- middlewares , handlerFunc := r . wrapMiddlewareAndHandler (h )
125
+ middlewares , handlerFunc := wrapMiddlewareAndHandler (r . curMiddlewares , h )
125
126
fullPattern := r .getPattern (pattern )
126
127
if strings .Contains (methods , "," ) {
127
128
methods := strings .Split (methods , "," )
@@ -141,7 +142,7 @@ func (r *Router) Mount(pattern string, subRouter *Router) {
141
142
142
143
// Any delegate requests for all methods
143
144
func (r * Router ) Any (pattern string , h ... any ) {
144
- middlewares , handlerFunc := r . wrapMiddlewareAndHandler (h )
145
+ middlewares , handlerFunc := wrapMiddlewareAndHandler (r . curMiddlewares , h )
145
146
r .chiRouter .With (middlewares ... ).HandleFunc (r .getPattern (pattern ), handlerFunc )
146
147
}
147
148
@@ -185,17 +186,6 @@ func (r *Router) NotFound(h http.HandlerFunc) {
185
186
r .chiRouter .NotFound (h )
186
187
}
187
188
188
- type pathProcessorParam struct {
189
- name string
190
- captureGroup int
191
- }
192
-
193
- type PathProcessor struct {
194
- methods container.Set [string ]
195
- re * regexp.Regexp
196
- params []pathProcessorParam
197
- }
198
-
199
189
func (r * Router ) normalizeRequestPath (resp http.ResponseWriter , req * http.Request , next http.Handler ) {
200
190
normalized := false
201
191
normalizedPath := req .URL .EscapedPath ()
@@ -253,121 +243,16 @@ func (r *Router) normalizeRequestPath(resp http.ResponseWriter, req *http.Reques
253
243
next .ServeHTTP (resp , req )
254
244
}
255
245
256
- func (p * PathProcessor ) ProcessRequestPath (chiCtx * chi.Context , path string ) bool {
257
- if ! p .methods .Contains (chiCtx .RouteMethod ) {
258
- return false
259
- }
260
- if ! strings .HasPrefix (path , "/" ) {
261
- path = "/" + path
262
- }
263
- pathMatches := p .re .FindStringSubmatchIndex (path ) // Golang regexp match pairs [start, end, start, end, ...]
264
- if pathMatches == nil {
265
- return false
266
- }
267
- var paramMatches [][]int
268
- for i := 2 ; i < len (pathMatches ); {
269
- paramMatches = append (paramMatches , []int {pathMatches [i ], pathMatches [i + 1 ]})
270
- pmIdx := len (paramMatches ) - 1
271
- end := pathMatches [i + 1 ]
272
- i += 2
273
- for ; i < len (pathMatches ); i += 2 {
274
- if pathMatches [i ] >= end {
275
- break
276
- }
277
- paramMatches [pmIdx ] = append (paramMatches [pmIdx ], pathMatches [i ], pathMatches [i + 1 ])
278
- }
279
- }
280
- for i , pm := range paramMatches {
281
- groupIdx := p .params [i ].captureGroup * 2
282
- chiCtx .URLParams .Add (p .params [i ].name , path [pm [groupIdx ]:pm [groupIdx + 1 ]])
283
- }
284
- return true
285
- }
286
-
287
- func NewPathProcessor (methods , pattern string ) * PathProcessor {
288
- p := & PathProcessor {methods : make (container.Set [string ])}
289
- for _ , method := range strings .Split (methods , "," ) {
290
- p .methods .Add (strings .TrimSpace (method ))
291
- }
292
- re := []byte {'^' }
293
- lastEnd := 0
294
- for lastEnd < len (pattern ) {
295
- start := strings .IndexByte (pattern [lastEnd :], '<' )
296
- if start == - 1 {
297
- re = append (re , pattern [lastEnd :]... )
298
- break
299
- }
300
- end := strings .IndexByte (pattern [lastEnd + start :], '>' )
301
- if end == - 1 {
302
- panic (fmt .Sprintf ("invalid pattern: %s" , pattern ))
303
- }
304
- re = append (re , pattern [lastEnd :lastEnd + start ]... )
305
- partName , partExp , _ := strings .Cut (pattern [lastEnd + start + 1 :lastEnd + start + end ], ":" )
306
- lastEnd += start + end + 1
307
-
308
- // TODO: it could support to specify a "capture group" for the name, for example: "/<name[2]:(\d)-(\d)>"
309
- // it is not used so no need to implement it now
310
- param := pathProcessorParam {}
311
- if partExp == "*" {
312
- re = append (re , "(.*?)/?" ... )
313
- if lastEnd < len (pattern ) {
314
- if pattern [lastEnd ] == '/' {
315
- lastEnd ++
316
- }
317
- }
318
- } else {
319
- partExp = util .IfZero (partExp , "[^/]+" )
320
- re = append (re , '(' )
321
- re = append (re , partExp ... )
322
- re = append (re , ')' )
323
- }
324
- param .name = partName
325
- p .params = append (p .params , param )
326
- }
327
- re = append (re , '$' )
328
- reStr := string (re )
329
- p .re = regexp .MustCompile (reStr )
330
- return p
331
- }
332
-
333
246
// Combo delegates requests to Combo
334
247
func (r * Router ) Combo (pattern string , h ... any ) * Combo {
335
248
return & Combo {r , pattern , h }
336
249
}
337
250
338
- // Combo represents a tiny group routes with same pattern
339
- type Combo struct {
340
- r * Router
341
- pattern string
342
- h []any
343
- }
344
-
345
- // Get delegates Get method
346
- func (c * Combo ) Get (h ... any ) * Combo {
347
- c .r .Get (c .pattern , append (c .h , h ... )... )
348
- return c
349
- }
350
-
351
- // Post delegates Post method
352
- func (c * Combo ) Post (h ... any ) * Combo {
353
- c .r .Post (c .pattern , append (c .h , h ... )... )
354
- return c
355
- }
356
-
357
- // Delete delegates Delete method
358
- func (c * Combo ) Delete (h ... any ) * Combo {
359
- c .r .Delete (c .pattern , append (c .h , h ... )... )
360
- return c
361
- }
362
-
363
- // Put delegates Put method
364
- func (c * Combo ) Put (h ... any ) * Combo {
365
- c .r .Put (c .pattern , append (c .h , h ... )... )
366
- return c
367
- }
368
-
369
- // Patch delegates Patch method
370
- func (c * Combo ) Patch (h ... any ) * Combo {
371
- c .r .Patch (c .pattern , append (c .h , h ... )... )
372
- return c
251
+ // PathGroup creates a group of paths which could be matched by regexp.
252
+ // It is only designed to resolve some special cases which chi router can't handle.
253
+ // For most cases, it shouldn't be used because it needs to iterate all rules to find the matched one (inefficient).
254
+ func (r * Router ) PathGroup (pattern string , fn func (g * RouterPathGroup ), h ... any ) {
255
+ g := & RouterPathGroup {r : r , pathParam : "*" }
256
+ fn (g )
257
+ r .Any (pattern , append (h , g .ServeHTTP )... )
373
258
}
0 commit comments