154 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | ||
| }
 |