Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
beego
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
beego
Commits
e00eab7f
Commit
e00eab7f
authored
Jun 08, 2014
by
astaxie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
beego: change to tree
parent
bfabcfcb
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
489 additions
and
697 deletions
+489
-697
admin.go
admin.go
+1
-40
beego.go
beego.go
+33
-9
controller.go
controller.go
+32
-2
filter.go
filter.go
+11
-38
filter_test.go
filter_test.go
+3
-3
namespace.go
namespace.go
+45
-34
namespace_test.go
namespace_test.go
+34
-26
parser.go
parser.go
+6
-0
router.go
router.go
+236
-534
router_test.go
router_test.go
+6
-4
tree.go
tree.go
+76
-7
tree_test.go
tree_test.go
+6
-0
No files found.
admin.go
View file @
e00eab7f
...
@@ -121,40 +121,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
...
@@ -121,40 +121,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
fmt
.
Fprintln
(
rw
,
"AdminHttpPort:"
,
AdminHttpPort
)
fmt
.
Fprintln
(
rw
,
"AdminHttpPort:"
,
AdminHttpPort
)
case
"router"
:
case
"router"
:
fmt
.
Fprintln
(
rw
,
"Print all router infomation:"
)
fmt
.
Fprintln
(
rw
,
"Print all router infomation:"
)
for
_
,
router
:=
range
BeeApp
.
Handlers
.
fixrouters
{
// @todo print routers
if
router
.
routerType
==
routerTypeBeego
{
if
router
.
hasMethod
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
methods
,
"----"
,
router
.
controllerType
.
Name
())
}
else
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
controllerType
.
Name
())
}
}
else
if
router
.
routerType
==
routerTypeRESTFul
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
methods
,
"----"
,
router
.
runfunction
)
}
else
if
router
.
routerType
==
routerTypeHandler
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
handler
)
}
}
for
_
,
router
:=
range
BeeApp
.
Handlers
.
routers
{
if
router
.
routerType
==
routerTypeBeego
{
if
router
.
hasMethod
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
methods
,
"----"
,
router
.
controllerType
.
Name
())
}
else
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
controllerType
.
Name
())
}
}
else
if
router
.
routerType
==
routerTypeRESTFul
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
methods
,
"----"
,
router
.
runfunction
)
}
else
if
router
.
routerType
==
routerTypeHandler
{
fmt
.
Fprintln
(
rw
,
router
.
pattern
,
"----"
,
router
.
handler
)
}
}
if
BeeApp
.
Handlers
.
enableAuto
{
for
controllerName
,
methodObj
:=
range
BeeApp
.
Handlers
.
autoRouter
{
fmt
.
Fprintln
(
rw
,
controllerName
,
"----"
)
for
methodName
,
obj
:=
range
methodObj
{
fmt
.
Fprintln
(
rw
,
" "
,
methodName
,
"-----"
,
obj
.
Name
())
}
}
}
case
"filter"
:
case
"filter"
:
fmt
.
Fprintln
(
rw
,
"Print all filter infomation:"
)
fmt
.
Fprintln
(
rw
,
"Print all filter infomation:"
)
if
BeeApp
.
Handlers
.
enableFilter
{
if
BeeApp
.
Handlers
.
enableFilter
{
...
@@ -164,12 +131,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
...
@@ -164,12 +131,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
fmt
.
Fprintln
(
rw
,
f
.
pattern
,
utils
.
GetFuncName
(
f
.
filterFunc
))
fmt
.
Fprintln
(
rw
,
f
.
pattern
,
utils
.
GetFuncName
(
f
.
filterFunc
))
}
}
}
}
fmt
.
Fprintln
(
rw
,
"AfterStatic:"
)
if
bf
,
ok
:=
BeeApp
.
Handlers
.
filters
[
AfterStatic
];
ok
{
for
_
,
f
:=
range
bf
{
fmt
.
Fprintln
(
rw
,
f
.
pattern
,
utils
.
GetFuncName
(
f
.
filterFunc
))
}
}
fmt
.
Fprintln
(
rw
,
"BeforeExec:"
)
fmt
.
Fprintln
(
rw
,
"BeforeExec:"
)
if
bf
,
ok
:=
BeeApp
.
Handlers
.
filters
[
BeforeExec
];
ok
{
if
bf
,
ok
:=
BeeApp
.
Handlers
.
filters
[
BeforeExec
];
ok
{
for
_
,
f
:=
range
bf
{
for
_
,
f
:=
range
bf
{
...
...
beego.go
View file @
e00eab7f
...
@@ -100,7 +100,7 @@ func AddGroupRouter(prefix string, groups GroupRouters) *App {
...
@@ -100,7 +100,7 @@ func AddGroupRouter(prefix string, groups GroupRouters) *App {
//
//
// regex router
// regex router
//
//
// beego.Router(
“/api/:id([0-9]+)“
, &controllers.RController{})
// beego.Router(
"/api/:id([0-9]+)"
, &controllers.RController{})
//
//
// custom rules
// custom rules
// beego.Router("/api/list",&RestController{},"*:ListFood")
// beego.Router("/api/list",&RestController{},"*:ListFood")
...
@@ -112,6 +112,38 @@ func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *A
...
@@ -112,6 +112,38 @@ func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *A
return
BeeApp
return
BeeApp
}
}
// Router add list from
// usage:
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
// type BankAccount struct{
// beego.Controller
// }
//
// register the function
// func (b *BankAccount)Mapping(){
// b.Mapping("ShowAccount" , b.ShowAccount)
// b.Mapping("ModifyAccount", b.ModifyAccount)
//}
//
// //@router /account/:id [get]
// func (b *BankAccount) ShowAccount(){
// //logic
// }
//
//
// //@router /account/:id [post]
// func (b *BankAccount) ModifyAccount(){
// //logic
// }
//
// the comments @router url methodlist
// url support all the function Router's pattern
// methodlist [get post head put delete options *]
func
Include
(
cList
...
ControllerInterface
)
*
App
{
BeeApp
.
Handlers
.
Include
(
cList
...
)
return
BeeApp
}
// RESTRouter adds a restful controller handler to BeeApp.
// RESTRouter adds a restful controller handler to BeeApp.
// its' controller implements beego.ControllerInterface and
// its' controller implements beego.ControllerInterface and
// defines a param "pattern/:objectId" to visit each resource.
// defines a param "pattern/:objectId" to visit each resource.
...
@@ -261,14 +293,6 @@ func DelStaticPath(url string) *App {
...
@@ -261,14 +293,6 @@ func DelStaticPath(url string) *App {
return
BeeApp
return
BeeApp
}
}
// [Deprecated] use InsertFilter.
// Filter adds a FilterFunc under pattern condition and named action.
// The actions contains BeforeRouter,AfterStatic,BeforeExec,AfterExec and FinishRouter.
func
AddFilter
(
pattern
,
action
string
,
filter
FilterFunc
)
*
App
{
BeeApp
.
Handlers
.
AddFilter
(
pattern
,
action
,
filter
)
return
BeeApp
}
// InsertFilter adds a FilterFunc with pattern condition and action constant.
// InsertFilter adds a FilterFunc with pattern condition and action constant.
// The pos means action constant including
// The pos means action constant including
// beego.BeforeRouter, beego.AfterStatic, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
// beego.BeforeRouter, beego.AfterStatic, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
...
...
controller.go
View file @
e00eab7f
...
@@ -34,7 +34,8 @@ const (
...
@@ -34,7 +34,8 @@ const (
var
(
var
(
// custom error when user stop request handler manually.
// custom error when user stop request handler manually.
USERSTOPRUN
=
errors
.
New
(
"User stop run"
)
USERSTOPRUN
=
errors
.
New
(
"User stop run"
)
GlobalControllerRouter
map
[
string
]
map
[
string
]
*
Tree
//pkgpath+controller:method:routertree
)
)
// Controller defines some basic http request handler operations, such as
// Controller defines some basic http request handler operations, such as
...
@@ -55,6 +56,7 @@ type Controller struct {
...
@@ -55,6 +56,7 @@ type Controller struct {
AppController
interface
{}
AppController
interface
{}
EnableRender
bool
EnableRender
bool
EnableXSRF
bool
EnableXSRF
bool
Routers
map
[
string
]
*
Tree
//method:routertree
}
}
// ControllerInterface is an interface to uniform all controller handler.
// ControllerInterface is an interface to uniform all controller handler.
...
@@ -72,6 +74,8 @@ type ControllerInterface interface {
...
@@ -72,6 +74,8 @@ type ControllerInterface interface {
Render
()
error
Render
()
error
XsrfToken
()
string
XsrfToken
()
string
CheckXsrfCookie
()
bool
CheckXsrfCookie
()
bool
HandlerFunc
(
fn
interface
{})
URLMapping
()
}
}
// Init generates default values of controller operations.
// Init generates default values of controller operations.
...
@@ -86,6 +90,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
...
@@ -86,6 +90,7 @@ func (c *Controller) Init(ctx *context.Context, controllerName, actionName strin
c
.
EnableRender
=
true
c
.
EnableRender
=
true
c
.
EnableXSRF
=
true
c
.
EnableXSRF
=
true
c
.
Data
=
ctx
.
Input
.
Data
c
.
Data
=
ctx
.
Input
.
Data
c
.
Routers
=
make
(
map
[
string
]
*
Tree
)
}
}
// Prepare runs after Init before request function execution.
// Prepare runs after Init before request function execution.
...
@@ -133,6 +138,32 @@ func (c *Controller) Options() {
...
@@ -133,6 +138,32 @@ func (c *Controller) Options() {
http
.
Error
(
c
.
Ctx
.
ResponseWriter
,
"Method Not Allowed"
,
405
)
http
.
Error
(
c
.
Ctx
.
ResponseWriter
,
"Method Not Allowed"
,
405
)
}
}
// call function fn
func
(
c
*
Controller
)
HandlerFunc
(
fn
interface
{})
{
if
v
,
ok
:=
fn
.
(
func
());
ok
{
v
()
}
}
// URLMapping register the internal Controller router.
func
(
c
*
Controller
)
URLMapping
()
{
}
func
(
c
*
Controller
)
Mapping
(
method
,
pattern
string
,
fn
func
())
{
method
=
strings
.
ToLower
(
method
)
if
!
utils
.
InSlice
(
method
,
HTTPMETHOD
)
&&
method
!=
"*"
{
Critical
(
"add mapping method:"
+
method
+
" is a valid method"
)
return
}
if
t
,
ok
:=
c
.
Routers
[
method
];
ok
{
t
.
AddRouter
(
pattern
,
fn
)
}
else
{
t
=
NewTree
()
t
.
AddRouter
(
pattern
,
fn
)
c
.
Routers
[
method
]
=
t
}
}
// Render sends the response with rendered template bytes as text/html type.
// Render sends the response with rendered template bytes as text/html type.
func
(
c
*
Controller
)
Render
()
error
{
func
(
c
*
Controller
)
Render
()
error
{
if
!
c
.
EnableRender
{
if
!
c
.
EnableRender
{
...
@@ -295,7 +326,6 @@ func (c *Controller) ServeXml() {
...
@@ -295,7 +326,6 @@ func (c *Controller) ServeXml() {
}
}
// ServeFormatted serve Xml OR Json, depending on the value of the Accept header
// ServeFormatted serve Xml OR Json, depending on the value of the Accept header
func
(
c
*
Controller
)
ServeFormatted
()
{
func
(
c
*
Controller
)
ServeFormatted
()
{
accept
:=
c
.
Ctx
.
Input
.
Header
(
"Accept"
)
accept
:=
c
.
Ctx
.
Input
.
Header
(
"Accept"
)
switch
accept
{
switch
accept
{
...
...
filter.go
View file @
e00eab7f
...
@@ -6,51 +6,24 @@
...
@@ -6,51 +6,24 @@
package
beego
package
beego
import
"regexp"
// FilterRouter defines filter operation before controller handler execution.
// FilterRouter defines filter operation before controller handler execution.
// it can match patterned url and do filter function when action arrives.
// it can match patterned url and do filter function when action arrives.
type
FilterRouter
struct
{
type
FilterRouter
struct
{
pattern
string
filterFunc
FilterFunc
regex
*
regexp
.
Regexp
tree
*
Tree
filterFunc
FilterFunc
pattern
string
hasregex
bool
params
map
[
int
]
string
parseParams
map
[
string
]
string
}
}
// ValidRouter check current request is valid for this filter.
// ValidRouter check current request is valid for this filter.
// if matched, returns parsed params in this request by defined filter router pattern.
// if matched, returns parsed params in this request by defined filter router pattern.
func
(
mr
*
FilterRouter
)
ValidRouter
(
router
string
)
(
bool
,
map
[
string
]
string
)
{
func
(
f
*
FilterRouter
)
ValidRouter
(
router
string
)
(
bool
,
map
[
string
]
string
)
{
if
mr
.
pattern
==
""
{
isok
,
params
:=
f
.
tree
.
Match
(
router
)
return
true
,
nil
if
isok
==
nil
{
}
return
false
,
nil
if
mr
.
pattern
==
"*"
{
return
true
,
nil
}
if
router
==
mr
.
pattern
{
return
true
,
nil
}
}
//pattern /admin router /admin/ match
if
isok
,
ok
:=
isok
.
(
bool
);
ok
{
//pattern /admin/ router /admin don't match, because url will 301 in router
return
isok
,
params
if
n
:=
len
(
router
);
n
>
1
&&
router
[
n
-
1
]
==
'/'
&&
router
[
:
n
-
2
]
==
mr
.
pattern
{
}
else
{
return
true
,
nil
return
false
,
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
}
}
filter_test.go
View file @
e00eab7f
...
@@ -22,7 +22,7 @@ func TestFilter(t *testing.T) {
...
@@ -22,7 +22,7 @@ func TestFilter(t *testing.T) {
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/person/asta/Xie"
,
nil
)
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/person/asta/Xie"
,
nil
)
w
:=
httptest
.
NewRecorder
()
w
:=
httptest
.
NewRecorder
()
handler
:=
NewControllerRegistor
()
handler
:=
NewControllerRegistor
()
handler
.
AddFilter
(
"/person/:last/:first"
,
"AfterStatic"
,
FilterUser
)
handler
.
InsertFilter
(
"/person/:last/:first"
,
BeforeRouter
,
FilterUser
)
handler
.
Add
(
"/person/:last/:first"
,
&
TestController
{})
handler
.
Add
(
"/person/:last/:first"
,
&
TestController
{})
handler
.
ServeHTTP
(
w
,
r
)
handler
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"i am astaXie"
{
if
w
.
Body
.
String
()
!=
"i am astaXie"
{
...
@@ -41,7 +41,7 @@ func TestPatternTwo(t *testing.T) {
...
@@ -41,7 +41,7 @@ func TestPatternTwo(t *testing.T) {
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/admin/"
,
nil
)
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/admin/"
,
nil
)
w
:=
httptest
.
NewRecorder
()
w
:=
httptest
.
NewRecorder
()
handler
:=
NewControllerRegistor
()
handler
:=
NewControllerRegistor
()
handler
.
AddFilter
(
"/admin/:all"
,
"AfterStatic"
,
FilterAdminUser
)
handler
.
InsertFilter
(
"/admin/?:all"
,
BeforeRouter
,
FilterAdminUser
)
handler
.
ServeHTTP
(
w
,
r
)
handler
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"i am admin"
{
if
w
.
Body
.
String
()
!=
"i am admin"
{
t
.
Errorf
(
"filter /admin/ can't run"
)
t
.
Errorf
(
"filter /admin/ can't run"
)
...
@@ -52,7 +52,7 @@ func TestPatternThree(t *testing.T) {
...
@@ -52,7 +52,7 @@ func TestPatternThree(t *testing.T) {
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/admin/astaxie"
,
nil
)
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/admin/astaxie"
,
nil
)
w
:=
httptest
.
NewRecorder
()
w
:=
httptest
.
NewRecorder
()
handler
:=
NewControllerRegistor
()
handler
:=
NewControllerRegistor
()
handler
.
AddFilter
(
"/admin/:all"
,
"AfterStatic"
,
FilterAdminUser
)
handler
.
InsertFilter
(
"/admin/:all"
,
BeforeRouter
,
FilterAdminUser
)
handler
.
ServeHTTP
(
w
,
r
)
handler
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"i am admin"
{
if
w
.
Body
.
String
()
!=
"i am admin"
{
t
.
Errorf
(
"filter /admin/astaxie can't run"
)
t
.
Errorf
(
"filter /admin/astaxie can't run"
)
...
...
namespace.go
View file @
e00eab7f
...
@@ -7,18 +7,17 @@ package beego
...
@@ -7,18 +7,17 @@ package beego
import
(
import
(
"net/http"
"net/http"
"strings"
beecontext
"github.com/astaxie/beego/context"
beecontext
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/middleware"
)
)
type
namespaceCond
func
(
*
beecontext
.
Context
)
bool
type
namespaceCond
func
(
*
beecontext
.
Context
)
bool
// Namespace is store all the info
// Namespace is store all the info
type
Namespace
struct
{
type
Namespace
struct
{
prefix
string
prefix
string
condition
namespaceCond
handlers
*
ControllerRegistor
handlers
*
ControllerRegistor
}
}
// get new Namespace
// get new Namespace
...
@@ -39,8 +38,23 @@ func NewNamespace(prefix string) *Namespace {
...
@@ -39,8 +38,23 @@ func NewNamespace(prefix string) *Namespace {
// }
// }
// return false
// return false
// })
// })
// Cond as the first filter
func
(
n
*
Namespace
)
Cond
(
cond
namespaceCond
)
*
Namespace
{
func
(
n
*
Namespace
)
Cond
(
cond
namespaceCond
)
*
Namespace
{
n
.
condition
=
cond
fn
:=
func
(
ctx
*
beecontext
.
Context
)
{
if
!
cond
(
ctx
)
{
middleware
.
Exception
(
"405"
,
ctx
.
ResponseWriter
,
ctx
.
Request
,
"Method not allowed"
)
}
}
if
v
,
ok
:=
n
.
handlers
.
filters
[
BeforeRouter
];
ok
{
mr
:=
new
(
FilterRouter
)
mr
.
tree
=
NewTree
()
mr
.
pattern
=
"*"
mr
.
filterFunc
=
fn
mr
.
tree
.
AddRouter
(
"*"
,
true
)
n
.
handlers
.
filters
[
BeforeRouter
]
=
append
([]
*
FilterRouter
{
mr
},
v
...
)
}
else
{
n
.
handlers
.
InsertFilter
(
"*"
,
BeforeRouter
,
fn
)
}
return
n
return
n
}
}
...
@@ -55,12 +69,13 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace {
...
@@ -55,12 +69,13 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace {
// }
// }
// })
// })
func
(
n
*
Namespace
)
Filter
(
action
string
,
filter
FilterFunc
)
*
Namespace
{
func
(
n
*
Namespace
)
Filter
(
action
string
,
filter
FilterFunc
)
*
Namespace
{
var
a
int
if
action
==
"before"
{
if
action
==
"before"
{
a
ction
=
"BeforeRouter"
a
=
BeforeRouter
}
else
if
action
==
"after"
{
}
else
if
action
==
"after"
{
a
ction
=
"FinishRouter"
a
=
FinishRouter
}
}
n
.
handlers
.
AddFilter
(
"*"
,
action
,
filter
)
n
.
handlers
.
InsertFilter
(
"*"
,
a
,
filter
)
return
n
return
n
}
}
...
@@ -167,39 +182,35 @@ func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
...
@@ -167,39 +182,35 @@ func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
//)
//)
func
(
n
*
Namespace
)
Namespace
(
ns
...*
Namespace
)
*
Namespace
{
func
(
n
*
Namespace
)
Namespace
(
ns
...*
Namespace
)
*
Namespace
{
for
_
,
ni
:=
range
ns
{
for
_
,
ni
:=
range
ns
{
n
.
handlers
.
Handler
(
ni
.
prefix
,
ni
,
true
)
n
.
handlers
.
routers
.
AddTree
(
ni
.
prefix
,
ni
.
handlers
.
routers
)
if
n
.
handlers
.
enableFilter
{
for
pos
,
filterList
:=
range
ni
.
handlers
.
filters
{
for
_
,
mr
:=
range
filterList
{
t
:=
NewTree
()
t
.
AddTree
(
ni
.
prefix
,
mr
.
tree
)
mr
.
tree
=
t
n
.
handlers
.
insertFilterRouter
(
pos
,
mr
)
}
}
}
}
}
return
n
return
n
}
}
// Namespace implement the http.Handler
func
(
n
*
Namespace
)
ServeHTTP
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
//trim the preifix from URL.Path
r
.
URL
.
Path
=
strings
.
TrimPrefix
(
r
.
URL
.
Path
,
n
.
prefix
)
// init context
context
:=
&
beecontext
.
Context
{
ResponseWriter
:
rw
,
Request
:
r
,
Input
:
beecontext
.
NewInput
(
r
),
Output
:
beecontext
.
NewOutput
(),
}
context
.
Output
.
Context
=
context
context
.
Output
.
EnableGzip
=
EnableGzip
if
context
.
Input
.
IsWebsocket
()
{
context
.
ResponseWriter
=
rw
}
if
n
.
condition
!=
nil
&&
!
n
.
condition
(
context
)
{
http
.
Error
(
rw
,
"Method Not Allowed"
,
405
)
return
}
n
.
handlers
.
ServeHTTP
(
rw
,
r
)
}
// register Namespace into beego.Handler
// register Namespace into beego.Handler
// support multi Namespace
// support multi Namespace
func
AddNamespace
(
nl
...*
Namespace
)
{
func
AddNamespace
(
nl
...*
Namespace
)
{
for
_
,
n
:=
range
nl
{
for
_
,
n
:=
range
nl
{
Handler
(
n
.
prefix
,
n
,
true
)
BeeApp
.
Handlers
.
routers
.
AddTree
(
n
.
prefix
,
n
.
handlers
.
routers
)
if
n
.
handlers
.
enableFilter
{
for
pos
,
filterList
:=
range
n
.
handlers
.
filters
{
for
_
,
mr
:=
range
filterList
{
t
:=
NewTree
()
t
.
AddTree
(
n
.
prefix
,
mr
.
tree
)
mr
.
tree
=
t
BeeApp
.
Handlers
.
insertFilterRouter
(
pos
,
mr
)
}
}
}
}
}
}
}
namespace_test.go
View file @
e00eab7f
...
@@ -23,7 +23,8 @@ func TestNamespaceGet(t *testing.T) {
...
@@ -23,7 +23,8 @@ func TestNamespaceGet(t *testing.T) {
ns
.
Get
(
"/user"
,
func
(
ctx
*
context
.
Context
)
{
ns
.
Get
(
"/user"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
"v1_user"
))
ctx
.
Output
.
Body
([]
byte
(
"v1_user"
))
})
})
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"v1_user"
{
if
w
.
Body
.
String
()
!=
"v1_user"
{
t
.
Errorf
(
"TestNamespaceGet can't run, get the response is "
+
w
.
Body
.
String
())
t
.
Errorf
(
"TestNamespaceGet can't run, get the response is "
+
w
.
Body
.
String
())
}
}
...
@@ -37,7 +38,8 @@ func TestNamespacePost(t *testing.T) {
...
@@ -37,7 +38,8 @@ func TestNamespacePost(t *testing.T) {
ns
.
Post
(
"/user/:id"
,
func
(
ctx
*
context
.
Context
)
{
ns
.
Post
(
"/user/:id"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
})
})
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"123"
{
if
w
.
Body
.
String
()
!=
"123"
{
t
.
Errorf
(
"TestNamespacePost can't run, get the response is "
+
w
.
Body
.
String
())
t
.
Errorf
(
"TestNamespacePost can't run, get the response is "
+
w
.
Body
.
String
())
}
}
...
@@ -54,7 +56,8 @@ func TestNamespaceNest(t *testing.T) {
...
@@ -54,7 +56,8 @@ func TestNamespaceNest(t *testing.T) {
ctx
.
Output
.
Body
([]
byte
(
"order"
))
ctx
.
Output
.
Body
([]
byte
(
"order"
))
}),
}),
)
)
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"order"
{
if
w
.
Body
.
String
()
!=
"order"
{
t
.
Errorf
(
"TestNamespaceNest can't run, get the response is "
+
w
.
Body
.
String
())
t
.
Errorf
(
"TestNamespaceNest can't run, get the response is "
+
w
.
Body
.
String
())
}
}
...
@@ -71,36 +74,21 @@ func TestNamespaceNestParam(t *testing.T) {
...
@@ -71,36 +74,21 @@ func TestNamespaceNestParam(t *testing.T) {
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
}),
}),
)
)
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"123"
{
if
w
.
Body
.
String
()
!=
"123"
{
t
.
Errorf
(
"TestNamespaceNestParam can't run, get the response is "
+
w
.
Body
.
String
())
t
.
Errorf
(
"TestNamespaceNestParam can't run, get the response is "
+
w
.
Body
.
String
())
}
}
}
}
func
TestNamespaceFilter
(
t
*
testing
.
T
)
{
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v1/user/123"
,
nil
)
w
:=
httptest
.
NewRecorder
()
ns
:=
NewNamespace
(
"/v1"
)
ns
.
Filter
(
"before"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
"this is Filter"
))
})
.
Get
(
"/user/:id"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
})
ns
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"this is Filter"
{
t
.
Errorf
(
"TestNamespaceFilter can't run, get the response is "
+
w
.
Body
.
String
())
}
}
func
TestNamespaceRouter
(
t
*
testing
.
T
)
{
func
TestNamespaceRouter
(
t
*
testing
.
T
)
{
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v1/api/list"
,
nil
)
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v1/api/list"
,
nil
)
w
:=
httptest
.
NewRecorder
()
w
:=
httptest
.
NewRecorder
()
ns
:=
NewNamespace
(
"/v1"
)
ns
:=
NewNamespace
(
"/v1"
)
ns
.
Router
(
"/api/list"
,
&
TestController
{},
"*:List"
)
ns
.
Router
(
"/api/list"
,
&
TestController
{},
"*:List"
)
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"i am list"
{
if
w
.
Body
.
String
()
!=
"i am list"
{
t
.
Errorf
(
"TestNamespaceRouter can't run, get the response is "
+
w
.
Body
.
String
())
t
.
Errorf
(
"TestNamespaceRouter can't run, get the response is "
+
w
.
Body
.
String
())
}
}
...
@@ -112,17 +100,36 @@ func TestNamespaceAutoFunc(t *testing.T) {
...
@@ -112,17 +100,36 @@ func TestNamespaceAutoFunc(t *testing.T) {
ns
:=
NewNamespace
(
"/v1"
)
ns
:=
NewNamespace
(
"/v1"
)
ns
.
AutoRouter
(
&
TestController
{})
ns
.
AutoRouter
(
&
TestController
{})
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"i am list"
{
if
w
.
Body
.
String
()
!=
"i am list"
{
t
.
Errorf
(
"user define func can't run"
)
t
.
Errorf
(
"user define func can't run"
)
}
}
}
}
func
TestNamespace
Cond
(
t
*
testing
.
T
)
{
func
TestNamespace
Filter
(
t
*
testing
.
T
)
{
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v1/
test/list
"
,
nil
)
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v1/
user/123
"
,
nil
)
w
:=
httptest
.
NewRecorder
()
w
:=
httptest
.
NewRecorder
()
ns
:=
NewNamespace
(
"/v1"
)
ns
:=
NewNamespace
(
"/v1"
)
ns
.
Filter
(
"before"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
"this is Filter"
))
})
.
Get
(
"/user/:id"
,
func
(
ctx
*
context
.
Context
)
{
ctx
.
Output
.
Body
([]
byte
(
ctx
.
Input
.
Param
(
":id"
)))
})
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Body
.
String
()
!=
"this is Filter"
{
t
.
Errorf
(
"TestNamespaceFilter can't run, get the response is "
+
w
.
Body
.
String
())
}
}
func
TestNamespaceCond
(
t
*
testing
.
T
)
{
r
,
_
:=
http
.
NewRequest
(
"GET"
,
"/v2/test/list"
,
nil
)
w
:=
httptest
.
NewRecorder
()
ns
:=
NewNamespace
(
"/v2"
)
ns
.
Cond
(
func
(
ctx
*
context
.
Context
)
bool
{
ns
.
Cond
(
func
(
ctx
*
context
.
Context
)
bool
{
if
ctx
.
Input
.
Domain
()
==
"beego.me"
{
if
ctx
.
Input
.
Domain
()
==
"beego.me"
{
return
true
return
true
...
@@ -130,7 +137,8 @@ func TestNamespaceCond(t *testing.T) {
...
@@ -130,7 +137,8 @@ func TestNamespaceCond(t *testing.T) {
return
false
return
false
})
.
})
.
AutoRouter
(
&
TestController
{})
AutoRouter
(
&
TestController
{})
ns
.
ServeHTTP
(
w
,
r
)
AddNamespace
(
ns
)
BeeApp
.
Handlers
.
ServeHTTP
(
w
,
r
)
if
w
.
Code
!=
405
{
if
w
.
Code
!=
405
{
t
.
Errorf
(
"TestNamespaceCond can't run get the result "
+
strconv
.
Itoa
(
w
.
Code
))
t
.
Errorf
(
"TestNamespaceCond can't run get the result "
+
strconv
.
Itoa
(
w
.
Code
))
}
}
...
...
parser.go
0 → 100644
View file @
e00eab7f
// 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
router.go
View file @
e00eab7f
...
@@ -12,9 +12,8 @@ import (
...
@@ -12,9 +12,8 @@ import (
"fmt"
"fmt"
"net"
"net"
"net/http"
"net/http"
"
net/url
"
"
path
"
"reflect"
"reflect"
"regexp"
"runtime"
"runtime"
"strconv"
"strconv"
"strings"
"strings"
...
@@ -29,7 +28,6 @@ import (
...
@@ -29,7 +28,6 @@ import (
const
(
const
(
// default filter execution points
// default filter execution points
BeforeRouter
=
iota
BeforeRouter
=
iota
AfterStatic
BeforeExec
BeforeExec
AfterExec
AfterExec
FinishRouter
FinishRouter
...
@@ -60,34 +58,25 @@ func ExceptMethodAppend(action string) {
...
@@ -60,34 +58,25 @@ func ExceptMethodAppend(action string) {
}
}
type
controllerInfo
struct
{
type
controllerInfo
struct
{
pattern
string
regex
*
regexp
.
Regexp
params
map
[
int
]
string
controllerType
reflect
.
Type
controllerType
reflect
.
Type
methods
map
[
string
]
string
methods
map
[
string
]
string
hasMethod
bool
handler
http
.
Handler
handler
http
.
Handler
runfunction
FilterFunc
runfunction
FilterFunc
routerType
int
routerType
int
isPrefix
bool
}
}
// ControllerRegistor containers registered router rules, controller handlers and filters.
// ControllerRegistor containers registered router rules, controller handlers and filters.
type
ControllerRegistor
struct
{
type
ControllerRegistor
struct
{
routers
[]
*
controllerInfo
// regexp router storage
routers
*
Tree
fixrouters
[]
*
controllerInfo
// fixed router storage
enableFilter
bool
enableFilter
bool
filters
map
[
int
][]
*
FilterRouter
filters
map
[
int
][]
*
FilterRouter
enableAuto
bool
autoRouter
map
[
string
]
map
[
string
]
reflect
.
Type
//key:controller key:method value:reflect.type
}
}
// NewControllerRegistor returns a new ControllerRegistor.
// NewControllerRegistor returns a new ControllerRegistor.
func
NewControllerRegistor
()
*
ControllerRegistor
{
func
NewControllerRegistor
()
*
ControllerRegistor
{
return
&
ControllerRegistor
{
return
&
ControllerRegistor
{
routers
:
make
([]
*
controllerInfo
,
0
),
routers
:
NewTree
(),
autoRouter
:
make
(
map
[
string
]
map
[
string
]
reflect
.
Type
),
filters
:
make
(
map
[
int
][]
*
FilterRouter
),
filters
:
make
(
map
[
int
][]
*
FilterRouter
),
}
}
}
}
...
@@ -102,7 +91,6 @@ func NewControllerRegistor() *ControllerRegistor {
...
@@ -102,7 +91,6 @@ func NewControllerRegistor() *ControllerRegistor {
// Add("/api",&RestController{},"get,post:ApiFunc")
// Add("/api",&RestController{},"get,post:ApiFunc")
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func
(
p
*
ControllerRegistor
)
Add
(
pattern
string
,
c
ControllerInterface
,
mappingMethods
...
string
)
{
func
(
p
*
ControllerRegistor
)
Add
(
pattern
string
,
c
ControllerInterface
,
mappingMethods
...
string
)
{
j
,
params
,
parts
:=
p
.
splitRoute
(
pattern
)
reflectVal
:=
reflect
.
ValueOf
(
c
)
reflectVal
:=
reflect
.
ValueOf
(
c
)
t
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
t
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
methods
:=
make
(
map
[
string
]
string
)
methods
:=
make
(
map
[
string
]
string
)
...
@@ -127,40 +115,23 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
...
@@ -127,40 +115,23 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
}
}
}
}
}
}
if
j
==
0
{
//now create the Route
route
:=
&
controllerInfo
{}
route
.
pattern
=
pattern
route
.
controllerType
=
t
route
.
methods
=
methods
route
.
routerType
=
routerTypeBeego
if
len
(
methods
)
>
0
{
route
.
hasMethod
=
true
}
p
.
fixrouters
=
append
(
p
.
fixrouters
,
route
)
}
else
{
// add regexp routers
//recreate the url pattern, with parameters replaced
//by regular expressions. then compile the regex
pattern
=
strings
.
Join
(
parts
,
"/"
)
regex
,
regexErr
:=
regexp
.
Compile
(
pattern
)
if
regexErr
!=
nil
{
//TODO add error handling here to avoid panic
panic
(
regexErr
)
}
//now create the Route
route
:=
&
controllerInfo
{}
route
.
methods
=
methods
route
.
routerType
=
routerTypeBeego
route
.
controllerType
=
t
p
.
routers
.
AddRouter
(
pattern
,
route
)
}
route
:=
&
controllerInfo
{}
// only when the Runmode is dev will generate router file in the router/auto.go from the controller
route
.
regex
=
regex
// Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
route
.
params
=
params
func
(
p
*
ControllerRegistor
)
Include
(
cList
...
ControllerInterface
)
{
route
.
pattern
=
pattern
if
RunMode
==
"dev"
{
route
.
methods
=
methods
for
_
,
c
:=
range
cList
{
route
.
routerType
=
routerTypeBeego
reflectVal
:=
reflect
.
ValueOf
(
c
)
if
len
(
methods
)
>
0
{
t
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
route
.
hasMethod
=
true
t
.
PkgPath
()
}
}
route
.
controllerType
=
t
p
.
routers
=
append
(
p
.
routers
,
route
)
}
}
}
}
...
@@ -257,146 +228,20 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
...
@@ -257,146 +228,20 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
methods
[
method
]
=
method
methods
[
method
]
=
method
}
}
route
.
methods
=
methods
route
.
methods
=
methods
paramnums
,
params
,
parts
:=
p
.
splitRoute
(
pattern
)
p
.
routers
.
AddRouter
(
pattern
,
route
)
if
paramnums
==
0
{
//now create the Route
route
.
pattern
=
pattern
p
.
fixrouters
=
append
(
p
.
fixrouters
,
route
)
}
else
{
//recreate the url pattern, with parameters replaced
//by regular expressions. then compile the regex
pattern
=
strings
.
Join
(
parts
,
"/"
)
regex
,
regexErr
:=
regexp
.
Compile
(
pattern
)
if
regexErr
!=
nil
{
panic
(
regexErr
)
}
//now create the Route
route
.
regex
=
regex
route
.
params
=
params
route
.
pattern
=
pattern
p
.
routers
=
append
(
p
.
routers
,
route
)
}
}
}
// add user defined Handler
func
(
p
*
ControllerRegistor
)
Handler
(
pattern
string
,
h
http
.
Handler
,
options
...
interface
{})
{
func
(
p
*
ControllerRegistor
)
Handler
(
pattern
string
,
h
http
.
Handler
,
options
...
interface
{})
{
paramnums
,
params
,
parts
:=
p
.
splitRoute
(
pattern
)
route
:=
&
controllerInfo
{}
route
:=
&
controllerInfo
{}
route
.
routerType
=
routerTypeHandler
route
.
routerType
=
routerTypeHandler
route
.
handler
=
h
route
.
handler
=
h
if
len
(
options
)
>
0
{
if
len
(
options
)
>
0
{
if
v
,
ok
:=
options
[
0
]
.
(
bool
);
ok
{
if
_
,
ok
:=
options
[
0
]
.
(
bool
);
ok
{
route
.
isPrefix
=
v
pattern
=
path
.
Join
(
pattern
,
"?:all"
)
}
}
if
paramnums
==
0
{
route
.
pattern
=
pattern
p
.
fixrouters
=
append
(
p
.
fixrouters
,
route
)
}
else
{
//recreate the url pattern, with parameters replaced
//by regular expressions. then compile the regex
pattern
=
strings
.
Join
(
parts
,
"/"
)
regex
,
regexErr
:=
regexp
.
Compile
(
pattern
)
if
regexErr
!=
nil
{
panic
(
regexErr
)
}
//now create the Route
route
.
regex
=
regex
route
.
params
=
params
route
.
pattern
=
pattern
p
.
routers
=
append
(
p
.
routers
,
route
)
}
}
// analisys the patter to params & parts
func
(
p
*
ControllerRegistor
)
splitRoute
(
pattern
string
)
(
paramnums
int
,
params
map
[
int
]
string
,
parts
[]
string
)
{
parts
=
strings
.
Split
(
pattern
,
"/"
)
j
:=
0
params
=
make
(
map
[
int
]
string
)
for
i
,
part
:=
range
parts
{
if
strings
.
HasPrefix
(
part
,
":"
)
{
expr
:=
"(.*)"
//a user may choose to override the defult 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
]
}
//marth /user/:id! non-empty value
}
else
if
part
[
len
(
part
)
-
1
]
==
'!'
{
expr
=
`(.+)`
part
=
part
[
:
len
(
part
)
-
1
]
}
params
[
j
]
=
part
parts
[
i
]
=
expr
j
++
}
if
strings
.
HasPrefix
(
part
,
"*"
)
{
expr
:=
"(.*)"
if
part
==
"*.*"
{
params
[
j
]
=
":path"
parts
[
i
]
=
`([^.]+)\.([^.]+)`
j
++
params
[
j
]
=
":ext"
j
++
}
else
{
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
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
)
}
}
}
}
return
j
,
params
,
parts
p
.
routers
.
AddRouter
(
pattern
,
route
)
}
}
// Add auto router to ControllerRegistor.
// Add auto router to ControllerRegistor.
...
@@ -405,21 +250,7 @@ func (p *ControllerRegistor) splitRoute(pattern string) (paramnums int, params m
...
@@ -405,21 +250,7 @@ func (p *ControllerRegistor) splitRoute(pattern string) (paramnums int, params m
// visit the url /main/list to execute List function
// visit the url /main/list to execute List function
// /main/page to execute Page function.
// /main/page to execute Page function.
func
(
p
*
ControllerRegistor
)
AddAuto
(
c
ControllerInterface
)
{
func
(
p
*
ControllerRegistor
)
AddAuto
(
c
ControllerInterface
)
{
p
.
enableAuto
=
true
p
.
AddAutoPrefix
(
"/"
,
c
)
reflectVal
:=
reflect
.
ValueOf
(
c
)
rt
:=
reflectVal
.
Type
()
ct
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
firstParam
:=
strings
.
ToLower
(
strings
.
TrimSuffix
(
ct
.
Name
(),
"Controller"
))
if
_
,
ok
:=
p
.
autoRouter
[
firstParam
];
ok
{
return
}
else
{
p
.
autoRouter
[
firstParam
]
=
make
(
map
[
string
]
reflect
.
Type
)
}
for
i
:=
0
;
i
<
rt
.
NumMethod
();
i
++
{
if
!
utils
.
InSlice
(
rt
.
Method
(
i
)
.
Name
,
exceptMethod
)
{
p
.
autoRouter
[
firstParam
][
rt
.
Method
(
i
)
.
Name
]
=
ct
}
}
}
}
// Add auto router to ControllerRegistor with prefix.
// Add auto router to ControllerRegistor with prefix.
...
@@ -428,78 +259,39 @@ func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
...
@@ -428,78 +259,39 @@ func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
// visit the url /admin/main/list to execute List function
// visit the url /admin/main/list to execute List function
// /admin/main/page to execute Page function.
// /admin/main/page to execute Page function.
func
(
p
*
ControllerRegistor
)
AddAutoPrefix
(
prefix
string
,
c
ControllerInterface
)
{
func
(
p
*
ControllerRegistor
)
AddAutoPrefix
(
prefix
string
,
c
ControllerInterface
)
{
p
.
enableAuto
=
true
reflectVal
:=
reflect
.
ValueOf
(
c
)
reflectVal
:=
reflect
.
ValueOf
(
c
)
rt
:=
reflectVal
.
Type
()
rt
:=
reflectVal
.
Type
()
ct
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
ct
:=
reflect
.
Indirect
(
reflectVal
)
.
Type
()
firstParam
:=
strings
.
Trim
(
prefix
,
"/"
)
+
"/"
+
strings
.
ToLower
(
strings
.
TrimSuffix
(
ct
.
Name
(),
"Controller"
))
controllerName
:=
strings
.
ToLower
(
strings
.
TrimSuffix
(
ct
.
Name
(),
"Controller"
))
if
_
,
ok
:=
p
.
autoRouter
[
firstParam
];
ok
{
return
}
else
{
p
.
autoRouter
[
firstParam
]
=
make
(
map
[
string
]
reflect
.
Type
)
}
for
i
:=
0
;
i
<
rt
.
NumMethod
();
i
++
{
for
i
:=
0
;
i
<
rt
.
NumMethod
();
i
++
{
if
!
utils
.
InSlice
(
rt
.
Method
(
i
)
.
Name
,
exceptMethod
)
{
if
!
utils
.
InSlice
(
rt
.
Method
(
i
)
.
Name
,
exceptMethod
)
{
p
.
autoRouter
[
firstParam
][
rt
.
Method
(
i
)
.
Name
]
=
ct
route
:=
&
controllerInfo
{}
route
.
routerType
=
routerTypeBeego
route
.
methods
=
map
[
string
]
string
{
"*"
:
rt
.
Method
(
i
)
.
Name
}
route
.
controllerType
=
ct
pattern
:=
path
.
Join
(
prefix
,
controllerName
,
strings
.
ToLower
(
rt
.
Method
(
i
)
.
Name
),
"*"
)
p
.
routers
.
AddRouter
(
pattern
,
route
)
}
}
}
}
}
}
// [Deprecated] use InsertFilter.
// Add FilterFunc with pattern for action.
func
(
p
*
ControllerRegistor
)
AddFilter
(
pattern
,
action
string
,
filter
FilterFunc
)
error
{
mr
,
err
:=
p
.
buildFilter
(
pattern
,
filter
)
if
err
!=
nil
{
return
err
}
switch
action
{
case
"BeforeRouter"
:
p
.
filters
[
BeforeRouter
]
=
append
(
p
.
filters
[
BeforeRouter
],
mr
)
case
"AfterStatic"
:
p
.
filters
[
AfterStatic
]
=
append
(
p
.
filters
[
AfterStatic
],
mr
)
case
"BeforeExec"
:
p
.
filters
[
BeforeExec
]
=
append
(
p
.
filters
[
BeforeExec
],
mr
)
case
"AfterExec"
:
p
.
filters
[
AfterExec
]
=
append
(
p
.
filters
[
AfterExec
],
mr
)
case
"FinishRouter"
:
p
.
filters
[
FinishRouter
]
=
append
(
p
.
filters
[
FinishRouter
],
mr
)
}
p
.
enableFilter
=
true
return
nil
}
// Add a FilterFunc with pattern rule and action constant.
// Add a FilterFunc with pattern rule and action constant.
func
(
p
*
ControllerRegistor
)
InsertFilter
(
pattern
string
,
pos
int
,
filter
FilterFunc
)
error
{
func
(
p
*
ControllerRegistor
)
InsertFilter
(
pattern
string
,
pos
int
,
filter
FilterFunc
)
error
{
mr
,
err
:=
p
.
buildFilter
(
pattern
,
filter
)
mr
:=
new
(
FilterRouter
)
if
err
!=
nil
{
mr
.
tree
=
NewTree
()
return
err
mr
.
pattern
=
pattern
}
mr
.
filterFunc
=
filter
mr
.
tree
.
AddRouter
(
pattern
,
true
)
return
p
.
insertFilterRouter
(
pos
,
mr
)
}
// add Filter into
func
(
p
*
ControllerRegistor
)
insertFilterRouter
(
pos
int
,
mr
*
FilterRouter
)
error
{
p
.
filters
[
pos
]
=
append
(
p
.
filters
[
pos
],
mr
)
p
.
filters
[
pos
]
=
append
(
p
.
filters
[
pos
],
mr
)
p
.
enableFilter
=
true
p
.
enableFilter
=
true
return
nil
return
nil
}
}
// build the Filter by pattern
func
(
p
*
ControllerRegistor
)
buildFilter
(
pattern
string
,
filter
FilterFunc
)
(
*
FilterRouter
,
error
)
{
mr
:=
new
(
FilterRouter
)
mr
.
params
=
make
(
map
[
int
]
string
)
mr
.
filterFunc
=
filter
j
,
params
,
parts
:=
p
.
splitRoute
(
pattern
)
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
.
params
=
params
mr
.
pattern
=
pattern
return
mr
,
nil
}
// UrlFor does another controller handler in this request function.
// UrlFor does another controller handler in this request function.
// it can access any controller method.
// it can access any controller method.
func
(
p
*
ControllerRegistor
)
UrlFor
(
endpoint
string
,
values
...
string
)
string
{
func
(
p
*
ControllerRegistor
)
UrlFor
(
endpoint
string
,
values
...
string
)
string
{
...
@@ -512,170 +304,135 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string {
...
@@ -512,170 +304,135 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string {
Warn
(
"urlfor params must key-value pair"
)
Warn
(
"urlfor params must key-value pair"
)
return
""
return
""
}
}
urlv
:=
url
.
Values
{}
params
:=
make
(
map
[
string
]
string
)
if
len
(
values
)
>
0
{
if
len
(
values
)
>
0
{
key
:=
""
key
:=
""
for
k
,
v
:=
range
values
{
for
k
,
v
:=
range
values
{
if
k
%
2
==
0
{
if
k
%
2
==
0
{
key
=
v
key
=
v
}
else
{
}
else
{
urlv
.
Set
(
key
,
v
)
params
[
key
]
=
v
}
}
}
}
}
}
controllName
:=
strings
.
Join
(
paths
[
:
len
(
paths
)
-
1
],
"."
)
controllName
:=
strings
.
Join
(
paths
[
:
len
(
paths
)
-
1
],
"."
)
methodName
:=
paths
[
len
(
paths
)
-
1
]
methodName
:=
paths
[
len
(
paths
)
-
1
]
for
_
,
route
:=
range
p
.
routers
{
ok
,
url
:=
p
.
geturl
(
p
.
routers
,
"/"
,
controllName
,
methodName
,
params
)
if
route
.
controllerType
.
Name
()
==
controllName
{
if
ok
{
var
finded
bool
return
url
if
utils
.
InSlice
(
strings
.
ToLower
(
methodName
),
HTTPMETHOD
)
{
}
else
{
if
route
.
hasMethod
{
return
""
if
m
,
ok
:=
route
.
methods
[
strings
.
ToLower
(
methodName
)];
ok
&&
m
!=
methodName
{
finded
=
false
}
else
if
m
,
ok
=
route
.
methods
[
"*"
];
ok
&&
m
!=
methodName
{
finded
=
false
}
else
{
finded
=
true
}
}
else
{
finded
=
true
}
}
else
if
route
.
hasMethod
{
for
_
,
md
:=
range
route
.
methods
{
if
md
==
methodName
{
finded
=
true
}
}
}
if
!
finded
{
continue
}
var
returnurl
string
var
i
int
var
startreg
bool
for
_
,
v
:=
range
route
.
regex
.
String
()
{
if
v
==
'('
{
startreg
=
true
continue
}
else
if
v
==
')'
{
startreg
=
false
returnurl
=
returnurl
+
urlv
.
Get
(
route
.
params
[
i
])
i
++
}
else
if
!
startreg
{
returnurl
=
string
(
append
([]
rune
(
returnurl
),
v
))
}
}
if
route
.
regex
.
MatchString
(
returnurl
)
{
return
returnurl
}
}
}
}
for
_
,
route
:=
range
p
.
fixrouters
{
}
if
route
.
controllerType
.
Name
()
==
controllName
{
var
finded
bool
func
(
p
*
ControllerRegistor
)
geturl
(
t
*
Tree
,
url
,
controllName
,
methodName
string
,
params
map
[
string
]
string
)
(
bool
,
string
)
{
if
utils
.
InSlice
(
strings
.
ToLower
(
methodName
),
HTTPMETHOD
)
{
for
k
,
subtree
:=
range
t
.
fixrouters
{
if
route
.
hasMethod
{
u
:=
path
.
Join
(
url
,
k
)
if
m
,
ok
:=
route
.
methods
[
strings
.
ToLower
(
methodName
)];
ok
&&
m
!=
methodName
{
ok
,
u
:=
p
.
geturl
(
subtree
,
u
,
controllName
,
methodName
,
params
)
finded
=
false
if
ok
{
}
else
if
m
,
ok
=
route
.
methods
[
"*"
];
ok
&&
m
!=
methodName
{
return
ok
,
u
finded
=
false
}
}
if
t
.
wildcard
!=
nil
{
ok
,
u
:=
p
.
geturl
(
t
.
wildcard
,
url
,
controllName
,
methodName
,
params
)
if
ok
{
return
ok
,
u
}
}
if
t
.
leaf
!=
nil
{
if
c
,
ok
:=
t
.
leaf
.
runObject
.
(
*
controllerInfo
);
ok
{
if
c
.
routerType
==
routerTypeBeego
&&
c
.
controllerType
.
Name
()
==
controllName
{
find
:=
false
if
utils
.
InSlice
(
strings
.
ToLower
(
methodName
),
HTTPMETHOD
)
{
if
m
,
ok
:=
c
.
methods
[
strings
.
ToLower
(
methodName
)];
ok
&&
m
!=
methodName
{
return
false
,
""
}
else
if
m
,
ok
=
c
.
methods
[
"*"
];
ok
&&
m
!=
methodName
{
return
false
,
""
}
else
{
}
else
{
find
ed
=
true
find
=
true
}
}
}
else
{
}
else
{
finded
=
true
for
_
,
md
:=
range
c
.
methods
{
}
if
md
==
methodName
{
}
else
if
route
.
hasMethod
{
find
=
true
for
_
,
md
:=
range
route
.
methods
{
}
if
md
==
methodName
{
finded
=
true
}
}
}
if
!
finded
{
continue
}
if
len
(
values
)
>
0
{
return
route
.
pattern
+
"?"
+
urlv
.
Encode
()
}
return
route
.
pattern
}
}
if
p
.
enableAuto
{
for
cName
,
methodList
:=
range
p
.
autoRouter
{
if
strings
.
ToLower
(
strings
.
TrimSuffix
(
paths
[
len
(
paths
)
-
2
],
"Controller"
))
==
cName
{
if
_
,
ok
:=
methodList
[
methodName
];
ok
{
if
len
(
values
)
>
0
{
return
"/"
+
strings
.
TrimSuffix
(
paths
[
len
(
paths
)
-
2
],
"Controller"
)
+
"/"
+
methodName
+
"?"
+
urlv
.
Encode
()
}
else
{
return
"/"
+
strings
.
TrimSuffix
(
paths
[
len
(
paths
)
-
2
],
"Controller"
)
+
"/"
+
methodName
}
}
}
}
}
if
find
{
}
if
t
.
leaf
.
regexps
==
nil
{
}
if
len
(
t
.
leaf
.
wildcards
)
==
0
{
return
""
return
true
,
url
}
}
if
len
(
t
.
leaf
.
wildcards
)
==
1
{
// Implement http.Handler interface.
if
v
,
ok
:=
params
[
t
.
leaf
.
wildcards
[
0
]];
ok
{
func
(
p
*
ControllerRegistor
)
ServeHTTP
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
delete
(
params
,
t
.
leaf
.
wildcards
[
0
])
defer
func
()
{
return
true
,
url
+
"/"
+
v
+
tourl
(
params
)
if
err
:=
recover
();
err
!=
nil
{
}
if
err
==
USERSTOPRUN
{
if
t
.
leaf
.
wildcards
[
0
]
==
":splat"
{
return
return
true
,
url
+
tourl
(
params
)
}
if
_
,
ok
:=
err
.
(
middleware
.
HTTPException
);
ok
{
// catch intented errors, only for HTTP 4XX and 5XX
}
else
{
if
RunMode
==
"dev"
{
if
!
RecoverPanic
{
panic
(
err
)
}
else
{
if
ErrorsShow
{
if
handler
,
ok
:=
middleware
.
ErrorMaps
[
fmt
.
Sprint
(
err
)];
ok
{
handler
(
rw
,
r
)
return
}
}
}
}
var
stack
string
if
len
(
t
.
leaf
.
wildcards
)
==
3
&&
t
.
leaf
.
wildcards
[
0
]
==
"."
{
Critical
(
"the request url is "
,
r
.
URL
.
Path
)
if
p
,
ok
:=
params
[
":path"
];
ok
{
Critical
(
"Handler crashed with error"
,
err
)
if
e
,
isok
:=
params
[
":ext"
];
isok
{
for
i
:=
1
;
;
i
++
{
delete
(
params
,
":path"
)
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
i
)
delete
(
params
,
":ext"
)
if
!
ok
{
return
true
,
url
+
"/"
+
p
+
"."
+
e
+
tourl
(
params
)
break
}
}
}
Critical
(
file
,
line
)
stack
=
stack
+
fmt
.
Sprintln
(
file
,
line
)
}
}
middleware
.
ShowErr
(
err
,
rw
,
r
,
stack
)
canskip
:=
false
}
for
_
,
v
:=
range
t
.
leaf
.
wildcards
{
}
else
{
if
v
==
":"
{
if
!
RecoverPanic
{
canskip
=
true
panic
(
err
)
continue
}
if
u
,
ok
:=
params
[
v
];
ok
{
url
+=
"/"
+
u
}
else
{
if
canskip
{
canskip
=
false
continue
}
else
{
return
false
,
""
}
}
}
return
true
,
url
}
else
{
}
else
{
// in production model show all infomation
var
i
int
if
ErrorsShow
{
var
startreg
bool
handler
:=
p
.
getErrorHandler
(
fmt
.
Sprint
(
err
))
url
=
url
+
"/"
handler
(
rw
,
r
)
for
_
,
v
:=
range
t
.
leaf
.
regexps
.
String
()
{
return
if
v
==
'('
{
}
else
{
startreg
=
true
Critical
(
"the request url is "
,
r
.
URL
.
Path
)
continue
Critical
(
"Handler crashed with error"
,
err
)
}
else
if
v
==
')'
{
for
i
:=
1
;
;
i
++
{
startreg
=
false
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
i
)
if
v
,
ok
:=
params
[
t
.
leaf
.
wildcards
[
i
]];
ok
{
if
!
ok
{
url
=
url
+
v
i
++
}
else
{
break
break
}
}
Critical
(
file
,
line
)
}
else
if
!
startreg
{
url
=
string
(
append
([]
rune
(
url
),
v
))
}
}
}
}
if
t
.
leaf
.
regexps
.
MatchString
(
url
)
{
return
true
,
url
}
}
}
}
}
}
}
}
}
}()
}
return
false
,
""
}
// Implement http.Handler interface.
func
(
p
*
ControllerRegistor
)
ServeHTTP
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
defer
p
.
recoverPanic
(
rw
,
r
)
starttime
:=
time
.
Now
()
starttime
:=
time
.
Now
()
requestPath
:=
r
.
URL
.
Path
requestPath
:=
r
.
URL
.
Path
...
@@ -683,7 +440,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
...
@@ -683,7 +440,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
var
findrouter
bool
var
findrouter
bool
var
runMethod
string
var
runMethod
string
var
routerInfo
*
controllerInfo
var
routerInfo
*
controllerInfo
params
:=
make
(
map
[
string
]
string
)
w
:=
&
responseWriter
{
writer
:
rw
}
w
:=
&
responseWriter
{
writer
:
rw
}
w
.
Header
()
.
Set
(
"Server"
,
BeegoServerName
)
w
.
Header
()
.
Set
(
"Server"
,
BeegoServerName
)
...
@@ -749,140 +505,24 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
...
@@ -749,140 +505,24 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
goto
Admin
goto
Admin
}
}
if
do_filter
(
AfterStatic
)
{
goto
Admin
}
if
context
.
Input
.
RunController
!=
nil
&&
context
.
Input
.
RunMethod
!=
""
{
if
context
.
Input
.
RunController
!=
nil
&&
context
.
Input
.
RunMethod
!=
""
{
findrouter
=
true
findrouter
=
true
runMethod
=
context
.
Input
.
RunMethod
runMethod
=
context
.
Input
.
RunMethod
runrouter
=
context
.
Input
.
RunController
runrouter
=
context
.
Input
.
RunController
}
}
//first find path from the fixrouters to Improve Performance
if
!
findrouter
{
if
!
findrouter
{
for
_
,
route
:=
range
p
.
fixrouters
{
runObject
,
p
:=
p
.
routers
.
Match
(
requestPath
)
n
:=
len
(
requestPath
)
if
r
,
ok
:=
runObject
.
(
*
controllerInfo
);
ok
{
if
n
==
0
{
routerInfo
=
r
continue
findrouter
=
true
}
if
splat
,
ok
:=
p
[
":splat"
];
ok
{
if
requestPath
==
route
.
pattern
{
splatlist
:=
strings
.
Split
(
splat
,
"/"
)
runMethod
=
p
.
getRunMethod
(
r
.
Method
,
context
,
route
)
for
k
,
v
:=
range
splatlist
{
if
runMethod
!=
""
{
p
[
strconv
.
Itoa
(
k
)]
=
v
routerInfo
=
route
runrouter
=
route
.
controllerType
findrouter
=
true
break
}
}
// pattern /admin url /admin 200 /admin/ 200
// pattern /admin/ url /admin 301 /admin/ 200
if
requestPath
[
n
-
1
]
!=
'/'
&&
requestPath
+
"/"
==
route
.
pattern
{
http
.
Redirect
(
w
,
r
,
requestPath
+
"/"
,
301
)
goto
Admin
}
if
requestPath
[
n
-
1
]
==
'/'
&&
route
.
pattern
+
"/"
==
requestPath
{
runMethod
=
p
.
getRunMethod
(
r
.
Method
,
context
,
route
)
if
runMethod
!=
""
{
routerInfo
=
route
runrouter
=
route
.
controllerType
findrouter
=
true
break
}
}
if
route
.
routerType
==
routerTypeHandler
&&
route
.
isPrefix
&&
strings
.
HasPrefix
(
requestPath
,
route
.
pattern
)
{
routerInfo
=
route
runrouter
=
route
.
controllerType
findrouter
=
true
break
}
}
}
//find regex's router
if
!
findrouter
{
//find a matching Route
for
_
,
route
:=
range
p
.
routers
{
//check if Route pattern matches url
if
!
route
.
regex
.
MatchString
(
requestPath
)
{
continue
}
//get submatches (params)
matches
:=
route
.
regex
.
FindStringSubmatch
(
requestPath
)
//double check that the Route matches the URL pattern.
if
len
(
matches
[
0
])
!=
len
(
requestPath
)
{
continue
}
if
len
(
route
.
params
)
>
0
{
for
i
,
match
:=
range
matches
[
1
:
]
{
params
[
route
.
params
[
i
]]
=
match
}
}
runMethod
=
p
.
getRunMethod
(
r
.
Method
,
context
,
route
)
if
runMethod
!=
""
{
routerInfo
=
route
runrouter
=
route
.
controllerType
context
.
Input
.
Params
=
params
findrouter
=
true
break
}
}
}
if
!
findrouter
&&
p
.
enableAuto
{
// deal with url with diffirent ext
// /controller/simple
// /controller/simple.html
// /controller/simple.json
// /controller/simple.rss
lastindex
:=
strings
.
LastIndex
(
requestPath
,
"/"
)
lastsub
:=
requestPath
[
lastindex
+
1
:
]
if
subindex
:=
strings
.
LastIndex
(
lastsub
,
"."
);
subindex
!=
-
1
{
context
.
Input
.
Params
[
":ext"
]
=
lastsub
[
subindex
+
1
:
]
r
.
URL
.
Query
()
.
Add
(
":ext"
,
lastsub
[
subindex
+
1
:
])
r
.
URL
.
RawQuery
=
r
.
URL
.
Query
()
.
Encode
()
requestPath
=
requestPath
[
:
len
(
requestPath
)
-
len
(
lastsub
[
subindex
:
])]
}
for
cName
,
methodmap
:=
range
p
.
autoRouter
{
// if prev already find the router break
if
findrouter
{
break
}
if
strings
.
ToLower
(
requestPath
)
==
"/"
+
cName
{
http
.
Redirect
(
w
,
r
,
requestPath
+
"/"
,
301
)
goto
Admin
}
// if there's no action, set the default action to index
if
strings
.
ToLower
(
requestPath
)
==
"/"
+
cName
+
"/"
{
requestPath
=
requestPath
+
"index"
}
// if the request path start with controllerName
if
strings
.
HasPrefix
(
strings
.
ToLower
(
requestPath
),
"/"
+
cName
+
"/"
)
{
for
mName
,
controllerType
:=
range
methodmap
{
if
strings
.
ToLower
(
requestPath
)
==
"/"
+
cName
+
"/"
+
strings
.
ToLower
(
mName
)
||
(
strings
.
HasPrefix
(
strings
.
ToLower
(
requestPath
),
"/"
+
cName
+
"/"
+
strings
.
ToLower
(
mName
))
&&
requestPath
[
len
(
"/"
+
cName
+
"/"
+
strings
.
ToLower
(
mName
))
:
len
(
"/"
+
cName
+
"/"
+
strings
.
ToLower
(
mName
))
+
1
]
==
"/"
)
{
runrouter
=
controllerType
runMethod
=
mName
findrouter
=
true
//parse params
otherurl
:=
requestPath
[
len
(
"/"
+
cName
+
"/"
+
strings
.
ToLower
(
mName
))
:
]
if
len
(
otherurl
)
>
1
{
plist
:=
strings
.
Split
(
otherurl
,
"/"
)
for
k
,
v
:=
range
plist
[
1
:
]
{
context
.
Input
.
Params
[
strconv
.
Itoa
(
k
)]
=
v
}
}
break
}
}
}
}
}
context
.
Input
.
Params
=
p
}
}
}
}
...
@@ -910,9 +550,26 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
...
@@ -910,9 +550,26 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
else
if
routerInfo
.
routerType
==
routerTypeHandler
{
}
else
if
routerInfo
.
routerType
==
routerTypeHandler
{
isRunable
=
true
isRunable
=
true
routerInfo
.
handler
.
ServeHTTP
(
rw
,
r
)
routerInfo
.
handler
.
ServeHTTP
(
rw
,
r
)
}
else
{
runrouter
=
routerInfo
.
controllerType
method
:=
strings
.
ToLower
(
r
.
Method
)
if
method
==
"post"
&&
strings
.
ToLower
(
context
.
Input
.
Query
(
"_method"
))
==
"put"
{
method
=
"put"
}
if
method
==
"post"
&&
strings
.
ToLower
(
context
.
Input
.
Query
(
"_method"
))
==
"delete"
{
method
=
"delete"
}
if
m
,
ok
:=
routerInfo
.
methods
[
method
];
ok
{
runMethod
=
m
}
else
if
m
,
ok
=
routerInfo
.
methods
[
"*"
];
ok
{
runMethod
=
m
}
else
{
runMethod
=
strings
.
Title
(
method
)
}
}
}
}
}
// also defined runrouter & runMethod from filter
if
!
isRunable
{
if
!
isRunable
{
//Invoke the request handler
//Invoke the request handler
vc
:=
reflect
.
New
(
runrouter
)
vc
:=
reflect
.
New
(
runrouter
)
...
@@ -981,6 +638,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
...
@@ -981,6 +638,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
}
do_filter
(
FinishRouter
)
do_filter
(
FinishRouter
)
Admin
:
Admin
:
//admin module record QPS
//admin module record QPS
if
EnableAdmin
{
if
EnableAdmin
{
...
@@ -995,6 +653,64 @@ Admin:
...
@@ -995,6 +653,64 @@ Admin:
}
}
}
}
func
(
p
*
ControllerRegistor
)
recoverPanic
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
if
err
:=
recover
();
err
!=
nil
{
if
err
==
USERSTOPRUN
{
return
}
if
_
,
ok
:=
err
.
(
middleware
.
HTTPException
);
ok
{
// catch intented errors, only for HTTP 4XX and 5XX
}
else
{
if
RunMode
==
"dev"
{
if
!
RecoverPanic
{
panic
(
err
)
}
else
{
if
ErrorsShow
{
if
handler
,
ok
:=
middleware
.
ErrorMaps
[
fmt
.
Sprint
(
err
)];
ok
{
handler
(
rw
,
r
)
return
}
}
var
stack
string
Critical
(
"the request url is "
,
r
.
URL
.
Path
)
Critical
(
"Handler crashed with error"
,
err
)
for
i
:=
1
;
;
i
++
{
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
i
)
if
!
ok
{
break
}
Critical
(
file
,
line
)
stack
=
stack
+
fmt
.
Sprintln
(
file
,
line
)
}
middleware
.
ShowErr
(
err
,
rw
,
r
,
stack
)
}
}
else
{
if
!
RecoverPanic
{
panic
(
err
)
}
else
{
// in production model show all infomation
if
ErrorsShow
{
handler
:=
p
.
getErrorHandler
(
fmt
.
Sprint
(
err
))
handler
(
rw
,
r
)
return
}
else
{
Critical
(
"the request url is "
,
r
.
URL
.
Path
)
Critical
(
"Handler crashed with error"
,
err
)
for
i
:=
1
;
;
i
++
{
_
,
file
,
line
,
ok
:=
runtime
.
Caller
(
i
)
if
!
ok
{
break
}
Critical
(
file
,
line
)
}
}
}
}
}
}
}
// there always should be error handler that sets error code accordingly for all unhandled errors.
// there always should be error handler that sets error code accordingly for all unhandled errors.
// in order to have custom UI for error page it's necessary to override "500" error.
// in order to have custom UI for error page it's necessary to override "500" error.
func
(
p
*
ControllerRegistor
)
getErrorHandler
(
errorCode
string
)
func
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
p
*
ControllerRegistor
)
getErrorHandler
(
errorCode
string
)
func
(
rw
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
...
@@ -1013,30 +729,6 @@ func (p *ControllerRegistor) getErrorHandler(errorCode string) func(rw http.Resp
...
@@ -1013,30 +729,6 @@ func (p *ControllerRegistor) getErrorHandler(errorCode string) func(rw http.Resp
return
handler
return
handler
}
}
// returns method name from request header or form field.
// sometimes browsers can't create PUT and DELETE request.
// set a form field "_method" instead.
func
(
p
*
ControllerRegistor
)
getRunMethod
(
method
string
,
context
*
beecontext
.
Context
,
router
*
controllerInfo
)
string
{
method
=
strings
.
ToLower
(
method
)
if
method
==
"post"
&&
strings
.
ToLower
(
context
.
Input
.
Query
(
"_method"
))
==
"put"
{
method
=
"put"
}
if
method
==
"post"
&&
strings
.
ToLower
(
context
.
Input
.
Query
(
"_method"
))
==
"delete"
{
method
=
"delete"
}
if
router
.
hasMethod
{
if
m
,
ok
:=
router
.
methods
[
method
];
ok
{
return
m
}
else
if
m
,
ok
=
router
.
methods
[
"*"
];
ok
{
return
m
}
else
{
return
""
}
}
else
{
return
strings
.
Title
(
method
)
}
}
//responseWriter is a wrapper for the http.ResponseWriter
//responseWriter is a wrapper for the http.ResponseWriter
//started set to true if response was written to then don't execute other handler
//started set to true if response was written to then don't execute other handler
type
responseWriter
struct
{
type
responseWriter
struct
{
...
@@ -1070,8 +762,18 @@ func (w *responseWriter) WriteHeader(code int) {
...
@@ -1070,8 +762,18 @@ func (w *responseWriter) WriteHeader(code int) {
func
(
w
*
responseWriter
)
Hijack
()
(
net
.
Conn
,
*
bufio
.
ReadWriter
,
error
)
{
func
(
w
*
responseWriter
)
Hijack
()
(
net
.
Conn
,
*
bufio
.
ReadWriter
,
error
)
{
hj
,
ok
:=
w
.
writer
.
(
http
.
Hijacker
)
hj
,
ok
:=
w
.
writer
.
(
http
.
Hijacker
)
if
!
ok
{
if
!
ok
{
println
(
"supported?"
)
return
nil
,
nil
,
errors
.
New
(
"webserver doesn't support hijacking"
)
return
nil
,
nil
,
errors
.
New
(
"webserver doesn't support hijacking"
)
}
}
return
hj
.
Hijack
()
return
hj
.
Hijack
()
}
}
func
tourl
(
params
map
[
string
]
string
)
string
{
if
len
(
params
)
==
0
{
return
""
}
u
:=
"?"
for
k
,
v
:=
range
params
{
u
+=
k
+
"="
+
v
+
"&"
}
return
strings
.
TrimRight
(
u
,
"&"
)
}
router_test.go
View file @
e00eab7f
...
@@ -10,6 +10,7 @@ import (
...
@@ -10,6 +10,7 @@ import (
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"testing"
"testing"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/context"
)
)
...
@@ -76,16 +77,17 @@ func TestUrlFor(t *testing.T) {
...
@@ -76,16 +77,17 @@ func TestUrlFor(t *testing.T) {
handler
.
Add
(
"/person/:last/:first"
,
&
TestController
{})
handler
.
Add
(
"/person/:last/:first"
,
&
TestController
{})
handler
.
AddAuto
(
&
TestController
{})
handler
.
AddAuto
(
&
TestController
{})
if
handler
.
UrlFor
(
"TestController.List"
)
!=
"/api/list"
{
if
handler
.
UrlFor
(
"TestController.List"
)
!=
"/api/list"
{
Info
(
handler
.
UrlFor
(
"TestController.List"
))
t
.
Errorf
(
"TestController.List must equal to /api/list"
)
t
.
Errorf
(
"TestController.List must equal to /api/list"
)
}
}
if
handler
.
UrlFor
(
"TestController.Get"
,
":last"
,
"xie"
,
":first"
,
"asta"
)
!=
"/person/xie/asta"
{
if
handler
.
UrlFor
(
"TestController.Get"
,
":last"
,
"xie"
,
":first"
,
"asta"
)
!=
"/person/xie/asta"
{
t
.
Errorf
(
"TestController.Get must equal to /person/xie/asta"
)
t
.
Errorf
(
"TestController.Get must equal to /person/xie/asta"
)
}
}
if
handler
.
UrlFor
(
"TestController.Myext"
)
!=
"/
Test/M
yext"
{
if
handler
.
UrlFor
(
"TestController.Myext"
)
!=
"/
test/m
yext"
{
t
.
Errorf
(
"TestController.Myext must equal to /
Test/M
yext"
)
t
.
Errorf
(
"TestController.Myext must equal to /
test/m
yext"
)
}
}
if
handler
.
UrlFor
(
"TestController.GetUrl"
)
!=
"/
Test/GetU
rl"
{
if
handler
.
UrlFor
(
"TestController.GetUrl"
)
!=
"/
test/getu
rl"
{
t
.
Errorf
(
"TestController.GetUrl must equal to /
Test/GetU
rl"
)
t
.
Errorf
(
"TestController.GetUrl must equal to /
test/getu
rl"
)
}
}
}
}
...
...
tree.go
View file @
e00eab7f
...
@@ -25,6 +25,26 @@ func NewTree() *Tree {
...
@@ -25,6 +25,26 @@ func NewTree() *Tree {
}
}
}
}
// add Tree to the exist Tree
// prefix should has no params
func
(
t
*
Tree
)
AddTree
(
prefix
string
,
tree
*
Tree
)
{
t
.
addtree
(
splitPath
(
prefix
),
tree
)
}
func
(
t
*
Tree
)
addtree
(
segments
[]
string
,
tree
*
Tree
)
{
if
len
(
segments
)
==
0
{
panic
(
"prefix should has path"
)
}
if
len
(
segments
)
==
1
&&
segments
[
0
]
!=
""
{
t
.
fixrouters
[
segments
[
0
]]
=
tree
return
}
seg
:=
segments
[
0
]
subTree
:=
NewTree
()
t
.
fixrouters
[
seg
]
=
subTree
subTree
.
addtree
(
segments
[
1
:
],
tree
)
}
// call addseg function
// call addseg function
func
(
t
*
Tree
)
AddRouter
(
pattern
string
,
runObject
interface
{})
{
func
(
t
*
Tree
)
AddRouter
(
pattern
string
,
runObject
interface
{})
{
t
.
addseg
(
splitPath
(
pattern
),
runObject
,
nil
,
""
)
t
.
addseg
(
splitPath
(
pattern
),
runObject
,
nil
,
""
)
...
@@ -83,22 +103,40 @@ func (t *Tree) match(segments []string, wildcardValues []string) (runObject inte
...
@@ -83,22 +103,40 @@ func (t *Tree) match(segments []string, wildcardValues []string) (runObject inte
return
t
.
leaf
.
runObject
,
pa
return
t
.
leaf
.
runObject
,
pa
}
}
}
}
if
t
.
wildcard
!=
nil
&&
t
.
wildcard
.
leaf
!=
nil
{
if
ok
,
pa
:=
t
.
wildcard
.
leaf
.
match
(
wildcardValues
);
ok
{
return
t
.
wildcard
.
leaf
.
runObject
,
pa
}
}
return
nil
,
nil
return
nil
,
nil
}
}
var
seg
string
seg
,
segs
:=
segments
[
0
],
segments
[
1
:
]
seg
,
segments
=
segments
[
0
],
segments
[
1
:
]
subTree
,
ok
:=
t
.
fixrouters
[
seg
]
subTree
,
ok
:=
t
.
fixrouters
[
seg
]
if
ok
{
if
ok
{
runObject
,
params
=
subTree
.
match
(
segments
,
wildcardValues
)
runObject
,
params
=
subTree
.
match
(
segs
,
wildcardValues
)
}
else
if
len
(
segs
)
==
0
{
//.json .xml
if
subindex
:=
strings
.
LastIndex
(
seg
,
"."
);
subindex
!=
-
1
{
subTree
,
ok
=
t
.
fixrouters
[
seg
[
:
subindex
]]
if
ok
{
runObject
,
params
=
subTree
.
match
(
segs
,
wildcardValues
)
if
runObject
!=
nil
{
if
params
==
nil
{
params
=
make
(
map
[
string
]
string
)
}
params
[
":ext"
]
=
seg
[
subindex
+
1
:
]
return
runObject
,
params
}
}
}
}
}
if
runObject
==
nil
&&
t
.
wildcard
!=
nil
{
if
runObject
==
nil
&&
t
.
wildcard
!=
nil
{
runObject
,
params
=
t
.
wildcard
.
match
(
seg
ment
s
,
append
(
wildcardValues
,
seg
))
runObject
,
params
=
t
.
wildcard
.
match
(
segs
,
append
(
wildcardValues
,
seg
))
}
}
if
runObject
==
nil
{
if
runObject
==
nil
{
if
t
.
leaf
!=
nil
{
if
t
.
leaf
!=
nil
{
if
ok
,
pa
:=
t
.
leaf
.
match
(
append
(
wildcardValues
,
seg
));
ok
{
if
ok
,
pa
:=
t
.
leaf
.
match
(
append
(
wildcardValues
,
seg
ments
...
));
ok
{
return
t
.
leaf
.
runObject
,
pa
return
t
.
leaf
.
runObject
,
pa
}
}
}
}
...
@@ -122,7 +160,21 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
...
@@ -122,7 +160,21 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
// has error
// has error
if
len
(
wildcardValues
)
==
0
&&
len
(
leaf
.
wildcards
)
>
0
{
if
len
(
wildcardValues
)
==
0
&&
len
(
leaf
.
wildcards
)
>
0
{
if
utils
.
InSlice
(
":"
,
leaf
.
wildcards
)
{
if
utils
.
InSlice
(
":"
,
leaf
.
wildcards
)
{
return
true
,
nil
params
=
make
(
map
[
string
]
string
)
j
:=
0
for
_
,
v
:=
range
leaf
.
wildcards
{
if
v
==
":"
{
continue
}
params
[
v
]
=
""
j
+=
1
}
return
true
,
params
}
if
len
(
leaf
.
wildcards
)
==
1
&&
leaf
.
wildcards
[
0
]
==
":splat"
{
params
=
make
(
map
[
string
]
string
)
params
[
":splat"
]
=
""
return
true
,
params
}
}
Error
(
"bug of router"
)
Error
(
"bug of router"
)
return
false
,
nil
return
false
,
nil
...
@@ -155,10 +207,27 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
...
@@ -155,10 +207,27 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
if
v
==
":"
{
if
v
==
":"
{
continue
continue
}
}
if
v
==
"."
{
lastone
:=
wildcardValues
[
len
(
wildcardValues
)
-
1
]
strs
:=
strings
.
SplitN
(
lastone
,
"."
,
2
)
if
len
(
strs
)
==
2
{
params
[
":ext"
]
=
strs
[
1
]
}
else
{
params
[
":ext"
]
=
""
}
if
len
(
wildcardValues
[
j
:
])
==
1
{
params
[
":path"
]
=
strs
[
0
]
}
else
{
params
[
":path"
]
=
path
.
Join
(
wildcardValues
[
j
:
]
...
)
+
"/"
+
strs
[
0
]
}
return
true
,
params
}
params
[
v
]
=
wildcardValues
[
j
]
params
[
v
]
=
wildcardValues
[
j
]
j
+=
1
j
+=
1
}
}
if
len
(
params
)
!=
len
(
wildcardValues
)
{
if
len
(
params
)
!=
len
(
wildcardValues
)
{
Info
(
params
)
Info
(
wildcardValues
)
Error
(
"bug of router"
)
Error
(
"bug of router"
)
return
false
,
nil
return
false
,
nil
}
}
...
@@ -193,7 +262,7 @@ func splitPath(key string) []string {
...
@@ -193,7 +262,7 @@ func splitPath(key string) []string {
// "admin" -> false, nil, ""
// "admin" -> false, nil, ""
// ":id" -> true, [:id], ""
// ":id" -> true, [:id], ""
// "?:id" -> true, [: id], "" : meaning can empty
// "?:id" -> true, [:
:
id], "" : meaning can empty
// ":id:int" -> true, [:id], ([0-9]+)
// ":id:int" -> true, [:id], ([0-9]+)
// ":name:string" -> true, [:name], ([\w]+)
// ":name:string" -> true, [:name], ([\w]+)
// ":id([0-9]+)" -> true, [:id], ([0-9]+)
// ":id([0-9]+)" -> true, [:id], ([0-9]+)
...
...
tree_test.go
View file @
e00eab7f
...
@@ -13,10 +13,16 @@ var routers []testinfo
...
@@ -13,10 +13,16 @@ var routers []testinfo
func
init
()
{
func
init
()
{
routers
=
make
([]
testinfo
,
0
)
routers
=
make
([]
testinfo
,
0
)
routers
=
append
(
routers
,
testinfo
{
"/:id"
,
"/123"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/:id"
,
"/123"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/hello/?:id"
,
"/hello"
,
map
[
string
]
string
{
":id"
:
""
}})
routers
=
append
(
routers
,
testinfo
{
"/"
,
"/"
,
nil
})
routers
=
append
(
routers
,
testinfo
{
"/"
,
"/"
,
nil
})
routers
=
append
(
routers
,
testinfo
{
"/customer/login"
,
"/customer/login"
,
nil
})
routers
=
append
(
routers
,
testinfo
{
"/customer/login"
,
"/customer/login"
,
nil
})
routers
=
append
(
routers
,
testinfo
{
"/customer/login"
,
"/customer/login.json"
,
map
[
string
]
string
{
":ext"
:
"json"
}})
routers
=
append
(
routers
,
testinfo
{
"/*"
,
"/customer/123"
,
map
[
string
]
string
{
":splat"
:
"customer/123"
}})
routers
=
append
(
routers
,
testinfo
{
"/*"
,
"/customer/123"
,
map
[
string
]
string
{
":splat"
:
"customer/123"
}})
routers
=
append
(
routers
,
testinfo
{
"/customer/*"
,
"/customer"
,
map
[
string
]
string
{
":splat"
:
""
}})
routers
=
append
(
routers
,
testinfo
{
"/*"
,
"/customer/2009/12/11"
,
map
[
string
]
string
{
":splat"
:
"customer/2009/12/11"
}})
routers
=
append
(
routers
,
testinfo
{
"/*.*"
,
"/nice/api.json"
,
map
[
string
]
string
{
":path"
:
"nice/api"
,
":ext"
:
"json"
}})
routers
=
append
(
routers
,
testinfo
{
"/*.*"
,
"/nice/api.json"
,
map
[
string
]
string
{
":path"
:
"nice/api"
,
":ext"
:
"json"
}})
routers
=
append
(
routers
,
testinfo
{
"/:name/*.*"
,
"/nice/api.json"
,
map
[
string
]
string
{
":name"
:
"nice"
,
":path"
:
"api"
,
":ext"
:
"json"
}})
routers
=
append
(
routers
,
testinfo
{
"/:name/test/*.*"
,
"/nice/test/api.json"
,
map
[
string
]
string
{
":name"
:
"nice"
,
":path"
:
"api"
,
":ext"
:
"json"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id:int"
,
"/v1/shop/123"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id:int"
,
"/v1/shop/123"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/:name"
,
"/v1/shop/123/nike"
,
map
[
string
]
string
{
":id"
:
"123"
,
":name"
:
"nike"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/:name"
,
"/v1/shop/123/nike"
,
map
[
string
]
string
{
":id"
:
"123"
,
":name"
:
"nike"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/account"
,
"/v1/shop/123/account"
,
map
[
string
]
string
{
":id"
:
"123"
}})
routers
=
append
(
routers
,
testinfo
{
"/v1/shop/:id/account"
,
"/v1/shop/123/account"
,
map
[
string
]
string
{
":id"
:
"123"
}})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment