mirror of
https://github.com/labstack/echo.git
synced 2024-12-24 20:14:31 +02:00
Not need of Echo.SetMaxParam
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
1a5e2935ea
commit
e7c1d5d9fb
@ -28,8 +28,7 @@ func NewContext(req *http.Request, res *Response, e *Echo) *Context {
|
||||
request: req,
|
||||
response: res,
|
||||
echo: e,
|
||||
pnames: make([]string, e.maxParam),
|
||||
pvalues: make([]string, e.maxParam),
|
||||
pvalues: make([]string, *e.maxParam),
|
||||
store: make(store),
|
||||
}
|
||||
}
|
||||
|
12
echo.go
12
echo.go
@ -25,7 +25,7 @@ type (
|
||||
prefix string
|
||||
middleware []MiddlewareFunc
|
||||
http2 bool
|
||||
maxParam byte
|
||||
maxParam *int
|
||||
notFoundHandler HandlerFunc
|
||||
defaultHTTPErrorHandler HTTPErrorHandler
|
||||
httpErrorHandler HTTPErrorHandler
|
||||
@ -141,8 +141,7 @@ var (
|
||||
|
||||
// New creates an Echo instance.
|
||||
func New() (e *Echo) {
|
||||
e = &Echo{}
|
||||
e.router = NewRouter(e)
|
||||
e = &Echo{maxParam: new(int), router: NewRouter(e)}
|
||||
e.pool.New = func() interface{} {
|
||||
return NewContext(nil, new(Response), e)
|
||||
}
|
||||
@ -152,7 +151,6 @@ func New() (e *Echo) {
|
||||
//----------
|
||||
|
||||
e.HTTP2(true)
|
||||
e.SetMaxParam(5)
|
||||
e.notFoundHandler = func(c *Context) error {
|
||||
return NewHTTPError(http.StatusNotFound)
|
||||
}
|
||||
@ -192,12 +190,6 @@ func (e *Echo) HTTP2(on bool) {
|
||||
e.http2 = on
|
||||
}
|
||||
|
||||
// SetMaxParam sets the maximum number of path parameters allowed for the application.
|
||||
// Default value is 5, good enough for many use cases.
|
||||
func (e *Echo) SetMaxParam(n uint8) {
|
||||
e.maxParam = n
|
||||
}
|
||||
|
||||
// DefaultHTTPErrorHandler invokes the default HTTP error handler.
|
||||
func (e *Echo) DefaultHTTPErrorHandler(err error, c *Context) {
|
||||
e.defaultHTTPErrorHandler(err, c)
|
||||
|
@ -41,13 +41,6 @@ func TestEcho(t *testing.T) {
|
||||
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
||||
}
|
||||
|
||||
// TODO: Improve me!
|
||||
func TestEchoMaxParam(t *testing.T) {
|
||||
e := New()
|
||||
e.SetMaxParam(8)
|
||||
assert.EqualValues(t, 8, e.maxParam)
|
||||
}
|
||||
|
||||
func TestEchoIndex(t *testing.T) {
|
||||
e := New()
|
||||
e.Index("examples/website/public/index.html")
|
||||
|
49
router.go
49
router.go
@ -4,9 +4,9 @@ import "net/http"
|
||||
|
||||
type (
|
||||
Router struct {
|
||||
trees map[string]*node
|
||||
routes []Route
|
||||
echo *Echo
|
||||
trees map[string]*node
|
||||
routes []Route
|
||||
echo *Echo
|
||||
}
|
||||
node struct {
|
||||
typ ntype
|
||||
@ -43,14 +43,14 @@ func NewRouter(e *Echo) (r *Router) {
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Router) Add(method, path string, h HandlerFunc, echo *Echo) {
|
||||
var pnames []string // Param names
|
||||
func (r *Router) Add(method, path string, h HandlerFunc, e *Echo) {
|
||||
pnames := []string{} // Param names
|
||||
|
||||
for i, l := 0, len(path); i < l; i++ {
|
||||
if path[i] == ':' {
|
||||
j := i + 1
|
||||
|
||||
r.insert(method, path[:i], nil, stype, nil, echo)
|
||||
r.insert(method, path[:i], nil, stype, nil, e)
|
||||
for ; i < l && path[i] != '/'; i++ {
|
||||
}
|
||||
|
||||
@ -59,21 +59,28 @@ func (r *Router) Add(method, path string, h HandlerFunc, echo *Echo) {
|
||||
i, l = j, len(path)
|
||||
|
||||
if i == l {
|
||||
r.insert(method, path[:i], h, ptype, pnames, echo)
|
||||
r.insert(method, path[:i], h, ptype, pnames, e)
|
||||
return
|
||||
}
|
||||
r.insert(method, path[:i], nil, ptype, pnames, echo)
|
||||
r.insert(method, path[:i], nil, ptype, pnames, e)
|
||||
} else if path[i] == '*' {
|
||||
r.insert(method, path[:i], nil, stype, nil, echo)
|
||||
r.insert(method, path[:i], nil, stype, nil, e)
|
||||
pnames = append(pnames, "_name")
|
||||
r.insert(method, path[:i+1], h, mtype, pnames, echo)
|
||||
r.insert(method, path[:i+1], h, mtype, pnames, e)
|
||||
return
|
||||
}
|
||||
}
|
||||
r.insert(method, path, h, stype, pnames, echo)
|
||||
|
||||
r.insert(method, path, h, stype, pnames, e)
|
||||
}
|
||||
|
||||
func (r *Router) insert(method, path string, h HandlerFunc, t ntype, pnames []string, echo *Echo) {
|
||||
func (r *Router) insert(method, path string, h HandlerFunc, t ntype, pnames []string, e *Echo) {
|
||||
// Adjust max param
|
||||
l := len(pnames)
|
||||
if *e.maxParam < l {
|
||||
*e.maxParam = l
|
||||
}
|
||||
|
||||
cn := r.trees[method] // Current node as root
|
||||
search := path
|
||||
|
||||
@ -90,7 +97,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t ntype, pnames []st
|
||||
cn.typ = t
|
||||
cn.handler = h
|
||||
cn.pnames = pnames
|
||||
cn.echo = echo
|
||||
cn.echo = e
|
||||
}
|
||||
} else if l < pl {
|
||||
// Split node
|
||||
@ -110,10 +117,10 @@ func (r *Router) insert(method, path string, h HandlerFunc, t ntype, pnames []st
|
||||
cn.typ = t
|
||||
cn.handler = h
|
||||
cn.pnames = pnames
|
||||
cn.echo = echo
|
||||
cn.echo = e
|
||||
} else {
|
||||
// Create child node
|
||||
n = newNode(t, search[l:], cn, nil, h, pnames, echo)
|
||||
n = newNode(t, search[l:], cn, nil, h, pnames, e)
|
||||
cn.children = append(cn.children, n)
|
||||
}
|
||||
} else if l < sl {
|
||||
@ -125,21 +132,21 @@ func (r *Router) insert(method, path string, h HandlerFunc, t ntype, pnames []st
|
||||
continue
|
||||
}
|
||||
// Create child node
|
||||
n := newNode(t, search, cn, nil, h, pnames, echo)
|
||||
n := newNode(t, search, cn, nil, h, pnames, e)
|
||||
cn.children = append(cn.children, n)
|
||||
} else {
|
||||
// Node already exists
|
||||
if h != nil {
|
||||
cn.handler = h
|
||||
cn.pnames = pnames
|
||||
cn.echo = echo
|
||||
cn.echo = e
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func newNode(t ntype, pre string, p *node, c children, h HandlerFunc, pnames []string, echo *Echo) *node {
|
||||
func newNode(t ntype, pre string, p *node, c children, h HandlerFunc, pnames []string, e *Echo) *node {
|
||||
return &node{
|
||||
typ: t,
|
||||
label: pre[0],
|
||||
@ -148,7 +155,7 @@ func newNode(t ntype, pre string, p *node, c children, h HandlerFunc, pnames []s
|
||||
children: c,
|
||||
handler: h,
|
||||
pnames: pnames,
|
||||
echo: echo,
|
||||
echo: e,
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,7 +207,7 @@ func lcp(a, b string) (i int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, echo *Echo) {
|
||||
func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, e *Echo) {
|
||||
cn := r.trees[method] // Current node as root
|
||||
search := path
|
||||
|
||||
@ -220,7 +227,7 @@ func (r *Router) Find(method, path string, ctx *Context) (h HandlerFunc, echo *E
|
||||
// Found
|
||||
ctx.pnames = cn.pnames
|
||||
h = cn.handler
|
||||
echo = cn.echo
|
||||
e = cn.echo
|
||||
return
|
||||
}
|
||||
|
||||
|
196
router_test.go
196
router_test.go
@ -10,7 +10,6 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
context = NewContext(nil, nil, New())
|
||||
api = []Route{
|
||||
// OAuth Authorizations
|
||||
{"GET", "/authorizations", nil},
|
||||
@ -276,230 +275,248 @@ var (
|
||||
)
|
||||
|
||||
func TestRouterStatic(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
path := "/folders/a/files/echo.gif"
|
||||
r.Add(GET, path, func(c *Context) error {
|
||||
c.Set("path", path)
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(GET, path, context)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
h, _ := r.Find(GET, path, c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, path, context.Get("path"))
|
||||
h(c)
|
||||
assert.Equal(t, path, c.Get("path"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterParam(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(GET, "/users/1", context)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
h, _ := r.Find(GET, "/users/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterTwoParam(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
|
||||
h, _ := r.Find(GET, "/users/1/files/1", context)
|
||||
h, _ := r.Find(GET, "/users/1/files/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "1", context.P(1))
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
assert.Equal(t, "1", c.P(1))
|
||||
}
|
||||
|
||||
h, _ = r.Find(GET, "/users/1", context)
|
||||
h, _ = r.Find(GET, "/users/1", c)
|
||||
assert.Nil(t, h)
|
||||
}
|
||||
|
||||
func TestRouterMatchAny(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
r.Add(GET, "/users/*", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
|
||||
h, _ := r.Find(GET, "/users/", context)
|
||||
h, _ := r.Find(GET, "/users/", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "", context.P(0))
|
||||
assert.Equal(t, "", c.P(0))
|
||||
}
|
||||
|
||||
h, _ = r.Find(GET, "/users/1", context)
|
||||
h, _ = r.Find(GET, "/users/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterMicroParam(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
r.Add(GET, "/:a/:b/:c", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(GET, "/1/2/3", context)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
h, _ := r.Find(GET, "/1/2/3", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "2", context.P(1))
|
||||
assert.Equal(t, "3", context.P(2))
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
assert.Equal(t, "2", c.P(1))
|
||||
assert.Equal(t, "3", c.P(2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterMultiRoute(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(c *Context) error {
|
||||
c.Set("path", "/users")
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
|
||||
// Route > /users
|
||||
h, _ := r.Find(GET, "/users", context)
|
||||
h, _ := r.Find(GET, "/users", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, "/users", context.Get("path"))
|
||||
h(c)
|
||||
assert.Equal(t, "/users", c.Get("path"))
|
||||
}
|
||||
|
||||
// Route > /users/:id
|
||||
h, _ = r.Find(GET, "/users/1", context)
|
||||
h, _ = r.Find(GET, "/users/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
}
|
||||
|
||||
// Route > /user
|
||||
h, _ = r.Find(GET, "/user", context)
|
||||
h, _ = r.Find(GET, "/user", c)
|
||||
assert.Nil(t, h)
|
||||
}
|
||||
|
||||
func TestRouterPriority(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(c *Context) error {
|
||||
c.Set("a", 1)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/new", func(c *Context) error {
|
||||
c.Set("b", 2)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
c.Set("c", 3)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/dew", func(c *Context) error {
|
||||
c.Set("d", 4)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/:id/files", func(c *Context) error {
|
||||
c.Set("e", 5)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/newsee", func(c *Context) error {
|
||||
c.Set("f", 6)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/*", func(c *Context) error {
|
||||
c.Set("g", 7)
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
|
||||
// Route > /users
|
||||
h, _ := r.Find(GET, "/users", context)
|
||||
h, _ := r.Find(GET, "/users", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 1, context.Get("a"))
|
||||
h(c)
|
||||
assert.Equal(t, 1, c.Get("a"))
|
||||
}
|
||||
|
||||
// Route > /users/new
|
||||
h, _ = r.Find(GET, "/users/new", context)
|
||||
h, _ = r.Find(GET, "/users/new", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 2, context.Get("b"))
|
||||
h(c)
|
||||
assert.Equal(t, 2, c.Get("b"))
|
||||
}
|
||||
|
||||
// Route > /users/:id
|
||||
h, _ = r.Find(GET, "/users/1", context)
|
||||
h, _ = r.Find(GET, "/users/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 3, context.Get("c"))
|
||||
h(c)
|
||||
assert.Equal(t, 3, c.Get("c"))
|
||||
}
|
||||
|
||||
// Route > /users/dew
|
||||
h, _ = r.Find(GET, "/users/dew", context)
|
||||
h, _ = r.Find(GET, "/users/dew", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 4, context.Get("d"))
|
||||
h(c)
|
||||
assert.Equal(t, 4, c.Get("d"))
|
||||
}
|
||||
|
||||
// Route > /users/:id/files
|
||||
h, _ = r.Find(GET, "/users/1/files", context)
|
||||
h, _ = r.Find(GET, "/users/1/files", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 5, context.Get("e"))
|
||||
h(c)
|
||||
assert.Equal(t, 5, c.Get("e"))
|
||||
}
|
||||
|
||||
// Route > /users/:id
|
||||
h, _ = r.Find(GET, "/users/news", context)
|
||||
h, _ = r.Find(GET, "/users/news", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 3, context.Get("c"))
|
||||
h(c)
|
||||
assert.Equal(t, 3, c.Get("c"))
|
||||
}
|
||||
|
||||
// Route > /users/*
|
||||
h, _ = r.Find(GET, "/users/joe/books", context)
|
||||
h, _ = r.Find(GET, "/users/joe/books", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, 7, context.Get("g"))
|
||||
h(c)
|
||||
assert.Equal(t, 7, c.Get("g"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterParamNames(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
|
||||
// Routes
|
||||
r.Add(GET, "/users", func(c *Context) error {
|
||||
c.Set("path", "/users")
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/:id", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
r.Add(GET, "/users/:uid/files/:fid", func(c *Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
c := NewContext(nil, nil, e)
|
||||
|
||||
// Route > /users
|
||||
h, _ := r.Find(GET, "/users", context)
|
||||
h, _ := r.Find(GET, "/users", c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
assert.Equal(t, "/users", context.Get("path"))
|
||||
h(c)
|
||||
assert.Equal(t, "/users", c.Get("path"))
|
||||
}
|
||||
|
||||
// Route > /users/:id
|
||||
h, _ = r.Find(GET, "/users/1", context)
|
||||
h, _ = r.Find(GET, "/users/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "id", context.pnames[0])
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "id", c.pnames[0])
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
}
|
||||
|
||||
// Route > /users/:uid/files/:fid
|
||||
h, _ = r.Find(GET, "/users/1/files/1", context)
|
||||
h, _ = r.Find(GET, "/users/1/files/1", c)
|
||||
if assert.NotNil(t, h) {
|
||||
assert.Equal(t, "uid", context.pnames[0])
|
||||
assert.Equal(t, "1", context.P(0))
|
||||
assert.Equal(t, "fid", context.pnames[1])
|
||||
assert.Equal(t, "1", context.P(1))
|
||||
assert.Equal(t, "uid", c.pnames[0])
|
||||
assert.Equal(t, "1", c.P(0))
|
||||
assert.Equal(t, "fid", c.pnames[1])
|
||||
assert.Equal(t, "1", c.P(1))
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterAPI(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
|
||||
for _, route := range api {
|
||||
r.Add(route.Method, route.Path, func(c *Context) error {
|
||||
for i, n := range c.pnames {
|
||||
@ -508,19 +525,24 @@ func TestRouterAPI(t *testing.T) {
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
h, _ := r.Find(route.Method, route.Path, context)
|
||||
}, e)
|
||||
}
|
||||
c := NewContext(nil, nil, e)
|
||||
for _, route := range api {
|
||||
h, _ := r.Find(route.Method, route.Path, c)
|
||||
if assert.NotNil(t, h) {
|
||||
h(context)
|
||||
h(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterServeHTTP(t *testing.T) {
|
||||
r := New().router
|
||||
e := New()
|
||||
r := e.router
|
||||
|
||||
r.Add(GET, "/users", func(*Context) error {
|
||||
return nil
|
||||
}, nil)
|
||||
}, e)
|
||||
|
||||
// OK
|
||||
req, _ := http.NewRequest(GET, "/users", nil)
|
||||
|
@ -27,14 +27,6 @@ Specific version of Echo can be installed using any [package manager](https://gi
|
||||
|
||||
## Customization
|
||||
|
||||
### Max path parameters
|
||||
|
||||
`Echo.SetMaxParam(n uint8)`
|
||||
|
||||
Sets the maximum number of path parameters allowed for the application.
|
||||
Default value is **5**, [good enough](https://github.com/interagent/http-api-design#minimize-path-nesting)
|
||||
for many use cases. Restricting path parameters allows us to use memory efficiently.
|
||||
|
||||
### HTTP error handler
|
||||
|
||||
`Echo.SetHTTPErrorHandler(h HTTPErrorHandler)`
|
||||
|
Loading…
Reference in New Issue
Block a user