package web import ( "fmt" "net/http" "regexp" "strings" ) type regexpPattern struct { re *regexp.Regexp names []string } func (p regexpPattern) Prefix() string { prefix, _ := p.re.LiteralPrefix() return prefix } func (p regexpPattern) Match(r *http.Request, c *C) bool { matches := p.re.FindStringSubmatch(r.URL.Path) if matches == nil { return false } if c.UrlParams == nil && len(matches) > 0 { c.UrlParams = make(map[string]string, len(matches)-1) } for i := 1; i < len(matches); i++ { c.UrlParams[p.names[i]] = matches[i] } return true } func parseRegexpPattern(re *regexp.Regexp) regexpPattern { rnames := re.SubexpNames() // We have to make our own copy since package regexp forbids us // from scribbling over the slice returned by SubexpNames(). names := make([]string, len(rnames)) for i, rname := range rnames { if rname == "" { rname = fmt.Sprintf("$%d", i) } names[i] = rname } return regexpPattern{ re: re, names: names, } } type stringPattern struct { raw string pats []string literals []string isPrefix bool } func (s stringPattern) Prefix() string { return s.literals[0] } func (s stringPattern) Match(r *http.Request, c *C) bool { path := r.URL.Path matches := make([]string, len(s.pats)) for i := 0; i < len(s.pats); i++ { if !strings.HasPrefix(path, s.literals[i]) { return false } path = path[len(s.literals[i]):] m := strings.IndexRune(path, '/') if m == -1 { m = len(path) } if m == 0 { // Empty strings are not matches, otherwise routes like // "/:foo" would match the path "/" return false } matches[i] = path[:m] path = path[m:] } // There's exactly one more literal than pat. if s.isPrefix { if strings.HasPrefix(path, s.literals[len(s.pats)]) { return false } } else { if path != s.literals[len(s.pats)] { return false } } if c.UrlParams == nil && len(matches) > 0 { c.UrlParams = make(map[string]string, len(matches)-1) } for i, match := range matches { c.UrlParams[s.pats[i]] = match } return true } func parseStringPattern(s string, isPrefix bool) stringPattern { matches := patternRe.FindAllStringSubmatchIndex(s, -1) pats := make([]string, len(matches)) literals := make([]string, len(matches)+1) n := 0 for i, match := range matches { a, b := match[2], match[3] literals[i] = s[n : a-1] // Need to leave off the colon pats[i] = s[a:b] n = b } literals[len(matches)] = s[n:] return stringPattern{ raw: s, pats: pats, literals: literals, isPrefix: isPrefix, } }