Skip to content

Different pnames on one route support #1430

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 86 additions & 16 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ type (
parent *node
children children
ppath string
pnames []string
pnames pnamesT
methodHandler *methodHandler
}
kind uint8
children []*node
kind uint8
children []*node
methodHandler struct {
connect HandlerFunc
delete HandlerFunc
Expand All @@ -35,6 +35,19 @@ type (
trace HandlerFunc
report HandlerFunc
}
pnamesT struct {
connect []string
delete []string
get []string
head []string
options []string
patch []string
post []string
propfind []string
put []string
trace []string
report []string
}
)

const (
Expand Down Expand Up @@ -127,7 +140,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
cn.kind = t
cn.addHandler(method, h)
cn.ppath = ppath
cn.pnames = pnames
cn.setPNames(method, pnames)
}
} else if l < pl {
// Split node
Expand All @@ -140,7 +153,7 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
cn.children = nil
cn.methodHandler = new(methodHandler)
cn.ppath = ""
cn.pnames = nil
cn.setPNames(method, nil)

cn.addChild(n)

Expand All @@ -149,11 +162,12 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
cn.kind = t
cn.addHandler(method, h)
cn.ppath = ppath
cn.pnames = pnames
cn.setPNames(method, pnames)
} else {
// Create child node
n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnames)
n = newNode(t, search[l:], cn, nil, new(methodHandler), ppath, pnamesT{})
n.addHandler(method, h)
n.setPNames(method, pnames)
cn.addChild(n)
}
} else if l < sl {
Expand All @@ -165,24 +179,25 @@ func (r *Router) insert(method, path string, h HandlerFunc, t kind, ppath string
continue
}
// Create child node
n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnames)
n := newNode(t, search, cn, nil, new(methodHandler), ppath, pnamesT{})
n.addHandler(method, h)
n.setPNames(method, pnames)
cn.addChild(n)
} else {
// Node already exists
if h != nil {
cn.addHandler(method, h)
cn.ppath = ppath
if len(cn.pnames) == 0 { // Issue #729
cn.pnames = pnames
if len(cn.findPNames(method)) == 0 { // Issue #729
cn.setPNames(method, pnames)
}
}
}
return
}
}

func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames []string) *node {
func newNode(t kind, pre string, p *node, c children, mh *methodHandler, ppath string, pnames pnamesT) *node {
return &node{
kind: t,
label: pre[0],
Expand Down Expand Up @@ -282,6 +297,62 @@ func (n *node) findHandler(method string) HandlerFunc {
}
}

func (n *node) findPNames(method string) []string {
switch method {
case http.MethodConnect:
return n.pnames.connect
case http.MethodDelete:
return n.pnames.delete
case http.MethodGet:
return n.pnames.get
case http.MethodHead:
return n.pnames.head
case http.MethodOptions:
return n.pnames.options
case http.MethodPatch:
return n.pnames.patch
case http.MethodPost:
return n.pnames.post
case PROPFIND:
return n.pnames.propfind
case http.MethodPut:
return n.pnames.put
case http.MethodTrace:
return n.pnames.trace
case REPORT:
return n.pnames.report
default:
return nil
}
}

func (n *node) setPNames(method string, p []string) {
switch method {
case http.MethodConnect:
n.pnames.connect = p
case http.MethodDelete:
n.pnames.delete = p
case http.MethodGet:
n.pnames.get = p
case http.MethodHead:
n.pnames.head = p
case http.MethodOptions:
n.pnames.options = p
case http.MethodPatch:
n.pnames.patch = p
case http.MethodPost:
n.pnames.post = p
case PROPFIND:
n.pnames.propfind = p
case http.MethodPut:
n.pnames.put = p
case http.MethodTrace:
n.pnames.trace = p
case REPORT:
n.pnames.report = p
}
}

func (n *node) checkMethodNotAllowed() HandlerFunc {
for _, m := range methods {
if h := n.findHandler(m); h != nil {
Expand Down Expand Up @@ -336,7 +407,6 @@ func (r *Router) Find(method, path string, c Context) {
}
}


if l == pl {
// Continue search
search = search[l:]
Expand Down Expand Up @@ -412,13 +482,13 @@ func (r *Router) Find(method, path string, c Context) {
}
return // Not found
}
pvalues[len(cn.pnames)-1] = search
pvalues[len(cn.findPNames(method))-1] = search
break
}

ctx.handler = cn.findHandler(method)
ctx.path = cn.ppath
ctx.pnames = cn.pnames
ctx.pnames = cn.findPNames(method)

// NOTE: Slow zone...
if ctx.handler == nil {
Expand All @@ -435,8 +505,8 @@ func (r *Router) Find(method, path string, c Context) {
ctx.handler = cn.checkMethodNotAllowed()
}
ctx.path = cn.ppath
ctx.pnames = cn.pnames
pvalues[len(cn.pnames)-1] = ""
ctx.pnames = cn.findPNames(method)
pvalues[len(cn.findPNames(method))-1] = ""
}

return
Expand Down
2 changes: 1 addition & 1 deletion router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1003,7 +1003,7 @@ func BenchmarkRouterGooglePlusAPI(b *testing.B) {

func (n *node) printTree(pfx string, tail bool) {
p := prefix(tail, pfx, "└── ", "├── ")
fmt.Printf("%s%s, %p: type=%d, parent=%p, handler=%v, pnames=%v\n", p, n.prefix, n, n.kind, n.parent, n.methodHandler, n.pnames)
fmt.Printf("%s%s, %p: type=%d, parent=%p, handler=%v, pnames=%+v\n", p, n.prefix, n, n.kind, n.parent, n.methodHandler, n.pnames)

children := n.children
l := len(children)
Expand Down