forked from zenazn/goji
/
pattern.go
80 lines (75 loc) · 3.34 KB
/
pattern.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
package web
import (
"log"
"net/http"
"regexp"
)
// A Pattern determines whether or not a given request matches some criteria.
// They are often used in routes, which are essentially (pattern, methodSet,
// handler) tuples. If the method and pattern match, the given handler is used.
//
// Built-in implementations of this interface are used to implement regular
// expression and string matching.
type Pattern interface {
// In practice, most real-world routes have a string prefix that can be
// used to quickly determine if a pattern is an eligible match. The
// router uses the result of this function to optimize away calls to the
// full Match function, which is likely much more expensive to compute.
// If your Pattern does not support prefixes, this function should
// return the empty string.
Prefix() string
// Returns true if the request satisfies the pattern. This function is
// free to examine both the request and the context to make this
// decision. Match should not modify either argument, and since it will
// potentially be called several times over the course of matching a
// request, it should be reasonably efficient.
Match(r *http.Request, c *C) bool
// Run the pattern on the request and context, modifying the context as
// necessary to bind URL parameters or other parsed state.
Run(r *http.Request, c *C)
}
/*
ParsePattern is used internally by Goji to parse route patterns. It is exposed
publicly to make it easier to write thin wrappers around the built-in Pattern
implementations.
Although its parameter has type interface{}, ParsePattern only accepts arguments
of three types:
- web.Pattern, which is passed through
- string, which is interpreted as a Sinatra-like URL pattern. In
particular, the following syntax is recognized:
- a path segment starting with with a colon will match any
string placed at that position. e.g., "/:name" will match
"/carl", binding "name" to "carl".
- a pattern ending with "/*" will match any route with that
prefix. For instance, the pattern "/u/:name/*" will match
"/u/carl/" and "/u/carl/projects/123", but not "/u/carl"
(because there is no trailing slash). In addition to any names
bound in the pattern, the special key "*" is bound to the
unmatched tail of the match, but including the leading "/". So
for the two matching examples above, "*" would be bound to "/"
and "/projects/123" respectively.
- regexp.Regexp, which is assumed to be a Perl-style regular expression
that is anchored on the left (i.e., the beginning of the string). If
your regular expression is not anchored on the left, a
hopefully-identical left-anchored regular expression will be created
and used instead. Named capturing groups will bind URLParams of the
same name; unnamed capturing groups will be bound to the variables
"$1", "$2", etc.
ParsePattern fatally exits (using log.Fatalf) if it is passed a value of an
unexpected type. It is the caller's responsibility to ensure that ParsePattern
is called in a type-safe manner.
*/
func ParsePattern(raw interface{}) Pattern {
switch v := raw.(type) {
case Pattern:
return v
case *regexp.Regexp:
return parseRegexpPattern(v)
case string:
return parseStringPattern(v)
default:
log.Fatalf("Unknown pattern type %T. Expected a web.Pattern, "+
"regexp.Regexp, or a string.", v)
}
panic("log.Fatalf does not return")
}