mirror of
https://github.com/labstack/echo.git
synced 2025-02-03 13:11:39 +02:00
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
724e92fdca
commit
fefbfeb28c
26
router.go
26
router.go
@ -10,8 +10,9 @@ type (
|
|||||||
node struct {
|
node struct {
|
||||||
label byte
|
label byte
|
||||||
prefix string
|
prefix string
|
||||||
handler HandlerFunc
|
parent *node
|
||||||
edges edges
|
edges edges
|
||||||
|
handler HandlerFunc
|
||||||
echo *Echo
|
echo *Echo
|
||||||
}
|
}
|
||||||
edges []*node
|
edges []*node
|
||||||
@ -74,7 +75,7 @@ func (r *router) insert(method, path string, h HandlerFunc, echo *Echo) {
|
|||||||
}
|
}
|
||||||
} else if l < pl {
|
} else if l < pl {
|
||||||
// Split node
|
// Split node
|
||||||
n := newNode(cn.prefix[l:], cn.handler, cn.edges, cn.echo)
|
n := newNode(cn.prefix[l:], cn, cn.edges, cn.handler, cn.echo)
|
||||||
cn.edges = edges{n} // Add to parent
|
cn.edges = edges{n} // Add to parent
|
||||||
|
|
||||||
// Reset parent node
|
// Reset parent node
|
||||||
@ -89,7 +90,7 @@ func (r *router) insert(method, path string, h HandlerFunc, echo *Echo) {
|
|||||||
cn.echo = echo
|
cn.echo = echo
|
||||||
} else {
|
} else {
|
||||||
// Create child node
|
// Create child node
|
||||||
n = newNode(search[l:], h, edges{}, echo)
|
n = newNode(search[l:], cn, edges{}, h, echo)
|
||||||
cn.edges = append(cn.edges, n)
|
cn.edges = append(cn.edges, n)
|
||||||
}
|
}
|
||||||
} else if l < sl {
|
} else if l < sl {
|
||||||
@ -101,7 +102,7 @@ func (r *router) insert(method, path string, h HandlerFunc, echo *Echo) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Create child node
|
// Create child node
|
||||||
n := newNode(search, h, edges{}, echo)
|
n := newNode(search, cn, edges{}, h, echo)
|
||||||
cn.edges = append(cn.edges, n)
|
cn.edges = append(cn.edges, n)
|
||||||
} else {
|
} else {
|
||||||
// Node already exists
|
// Node already exists
|
||||||
@ -114,12 +115,13 @@ func (r *router) insert(method, path string, h HandlerFunc, echo *Echo) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNode(pfx string, h HandlerFunc, e edges, echo *Echo) (n *node) {
|
func newNode(pfx string, p *node, e edges, h HandlerFunc, echo *Echo) (n *node) {
|
||||||
n = &node{
|
n = &node{
|
||||||
label: pfx[0],
|
label: pfx[0],
|
||||||
prefix: pfx,
|
prefix: pfx,
|
||||||
handler: h,
|
parent: p,
|
||||||
edges: e,
|
edges: e,
|
||||||
|
handler: h,
|
||||||
echo: echo,
|
echo: echo,
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -152,6 +154,7 @@ func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *
|
|||||||
n := 0 // Param count
|
n := 0 // Param count
|
||||||
|
|
||||||
// Search order static > param > catch-all
|
// Search order static > param > catch-all
|
||||||
|
// TODO: do we need continue???
|
||||||
for {
|
for {
|
||||||
if search == "" || search == cn.prefix { // Fix me
|
if search == "" || search == cn.prefix { // Fix me
|
||||||
// Found
|
// Found
|
||||||
@ -174,15 +177,15 @@ func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Param node
|
// Param node
|
||||||
|
param:
|
||||||
e = cn.findEdge(':')
|
e = cn.findEdge(':')
|
||||||
if e != nil {
|
if e != nil {
|
||||||
cn = e
|
cn = e
|
||||||
i, l := 0, len(search)
|
i, l := 0, len(search)
|
||||||
for ; i < l && search[i] != '/'; i++ {
|
for ; i < l && search[i] != '/'; i++ {
|
||||||
}
|
}
|
||||||
p := params[:n+1]
|
params[n].Name = cn.prefix[1:]
|
||||||
p[n].Name = cn.prefix[1:]
|
params[n].Value = search[:i]
|
||||||
p[n].Value = search[:i]
|
|
||||||
n++
|
n++
|
||||||
search = search[i:]
|
search = search[i:]
|
||||||
continue
|
continue
|
||||||
@ -199,9 +202,14 @@ func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cn = cn.parent
|
||||||
|
if cn == nil {
|
||||||
// Not found
|
// Not found
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// Search backwards
|
||||||
|
goto param
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
155
router_test.go
155
router_test.go
@ -1,6 +1,7 @@
|
|||||||
package echo
|
package echo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
@ -280,91 +281,142 @@ var (
|
|||||||
|
|
||||||
func TestRouterStatic(t *testing.T) {
|
func TestRouterStatic(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/folders/files/echo.gif", func(*Context) {}, nil)
|
b := new(bytes.Buffer)
|
||||||
h, _ := r.Find(GET, "/folders/files/echo.gif", params)
|
path := "/folders/a/files/echo.gif"
|
||||||
|
r.Add(GET, path, func(*Context) {
|
||||||
|
b.WriteString(path)
|
||||||
|
}, nil)
|
||||||
|
h, _ := r.Find(GET, path, params)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Fatal("handle not found")
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
h(nil)
|
||||||
|
if b.String() != path {
|
||||||
|
t.Errorf("buffer should %s", path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterParam(t *testing.T) {
|
func TestRouterParam(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/users/:id", func(c *Context) {
|
r.Add(GET, "/users/:id", func(c *Context) {}, nil)
|
||||||
if c.P(0) != "1" {
|
|
||||||
t.Error("param id should be 1")
|
h, _ := r.Find(GET, "/users/1", params)
|
||||||
}
|
|
||||||
}, nil)
|
|
||||||
h, _ := r.Find(GET, "/users/1", make(Params, 5))
|
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Fatal("handle not found")
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != "1" {
|
||||||
|
t.Error("param id should be 1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterTwoParam(t *testing.T) {
|
func TestRouterTwoParam(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/users/:uid/files/:fid", func(c *Context) {
|
r.Add(GET, "/users/:uid/files/:fid", func(*Context) {}, nil)
|
||||||
if c.P(0) != "1" {
|
|
||||||
t.Error("param uid should be 1")
|
|
||||||
}
|
|
||||||
if c.P(1) != "1" {
|
|
||||||
t.Error("param fid should be 1")
|
|
||||||
}
|
|
||||||
}, nil)
|
|
||||||
h, _ := r.Find(GET, "/users/1/files/1", params)
|
h, _ := r.Find(GET, "/users/1/files/1", params)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Fatal("handle not found")
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != "1" {
|
||||||
|
t.Error("param uid should be 1")
|
||||||
|
}
|
||||||
|
if params[1].Value != "1" {
|
||||||
|
t.Error("param fid should be 1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterCatchAll(t *testing.T) {
|
func TestRouterCatchAll(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/static/*", func(*Context) {}, nil)
|
r.Add(GET, "/static/*", func(*Context) {}, nil)
|
||||||
h, _ := r.Find(GET, "/static/*", params)
|
h, _ := r.Find(GET, "/static/echo.gif", params)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Fatal("handle not found")
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != "echo.gif" {
|
||||||
|
t.Error("value should be echo.gif")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterMicroParam(t *testing.T) {
|
func TestRouterMicroParam(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/:a/:b/:c", func(c *Context) {
|
r.Add(GET, "/:a/:b/:c", func(c *Context) {}, nil)
|
||||||
if c.P(0) != "1" {
|
|
||||||
t.Error("param a should be 1")
|
|
||||||
}
|
|
||||||
if c.P(1) != "2" {
|
|
||||||
t.Error("param b should be 2")
|
|
||||||
}
|
|
||||||
if c.P(2) != "3" {
|
|
||||||
t.Error("param c should be 3")
|
|
||||||
}
|
|
||||||
}, nil)
|
|
||||||
h, _ := r.Find(GET, "/1/2/3", params)
|
h, _ := r.Find(GET, "/1/2/3", params)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Fatal("handle not found")
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != "1" {
|
||||||
|
t.Error("param a should be 1")
|
||||||
|
}
|
||||||
|
if params[1].Value != "2" {
|
||||||
|
t.Error("param b should be 2")
|
||||||
|
}
|
||||||
|
if params[2].Value != "3" {
|
||||||
|
t.Error("param c should be 3")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterConflict(t *testing.T) {
|
func TestRouterConflictingRoute(t *testing.T) {
|
||||||
r := New().Router
|
r := New().Router
|
||||||
r.Add(GET, "/new", func(*Context) {
|
b := new(bytes.Buffer)
|
||||||
println("/new")
|
path := "/new"
|
||||||
|
|
||||||
|
r.Add(GET, path, func(*Context) {
|
||||||
|
b.WriteString(path)
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/new/:id", func(*Context) {
|
h, _ := r.Find(GET, path, params)
|
||||||
println("/new/:id")
|
if h == nil {
|
||||||
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
h(nil)
|
||||||
|
if b.String() != path {
|
||||||
|
t.Errorf("buffer should be %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
name := "joe"
|
||||||
|
r.Add(GET, "/new/:id", func(c *Context) {}, nil)
|
||||||
|
h, _ = r.Find(GET, "/new/"+name, params)
|
||||||
|
if h == nil {
|
||||||
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != name {
|
||||||
|
t.Errorf("param id should be %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
path = "/new/name"
|
||||||
|
r.Add(GET, path, func(*Context) {
|
||||||
|
b.Reset()
|
||||||
|
b.WriteString(path)
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/new/name", func(*Context) {
|
h, _ = r.Find(GET, path, params)
|
||||||
println("/new/name")
|
if h == nil {
|
||||||
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
h(nil)
|
||||||
|
if b.String() != path {
|
||||||
|
t.Errorf("buffer should be %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.Add(GET, "/new/name/:id", func(c *Context) {}, nil)
|
||||||
|
h, _ = r.Find(GET, "/new/name/"+name, params)
|
||||||
|
if h == nil {
|
||||||
|
t.Fatal("handler not found")
|
||||||
|
}
|
||||||
|
if params[0].Value != name {
|
||||||
|
t.Errorf("param id should be %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
path = "/new/name/joe"
|
||||||
|
r.Add(GET, path, func(c *Context) {
|
||||||
|
b.Reset()
|
||||||
|
b.WriteString(path)
|
||||||
}, nil)
|
}, nil)
|
||||||
r.Add(GET, "/new/name/joe", func(*Context) {
|
h, _ = r.Find(GET, "/new/name/joe", params)
|
||||||
println("/new/name/joe")
|
if h == nil {
|
||||||
}, nil)
|
t.Fatal("handler not found")
|
||||||
r.Add(GET, "/new/name/:id", func(*Context) {
|
}
|
||||||
println("/new/name/:id")
|
h(nil)
|
||||||
}, nil)
|
if b.String() != path {
|
||||||
// h, _ := r.Find(GET, "/users/new", params)
|
t.Errorf("buffer should be %s", path)
|
||||||
// h(&Context{})
|
}
|
||||||
n := r.trees[GET]
|
|
||||||
n.printTree("", true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRouterAPI(t *testing.T) {
|
func TestRouterAPI(t *testing.T) {
|
||||||
@ -379,6 +431,7 @@ func TestRouterAPI(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
||||||
h, _ := r.Find(route.method, route.path, params)
|
h, _ := r.Find(route.method, route.path, params)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
t.Errorf("handler not found, method=%s, path=%s", route.method, route.path)
|
t.Errorf("handler not found, method=%s, path=%s", route.method, route.path)
|
||||||
@ -403,7 +456,7 @@ func TestRouterServeHTTP(t *testing.T) {
|
|||||||
|
|
||||||
func (n *node) printTree(pfx string, tail bool) {
|
func (n *node) printTree(pfx string, tail bool) {
|
||||||
p := prefix(tail, pfx, "└── ", "├── ")
|
p := prefix(tail, pfx, "└── ", "├── ")
|
||||||
fmt.Printf("%s%s has=%d, echo=%v\n", p, n.prefix, n.handler, n.echo)
|
fmt.Printf("%s%s, %p: parent=%p, handler=%v, echo=%v\n", p, n.prefix, n, n.parent, n.handler, n.echo)
|
||||||
|
|
||||||
nodes := n.edges
|
nodes := n.edges
|
||||||
l := len(nodes)
|
l := len(nodes)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user