mirror of https://github.com/golang/go.git
net/http: represent multi wildcards properly
The routing tree used for matching ServeMux patterns used the key "*" to hold a child node for a multi-segment wildcard. The problem is that "*" is a valid path segment, which confused the matching algorithm: it would fetch the multi wildcard child when looking for the literal child for "*". Eschew clever encodings. Use a separate field in the node to represent the multi wildcard child. Fixes #67067. Change-Id: I300ca08b8628f5367626cf41979f6c238ed8c831 Reviewed-on: https://go-review.googlesource.com/c/go/+/582115 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
8509f6939c
commit
cf05873029
|
|
@ -1559,6 +1559,14 @@ func TestPathValue(t *testing.T) {
|
|||
"other": "there/is//more",
|
||||
},
|
||||
},
|
||||
{
|
||||
"/names/{name}/{other...}",
|
||||
"/names/n/*",
|
||||
map[string]string{
|
||||
"name": "n",
|
||||
"other": "*",
|
||||
},
|
||||
},
|
||||
} {
|
||||
mux := NewServeMux()
|
||||
mux.HandleFunc(test.pattern, func(w ResponseWriter, r *Request) {
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ type routingNode struct {
|
|||
// special children keys:
|
||||
// "/" trailing slash (resulting from {$})
|
||||
// "" single wildcard
|
||||
// "*" multi wildcard
|
||||
children mapping[string, *routingNode]
|
||||
multiChild *routingNode // child with multi wildcard
|
||||
emptyChild *routingNode // optimization: child with key ""
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +63,9 @@ func (n *routingNode) addSegments(segs []segment, p *pattern, h Handler) {
|
|||
if len(segs) != 1 {
|
||||
panic("multi wildcard not last")
|
||||
}
|
||||
n.addChild("*").set(p, h)
|
||||
c := &routingNode{}
|
||||
n.multiChild = c
|
||||
c.set(p, h)
|
||||
} else if seg.wild {
|
||||
n.addChild("").addSegments(segs[1:], p, h)
|
||||
} else {
|
||||
|
|
@ -185,7 +187,7 @@ func (n *routingNode) matchPath(path string, matches []string) (*routingNode, []
|
|||
}
|
||||
// Lastly, match the pattern (there can be at most one) that has a multi
|
||||
// wildcard in this position to the rest of the path.
|
||||
if c := n.findChild("*"); c != nil {
|
||||
if c := n.multiChild; c != nil {
|
||||
// Don't record a match for a nameless wildcard (which arises from a
|
||||
// trailing slash in the pattern).
|
||||
if c.pattern.lastSegment().s != "" {
|
||||
|
|
|
|||
|
|
@ -72,10 +72,10 @@ func TestRoutingAddPattern(t *testing.T) {
|
|||
"/a/b"
|
||||
"":
|
||||
"/a/b/{y}"
|
||||
"*":
|
||||
"/a/b/{x...}"
|
||||
"/":
|
||||
"/a/b/{$}"
|
||||
MULTI:
|
||||
"/a/b/{x...}"
|
||||
"g":
|
||||
"":
|
||||
"j":
|
||||
|
|
@ -172,6 +172,8 @@ func TestRoutingNodeMatch(t *testing.T) {
|
|||
"HEAD /headwins", nil},
|
||||
{"GET", "", "/path/to/file",
|
||||
"/path/{p...}", []string{"to/file"}},
|
||||
{"GET", "", "/path/*",
|
||||
"/path/{p...}", []string{"*"}},
|
||||
})
|
||||
|
||||
// A pattern ending in {$} should only match URLS with a trailing slash.
|
||||
|
|
@ -291,4 +293,9 @@ func (n *routingNode) print(w io.Writer, level int) {
|
|||
n, _ := n.children.find(k)
|
||||
n.print(w, level+1)
|
||||
}
|
||||
|
||||
if n.multiChild != nil {
|
||||
fmt.Fprintf(w, "%sMULTI:\n", indent)
|
||||
n.multiChild.print(w, level+1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue