Skip to content

Commit a3f3db5

Browse files
author
Sergio Andres Virviescas Santana
committed
feature #29 Add router.ANY()
1 parent c4e7c3c commit a3f3db5

File tree

7 files changed

+174
-85
lines changed

7 files changed

+174
-85
lines changed

radix/conts.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ const (
1313
param
1414
wildcard
1515
)
16+
17+
// MethodWild wild HTTP method
18+
const MethodWild = "*"

radix/node.go

Lines changed: 82 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func newNodeAndHandler(method, path string, lastSegment bool) (*node, *nodeHandl
4747

4848
// conflict raises a panic with some details
4949
func (n *nodeWildcard) conflict(path, fullPath string) {
50-
prefix := fullPath[:strings.Index(fullPath, path)] + n.path
50+
prefix := fullPath[:strings.LastIndex(fullPath, path)] + n.path
5151

5252
panicf(
5353
"'%s' in new path '%s' conflicts with existing wildcard '%s' in existing prefix '%s'",
@@ -58,7 +58,7 @@ func (n *nodeWildcard) conflict(path, fullPath string) {
5858
// wildPathConflict raises a panic with some details
5959
func (n *node) wildPathConflict(path, fullPath string) {
6060
pathSeg := strings.SplitN(path, "/", 2)[0]
61-
prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path
61+
prefix := fullPath[:strings.LastIndex(fullPath, path)] + n.path
6262

6363
panicf(
6464
"'%s' in new path '%s' conflicts with existing wildcard '%s' in existing prefix '%s'",
@@ -337,21 +337,25 @@ walk:
337337
continue walk
338338

339339
} else if path == child.path {
340-
nHandler := child.handlers[method]
341-
342-
switch {
343-
case nHandler == nil:
344-
return nil, false
345-
case nHandler.tsr:
346-
return nil, true
347-
case nHandler.handler != nil:
348-
return nHandler.handler, false
349-
case nHandler.wildcard != nil:
350-
if ctx != nil {
351-
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
352-
}
340+
methods := []string{method, MethodWild}
341+
342+
for i := range methods {
343+
nHandler := child.handlers[methods[i]]
344+
345+
switch {
346+
case nHandler == nil:
347+
continue
348+
case nHandler.tsr:
349+
return nil, true
350+
case nHandler.handler != nil:
351+
return nHandler.handler, false
352+
case nHandler.wildcard != nil:
353+
if ctx != nil {
354+
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
355+
}
353356

354-
return nHandler.wildcard.handler, false
357+
return nHandler.wildcard.handler, false
358+
}
355359
}
356360
}
357361

@@ -381,20 +385,24 @@ walk:
381385
}
382386

383387
} else if len(path) == end {
384-
nHandler := child.handlers[method]
385-
386-
switch {
387-
case nHandler == nil:
388-
return nil, false
389-
case nHandler.tsr:
390-
return nil, true
391-
case ctx != nil:
392-
for i, key := range child.paramKeys {
393-
ctx.SetUserValue(key, values[i])
388+
methods := []string{method, MethodWild}
389+
390+
for i := range methods {
391+
nHandler := child.handlers[methods[i]]
392+
393+
switch {
394+
case nHandler == nil:
395+
continue
396+
case nHandler.tsr:
397+
return nil, true
398+
case ctx != nil:
399+
for i, key := range child.paramKeys {
400+
ctx.SetUserValue(key, values[i])
401+
}
394402
}
395-
}
396403

397-
return nHandler.handler, false
404+
return nHandler.handler, false
405+
}
398406
}
399407

400408
default:
@@ -403,10 +411,15 @@ walk:
403411
}
404412

405413
if n.handlers != nil {
406-
nHandler := n.handlers[method]
414+
methods := []string{method, MethodWild}
407415

408-
if nHandler != nil && nHandler.wildcard != nil {
409-
if ctx != nil {
416+
for i := range methods {
417+
nHandler := n.handlers[methods[i]]
418+
419+
switch {
420+
case nHandler == nil, nHandler.wildcard == nil:
421+
continue
422+
case ctx != nil:
410423
ctx.SetUserValue(nHandler.wildcard.paramKey, path)
411424
}
412425

@@ -435,24 +448,28 @@ func (n *node) find(method, path string, buf *bytebufferpool.ByteBuffer) (bool,
435448
bufferRemoveString(buf, n.path)
436449

437450
} else if strings.EqualFold(path, n.path) {
438-
nHandler := n.handlers[method]
439-
if nHandler == nil {
440-
return false, false
441-
}
451+
methods := []string{method, MethodWild}
442452

443-
buf.WriteString(n.path)
453+
for i := range methods {
454+
nHandler := n.handlers[methods[i]]
455+
if nHandler == nil {
456+
continue
457+
}
444458

445-
if nHandler.tsr {
446-
if n.path == "/" {
447-
bufferRemoveString(buf, n.path)
448-
} else {
449-
buf.WriteByte('/')
459+
buf.WriteString(n.path)
460+
461+
if nHandler.tsr {
462+
if n.path == "/" {
463+
bufferRemoveString(buf, n.path)
464+
} else {
465+
buf.WriteByte('/')
466+
}
467+
468+
return true, true
450469
}
451470

452-
return true, true
471+
return true, false
453472
}
454-
455-
return true, false
456473
}
457474

458475
return false, false
@@ -486,18 +503,22 @@ func (n *node) findFromChild(method, path string, buf *bytebufferpool.ByteBuffer
486503
}
487504

488505
} else if len(path) == end {
489-
nHandler := child.handlers[method]
490-
if nHandler == nil {
491-
return false, false
492-
}
506+
methods := []string{method, MethodWild}
493507

494-
if nHandler.tsr {
495-
buf.WriteByte('/')
508+
for i := range methods {
509+
nHandler := child.handlers[methods[i]]
510+
if nHandler == nil {
511+
continue
512+
}
496513

497-
return true, true
498-
}
514+
if nHandler.tsr {
515+
buf.WriteByte('/')
499516

500-
return true, false
517+
return true, true
518+
}
519+
520+
return true, false
521+
}
501522
}
502523

503524
bufferRemoveString(buf, path[:end])
@@ -508,12 +529,16 @@ func (n *node) findFromChild(method, path string, buf *bytebufferpool.ByteBuffer
508529
}
509530

510531
if n.handlers != nil {
511-
nHandler := n.handlers[method]
532+
methods := []string{method, MethodWild}
512533

513-
if nHandler != nil && nHandler.wildcard != nil {
514-
buf.WriteString(path)
534+
for i := range methods {
535+
nHandler := n.handlers[methods[i]]
515536

516-
return true, false
537+
if nHandler != nil && nHandler.wildcard != nil {
538+
buf.WriteString(path)
539+
540+
return true, false
541+
}
517542
}
518543
}
519544

radix/node_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ func TestTreeWildcardConflictEx(t *testing.T) {
715715
"/con{tact}",
716716
"/who/are/{you:*}",
717717
"/who/foo/hello",
718+
"/whose/{users}/{name}",
718719
"/{filepath:*}",
719720
"/{id}",
720721
}

radix/tree.go

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,35 +59,36 @@ func (t *Tree) Add(method, path string, handler fasthttp.RequestHandler) {
5959
// made if a handle exists with an extra (without the) trailing slash for the
6060
// given path.
6161
func (t *Tree) Get(method, path string, ctx *fasthttp.RequestCtx) (fasthttp.RequestHandler, bool) {
62-
n := t.root
63-
64-
if len(path) > len(n.path) {
65-
if path[:len(n.path)] != n.path {
62+
if len(path) > len(t.root.path) {
63+
if path[:len(t.root.path)] != t.root.path {
6664
return nil, false
6765
}
6866

69-
path = path[len(n.path):]
67+
path = path[len(t.root.path):]
7068

71-
return n.getFromChild(method, path, ctx)
69+
return t.root.getFromChild(method, path, ctx)
7270

73-
} else if path == n.path {
74-
nHandler := n.handlers[method]
71+
} else if path == t.root.path {
72+
methods := []string{method, MethodWild}
7573

76-
switch {
77-
case nHandler == nil:
78-
return nil, false
79-
case nHandler.tsr:
80-
return nil, true
81-
case nHandler.handler != nil:
82-
return nHandler.handler, false
83-
case nHandler.wildcard != nil:
84-
if ctx != nil {
85-
ctx.SetUserValue(nHandler.wildcard.paramKey, "/")
86-
}
74+
for i := range methods {
75+
nHandler := t.root.handlers[methods[i]]
8776

88-
return nHandler.wildcard.handler, false
89-
}
77+
switch {
78+
case nHandler == nil:
79+
continue
80+
case nHandler.tsr:
81+
return nil, true
82+
case nHandler.handler != nil:
83+
return nHandler.handler, false
84+
case nHandler.wildcard != nil:
85+
if ctx != nil {
86+
ctx.SetUserValue(nHandler.wildcard.paramKey, "/")
87+
}
9088

89+
return nHandler.wildcard.handler, false
90+
}
91+
}
9192
}
9293

9394
return nil, false

radix/tree_test.go

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ var httpMethods = []string{
2626
fasthttp.MethodConnect,
2727
fasthttp.MethodOptions,
2828
fasthttp.MethodTrace,
29+
MethodWild,
2930
}
3031

3132
func randomHTTPMethod() string {
@@ -208,19 +209,29 @@ func Test_Get(t *testing.T) {
208209
tree.Add(method, "/api", handler)
209210
tree.Add(method, "/api/users", handler)
210211

211-
testHandlerAndParams(t, tree, method, "/api/", nil, true, nil)
212+
reqMethod := method
213+
for reqMethod == MethodWild {
214+
reqMethod = randomHTTPMethod()
215+
}
216+
217+
testHandlerAndParams(t, tree, reqMethod, "/api/", nil, true, nil)
212218

213-
testHandlerAndParams(t, tree, method, "/a", nil, false, nil)
214-
testHandlerAndParams(t, tree, method, "/api/user", nil, false, nil)
219+
testHandlerAndParams(t, tree, reqMethod, "/a", nil, false, nil)
220+
testHandlerAndParams(t, tree, reqMethod, "/api/user", nil, false, nil)
215221
}
216222

217223
for _, method := range httpMethods {
218224
tree := New()
219225
tree.Add(method, "/api/", handler)
220226

221-
testHandlerAndParams(t, tree, method, "/api", nil, true, nil)
222-
testHandlerAndParams(t, tree, method, "/api/", handler, false, nil)
223-
testHandlerAndParams(t, tree, method, "/data", nil, false, nil)
227+
reqMethod := method
228+
for reqMethod == MethodWild {
229+
reqMethod = randomHTTPMethod()
230+
}
231+
232+
testHandlerAndParams(t, tree, reqMethod, "/api", nil, true, nil)
233+
testHandlerAndParams(t, tree, reqMethod, "/api/", handler, false, nil)
234+
testHandlerAndParams(t, tree, reqMethod, "/data", nil, false, nil)
224235
}
225236
}
226237

router.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import (
1616
"github.com/valyala/fasthttp"
1717
)
1818

19+
// MethodWild wild HTTP method
20+
const MethodWild = radix.MethodWild
21+
1922
var (
2023
defaultContentType = []byte("text/plain; charset=utf-8")
2124
questionMark = byte('?')
@@ -91,6 +94,13 @@ func (r *Router) DELETE(path string, handler fasthttp.RequestHandler) {
9194
r.Handle(fasthttp.MethodDelete, path, handler)
9295
}
9396

97+
// ANY is a shortcut for router.Handle(router.MethodWild, path, handler)
98+
//
99+
// WARNING: Use only for routes where the request method is not important
100+
func (r *Router) ANY(path string, handler fasthttp.RequestHandler) {
101+
r.Handle(MethodWild, path, handler)
102+
}
103+
94104
// Handle registers a new request handler with the given path and method.
95105
//
96106
// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut

0 commit comments

Comments
 (0)