| package restful |
| |
| // Copyright 2013 Ernest Micklei. All rights reserved. |
| // Use of this source code is governed by a license |
| // that can be found in the LICENSE file. |
| |
| import ( |
| "bytes" |
| "fmt" |
| "regexp" |
| "strings" |
| ) |
| |
| // PathExpression holds a compiled path expression (RegExp) needed to match against |
| // Http request paths and to extract path parameter values. |
| type pathExpression struct { |
| LiteralCount int // the number of literal characters (means those not resulting from template variable substitution) |
| VarNames []string // the names of parameters (enclosed by {}) in the path |
| VarCount int // the number of named parameters (enclosed by {}) in the path |
| Matcher *regexp.Regexp |
| Source string // Path as defined by the RouteBuilder |
| tokens []string |
| } |
| |
| // NewPathExpression creates a PathExpression from the input URL path. |
| // Returns an error if the path is invalid. |
| func newPathExpression(path string) (*pathExpression, error) { |
| expression, literalCount, varNames, varCount, tokens := templateToRegularExpression(path) |
| compiled, err := regexp.Compile(expression) |
| if err != nil { |
| return nil, err |
| } |
| return &pathExpression{literalCount, varNames, varCount, compiled, expression, tokens}, nil |
| } |
| |
| // http://jsr311.java.net/nonav/releases/1.1/spec/spec3.html#x3-370003.7.3 |
| func templateToRegularExpression(template string) (expression string, literalCount int, varNames []string, varCount int, tokens []string) { |
| var buffer bytes.Buffer |
| buffer.WriteString("^") |
| //tokens = strings.Split(template, "/") |
| tokens = tokenizePath(template) |
| for _, each := range tokens { |
| if each == "" { |
| continue |
| } |
| buffer.WriteString("/") |
| if strings.HasPrefix(each, "{") { |
| // check for regular expression in variable |
| colon := strings.Index(each, ":") |
| var varName string |
| if colon != -1 { |
| // extract expression |
| varName = strings.TrimSpace(each[1:colon]) |
| paramExpr := strings.TrimSpace(each[colon+1 : len(each)-1]) |
| if paramExpr == "*" { // special case |
| buffer.WriteString("(.*)") |
| } else { |
| buffer.WriteString(fmt.Sprintf("(%s)", paramExpr)) // between colon and closing moustache |
| } |
| } else { |
| // plain var |
| varName = strings.TrimSpace(each[1 : len(each)-1]) |
| buffer.WriteString("([^/]+?)") |
| } |
| varNames = append(varNames, varName) |
| varCount += 1 |
| } else { |
| literalCount += len(each) |
| encoded := each // TODO URI encode |
| buffer.WriteString(regexp.QuoteMeta(encoded)) |
| } |
| } |
| return strings.TrimRight(buffer.String(), "/") + "(/.*)?$", literalCount, varNames, varCount, tokens |
| } |