Source File
routing_index.go
Belonging Package
net/http
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package http
import
// A routingIndex optimizes conflict detection by indexing patterns.
//
// The basic idea is to rule out patterns that cannot conflict with a given
// pattern because they have a different literal in a corresponding segment.
// See the comments in [routingIndex.possiblyConflictingPatterns] for more details.
type routingIndex struct {
// map from a particular segment position and value to all registered patterns
// with that value in that position.
// For example, the key {1, "b"} would hold the patterns "/a/b" and "/a/b/c"
// but not "/a", "b/a", "/a/c" or "/a/{x}".
segments map[routingIndexKey][]*pattern
// All patterns that end in a multi wildcard (including trailing slash).
// We do not try to be clever about indexing multi patterns, because there
// are unlikely to be many of them.
multis []*pattern
}
type routingIndexKey struct {
pos int // 0-based segment position
s string // literal, or empty for wildcard
}
func ( *routingIndex) ( *pattern) {
if .lastSegment().multi {
.multis = append(.multis, )
} else {
if .segments == nil {
.segments = map[routingIndexKey][]*pattern{}
}
for , := range .segments {
:= routingIndexKey{pos: , s: ""}
if !.wild {
.s = .s
}
.segments[] = append(.segments[], )
}
}
}
// possiblyConflictingPatterns calls f on all patterns that might conflict with
// pat. If f returns a non-nil error, possiblyConflictingPatterns returns immediately
// with that error.
//
// To be correct, possiblyConflictingPatterns must include all patterns that
// might conflict. But it may also include patterns that cannot conflict.
// For instance, an implementation that returns all registered patterns is correct.
// We use this fact throughout, simplifying the implementation by returning more
// patterns that we might need to.
func ( *routingIndex) ( *pattern, func(*pattern) error) ( error) {
// Terminology:
// dollar pattern: one ending in "{$}"
// multi pattern: one ending in a trailing slash or "{x...}" wildcard
// ordinary pattern: neither of the above
// apply f to all the pats, stopping on error.
:= func( []*pattern) error {
if != nil {
return
}
for , := range {
= ()
if != nil {
return
}
}
return nil
}
// Our simple indexing scheme doesn't try to prune multi patterns; assume
// any of them can match the argument.
if := (.multis); != nil {
return
}
if .lastSegment().s == "/" {
// All paths that a dollar pattern matches end in a slash; no paths that
// an ordinary pattern matches do. So only other dollar or multi
// patterns can conflict with a dollar pattern. Furthermore, conflicting
// dollar patterns must have the {$} in the same position.
return (.segments[routingIndexKey{s: "/", pos: len(.segments) - 1}])
}
// For ordinary and multi patterns, the only conflicts can be with a multi,
// or a pattern that has the same literal or a wildcard at some literal
// position.
// We could intersect all the possible matches at each position, but we
// do something simpler: we find the position with the fewest patterns.
var , []*pattern
:= math.MaxInt
:= false
for , := range .segments {
if .multi {
break
}
if !.wild {
= true
:= .segments[routingIndexKey{s: .s, pos: }]
:= .segments[routingIndexKey{s: "", pos: }]
if := len() + len(); < {
=
=
=
}
}
}
if {
()
()
return
}
// This pattern is all wildcards.
// Check it against everything.
for , := range .segments {
()
}
return
}
The pages are generated with Golds v0.7.3-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |