mirror of
https://github.com/astaxie/beego.git
synced 2025-07-12 22:01:02 +00:00
Compare commits
106 Commits
Author | SHA1 | Date | |
---|---|---|---|
469f283b68 | |||
085c362ffb | |||
c3a07555c4 | |||
2b8e411174 | |||
720a77c1f9 | |||
b943b74fc5 | |||
67be7b532d | |||
8be83fe488 | |||
cff632f553 | |||
4990d88861 | |||
7075ad8a28 | |||
0e278ae358 | |||
e38a23b30e | |||
117904be73 | |||
3b807845f2 | |||
00b710e168 | |||
e25fcffbc0 | |||
c13141b8bf | |||
7a7ff735e3 | |||
3b934bb910 | |||
aa275fb5ce | |||
deb553be7f | |||
3db9633ebd | |||
2f8a70d548 | |||
7c0d0900ac | |||
6809c97611 | |||
675643c68d | |||
06f4bf493d | |||
4786fb0948 | |||
fdb5672b7a | |||
107a7a21c0 | |||
dbebf8df4b | |||
f7b01aab13 | |||
2570f075d9 | |||
21cb8ea4a3 | |||
6c8a7f1382 | |||
e00eab7f49 | |||
bfabcfcb6b | |||
f06ba52ede | |||
fcae000a79 | |||
3e4c015982 | |||
d689be30e8 | |||
7b110a0b73 | |||
e3033b57a6 | |||
bd537554ea | |||
ebb3b91df9 | |||
a65ad1a4bc | |||
bdc01f52a0 | |||
a673a85d4a | |||
61008fe75c | |||
5dee6b7d19 | |||
f6c7a6bd32 | |||
d2eece9a39 | |||
c3a23b28ee | |||
9083927c6a | |||
3f7e91e6a4 | |||
a2a6f47afa | |||
23229ef9ef | |||
0d17d974cd | |||
17104c25a2 | |||
8b374d7f90 | |||
fa3234147a | |||
33ad6c1370 | |||
04290dfc68 | |||
03080b3ef2 | |||
3f2a712ba8 | |||
f215aa4810 | |||
18a02d7d60 | |||
3f4d750dc4 | |||
9f01aeed31 | |||
b45f0b9bf6 | |||
cf04ade603 | |||
2c59ff1cc6 | |||
6bdf0838ce | |||
31a63c5d50 | |||
237aaadd65 | |||
34ddcef1dc | |||
f6ce2656db | |||
b647026dff | |||
568c0c47f0 | |||
2629de28f2 | |||
10d2c7c328 | |||
af7ac98bd6 | |||
6f78f1d4b2 | |||
9f95fd3309 | |||
74c309cefd | |||
29e113a48a | |||
3caf1896d6 | |||
d5d5f23756 | |||
46641ef3b6 | |||
b2a69f505c | |||
b2bd829d39 | |||
f9b8617fa3 | |||
6c6e4ecfbc | |||
8bcf03c652 | |||
1ea449aa3a | |||
b212ec8dab | |||
e50cbecf80 | |||
127b85bcaa | |||
89dde6cd9d | |||
5a52949761 | |||
a78162e9e4 | |||
931e6162ac | |||
1bb876f2df | |||
18f70e6ee4 | |||
4785ac14d7 |
60
admin.go
60
admin.go
@ -88,7 +88,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintln(rw, "StaticExtensionsToGzip:", StaticExtensionsToGzip)
|
fmt.Fprintln(rw, "StaticExtensionsToGzip:", StaticExtensionsToGzip)
|
||||||
fmt.Fprintln(rw, "HttpAddr:", HttpAddr)
|
fmt.Fprintln(rw, "HttpAddr:", HttpAddr)
|
||||||
fmt.Fprintln(rw, "HttpPort:", HttpPort)
|
fmt.Fprintln(rw, "HttpPort:", HttpPort)
|
||||||
fmt.Fprintln(rw, "HttpTLS:", HttpTLS)
|
fmt.Fprintln(rw, "HttpTLS:", EnableHttpTLS)
|
||||||
fmt.Fprintln(rw, "HttpCertFile:", HttpCertFile)
|
fmt.Fprintln(rw, "HttpCertFile:", HttpCertFile)
|
||||||
fmt.Fprintln(rw, "HttpKeyFile:", HttpKeyFile)
|
fmt.Fprintln(rw, "HttpKeyFile:", HttpKeyFile)
|
||||||
fmt.Fprintln(rw, "RecoverPanic:", RecoverPanic)
|
fmt.Fprintln(rw, "RecoverPanic:", RecoverPanic)
|
||||||
@ -107,7 +107,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
|||||||
fmt.Fprintln(rw, "MaxMemory:", MaxMemory)
|
fmt.Fprintln(rw, "MaxMemory:", MaxMemory)
|
||||||
fmt.Fprintln(rw, "EnableGzip:", EnableGzip)
|
fmt.Fprintln(rw, "EnableGzip:", EnableGzip)
|
||||||
fmt.Fprintln(rw, "DirectoryIndex:", DirectoryIndex)
|
fmt.Fprintln(rw, "DirectoryIndex:", DirectoryIndex)
|
||||||
fmt.Fprintln(rw, "EnableHotUpdate:", EnableHotUpdate)
|
|
||||||
fmt.Fprintln(rw, "HttpServerTimeOut:", HttpServerTimeOut)
|
fmt.Fprintln(rw, "HttpServerTimeOut:", HttpServerTimeOut)
|
||||||
fmt.Fprintln(rw, "ErrorsShow:", ErrorsShow)
|
fmt.Fprintln(rw, "ErrorsShow:", ErrorsShow)
|
||||||
fmt.Fprintln(rw, "XSRFKEY:", XSRFKEY)
|
fmt.Fprintln(rw, "XSRFKEY:", XSRFKEY)
|
||||||
@ -122,28 +121,13 @@ 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 {
|
for method, t := range BeeApp.Handlers.routers {
|
||||||
if router.hasMethod {
|
fmt.Fprintln(rw)
|
||||||
fmt.Fprintln(rw, router.pattern, "----", router.methods, "----", router.controllerType.Name())
|
fmt.Fprintln(rw)
|
||||||
} else {
|
fmt.Fprintln(rw, " Method:", method)
|
||||||
fmt.Fprintln(rw, router.pattern, "----", router.controllerType.Name())
|
printTree(rw, t)
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, router := range BeeApp.Handlers.routers {
|
|
||||||
if router.hasMethod {
|
|
||||||
fmt.Fprintln(rw, router.pattern, "----", router.methods, "----", router.controllerType.Name())
|
|
||||||
} else {
|
|
||||||
fmt.Fprintln(rw, router.pattern, "----", router.controllerType.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// @todo print routers
|
||||||
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 {
|
||||||
@ -153,12 +137,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 {
|
||||||
@ -191,6 +169,26 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printTree(rw http.ResponseWriter, t *Tree) {
|
||||||
|
for _, tr := range t.fixrouters {
|
||||||
|
printTree(rw, tr)
|
||||||
|
}
|
||||||
|
if t.wildcard != nil {
|
||||||
|
printTree(rw, t.wildcard)
|
||||||
|
}
|
||||||
|
for _, l := range t.leaves {
|
||||||
|
if v, ok := l.runObject.(*controllerInfo); ok {
|
||||||
|
if v.routerType == routerTypeBeego {
|
||||||
|
fmt.Fprintln(rw, v.pattern, v.methods, v.controllerType.Name())
|
||||||
|
} else if v.routerType == routerTypeRESTFul {
|
||||||
|
fmt.Fprintln(rw, v.pattern, v.methods)
|
||||||
|
} else if v.routerType == routerTypeHandler {
|
||||||
|
fmt.Fprintln(rw, v.pattern, "handler")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ProfIndex is a http.Handler for showing profile command.
|
// ProfIndex is a http.Handler for showing profile command.
|
||||||
// it's in url pattern "/prof" in admin module.
|
// it's in url pattern "/prof" in admin module.
|
||||||
func profIndex(rw http.ResponseWriter, r *http.Request) {
|
func profIndex(rw http.ResponseWriter, r *http.Request) {
|
||||||
@ -219,9 +217,9 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
|
|||||||
func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
func healthcheck(rw http.ResponseWriter, req *http.Request) {
|
||||||
for name, h := range toolbox.AdminCheckList {
|
for name, h := range toolbox.AdminCheckList {
|
||||||
if err := h.Check(); err != nil {
|
if err := h.Check(); err != nil {
|
||||||
fmt.Fprintf(rw, "%s : ok\n", name)
|
|
||||||
} else {
|
|
||||||
fmt.Fprintf(rw, "%s : %s\n", name, err.Error())
|
fmt.Fprintf(rw, "%s : %s\n", name, err.Error())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(rw, "%s : ok\n", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
196
app.go
196
app.go
@ -22,12 +22,13 @@ type FilterFunc func(*context.Context)
|
|||||||
// App defines beego application with a new PatternServeMux.
|
// App defines beego application with a new PatternServeMux.
|
||||||
type App struct {
|
type App struct {
|
||||||
Handlers *ControllerRegistor
|
Handlers *ControllerRegistor
|
||||||
|
Server *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp returns a new beego application.
|
// NewApp returns a new beego application.
|
||||||
func NewApp() *App {
|
func NewApp() *App {
|
||||||
cr := NewControllerRegistor()
|
cr := NewControllerRegister()
|
||||||
app := &App{Handlers: cr}
|
app := &App{Handlers: cr, Server: &http.Server{}}
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +46,7 @@ func (app *App) Run() {
|
|||||||
err error
|
err error
|
||||||
l net.Listener
|
l net.Listener
|
||||||
)
|
)
|
||||||
|
endRunning := make(chan bool, 1)
|
||||||
|
|
||||||
if UseFcgi {
|
if UseFcgi {
|
||||||
if HttpPort == 0 {
|
if HttpPort == 0 {
|
||||||
@ -57,180 +59,36 @@ func (app *App) Run() {
|
|||||||
}
|
}
|
||||||
err = fcgi.Serve(l, app.Handlers)
|
err = fcgi.Serve(l, app.Handlers)
|
||||||
} else {
|
} else {
|
||||||
if EnableHotUpdate {
|
app.Server.Addr = addr
|
||||||
server := &http.Server{
|
app.Server.Handler = app.Handlers
|
||||||
Handler: app.Handlers,
|
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||||
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
|
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
|
||||||
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
|
|
||||||
}
|
if EnableHttpTLS {
|
||||||
laddr, err := net.ResolveTCPAddr("tcp", addr)
|
go func() {
|
||||||
if nil != err {
|
if HttpsPort != 0 {
|
||||||
BeeLogger.Critical("ResolveTCPAddr:", err)
|
app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
|
||||||
}
|
|
||||||
l, err = GetInitListener(laddr)
|
|
||||||
if err == nil {
|
|
||||||
theStoppable = newStoppable(l)
|
|
||||||
err = server.Serve(theStoppable)
|
|
||||||
if err == nil {
|
|
||||||
theStoppable.wg.Wait()
|
|
||||||
err = CloseSelf()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
s := &http.Server{
|
|
||||||
Addr: addr,
|
|
||||||
Handler: app.Handlers,
|
|
||||||
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
|
|
||||||
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
|
|
||||||
}
|
|
||||||
if HttpTLS {
|
|
||||||
err = s.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
|
|
||||||
} else {
|
|
||||||
err = s.ListenAndServe()
|
|
||||||
}
|
}
|
||||||
|
err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
BeeLogger.Critical("ListenAndServeTLS: ", err)
|
||||||
|
time.Sleep(100 * time.Microsecond)
|
||||||
|
endRunning <- true
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if EnableHttpListen {
|
||||||
|
go func() {
|
||||||
|
err := app.Server.ListenAndServe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
BeeLogger.Critical("ListenAndServe: ", err)
|
BeeLogger.Critical("ListenAndServe: ", err)
|
||||||
time.Sleep(100 * time.Microsecond)
|
time.Sleep(100 * time.Microsecond)
|
||||||
|
endRunning <- true
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Router adds a url-patterned controller handler.
|
<-endRunning
|
||||||
// The path argument supports regex rules and specific placeholders.
|
|
||||||
// The c argument needs a controller handler implemented beego.ControllerInterface.
|
|
||||||
// The mapping methods argument only need one string to define custom router rules.
|
|
||||||
// usage:
|
|
||||||
// simple router
|
|
||||||
// beego.Router("/admin", &admin.UserController{})
|
|
||||||
// beego.Router("/admin/index", &admin.ArticleController{})
|
|
||||||
//
|
|
||||||
// regex router
|
|
||||||
//
|
|
||||||
// beego.Router(“/api/:id([0-9]+)“, &controllers.RController{})
|
|
||||||
//
|
|
||||||
// custom rules
|
|
||||||
// beego.Router("/api/list",&RestController{},"*:ListFood")
|
|
||||||
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
|
||||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
|
||||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
|
||||||
func (app *App) Router(path string, c ControllerInterface, mappingMethods ...string) *App {
|
|
||||||
app.Handlers.Add(path, c, mappingMethods...)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// AutoRouter adds beego-defined controller handler.
|
|
||||||
// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
|
|
||||||
// visit the url /main/list to exec List function or /main/page to exec Page function.
|
|
||||||
func (app *App) AutoRouter(c ControllerInterface) *App {
|
|
||||||
app.Handlers.AddAuto(c)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// AutoRouterWithPrefix adds beego-defined controller handler with prefix.
|
|
||||||
// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
|
|
||||||
// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
|
|
||||||
func (app *App) AutoRouterWithPrefix(prefix string, c ControllerInterface) *App {
|
|
||||||
app.Handlers.AddAutoPrefix(prefix, c)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Get method
|
|
||||||
func (app *App) Get(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Get(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Post method
|
|
||||||
func (app *App) Post(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Post(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Put method
|
|
||||||
func (app *App) Put(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Put(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Delete method
|
|
||||||
func (app *App) Delete(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Delete(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Options method
|
|
||||||
func (app *App) Options(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Options(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Head method
|
|
||||||
func (app *App) Head(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Head(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Patch method
|
|
||||||
func (app *App) Patch(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Patch(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for Patch method
|
|
||||||
func (app *App) Any(rootpath string, f FilterFunc) *App {
|
|
||||||
app.Handlers.Any(rootpath, f)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// add router for http.Handler
|
|
||||||
func (app *App) Handler(rootpath string, h http.Handler, options ...interface{}) *App {
|
|
||||||
app.Handlers.Handler(rootpath, h, options...)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// UrlFor creates a url with another registered controller handler with params.
|
|
||||||
// The endpoint is formed as path.controller.name to defined the controller method which will run.
|
|
||||||
// The values need key-pair data to assign into controller method.
|
|
||||||
func (app *App) UrlFor(endpoint string, values ...string) string {
|
|
||||||
return app.Handlers.UrlFor(endpoint, values...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// [Deprecated] use InsertFilter.
|
|
||||||
// Filter adds a FilterFunc under pattern condition and named action.
|
|
||||||
// The actions contains BeforeRouter,AfterStatic,BeforeExec,AfterExec and FinishRouter.
|
|
||||||
func (app *App) Filter(pattern, action string, filter FilterFunc) *App {
|
|
||||||
app.Handlers.AddFilter(pattern, action, filter)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsertFilter adds a FilterFunc with pattern condition and action constant.
|
|
||||||
// The pos means action constant including
|
|
||||||
// beego.BeforeRouter, beego.AfterStatic, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
|
|
||||||
func (app *App) InsertFilter(pattern string, pos int, filter FilterFunc) *App {
|
|
||||||
app.Handlers.InsertFilter(pattern, pos, filter)
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetViewsPath sets view directory path in beego application.
|
|
||||||
// it returns beego application self.
|
|
||||||
func (app *App) SetViewsPath(path string) *App {
|
|
||||||
ViewsPath = path
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetStaticPath sets static directory path and proper url pattern in beego application.
|
|
||||||
// if beego.SetStaticPath("static","public"), visit /static/* to load static file in folder "public".
|
|
||||||
// it returns beego application self.
|
|
||||||
func (app *App) SetStaticPath(url string, path string) *App {
|
|
||||||
StaticDir[url] = path
|
|
||||||
return app
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelStaticPath removes the static folder setting in this url pattern in beego application.
|
|
||||||
// it returns beego application self.
|
|
||||||
func (app *App) DelStaticPath(url string) *App {
|
|
||||||
delete(StaticDir, url)
|
|
||||||
return app
|
|
||||||
}
|
}
|
||||||
|
166
beego.go
166
beego.go
@ -19,7 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// beego web framework version.
|
// beego web framework version.
|
||||||
const VERSION = "1.2.0"
|
const VERSION = "1.3.0"
|
||||||
|
|
||||||
type hookfunc func() error //hook function to run
|
type hookfunc func() error //hook function to run
|
||||||
var hooks []hookfunc //hook function slice to store the hookfunc
|
var hooks []hookfunc //hook function slice to store the hookfunc
|
||||||
@ -80,11 +80,11 @@ func (gr *GroupRouters) AddAuto(c ControllerInterface) {
|
|||||||
func AddGroupRouter(prefix string, groups GroupRouters) *App {
|
func AddGroupRouter(prefix string, groups GroupRouters) *App {
|
||||||
for _, v := range groups {
|
for _, v := range groups {
|
||||||
if v.pattern == "" {
|
if v.pattern == "" {
|
||||||
BeeApp.AutoRouterWithPrefix(prefix, v.controller)
|
BeeApp.Handlers.AddAutoPrefix(prefix, v.controller)
|
||||||
} else if v.mappingMethods != "" {
|
} else if v.mappingMethods != "" {
|
||||||
BeeApp.Router(prefix+v.pattern, v.controller, v.mappingMethods)
|
BeeApp.Handlers.Add(prefix+v.pattern, v.controller, v.mappingMethods)
|
||||||
} else {
|
} else {
|
||||||
BeeApp.Router(prefix+v.pattern, v.controller)
|
BeeApp.Handlers.Add(prefix+v.pattern, v.controller)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -93,8 +93,54 @@ func AddGroupRouter(prefix string, groups GroupRouters) *App {
|
|||||||
|
|
||||||
// Router adds a patterned controller handler to BeeApp.
|
// Router adds a patterned controller handler to BeeApp.
|
||||||
// it's an alias method of App.Router.
|
// it's an alias method of App.Router.
|
||||||
|
// usage:
|
||||||
|
// simple router
|
||||||
|
// beego.Router("/admin", &admin.UserController{})
|
||||||
|
// beego.Router("/admin/index", &admin.ArticleController{})
|
||||||
|
//
|
||||||
|
// regex router
|
||||||
|
//
|
||||||
|
// beego.Router("/api/:id([0-9]+)", &controllers.RController{})
|
||||||
|
//
|
||||||
|
// custom rules
|
||||||
|
// beego.Router("/api/list",&RestController{},"*:ListFood")
|
||||||
|
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
||||||
|
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||||
|
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
||||||
BeeApp.Router(rootpath, c, mappingMethods...)
|
BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
|
||||||
|
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
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,69 +155,109 @@ func RESTRouter(rootpath string, c ControllerInterface) *App {
|
|||||||
|
|
||||||
// AutoRouter adds defined controller handler to BeeApp.
|
// AutoRouter adds defined controller handler to BeeApp.
|
||||||
// it's same to App.AutoRouter.
|
// it's same to App.AutoRouter.
|
||||||
|
// if beego.AddAuto(&MainContorlller{}) and MainController has methods List and Page,
|
||||||
|
// visit the url /main/list to exec List function or /main/page to exec Page function.
|
||||||
func AutoRouter(c ControllerInterface) *App {
|
func AutoRouter(c ControllerInterface) *App {
|
||||||
BeeApp.AutoRouter(c)
|
BeeApp.Handlers.AddAuto(c)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutoPrefix adds controller handler to BeeApp with prefix.
|
// AutoPrefix adds controller handler to BeeApp with prefix.
|
||||||
// it's same to App.AutoRouterWithPrefix.
|
// it's same to App.AutoRouterWithPrefix.
|
||||||
|
// if beego.AutoPrefix("/admin",&MainContorlller{}) and MainController has methods List and Page,
|
||||||
|
// visit the url /admin/main/list to exec List function or /admin/main/page to exec Page function.
|
||||||
func AutoPrefix(prefix string, c ControllerInterface) *App {
|
func AutoPrefix(prefix string, c ControllerInterface) *App {
|
||||||
BeeApp.AutoRouterWithPrefix(prefix, c)
|
BeeApp.Handlers.AddAutoPrefix(prefix, c)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Get method
|
// register router for Get method
|
||||||
|
// usage:
|
||||||
|
// beego.Get("/", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Get(rootpath string, f FilterFunc) *App {
|
func Get(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Get(rootpath, f)
|
BeeApp.Handlers.Get(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Post method
|
// register router for Post method
|
||||||
|
// usage:
|
||||||
|
// beego.Post("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Post(rootpath string, f FilterFunc) *App {
|
func Post(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Post(rootpath, f)
|
BeeApp.Handlers.Post(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Delete method
|
// register router for Delete method
|
||||||
|
// usage:
|
||||||
|
// beego.Delete("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Delete(rootpath string, f FilterFunc) *App {
|
func Delete(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Delete(rootpath, f)
|
BeeApp.Handlers.Delete(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Put method
|
// register router for Put method
|
||||||
|
// usage:
|
||||||
|
// beego.Put("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Put(rootpath string, f FilterFunc) *App {
|
func Put(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Put(rootpath, f)
|
BeeApp.Handlers.Put(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Head method
|
// register router for Head method
|
||||||
|
// usage:
|
||||||
|
// beego.Head("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Head(rootpath string, f FilterFunc) *App {
|
func Head(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Head(rootpath, f)
|
BeeApp.Handlers.Head(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Options method
|
// register router for Options method
|
||||||
|
// usage:
|
||||||
|
// beego.Options("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Options(rootpath string, f FilterFunc) *App {
|
func Options(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Options(rootpath, f)
|
BeeApp.Handlers.Options(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for Patch method
|
// register router for Patch method
|
||||||
|
// usage:
|
||||||
|
// beego.Patch("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Patch(rootpath string, f FilterFunc) *App {
|
func Patch(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Patch(rootpath, f)
|
BeeApp.Handlers.Patch(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for all method
|
// register router for all method
|
||||||
|
// usage:
|
||||||
|
// beego.Any("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Any(rootpath string, f FilterFunc) *App {
|
func Any(rootpath string, f FilterFunc) *App {
|
||||||
BeeApp.Any(rootpath, f)
|
BeeApp.Handlers.Any(rootpath, f)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// register router for own Handler
|
// register router for own Handler
|
||||||
|
// usage:
|
||||||
|
// beego.Handler("/api", func(ctx *context.Context){
|
||||||
|
// ctx.Output.Body("hello world")
|
||||||
|
// })
|
||||||
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
|
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
|
||||||
BeeApp.Handler(rootpath, h, options...)
|
BeeApp.Handlers.Handler(rootpath, h, options...)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,15 +270,14 @@ func Errorhandler(err string, h http.HandlerFunc) *App {
|
|||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetViewsPath sets view directory to BeeApp.
|
// SetViewsPath sets view directory path in beego application.
|
||||||
// it's alias of App.SetViewsPath.
|
|
||||||
func SetViewsPath(path string) *App {
|
func SetViewsPath(path string) *App {
|
||||||
BeeApp.SetViewsPath(path)
|
ViewsPath = path
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetStaticPath sets static directory and url prefix to BeeApp.
|
// SetStaticPath sets static directory path and proper url pattern in beego application.
|
||||||
// it's alias of App.SetStaticPath.
|
// if beego.SetStaticPath("static","public"), visit /static/* to load static file in folder "public".
|
||||||
func SetStaticPath(url string, path string) *App {
|
func SetStaticPath(url string, path string) *App {
|
||||||
if !strings.HasPrefix(url, "/") {
|
if !strings.HasPrefix(url, "/") {
|
||||||
url = "/" + url
|
url = "/" + url
|
||||||
@ -203,27 +288,16 @@ func SetStaticPath(url string, path string) *App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DelStaticPath removes the static folder setting in this url pattern in beego application.
|
// DelStaticPath removes the static folder setting in this url pattern in beego application.
|
||||||
// it's alias of App.DelStaticPath.
|
|
||||||
func DelStaticPath(url string) *App {
|
func DelStaticPath(url string) *App {
|
||||||
delete(StaticDir, url)
|
delete(StaticDir, url)
|
||||||
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.
|
|
||||||
// it's alias of App.Filter.
|
|
||||||
func AddFilter(pattern, action string, filter FilterFunc) *App {
|
|
||||||
BeeApp.Filter(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.
|
||||||
// it's alias of App.InsertFilter.
|
|
||||||
func InsertFilter(pattern string, pos int, filter FilterFunc) *App {
|
func InsertFilter(pattern string, pos int, filter FilterFunc) *App {
|
||||||
BeeApp.InsertFilter(pattern, pos, filter)
|
BeeApp.Handlers.InsertFilter(pattern, pos, filter)
|
||||||
return BeeApp
|
return BeeApp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,8 +308,19 @@ func AddAPPStartHook(hf hookfunc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run beego application.
|
// Run beego application.
|
||||||
// it's alias of App.Run.
|
// beego.Run() default run on HttpPort
|
||||||
func Run() {
|
// beego.Run(":8089")
|
||||||
|
// beego.Run("127.0.0.1:8089")
|
||||||
|
func Run(params ...string) {
|
||||||
|
if len(params) > 0 && params[0] != "" {
|
||||||
|
strs := strings.Split(params[0], ":")
|
||||||
|
if len(strs) > 0 && strs[0] != "" {
|
||||||
|
HttpAddr = strs[0]
|
||||||
|
}
|
||||||
|
if len(strs) > 1 && strs[1] != "" {
|
||||||
|
HttpPort, _ = strconv.Atoi(strs[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
initBeforeHttpRun()
|
initBeforeHttpRun()
|
||||||
|
|
||||||
if EnableAdmin {
|
if EnableAdmin {
|
||||||
@ -270,7 +355,7 @@ func initBeforeHttpRun() {
|
|||||||
sessionConfig = `{"cookieName":"` + SessionName + `",` +
|
sessionConfig = `{"cookieName":"` + SessionName + `",` +
|
||||||
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
|
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
|
||||||
`"providerConfig":"` + SessionSavePath + `",` +
|
`"providerConfig":"` + SessionSavePath + `",` +
|
||||||
`"secure":` + strconv.FormatBool(HttpTLS) + `,` +
|
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
|
||||||
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
|
`"sessionIDHashFunc":"` + SessionHashFunc + `",` +
|
||||||
`"sessionIDHashKey":"` + SessionHashKey + `",` +
|
`"sessionIDHashKey":"` + SessionHashKey + `",` +
|
||||||
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
|
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
|
||||||
@ -294,10 +379,19 @@ func initBeforeHttpRun() {
|
|||||||
middleware.VERSION = VERSION
|
middleware.VERSION = VERSION
|
||||||
middleware.AppName = AppName
|
middleware.AppName = AppName
|
||||||
middleware.RegisterErrorHandler()
|
middleware.RegisterErrorHandler()
|
||||||
|
|
||||||
|
for u, _ := range StaticDir {
|
||||||
|
Get(u+"/*", serverStaticRouter)
|
||||||
|
}
|
||||||
|
if EnableDocs {
|
||||||
|
Get("/docs/*", serverDocs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this function is for test package init
|
||||||
func TestBeegoInit(apppath string) {
|
func TestBeegoInit(apppath string) {
|
||||||
AppPath = apppath
|
AppPath = apppath
|
||||||
|
RunMode = "test"
|
||||||
AppConfigPath = filepath.Join(AppPath, "conf", "app.conf")
|
AppConfigPath = filepath.Join(AppPath, "conf", "app.conf")
|
||||||
err := ParseConfig()
|
err := ParseConfig()
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
|
227
config.go
227
config.go
@ -7,12 +7,12 @@
|
|||||||
package beego
|
package beego
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/astaxie/beego/config"
|
"github.com/astaxie/beego/config"
|
||||||
@ -30,9 +30,11 @@ var (
|
|||||||
StaticDir map[string]string
|
StaticDir map[string]string
|
||||||
TemplateCache map[string]*template.Template // template caching map
|
TemplateCache map[string]*template.Template // template caching map
|
||||||
StaticExtensionsToGzip []string // files with should be compressed with gzip (.js,.css,etc)
|
StaticExtensionsToGzip []string // files with should be compressed with gzip (.js,.css,etc)
|
||||||
|
EnableHttpListen bool
|
||||||
HttpAddr string
|
HttpAddr string
|
||||||
HttpPort int
|
HttpPort int
|
||||||
HttpTLS bool
|
EnableHttpTLS bool
|
||||||
|
HttpsPort int
|
||||||
HttpCertFile string
|
HttpCertFile string
|
||||||
HttpKeyFile string
|
HttpKeyFile string
|
||||||
RecoverPanic bool // flag of auto recover panic
|
RecoverPanic bool // flag of auto recover panic
|
||||||
@ -54,7 +56,6 @@ var (
|
|||||||
MaxMemory int64
|
MaxMemory int64
|
||||||
EnableGzip bool // flag of enable gzip
|
EnableGzip bool // flag of enable gzip
|
||||||
DirectoryIndex bool // flag of display directory index. default is false.
|
DirectoryIndex bool // flag of display directory index. default is false.
|
||||||
EnableHotUpdate bool // flag of hot update checking by app self. default is false.
|
|
||||||
HttpServerTimeOut int64
|
HttpServerTimeOut int64
|
||||||
ErrorsShow bool // flag of show errors in page. if true, show error and trace info in page rendered with error template.
|
ErrorsShow bool // flag of show errors in page. if true, show error and trace info in page rendered with error template.
|
||||||
XSRFKEY string // xsrf hash salt string.
|
XSRFKEY string // xsrf hash salt string.
|
||||||
@ -69,6 +70,8 @@ var (
|
|||||||
AdminHttpPort int
|
AdminHttpPort int
|
||||||
FlashName string // name of the flash variable found in response header and cookie
|
FlashName string // name of the flash variable found in response header and cookie
|
||||||
FlashSeperator string // used to seperate flash key:value
|
FlashSeperator string // used to seperate flash key:value
|
||||||
|
AppConfigProvider string // config provider
|
||||||
|
EnableDocs bool // enable generate docs & server docs API Swagger
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -90,6 +93,8 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppConfigProvider = "ini"
|
||||||
|
|
||||||
StaticDir = make(map[string]string)
|
StaticDir = make(map[string]string)
|
||||||
StaticDir["/static"] = "static"
|
StaticDir["/static"] = "static"
|
||||||
|
|
||||||
@ -98,9 +103,13 @@ func init() {
|
|||||||
TemplateCache = make(map[string]*template.Template)
|
TemplateCache = make(map[string]*template.Template)
|
||||||
|
|
||||||
// set this to 0.0.0.0 to make this app available to externally
|
// set this to 0.0.0.0 to make this app available to externally
|
||||||
|
EnableHttpListen = true //default enable http Listen
|
||||||
|
|
||||||
HttpAddr = ""
|
HttpAddr = ""
|
||||||
HttpPort = 8080
|
HttpPort = 8080
|
||||||
|
|
||||||
|
HttpsPort = 10443
|
||||||
|
|
||||||
AppName = "beego"
|
AppName = "beego"
|
||||||
|
|
||||||
RunMode = "dev" //default runmod
|
RunMode = "dev" //default runmod
|
||||||
@ -137,7 +146,7 @@ func init() {
|
|||||||
TemplateLeft = "{{"
|
TemplateLeft = "{{"
|
||||||
TemplateRight = "}}"
|
TemplateRight = "}}"
|
||||||
|
|
||||||
BeegoServerName = "beegoServer"
|
BeegoServerName = "beegoServer:" + VERSION
|
||||||
|
|
||||||
EnableAdmin = false
|
EnableAdmin = false
|
||||||
AdminHttpAddr = "127.0.0.1"
|
AdminHttpAddr = "127.0.0.1"
|
||||||
@ -165,151 +174,157 @@ func init() {
|
|||||||
// ParseConfig parsed default config file.
|
// ParseConfig parsed default config file.
|
||||||
// now only support ini, next will support json.
|
// now only support ini, next will support json.
|
||||||
func ParseConfig() (err error) {
|
func ParseConfig() (err error) {
|
||||||
AppConfig, err = config.NewConfig("ini", AppConfigPath)
|
AppConfig, err = config.NewConfig(AppConfigProvider, AppConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
AppConfig = config.NewFakeConfig()
|
AppConfig = config.NewFakeConfig()
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
HttpAddr = AppConfig.String("HttpAddr")
|
|
||||||
|
|
||||||
if v, err := AppConfig.Int("HttpPort"); err == nil {
|
if v, err := getConfig("string", "HttpAddr"); err == nil {
|
||||||
HttpPort = v
|
HttpAddr = v.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if maxmemory, err := AppConfig.Int64("MaxMemory"); err == nil {
|
if v, err := getConfig("int", "HttpPort"); err == nil {
|
||||||
MaxMemory = maxmemory
|
HttpPort = v.(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if appname := AppConfig.String("AppName"); appname != "" {
|
if v, err := getConfig("bool", "EnableHttpListen"); err == nil {
|
||||||
AppName = appname
|
EnableHttpListen = v.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if runmode := AppConfig.String("RunMode"); runmode != "" {
|
if maxmemory, err := getConfig("int64", "MaxMemory"); err == nil {
|
||||||
RunMode = runmode
|
MaxMemory = maxmemory.(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if autorender, err := AppConfig.Bool("AutoRender"); err == nil {
|
if appname, _ := getConfig("string", "AppName"); appname != "" {
|
||||||
AutoRender = autorender
|
AppName = appname.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if autorecover, err := AppConfig.Bool("RecoverPanic"); err == nil {
|
if runmode, _ := getConfig("string", "RunMode"); runmode != "" {
|
||||||
RecoverPanic = autorecover
|
RunMode = runmode.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if views := AppConfig.String("ViewsPath"); views != "" {
|
if autorender, err := getConfig("bool", "AutoRender"); err == nil {
|
||||||
ViewsPath = views
|
AutoRender = autorender.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sessionon, err := AppConfig.Bool("SessionOn"); err == nil {
|
if autorecover, err := getConfig("bool", "RecoverPanic"); err == nil {
|
||||||
SessionOn = sessionon
|
RecoverPanic = autorecover.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sessProvider := AppConfig.String("SessionProvider"); sessProvider != "" {
|
if views, _ := getConfig("string", "ViewsPath"); views != "" {
|
||||||
SessionProvider = sessProvider
|
ViewsPath = views.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sessName := AppConfig.String("SessionName"); sessName != "" {
|
if sessionon, err := getConfig("bool", "SessionOn"); err == nil {
|
||||||
SessionName = sessName
|
SessionOn = sessionon.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sesssavepath := AppConfig.String("SessionSavePath"); sesssavepath != "" {
|
if sessProvider, _ := getConfig("string", "SessionProvider"); sessProvider != "" {
|
||||||
SessionSavePath = sesssavepath
|
SessionProvider = sessProvider.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sesshashfunc := AppConfig.String("SessionHashFunc"); sesshashfunc != "" {
|
if sessName, _ := getConfig("string", "SessionName"); sessName != "" {
|
||||||
SessionHashFunc = sesshashfunc
|
SessionName = sessName.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sesshashkey := AppConfig.String("SessionHashKey"); sesshashkey != "" {
|
if sesssavepath, _ := getConfig("string", "SessionSavePath"); sesssavepath != "" {
|
||||||
SessionHashKey = sesshashkey
|
SessionSavePath = sesssavepath.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sessMaxLifeTime, err := AppConfig.Int("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 {
|
if sesshashfunc, _ := getConfig("string", "SessionHashFunc"); sesshashfunc != "" {
|
||||||
int64val, _ := strconv.ParseInt(strconv.Itoa(sessMaxLifeTime), 10, 64)
|
SessionHashFunc = sesshashfunc.(string)
|
||||||
SessionGCMaxLifetime = int64val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sesscookielifetime, err := AppConfig.Int("SessionCookieLifeTime"); err == nil && sesscookielifetime != 0 {
|
if sesshashkey, _ := getConfig("string", "SessionHashKey"); sesshashkey != "" {
|
||||||
SessionCookieLifeTime = sesscookielifetime
|
SessionHashKey = sesshashkey.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if usefcgi, err := AppConfig.Bool("UseFcgi"); err == nil {
|
if sessMaxLifeTime, err := getConfig("int64", "SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 {
|
||||||
UseFcgi = usefcgi
|
SessionGCMaxLifetime = sessMaxLifeTime.(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if enablegzip, err := AppConfig.Bool("EnableGzip"); err == nil {
|
if sesscookielifetime, err := getConfig("int", "SessionCookieLifeTime"); err == nil && sesscookielifetime != 0 {
|
||||||
EnableGzip = enablegzip
|
SessionCookieLifeTime = sesscookielifetime.(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if directoryindex, err := AppConfig.Bool("DirectoryIndex"); err == nil {
|
if usefcgi, err := getConfig("bool", "UseFcgi"); err == nil {
|
||||||
DirectoryIndex = directoryindex
|
UseFcgi = usefcgi.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hotupdate, err := AppConfig.Bool("HotUpdate"); err == nil {
|
if enablegzip, err := getConfig("bool", "EnableGzip"); err == nil {
|
||||||
EnableHotUpdate = hotupdate
|
EnableGzip = enablegzip.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if timeout, err := AppConfig.Int64("HttpServerTimeOut"); err == nil {
|
if directoryindex, err := getConfig("bool", "DirectoryIndex"); err == nil {
|
||||||
HttpServerTimeOut = timeout
|
DirectoryIndex = directoryindex.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errorsshow, err := AppConfig.Bool("ErrorsShow"); err == nil {
|
if timeout, err := getConfig("int64", "HttpServerTimeOut"); err == nil {
|
||||||
ErrorsShow = errorsshow
|
HttpServerTimeOut = timeout.(int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
if copyrequestbody, err := AppConfig.Bool("CopyRequestBody"); err == nil {
|
if errorsshow, err := getConfig("bool", "ErrorsShow"); err == nil {
|
||||||
CopyRequestBody = copyrequestbody
|
ErrorsShow = errorsshow.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if xsrfkey := AppConfig.String("XSRFKEY"); xsrfkey != "" {
|
if copyrequestbody, err := getConfig("bool", "CopyRequestBody"); err == nil {
|
||||||
XSRFKEY = xsrfkey
|
CopyRequestBody = copyrequestbody.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if enablexsrf, err := AppConfig.Bool("EnableXSRF"); err == nil {
|
if xsrfkey, _ := getConfig("string", "XSRFKEY"); xsrfkey != "" {
|
||||||
EnableXSRF = enablexsrf
|
XSRFKEY = xsrfkey.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expire, err := AppConfig.Int("XSRFExpire"); err == nil {
|
if enablexsrf, err := getConfig("bool", "EnableXSRF"); err == nil {
|
||||||
XSRFExpire = expire
|
EnableXSRF = enablexsrf.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tplleft := AppConfig.String("TemplateLeft"); tplleft != "" {
|
if expire, err := getConfig("int", "XSRFExpire"); err == nil {
|
||||||
TemplateLeft = tplleft
|
XSRFExpire = expire.(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tplright := AppConfig.String("TemplateRight"); tplright != "" {
|
if tplleft, _ := getConfig("string", "TemplateLeft"); tplleft != "" {
|
||||||
TemplateRight = tplright
|
TemplateLeft = tplleft.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if httptls, err := AppConfig.Bool("HttpTLS"); err == nil {
|
if tplright, _ := getConfig("string", "TemplateRight"); tplright != "" {
|
||||||
HttpTLS = httptls
|
TemplateRight = tplright.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if certfile := AppConfig.String("HttpCertFile"); certfile != "" {
|
if httptls, err := getConfig("bool", "EnableHttpTLS"); err == nil {
|
||||||
HttpCertFile = certfile
|
EnableHttpTLS = httptls.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyfile := AppConfig.String("HttpKeyFile"); keyfile != "" {
|
if httpsport, err := getConfig("int", "HttpsPort"); err == nil {
|
||||||
HttpKeyFile = keyfile
|
HttpsPort = httpsport.(int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if serverName := AppConfig.String("BeegoServerName"); serverName != "" {
|
if certfile, _ := getConfig("string", "HttpCertFile"); certfile != "" {
|
||||||
BeegoServerName = serverName
|
HttpCertFile = certfile.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if flashname := AppConfig.String("FlashName"); flashname != "" {
|
if keyfile, _ := getConfig("string", "HttpKeyFile"); keyfile != "" {
|
||||||
FlashName = flashname
|
HttpKeyFile = keyfile.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if flashseperator := AppConfig.String("FlashSeperator"); flashseperator != "" {
|
if serverName, _ := getConfig("string", "BeegoServerName"); serverName != "" {
|
||||||
FlashSeperator = flashseperator
|
BeegoServerName = serverName.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sd := AppConfig.String("StaticDir"); sd != "" {
|
if flashname, _ := getConfig("string", "FlashName"); flashname != "" {
|
||||||
|
FlashName = flashname.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if flashseperator, _ := getConfig("string", "FlashSeperator"); flashseperator != "" {
|
||||||
|
FlashSeperator = flashseperator.(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sd, _ := getConfig("string", "StaticDir"); sd != "" {
|
||||||
for k := range StaticDir {
|
for k := range StaticDir {
|
||||||
delete(StaticDir, k)
|
delete(StaticDir, k)
|
||||||
}
|
}
|
||||||
sds := strings.Fields(sd)
|
sds := strings.Fields(sd.(string))
|
||||||
for _, v := range sds {
|
for _, v := range sds {
|
||||||
if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
|
if url2fsmap := strings.SplitN(v, ":", 2); len(url2fsmap) == 2 {
|
||||||
StaticDir["/"+strings.TrimRight(url2fsmap[0], "/")] = url2fsmap[1]
|
StaticDir["/"+strings.TrimRight(url2fsmap[0], "/")] = url2fsmap[1]
|
||||||
@ -319,8 +334,8 @@ func ParseConfig() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sgz := AppConfig.String("StaticExtensionsToGzip"); sgz != "" {
|
if sgz, _ := getConfig("string", "StaticExtensionsToGzip"); sgz != "" {
|
||||||
extensions := strings.Split(sgz, ",")
|
extensions := strings.Split(sgz.(string), ",")
|
||||||
if len(extensions) > 0 {
|
if len(extensions) > 0 {
|
||||||
StaticExtensionsToGzip = []string{}
|
StaticExtensionsToGzip = []string{}
|
||||||
for _, ext := range extensions {
|
for _, ext := range extensions {
|
||||||
@ -336,17 +351,63 @@ func ParseConfig() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if enableadmin, err := AppConfig.Bool("EnableAdmin"); err == nil {
|
if enableadmin, err := getConfig("bool", "EnableAdmin"); err == nil {
|
||||||
EnableAdmin = enableadmin
|
EnableAdmin = enableadmin.(bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
if adminhttpaddr := AppConfig.String("AdminHttpAddr"); adminhttpaddr != "" {
|
if adminhttpaddr, _ := getConfig("string", "AdminHttpAddr"); adminhttpaddr != "" {
|
||||||
AdminHttpAddr = adminhttpaddr
|
AdminHttpAddr = adminhttpaddr.(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if adminhttpport, err := AppConfig.Int("AdminHttpPort"); err == nil {
|
if adminhttpport, err := getConfig("int", "AdminHttpPort"); err == nil {
|
||||||
AdminHttpPort = adminhttpport
|
AdminHttpPort = adminhttpport.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
if enabledocs, err := getConfig("bool", "EnableDocs"); err == nil {
|
||||||
|
EnableDocs = enabledocs.(bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getConfig(typ, key string) (interface{}, error) {
|
||||||
|
switch typ {
|
||||||
|
case "string":
|
||||||
|
v := AppConfig.String(RunMode + "::" + key)
|
||||||
|
if v == "" {
|
||||||
|
v = AppConfig.String(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case "strings":
|
||||||
|
v := AppConfig.Strings(RunMode + "::" + key)
|
||||||
|
if len(v) == 0 {
|
||||||
|
v = AppConfig.Strings(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case "int":
|
||||||
|
v, err := AppConfig.Int(RunMode + "::" + key)
|
||||||
|
if err != nil || v == 0 {
|
||||||
|
return AppConfig.Int(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case "bool":
|
||||||
|
v, err := AppConfig.Bool(RunMode + "::" + key)
|
||||||
|
if err != nil {
|
||||||
|
return AppConfig.Bool(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case "int64":
|
||||||
|
v, err := AppConfig.Int64(RunMode + "::" + key)
|
||||||
|
if err != nil || v == 0 {
|
||||||
|
return AppConfig.Int64(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
case "float":
|
||||||
|
v, err := AppConfig.Float(RunMode + "::" + key)
|
||||||
|
if err != nil || v == 0 {
|
||||||
|
return AppConfig.Float(key)
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
return "", errors.New("not support type")
|
||||||
|
}
|
||||||
|
@ -35,8 +35,13 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) {
|
|||||||
}
|
}
|
||||||
err = json.Unmarshal(content, &x.data)
|
err = json.Unmarshal(content, &x.data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var wrappingArray []interface{}
|
||||||
|
err2 := json.Unmarshal(content, &wrappingArray)
|
||||||
|
if err2 != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
x.data["rootArray"] = wrappingArray
|
||||||
|
}
|
||||||
return x, nil
|
return x, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,53 @@ var jsoncontext = `{
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
var jsoncontextwitharray = `[
|
||||||
|
{
|
||||||
|
"url": "user",
|
||||||
|
"serviceAPI": "http://www.test.com/user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "employee",
|
||||||
|
"serviceAPI": "http://www.test.com/employee"
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
func TestJsonStartsWithArray(t *testing.T) {
|
||||||
|
f, err := os.Create("testjsonWithArray.conf")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err = f.WriteString(jsoncontextwitharray)
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
defer os.Remove("testjsonWithArray.conf")
|
||||||
|
jsonconf, err := NewConfig("json", "testjsonWithArray.conf")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
rootArray, err := jsonconf.DIY("rootArray")
|
||||||
|
if (err != nil) {
|
||||||
|
t.Error("array does not exist as element")
|
||||||
|
}
|
||||||
|
rootArrayCasted := rootArray.([]interface{})
|
||||||
|
if (rootArrayCasted == nil) {
|
||||||
|
t.Error("array from root is nil")
|
||||||
|
}else {
|
||||||
|
elem := rootArrayCasted[0].(map[string]interface{})
|
||||||
|
if elem["url"] != "user" || elem["serviceAPI"] != "http://www.test.com/user" {
|
||||||
|
t.Error("array[0] values are not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
elem2 := rootArrayCasted[1].(map[string]interface{})
|
||||||
|
if elem2["url"] != "employee" || elem2["serviceAPI"] != "http://www.test.com/employee" {
|
||||||
|
t.Error("array[1] values are not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestJson(t *testing.T) {
|
func TestJson(t *testing.T) {
|
||||||
f, err := os.Create("testjson.conf")
|
f, err := os.Create("testjson.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -100,4 +147,28 @@ func TestJson(t *testing.T) {
|
|||||||
t.Fatal("get host err")
|
t.Fatal("get host err")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, err := jsonconf.Int("unknown"); err == nil {
|
||||||
|
t.Error("unknown keys should return an error when expecting an Int")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := jsonconf.Int64("unknown"); err == nil {
|
||||||
|
t.Error("unknown keys should return an error when expecting an Int64")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := jsonconf.Float("unknown"); err == nil {
|
||||||
|
t.Error("unknown keys should return an error when expecting a Float")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := jsonconf.DIY("unknown"); err == nil {
|
||||||
|
t.Error("unknown keys should return an error when expecting an interface{}")
|
||||||
|
}
|
||||||
|
|
||||||
|
if val := jsonconf.String("unknown"); val != "" {
|
||||||
|
t.Error("unknown keys should return an empty string when expecting a String")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := jsonconf.Bool("unknown"); err == nil {
|
||||||
|
t.Error("unknown keys should return an error when expecting a Bool")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,8 @@ func (input *BeegoInput) IsUpload() bool {
|
|||||||
func (input *BeegoInput) IP() string {
|
func (input *BeegoInput) IP() string {
|
||||||
ips := input.Proxy()
|
ips := input.Proxy()
|
||||||
if len(ips) > 0 && ips[0] != "" {
|
if len(ips) > 0 && ips[0] != "" {
|
||||||
return ips[0]
|
rip := strings.Split(ips[0], ":")
|
||||||
|
return rip[0]
|
||||||
}
|
}
|
||||||
ip := strings.Split(input.Request.RemoteAddr, ":")
|
ip := strings.Split(input.Request.RemoteAddr, ":")
|
||||||
if len(ip) > 0 {
|
if len(ip) > 0 {
|
||||||
|
@ -237,10 +237,14 @@ func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error {
|
|||||||
|
|
||||||
// Download forces response for download file.
|
// Download forces response for download file.
|
||||||
// it prepares the download response header automatically.
|
// it prepares the download response header automatically.
|
||||||
func (output *BeegoOutput) Download(file string) {
|
func (output *BeegoOutput) Download(file string, filename ...string) {
|
||||||
output.Header("Content-Description", "File Transfer")
|
output.Header("Content-Description", "File Transfer")
|
||||||
output.Header("Content-Type", "application/octet-stream")
|
output.Header("Content-Type", "application/octet-stream")
|
||||||
|
if len(filename) > 0 && filename[0] != "" {
|
||||||
|
output.Header("Content-Disposition", "attachment; filename="+filename[0])
|
||||||
|
} else {
|
||||||
output.Header("Content-Disposition", "attachment; filename="+filepath.Base(file))
|
output.Header("Content-Disposition", "attachment; filename="+filepath.Base(file))
|
||||||
|
}
|
||||||
output.Header("Content-Transfer-Encoding", "binary")
|
output.Header("Content-Transfer-Encoding", "binary")
|
||||||
output.Header("Expires", "0")
|
output.Header("Expires", "0")
|
||||||
output.Header("Cache-Control", "must-revalidate")
|
output.Header("Cache-Control", "must-revalidate")
|
||||||
|
@ -28,15 +28,24 @@ import (
|
|||||||
//commonly used mime-types
|
//commonly used mime-types
|
||||||
const (
|
const (
|
||||||
applicationJson = "application/json"
|
applicationJson = "application/json"
|
||||||
applicationXml = "applicatoin/xml"
|
applicationXml = "application/xml"
|
||||||
textXml = "text/xml"
|
textXml = "text/xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
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][]ControllerComments = make(map[string][]ControllerComments) //pkgpath+controller:comments
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// store the comment for the controller method
|
||||||
|
type ControllerComments struct {
|
||||||
|
Method string
|
||||||
|
Router string
|
||||||
|
AllowHTTPMethods []string
|
||||||
|
Params []map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
// Controller defines some basic http request handler operations, such as
|
// Controller defines some basic http request handler operations, such as
|
||||||
// http context, template and view, session and xsrf.
|
// http context, template and view, session and xsrf.
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
@ -55,6 +64,7 @@ type Controller struct {
|
|||||||
AppController interface{}
|
AppController interface{}
|
||||||
EnableRender bool
|
EnableRender bool
|
||||||
EnableXSRF bool
|
EnableXSRF bool
|
||||||
|
methodMapping map[string]func() //method:routertree
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControllerInterface is an interface to uniform all controller handler.
|
// ControllerInterface is an interface to uniform all controller handler.
|
||||||
@ -72,6 +82,8 @@ type ControllerInterface interface {
|
|||||||
Render() error
|
Render() error
|
||||||
XsrfToken() string
|
XsrfToken() string
|
||||||
CheckXsrfCookie() bool
|
CheckXsrfCookie() bool
|
||||||
|
HandlerFunc(fn string) bool
|
||||||
|
URLMapping()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init generates default values of controller operations.
|
// Init generates default values of controller operations.
|
||||||
@ -86,6 +98,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.methodMapping = make(map[string]func())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare runs after Init before request function execution.
|
// Prepare runs after Init before request function execution.
|
||||||
@ -133,6 +146,24 @@ 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(fnname string) bool {
|
||||||
|
if v, ok := c.methodMapping[fnname]; ok {
|
||||||
|
v()
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLMapping register the internal Controller router.
|
||||||
|
func (c *Controller) URLMapping() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Controller) Mapping(method string, fn func()) {
|
||||||
|
c.methodMapping[method] = fn
|
||||||
|
}
|
||||||
|
|
||||||
// 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() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
@ -452,7 +482,7 @@ func (c *Controller) XsrfToken() string {
|
|||||||
} else {
|
} else {
|
||||||
expire = int64(XSRFExpire)
|
expire = int64(XSRFExpire)
|
||||||
}
|
}
|
||||||
token = string(utils.RandomCreateBytes(15))
|
token = string(utils.RandomCreateBytes(32))
|
||||||
c.SetSecureCookie(XSRFKEY, "_xsrf", token, expire)
|
c.SetSecureCookie(XSRFKEY, "_xsrf", token, expire)
|
||||||
}
|
}
|
||||||
c._xsrf_token = token
|
c._xsrf_token = token
|
||||||
|
38
docs.go
Normal file
38
docs.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package beego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
var GlobalDocApi map[string]interface{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if EnableDocs {
|
||||||
|
GlobalDocApi = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serverDocs(ctx *context.Context) {
|
||||||
|
var obj interface{}
|
||||||
|
if splat := ctx.Input.Param(":splat"); splat == "" {
|
||||||
|
obj = GlobalDocApi["Root"]
|
||||||
|
} else {
|
||||||
|
if v, ok := GlobalDocApi[splat]; ok {
|
||||||
|
obj = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if obj != nil {
|
||||||
|
bt, err := json.Marshal(obj)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Output.SetStatus(504)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Output.Header("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
ctx.Output.Header("Access-Control-Allow-Origin", "*")
|
||||||
|
ctx.Output.Body(bt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Output.SetStatus(404)
|
||||||
|
}
|
@ -60,9 +60,9 @@ func (c *connection) readPump() {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch op {
|
switch op {
|
||||||
case websocket.OpPong:
|
case websocket.PongMessage:
|
||||||
c.ws.SetReadDeadline(time.Now().Add(readWait))
|
c.ws.SetReadDeadline(time.Now().Add(readWait))
|
||||||
case websocket.OpText:
|
case websocket.TextMessage:
|
||||||
message, err := ioutil.ReadAll(r)
|
message, err := ioutil.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
@ -89,14 +89,14 @@ func (c *connection) writePump() {
|
|||||||
select {
|
select {
|
||||||
case message, ok := <-c.send:
|
case message, ok := <-c.send:
|
||||||
if !ok {
|
if !ok {
|
||||||
c.write(websocket.OpClose, []byte{})
|
c.write(websocket.CloseMessage, []byte{})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := c.write(websocket.OpText, message); err != nil {
|
if err := c.write(websocket.TextMessage, message); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
if err := c.write(websocket.OpPing, []byte{}); err != nil {
|
if err := c.write(websocket.PingMessage, []byte{}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,8 +149,13 @@ type WSController struct {
|
|||||||
beego.Controller
|
beego.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{
|
||||||
|
ReadBufferSize: 1024,
|
||||||
|
WriteBufferSize: 1024,
|
||||||
|
}
|
||||||
|
|
||||||
func (this *WSController) Get() {
|
func (this *WSController) Get() {
|
||||||
ws, err := websocket.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request.Header, nil, 1024, 1024)
|
ws, err := upgrader.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request,nil)
|
||||||
if _, ok := err.(websocket.HandshakeError); ok {
|
if _, ok := err.(websocket.HandshakeError); ok {
|
||||||
http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400)
|
http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400)
|
||||||
return
|
return
|
||||||
|
148
filter.go
148
filter.go
@ -6,154 +6,24 @@
|
|||||||
|
|
||||||
package beego
|
package beego
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
regex *regexp.Regexp
|
|
||||||
filterFunc FilterFunc
|
filterFunc FilterFunc
|
||||||
hasregex bool
|
tree *Tree
|
||||||
params map[int]string
|
pattern 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 {
|
||||||
}
|
|
||||||
if mr.pattern == "*" {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
if router == mr.pattern {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
//pattern /admin router /admin/ match
|
|
||||||
//pattern /admin/ router /admin don't match, because url will 301 in router
|
|
||||||
if n := len(router); n > 1 && router[n-1] == '/' && router[:n-2] == mr.pattern {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if mr.hasregex {
|
|
||||||
if !mr.regex.MatchString(router) {
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
matches := mr.regex.FindStringSubmatch(router)
|
if isok, ok := isok.(bool); ok {
|
||||||
if len(matches) > 0 {
|
return isok, params
|
||||||
if len(matches[0]) == len(router) {
|
} else {
|
||||||
params := make(map[string]string)
|
|
||||||
for i, match := range matches[1:] {
|
|
||||||
params[mr.params[i]] = match
|
|
||||||
}
|
|
||||||
return true, params
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFilter(pattern string, filter FilterFunc) (*FilterRouter, error) {
|
|
||||||
mr := new(FilterRouter)
|
|
||||||
mr.params = make(map[int]string)
|
|
||||||
mr.filterFunc = filter
|
|
||||||
parts := strings.Split(pattern, "/")
|
|
||||||
j := 0
|
|
||||||
for i, part := range parts {
|
|
||||||
if strings.HasPrefix(part, ":") {
|
|
||||||
expr := "(.*)"
|
|
||||||
//a user may choose to override the default expression
|
|
||||||
// similar to expressjs: ‘/user/:id([0-9]+)’
|
|
||||||
if index := strings.Index(part, "("); index != -1 {
|
|
||||||
expr = part[index:]
|
|
||||||
part = part[:index]
|
|
||||||
//match /user/:id:int ([0-9]+)
|
|
||||||
//match /post/:username:string ([\w]+)
|
|
||||||
} else if lindex := strings.LastIndex(part, ":"); lindex != 0 {
|
|
||||||
switch part[lindex:] {
|
|
||||||
case ":int":
|
|
||||||
expr = "([0-9]+)"
|
|
||||||
part = part[:lindex]
|
|
||||||
case ":string":
|
|
||||||
expr = `([\w]+)`
|
|
||||||
part = part[:lindex]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mr.params[j] = part
|
|
||||||
parts[i] = expr
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(part, "*") {
|
|
||||||
expr := "(.*)"
|
|
||||||
if part == "*.*" {
|
|
||||||
mr.params[j] = ":path"
|
|
||||||
parts[i] = "([^.]+).([^.]+)"
|
|
||||||
j++
|
|
||||||
mr.params[j] = ":ext"
|
|
||||||
j++
|
|
||||||
} else {
|
|
||||||
mr.params[j] = ":splat"
|
|
||||||
parts[i] = expr
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//url like someprefix:id(xxx).html
|
|
||||||
if strings.Contains(part, ":") && strings.Contains(part, "(") && strings.Contains(part, ")") {
|
|
||||||
var out []rune
|
|
||||||
var start bool
|
|
||||||
var startexp bool
|
|
||||||
var param []rune
|
|
||||||
var expt []rune
|
|
||||||
for _, v := range part {
|
|
||||||
if start {
|
|
||||||
if v != '(' {
|
|
||||||
param = append(param, v)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if startexp {
|
|
||||||
if v != ')' {
|
|
||||||
expt = append(expt, v)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v == ':' {
|
|
||||||
param = make([]rune, 0)
|
|
||||||
param = append(param, ':')
|
|
||||||
start = true
|
|
||||||
} else if v == '(' {
|
|
||||||
startexp = true
|
|
||||||
start = false
|
|
||||||
mr.params[j] = string(param)
|
|
||||||
j++
|
|
||||||
expt = make([]rune, 0)
|
|
||||||
expt = append(expt, '(')
|
|
||||||
} else if v == ')' {
|
|
||||||
startexp = false
|
|
||||||
expt = append(expt, ')')
|
|
||||||
out = append(out, expt...)
|
|
||||||
} else {
|
|
||||||
out = append(out, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parts[i] = string(out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if j != 0 {
|
|
||||||
pattern = strings.Join(parts, "/")
|
|
||||||
regex, regexErr := regexp.Compile(pattern)
|
|
||||||
if regexErr != nil {
|
|
||||||
return nil, regexErr
|
|
||||||
}
|
|
||||||
mr.regex = regex
|
|
||||||
mr.hasregex = true
|
|
||||||
}
|
|
||||||
mr.pattern = pattern
|
|
||||||
return mr, nil
|
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,8 @@ var FilterUser = func(ctx *context.Context) {
|
|||||||
func TestFilter(t *testing.T) {
|
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 := NewControllerRegister()
|
||||||
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" {
|
||||||
@ -40,8 +40,8 @@ var FilterAdminUser = func(ctx *context.Context) {
|
|||||||
func TestPatternTwo(t *testing.T) {
|
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 := NewControllerRegister()
|
||||||
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")
|
||||||
@ -51,8 +51,8 @@ func TestPatternTwo(t *testing.T) {
|
|||||||
func TestPatternThree(t *testing.T) {
|
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 := NewControllerRegister()
|
||||||
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")
|
||||||
|
@ -31,7 +31,7 @@ func TestFlashHeader(t *testing.T) {
|
|||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
// setup the handler
|
// setup the handler
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
|
handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
@ -16,22 +16,45 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/cookiejar"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultUserAgent = "beegoServer"
|
var defaultSetting = BeegoHttpSettings{false, "beegoServer", 60 * time.Second, 60 * time.Second, nil, nil, nil, false}
|
||||||
|
var defaultCookieJar http.CookieJar
|
||||||
|
var settingMutex sync.Mutex
|
||||||
|
|
||||||
|
// createDefaultCookieJar creates a global cookiejar to store cookies.
|
||||||
|
func createDefaultCookie() {
|
||||||
|
settingMutex.Lock()
|
||||||
|
defer settingMutex.Unlock()
|
||||||
|
defaultCookieJar, _ = cookiejar.New(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite default settings
|
||||||
|
func SetDefaultSetting(setting BeegoHttpSettings) {
|
||||||
|
settingMutex.Lock()
|
||||||
|
defer settingMutex.Unlock()
|
||||||
|
defaultSetting = setting
|
||||||
|
if defaultSetting.ConnectTimeout == 0 {
|
||||||
|
defaultSetting.ConnectTimeout = 60 * time.Second
|
||||||
|
}
|
||||||
|
if defaultSetting.ReadWriteTimeout == 0 {
|
||||||
|
defaultSetting.ReadWriteTimeout = 60 * time.Second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns *BeegoHttpRequest with GET method.
|
// Get returns *BeegoHttpRequest with GET method.
|
||||||
func Get(url string) *BeegoHttpRequest {
|
func Get(url string) *BeegoHttpRequest {
|
||||||
var req http.Request
|
var req http.Request
|
||||||
req.Method = "GET"
|
req.Method = "GET"
|
||||||
req.Header = http.Header{}
|
req.Header = http.Header{}
|
||||||
req.Header.Set("User-Agent", defaultUserAgent)
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post returns *BeegoHttpRequest with POST method.
|
// Post returns *BeegoHttpRequest with POST method.
|
||||||
@ -39,8 +62,7 @@ func Post(url string) *BeegoHttpRequest {
|
|||||||
var req http.Request
|
var req http.Request
|
||||||
req.Method = "POST"
|
req.Method = "POST"
|
||||||
req.Header = http.Header{}
|
req.Header = http.Header{}
|
||||||
req.Header.Set("User-Agent", defaultUserAgent)
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put returns *BeegoHttpRequest with PUT method.
|
// Put returns *BeegoHttpRequest with PUT method.
|
||||||
@ -48,8 +70,7 @@ func Put(url string) *BeegoHttpRequest {
|
|||||||
var req http.Request
|
var req http.Request
|
||||||
req.Method = "PUT"
|
req.Method = "PUT"
|
||||||
req.Header = http.Header{}
|
req.Header = http.Header{}
|
||||||
req.Header.Set("User-Agent", defaultUserAgent)
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete returns *BeegoHttpRequest DELETE GET method.
|
// Delete returns *BeegoHttpRequest DELETE GET method.
|
||||||
@ -57,8 +78,7 @@ func Delete(url string) *BeegoHttpRequest {
|
|||||||
var req http.Request
|
var req http.Request
|
||||||
req.Method = "DELETE"
|
req.Method = "DELETE"
|
||||||
req.Header = http.Header{}
|
req.Header = http.Header{}
|
||||||
req.Header.Set("User-Agent", defaultUserAgent)
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Head returns *BeegoHttpRequest with HEAD method.
|
// Head returns *BeegoHttpRequest with HEAD method.
|
||||||
@ -66,8 +86,19 @@ func Head(url string) *BeegoHttpRequest {
|
|||||||
var req http.Request
|
var req http.Request
|
||||||
req.Method = "HEAD"
|
req.Method = "HEAD"
|
||||||
req.Header = http.Header{}
|
req.Header = http.Header{}
|
||||||
req.Header.Set("User-Agent", defaultUserAgent)
|
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, defaultSetting}
|
||||||
return &BeegoHttpRequest{url, &req, map[string]string{}, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil}
|
}
|
||||||
|
|
||||||
|
// BeegoHttpSettings
|
||||||
|
type BeegoHttpSettings struct {
|
||||||
|
ShowDebug bool
|
||||||
|
UserAgent string
|
||||||
|
ConnectTimeout time.Duration
|
||||||
|
ReadWriteTimeout time.Duration
|
||||||
|
TlsClientConfig *tls.Config
|
||||||
|
Proxy func(*http.Request) (*url.URL, error)
|
||||||
|
Transport http.RoundTripper
|
||||||
|
EnableCookie bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// BeegoHttpRequest provides more useful methods for requesting one url than http.Request.
|
// BeegoHttpRequest provides more useful methods for requesting one url than http.Request.
|
||||||
@ -76,30 +107,43 @@ type BeegoHttpRequest struct {
|
|||||||
req *http.Request
|
req *http.Request
|
||||||
params map[string]string
|
params map[string]string
|
||||||
files map[string]string
|
files map[string]string
|
||||||
showdebug bool
|
setting BeegoHttpSettings
|
||||||
connectTimeout time.Duration
|
}
|
||||||
readWriteTimeout time.Duration
|
|
||||||
tlsClientConfig *tls.Config
|
// Change request settings
|
||||||
proxy func(*http.Request) (*url.URL, error)
|
func (b *BeegoHttpRequest) Setting(setting BeegoHttpSettings) *BeegoHttpRequest {
|
||||||
transport http.RoundTripper
|
b.setting = setting
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEnableCookie sets enable/disable cookiejar
|
||||||
|
func (b *BeegoHttpRequest) SetEnableCookie(enable bool) *BeegoHttpRequest {
|
||||||
|
b.setting.EnableCookie = enable
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserAgent sets User-Agent header field
|
||||||
|
func (b *BeegoHttpRequest) SetAgent(useragent string) *BeegoHttpRequest {
|
||||||
|
b.setting.UserAgent = useragent
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug sets show debug or not when executing request.
|
// Debug sets show debug or not when executing request.
|
||||||
func (b *BeegoHttpRequest) Debug(isdebug bool) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) Debug(isdebug bool) *BeegoHttpRequest {
|
||||||
b.showdebug = isdebug
|
b.setting.ShowDebug = isdebug
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTimeout sets connect time out and read-write time out for BeegoRequest.
|
// SetTimeout sets connect time out and read-write time out for BeegoRequest.
|
||||||
func (b *BeegoHttpRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHttpRequest {
|
||||||
b.connectTimeout = connectTimeout
|
b.setting.ConnectTimeout = connectTimeout
|
||||||
b.readWriteTimeout = readWriteTimeout
|
b.setting.ReadWriteTimeout = readWriteTimeout
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTLSClientConfig sets tls connection configurations if visiting https url.
|
// SetTLSClientConfig sets tls connection configurations if visiting https url.
|
||||||
func (b *BeegoHttpRequest) SetTLSClientConfig(config *tls.Config) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) SetTLSClientConfig(config *tls.Config) *BeegoHttpRequest {
|
||||||
b.tlsClientConfig = config
|
b.setting.TlsClientConfig = config
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +178,7 @@ func (b *BeegoHttpRequest) SetCookie(cookie *http.Cookie) *BeegoHttpRequest {
|
|||||||
|
|
||||||
// Set transport to
|
// Set transport to
|
||||||
func (b *BeegoHttpRequest) SetTransport(transport http.RoundTripper) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) SetTransport(transport http.RoundTripper) *BeegoHttpRequest {
|
||||||
b.transport = transport
|
b.setting.Transport = transport
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +190,7 @@ func (b *BeegoHttpRequest) SetTransport(transport http.RoundTripper) *BeegoHttpR
|
|||||||
// return u, nil
|
// return u, nil
|
||||||
// }
|
// }
|
||||||
func (b *BeegoHttpRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHttpRequest {
|
func (b *BeegoHttpRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHttpRequest {
|
||||||
b.proxy = proxy
|
b.setting.Proxy = proxy
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,7 +286,7 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.req.URL = url
|
b.req.URL = url
|
||||||
if b.showdebug {
|
if b.setting.ShowDebug {
|
||||||
dump, err := httputil.DumpRequest(b.req, true)
|
dump, err := httputil.DumpRequest(b.req, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
@ -250,32 +294,47 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
|||||||
println(string(dump))
|
println(string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
trans := b.transport
|
trans := b.setting.Transport
|
||||||
|
|
||||||
if trans == nil {
|
if trans == nil {
|
||||||
// create default transport
|
// create default transport
|
||||||
trans = &http.Transport{
|
trans = &http.Transport{
|
||||||
TLSClientConfig: b.tlsClientConfig,
|
TLSClientConfig: b.setting.TlsClientConfig,
|
||||||
Proxy: b.proxy,
|
Proxy: b.setting.Proxy,
|
||||||
Dial: TimeoutDialer(b.connectTimeout, b.readWriteTimeout),
|
Dial: TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if b.transport is *http.Transport then set the settings.
|
// if b.transport is *http.Transport then set the settings.
|
||||||
if t, ok := trans.(*http.Transport); ok {
|
if t, ok := trans.(*http.Transport); ok {
|
||||||
if t.TLSClientConfig == nil {
|
if t.TLSClientConfig == nil {
|
||||||
t.TLSClientConfig = b.tlsClientConfig
|
t.TLSClientConfig = b.setting.TlsClientConfig
|
||||||
}
|
}
|
||||||
if t.Proxy == nil {
|
if t.Proxy == nil {
|
||||||
t.Proxy = b.proxy
|
t.Proxy = b.setting.Proxy
|
||||||
}
|
}
|
||||||
if t.Dial == nil {
|
if t.Dial == nil {
|
||||||
t.Dial = TimeoutDialer(b.connectTimeout, b.readWriteTimeout)
|
t.Dial = TimeoutDialer(b.setting.ConnectTimeout, b.setting.ReadWriteTimeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jar http.CookieJar
|
||||||
|
if b.setting.EnableCookie {
|
||||||
|
if defaultCookieJar == nil {
|
||||||
|
createDefaultCookie()
|
||||||
|
}
|
||||||
|
jar = defaultCookieJar
|
||||||
|
} else {
|
||||||
|
jar = nil
|
||||||
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: trans,
|
Transport: trans,
|
||||||
|
Jar: jar,
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.setting.UserAgent != "" {
|
||||||
|
b.req.Header.Set("User-Agent", b.setting.UserAgent)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Do(b.req)
|
resp, err := client.Do(b.req)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Beego (http://beego.me/)
|
// Beego (http://beego.me)
|
||||||
// @description beego is an open-source, high-performance web framework for the Go programming language.
|
// @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
|
// @link http://github.com/astaxie/beego for the canonical source repository
|
||||||
// @license http://github.com/astaxie/beego/blob/master/LICENSE
|
// @license http://github.com/astaxie/beego/blob/master/LICENSE
|
||||||
@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestGetUrl(t *testing.T) {
|
func TestGetUrl(t *testing.T) {
|
||||||
resp, err := Get("http://beego.me/").Debug(true).Response()
|
resp, err := Get("http://beego.me").Debug(true).Response()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ func TestGetUrl(t *testing.T) {
|
|||||||
t.Fatal("data is no")
|
t.Fatal("data is no")
|
||||||
}
|
}
|
||||||
|
|
||||||
str, err := Get("http://beego.me/").String()
|
str, err := Get("http://beego.me").String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -38,14 +38,63 @@ func TestGetUrl(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPost(t *testing.T) {
|
func ExamplePost(t *testing.T) {
|
||||||
b := Post("http://beego.me/").Debug(true)
|
b := Post("http://beego.me/").Debug(true)
|
||||||
b.Param("username", "astaxie")
|
b.Param("username", "astaxie")
|
||||||
b.Param("password", "hello")
|
b.Param("password", "hello")
|
||||||
b.PostFile("uploadfile", "httplib.go")
|
b.PostFile("uploadfile", "httplib_test.go")
|
||||||
str, err := b.String()
|
str, err := b.String()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
fmt.Println(str)
|
fmt.Println(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSimpleGetString(t *testing.T) {
|
||||||
|
fmt.Println("TestSimpleGetString==========================================")
|
||||||
|
html, err := Get("http://httpbin.org/headers").SetAgent("beegoooooo").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(html)
|
||||||
|
fmt.Println("TestSimpleGetString==========================================")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSimpleGetStringWithDefaultCookie(t *testing.T) {
|
||||||
|
fmt.Println("TestSimpleGetStringWithDefaultCookie==========================================")
|
||||||
|
html, err := Get("http://httpbin.org/cookies/set?k1=v1").SetEnableCookie(true).String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(html)
|
||||||
|
html, err = Get("http://httpbin.org/cookies").SetEnableCookie(true).String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(html)
|
||||||
|
fmt.Println("TestSimpleGetStringWithDefaultCookie==========================================")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDefaultSetting(t *testing.T) {
|
||||||
|
fmt.Println("TestDefaultSetting==========================================")
|
||||||
|
var def BeegoHttpSettings
|
||||||
|
def.EnableCookie = true
|
||||||
|
//def.ShowDebug = true
|
||||||
|
def.UserAgent = "UserAgent"
|
||||||
|
//def.ConnectTimeout = 60*time.Second
|
||||||
|
//def.ReadWriteTimeout = 60*time.Second
|
||||||
|
def.Transport = nil //http.DefaultTransport
|
||||||
|
SetDefaultSetting(def)
|
||||||
|
|
||||||
|
html, err := Get("http://httpbin.org/headers").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(html)
|
||||||
|
html, err = Get("http://httpbin.org/headers").String()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Println(html)
|
||||||
|
fmt.Println("TestDefaultSetting==========================================")
|
||||||
|
}
|
||||||
|
313
namespace.go
313
namespace.go
@ -7,131 +7,372 @@ 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
|
||||||
|
|
||||||
|
type innnerNamespace func(*Namespace)
|
||||||
|
|
||||||
|
// Namespace is store all the info
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
prefix string
|
prefix string
|
||||||
condition namespaceCond
|
|
||||||
handlers *ControllerRegistor
|
handlers *ControllerRegistor
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNamespace(prefix string) *Namespace {
|
// get new Namespace
|
||||||
cr := NewControllerRegistor()
|
func NewNamespace(prefix string, params ...innnerNamespace) *Namespace {
|
||||||
return &Namespace{
|
ns := &Namespace{
|
||||||
prefix: prefix,
|
prefix: prefix,
|
||||||
handlers: cr,
|
handlers: NewControllerRegister(),
|
||||||
}
|
}
|
||||||
|
for _, p := range params {
|
||||||
|
p(ns)
|
||||||
|
}
|
||||||
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set condtion function
|
||||||
|
// if cond return true can run this namespace, else can't
|
||||||
|
// usage:
|
||||||
|
// ns.Cond(func (ctx *context.Context) bool{
|
||||||
|
// if ctx.Input.Domain() == "api.beego.me" {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// 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) {
|
||||||
return n
|
if !cond(ctx) {
|
||||||
}
|
middleware.Exception("405", ctx.ResponseWriter, ctx.Request, "Method not allowed")
|
||||||
|
}
|
||||||
func (n *Namespace) Filter(action string, filter FilterFunc) *Namespace {
|
}
|
||||||
if action == "before" {
|
if v, ok := n.handlers.filters[BeforeRouter]; ok {
|
||||||
action = "BeforeRouter"
|
mr := new(FilterRouter)
|
||||||
} else if action == "after" {
|
mr.tree = NewTree()
|
||||||
action = "FinishRouter"
|
mr.pattern = "*"
|
||||||
|
mr.filterFunc = fn
|
||||||
|
mr.tree.AddRouter("*", true)
|
||||||
|
n.handlers.filters[BeforeRouter] = append([]*FilterRouter{mr}, v...)
|
||||||
|
} else {
|
||||||
|
n.handlers.InsertFilter("*", BeforeRouter, fn)
|
||||||
}
|
}
|
||||||
n.handlers.AddFilter("*", action, filter)
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add filter in the Namespace
|
||||||
|
// action has before & after
|
||||||
|
// FilterFunc
|
||||||
|
// usage:
|
||||||
|
// Filter("before", func (ctx *context.Context){
|
||||||
|
// _, ok := ctx.Input.Session("uid").(int)
|
||||||
|
// if !ok && ctx.Request.RequestURI != "/login" {
|
||||||
|
// ctx.Redirect(302, "/login")
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
|
||||||
|
var a int
|
||||||
|
if action == "before" {
|
||||||
|
a = BeforeRouter
|
||||||
|
} else if action == "after" {
|
||||||
|
a = FinishRouter
|
||||||
|
}
|
||||||
|
for _, f := range filter {
|
||||||
|
n.handlers.InsertFilter("*", a, f)
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as beego.Rourer
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Router
|
||||||
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
|
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
|
||||||
n.handlers.Add(rootpath, c, mappingMethods...)
|
n.handlers.Add(rootpath, c, mappingMethods...)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.AutoRouter
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#AutoRouter
|
||||||
func (n *Namespace) AutoRouter(c ControllerInterface) *Namespace {
|
func (n *Namespace) AutoRouter(c ControllerInterface) *Namespace {
|
||||||
n.handlers.AddAuto(c)
|
n.handlers.AddAuto(c)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.AutoPrefix
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#AutoPrefix
|
||||||
func (n *Namespace) AutoPrefix(prefix string, c ControllerInterface) *Namespace {
|
func (n *Namespace) AutoPrefix(prefix string, c ControllerInterface) *Namespace {
|
||||||
n.handlers.AddAutoPrefix(prefix, c)
|
n.handlers.AddAutoPrefix(prefix, c)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Get
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Get
|
||||||
func (n *Namespace) Get(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Get(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Get(rootpath, f)
|
n.handlers.Get(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Post
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Post
|
||||||
func (n *Namespace) Post(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Post(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Post(rootpath, f)
|
n.handlers.Post(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Delete
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Delete
|
||||||
func (n *Namespace) Delete(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Delete(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Delete(rootpath, f)
|
n.handlers.Delete(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Put
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Put
|
||||||
func (n *Namespace) Put(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Put(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Put(rootpath, f)
|
n.handlers.Put(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Head
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Head
|
||||||
func (n *Namespace) Head(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Head(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Head(rootpath, f)
|
n.handlers.Head(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Options
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Options
|
||||||
func (n *Namespace) Options(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Options(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Options(rootpath, f)
|
n.handlers.Options(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Patch
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Patch
|
||||||
func (n *Namespace) Patch(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Patch(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Patch(rootpath, f)
|
n.handlers.Patch(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Any
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Any
|
||||||
func (n *Namespace) Any(rootpath string, f FilterFunc) *Namespace {
|
func (n *Namespace) Any(rootpath string, f FilterFunc) *Namespace {
|
||||||
n.handlers.Any(rootpath, f)
|
n.handlers.Any(rootpath, f)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same as beego.Handler
|
||||||
|
// refer: https://godoc.org/github.com/astaxie/beego#Handler
|
||||||
func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
|
func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
|
||||||
n.handlers.Handler(rootpath, h)
|
n.handlers.Handler(rootpath, h)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Namespace) Namespace(ns *Namespace) *Namespace {
|
// add include class
|
||||||
n.handlers.Handler(ns.prefix, ns, true)
|
// refer: https://godoc.org/github.com/astaxie/beego#Include
|
||||||
|
func (n *Namespace) Include(cList ...ControllerInterface) *Namespace {
|
||||||
|
n.handlers.Include(cList...)
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Namespace) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
// nest Namespace
|
||||||
//trim the preifix from URL.Path
|
// usage:
|
||||||
r.URL.Path = strings.TrimPrefix(r.URL.Path, n.prefix)
|
//ns := beego.NewNamespace(“/v1”).
|
||||||
// init context
|
//Namespace(
|
||||||
context := &beecontext.Context{
|
// beego.NewNamespace("/shop").
|
||||||
ResponseWriter: rw,
|
// Get("/:id", func(ctx *context.Context) {
|
||||||
Request: r,
|
// ctx.Output.Body([]byte("shopinfo"))
|
||||||
Input: beecontext.NewInput(r),
|
// }),
|
||||||
Output: beecontext.NewOutput(),
|
// beego.NewNamespace("/order").
|
||||||
|
// Get("/:id", func(ctx *context.Context) {
|
||||||
|
// ctx.Output.Body([]byte("orderinfo"))
|
||||||
|
// }),
|
||||||
|
// beego.NewNamespace("/crm").
|
||||||
|
// Get("/:id", func(ctx *context.Context) {
|
||||||
|
// ctx.Output.Body([]byte("crminfo"))
|
||||||
|
// }),
|
||||||
|
//)
|
||||||
|
func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
|
||||||
|
for _, ni := range ns {
|
||||||
|
for k, v := range ni.handlers.routers {
|
||||||
|
if t, ok := n.handlers.routers[k]; ok {
|
||||||
|
addPrefix(v, ni.prefix)
|
||||||
|
n.handlers.routers[k].AddTree(ni.prefix, v)
|
||||||
|
} else {
|
||||||
|
t = NewTree()
|
||||||
|
t.AddTree(ni.prefix, v)
|
||||||
|
addPrefix(t, ni.prefix)
|
||||||
|
n.handlers.routers[k] = t
|
||||||
}
|
}
|
||||||
context.Output.Context = context
|
|
||||||
context.Output.EnableGzip = EnableGzip
|
|
||||||
|
|
||||||
if context.Input.IsWebsocket() {
|
|
||||||
context.ResponseWriter = rw
|
|
||||||
}
|
}
|
||||||
if n.condition != nil && !n.condition(context) {
|
if n.handlers.enableFilter {
|
||||||
http.Error(rw, "Method Not Allowed", 405)
|
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)
|
||||||
}
|
}
|
||||||
n.handlers.ServeHTTP(rw, r)
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// register Namespace into beego.Handler
|
||||||
|
// support multi Namespace
|
||||||
func AddNamespace(nl ...*Namespace) {
|
func AddNamespace(nl ...*Namespace) {
|
||||||
for _, n := range nl {
|
for _, n := range nl {
|
||||||
Handler(n.prefix, n, true)
|
for k, v := range n.handlers.routers {
|
||||||
|
if t, ok := BeeApp.Handlers.routers[k]; ok {
|
||||||
|
addPrefix(v, n.prefix)
|
||||||
|
BeeApp.Handlers.routers[k].AddTree(n.prefix, v)
|
||||||
|
} else {
|
||||||
|
t = NewTree()
|
||||||
|
t.AddTree(n.prefix, v)
|
||||||
|
addPrefix(t, n.prefix)
|
||||||
|
BeeApp.Handlers.routers[k] = t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addPrefix(t *Tree, prefix string) {
|
||||||
|
for _, v := range t.fixrouters {
|
||||||
|
addPrefix(v, prefix)
|
||||||
|
}
|
||||||
|
if t.wildcard != nil {
|
||||||
|
addPrefix(t.wildcard, prefix)
|
||||||
|
}
|
||||||
|
for _, l := range t.leaves {
|
||||||
|
if c, ok := l.runObject.(*controllerInfo); ok {
|
||||||
|
c.pattern = prefix + c.pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Condition
|
||||||
|
func NSCond(cond namespaceCond) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Cond(cond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace BeforeRouter filter
|
||||||
|
func NSBefore(filiterList ...FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Filter("before", filiterList...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace FinishRouter filter
|
||||||
|
func NSAfter(filiterList ...FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Filter("after", filiterList...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Include ControllerInterface
|
||||||
|
func NSInclude(cList ...ControllerInterface) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Include(cList...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Router
|
||||||
|
func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Router(rootpath, c, mappingMethods...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Get
|
||||||
|
func NSGet(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Get(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Post
|
||||||
|
func NSPost(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Post(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Head
|
||||||
|
func NSHead(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Head(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Put
|
||||||
|
func NSPut(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Put(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Delete
|
||||||
|
func NSDelete(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Delete(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Any
|
||||||
|
func NSAny(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Any(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Options
|
||||||
|
func NSOptions(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Options(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace Patch
|
||||||
|
func NSPatch(rootpath string, f FilterFunc) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.Patch(rootpath, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Namespace AutoRouter
|
||||||
|
func NSAutoRouter(c ControllerInterface) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.AutoRouter(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace AutoPrefix
|
||||||
|
func NSAutoPrefix(prefix string, c ControllerInterface) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
ns.AutoPrefix(prefix, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Namespace add sub Namespace
|
||||||
|
func NSNamespace(prefix string, params ...innnerNamespace) innnerNamespace {
|
||||||
|
return func(ns *Namespace) {
|
||||||
|
n := NewNamespace(prefix, params...)
|
||||||
|
ns.Namespace(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
|||||||
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) {
|
|||||||
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,12 +74,39 @@ 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 TestNamespaceRouter(t *testing.T) {
|
||||||
|
r, _ := http.NewRequest("GET", "/v1/api/list", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
ns := NewNamespace("/v1")
|
||||||
|
ns.Router("/api/list", &TestController{}, "*:List")
|
||||||
|
AddNamespace(ns)
|
||||||
|
BeeApp.Handlers.ServeHTTP(w, r)
|
||||||
|
if w.Body.String() != "i am list" {
|
||||||
|
t.Errorf("TestNamespaceRouter can't run, get the response is " + w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamespaceAutoFunc(t *testing.T) {
|
||||||
|
r, _ := http.NewRequest("GET", "/v1/test/list", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
ns := NewNamespace("/v1")
|
||||||
|
ns.AutoRouter(&TestController{})
|
||||||
|
AddNamespace(ns)
|
||||||
|
BeeApp.Handlers.ServeHTTP(w, r)
|
||||||
|
if w.Body.String() != "i am list" {
|
||||||
|
t.Errorf("user define func can't run")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNamespaceFilter(t *testing.T) {
|
func TestNamespaceFilter(t *testing.T) {
|
||||||
r, _ := http.NewRequest("GET", "/v1/user/123", nil)
|
r, _ := http.NewRequest("GET", "/v1/user/123", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -88,41 +118,18 @@ func TestNamespaceFilter(t *testing.T) {
|
|||||||
Get("/user/:id", func(ctx *context.Context) {
|
Get("/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() != "this is Filter" {
|
if w.Body.String() != "this is Filter" {
|
||||||
t.Errorf("TestNamespaceFilter can't run, get the response is " + w.Body.String())
|
t.Errorf("TestNamespaceFilter can't run, get the response is " + w.Body.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNamespaceRouter(t *testing.T) {
|
|
||||||
r, _ := http.NewRequest("GET", "/v1/api/list", nil)
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
|
|
||||||
ns := NewNamespace("/v1")
|
|
||||||
ns.Router("/api/list", &TestController{}, "*:List")
|
|
||||||
ns.ServeHTTP(w, r)
|
|
||||||
if w.Body.String() != "i am list" {
|
|
||||||
t.Errorf("TestNamespaceRouter can't run, get the response is " + w.Body.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamespaceAutoFunc(t *testing.T) {
|
|
||||||
r, _ := http.NewRequest("GET", "/v1/test/list", nil)
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
|
|
||||||
ns := NewNamespace("/v1")
|
|
||||||
ns.AutoRouter(&TestController{})
|
|
||||||
ns.ServeHTTP(w, r)
|
|
||||||
if w.Body.String() != "i am list" {
|
|
||||||
t.Errorf("user define func can't run")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNamespaceCond(t *testing.T) {
|
func TestNamespaceCond(t *testing.T) {
|
||||||
r, _ := http.NewRequest("GET", "/v1/test/list", nil)
|
r, _ := http.NewRequest("GET", "/v2/test/list", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
ns := NewNamespace("/v1")
|
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,8 +137,27 @@ 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNamespaceInside(t *testing.T) {
|
||||||
|
r, _ := http.NewRequest("GET", "/v3/shop/order/123", nil)
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
ns := NewNamespace("/v3",
|
||||||
|
NSAutoRouter(&TestController{}),
|
||||||
|
NSNamespace("/shop",
|
||||||
|
NSGet("/order/:id", func(ctx *context.Context) {
|
||||||
|
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
AddNamespace(ns)
|
||||||
|
BeeApp.Handlers.ServeHTTP(w, r)
|
||||||
|
if w.Body.String() != "123" {
|
||||||
|
t.Errorf("TestNamespaceInside can't run, get the response is " + w.Body.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -144,8 +144,12 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
|||||||
value = field.Interface()
|
value = field.Interface()
|
||||||
if t, ok := value.(time.Time); ok {
|
if t, ok := value.(time.Time); ok {
|
||||||
d.ins.TimeToDB(&t, tz)
|
d.ins.TimeToDB(&t, tz)
|
||||||
|
if t.IsZero() {
|
||||||
|
value = nil
|
||||||
|
} else {
|
||||||
value = t
|
value = t
|
||||||
}
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
switch {
|
switch {
|
||||||
case fi.fieldType&IsPostiveIntegerField > 0:
|
case fi.fieldType&IsPostiveIntegerField > 0:
|
||||||
|
187
parser.go
Normal file
187
parser.go
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
// Beego (http://beego.me/)
|
||||||
|
// @description beego is an open-source, high-performance web framework for the Go programming language.
|
||||||
|
// @link http://github.com/astaxie/beego for the canonical source repository
|
||||||
|
// @license http://github.com/astaxie/beego/blob/master/LICENSE
|
||||||
|
// @authors astaxie
|
||||||
|
package beego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/parser"
|
||||||
|
"go/token"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var globalRouterTemplate = `package routers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/astaxie/beego"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
{{.globalinfo}}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
var (
|
||||||
|
lastupdateFilename string = "lastupdate.tmp"
|
||||||
|
pkgLastupdate map[string]int64
|
||||||
|
genInfoList map[string][]ControllerComments
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
pkgLastupdate = make(map[string]int64)
|
||||||
|
genInfoList = make(map[string][]ControllerComments)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parserPkg(pkgRealpath, pkgpath string) error {
|
||||||
|
if !compareFile(pkgRealpath) {
|
||||||
|
Info(pkgRealpath + " don't has updated")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fileSet := token.NewFileSet()
|
||||||
|
astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool {
|
||||||
|
name := info.Name()
|
||||||
|
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
|
||||||
|
}, parser.ParseComments)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, pkg := range astPkgs {
|
||||||
|
for _, fl := range pkg.Files {
|
||||||
|
for _, d := range fl.Decls {
|
||||||
|
switch specDecl := d.(type) {
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(specDecl.Recv.List[0].Type.(*ast.StarExpr).X), pkgpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
genRouterCode()
|
||||||
|
savetoFile(pkgRealpath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
|
||||||
|
if comments != nil && comments.List != nil {
|
||||||
|
for _, c := range comments.List {
|
||||||
|
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
|
||||||
|
if strings.HasPrefix(t, "@router") {
|
||||||
|
elements := strings.TrimLeft(t, "@router ")
|
||||||
|
e1 := strings.SplitN(elements, " ", 2)
|
||||||
|
if len(e1) < 1 {
|
||||||
|
return errors.New("you should has router infomation")
|
||||||
|
}
|
||||||
|
key := pkgpath + ":" + controllerName
|
||||||
|
cc := ControllerComments{}
|
||||||
|
cc.Method = funcName
|
||||||
|
cc.Router = e1[0]
|
||||||
|
if len(e1) == 2 && e1[1] != "" {
|
||||||
|
e1 = strings.SplitN(e1[1], " ", 2)
|
||||||
|
if len(e1) >= 1 {
|
||||||
|
cc.AllowHTTPMethods = strings.Split(strings.Trim(e1[0], "[]"), ",")
|
||||||
|
} else {
|
||||||
|
cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get")
|
||||||
|
}
|
||||||
|
if len(e1) == 2 && e1[1] != "" {
|
||||||
|
keyval := strings.Split(strings.Trim(e1[1], "[]"), " ")
|
||||||
|
for _, kv := range keyval {
|
||||||
|
kk := strings.Split(kv, ":")
|
||||||
|
cc.Params = append(cc.Params, map[string]string{strings.Join(kk[:len(kk)-1], ":"): kk[len(kk)-1]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
genInfoList[key] = append(genInfoList[key], cc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func genRouterCode() {
|
||||||
|
os.Mkdir(path.Join(AppPath, "routers"), 0755)
|
||||||
|
Info("generate router from comments")
|
||||||
|
var globalinfo string
|
||||||
|
for k, cList := range genInfoList {
|
||||||
|
for _, c := range cList {
|
||||||
|
allmethod := "nil"
|
||||||
|
if len(c.AllowHTTPMethods) > 0 {
|
||||||
|
allmethod = "[]string{"
|
||||||
|
for _, m := range c.AllowHTTPMethods {
|
||||||
|
allmethod += `"` + m + `",`
|
||||||
|
}
|
||||||
|
allmethod = strings.TrimRight(allmethod, ",") + "}"
|
||||||
|
}
|
||||||
|
params := "nil"
|
||||||
|
if len(c.Params) > 0 {
|
||||||
|
params = "[]map[string]string{"
|
||||||
|
for _, p := range c.Params {
|
||||||
|
for k, v := range p {
|
||||||
|
params = params + `map[string]string{` + k + `:"` + v + `"},`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params = strings.TrimRight(params, ",") + "}"
|
||||||
|
}
|
||||||
|
globalinfo = globalinfo + `
|
||||||
|
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
|
||||||
|
beego.ControllerComments{
|
||||||
|
"` + strings.TrimSpace(c.Method) + `",
|
||||||
|
"` + c.Router + `",
|
||||||
|
` + allmethod + `,
|
||||||
|
` + params + `})
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if globalinfo != "" {
|
||||||
|
f, err := os.Create(path.Join(AppPath, "routers", "commentsRouter.go"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.WriteString(strings.Replace(globalRouterTemplate, "{{.globalinfo}}", globalinfo, -1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareFile(pkgRealpath string) bool {
|
||||||
|
if utils.FileExists(path.Join(AppPath, lastupdateFilename)) {
|
||||||
|
content, err := ioutil.ReadFile(path.Join(AppPath, lastupdateFilename))
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
json.Unmarshal(content, &pkgLastupdate)
|
||||||
|
ft, err := os.Lstat(pkgRealpath)
|
||||||
|
if err != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if v, ok := pkgLastupdate[pkgRealpath]; ok {
|
||||||
|
if ft.ModTime().UnixNano() >= v {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func savetoFile(pkgRealpath string) {
|
||||||
|
ft, err := os.Lstat(pkgRealpath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pkgLastupdate[pkgRealpath] = ft.ModTime().UnixNano()
|
||||||
|
d, err := json.Marshal(pkgLastupdate)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ioutil.WriteFile(path.Join(AppPath, lastupdateFilename), d, os.ModePerm)
|
||||||
|
}
|
169
reload.go
169
reload.go
@ -1,169 +0,0 @@
|
|||||||
// Beego (http://beego.me/)
|
|
||||||
// @description beego is an open-source, high-performance web framework for the Go programming language.
|
|
||||||
// @link http://github.com/astaxie/beego for the canonical source repository
|
|
||||||
// @license http://github.com/astaxie/beego/blob/master/LICENSE
|
|
||||||
// @authors astaxie
|
|
||||||
|
|
||||||
package beego
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"os/signal"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
//"syscall"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// An environment variable when restarting application http listener.
|
|
||||||
FDKey = "BEEGO_HOT_FD"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Export an error equivalent to net.errClosing for use with Accept during
|
|
||||||
// a graceful exit.
|
|
||||||
var ErrClosing = errors.New("use of closed network connection")
|
|
||||||
var ErrInitStart = errors.New("init from")
|
|
||||||
|
|
||||||
// Allows for us to notice when the connection is closed.
|
|
||||||
type conn struct {
|
|
||||||
net.Conn
|
|
||||||
wg *sync.WaitGroup
|
|
||||||
isclose bool
|
|
||||||
lock *sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close current processing connection.
|
|
||||||
func (c conn) Close() error {
|
|
||||||
c.lock.Lock()
|
|
||||||
defer c.lock.Unlock()
|
|
||||||
err := c.Conn.Close()
|
|
||||||
if !c.isclose && err == nil {
|
|
||||||
c.wg.Done()
|
|
||||||
c.isclose = true
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type stoppableListener struct {
|
|
||||||
net.Listener
|
|
||||||
count int64
|
|
||||||
stopped bool
|
|
||||||
wg sync.WaitGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
var theStoppable *stoppableListener
|
|
||||||
|
|
||||||
func newStoppable(l net.Listener) (sl *stoppableListener) {
|
|
||||||
sl = &stoppableListener{Listener: l}
|
|
||||||
|
|
||||||
// this goroutine monitors the channel. Can't do this in
|
|
||||||
// Accept (below) because once it enters sl.Listener.Accept()
|
|
||||||
// it blocks. We unblock it by closing the fd it is trying to
|
|
||||||
// accept(2) on.
|
|
||||||
go func() {
|
|
||||||
WaitSignal(l)
|
|
||||||
sl.stopped = true
|
|
||||||
sl.Listener.Close()
|
|
||||||
}()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set stopped Listener to accept requests again.
|
|
||||||
// it returns the accepted and closable connection or error.
|
|
||||||
func (sl *stoppableListener) Accept() (c net.Conn, err error) {
|
|
||||||
c, err = sl.Listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sl.wg.Add(1)
|
|
||||||
// Wrap the returned connection, so that we can observe when
|
|
||||||
// it is closed.
|
|
||||||
c = conn{Conn: c, wg: &sl.wg}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listener waits signal to kill or interrupt then restart.
|
|
||||||
func WaitSignal(l net.Listener) error {
|
|
||||||
ch := make(chan os.Signal, 1)
|
|
||||||
signal.Notify(ch, os.Interrupt, os.Kill)
|
|
||||||
for {
|
|
||||||
sig := <-ch
|
|
||||||
log.Println(sig.String())
|
|
||||||
switch sig {
|
|
||||||
|
|
||||||
case os.Kill:
|
|
||||||
return nil
|
|
||||||
case os.Interrupt:
|
|
||||||
err := Restart(l)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill current running os process.
|
|
||||||
func CloseSelf() error {
|
|
||||||
ppid := os.Getpid()
|
|
||||||
if ppid == 1 { // init provided sockets, for example systemd
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
p, err := os.FindProcess(ppid)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return p.Kill()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-exec this image without dropping the listener passed to this function.
|
|
||||||
func Restart(l net.Listener) error {
|
|
||||||
argv0, err := exec.LookPath(os.Args[0])
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
v := reflect.ValueOf(l).Elem().FieldByName("fd").Elem()
|
|
||||||
fd := uintptr(v.FieldByName("sysfd").Int())
|
|
||||||
allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr},
|
|
||||||
os.NewFile(fd, string(v.FieldByName("sysfile").String())))
|
|
||||||
|
|
||||||
p, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{
|
|
||||||
Dir: wd,
|
|
||||||
Env: append(os.Environ(), fmt.Sprintf("%s=%d", FDKey, fd)),
|
|
||||||
Files: allFiles,
|
|
||||||
})
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
log.Printf("spawned child %d\n", p.Pid)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current net.Listen in running process.
|
|
||||||
func GetInitListener(tcpaddr *net.TCPAddr) (l net.Listener, err error) {
|
|
||||||
countStr := os.Getenv(FDKey)
|
|
||||||
if countStr == "" {
|
|
||||||
return net.ListenTCP("tcp", tcpaddr)
|
|
||||||
}
|
|
||||||
count, err := strconv.Atoi(countStr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f := os.NewFile(uintptr(count), "listen socket")
|
|
||||||
l, err = net.FileListener(f)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return l, nil
|
|
||||||
}
|
|
165
router_test.go
165
router_test.go
@ -27,6 +27,10 @@ func (this *TestController) Post() {
|
|||||||
this.Ctx.Output.Body([]byte(this.Ctx.Input.Query(":name")))
|
this.Ctx.Output.Body([]byte(this.Ctx.Input.Query(":name")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *TestController) Param() {
|
||||||
|
this.Ctx.Output.Body([]byte(this.Ctx.Input.Query(":name")))
|
||||||
|
}
|
||||||
|
|
||||||
func (this *TestController) List() {
|
func (this *TestController) List() {
|
||||||
this.Ctx.Output.Body([]byte("i am list"))
|
this.Ctx.Output.Body([]byte("i am list"))
|
||||||
}
|
}
|
||||||
@ -43,6 +47,15 @@ func (this *TestController) GetUrl() {
|
|||||||
this.Ctx.Output.Body([]byte(this.UrlFor(".Myext")))
|
this.Ctx.Output.Body([]byte(this.UrlFor(".Myext")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TestController) GetParams() {
|
||||||
|
t.Ctx.WriteString(t.Ctx.Input.Query(":last") + "+" +
|
||||||
|
t.Ctx.Input.Query(":first") + "+" + t.Ctx.Input.Query("learn"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *TestController) GetManyRouter() {
|
||||||
|
t.Ctx.WriteString(t.Ctx.Input.Query(":id") + t.Ctx.Input.Query(":page"))
|
||||||
|
}
|
||||||
|
|
||||||
type ResStatus struct {
|
type ResStatus struct {
|
||||||
Code int
|
Code int
|
||||||
Msg string
|
Msg string
|
||||||
@ -63,21 +76,45 @@ func (this *JsonController) Get() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUrlFor(t *testing.T) {
|
func TestUrlFor(t *testing.T) {
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/api/list", &TestController{}, "*:List")
|
handler.Add("/api/list", &TestController{}, "*:List")
|
||||||
handler.Add("/person/:last/:first", &TestController{})
|
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
|
||||||
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.Param", ":last", "xie", ":first", "asta") != "/person/xie/asta" {
|
||||||
t.Errorf("TestController.Get must equal to /person/xie/asta")
|
t.Errorf("TestController.Param must equal to /person/xie/asta, but get " + handler.UrlFor("TestController.Param", ":last", "xie", ":first", "asta"))
|
||||||
}
|
}
|
||||||
if handler.UrlFor("TestController.Myext") != "/Test/Myext" {
|
if handler.UrlFor("TestController.Myext") != "/test/myext" {
|
||||||
t.Errorf("TestController.Myext must equal to /Test/Myext")
|
t.Errorf("TestController.Myext must equal to /test/myext")
|
||||||
}
|
}
|
||||||
if handler.UrlFor("TestController.GetUrl") != "/Test/GetUrl" {
|
if handler.UrlFor("TestController.GetUrl") != "/test/geturl" {
|
||||||
t.Errorf("TestController.GetUrl must equal to /Test/GetUrl")
|
t.Errorf("TestController.GetUrl must equal to /test/geturl")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUrlFor2(t *testing.T) {
|
||||||
|
handler := NewControllerRegister()
|
||||||
|
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
|
||||||
|
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
|
||||||
|
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
||||||
|
if handler.UrlFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
|
||||||
|
"/v1/za/cms_12_123.html" {
|
||||||
|
Info(handler.UrlFor("TestController.List"))
|
||||||
|
t.Errorf("TestController.List must equal to /v1/za/cms_12_123.html")
|
||||||
|
}
|
||||||
|
if handler.UrlFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") !=
|
||||||
|
"/v1/za_cms/ttt_12_123.html" {
|
||||||
|
Info(handler.UrlFor("TestController.Param"))
|
||||||
|
t.Errorf("TestController.List must equal to /v1/za_cms/ttt_12_123.html")
|
||||||
|
}
|
||||||
|
if handler.UrlFor("TestController.Get", ":year", "1111", ":month", "11",
|
||||||
|
":title", "aaaa", ":entid", "aaaa") !=
|
||||||
|
"/1111/11/aaaa/aaaa" {
|
||||||
|
Info(handler.UrlFor("TestController.Get"))
|
||||||
|
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +122,7 @@ func TestUserFunc(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/api/list", nil)
|
r, _ := http.NewRequest("GET", "/api/list", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/api/list", &TestController{}, "*:List")
|
handler.Add("/api/list", &TestController{}, "*:List")
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "i am list" {
|
if w.Body.String() != "i am list" {
|
||||||
@ -97,7 +134,7 @@ func TestPostFunc(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("POST", "/astaxie", nil)
|
r, _ := http.NewRequest("POST", "/astaxie", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/:name", &TestController{})
|
handler.Add("/:name", &TestController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "astaxie" {
|
if w.Body.String() != "astaxie" {
|
||||||
@ -109,7 +146,7 @@ func TestAutoFunc(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/test/list", nil)
|
r, _ := http.NewRequest("GET", "/test/list", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.AddAuto(&TestController{})
|
handler.AddAuto(&TestController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "i am list" {
|
if w.Body.String() != "i am list" {
|
||||||
@ -121,7 +158,7 @@ func TestAutoFuncParams(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/test/params/2009/11/12", nil)
|
r, _ := http.NewRequest("GET", "/test/params/2009/11/12", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.AddAuto(&TestController{})
|
handler.AddAuto(&TestController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "20091112" {
|
if w.Body.String() != "20091112" {
|
||||||
@ -133,7 +170,7 @@ func TestAutoExtFunc(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/test/myext.json", nil)
|
r, _ := http.NewRequest("GET", "/test/myext.json", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.AddAuto(&TestController{})
|
handler.AddAuto(&TestController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "json" {
|
if w.Body.String() != "json" {
|
||||||
@ -146,22 +183,12 @@ func TestRouteOk(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/person/anderson/thomas?learn=kungfu", nil)
|
r, _ := http.NewRequest("GET", "/person/anderson/thomas?learn=kungfu", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/person/:last/:first", &TestController{})
|
handler.Add("/person/:last/:first", &TestController{}, "get:GetParams")
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
|
body := w.Body.String()
|
||||||
lastNameParam := r.URL.Query().Get(":last")
|
if body != "anderson+thomas+kungfu" {
|
||||||
firstNameParam := r.URL.Query().Get(":first")
|
t.Errorf("url param set to [%s];", body)
|
||||||
learnParam := r.URL.Query().Get("learn")
|
|
||||||
|
|
||||||
if lastNameParam != "anderson" {
|
|
||||||
t.Errorf("url param set to [%s]; want [%s]", lastNameParam, "anderson")
|
|
||||||
}
|
|
||||||
if firstNameParam != "thomas" {
|
|
||||||
t.Errorf("url param set to [%s]; want [%s]", firstNameParam, "thomas")
|
|
||||||
}
|
|
||||||
if learnParam != "kungfu" {
|
|
||||||
t.Errorf("url param set to [%s]; want [%s]", learnParam, "kungfu")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,18 +197,14 @@ func TestManyRoute(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/beego32-12.html", nil)
|
r, _ := http.NewRequest("GET", "/beego32-12.html", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{})
|
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, "get:GetManyRouter")
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
id := r.URL.Query().Get(":id")
|
body := w.Body.String()
|
||||||
page := r.URL.Query().Get(":page")
|
|
||||||
|
|
||||||
if id != "32" {
|
if body != "3212" {
|
||||||
t.Errorf("url param set to [%s]; want [%s]", id, "32")
|
t.Errorf("url param set to [%s];", body)
|
||||||
}
|
|
||||||
if page != "12" {
|
|
||||||
t.Errorf("url param set to [%s]; want [%s]", page, "12")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +212,7 @@ func TestNotFound(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/", nil)
|
r, _ := http.NewRequest("GET", "/", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
if w.Code != http.StatusNotFound {
|
if w.Code != http.StatusNotFound {
|
||||||
@ -203,7 +226,7 @@ func TestStatic(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/static/js/jquery.js", nil)
|
r, _ := http.NewRequest("GET", "/static/js/jquery.js", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
|
|
||||||
if w.Code != 404 {
|
if w.Code != 404 {
|
||||||
@ -215,7 +238,7 @@ func TestPrepare(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/json/list", nil)
|
r, _ := http.NewRequest("GET", "/json/list", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Add("/json/list", &JsonController{})
|
handler.Add("/json/list", &JsonController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != `"prepare"` {
|
if w.Body.String() != `"prepare"` {
|
||||||
@ -227,7 +250,7 @@ func TestAutoPrefix(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/admin/test/list", nil)
|
r, _ := http.NewRequest("GET", "/admin/test/list", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.AddAutoPrefix("/admin", &TestController{})
|
handler.AddAutoPrefix("/admin", &TestController{})
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "i am list" {
|
if w.Body.String() != "i am list" {
|
||||||
@ -239,7 +262,7 @@ func TestRouterGet(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("GET", "/user", nil)
|
r, _ := http.NewRequest("GET", "/user", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Get("/user", func(ctx *context.Context) {
|
handler.Get("/user", func(ctx *context.Context) {
|
||||||
ctx.Output.Body([]byte("Get userlist"))
|
ctx.Output.Body([]byte("Get userlist"))
|
||||||
})
|
})
|
||||||
@ -253,7 +276,7 @@ func TestRouterPost(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("POST", "/user/123", nil)
|
r, _ := http.NewRequest("POST", "/user/123", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Post("/user/:id", func(ctx *context.Context) {
|
handler.Post("/user/:id", func(ctx *context.Context) {
|
||||||
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
|
ctx.Output.Body([]byte(ctx.Input.Param(":id")))
|
||||||
})
|
})
|
||||||
@ -271,10 +294,64 @@ func TestRouterHandler(t *testing.T) {
|
|||||||
r, _ := http.NewRequest("POST", "/sayhi", nil)
|
r, _ := http.NewRequest("POST", "/sayhi", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler := NewControllerRegistor()
|
handler := NewControllerRegister()
|
||||||
handler.Handler("/sayhi", http.HandlerFunc(sayhello))
|
handler.Handler("/sayhi", http.HandlerFunc(sayhello))
|
||||||
handler.ServeHTTP(w, r)
|
handler.ServeHTTP(w, r)
|
||||||
if w.Body.String() != "sayhello" {
|
if w.Body.String() != "sayhello" {
|
||||||
t.Errorf("TestRouterHandler can't run")
|
t.Errorf("TestRouterHandler can't run")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Benchmarks NewApp:
|
||||||
|
//
|
||||||
|
|
||||||
|
func beegoFilterFunc(ctx *context.Context) {
|
||||||
|
ctx.WriteString("hello")
|
||||||
|
}
|
||||||
|
|
||||||
|
type AdminController struct {
|
||||||
|
Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AdminController) Get() {
|
||||||
|
a.Ctx.WriteString("hello")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterFunc(t *testing.T) {
|
||||||
|
mux := NewControllerRegister()
|
||||||
|
mux.Get("/action", beegoFilterFunc)
|
||||||
|
mux.Post("/action", beegoFilterFunc)
|
||||||
|
rw, r := testRequest("GET", "/action")
|
||||||
|
mux.ServeHTTP(rw, r)
|
||||||
|
if rw.Body.String() != "hello" {
|
||||||
|
t.Errorf("TestRouterFunc can't run")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkFunc(b *testing.B) {
|
||||||
|
mux := NewControllerRegister()
|
||||||
|
mux.Get("/action", beegoFilterFunc)
|
||||||
|
rw, r := testRequest("GET", "/action")
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
mux.ServeHTTP(rw, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkController(b *testing.B) {
|
||||||
|
mux := NewControllerRegister()
|
||||||
|
mux.Add("/action", &AdminController{})
|
||||||
|
rw, r := testRequest("GET", "/action")
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
mux.ServeHTTP(rw, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) {
|
||||||
|
request, _ := http.NewRequest(method, path, nil)
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
return recorder, request
|
||||||
|
}
|
||||||
|
@ -20,6 +20,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -60,8 +62,8 @@ func DecodeGob(encoded []byte) (map[interface{}]interface{}, error) {
|
|||||||
// generateRandomKey creates a random key with the given strength.
|
// generateRandomKey creates a random key with the given strength.
|
||||||
func generateRandomKey(strength int) []byte {
|
func generateRandomKey(strength int) []byte {
|
||||||
k := make([]byte, strength)
|
k := make([]byte, strength)
|
||||||
if _, err := io.ReadFull(rand.Reader, k); err != nil {
|
if n, err := io.ReadFull(rand.Reader, k); n != strength || err != nil {
|
||||||
return nil
|
return utils.RandomCreateBytes(strength)
|
||||||
}
|
}
|
||||||
return k
|
return k
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SessionStore contains all data for one session process with specific id.
|
// SessionStore contains all data for one session process with specific id.
|
||||||
@ -237,9 +239,9 @@ func (manager *Manager) SetSecure(secure bool) {
|
|||||||
|
|
||||||
// generate session id with rand string, unix nano time, remote addr by hash function.
|
// generate session id with rand string, unix nano time, remote addr by hash function.
|
||||||
func (manager *Manager) sessionId(r *http.Request) (sid string) {
|
func (manager *Manager) sessionId(r *http.Request) (sid string) {
|
||||||
bs := make([]byte, 24)
|
bs := make([]byte, 32)
|
||||||
if _, err := io.ReadFull(rand.Reader, bs); err != nil {
|
if n, err := io.ReadFull(rand.Reader, bs); n != 32 || err != nil {
|
||||||
return ""
|
bs = utils.RandomCreateBytes(32)
|
||||||
}
|
}
|
||||||
sig := fmt.Sprintf("%s%d%s", r.RemoteAddr, time.Now().UnixNano(), bs)
|
sig := fmt.Sprintf("%s%d%s", r.RemoteAddr, time.Now().UnixNano(), bs)
|
||||||
if manager.config.SessionIDHashFunc == "md5" {
|
if manager.config.SessionIDHashFunc == "md5" {
|
||||||
|
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/astaxie/beego/utils"
|
"github.com/astaxie/beego/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serverStaticRouter(ctx *context.Context) bool {
|
func serverStaticRouter(ctx *context.Context) {
|
||||||
requestPath := path.Clean(ctx.Input.Request.URL.Path)
|
requestPath := path.Clean(ctx.Input.Request.URL.Path)
|
||||||
for prefix, staticDir := range StaticDir {
|
for prefix, staticDir := range StaticDir {
|
||||||
if len(prefix) == 0 {
|
if len(prefix) == 0 {
|
||||||
@ -28,17 +28,13 @@ func serverStaticRouter(ctx *context.Context) bool {
|
|||||||
file := path.Join(staticDir, requestPath)
|
file := path.Join(staticDir, requestPath)
|
||||||
if utils.FileExists(file) {
|
if utils.FileExists(file) {
|
||||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
|
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(requestPath, prefix) {
|
if strings.HasPrefix(requestPath, prefix) {
|
||||||
if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' {
|
if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if requestPath == prefix && prefix[len(prefix)-1] != '/' {
|
|
||||||
http.Redirect(ctx.ResponseWriter, ctx.Request, requestPath+"/", 302)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
file := path.Join(staticDir, requestPath[len(prefix):])
|
file := path.Join(staticDir, requestPath[len(prefix):])
|
||||||
finfo, err := os.Stat(file)
|
finfo, err := os.Stat(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -46,12 +42,12 @@ func serverStaticRouter(ctx *context.Context) bool {
|
|||||||
Warn(err)
|
Warn(err)
|
||||||
}
|
}
|
||||||
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
http.NotFound(ctx.ResponseWriter, ctx.Request)
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
//if the request is dir and DirectoryIndex is false then
|
//if the request is dir and DirectoryIndex is false then
|
||||||
if finfo.IsDir() && !DirectoryIndex {
|
if finfo.IsDir() && !DirectoryIndex {
|
||||||
middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden")
|
middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden")
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request
|
//This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request
|
||||||
@ -73,7 +69,7 @@ func serverStaticRouter(ctx *context.Context) bool {
|
|||||||
|
|
||||||
memzipfile, err := openMemZipFile(file, contentEncoding)
|
memzipfile, err := openMemZipFile(file, contentEncoding)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if contentEncoding == "gzip" {
|
if contentEncoding == "gzip" {
|
||||||
@ -89,8 +85,7 @@ func serverStaticRouter(ctx *context.Context) bool {
|
|||||||
} else {
|
} else {
|
||||||
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
|
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
|
||||||
}
|
}
|
||||||
return true
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
133
swagger/docsSpec.go
Normal file
133
swagger/docsSpec.go
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package swagger
|
||||||
|
|
||||||
|
const SwaggerVersion = "1.2"
|
||||||
|
|
||||||
|
type ResourceListing struct {
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
|
SwaggerVersion string `json:"swaggerVersion"` // e.g 1.2
|
||||||
|
// BasePath string `json:"basePath"` obsolete in 1.1
|
||||||
|
Apis []ApiRef `json:"apis"`
|
||||||
|
Infos Infomation `json:"info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiRef struct {
|
||||||
|
Path string `json:"path"` // relative or absolute, must start with /
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Infomation struct {
|
||||||
|
Title string `json:"title,omitempty"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Contact string `json:"contact,omitempty"`
|
||||||
|
TermsOfServiceUrl string `json:"termsOfServiceUrl,omitempty"`
|
||||||
|
License string `json:"license,omitempty"`
|
||||||
|
LicenseUrl string `json:"licenseUrl,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/blob/scala_2.10-1.3-RC3/schemas/api-declaration-schema.json
|
||||||
|
type ApiDeclaration struct {
|
||||||
|
ApiVersion string `json:"apiVersion"`
|
||||||
|
SwaggerVersion string `json:"swaggerVersion"`
|
||||||
|
BasePath string `json:"basePath"`
|
||||||
|
ResourcePath string `json:"resourcePath"` // must start with /
|
||||||
|
Consumes []string `json:"consumes,omitempty"`
|
||||||
|
Produces []string `json:"produces,omitempty"`
|
||||||
|
Apis []Api `json:"apis,omitempty"`
|
||||||
|
Models map[string]Model `json:"models,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
Path string `json:"path"` // relative or absolute, must start with /
|
||||||
|
Description string `json:"description"`
|
||||||
|
Operations []Operation `json:"operations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Operation struct {
|
||||||
|
HttpMethod string `json:"httpMethod"`
|
||||||
|
Nickname string `json:"nickname"`
|
||||||
|
Type string `json:"type"` // in 1.1 = DataType
|
||||||
|
// ResponseClass string `json:"responseClass"` obsolete in 1.2
|
||||||
|
Summary string `json:"summary,omitempty"`
|
||||||
|
Notes string `json:"notes,omitempty"`
|
||||||
|
Parameters []Parameter `json:"parameters,omitempty"`
|
||||||
|
ResponseMessages []ResponseMessage `json:"responseMessages,omitempty"` // optional
|
||||||
|
Consumes []string `json:"consumes,omitempty"`
|
||||||
|
Produces []string `json:"produces,omitempty"`
|
||||||
|
Authorizations []Authorization `json:"authorizations,omitempty"`
|
||||||
|
Protocols []Protocol `json:"protocols,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Protocol struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseMessage struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
ResponseModel string `json:"responseModel"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Parameter struct {
|
||||||
|
ParamType string `json:"paramType"` // path,query,body,header,form
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
DataType string `json:"dataType"` // 1.2 needed?
|
||||||
|
Type string `json:"type"` // integer
|
||||||
|
Format string `json:"format"` // int64
|
||||||
|
AllowMultiple bool `json:"allowMultiple"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
Minimum int `json:"minimum"`
|
||||||
|
Maximum int `json:"maximum"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorResponse struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
Id string `json:"id"`
|
||||||
|
Required []string `json:"required,omitempty"`
|
||||||
|
Properties map[string]ModelProperty `json:"properties"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModelProperty struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Items map[string]string `json:"items,omitempty"`
|
||||||
|
Format string `json:"format"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/wiki/authorizations
|
||||||
|
type Authorization struct {
|
||||||
|
LocalOAuth OAuth `json:"local-oauth"`
|
||||||
|
ApiKey ApiKey `json:"apiKey"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/wiki/authorizations
|
||||||
|
type OAuth struct {
|
||||||
|
Type string `json:"type"` // e.g. oauth2
|
||||||
|
Scopes []string `json:"scopes"` // e.g. PUBLIC
|
||||||
|
GrantTypes map[string]GrantType `json:"grantTypes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/wiki/authorizations
|
||||||
|
type GrantType struct {
|
||||||
|
LoginEndpoint Endpoint `json:"loginEndpoint"`
|
||||||
|
TokenName string `json:"tokenName"` // e.g. access_code
|
||||||
|
TokenRequestEndpoint Endpoint `json:"tokenRequestEndpoint"`
|
||||||
|
TokenEndpoint Endpoint `json:"tokenEndpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/wiki/authorizations
|
||||||
|
type Endpoint struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
ClientIdName string `json:"clientIdName"`
|
||||||
|
ClientSecretName string `json:"clientSecretName"`
|
||||||
|
TokenName string `json:"tokenName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/wordnik/swagger-core/wiki/authorizations
|
||||||
|
type ApiKey struct {
|
||||||
|
Type string `json:"type"` // e.g. apiKey
|
||||||
|
PassAs string `json:"passAs"` // e.g. header
|
||||||
|
}
|
@ -44,6 +44,7 @@ func init() {
|
|||||||
beegoTplFuncMap["renderform"] = RenderForm
|
beegoTplFuncMap["renderform"] = RenderForm
|
||||||
beegoTplFuncMap["assets_js"] = AssetsJs
|
beegoTplFuncMap["assets_js"] = AssetsJs
|
||||||
beegoTplFuncMap["assets_css"] = AssetsCss
|
beegoTplFuncMap["assets_css"] = AssetsCss
|
||||||
|
beegoTplFuncMap["config"] = Config
|
||||||
|
|
||||||
// go1.2 added template funcs
|
// go1.2 added template funcs
|
||||||
// Comparisons
|
// Comparisons
|
||||||
|
@ -131,6 +131,43 @@ func Compare(a, b interface{}) (equal bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Config(returnType, key string, defaultVal interface{}) (value interface{}, err error) {
|
||||||
|
switch returnType {
|
||||||
|
case "String":
|
||||||
|
value = AppConfig.String(key)
|
||||||
|
case "Bool":
|
||||||
|
value, err = AppConfig.Bool(key)
|
||||||
|
case "Int":
|
||||||
|
value, err = AppConfig.Int(key)
|
||||||
|
case "Int64":
|
||||||
|
value, err = AppConfig.Int64(key)
|
||||||
|
case "Float":
|
||||||
|
value, err = AppConfig.Float(key)
|
||||||
|
case "DIY":
|
||||||
|
value, err = AppConfig.DIY(key)
|
||||||
|
default:
|
||||||
|
err = errors.New("Config keys must be of type String, Bool, Int, Int64, Float, or DIY!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if reflect.TypeOf(returnType) != reflect.TypeOf(defaultVal) {
|
||||||
|
err = errors.New("defaultVal type does not match returnType!")
|
||||||
|
} else {
|
||||||
|
value, err = defaultVal, nil
|
||||||
|
}
|
||||||
|
} else if reflect.TypeOf(value).Kind() == reflect.String {
|
||||||
|
if value == "" {
|
||||||
|
if reflect.TypeOf(defaultVal).Kind() != reflect.String {
|
||||||
|
err = errors.New("defaultVal type must be a String if the returnType is a String")
|
||||||
|
} else {
|
||||||
|
value = defaultVal.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Convert string to template.HTML type.
|
// Convert string to template.HTML type.
|
||||||
func Str2html(raw string) template.HTML {
|
func Str2html(raw string) template.HTML {
|
||||||
return template.HTML(raw)
|
return template.HTML(raw)
|
||||||
@ -202,7 +239,7 @@ func Htmlunquote(src string) string {
|
|||||||
//
|
//
|
||||||
// more detail http://beego.me/docs/mvc/controller/urlbuilding.md
|
// more detail http://beego.me/docs/mvc/controller/urlbuilding.md
|
||||||
func UrlFor(endpoint string, values ...string) string {
|
func UrlFor(endpoint string, values ...string) string {
|
||||||
return BeeApp.UrlFor(endpoint, values...)
|
return BeeApp.Handlers.UrlFor(endpoint, values...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns script tag with src string.
|
// returns script tag with src string.
|
||||||
|
@ -36,25 +36,27 @@ func TestHtml2str(t *testing.T) {
|
|||||||
func TestDateFormat(t *testing.T) {
|
func TestDateFormat(t *testing.T) {
|
||||||
ts := "Mon, 01 Jul 2013 13:27:42 CST"
|
ts := "Mon, 01 Jul 2013 13:27:42 CST"
|
||||||
tt, _ := time.Parse(time.RFC1123, ts)
|
tt, _ := time.Parse(time.RFC1123, ts)
|
||||||
if DateFormat(tt, "2006-01-02 15:04:05") != "2013-07-01 13:27:42" {
|
|
||||||
t.Error("should be equal")
|
if ss := DateFormat(tt, "2006-01-02 15:04:05"); ss != "2013-07-01 13:27:42" {
|
||||||
|
t.Errorf("2013-07-01 13:27:42 does not equal %v", ss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDate(t *testing.T) {
|
func TestDate(t *testing.T) {
|
||||||
ts := "Mon, 01 Jul 2013 13:27:42 CST"
|
ts := "Mon, 01 Jul 2013 13:27:42 CST"
|
||||||
tt, _ := time.Parse(time.RFC1123, ts)
|
tt, _ := time.Parse(time.RFC1123, ts)
|
||||||
if Date(tt, "Y-m-d H:i:s") != "2013-07-01 13:27:42" {
|
|
||||||
t.Error("should be equal")
|
if ss := Date(tt, "Y-m-d H:i:s"); ss != "2013-07-01 13:27:42" {
|
||||||
|
t.Errorf("2013-07-01 13:27:42 does not equal %v", ss)
|
||||||
}
|
}
|
||||||
if Date(tt, "y-n-j h:i:s A") != "13-7-1 01:27:42 PM" {
|
if ss := Date(tt, "y-n-j h:i:s A"); ss != "13-7-1 01:27:42 PM" {
|
||||||
t.Error("should be equal")
|
t.Errorf("13-7-1 01:27:42 PM does not equal %v", ss)
|
||||||
}
|
}
|
||||||
if Date(tt, "D, d M Y g:i:s a") != "Mon, 01 Jul 2013 1:27:42 pm" {
|
if ss := Date(tt, "D, d M Y g:i:s a"); ss != "Mon, 01 Jul 2013 1:27:42 pm" {
|
||||||
t.Error("should be equal")
|
t.Errorf("Mon, 01 Jul 2013 1:27:42 pm does not equal %v", ss)
|
||||||
}
|
}
|
||||||
if Date(tt, "l, d F Y G:i:s") != "Monday, 01 July 2013 13:27:42" {
|
if ss := Date(tt, "l, d F Y G:i:s"); ss != "Monday, 01 July 2013 13:27:42" {
|
||||||
t.Error("should be equal")
|
t.Errorf("Monday, 01 July 2013 13:27:42 does not equal %v", ss)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
467
tree.go
Normal file
467
tree.go
Normal file
@ -0,0 +1,467 @@
|
|||||||
|
package beego
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/astaxie/beego/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tree struct {
|
||||||
|
//search fix route first
|
||||||
|
fixrouters map[string]*Tree
|
||||||
|
|
||||||
|
//if set, failure to match fixrouters search then search wildcard
|
||||||
|
wildcard *Tree
|
||||||
|
|
||||||
|
//if set, failure to match wildcard search
|
||||||
|
leaves []*leafInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTree() *Tree {
|
||||||
|
return &Tree{
|
||||||
|
fixrouters: make(map[string]*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, nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg string) {
|
||||||
|
if len(segments) == 0 {
|
||||||
|
panic("prefix should has path")
|
||||||
|
}
|
||||||
|
seg := segments[0]
|
||||||
|
iswild, params, regexpStr := splitSegment(seg)
|
||||||
|
if len(segments) == 1 && seg != "" {
|
||||||
|
if iswild {
|
||||||
|
wildcards = append(wildcards, params...)
|
||||||
|
if regexpStr != "" {
|
||||||
|
for _, w := range params {
|
||||||
|
if w == "." || w == ":" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
regexpStr = "([^/]+)/" + regexpStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reg = reg + regexpStr
|
||||||
|
filterTreeWithPrefix(tree, wildcards, reg)
|
||||||
|
t.wildcard = tree
|
||||||
|
} else {
|
||||||
|
filterTreeWithPrefix(tree, wildcards, reg)
|
||||||
|
t.fixrouters[seg] = tree
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if iswild {
|
||||||
|
if t.wildcard == nil {
|
||||||
|
t.wildcard = NewTree()
|
||||||
|
}
|
||||||
|
wildcards = append(wildcards)
|
||||||
|
if regexpStr != "" {
|
||||||
|
for _, w := range params {
|
||||||
|
if w == "." || w == ":" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
regexpStr = "([^/]+)/" + regexpStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reg = reg + regexpStr
|
||||||
|
t.wildcard.addtree(segments[1:], tree, wildcards, reg)
|
||||||
|
} else {
|
||||||
|
subTree := NewTree()
|
||||||
|
t.fixrouters[seg] = subTree
|
||||||
|
subTree.addtree(segments[1:], tree, wildcards, reg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
|
||||||
|
for _, v := range t.fixrouters {
|
||||||
|
filterTreeWithPrefix(v, wildcards, reg)
|
||||||
|
}
|
||||||
|
if t.wildcard != nil {
|
||||||
|
filterTreeWithPrefix(t.wildcard, wildcards, reg)
|
||||||
|
}
|
||||||
|
for _, l := range t.leaves {
|
||||||
|
l.wildcards = append(wildcards, l.wildcards...)
|
||||||
|
if reg != "" {
|
||||||
|
filterCards := []string{}
|
||||||
|
for _, v := range l.wildcards {
|
||||||
|
if v == ":" || v == "." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filterCards = append(filterCards, v)
|
||||||
|
}
|
||||||
|
l.wildcards = filterCards
|
||||||
|
l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$")
|
||||||
|
} else {
|
||||||
|
if l.regexps != nil {
|
||||||
|
filterCards := []string{}
|
||||||
|
for _, v := range l.wildcards {
|
||||||
|
if v == ":" || v == "." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filterCards = append(filterCards, v)
|
||||||
|
}
|
||||||
|
l.wildcards = filterCards
|
||||||
|
for _, w := range wildcards {
|
||||||
|
if w == "." || w == ":" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
reg = "([^/]+)/" + reg
|
||||||
|
}
|
||||||
|
l.regexps = regexp.MustCompile("^" + reg + strings.Trim(l.regexps.String(), "^$") + "$")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// call addseg function
|
||||||
|
func (t *Tree) AddRouter(pattern string, runObject interface{}) {
|
||||||
|
t.addseg(splitPath(pattern), runObject, nil, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// "/"
|
||||||
|
// "admin" ->
|
||||||
|
func (t *Tree) addseg(segments []string, route interface{}, wildcards []string, reg string) {
|
||||||
|
if len(segments) == 0 {
|
||||||
|
if reg != "" {
|
||||||
|
filterCards := []string{}
|
||||||
|
for _, v := range wildcards {
|
||||||
|
if v == ":" || v == "." {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
filterCards = append(filterCards, v)
|
||||||
|
}
|
||||||
|
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards, regexps: regexp.MustCompile("^" + reg + "$")})
|
||||||
|
} else {
|
||||||
|
t.leaves = append(t.leaves, &leafInfo{runObject: route, wildcards: wildcards})
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
seg := segments[0]
|
||||||
|
iswild, params, regexpStr := splitSegment(seg)
|
||||||
|
if iswild {
|
||||||
|
if t.wildcard == nil {
|
||||||
|
t.wildcard = NewTree()
|
||||||
|
}
|
||||||
|
if regexpStr != "" {
|
||||||
|
if reg == "" {
|
||||||
|
for _, w := range wildcards {
|
||||||
|
if w == "." || w == ":" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
regexpStr = "([^/]+)/" + regexpStr
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
regexpStr = "/" + regexpStr
|
||||||
|
}
|
||||||
|
} else if reg != "" {
|
||||||
|
for _, w := range params {
|
||||||
|
if w == "." || w == ":" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
regexpStr = "/([^/]+)" + regexpStr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.wildcard.addseg(segments[1:], route, append(wildcards, params...), reg+regexpStr)
|
||||||
|
} else {
|
||||||
|
subTree, ok := t.fixrouters[seg]
|
||||||
|
if !ok {
|
||||||
|
subTree = NewTree()
|
||||||
|
t.fixrouters[seg] = subTree
|
||||||
|
}
|
||||||
|
subTree.addseg(segments[1:], route, wildcards, reg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// match router to runObject & params
|
||||||
|
func (t *Tree) Match(pattern string) (runObject interface{}, params map[string]string) {
|
||||||
|
if len(pattern) == 0 || pattern[0] != '/' {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.match(splitPath(pattern), nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Tree) match(segments []string, wildcardValues []string) (runObject interface{}, params map[string]string) {
|
||||||
|
// Handle leaf nodes:
|
||||||
|
if len(segments) == 0 {
|
||||||
|
for _, l := range t.leaves {
|
||||||
|
if ok, pa := l.match(wildcardValues); ok {
|
||||||
|
return l.runObject, pa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if t.wildcard != nil {
|
||||||
|
for _, l := range t.wildcard.leaves {
|
||||||
|
if ok, pa := l.match(wildcardValues); ok {
|
||||||
|
return l.runObject, pa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
seg, segs := segments[0], segments[1:]
|
||||||
|
|
||||||
|
subTree, ok := t.fixrouters[seg]
|
||||||
|
if ok {
|
||||||
|
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 {
|
||||||
|
runObject, params = t.wildcard.match(segs, append(wildcardValues, seg))
|
||||||
|
}
|
||||||
|
if runObject == nil {
|
||||||
|
for _, l := range t.leaves {
|
||||||
|
if ok, pa := l.match(append(wildcardValues, segments...)); ok {
|
||||||
|
return l.runObject, pa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runObject, params
|
||||||
|
}
|
||||||
|
|
||||||
|
type leafInfo struct {
|
||||||
|
// names of wildcards that lead to this leaf. eg, ["id" "name"] for the wildcard ":id" and ":name"
|
||||||
|
wildcards []string
|
||||||
|
|
||||||
|
// if the leaf is regexp
|
||||||
|
regexps *regexp.Regexp
|
||||||
|
|
||||||
|
runObject interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string]string) {
|
||||||
|
if leaf.regexps == nil {
|
||||||
|
// has error
|
||||||
|
if len(wildcardValues) == 0 && len(leaf.wildcards) > 0 {
|
||||||
|
if utils.InSlice(":", leaf.wildcards) {
|
||||||
|
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")
|
||||||
|
return false, nil
|
||||||
|
} else if len(wildcardValues) == 0 { // static path
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
// match *
|
||||||
|
if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" {
|
||||||
|
params = make(map[string]string)
|
||||||
|
params[":splat"] = path.Join(wildcardValues...)
|
||||||
|
return true, params
|
||||||
|
}
|
||||||
|
// match *.*
|
||||||
|
if len(leaf.wildcards) == 3 && leaf.wildcards[0] == "." {
|
||||||
|
params = make(map[string]string)
|
||||||
|
lastone := wildcardValues[len(wildcardValues)-1]
|
||||||
|
strs := strings.SplitN(lastone, ".", 2)
|
||||||
|
if len(strs) == 2 {
|
||||||
|
params[":ext"] = strs[1]
|
||||||
|
} else {
|
||||||
|
params[":ext"] = ""
|
||||||
|
}
|
||||||
|
params[":path"] = path.Join(wildcardValues[:len(wildcardValues)-1]...) + "/" + strs[0]
|
||||||
|
return true, params
|
||||||
|
}
|
||||||
|
// match :id
|
||||||
|
params = make(map[string]string)
|
||||||
|
j := 0
|
||||||
|
for _, v := range leaf.wildcards {
|
||||||
|
if v == ":" {
|
||||||
|
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]
|
||||||
|
j += 1
|
||||||
|
}
|
||||||
|
if len(params) != len(wildcardValues) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return true, params
|
||||||
|
}
|
||||||
|
if !leaf.regexps.MatchString(path.Join(wildcardValues...)) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
params = make(map[string]string)
|
||||||
|
matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
|
||||||
|
for i, match := range matches[1:] {
|
||||||
|
params[leaf.wildcards[i]] = match
|
||||||
|
}
|
||||||
|
return true, params
|
||||||
|
}
|
||||||
|
|
||||||
|
// "/" -> []
|
||||||
|
// "/admin" -> ["admin"]
|
||||||
|
// "/admin/" -> ["admin"]
|
||||||
|
// "/admin/users" -> ["admin", "users"]
|
||||||
|
func splitPath(key string) []string {
|
||||||
|
elements := strings.Split(key, "/")
|
||||||
|
if elements[0] == "" {
|
||||||
|
elements = elements[1:]
|
||||||
|
}
|
||||||
|
if elements[len(elements)-1] == "" {
|
||||||
|
elements = elements[:len(elements)-1]
|
||||||
|
}
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
// "admin" -> false, nil, ""
|
||||||
|
// ":id" -> true, [:id], ""
|
||||||
|
// "?:id" -> true, [: :id], "" : meaning can empty
|
||||||
|
// ":id:int" -> true, [:id], ([0-9]+)
|
||||||
|
// ":name:string" -> true, [:name], ([\w]+)
|
||||||
|
// ":id([0-9]+)" -> true, [:id], ([0-9]+)
|
||||||
|
// ":id([0-9]+)_:name" -> true, [:id :name], ([0-9]+)_(.+)
|
||||||
|
// "cms_:id_:page.html" -> true, [:id :page], cms_(.+)_(.+).html
|
||||||
|
// "*" -> true, [:splat], ""
|
||||||
|
// "*.*" -> true,[. :path :ext], "" . meaning separator
|
||||||
|
func splitSegment(key string) (bool, []string, string) {
|
||||||
|
if strings.HasPrefix(key, "*") {
|
||||||
|
if key == "*.*" {
|
||||||
|
return true, []string{".", ":path", ":ext"}, ""
|
||||||
|
} else {
|
||||||
|
return true, []string{":splat"}, ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.ContainsAny(key, ":") {
|
||||||
|
var paramsNum int
|
||||||
|
var out []rune
|
||||||
|
var start bool
|
||||||
|
var startexp bool
|
||||||
|
var param []rune
|
||||||
|
var expt []rune
|
||||||
|
var skipnum int
|
||||||
|
params := []string{}
|
||||||
|
reg := regexp.MustCompile(`[a-zA-Z0-9_]+`)
|
||||||
|
for i, v := range key {
|
||||||
|
if skipnum > 0 {
|
||||||
|
skipnum -= 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if start {
|
||||||
|
//:id:int and :name:string
|
||||||
|
if v == ':' {
|
||||||
|
if len(key) >= i+4 {
|
||||||
|
if key[i+1:i+4] == "int" {
|
||||||
|
out = append(out, []rune("([0-9]+)")...)
|
||||||
|
params = append(params, ":"+string(param))
|
||||||
|
start = false
|
||||||
|
startexp = false
|
||||||
|
skipnum = 3
|
||||||
|
param = make([]rune, 0)
|
||||||
|
paramsNum += 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(key) >= i+7 {
|
||||||
|
if key[i+1:i+7] == "string" {
|
||||||
|
out = append(out, []rune(`([\w]+)`)...)
|
||||||
|
params = append(params, ":"+string(param))
|
||||||
|
paramsNum += 1
|
||||||
|
start = false
|
||||||
|
startexp = false
|
||||||
|
skipnum = 6
|
||||||
|
param = make([]rune, 0)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// params only support a-zA-Z0-9
|
||||||
|
if reg.MatchString(string(v)) {
|
||||||
|
param = append(param, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if v != '(' {
|
||||||
|
out = append(out, []rune(`(.+)`)...)
|
||||||
|
params = append(params, ":"+string(param))
|
||||||
|
param = make([]rune, 0)
|
||||||
|
paramsNum += 1
|
||||||
|
start = false
|
||||||
|
startexp = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if startexp {
|
||||||
|
if v != ')' {
|
||||||
|
expt = append(expt, v)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if v == ':' {
|
||||||
|
param = make([]rune, 0)
|
||||||
|
start = true
|
||||||
|
} else if v == '(' {
|
||||||
|
startexp = true
|
||||||
|
start = false
|
||||||
|
params = append(params, ":"+string(param))
|
||||||
|
paramsNum += 1
|
||||||
|
expt = make([]rune, 0)
|
||||||
|
expt = append(expt, '(')
|
||||||
|
} else if v == ')' {
|
||||||
|
startexp = false
|
||||||
|
expt = append(expt, ')')
|
||||||
|
out = append(out, expt...)
|
||||||
|
param = make([]rune, 0)
|
||||||
|
} else if v == '?' {
|
||||||
|
params = append(params, ":")
|
||||||
|
} else {
|
||||||
|
out = append(out, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(param) > 0 {
|
||||||
|
if paramsNum > 0 {
|
||||||
|
out = append(out, []rune(`(.+)`)...)
|
||||||
|
}
|
||||||
|
params = append(params, ":"+string(param))
|
||||||
|
}
|
||||||
|
return true, params, string(out)
|
||||||
|
} else {
|
||||||
|
return false, nil, ""
|
||||||
|
}
|
||||||
|
}
|
179
tree_test.go
Normal file
179
tree_test.go
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
package beego
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
type testinfo struct {
|
||||||
|
url string
|
||||||
|
requesturl string
|
||||||
|
params map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
var routers []testinfo
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
routers = make([]testinfo, 0)
|
||||||
|
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{"/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/*", "/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{"/: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{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}})
|
||||||
|
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/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
|
||||||
|
routers = append(routers, testinfo{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTreeRouters(t *testing.T) {
|
||||||
|
for _, r := range routers {
|
||||||
|
tr := NewTree()
|
||||||
|
tr.AddRouter(r.url, "astaxie")
|
||||||
|
obj, param := tr.Match(r.requesturl)
|
||||||
|
if obj == nil || obj.(string) != "astaxie" {
|
||||||
|
t.Fatal(r.url + " can't get obj ")
|
||||||
|
}
|
||||||
|
if r.params != nil {
|
||||||
|
for k, v := range r.params {
|
||||||
|
if vv, ok := param[k]; !ok {
|
||||||
|
t.Fatal(r.url + r.requesturl + " get param empty:" + k)
|
||||||
|
} else if vv != v {
|
||||||
|
t.Fatal(r.url + " " + r.requesturl + " should be:" + v + " get param:" + vv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddTree(t *testing.T) {
|
||||||
|
tr := NewTree()
|
||||||
|
tr.AddRouter("/shop/:id/account", "astaxie")
|
||||||
|
tr.AddRouter("/shop/:sd/ttt_:id(.+)_:page(.+).html", "astaxie")
|
||||||
|
t1 := NewTree()
|
||||||
|
t1.AddTree("/v1/zl", tr)
|
||||||
|
obj, param := t1.Match("/v1/zl/shop/123/account")
|
||||||
|
if obj == nil || obj.(string) != "astaxie" {
|
||||||
|
t.Fatal("/v1/zl/shop/:id/account can't get obj ")
|
||||||
|
}
|
||||||
|
if param == nil {
|
||||||
|
t.Fatal("get param error")
|
||||||
|
}
|
||||||
|
if param[":id"] != "123" {
|
||||||
|
t.Fatal("get :id param error")
|
||||||
|
}
|
||||||
|
obj, param = t1.Match("/v1/zl/shop/123/ttt_1_12.html")
|
||||||
|
if obj == nil || obj.(string) != "astaxie" {
|
||||||
|
t.Fatal("/v1/zl//shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
|
||||||
|
}
|
||||||
|
if param == nil {
|
||||||
|
t.Fatal("get param error")
|
||||||
|
}
|
||||||
|
if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" {
|
||||||
|
t.Fatal("get :sd :id :page param error")
|
||||||
|
}
|
||||||
|
|
||||||
|
t2 := NewTree()
|
||||||
|
t2.AddTree("/v1/:shopid", tr)
|
||||||
|
obj, param = t2.Match("/v1/zl/shop/123/account")
|
||||||
|
if obj == nil || obj.(string) != "astaxie" {
|
||||||
|
t.Fatal("/v1/:shopid/shop/:id/account can't get obj ")
|
||||||
|
}
|
||||||
|
if param == nil {
|
||||||
|
t.Fatal("get param error")
|
||||||
|
}
|
||||||
|
if param[":id"] != "123" || param[":shopid"] != "zl" {
|
||||||
|
t.Fatal("get :id :shopid param error")
|
||||||
|
}
|
||||||
|
obj, param = t2.Match("/v1/zl/shop/123/ttt_1_12.html")
|
||||||
|
if obj == nil || obj.(string) != "astaxie" {
|
||||||
|
t.Fatal("/v1/:shopid/shop/:sd/ttt_:id(.+)_:page(.+).html can't get obj ")
|
||||||
|
}
|
||||||
|
if param == nil {
|
||||||
|
t.Fatal("get :shopid param error")
|
||||||
|
}
|
||||||
|
if param[":sd"] != "123" || param[":id"] != "1" || param[":page"] != "12" || param[":shopid"] != "zl" {
|
||||||
|
t.Fatal("get :sd :id :page :shopid param error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitPath(t *testing.T) {
|
||||||
|
a := splitPath("/")
|
||||||
|
if len(a) != 0 {
|
||||||
|
t.Fatal("/ should retrun []")
|
||||||
|
}
|
||||||
|
a = splitPath("/admin")
|
||||||
|
if len(a) != 1 || a[0] != "admin" {
|
||||||
|
t.Fatal("/admin should retrun [admin]")
|
||||||
|
}
|
||||||
|
a = splitPath("/admin/")
|
||||||
|
if len(a) != 1 || a[0] != "admin" {
|
||||||
|
t.Fatal("/admin/ should retrun [admin]")
|
||||||
|
}
|
||||||
|
a = splitPath("/admin/users")
|
||||||
|
if len(a) != 2 || a[0] != "admin" || a[1] != "users" {
|
||||||
|
t.Fatal("/admin should retrun [admin users]")
|
||||||
|
}
|
||||||
|
a = splitPath("/admin/:id:int")
|
||||||
|
if len(a) != 2 || a[0] != "admin" || a[1] != ":id:int" {
|
||||||
|
t.Fatal("/admin should retrun [admin :id:int]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitSegment(t *testing.T) {
|
||||||
|
b, w, r := splitSegment("admin")
|
||||||
|
if b || len(w) != 0 || r != "" {
|
||||||
|
t.Fatal("admin should return false, nil, ''")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment("*")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":splat" || r != "" {
|
||||||
|
t.Fatal("* should return true, [:splat], ''")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment("*.*")
|
||||||
|
if !b || len(w) != 3 || w[1] != ":path" || w[2] != ":ext" || w[0] != "." || r != "" {
|
||||||
|
t.Fatal("admin should return true,[. :path :ext], ''")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":id")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":id" || r != "" {
|
||||||
|
t.Fatal(":id should return true, [:id], ''")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment("?:id")
|
||||||
|
if !b || len(w) != 2 || w[0] != ":" || w[1] != ":id" || r != "" {
|
||||||
|
t.Fatal("?:id should return true, [: :id], ''")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":id:int")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":id" || r != "([0-9]+)" {
|
||||||
|
t.Fatal(":id:int should return true, [:id], '([0-9]+)'")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":name:string")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":name" || r != `([\w]+)` {
|
||||||
|
t.Fatal(`:name:string should return true, [:name], '([\w]+)'`)
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":id([0-9]+)")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":id" || r != `([0-9]+)` {
|
||||||
|
t.Fatal(`:id([0-9]+) should return true, [:id], '([0-9]+)'`)
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":id([0-9]+)_:name")
|
||||||
|
if !b || len(w) != 2 || w[0] != ":id" || w[1] != ":name" || r != `([0-9]+)_(.+)` {
|
||||||
|
t.Fatal(`:id([0-9]+)_:name should return true, [:id :name], '([0-9]+)_(.+)'`)
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment(":id(.+)_cms.html")
|
||||||
|
if !b || len(w) != 1 || w[0] != ":id" || r != `(.+)_cms.html` {
|
||||||
|
t.Fatal(":id_cms.html should return true, [:id], '(.+)_cms.html'")
|
||||||
|
}
|
||||||
|
b, w, r = splitSegment("cms_:id(.+)_:page(.+).html")
|
||||||
|
if !b || len(w) != 2 || w[0] != ":id" || w[1] != ":page" || r != `cms_(.+)_(.+).html` {
|
||||||
|
t.Fatal(":id_cms.html should return true, [:id :page], cms_(.+)_(.+).html")
|
||||||
|
}
|
||||||
|
}
|
@ -248,7 +248,7 @@ func NewWithFilter(urlPrefix string, store cache.Cache) *Captcha {
|
|||||||
cpt := NewCaptcha(urlPrefix, store)
|
cpt := NewCaptcha(urlPrefix, store)
|
||||||
|
|
||||||
// create filter for serve captcha image
|
// create filter for serve captcha image
|
||||||
beego.AddFilter(cpt.URLPrefix+":", "BeforeRouter", cpt.Handler)
|
beego.InsertFilter(cpt.URLPrefix+"*", beego.BeforeRouter, cpt.Handler)
|
||||||
|
|
||||||
// add to template func map
|
// add to template func map
|
||||||
beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHtml)
|
beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHtml)
|
||||||
|
@ -64,24 +64,30 @@ func GrepFile(patten string, filename string) (lines []string, err error) {
|
|||||||
lines = make([]string, 0)
|
lines = make([]string, 0)
|
||||||
reader := bufio.NewReader(fd)
|
reader := bufio.NewReader(fd)
|
||||||
prefix := ""
|
prefix := ""
|
||||||
|
isLongLine := false
|
||||||
for {
|
for {
|
||||||
byteLine, isPrefix, er := reader.ReadLine()
|
byteLine, isPrefix, er := reader.ReadLine()
|
||||||
if er != nil && er != io.EOF {
|
if er != nil && er != io.EOF {
|
||||||
return nil, er
|
return nil, er
|
||||||
}
|
}
|
||||||
|
if er == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
line := string(byteLine)
|
line := string(byteLine)
|
||||||
if isPrefix {
|
if isPrefix {
|
||||||
prefix += line
|
prefix += line
|
||||||
continue
|
continue
|
||||||
|
} else {
|
||||||
|
isLongLine = true
|
||||||
}
|
}
|
||||||
|
|
||||||
line = prefix + line
|
line = prefix + line
|
||||||
|
if isLongLine {
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
if re.MatchString(line) {
|
if re.MatchString(line) {
|
||||||
lines = append(lines, line)
|
lines = append(lines, line)
|
||||||
}
|
}
|
||||||
if er == io.EOF {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return lines, nil
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
@ -8,19 +8,33 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
r "math/rand"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomCreateBytes generate random []byte by specify chars.
|
// RandomCreateBytes generate random []byte by specify chars.
|
||||||
func RandomCreateBytes(n int, alphabets ...byte) []byte {
|
func RandomCreateBytes(n int, alphabets ...byte) []byte {
|
||||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||||
var bytes = make([]byte, n)
|
var bytes = make([]byte, n)
|
||||||
rand.Read(bytes)
|
var randby bool
|
||||||
|
if num, err := rand.Read(bytes); num != n || err != nil {
|
||||||
|
r.Seed(time.Now().UnixNano())
|
||||||
|
randby = true
|
||||||
|
}
|
||||||
for i, b := range bytes {
|
for i, b := range bytes {
|
||||||
if len(alphabets) == 0 {
|
if len(alphabets) == 0 {
|
||||||
|
if randby {
|
||||||
|
bytes[i] = alphanum[r.Intn(len(alphanum))]
|
||||||
|
} else {
|
||||||
bytes[i] = alphanum[b%byte(len(alphanum))]
|
bytes[i] = alphanum[b%byte(len(alphanum))]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if randby {
|
||||||
|
bytes[i] = alphabets[r.Intn(len(alphabets))]
|
||||||
} else {
|
} else {
|
||||||
bytes[i] = alphabets[b%byte(len(alphabets))]
|
bytes[i] = alphabets[b%byte(len(alphabets))]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user