// Beego (http://beego.me/) // @description beego is an open-source, high-performance web framework for the Go programming language. // @link http://github.com/astaxie/beego for the canonical source repository // @license http://github.com/astaxie/beego/blob/master/LICENSE // @authors astaxie package beego import ( "regexp" "strings" ) // FilterRouter defines filter operation before controller handler execution. // it can match patterned url and do filter function when action arrives. type FilterRouter struct { pattern string regex *regexp.Regexp filterFunc FilterFunc hasregex bool params map[int]string parseParams map[string]string } // ValidRouter check current request is valid for this filter. // if matched, returns parsed params in this request by defined filter router pattern. func (mr *FilterRouter) ValidRouter(router string) (bool, map[string]string) { if mr.pattern == "" { return true, nil } if mr.pattern == "*" { return true, nil } if router == mr.pattern { return true, nil } //pattern /admin router /admin/ match //pattern /admin/ router /admin don't match, because url will 301 in router if n := len(router); n > 1 && router[n-1] == '/' && router[:n-2] == mr.pattern { return true, nil } if mr.hasregex { if !mr.regex.MatchString(router) { return false, nil } matches := mr.regex.FindStringSubmatch(router) if len(matches) > 0 { if len(matches[0]) == len(router) { params := make(map[string]string) for i, match := range matches[1:] { params[mr.params[i]] = match } return true, params } } } return false, nil } func buildFilter(pattern string, filter FilterFunc) (*FilterRouter, error) { mr := new(FilterRouter) mr.params = make(map[int]string) mr.filterFunc = filter parts := strings.Split(pattern, "/") j := 0 for i, part := range parts { if strings.HasPrefix(part, ":") { expr := "(.*)" //a user may choose to override the default expression // similar to expressjs: ‘/user/:id([0-9]+)’ if index := strings.Index(part, "("); index != -1 { expr = part[index:] part = part[:index] //match /user/:id:int ([0-9]+) //match /post/:username:string ([\w]+) } else if lindex := strings.LastIndex(part, ":"); lindex != 0 { switch part[lindex:] { case ":int": expr = "([0-9]+)" part = part[:lindex] case ":string": expr = `([\w]+)` part = part[:lindex] } } mr.params[j] = part parts[i] = expr j++ } if strings.HasPrefix(part, "*") { expr := "(.*)" if part == "*.*" { mr.params[j] = ":path" parts[i] = "([^.]+).([^.]+)" j++ mr.params[j] = ":ext" j++ } else { mr.params[j] = ":splat" parts[i] = expr j++ } } //url like someprefix:id(xxx).html if strings.Contains(part, ":") && strings.Contains(part, "(") && strings.Contains(part, ")") { var out []rune var start bool var startexp bool var param []rune var expt []rune for _, v := range part { if start { if v != '(' { param = append(param, v) continue } } if startexp { if v != ')' { expt = append(expt, v) continue } } if v == ':' { param = make([]rune, 0) param = append(param, ':') start = true } else if v == '(' { startexp = true start = false mr.params[j] = string(param) j++ expt = make([]rune, 0) expt = append(expt, '(') } else if v == ')' { startexp = false expt = append(expt, ')') out = append(out, expt...) } else { out = append(out, v) } } parts[i] = string(out) } } if j != 0 { pattern = strings.Join(parts, "/") regex, regexErr := regexp.Compile(pattern) if regexErr != nil { return nil, regexErr } mr.regex = regex mr.hasregex = true } mr.pattern = pattern return mr, nil }