Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get matched route from context #1390

Closed
wants to merge 12 commits into from
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
- [http2 server push](#http2-server-push)
- [Define format for the log of routes](#define-format-for-the-log-of-routes)
- [Set and get a cookie](#set-and-get-a-cookie)
- [Route in context](#route-in-context)
- [Testing](#testing)
- [Users](#users)

Expand Down Expand Up @@ -1910,6 +1911,26 @@ func main() {
}
```

### Route in context

```go
package main

import (
"log"

"github.com/gin-gonic/gin"
)

func main() {
router := gin.Default()
router.GET("/user/:id", func(c *gin.Context) {
log.Println(c.Route) // /user/:id
log.Println(c.Request.URL.Path) // /user/abc
})
router.Run()
}
```

## Testing

Expand Down
2 changes: 2 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Context struct {
Request *http.Request
Writer ResponseWriter

Route string
Params Params
handlers HandlersChain
index int8
Expand All @@ -65,6 +66,7 @@ type Context struct {

func (c *Context) reset() {
c.Writer = &c.writermem
c.Route = ""
c.Params = c.Params[0:0]
c.handlers = nil
c.index = -1
Expand Down
5 changes: 3 additions & 2 deletions gin.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,10 +358,11 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
}
root := t[i].root
// Find route in tree
handlers, params, tsr := root.getValue(path, c.Params, unescape)
handlers, params, route, tsr := root.getValue(path, c.Params, unescape)
if handlers != nil {
c.handlers = handlers
c.Params = params
c.Route = route
c.Next()
c.writermem.WriteHeaderNow()
return
Expand All @@ -383,7 +384,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
if tree.method == httpMethod {
continue
}
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
if handlers, _, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
c.handlers = engine.allNoMethod
serveError(c, http.StatusMethodNotAllowed, default405Body)
return
Expand Down
39 changes: 39 additions & 0 deletions gin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,3 +483,42 @@ func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo)

func handlerTest1(c *Context) {}
func handlerTest2(c *Context) {}

func TestRegistredRouteInContext(t *testing.T) {
tt := []struct {
Route string
Paths []string
}{
{"/", []string{"/"}},
{"/user", []string{"/user"}},
{"/user/:id", []string{"/user/123", "/user/abc"}},
{"/user/:id/profile/:p_id", []string{"/user/123/profile/123", "/user/abc/profile/abc"}},
}

r := New()
h := func(p string) HandlerFunc {
return func(c *Context) {
if p == c.Route {
c.JSON(http.StatusOK, H{"message": "route matched"})
return
}
c.JSON(http.StatusInternalServerError, H{
"message": "route missmatch",
"expected": p,
"found": c.Route,
})
}
}
for _, tc := range tt {
r.GET(tc.Route, h(tc.Route))
}

for _, tc := range tt {
for _, path := range tc.Paths {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", path, nil)
r.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code, w.Body.String())
}
}
}
7 changes: 6 additions & 1 deletion tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,13 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle
// If no handle can be found, a TSR (trailing slash redirect) recommendation is
// made if a handle exists with an extra (without the) trailing slash for the
// given path.
func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, tsr bool) {
func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, route string, tsr bool) {
p = po
walk: // Outer loop for walking the tree
for {
if len(path) > len(n.path) {
if path[:len(n.path)] == n.path {
route += n.path
path = path[len(n.path):]
// If this node does not have a wildcard (param or catchAll)
// child, we can just look up the next child node and continue
Expand Down Expand Up @@ -425,6 +426,7 @@ walk: // Outer loop for walking the tree
// we need to go deeper!
if end < len(path) {
if len(n.children) > 0 {
route += n.path
path = path[end:]
n = n.children[0]
continue walk
Expand All @@ -436,6 +438,7 @@ walk: // Outer loop for walking the tree
}

if handlers = n.handlers; handlers != nil {
route += n.path
return
}
if len(n.children) == 1 {
Expand Down Expand Up @@ -464,6 +467,7 @@ walk: // Outer loop for walking the tree
p[i].Value = path
}

route += n.path
handlers = n.handlers
return

Expand All @@ -475,6 +479,7 @@ walk: // Outer loop for walking the tree
// We should have reached the node containing the handle.
// Check if this node has a handle registered.
if handlers = n.handlers; handlers != nil {
route += n.path
return
}

Expand Down
11 changes: 7 additions & 4 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ..
}

for _, request := range requests {
handler, ps, _ := tree.getValue(request.path, nil, unescape)
handler, ps, route, _ := tree.getValue(request.path, nil, unescape)

if handler == nil {
if !request.nilHandler {
Expand All @@ -48,6 +48,9 @@ func checkRequests(t *testing.T, tree *node, requests testRequests, unescapes ..
if fakeHandlerValue != request.route {
t.Errorf("handle mismatch for route '%s': Wrong handle (%s != %s)", request.path, fakeHandlerValue, request.route)
}
if route != request.route {
t.Errorf("route mismatch for route '%s': Wrong route (%s != %s)", request.path, route, request.route)
}
lftk marked this conversation as resolved.
Show resolved Hide resolved
}

if !reflect.DeepEqual(ps, request.ps) {
Expand Down Expand Up @@ -454,7 +457,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/doc/",
}
for _, route := range tsrRoutes {
handler, _, tsr := tree.getValue(route, nil, false)
handler, _, _, tsr := tree.getValue(route, nil, false)
if handler != nil {
t.Fatalf("non-nil handler for TSR route '%s", route)
} else if !tsr {
Expand All @@ -471,7 +474,7 @@ func TestTreeTrailingSlashRedirect(t *testing.T) {
"/api/world/abc",
}
for _, route := range noTsrRoutes {
handler, _, tsr := tree.getValue(route, nil, false)
handler, _, _, tsr := tree.getValue(route, nil, false)
if handler != nil {
t.Fatalf("non-nil handler for No-TSR route '%s", route)
} else if tsr {
Expand All @@ -490,7 +493,7 @@ func TestTreeRootTrailingSlashRedirect(t *testing.T) {
t.Fatalf("panic inserting test route: %v", recv)
}

handler, _, tsr := tree.getValue("/", nil, false)
handler, _, _, tsr := tree.getValue("/", nil, false)
if handler != nil {
t.Fatalf("non-nil handler")
} else if tsr {
Expand Down