1
0
mirror of https://github.com/labstack/echo.git synced 2025-04-13 11:50:33 +02:00
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
Vishal Rana 2015-04-25 22:32:20 -07:00
parent 1a124f8aab
commit 2b87e75870
6 changed files with 86 additions and 88 deletions

View File

@ -11,7 +11,9 @@ type (
Context struct { Context struct {
Request *http.Request Request *http.Request
Response *response Response *response
params Params pnames []string
pvalues []string
pn int // Param count
store store store store
echo *Echo echo *Echo
} }
@ -19,15 +21,19 @@ type (
) )
// P returns path parameter by index. // P returns path parameter by index.
func (c *Context) P(i uint8) string { func (c *Context) P(i int) (value string) {
return c.params[i].Value if i <= c.pn {
value = c.pvalues[i]
}
return
} }
// Param returns path parameter by name. // Param returns path parameter by name.
func (c *Context) Param(name string) (value string) { func (c *Context) Param(name string) (value string) {
for _, p := range c.params { for i, n := range c.pnames {
if p.Name == name { if n == name && i <= c.pn {
value = p.Value value = c.pvalues[i]
break
} }
} }
return return

View File

@ -26,7 +26,7 @@ func TestContext(t *testing.T) {
c := &Context{ c := &Context{
Response: &response{Writer: httptest.NewRecorder()}, Response: &response{Writer: httptest.NewRecorder()},
Request: r, Request: r,
params: make(Params, 5), pvalues: make([]string, 5),
store: make(store), store: make(store),
echo: New(), echo: New(),
} }
@ -64,7 +64,8 @@ func TestContext(t *testing.T) {
//------- //-------
// By id // By id
c.params = Params{{"id", "1"}} c.pnames = []string{"id"}
c.pvalues = []string{"1"}
if c.P(0) != "1" { if c.P(0) != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }

View File

@ -110,7 +110,8 @@ func New() (e *Echo) {
e.pool.New = func() interface{} { e.pool.New = func() interface{} {
return &Context{ return &Context{
Response: &response{}, Response: &response{},
params: make(Params, e.maxParam), pnames: make([]string, e.maxParam),
pvalues: make([]string, e.maxParam),
store: make(store), store: make(store),
} }
} }
@ -118,6 +119,7 @@ func New() (e *Echo) {
//---------- //----------
// Defaults // Defaults
//---------- //----------
e.MaxParam(5) e.MaxParam(5)
e.NotFoundHandler(func(c *Context) { e.NotFoundHandler(func(c *Context) {
http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound) http.Error(c.Response, http.StatusText(http.StatusNotFound), http.StatusNotFound)
@ -289,7 +291,7 @@ func (e *Echo) Index(file string) {
func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (e *Echo) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c := e.pool.Get().(*Context) c := e.pool.Get().(*Context)
h, echo := e.Router.Find(r.Method, r.URL.Path, c.params) h, echo := e.Router.Find(r.Method, r.URL.Path, c)
if echo != nil { if echo != nil {
e = echo e = echo
} }

View File

@ -21,11 +21,6 @@ type (
} }
ntype uint8 ntype uint8
children []*node children []*node
param struct {
Name string
Value string
}
Params []param
) )
const ( const (
@ -204,20 +199,18 @@ func lcp(a, b string) (i int) {
return return
} }
func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *Echo) { func (r *router) Find(method, path string, c *Context) (h HandlerFunc, echo *Echo) {
cn := r.trees[method] // Current node as root cn := r.trees[method] // Current node as root
search := path search := path
n := 0 // Param count chn := new(node) // Child node
c := new(node) // Child node c.pn = 0 // Param count
// Search order static > param > catch-all // Search order static > param > catch-all
for { for {
if search == "" || search == cn.prefix { if search == "" || search == cn.prefix {
// Found // Found
h = cn.handler h = cn.handler
for i := 0; i < len(cn.pnames); i++ { c.pnames = cn.pnames
params[i].Name = cn.pnames[i]
}
echo = cn.echo echo = cn.echo
return return
} }
@ -232,33 +225,32 @@ func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *
} }
// Static node // Static node
c = cn.findSchild(search[0]) chn = cn.findSchild(search[0])
if c != nil { if chn != nil {
cn = c cn = chn
continue continue
} }
// Param node // Param node
Param: Param:
c = cn.findPchild() chn = cn.findPchild()
if c != nil { if chn != nil {
cn = c cn = chn
i, l := 0, len(search) i, l := 0, len(search)
for ; i < l && search[i] != '/'; i++ { for ; i < l && search[i] != '/'; i++ {
} }
params[n].Value = search[:i] c.pvalues[c.pn] = search[:i]
n++ c.pn++
search = search[i:] search = search[i:]
continue continue
} }
// Catch-all node // Catch-all node
c = cn.findCchild() chn = cn.findCchild()
if c != nil { if chn != nil {
cn = c cn = chn
p := params[:n+1] c.pnames[c.pn] = "_name"
p[n].Name = "_name" c.pvalues[c.pn] = search
p[n].Value = search
search = "" // End search search = "" // End search
continue continue
} }
@ -281,8 +273,8 @@ func (r *router) Find(method, path string, params Params) (h HandlerFunc, echo *
func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (r *router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
c := r.echo.pool.Get().(*Context) c := r.echo.pool.Get().(*Context)
h, _ := r.Find(req.Method, req.URL.Path, c.params) h, _ := r.Find(req.Method, req.URL.Path, c)
c.Response.Writer = w c.reset(w, req, nil)
if h != nil { if h != nil {
h(c) h(c)
} else { } else {

View File

@ -23,8 +23,8 @@ var (
) )
var ( var (
params = make(Params, 5) context = &Context{pvalues: make([]string, 5)}
api = []route{ api = []route{
// OAuth Authorizations // OAuth Authorizations
{"GET", "/authorizations"}, {"GET", "/authorizations"},
{"GET", "/authorizations/:id"}, {"GET", "/authorizations/:id"},
@ -296,7 +296,7 @@ func TestRouterStatic(t *testing.T) {
b.WriteString(path) b.WriteString(path)
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, path, params) h, _ := r.Find(GET, path, context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
@ -311,11 +311,11 @@ func TestRouterParam(t *testing.T) {
r.Add(GET, "/users/:id", func(c *Context) error { r.Add(GET, "/users/:id", func(c *Context) error {
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, "/users/1", params) h, _ := r.Find(GET, "/users/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
} }
@ -326,14 +326,14 @@ func TestRouterTwoParam(t *testing.T) {
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, "/users/1/files/1", params) h, _ := r.Find(GET, "/users/1/files/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param uid should be 1") t.Error("param uid should be 1")
} }
if params[1].Value != "1" { if context.pvalues[1] != "1" {
t.Error("param fid should be 1") t.Error("param fid should be 1")
} }
} }
@ -343,11 +343,11 @@ func TestRouterCatchAll(t *testing.T) {
r.Add(GET, "/static/*", func(*Context) error { r.Add(GET, "/static/*", func(*Context) error {
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, "/static/echo.gif", params) h, _ := r.Find(GET, "/static/echo.gif", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "echo.gif" { if context.pvalues[0] != "echo.gif" {
t.Error("value should be echo.gif") t.Error("value should be echo.gif")
} }
} }
@ -357,17 +357,17 @@ func TestRouterMicroParam(t *testing.T) {
r.Add(GET, "/:a/:b/:c", func(c *Context) error { r.Add(GET, "/:a/:b/:c", func(c *Context) error {
return nil return nil
}, nil) }, nil)
h, _ := r.Find(GET, "/1/2/3", params) h, _ := r.Find(GET, "/1/2/3", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param a should be 1") t.Error("param a should be 1")
} }
if params[1].Value != "2" { if context.pvalues[1] != "2" {
t.Error("param b should be 2") t.Error("param b should be 2")
} }
if params[2].Value != "3" { if context.pvalues[2] != "3" {
t.Error("param c should be 3") t.Error("param c should be 3")
} }
} }
@ -386,7 +386,7 @@ func TestRouterMultiRoute(t *testing.T) {
}, nil) }, nil)
// Route > /users // Route > /users
h, _ := r.Find(GET, "/users", params) h, _ := r.Find(GET, "/users", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
@ -396,16 +396,16 @@ func TestRouterMultiRoute(t *testing.T) {
} }
// Route > /users/:id > /users/1 // Route > /users/:id > /users/1
h, _ = r.Find(GET, "/users/1", params) h, _ = r.Find(GET, "/users/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
// Route > /user // Route > /user
h, _ = r.Find(GET, "/user", params) h, _ = r.Find(GET, "/user", context)
if h != nil { if h != nil {
t.Fatal("handler should be nil") t.Fatal("handler should be nil")
} }
@ -438,13 +438,13 @@ func TestRouterConflictingRoute(t *testing.T) {
}, nil) }, nil)
// Route > /users // Route > /users
h, _ := r.Find(GET, "/users", params) h, _ := r.Find(GET, "/users", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
// Route > /users/new // Route > /users/new
h, _ = r.Find(GET, "/users/new", params) h, _ = r.Find(GET, "/users/new", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
@ -454,29 +454,29 @@ func TestRouterConflictingRoute(t *testing.T) {
} }
// Route > /users/:id > /users/1 // Route > /users/:id > /users/1
h, _ = r.Find(GET, "/users/1", params) h, _ = r.Find(GET, "/users/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
// Route > /users/:id > /users/nil // Route > /users/:id > /users/nil
h, _ = r.Find(GET, "/users/nil", params) h, _ = r.Find(GET, "/users/nil", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "nil" { if context.pvalues[0] != "nil" {
t.Error("param id should be nil") t.Error("param id should be nil")
} }
// Route > /users/:id > /users/news // Route > /users/:id > /users/news
h, _ = r.Find(GET, "/users/news", params) h, _ = r.Find(GET, "/users/news", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "news" { if context.pvalues[0] != "news" {
t.Error("param id should be news") t.Error("param id should be news")
} }
@ -485,7 +485,7 @@ func TestRouterConflictingRoute(t *testing.T) {
//----------- //-----------
// Route > /users/new/moon > /users/new/moon // Route > /users/new/moon > /users/new/moon
h, _ = r.Find(GET, "/users/new/moon", params) h, _ = r.Find(GET, "/users/new/moon", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
@ -495,29 +495,29 @@ func TestRouterConflictingRoute(t *testing.T) {
} }
// Route > /users/new/:id > /users/new/1 // Route > /users/new/:id > /users/new/1
h, _ = r.Find(GET, "/users/new/1", params) h, _ = r.Find(GET, "/users/new/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
// Route > /users/new/:id > /users/new/me // Route > /users/new/:id > /users/new/me
h, _ = r.Find(GET, "/users/new/me", params) h, _ = r.Find(GET, "/users/new/me", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "me" { if context.pvalues[0] != "me" {
t.Error("param id should be me") t.Error("param id should be me")
} }
// Route > /users/new/:id > /users/new/moons // Route > /users/new/:id > /users/new/moons
h, _ = r.Find(GET, "/users/new/moons", params) h, _ = r.Find(GET, "/users/new/moons", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Value != "moons" { if context.pvalues[0] != "moons" {
t.Error("param id should be moons") t.Error("param id should be moons")
} }
} }
@ -539,7 +539,7 @@ func TestRouterParamNames(t *testing.T) {
}, nil) }, nil)
// Route > /users // Route > /users
h, _ := r.Find(GET, "/users", params) h, _ := r.Find(GET, "/users", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
@ -549,32 +549,32 @@ func TestRouterParamNames(t *testing.T) {
} }
// Route > /users/:id > /users/1 // Route > /users/:id > /users/1
h, _ = r.Find(GET, "/users/1", params) h, _ = r.Find(GET, "/users/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Name != "id" { if context.pnames[0] != "id" {
t.Error("param name should be id") t.Error("param name should be id")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
// Route > /users/:uid/files/:fid > /users/1/files/1 // Route > /users/:uid/files/:fid > /users/1/files/1
h, _ = r.Find(GET, "/users/1/files/1", params) h, _ = r.Find(GET, "/users/1/files/1", context)
if h == nil { if h == nil {
t.Fatal("handler not found") t.Fatal("handler not found")
} }
if params[0].Name != "uid" { if context.pnames[0] != "uid" {
t.Error("param name should be id") t.Error("param name should be id")
} }
if params[0].Value != "1" { if context.pvalues[0] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
if params[1].Name != "fid" { if context.pnames[1] != "fid" {
t.Error("param name should be id") t.Error("param name should be id")
} }
if params[1].Value != "1" { if context.pvalues[1] != "1" {
t.Error("param id should be 1") t.Error("param id should be 1")
} }
} }
@ -583,23 +583,20 @@ func TestRouterAPI(t *testing.T) {
r := New().Router r := New().Router
for _, route := range api { for _, route := range api {
r.Add(route.method, route.path, func(c *Context) error { r.Add(route.method, route.path, func(c *Context) error {
for _, p := range c.params { for i, n := range c.pnames {
if p.Name != "" { if n != "" {
if ":"+p.Name != p.Value { if ":"+n != c.pvalues[i] {
t.Errorf("param not found, method=%s, path=%s", route.method, route.path) t.Errorf("param not found, method=%s, path=%s", route.method, route.path)
} }
} }
} }
return nil return nil
}, nil) }, nil)
// Reset params h, _ := r.Find(route.method, route.path, context)
params = make(Params, 5)
c := &Context{params: params}
h, _ := r.Find(route.method, route.path, params)
if h == nil { if h == nil {
t.Fatalf("handler not found, method=%s, path=%s", route.method, route.path) t.Fatalf("handler not found, method=%s, path=%s", route.method, route.path)
} }
h(c) h(context)
} }
} }

View File

@ -10,7 +10,7 @@
Echo has been developed and tested using Go `1.4.x` Echo has been developed and tested using Go `1.4.x`
Install latest version of Echo via `go get` Install the latest version of Echo via `go get`
```sh ```sh
$ go get github.com/labstack/echo $ go get github.com/labstack/echo