Browse Source

Allow ".,;" as string pattern "break chars"

This allows you to match "/a/cat.gif" with patterns like "/a/:b.:c".

Thanks to @Minecrell for an early patch implementing this functionality.

Fixes #75.
Fixes #48.
Carl Jackson 11 years ago
parent
commit
1a390aba1c
2 changed files with 36 additions and 2 deletions
  1. +18
    -0
      web/pattern_test.go
  2. +18
    -2
      web/string_pattern.go

+ 18
- 0
web/pattern_test.go View File

@ -93,6 +93,9 @@ var patternTests = []struct {
pt("/hello/world", true, map[string]string{
"name": "world",
}),
pt("/hello/my.world;wow", true, map[string]string{
"name": "my.world;wow",
}),
pt("/hell", false, nil),
pt("/hello/", false, nil),
pt("/hello/my/love", false, nil),
@ -107,6 +110,21 @@ var patternTests = []struct {
pt("/a//b/", false, nil),
pt("/a/1/b/2/3", false, nil),
}},
{parseStringPattern("/a/:b.:c"),
"/a/", []patternTest{
pt("/a/cat.gif", true, map[string]string{
"b": "cat",
"c": "gif",
}),
pt("/a/cat.tar.gz", true, map[string]string{
"b": "cat",
"c": "tar.gz",
}),
pt("/a", false, nil),
pt("/a/cat", false, nil),
pt("/a/cat/gif", false, nil),
pt("/a/cat.", false, nil),
}},
// String prefix tests
{parseStringPattern("/user/:user*"),


+ 18
- 2
web/string_pattern.go View File

@ -7,9 +7,11 @@ import (
"strings"
)
// stringPattern is a struct describing
type stringPattern struct {
raw string
pats []string
breaks []byte
literals []string
isPrefix bool
}
@ -37,8 +39,9 @@ func (s stringPattern) match(r *http.Request, c *C, dryrun bool) bool {
path = path[len(sli):]
m := 0
bc := s.breaks[i]
for ; m < len(path); m++ {
if path[m] == '/' {
if path[m] == bc {
break
}
}
@ -81,7 +84,13 @@ func (s stringPattern) String() string {
return fmt.Sprintf("stringPattern(%q, %v)", s.raw, s.isPrefix)
}
var patternRe = regexp.MustCompile(`/:([^/]+)`)
// "Break characters" are characters that can end patterns. They are not allowed
// to appear in pattern names. "/" was chosen because it is the standard path
// separator, and "." was chosen because it often delimits file extensions. ";"
// and "," were chosen because Section 3.3 of RFC 3986 suggests their use.
const bc = "/.;,"
var patternRe = regexp.MustCompile(`[` + bc + `]:([^` + bc + `]+)`)
func parseStringPattern(s string) stringPattern {
var isPrefix bool
@ -93,18 +102,25 @@ func parseStringPattern(s string) stringPattern {
matches := patternRe.FindAllStringSubmatchIndex(s, -1)
pats := make([]string, len(matches))
breaks := make([]byte, 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]
if b == len(s) {
breaks[i] = '/'
} else {
breaks[i] = s[b]
}
n = b
}
literals[len(matches)] = s[n:]
return stringPattern{
raw: s,
pats: pats,
breaks: breaks,
literals: literals,
isPrefix: isPrefix,
}


Loading…
Cancel
Save