-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroute.go
154 lines (131 loc) · 3.84 KB
/
route.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package fox
import (
"iter"
"strings"
)
// Annotations is a collection of Annotation key-value pairs that can be attached to routes.
type Annotations []Annotation
// Annotation represents a single key-value pair that provides metadata for a route.
// Annotations are typically used to store information that can be leveraged by middleware, handlers, or external
// libraries to modify or customize route behavior.
type Annotation struct {
Key string
Value any
}
// Route represent a registered route in the route tree.
// Most of the Route API is EXPERIMENTAL and is likely to change in future release.
type Route struct {
ipStrategy ClientIPStrategy
hbase HandlerFunc
hself HandlerFunc
hall HandlerFunc
path string
mws []middleware
annots Annotations
redirectTrailingSlash bool
ignoreTrailingSlash bool
}
// Handle calls the handler with the provided [Context]. See also [HandleMiddleware].
func (r *Route) Handle(c Context) {
r.hbase(c)
}
// HandleMiddleware calls the handler with route-specific middleware applied, using the provided [Context].
func (r *Route) HandleMiddleware(c Context, _ ...struct{}) {
// The variadic parameter is intentionally added to prevent this method from having the same signature as HandlerFunc.
// This avoids accidental use of HandleMiddleware where a HandlerFunc is required.
r.hself(c)
}
// Path returns the route path.
func (r *Route) Path() string {
return r.path
}
// Annotations returns a range iterator over annotations associated with the route.
func (r *Route) Annotations() iter.Seq[Annotation] {
return func(yield func(Annotation) bool) {
for _, a := range r.annots {
if !yield(a) {
return
}
}
}
}
// RedirectTrailingSlashEnabled returns whether the route is configured to automatically
// redirect requests that include or omit a trailing slash.
// This api is EXPERIMENTAL and is likely to change in future release.
func (r *Route) RedirectTrailingSlashEnabled() bool {
return r.redirectTrailingSlash
}
// IgnoreTrailingSlashEnabled returns whether the route is configured to ignore
// trailing slashes in requests when matching routes.
// This api is EXPERIMENTAL and is likely to change in future release.
func (r *Route) IgnoreTrailingSlashEnabled() bool {
return r.ignoreTrailingSlash
}
// ClientIPStrategyEnabled returns whether the route is configured with a [ClientIPStrategy].
// This api is EXPERIMENTAL and is likely to change in future release.
func (r *Route) ClientIPStrategyEnabled() bool {
_, ok := r.ipStrategy.(noClientIPStrategy)
return !ok
}
func (r *Route) hydrateParams(path string, params *Params) bool {
rLen := len(r.path)
pLen := len(path)
var i, j int
state := stateDefault
// Note that we assume that this is a valid route (validated with parseRoute).
OUTER:
for i < rLen && j < pLen {
switch state {
case stateParam:
startPath := j
idx := strings.IndexByte(path[j:], slashDelim)
if idx > 0 {
j += idx
} else if idx < 0 {
j += len(path[j:])
} else {
// segment is empty
return false
}
startRoute := i
idx = strings.IndexByte(r.path[i:], slashDelim)
if idx >= 0 {
i += idx
} else {
i += len(r.path[i:])
}
*params = append(*params, Param{
Key: r.path[startRoute : i-1],
Value: path[startPath:j],
})
state = stateDefault
default:
if r.path[i] == '{' {
i++
state = stateParam
continue
}
if r.path[i] == '*' {
state = stateCatchAll
break OUTER
}
if r.path[i] == path[j] {
i++
j++
continue
}
return false
}
}
if state == stateCatchAll || (i < rLen && r.path[i] == '*') {
*params = append(*params, Param{
Key: r.path[i+2 : rLen-1],
Value: path[j:],
})
return true
}
if i == rLen && j == pLen {
return true
}
return false
}