mirror of
https://github.com/astaxie/beego.git
synced 2025-07-16 02:32:17 +00:00
refactor router
This commit is contained in:
257
tree.go
257
tree.go
@@ -23,26 +23,28 @@ import (
|
||||
"github.com/astaxie/beego/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
allowSuffixExt = []string{".json", ".xml", ".html"}
|
||||
)
|
||||
|
||||
// Tree has three elements: FixRouter/wildcard/leaves
|
||||
// fixRouter sotres Fixed Router
|
||||
// wildcard stores params
|
||||
// leaves store the endpoint information
|
||||
type Tree struct {
|
||||
//prefix set for static router
|
||||
prefix string
|
||||
//search fix route first
|
||||
fixrouters map[string]*Tree
|
||||
|
||||
fixrouters []*Tree
|
||||
//if set, failure to match fixrouters search then search wildcard
|
||||
wildcard *Tree
|
||||
|
||||
//if set, failure to match wildcard search
|
||||
leaves []*leafInfo
|
||||
}
|
||||
|
||||
// NewTree return a new Tree
|
||||
func NewTree() *Tree {
|
||||
return &Tree{
|
||||
fixrouters: make(map[string]*Tree),
|
||||
}
|
||||
return &Tree{}
|
||||
}
|
||||
|
||||
// AddTree will add tree to the exist Tree
|
||||
@@ -57,15 +59,31 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
|
||||
}
|
||||
seg := segments[0]
|
||||
iswild, params, regexpStr := splitSegment(seg)
|
||||
// if it's ? meaning can igone this, so add one more rule for it
|
||||
if len(params) > 0 && params[0] == ":" {
|
||||
params = params[1:]
|
||||
if len(segments[1:]) > 0 {
|
||||
t.addtree(segments[1:], tree, append(wildcards, params...), reg)
|
||||
} else {
|
||||
filterTreeWithPrefix(tree, wildcards, reg)
|
||||
}
|
||||
}
|
||||
//Rule: /login/*/access match /login/2009/11/access
|
||||
//if already has *, and when loop the access, should as a regexpStr
|
||||
if !iswild && utils.InSlice(":splat", wildcards) {
|
||||
iswild = true
|
||||
regexpStr = seg
|
||||
}
|
||||
//Rule: /user/:id/*
|
||||
if seg == "*" && len(wildcards) > 0 && reg == "" {
|
||||
regexpStr = "(.+)"
|
||||
}
|
||||
if len(segments) == 1 {
|
||||
if iswild {
|
||||
if regexpStr != "" {
|
||||
if reg == "" {
|
||||
rr := ""
|
||||
for _, w := range wildcards {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
if w == ":splat" {
|
||||
rr = rr + "(.+)/"
|
||||
} else {
|
||||
@@ -94,10 +112,12 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
|
||||
} else {
|
||||
reg = strings.Trim(reg+"/"+regexpStr, "/")
|
||||
filterTreeWithPrefix(tree, append(wildcards, params...), reg)
|
||||
t.fixrouters[seg] = tree
|
||||
tree.prefix = seg
|
||||
t.fixrouters = append(t.fixrouters, tree)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if iswild {
|
||||
if t.wildcard == nil {
|
||||
t.wildcard = NewTree()
|
||||
@@ -106,9 +126,6 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
|
||||
if reg == "" {
|
||||
rr := ""
|
||||
for _, w := range wildcards {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
if w == ":splat" {
|
||||
rr = rr + "(.+)/"
|
||||
} else {
|
||||
@@ -122,20 +139,23 @@ func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg st
|
||||
} else if reg != "" {
|
||||
if seg == "*.*" {
|
||||
regexpStr = "([^.]+).(.+)"
|
||||
params = params[1:]
|
||||
} else {
|
||||
for _, w := range params {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
for _ = range params {
|
||||
regexpStr = "([^/]+)/" + regexpStr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if seg == "*.*" {
|
||||
params = params[1:]
|
||||
}
|
||||
}
|
||||
reg = strings.TrimRight(strings.TrimRight(reg, "/")+"/"+regexpStr, "/")
|
||||
t.wildcard.addtree(segments[1:], tree, append(wildcards, params...), reg)
|
||||
} else {
|
||||
subTree := NewTree()
|
||||
t.fixrouters[seg] = subTree
|
||||
subTree.prefix = seg
|
||||
t.fixrouters = append(t.fixrouters, subTree)
|
||||
subTree.addtree(segments[1:], tree, append(wildcards, params...), reg)
|
||||
}
|
||||
}
|
||||
@@ -154,9 +174,6 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
|
||||
l.regexps = regexp.MustCompile("^" + reg + "/" + strings.Trim(l.regexps.String(), "^$") + "$")
|
||||
} else {
|
||||
for _, v := range l.wildcards {
|
||||
if v == ":" || v == "." {
|
||||
continue
|
||||
}
|
||||
if v == ":splat" {
|
||||
reg = reg + "/(.+)"
|
||||
} else {
|
||||
@@ -166,21 +183,10 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
|
||||
l.regexps = regexp.MustCompile("^" + reg + "$")
|
||||
l.wildcards = append(wildcards, l.wildcards...)
|
||||
}
|
||||
filterCards := []string{}
|
||||
for _, v := range l.wildcards {
|
||||
if v == ":" || v == "." {
|
||||
continue
|
||||
}
|
||||
filterCards = append(filterCards, v)
|
||||
}
|
||||
l.wildcards = filterCards
|
||||
} else {
|
||||
l.wildcards = append(wildcards, l.wildcards...)
|
||||
if l.regexps != nil {
|
||||
for _, w := range wildcards {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
if w == ":splat" {
|
||||
reg = "(.+)/" + reg
|
||||
} else {
|
||||
@@ -203,32 +209,26 @@ func (t *Tree) AddRouter(pattern string, runObject interface{}) {
|
||||
func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) {
|
||||
if len(segments) == 0 {
|
||||
if reg != "" {
|
||||
filterCards := []string{}
|
||||
for _, v := range wildcards {
|
||||
if v == ":" || v == "." {
|
||||
continue
|
||||
}
|
||||
filterCards = append(filterCards, v)
|
||||
}
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: filterCards, regexps: regexp.MustCompile("^" + reg + "$")})
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")})
|
||||
} else {
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards})
|
||||
}
|
||||
for i, v := range wildcards {
|
||||
if v == ":" {
|
||||
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards[:i+1]})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
seg := segments[0]
|
||||
iswild, params, regexpStr := splitSegment(seg)
|
||||
//for the router /login/*/access match /login/2009/11/access
|
||||
// if it's ? meaning can igone this, so add one more rule for it
|
||||
if len(params) > 0 && params[0] == ":" {
|
||||
t.addseg(segments[1:], route, wildcards, reg)
|
||||
params = params[1:]
|
||||
}
|
||||
//Rule: /login/*/access match /login/2009/11/access
|
||||
//if already has *, and when loop the access, should as a regexpStr
|
||||
if !iswild && utils.InSlice(":splat", wildcards) {
|
||||
iswild = true
|
||||
regexpStr = seg
|
||||
}
|
||||
//Rule: /user/:id/*
|
||||
if seg == "*" && len(wildcards) > 0 && reg == "" {
|
||||
iswild = true
|
||||
regexpStr = "(.+)"
|
||||
}
|
||||
if iswild {
|
||||
@@ -239,9 +239,6 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
|
||||
if reg == "" {
|
||||
rr := ""
|
||||
for _, w := range wildcards {
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
if w == ":splat" {
|
||||
rr = rr + "(.+)/"
|
||||
} else {
|
||||
@@ -255,22 +252,31 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
|
||||
} else if reg != "" {
|
||||
if seg == "*.*" {
|
||||
regexpStr = "/([^.]+).(.+)"
|
||||
params = params[1:]
|
||||
} else {
|
||||
for _, w := range params {
|
||||
|
||||
if w == "." || w == ":" {
|
||||
continue
|
||||
}
|
||||
for _ = range params {
|
||||
regexpStr = "/([^/]+)" + regexpStr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if seg == "*.*" {
|
||||
params = params[1:]
|
||||
}
|
||||
}
|
||||
t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr)
|
||||
} else {
|
||||
subTree, ok := t.fixrouters[seg]
|
||||
var ok bool
|
||||
var subTree *Tree
|
||||
for _, subTree = range t.fixrouters {
|
||||
if t.prefix == seg {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
subTree = NewTree()
|
||||
t.fixrouters[seg] = subTree
|
||||
subTree.prefix = seg
|
||||
t.fixrouters = append(t.fixrouters, subTree)
|
||||
}
|
||||
subTree.addseg(segments[1:], route, wildcards, reg)
|
||||
}
|
||||
@@ -282,13 +288,18 @@ func (t *Tree) Match(pattern string, ctx *context.Context) (runObject interface{
|
||||
if len(pattern) == 0 || pattern[0] != '/' {
|
||||
return nil
|
||||
}
|
||||
|
||||
return t.match(splitPath(pattern), nil, ctx)
|
||||
return t.match(pattern, nil, ctx)
|
||||
}
|
||||
|
||||
func (t *Tree) match(segments []string, wildcardValues []string, ctx *context.Context) (runObject interface{}) {
|
||||
func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Context) (runObject interface{}) {
|
||||
if len(pattern) > 0 {
|
||||
i := 0
|
||||
for ; i < len(pattern) && pattern[i] == '/'; i++ {
|
||||
}
|
||||
pattern = pattern[i:]
|
||||
}
|
||||
// Handle leaf nodes:
|
||||
if len(segments) == 0 {
|
||||
if len(pattern) == 0 {
|
||||
for _, l := range t.leaves {
|
||||
if ok := l.match(wildcardValues, ctx); ok {
|
||||
return l.runObject
|
||||
@@ -303,28 +314,47 @@ func (t *Tree) match(segments []string, wildcardValues []string, ctx *context.Co
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
seg, segs := segments[0], segments[1:]
|
||||
|
||||
subTree, ok := t.fixrouters[seg]
|
||||
if ok {
|
||||
runObject = subTree.match(segs, wildcardValues, ctx)
|
||||
} else if len(segs) == 0 { //.json .xml
|
||||
if subindex := strings.LastIndex(seg, "."); subindex != -1 {
|
||||
subTree, ok = t.fixrouters[seg[:subindex]]
|
||||
if ok {
|
||||
runObject = subTree.match(segs, wildcardValues, ctx)
|
||||
if runObject != nil {
|
||||
ctx.Input.Params[":ext"] = seg[subindex+1:]
|
||||
return runObject
|
||||
var seg string
|
||||
i, l := 0, len(pattern)
|
||||
for ; i < l && pattern[i] != '/'; i++ {
|
||||
}
|
||||
if i == 0 {
|
||||
seg = pattern
|
||||
pattern = ""
|
||||
} else {
|
||||
seg = pattern[:i]
|
||||
pattern = pattern[i:]
|
||||
}
|
||||
for _, subTree := range t.fixrouters {
|
||||
if subTree.prefix == seg {
|
||||
runObject = subTree.match(pattern, wildcardValues, ctx)
|
||||
if runObject != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if runObject == nil {
|
||||
// Filter the .json .xml .html extension
|
||||
for _, str := range allowSuffixExt {
|
||||
if strings.HasSuffix(seg, str) {
|
||||
for _, subTree := range t.fixrouters {
|
||||
if subTree.prefix == seg[:len(seg)-len(str)] {
|
||||
runObject = subTree.match(pattern, wildcardValues, ctx)
|
||||
if runObject != nil {
|
||||
ctx.Input.SetParam(":ext", str[1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if runObject == nil && t.wildcard != nil {
|
||||
runObject = t.wildcard.match(segs, append(wildcardValues, seg), ctx)
|
||||
runObject = t.wildcard.match(pattern, append(wildcardValues, seg), ctx)
|
||||
}
|
||||
|
||||
if runObject == nil {
|
||||
segments := splitPath(pattern)
|
||||
wildcardValues = append(wildcardValues, seg)
|
||||
for _, l := range t.leaves {
|
||||
if ok := l.match(append(wildcardValues, segments...), ctx); ok {
|
||||
return l.runObject
|
||||
@@ -345,71 +375,48 @@ type leafInfo struct {
|
||||
}
|
||||
|
||||
func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok bool) {
|
||||
//fmt.Println("Leaf:", wildcardValues, leaf.wildcards, leaf.regexps)
|
||||
if leaf.regexps == nil {
|
||||
// has error
|
||||
if len(wildcardValues) == 0 && len(leaf.wildcards) > 0 {
|
||||
if utils.InSlice(":", leaf.wildcards) {
|
||||
j := 0
|
||||
for _, v := range leaf.wildcards {
|
||||
if v == ":" {
|
||||
continue
|
||||
}
|
||||
ctx.Input.Params[v] = ""
|
||||
j++
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} else if len(wildcardValues) == 0 { // static path
|
||||
if len(wildcardValues) == 0 { // static path
|
||||
return true
|
||||
}
|
||||
// match *
|
||||
if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" {
|
||||
ctx.Input.Params[":splat"] = path.Join(wildcardValues...)
|
||||
ctx.Input.SetParam(":splat", path.Join(wildcardValues...))
|
||||
return true
|
||||
}
|
||||
// match *.*
|
||||
if len(leaf.wildcards) == 3 && leaf.wildcards[0] == "." {
|
||||
lastone := wildcardValues[len(wildcardValues)-1]
|
||||
strs := strings.SplitN(lastone, ".", 2)
|
||||
if len(strs) == 2 {
|
||||
ctx.Input.Params[":ext"] = strs[1]
|
||||
} else {
|
||||
ctx.Input.Params[":ext"] = ""
|
||||
}
|
||||
ctx.Input.Params[":path"] = path.Join(wildcardValues[:len(wildcardValues)-1]...) + "/" + strs[0]
|
||||
return true
|
||||
}
|
||||
// match :id
|
||||
j := 0
|
||||
for _, v := range leaf.wildcards {
|
||||
if v == ":" {
|
||||
continue
|
||||
}
|
||||
if v == "." {
|
||||
// match *.* or :id
|
||||
if len(leaf.wildcards) >= 2 && leaf.wildcards[len(leaf.wildcards)-2] == ":path" && leaf.wildcards[len(leaf.wildcards)-1] == ":ext" {
|
||||
if len(leaf.wildcards) == 2 {
|
||||
lastone := wildcardValues[len(wildcardValues)-1]
|
||||
strs := strings.SplitN(lastone, ".", 2)
|
||||
if len(strs) == 2 {
|
||||
ctx.Input.Params[":ext"] = strs[1]
|
||||
} else {
|
||||
ctx.Input.Params[":ext"] = ""
|
||||
}
|
||||
if len(wildcardValues[j:]) == 1 {
|
||||
ctx.Input.Params[":path"] = strs[0]
|
||||
} else {
|
||||
ctx.Input.Params[":path"] = path.Join(wildcardValues[j:]...) + "/" + strs[0]
|
||||
ctx.Input.SetParam(":ext", strs[1])
|
||||
}
|
||||
ctx.Input.SetParam(":path", path.Join(path.Join(wildcardValues[:len(wildcardValues)-1]...), strs[0]))
|
||||
return true
|
||||
}
|
||||
if len(wildcardValues) <= j {
|
||||
} else if len(wildcardValues) < 2 {
|
||||
return false
|
||||
}
|
||||
ctx.Input.Params[v] = wildcardValues[j]
|
||||
j++
|
||||
var index int
|
||||
for index = 0; index < len(leaf.wildcards)-2; index++ {
|
||||
ctx.Input.SetParam(leaf.wildcards[index], wildcardValues[index])
|
||||
}
|
||||
lastone := wildcardValues[len(wildcardValues)-1]
|
||||
strs := strings.SplitN(lastone, ".", 2)
|
||||
if len(strs) == 2 {
|
||||
ctx.Input.SetParam(":ext", strs[1])
|
||||
}
|
||||
ctx.Input.SetParam(":path", path.Join(path.Join(wildcardValues[index:len(wildcardValues)-1]...), strs[0]))
|
||||
return true
|
||||
}
|
||||
if len(ctx.Input.Params) != len(wildcardValues) {
|
||||
// match :id
|
||||
if len(leaf.wildcards) != len(wildcardValues) {
|
||||
return false
|
||||
}
|
||||
for j, v := range leaf.wildcards {
|
||||
ctx.Input.SetParam(v, wildcardValues[j])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -418,7 +425,7 @@ func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok b
|
||||
}
|
||||
matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
|
||||
for i, match := range matches[1:] {
|
||||
ctx.Input.Params[leaf.wildcards[i]] = match
|
||||
ctx.Input.SetParam(leaf.wildcards[i], match)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
Reference in New Issue
Block a user