diff --git a/context.go b/context.go index 5dc7f8a0..df76c1cb 100644 --- a/context.go +++ b/context.go @@ -48,6 +48,7 @@ type Context struct { Params Params handlers HandlersChain index int8 + fullPath string engine *Engine @@ -70,6 +71,7 @@ func (c *Context) reset() { c.Params = c.Params[0:0] c.handlers = nil c.index = -1 + c.fullPath = "" c.Keys = nil c.Errors = c.Errors[0:0] c.Accepted = nil @@ -111,6 +113,15 @@ func (c *Context) Handler() HandlerFunc { return c.handlers.Last() } +// FullPath returns a matched route full path. For not found routes +// returns an empty string. +// router.GET("/user/:id", func(c *gin.Context) { +// c.FullPath() == "/user/:id" // true +// }) +func (c *Context) FullPath() string { + return c.fullPath +} + /************************************/ /*********** FLOW CONTROL ***********/ /************************************/ diff --git a/gin.go b/gin.go index 9fea8314..be08f010 100644 --- a/gin.go +++ b/gin.go @@ -252,6 +252,7 @@ func (engine *Engine) addRoute(method, path string, handlers HandlersChain) { root := engine.trees.get(method) if root == nil { root = new(node) + root.fullPath = "/" engine.trees = append(engine.trees, methodTree{method: method, root: root}) } root.addRoute(path, handlers) @@ -385,6 +386,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) { if value.handlers != nil { c.handlers = value.handlers c.Params = value.params + c.fullPath = value.fullPath c.Next() c.writermem.WriteHeaderNow() return diff --git a/routes_test.go b/routes_test.go index de363a8c..f0e259a5 100644 --- a/routes_test.go +++ b/routes_test.go @@ -522,3 +522,38 @@ func TestRouteServeErrorWithWriteHeader(t *testing.T) { assert.Equal(t, 421, w.Code) assert.Equal(t, 0, w.Body.Len()) } + +func TestRouteContextHoldsFullPath(t *testing.T) { + router := New() + + // Test routes + routes := []string{ + "/", + "/simple", + "/project/:name", + "/project/:name/build/*params", + } + + for _, route := range routes { + actualRoute := route + router.GET(route, func(c *Context) { + // For each defined route context should contain its full path + assert.Equal(t, actualRoute, c.FullPath()) + c.AbortWithStatus(http.StatusOK) + }) + } + + for _, route := range routes { + w := performRequest(router, "GET", route) + assert.Equal(t, http.StatusOK, w.Code) + } + + // Test not found + router.Use(func(c *Context) { + // For not found routes full path is empty + assert.Equal(t, "", c.FullPath()) + }) + + w := performRequest(router, "GET", "/not-found") + assert.Equal(t, http.StatusNotFound, w.Code) +} diff --git a/tree.go b/tree.go index 607444ec..b9e272f9 100644 --- a/tree.go +++ b/tree.go @@ -94,6 +94,7 @@ type node struct { nType nodeType maxParams uint8 wildChild bool + fullPath string } // increments priority of the given child and reorders if necessary. @@ -154,6 +155,7 @@ func (n *node) addRoute(path string, handlers HandlersChain) { children: n.children, handlers: n.handlers, priority: n.priority - 1, + fullPath: fullPath, } // Update maxParams (max of all children) @@ -229,6 +231,7 @@ func (n *node) addRoute(path string, handlers HandlersChain) { n.indices += string([]byte{c}) child := &node{ maxParams: numParams, + fullPath: fullPath, } n.children = append(n.children, child) n.incrementChildPrio(len(n.indices) - 1) @@ -296,6 +299,7 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle child := &node{ nType: param, maxParams: numParams, + fullPath: fullPath, } n.children = []*node{child} n.wildChild = true @@ -312,6 +316,7 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle child := &node{ maxParams: numParams, priority: 1, + fullPath: fullPath, } n.children = []*node{child} n = child @@ -339,6 +344,7 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle wildChild: true, nType: catchAll, maxParams: 1, + fullPath: fullPath, } n.children = []*node{child} n.indices = string(path[i]) @@ -352,6 +358,7 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle maxParams: 1, handlers: handlers, priority: 1, + fullPath: fullPath, } n.children = []*node{child} @@ -364,10 +371,12 @@ func (n *node) insertChild(numParams uint8, path string, fullPath string, handle n.handlers = handlers } +// nodeValue holds return values of (*Node).getValue method type nodeValue struct { handlers HandlersChain params Params tsr bool + fullPath string } // getValue returns the handle registered with the given path (key). The values of @@ -442,6 +451,7 @@ walk: // Outer loop for walking the tree } if value.handlers = n.handlers; value.handlers != nil { + value.fullPath = n.fullPath return } if len(n.children) == 1 { @@ -471,6 +481,7 @@ walk: // Outer loop for walking the tree } value.handlers = n.handlers + value.fullPath = n.fullPath return default: @@ -481,6 +492,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 value.handlers = n.handlers; value.handlers != nil { + value.fullPath = n.fullPath return }