mirror of
https://github.com/labstack/echo.git
synced 2025-11-29 22:48:07 +02:00
Allow different param names in different methods with same path scheme (#2209)
* Change methodHandler element type to methodContext Signed-off-by: ortyomka <iurin.art@gmail.com> * Allow different param names in the smae path with different methods Signed-off-by: ortyomka <iurin.art@gmail.com> * Rename methodContext to routeMethod Add paramsCount in each node for perfomance Signed-off-by: ortyomka <iurin.art@gmail.com> * Add backtracking to nearest path Signed-off-by: ortyomka <iurin.art@gmail.com> * Remove params from NotAllowed Signed-off-by: ortyomka <iurin.art@gmail.com>
This commit is contained in:
210
router.go
210
router.go
@@ -19,30 +19,35 @@ type (
|
|||||||
prefix string
|
prefix string
|
||||||
parent *node
|
parent *node
|
||||||
staticChildren children
|
staticChildren children
|
||||||
ppath string
|
originalPath string
|
||||||
pnames []string
|
methods *routeMethods
|
||||||
methodHandler *methodHandler
|
|
||||||
paramChild *node
|
paramChild *node
|
||||||
anyChild *node
|
anyChild *node
|
||||||
|
paramsCount int
|
||||||
// isLeaf indicates that node does not have child routes
|
// isLeaf indicates that node does not have child routes
|
||||||
isLeaf bool
|
isLeaf bool
|
||||||
// isHandler indicates that node has at least one handler registered to it
|
// isHandler indicates that node has at least one handler registered to it
|
||||||
isHandler bool
|
isHandler bool
|
||||||
}
|
}
|
||||||
kind uint8
|
kind uint8
|
||||||
children []*node
|
children []*node
|
||||||
methodHandler struct {
|
routeMethod struct {
|
||||||
connect HandlerFunc
|
ppath string
|
||||||
delete HandlerFunc
|
pnames []string
|
||||||
get HandlerFunc
|
handler HandlerFunc
|
||||||
head HandlerFunc
|
}
|
||||||
options HandlerFunc
|
routeMethods struct {
|
||||||
patch HandlerFunc
|
connect *routeMethod
|
||||||
post HandlerFunc
|
delete *routeMethod
|
||||||
propfind HandlerFunc
|
get *routeMethod
|
||||||
put HandlerFunc
|
head *routeMethod
|
||||||
trace HandlerFunc
|
options *routeMethod
|
||||||
report HandlerFunc
|
patch *routeMethod
|
||||||
|
post *routeMethod
|
||||||
|
propfind *routeMethod
|
||||||
|
put *routeMethod
|
||||||
|
trace *routeMethod
|
||||||
|
report *routeMethod
|
||||||
allowHeader string
|
allowHeader string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -56,7 +61,7 @@ const (
|
|||||||
anyLabel = byte('*')
|
anyLabel = byte('*')
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *methodHandler) isHandler() bool {
|
func (m *routeMethods) isHandler() bool {
|
||||||
return m.connect != nil ||
|
return m.connect != nil ||
|
||||||
m.delete != nil ||
|
m.delete != nil ||
|
||||||
m.get != nil ||
|
m.get != nil ||
|
||||||
@@ -70,7 +75,7 @@ func (m *methodHandler) isHandler() bool {
|
|||||||
m.report != nil
|
m.report != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *methodHandler) updateAllowHeader() {
|
func (m *routeMethods) updateAllowHeader() {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.WriteString(http.MethodOptions)
|
buf.WriteString(http.MethodOptions)
|
||||||
|
|
||||||
@@ -119,7 +124,7 @@ func (m *methodHandler) updateAllowHeader() {
|
|||||||
func NewRouter(e *Echo) *Router {
|
func NewRouter(e *Echo) *Router {
|
||||||
return &Router{
|
return &Router{
|
||||||
tree: &node{
|
tree: &node{
|
||||||
methodHandler: new(methodHandler),
|
methods: new(routeMethods),
|
||||||
},
|
},
|
||||||
routes: map[string]*Route{},
|
routes: map[string]*Route{},
|
||||||
echo: e,
|
echo: e,
|
||||||
@@ -153,7 +158,7 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
|||||||
}
|
}
|
||||||
j := i + 1
|
j := i + 1
|
||||||
|
|
||||||
r.insert(method, path[:i], nil, staticKind, "", nil)
|
r.insert(method, path[:i], staticKind, routeMethod{})
|
||||||
for ; i < lcpIndex && path[i] != '/'; i++ {
|
for ; i < lcpIndex && path[i] != '/'; i++ {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,23 +168,23 @@ func (r *Router) Add(method, path string, h HandlerFunc) {
|
|||||||
|
|
||||||
if i == lcpIndex {
|
if i == lcpIndex {
|
||||||
// path node is last fragment of route path. ie. `/users/:id`
|
// path node is last fragment of route path. ie. `/users/:id`
|
||||||
r.insert(method, path[:i], h, paramKind, ppath, pnames)
|
r.insert(method, path[:i], paramKind, routeMethod{ppath, pnames, h})
|
||||||
} else {
|
} else {
|
||||||
r.insert(method, path[:i], nil, paramKind, "", nil)
|
r.insert(method, path[:i], paramKind, routeMethod{})
|
||||||
}
|
}
|
||||||
} else if path[i] == '*' {
|
} else if path[i] == '*' {
|
||||||
r.insert(method, path[:i], nil, staticKind, "", nil)
|
r.insert(method, path[:i], staticKind, routeMethod{})
|
||||||
pnames = append(pnames, "*")
|
pnames = append(pnames, "*")
|
||||||
r.insert(method, path[:i+1], h, anyKind, ppath, pnames)
|
r.insert(method, path[:i+1], anyKind, routeMethod{ppath, pnames, h})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r.insert(method, path, h, staticKind, ppath, pnames)
|
r.insert(method, path, staticKind, routeMethod{ppath, pnames, h})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string, pnames []string) {
|
func (r *Router) insert(method, path string, t kind, rm routeMethod) {
|
||||||
// Adjust max param
|
// Adjust max param
|
||||||
paramLen := len(pnames)
|
paramLen := len(rm.pnames)
|
||||||
if *r.echo.maxParam < paramLen {
|
if *r.echo.maxParam < paramLen {
|
||||||
*r.echo.maxParam = paramLen
|
*r.echo.maxParam = paramLen
|
||||||
}
|
}
|
||||||
@@ -207,11 +212,11 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
// At root node
|
// At root node
|
||||||
currentNode.label = search[0]
|
currentNode.label = search[0]
|
||||||
currentNode.prefix = search
|
currentNode.prefix = search
|
||||||
if h != nil {
|
if rm.handler != nil {
|
||||||
currentNode.kind = t
|
currentNode.kind = t
|
||||||
currentNode.addHandler(method, h)
|
currentNode.addMethod(method, &rm)
|
||||||
currentNode.ppath = ppath
|
currentNode.paramsCount = len(rm.pnames)
|
||||||
currentNode.pnames = pnames
|
currentNode.originalPath = rm.ppath
|
||||||
}
|
}
|
||||||
currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
|
currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
|
||||||
} else if lcpLen < prefixLen {
|
} else if lcpLen < prefixLen {
|
||||||
@@ -221,9 +226,9 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
currentNode.prefix[lcpLen:],
|
currentNode.prefix[lcpLen:],
|
||||||
currentNode,
|
currentNode,
|
||||||
currentNode.staticChildren,
|
currentNode.staticChildren,
|
||||||
currentNode.methodHandler,
|
currentNode.originalPath,
|
||||||
currentNode.ppath,
|
currentNode.methods,
|
||||||
currentNode.pnames,
|
currentNode.paramsCount,
|
||||||
currentNode.paramChild,
|
currentNode.paramChild,
|
||||||
currentNode.anyChild,
|
currentNode.anyChild,
|
||||||
)
|
)
|
||||||
@@ -243,9 +248,9 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
currentNode.label = currentNode.prefix[0]
|
currentNode.label = currentNode.prefix[0]
|
||||||
currentNode.prefix = currentNode.prefix[:lcpLen]
|
currentNode.prefix = currentNode.prefix[:lcpLen]
|
||||||
currentNode.staticChildren = nil
|
currentNode.staticChildren = nil
|
||||||
currentNode.methodHandler = new(methodHandler)
|
currentNode.originalPath = ""
|
||||||
currentNode.ppath = ""
|
currentNode.methods = new(routeMethods)
|
||||||
currentNode.pnames = nil
|
currentNode.paramsCount = 0
|
||||||
currentNode.paramChild = nil
|
currentNode.paramChild = nil
|
||||||
currentNode.anyChild = nil
|
currentNode.anyChild = nil
|
||||||
currentNode.isLeaf = false
|
currentNode.isLeaf = false
|
||||||
@@ -257,13 +262,19 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
if lcpLen == searchLen {
|
if lcpLen == searchLen {
|
||||||
// At parent node
|
// At parent node
|
||||||
currentNode.kind = t
|
currentNode.kind = t
|
||||||
currentNode.addHandler(method, h)
|
if rm.handler != nil {
|
||||||
currentNode.ppath = ppath
|
currentNode.addMethod(method, &rm)
|
||||||
currentNode.pnames = pnames
|
currentNode.paramsCount = len(rm.pnames)
|
||||||
|
currentNode.originalPath = rm.ppath
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create child node
|
// Create child node
|
||||||
n = newNode(t, search[lcpLen:], currentNode, nil, new(methodHandler), ppath, pnames, nil, nil)
|
n = newNode(t, search[lcpLen:], currentNode, nil, "", new(routeMethods), 0, nil, nil)
|
||||||
n.addHandler(method, h)
|
if rm.handler != nil {
|
||||||
|
n.addMethod(method, &rm)
|
||||||
|
n.paramsCount = len(rm.pnames)
|
||||||
|
n.originalPath = rm.ppath
|
||||||
|
}
|
||||||
// Only Static children could reach here
|
// Only Static children could reach here
|
||||||
currentNode.addStaticChild(n)
|
currentNode.addStaticChild(n)
|
||||||
}
|
}
|
||||||
@@ -277,8 +288,12 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Create child node
|
// Create child node
|
||||||
n := newNode(t, search, currentNode, nil, new(methodHandler), ppath, pnames, nil, nil)
|
n := newNode(t, search, currentNode, nil, rm.ppath, new(routeMethods), 0, nil, nil)
|
||||||
n.addHandler(method, h)
|
if rm.handler != nil {
|
||||||
|
n.addMethod(method, &rm)
|
||||||
|
n.paramsCount = len(rm.pnames)
|
||||||
|
}
|
||||||
|
|
||||||
switch t {
|
switch t {
|
||||||
case staticKind:
|
case staticKind:
|
||||||
currentNode.addStaticChild(n)
|
currentNode.addStaticChild(n)
|
||||||
@@ -290,28 +305,26 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
|
|||||||
currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
|
currentNode.isLeaf = currentNode.staticChildren == nil && currentNode.paramChild == nil && currentNode.anyChild == nil
|
||||||
} else {
|
} else {
|
||||||
// Node already exists
|
// Node already exists
|
||||||
if h != nil {
|
if rm.handler != nil {
|
||||||
currentNode.addHandler(method, h)
|
currentNode.addMethod(method, &rm)
|
||||||
currentNode.ppath = ppath
|
currentNode.paramsCount = len(rm.pnames)
|
||||||
if len(currentNode.pnames) == 0 { // Issue #729
|
currentNode.originalPath = rm.ppath
|
||||||
currentNode.pnames = pnames
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNode(t kind, pre string, p *node, sc children, mh *methodHandler, ppath string, pnames []string, paramChildren, anyChildren *node) *node {
|
func newNode(t kind, pre string, p *node, sc children, originalPath string, mh *routeMethods, paramsCount int, paramChildren, anyChildren *node) *node {
|
||||||
return &node{
|
return &node{
|
||||||
kind: t,
|
kind: t,
|
||||||
label: pre[0],
|
label: pre[0],
|
||||||
prefix: pre,
|
prefix: pre,
|
||||||
parent: p,
|
parent: p,
|
||||||
staticChildren: sc,
|
staticChildren: sc,
|
||||||
ppath: ppath,
|
originalPath: originalPath,
|
||||||
pnames: pnames,
|
methods: mh,
|
||||||
methodHandler: mh,
|
paramsCount: paramsCount,
|
||||||
paramChild: paramChildren,
|
paramChild: paramChildren,
|
||||||
anyChild: anyChildren,
|
anyChild: anyChildren,
|
||||||
isLeaf: sc == nil && paramChildren == nil && anyChildren == nil,
|
isLeaf: sc == nil && paramChildren == nil && anyChildren == nil,
|
||||||
@@ -345,64 +358,60 @@ func (n *node) findChildWithLabel(l byte) *node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) addHandler(method string, h HandlerFunc) {
|
func (n *node) addMethod(method string, h *routeMethod) {
|
||||||
switch method {
|
switch method {
|
||||||
case http.MethodConnect:
|
case http.MethodConnect:
|
||||||
n.methodHandler.connect = h
|
n.methods.connect = h
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
n.methodHandler.delete = h
|
n.methods.delete = h
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
n.methodHandler.get = h
|
n.methods.get = h
|
||||||
case http.MethodHead:
|
case http.MethodHead:
|
||||||
n.methodHandler.head = h
|
n.methods.head = h
|
||||||
case http.MethodOptions:
|
case http.MethodOptions:
|
||||||
n.methodHandler.options = h
|
n.methods.options = h
|
||||||
case http.MethodPatch:
|
case http.MethodPatch:
|
||||||
n.methodHandler.patch = h
|
n.methods.patch = h
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
n.methodHandler.post = h
|
n.methods.post = h
|
||||||
case PROPFIND:
|
case PROPFIND:
|
||||||
n.methodHandler.propfind = h
|
n.methods.propfind = h
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
n.methodHandler.put = h
|
n.methods.put = h
|
||||||
case http.MethodTrace:
|
case http.MethodTrace:
|
||||||
n.methodHandler.trace = h
|
n.methods.trace = h
|
||||||
case REPORT:
|
case REPORT:
|
||||||
n.methodHandler.report = h
|
n.methods.report = h
|
||||||
}
|
}
|
||||||
|
|
||||||
n.methodHandler.updateAllowHeader()
|
n.methods.updateAllowHeader()
|
||||||
if h != nil {
|
n.isHandler = true
|
||||||
n.isHandler = true
|
|
||||||
} else {
|
|
||||||
n.isHandler = n.methodHandler.isHandler()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *node) findHandler(method string) HandlerFunc {
|
func (n *node) findMethod(method string) *routeMethod {
|
||||||
switch method {
|
switch method {
|
||||||
case http.MethodConnect:
|
case http.MethodConnect:
|
||||||
return n.methodHandler.connect
|
return n.methods.connect
|
||||||
case http.MethodDelete:
|
case http.MethodDelete:
|
||||||
return n.methodHandler.delete
|
return n.methods.delete
|
||||||
case http.MethodGet:
|
case http.MethodGet:
|
||||||
return n.methodHandler.get
|
return n.methods.get
|
||||||
case http.MethodHead:
|
case http.MethodHead:
|
||||||
return n.methodHandler.head
|
return n.methods.head
|
||||||
case http.MethodOptions:
|
case http.MethodOptions:
|
||||||
return n.methodHandler.options
|
return n.methods.options
|
||||||
case http.MethodPatch:
|
case http.MethodPatch:
|
||||||
return n.methodHandler.patch
|
return n.methods.patch
|
||||||
case http.MethodPost:
|
case http.MethodPost:
|
||||||
return n.methodHandler.post
|
return n.methods.post
|
||||||
case PROPFIND:
|
case PROPFIND:
|
||||||
return n.methodHandler.propfind
|
return n.methods.propfind
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
return n.methodHandler.put
|
return n.methods.put
|
||||||
case http.MethodTrace:
|
case http.MethodTrace:
|
||||||
return n.methodHandler.trace
|
return n.methods.trace
|
||||||
case REPORT:
|
case REPORT:
|
||||||
return n.methodHandler.report
|
return n.methods.report
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -433,7 +442,7 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
previousBestMatchNode *node
|
previousBestMatchNode *node
|
||||||
matchedHandler HandlerFunc
|
matchedRouteMethod *routeMethod
|
||||||
// search stores the remaining path to check for match. By each iteration we move from start of path to end of the path
|
// search stores the remaining path to check for match. By each iteration we move from start of path to end of the path
|
||||||
// and search value gets shorter and shorter.
|
// and search value gets shorter and shorter.
|
||||||
search = path
|
search = path
|
||||||
@@ -529,8 +538,8 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
if previousBestMatchNode == nil {
|
if previousBestMatchNode == nil {
|
||||||
previousBestMatchNode = currentNode
|
previousBestMatchNode = currentNode
|
||||||
}
|
}
|
||||||
if h := currentNode.findHandler(method); h != nil {
|
if h := currentNode.findMethod(method); h != nil {
|
||||||
matchedHandler = h
|
matchedRouteMethod = h
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -569,7 +578,8 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
if child := currentNode.anyChild; child != nil {
|
if child := currentNode.anyChild; child != nil {
|
||||||
// If any node is found, use remaining path for paramValues
|
// If any node is found, use remaining path for paramValues
|
||||||
currentNode = child
|
currentNode = child
|
||||||
paramValues[len(currentNode.pnames)-1] = search
|
paramValues[currentNode.paramsCount-1] = search
|
||||||
|
|
||||||
// update indexes/search in case we need to backtrack when no handler match is found
|
// update indexes/search in case we need to backtrack when no handler match is found
|
||||||
paramIndex++
|
paramIndex++
|
||||||
searchIndex += +len(search)
|
searchIndex += +len(search)
|
||||||
@@ -580,8 +590,8 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
if previousBestMatchNode == nil {
|
if previousBestMatchNode == nil {
|
||||||
previousBestMatchNode = currentNode
|
previousBestMatchNode = currentNode
|
||||||
}
|
}
|
||||||
if h := currentNode.findHandler(method); h != nil {
|
if h := currentNode.findMethod(method); h != nil {
|
||||||
matchedHandler = h
|
matchedRouteMethod = h
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,22 +614,28 @@ func (r *Router) Find(method, path string, c Context) {
|
|||||||
return // nothing matched at all
|
return // nothing matched at all
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchedHandler != nil {
|
var rPath string
|
||||||
ctx.handler = matchedHandler
|
var rPNames []string
|
||||||
|
if matchedRouteMethod != nil {
|
||||||
|
ctx.handler = matchedRouteMethod.handler
|
||||||
|
rPath = matchedRouteMethod.ppath
|
||||||
|
rPNames = matchedRouteMethod.pnames
|
||||||
} else {
|
} else {
|
||||||
// use previous match as basis. although we have no matching handler we have path match.
|
// use previous match as basis. although we have no matching handler we have path match.
|
||||||
// so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404)
|
// so we can send http.StatusMethodNotAllowed (405) instead of http.StatusNotFound (404)
|
||||||
currentNode = previousBestMatchNode
|
currentNode = previousBestMatchNode
|
||||||
|
|
||||||
|
rPath = currentNode.originalPath
|
||||||
|
rPNames = nil // no params here
|
||||||
ctx.handler = NotFoundHandler
|
ctx.handler = NotFoundHandler
|
||||||
if currentNode.isHandler {
|
if currentNode.isHandler {
|
||||||
ctx.Set(ContextKeyHeaderAllow, currentNode.methodHandler.allowHeader)
|
ctx.Set(ContextKeyHeaderAllow, currentNode.methods.allowHeader)
|
||||||
ctx.handler = MethodNotAllowedHandler
|
ctx.handler = MethodNotAllowedHandler
|
||||||
if method == http.MethodOptions {
|
if method == http.MethodOptions {
|
||||||
ctx.handler = optionsMethodHandler(currentNode.methodHandler.allowHeader)
|
ctx.handler = optionsMethodHandler(currentNode.methods.allowHeader)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.path = currentNode.ppath
|
ctx.path = rPath
|
||||||
ctx.pnames = currentNode.pnames
|
ctx.pnames = rPNames
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2318,6 +2318,33 @@ func TestRouterPanicWhenParamNoRootOnlyChildsFailsFind(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Issue #1726
|
||||||
|
func TestRouterDifferentParamsInPath(t *testing.T) {
|
||||||
|
e := New()
|
||||||
|
r := e.router
|
||||||
|
r.Add(http.MethodPut, "/*", func(Context) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
r.Add(http.MethodPut, "/users/:vid/files/:gid", func(Context) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
r.Add(http.MethodGet, "/users/:uid/files/:fid", func(Context) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c := e.NewContext(nil, nil).(*context)
|
||||||
|
|
||||||
|
r.Find(http.MethodGet, "/users/1/files/2", c)
|
||||||
|
assert.Equal(t, "1", c.Param("uid"))
|
||||||
|
assert.Equal(t, "2", c.Param("fid"))
|
||||||
|
|
||||||
|
r.Find(http.MethodGet, "/users/1/shouldBacktrackToFirstAnyRouteAnd405", c)
|
||||||
|
assert.Equal(t, "/*", c.Path())
|
||||||
|
|
||||||
|
r.Find(http.MethodPut, "/users/3/files/4", c)
|
||||||
|
assert.Equal(t, "3", c.Param("vid"))
|
||||||
|
assert.Equal(t, "4", c.Param("gid"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestRouterHandleMethodOptions(t *testing.T) {
|
func TestRouterHandleMethodOptions(t *testing.T) {
|
||||||
e := New()
|
e := New()
|
||||||
r := e.router
|
r := e.router
|
||||||
@@ -2380,7 +2407,7 @@ func TestRouterHandleMethodOptions(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tc.expectStatus, rec.Code)
|
assert.Equal(t, tc.expectStatus, rec.Code)
|
||||||
}
|
}
|
||||||
assert.Equal(t, tc.expectAllowHeader, c.Response().Header().Get("Allow"))
|
assert.Equal(t, tc.expectAllowHeader, c.Response().Header().Get(HeaderAllow))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user