mirror of
https://github.com/geektutu/7days-golang.git
synced 2024-04-21 12:32:11 +00:00
add /*filepath route support
This commit is contained in:
+33
-22
@@ -17,8 +17,25 @@ func newRouter() *router {
|
||||
}
|
||||
}
|
||||
|
||||
// Only one * is allowed
|
||||
func parsePattern(pattern string) []string {
|
||||
vs := strings.Split(pattern, "/")
|
||||
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
if item[0] == '*' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
parts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
parts := parsePattern(pattern)
|
||||
|
||||
key := method + "-" + pattern
|
||||
_, ok := r.roots[method]
|
||||
if !ok {
|
||||
@@ -28,19 +45,8 @@ func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
r.handlers[key] = handler
|
||||
}
|
||||
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
if n != nil {
|
||||
c.Params = params
|
||||
key := c.Method + "-" + n.pattern
|
||||
r.handlers[key](c)
|
||||
} else {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *router) getRoute(method string, pattern string) (*node, map[string]string) {
|
||||
searchParts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
func (r *router) getRoute(method string, path string) (*node, map[string]string) {
|
||||
searchParts := parsePattern(path)
|
||||
params := make(map[string]string)
|
||||
root, ok := r.roots[method]
|
||||
|
||||
@@ -51,11 +57,15 @@ func (r *router) getRoute(method string, pattern string) (*node, map[string]stri
|
||||
n := root.search(searchParts, 0)
|
||||
|
||||
if n != nil {
|
||||
parts := filterNonEmpty(strings.Split(n.pattern, "/"))
|
||||
parts := parsePattern(n.pattern)
|
||||
for index, part := range parts {
|
||||
if part[0] == ':' {
|
||||
params[part[1:]] = searchParts[index]
|
||||
}
|
||||
if part[0] == '*' && len(part) > 1 {
|
||||
params[part[1:]] = strings.Join(searchParts[index:], "/")
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, params
|
||||
}
|
||||
@@ -73,12 +83,13 @@ func (r *router) getRoutes(method string) []*node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func filterNonEmpty(vs []string) []string {
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
}
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
if n != nil {
|
||||
c.Params = params
|
||||
key := c.Method + "-" + n.pattern
|
||||
r.handlers[key](c)
|
||||
} else {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -11,9 +12,19 @@ func newTestRouter() *router {
|
||||
r.addRoute("GET", "/hello/:name", nil)
|
||||
r.addRoute("GET", "/hello/b/c", nil)
|
||||
r.addRoute("GET", "/hi/:name", nil)
|
||||
r.addRoute("GET", "/assets/*filepath", nil)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestParsePattern(t *testing.T) {
|
||||
ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"})
|
||||
if !ok {
|
||||
t.Fatal("test parsePattern failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoute(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n, ps := r.getRoute("GET", "/hello/geektutu")
|
||||
@@ -34,6 +45,22 @@ func TestGetRoute(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoute2(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n1, ps1 := r.getRoute("GET", "/assets/file1.txt")
|
||||
ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt"
|
||||
if !ok1 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt")
|
||||
}
|
||||
|
||||
n2, ps2 := r.getRoute("GET", "/assets/css/test.css")
|
||||
ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css"
|
||||
if !ok2 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoutes(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
nodes := r.getRoutes("GET")
|
||||
@@ -41,7 +68,7 @@ func TestGetRoutes(t *testing.T) {
|
||||
fmt.Println(i+1, n)
|
||||
}
|
||||
|
||||
if len(nodes) != 4 {
|
||||
if len(nodes) != 5 {
|
||||
t.Fatal("the number of routes shoule be 4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
@@ -24,14 +25,14 @@ func (n *node) insert(pattern string, parts []string, height int) {
|
||||
part := parts[height]
|
||||
child := n.matchChild(part)
|
||||
if child == nil {
|
||||
child = &node{part: part, isWild: part[0] == ':'}
|
||||
child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'}
|
||||
n.children = append(n.children, child)
|
||||
}
|
||||
child.insert(pattern, parts, height+1)
|
||||
}
|
||||
|
||||
func (n *node) search(parts []string, height int) *node {
|
||||
if len(parts) == height {
|
||||
if len(parts) == height || strings.HasPrefix(n.part, "*") {
|
||||
if n.pattern == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
+33
-22
@@ -17,8 +17,25 @@ func newRouter() *router {
|
||||
}
|
||||
}
|
||||
|
||||
// Only one * is allowed
|
||||
func parsePattern(pattern string) []string {
|
||||
vs := strings.Split(pattern, "/")
|
||||
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
if item[0] == '*' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
parts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
parts := parsePattern(pattern)
|
||||
|
||||
key := method + "-" + pattern
|
||||
_, ok := r.roots[method]
|
||||
if !ok {
|
||||
@@ -28,19 +45,8 @@ func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
r.handlers[key] = handler
|
||||
}
|
||||
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
if n != nil {
|
||||
c.Params = params
|
||||
key := c.Method + "-" + n.pattern
|
||||
r.handlers[key](c)
|
||||
} else {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *router) getRoute(method string, pattern string) (*node, map[string]string) {
|
||||
searchParts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
func (r *router) getRoute(method string, path string) (*node, map[string]string) {
|
||||
searchParts := parsePattern(path)
|
||||
params := make(map[string]string)
|
||||
root, ok := r.roots[method]
|
||||
|
||||
@@ -51,11 +57,15 @@ func (r *router) getRoute(method string, pattern string) (*node, map[string]stri
|
||||
n := root.search(searchParts, 0)
|
||||
|
||||
if n != nil {
|
||||
parts := filterNonEmpty(strings.Split(n.pattern, "/"))
|
||||
parts := parsePattern(n.pattern)
|
||||
for index, part := range parts {
|
||||
if part[0] == ':' {
|
||||
params[part[1:]] = searchParts[index]
|
||||
}
|
||||
if part[0] == '*' && len(part) > 1 {
|
||||
params[part[1:]] = strings.Join(searchParts[index:], "/")
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, params
|
||||
}
|
||||
@@ -73,12 +83,13 @@ func (r *router) getRoutes(method string) []*node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func filterNonEmpty(vs []string) []string {
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
}
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
if n != nil {
|
||||
c.Params = params
|
||||
key := c.Method + "-" + n.pattern
|
||||
r.handlers[key](c)
|
||||
} else {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -11,9 +12,19 @@ func newTestRouter() *router {
|
||||
r.addRoute("GET", "/hello/:name", nil)
|
||||
r.addRoute("GET", "/hello/b/c", nil)
|
||||
r.addRoute("GET", "/hi/:name", nil)
|
||||
r.addRoute("GET", "/assets/*filepath", nil)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestParsePattern(t *testing.T) {
|
||||
ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"})
|
||||
if !ok {
|
||||
t.Fatal("test parsePattern failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoute(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n, ps := r.getRoute("GET", "/hello/geektutu")
|
||||
@@ -34,6 +45,22 @@ func TestGetRoute(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoute2(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n1, ps1 := r.getRoute("GET", "/assets/file1.txt")
|
||||
ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt"
|
||||
if !ok1 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt")
|
||||
}
|
||||
|
||||
n2, ps2 := r.getRoute("GET", "/assets/css/test.css")
|
||||
ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css"
|
||||
if !ok2 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoutes(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
nodes := r.getRoutes("GET")
|
||||
@@ -41,7 +68,7 @@ func TestGetRoutes(t *testing.T) {
|
||||
fmt.Println(i+1, n)
|
||||
}
|
||||
|
||||
if len(nodes) != 4 {
|
||||
if len(nodes) != 5 {
|
||||
t.Fatal("the number of routes shoule be 4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
@@ -24,14 +25,14 @@ func (n *node) insert(pattern string, parts []string, height int) {
|
||||
part := parts[height]
|
||||
child := n.matchChild(part)
|
||||
if child == nil {
|
||||
child = &node{part: part, isWild: part[0] == ':'}
|
||||
child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'}
|
||||
n.children = append(n.children, child)
|
||||
}
|
||||
child.insert(pattern, parts, height+1)
|
||||
}
|
||||
|
||||
func (n *node) search(parts []string, height int) *node {
|
||||
if len(parts) == height {
|
||||
if len(parts) == height || strings.HasPrefix(n.part, "*") {
|
||||
if n.pattern == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,8 +17,25 @@ func newRouter() *router {
|
||||
}
|
||||
}
|
||||
|
||||
// Only one * is allowed
|
||||
func parsePattern(pattern string) []string {
|
||||
vs := strings.Split(pattern, "/")
|
||||
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
if item[0] == '*' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
parts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
parts := parsePattern(pattern)
|
||||
|
||||
key := method + "-" + pattern
|
||||
_, ok := r.roots[method]
|
||||
if !ok {
|
||||
@@ -28,23 +45,8 @@ func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
r.handlers[key] = handler
|
||||
}
|
||||
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
|
||||
if n != nil {
|
||||
key := c.Method + "-" + n.pattern
|
||||
c.Params = params
|
||||
c.handlers = append(c.handlers, r.handlers[key])
|
||||
} else {
|
||||
c.handlers = append(c.handlers, func(c *Context) {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
})
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
||||
func (r *router) getRoute(method string, pattern string) (*node, map[string]string) {
|
||||
searchParts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
func (r *router) getRoute(method string, path string) (*node, map[string]string) {
|
||||
searchParts := parsePattern(path)
|
||||
params := make(map[string]string)
|
||||
root, ok := r.roots[method]
|
||||
|
||||
@@ -55,11 +57,15 @@ func (r *router) getRoute(method string, pattern string) (*node, map[string]stri
|
||||
n := root.search(searchParts, 0)
|
||||
|
||||
if n != nil {
|
||||
parts := filterNonEmpty(strings.Split(n.pattern, "/"))
|
||||
parts := parsePattern(n.pattern)
|
||||
for index, part := range parts {
|
||||
if part[0] == ':' {
|
||||
params[part[1:]] = searchParts[index]
|
||||
}
|
||||
if part[0] == '*' && len(part) > 1 {
|
||||
params[part[1:]] = strings.Join(searchParts[index:], "/")
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, params
|
||||
}
|
||||
@@ -77,12 +83,17 @@ func (r *router) getRoutes(method string) []*node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func filterNonEmpty(vs []string) []string {
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
}
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
|
||||
if n != nil {
|
||||
key := c.Method + "-" + n.pattern
|
||||
c.Params = params
|
||||
c.handlers = append(c.handlers, r.handlers[key])
|
||||
} else {
|
||||
c.handlers = append(c.handlers, func(c *Context) {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
})
|
||||
}
|
||||
return parts
|
||||
c.Next()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -11,9 +12,19 @@ func newTestRouter() *router {
|
||||
r.addRoute("GET", "/hello/:name", nil)
|
||||
r.addRoute("GET", "/hello/b/c", nil)
|
||||
r.addRoute("GET", "/hi/:name", nil)
|
||||
r.addRoute("GET", "/assets/*filepath", nil)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestParsePattern(t *testing.T) {
|
||||
ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"})
|
||||
if !ok {
|
||||
t.Fatal("test parsePattern failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoute(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n, ps := r.getRoute("GET", "/hello/geektutu")
|
||||
@@ -34,6 +45,22 @@ func TestGetRoute(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoute2(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n1, ps1 := r.getRoute("GET", "/assets/file1.txt")
|
||||
ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt"
|
||||
if !ok1 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt")
|
||||
}
|
||||
|
||||
n2, ps2 := r.getRoute("GET", "/assets/css/test.css")
|
||||
ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css"
|
||||
if !ok2 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoutes(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
nodes := r.getRoutes("GET")
|
||||
@@ -41,7 +68,7 @@ func TestGetRoutes(t *testing.T) {
|
||||
fmt.Println(i+1, n)
|
||||
}
|
||||
|
||||
if len(nodes) != 4 {
|
||||
if len(nodes) != 5 {
|
||||
t.Fatal("the number of routes shoule be 4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
@@ -24,14 +25,14 @@ func (n *node) insert(pattern string, parts []string, height int) {
|
||||
part := parts[height]
|
||||
child := n.matchChild(part)
|
||||
if child == nil {
|
||||
child = &node{part: part, isWild: part[0] == ':'}
|
||||
child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'}
|
||||
n.children = append(n.children, child)
|
||||
}
|
||||
child.insert(pattern, parts, height+1)
|
||||
}
|
||||
|
||||
func (n *node) search(parts []string, height int) *node {
|
||||
if len(parts) == height {
|
||||
if len(parts) == height || strings.HasPrefix(n.part, "*") {
|
||||
if n.pattern == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ type (
|
||||
router *router
|
||||
groups []*RouterGroup // store all group
|
||||
htmlTemplates *template.Template // for html render
|
||||
funcMap template.FuncMap
|
||||
funcMap template.FuncMap // for html render
|
||||
}
|
||||
)
|
||||
|
||||
@@ -89,7 +89,7 @@ func (group *RouterGroup) createStaticHandler(relativePath string, fs http.FileS
|
||||
// serve static files
|
||||
func (group *RouterGroup) Static(relativePath string, root string) {
|
||||
handler := group.createStaticHandler(relativePath, http.Dir(root))
|
||||
urlPattern := path.Join(relativePath, "/:filepath")
|
||||
urlPattern := path.Join(relativePath, "/*filepath")
|
||||
// Register GET handlers
|
||||
group.GET(urlPattern, handler)
|
||||
}
|
||||
|
||||
+37
-26
@@ -17,8 +17,25 @@ func newRouter() *router {
|
||||
}
|
||||
}
|
||||
|
||||
// Only one * is allowed
|
||||
func parsePattern(pattern string) []string {
|
||||
vs := strings.Split(pattern, "/")
|
||||
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
if item[0] == '*' {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
parts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
parts := parsePattern(pattern)
|
||||
|
||||
key := method + "-" + pattern
|
||||
_, ok := r.roots[method]
|
||||
if !ok {
|
||||
@@ -28,23 +45,8 @@ func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
|
||||
r.handlers[key] = handler
|
||||
}
|
||||
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
|
||||
if n != nil {
|
||||
key := c.Method + "-" + n.pattern
|
||||
c.Params = params
|
||||
c.handlers = append(c.handlers, r.handlers[key])
|
||||
} else {
|
||||
c.handlers = append(c.handlers, func(c *Context) {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
})
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
|
||||
func (r *router) getRoute(method string, pattern string) (*node, map[string]string) {
|
||||
searchParts := filterNonEmpty(strings.Split(pattern, "/"))
|
||||
func (r *router) getRoute(method string, path string) (*node, map[string]string) {
|
||||
searchParts := parsePattern(path)
|
||||
params := make(map[string]string)
|
||||
root, ok := r.roots[method]
|
||||
|
||||
@@ -55,11 +57,15 @@ func (r *router) getRoute(method string, pattern string) (*node, map[string]stri
|
||||
n := root.search(searchParts, 0)
|
||||
|
||||
if n != nil {
|
||||
parts := filterNonEmpty(strings.Split(n.pattern, "/"))
|
||||
parts := parsePattern(n.pattern)
|
||||
for index, part := range parts {
|
||||
if part[0] == ':' {
|
||||
params[part[1:]] = searchParts[index]
|
||||
}
|
||||
if part[0] == '*' && len(part) > 1 {
|
||||
params[part[1:]] = strings.Join(searchParts[index:], "/")
|
||||
break
|
||||
}
|
||||
}
|
||||
return n, params
|
||||
}
|
||||
@@ -77,12 +83,17 @@ func (r *router) getRoutes(method string) []*node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func filterNonEmpty(vs []string) []string {
|
||||
parts := make([]string, 0)
|
||||
for _, item := range vs {
|
||||
if item != "" {
|
||||
parts = append(parts, item)
|
||||
}
|
||||
func (r *router) handle(c *Context) {
|
||||
n, params := r.getRoute(c.Method, c.Path)
|
||||
|
||||
if n != nil {
|
||||
key := c.Method + "-" + n.pattern
|
||||
c.Params = params
|
||||
c.handlers = append(c.handlers, r.handlers[key])
|
||||
} else {
|
||||
c.handlers = append(c.handlers, func(c *Context) {
|
||||
c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
|
||||
})
|
||||
}
|
||||
return parts
|
||||
c.Next()
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -11,9 +12,19 @@ func newTestRouter() *router {
|
||||
r.addRoute("GET", "/hello/:name", nil)
|
||||
r.addRoute("GET", "/hello/b/c", nil)
|
||||
r.addRoute("GET", "/hi/:name", nil)
|
||||
r.addRoute("GET", "/assets/*filepath", nil)
|
||||
return r
|
||||
}
|
||||
|
||||
func TestParsePattern(t *testing.T) {
|
||||
ok := reflect.DeepEqual(parsePattern("/p/:name"), []string{"p", ":name"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*"), []string{"p", "*"})
|
||||
ok = ok && reflect.DeepEqual(parsePattern("/p/*name/*"), []string{"p", "*name"})
|
||||
if !ok {
|
||||
t.Fatal("test parsePattern failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRoute(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n, ps := r.getRoute("GET", "/hello/geektutu")
|
||||
@@ -34,6 +45,22 @@ func TestGetRoute(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoute2(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
n1, ps1 := r.getRoute("GET", "/assets/file1.txt")
|
||||
ok1 := n1.pattern == "/assets/*filepath" && ps1["filepath"] == "file1.txt"
|
||||
if !ok1 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be file1.txt")
|
||||
}
|
||||
|
||||
n2, ps2 := r.getRoute("GET", "/assets/css/test.css")
|
||||
ok2 := n2.pattern == "/assets/*filepath" && ps2["filepath"] == "css/test.css"
|
||||
if !ok2 {
|
||||
t.Fatal("pattern shoule be /assets/*filepath & filepath shoule be css/test.css")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetRoutes(t *testing.T) {
|
||||
r := newTestRouter()
|
||||
nodes := r.getRoutes("GET")
|
||||
@@ -41,7 +68,7 @@ func TestGetRoutes(t *testing.T) {
|
||||
fmt.Println(i+1, n)
|
||||
}
|
||||
|
||||
if len(nodes) != 4 {
|
||||
if len(nodes) != 5 {
|
||||
t.Fatal("the number of routes shoule be 4")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package gee
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type node struct {
|
||||
@@ -24,14 +25,14 @@ func (n *node) insert(pattern string, parts []string, height int) {
|
||||
part := parts[height]
|
||||
child := n.matchChild(part)
|
||||
if child == nil {
|
||||
child = &node{part: part, isWild: part[0] == ':'}
|
||||
child = &node{part: part, isWild: part[0] == ':' || part[0] == '*'}
|
||||
n.children = append(n.children, child)
|
||||
}
|
||||
child.insert(pattern, parts, height+1)
|
||||
}
|
||||
|
||||
func (n *node) search(parts []string, height int) *node {
|
||||
if len(parts) == height {
|
||||
if len(parts) == height || strings.HasPrefix(n.part, "*") {
|
||||
if n.pattern == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html>
|
||||
<link rel="stylesheet" href="/assets/geektutu.css">
|
||||
<link rel="stylesheet" href="/assets/css/geektutu.css">
|
||||
<p>geektutu.css is loaded</p>
|
||||
</html>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
Reference in New Issue
Block a user