@@ -14,6 +14,20 @@ import (
14
14
"strings"
15
15
)
16
16
17
+ type routeRegexpOptions struct {
18
+ strictSlash bool
19
+ useEncodedPath bool
20
+ }
21
+
22
+ type regexpType int
23
+
24
+ const (
25
+ regexpTypePath regexpType = 0
26
+ regexpTypeHost regexpType = 1
27
+ regexpTypePrefix regexpType = 2
28
+ regexpTypeQuery regexpType = 3
29
+ )
30
+
17
31
// newRouteRegexp parses a route template and returns a routeRegexp,
18
32
// used to match a host, a path or a query string.
19
33
//
@@ -24,7 +38,7 @@ import (
24
38
// Previously we accepted only Python-like identifiers for variable
25
39
// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
26
40
// name and pattern can't be empty, and names can't contain a colon.
27
- func newRouteRegexp (tpl string , matchHost , matchPrefix , matchQuery , strictSlash , useEncodedPath bool ) (* routeRegexp , error ) {
41
+ func newRouteRegexp (tpl string , typ regexpType , options routeRegexpOptions ) (* routeRegexp , error ) {
28
42
// Check if it is well-formed.
29
43
idxs , errBraces := braceIndices (tpl )
30
44
if errBraces != nil {
@@ -34,19 +48,18 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
34
48
template := tpl
35
49
// Now let's parse it.
36
50
defaultPattern := "[^/]+"
37
- if matchQuery {
51
+ if typ == regexpTypeQuery {
38
52
defaultPattern = ".*"
39
- } else if matchHost {
53
+ } else if typ == regexpTypeHost {
40
54
defaultPattern = "[^.]+"
41
- matchPrefix = false
42
55
}
43
56
// Only match strict slash if not matching
44
- if matchPrefix || matchHost || matchQuery {
45
- strictSlash = false
57
+ if typ != regexpTypePath {
58
+ options . strictSlash = false
46
59
}
47
60
// Set a flag for strictSlash.
48
61
endSlash := false
49
- if strictSlash && strings .HasSuffix (tpl , "/" ) {
62
+ if options . strictSlash && strings .HasSuffix (tpl , "/" ) {
50
63
tpl = tpl [:len (tpl )- 1 ]
51
64
endSlash = true
52
65
}
@@ -88,16 +101,16 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
88
101
// Add the remaining.
89
102
raw := tpl [end :]
90
103
pattern .WriteString (regexp .QuoteMeta (raw ))
91
- if strictSlash {
104
+ if options . strictSlash {
92
105
pattern .WriteString ("[/]?" )
93
106
}
94
- if matchQuery {
107
+ if typ == regexpTypeQuery {
95
108
// Add the default pattern if the query value is empty
96
109
if queryVal := strings .SplitN (template , "=" , 2 )[1 ]; queryVal == "" {
97
110
pattern .WriteString (defaultPattern )
98
111
}
99
112
}
100
- if ! matchPrefix {
113
+ if typ != regexpTypePrefix {
101
114
pattern .WriteByte ('$' )
102
115
}
103
116
reverse .WriteString (raw )
@@ -118,15 +131,13 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
118
131
119
132
// Done!
120
133
return & routeRegexp {
121
- template : template ,
122
- matchHost : matchHost ,
123
- matchQuery : matchQuery ,
124
- strictSlash : strictSlash ,
125
- useEncodedPath : useEncodedPath ,
126
- regexp : reg ,
127
- reverse : reverse .String (),
128
- varsN : varsN ,
129
- varsR : varsR ,
134
+ template : template ,
135
+ regexpType : typ ,
136
+ options : options ,
137
+ regexp : reg ,
138
+ reverse : reverse .String (),
139
+ varsN : varsN ,
140
+ varsR : varsR ,
130
141
}, nil
131
142
}
132
143
@@ -135,15 +146,10 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
135
146
type routeRegexp struct {
136
147
// The unmodified template.
137
148
template string
138
- // True for host match, false for path or query string match.
139
- matchHost bool
140
- // True for query string match, false for path and host match.
141
- matchQuery bool
142
- // The strictSlash value defined on the route, but disabled if PathPrefix was used.
143
- strictSlash bool
144
- // Determines whether to use encoded req.URL.EnscapedPath() or unencoded
145
- // req.URL.Path for path matching
146
- useEncodedPath bool
149
+ // The type of match
150
+ regexpType regexpType
151
+ // Options for matching
152
+ options routeRegexpOptions
147
153
// Expanded regexp.
148
154
regexp * regexp.Regexp
149
155
// Reverse template.
@@ -156,12 +162,12 @@ type routeRegexp struct {
156
162
157
163
// Match matches the regexp against the URL host or path.
158
164
func (r * routeRegexp ) Match (req * http.Request , match * RouteMatch ) bool {
159
- if ! r . matchHost {
160
- if r .matchQuery {
165
+ if r . regexpType != regexpTypeHost {
166
+ if r .regexpType == regexpTypeQuery {
161
167
return r .matchQueryString (req )
162
168
}
163
169
path := req .URL .Path
164
- if r .useEncodedPath {
170
+ if r .options . useEncodedPath {
165
171
path = req .URL .EscapedPath ()
166
172
}
167
173
return r .regexp .MatchString (path )
@@ -178,7 +184,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
178
184
if ! ok {
179
185
return "" , fmt .Errorf ("mux: missing route variable %q" , v )
180
186
}
181
- if r .matchQuery {
187
+ if r .regexpType == regexpTypeQuery {
182
188
value = url .QueryEscape (value )
183
189
}
184
190
urlValues [k ] = value
@@ -203,7 +209,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
203
209
// For a URL with foo=bar&baz=ding, we return only the relevant key
204
210
// value pair for the routeRegexp.
205
211
func (r * routeRegexp ) getURLQuery (req * http.Request ) string {
206
- if ! r . matchQuery {
212
+ if r . regexpType != regexpTypeQuery {
207
213
return ""
208
214
}
209
215
templateKey := strings .SplitN (r .template , "=" , 2 )[0 ]
@@ -280,7 +286,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
280
286
if len (matches ) > 0 {
281
287
extractVars (path , matches , v .path .varsN , m .Vars )
282
288
// Check if we should redirect.
283
- if v .path .strictSlash {
289
+ if v .path .options . strictSlash {
284
290
p1 := strings .HasSuffix (path , "/" )
285
291
p2 := strings .HasSuffix (v .path .template , "/" )
286
292
if p1 != p2 {
0 commit comments