Merge branch 'develop' of github.com:dvwallin/beego into develop

This commit is contained in:
David V. Wallin 2015-09-17 17:07:06 +02:00
commit edbad60782
56 changed files with 1571 additions and 995 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.DS_Store
*.swp
*.swo
beego.iml

View File

@ -3,14 +3,36 @@
[![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest)
[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego)
beego is an open-source, high-performance, modular, full-stack web framework.
beego is used for rapid development of RESTful APIs, web apps and backend services in Go.
It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding.
More info [beego.me](http://beego.me)
## Installation
##Quick Start
######Download and install
go get github.com/astaxie/beego
######Create file `hello.go`
```go
package main
import "github.com/astaxie/beego"
func main(){
beego.Run()
}
```
######Build and run
```bash
go build hello.go
./hello
```
######Congratulations!
You just built your first beego app.
Open your browser and visit `http://localhost:8000`.
Please see [Documentation](http://beego.me/docs) for more.
## Features
* RESTful support

View File

@ -101,11 +101,11 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
m["AppConfigPath"] = AppConfigPath
m["StaticDir"] = StaticDir
m["StaticExtensionsToGzip"] = StaticExtensionsToGzip
m["HttpAddr"] = HttpAddr
m["HttpPort"] = HttpPort
m["HttpTLS"] = EnableHttpTLS
m["HttpCertFile"] = HttpCertFile
m["HttpKeyFile"] = HttpKeyFile
m["HTTPAddr"] = HTTPAddr
m["HTTPPort"] = HTTPPort
m["HTTPTLS"] = EnableHTTPTLS
m["HTTPCertFile"] = HTTPCertFile
m["HTTPKeyFile"] = HTTPKeyFile
m["RecoverPanic"] = RecoverPanic
m["AutoRender"] = AutoRender
m["ViewsPath"] = ViewsPath
@ -114,14 +114,14 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
m["SessionProvider"] = SessionProvider
m["SessionName"] = SessionName
m["SessionGCMaxLifetime"] = SessionGCMaxLifetime
m["SessionSavePath"] = SessionSavePath
m["SessionProviderConfig"] = SessionProviderConfig
m["SessionCookieLifeTime"] = SessionCookieLifeTime
m["UseFcgi"] = UseFcgi
m["EnabelFcgi"] = EnabelFcgi
m["MaxMemory"] = MaxMemory
m["EnableGzip"] = EnableGzip
m["DirectoryIndex"] = DirectoryIndex
m["HttpServerTimeOut"] = HttpServerTimeOut
m["ErrorsShow"] = ErrorsShow
m["HTTPServerTimeOut"] = HTTPServerTimeOut
m["EnableErrorsShow"] = EnableErrorsShow
m["XSRFKEY"] = XSRFKEY
m["EnableXSRF"] = EnableXSRF
m["XSRFExpire"] = XSRFExpire
@ -130,8 +130,8 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
m["TemplateRight"] = TemplateRight
m["BeegoServerName"] = BeegoServerName
m["EnableAdmin"] = EnableAdmin
m["AdminHttpAddr"] = AdminHttpAddr
m["AdminHttpPort"] = AdminHttpPort
m["AdminHTTPAddr"] = AdminHTTPAddr
m["AdminHTTPPort"] = AdminHTTPPort
tmpl := template.Must(template.New("dashboard").Parse(dashboardTpl))
tmpl = template.Must(tmpl.Parse(configTpl))
@ -314,14 +314,14 @@ func profIndex(rw http.ResponseWriter, r *http.Request) {
data["Content"] = result.String()
if format == "json" && command == "gc summary" {
dataJson, err := json.Marshal(data)
dataJSON, err := json.Marshal(data)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
rw.Header().Set("Content-Type", "application/json")
rw.Write(dataJson)
rw.Write(dataJSON)
return
}
@ -451,10 +451,10 @@ func (admin *adminApp) Run() {
if len(toolbox.AdminTaskList) > 0 {
toolbox.StartTask()
}
addr := AdminHttpAddr
addr := AdminHTTPAddr
if AdminHttpPort != 0 {
addr = fmt.Sprintf("%s:%d", AdminHttpAddr, AdminHttpPort)
if AdminHTTPPort != 0 {
addr = fmt.Sprintf("%s:%d", AdminHTTPAddr, AdminHTTPPort)
}
for p, f := range admin.routers {
http.Handle(p, f)

236
app.go
View File

@ -20,15 +20,26 @@ import (
"net/http"
"net/http/fcgi"
"os"
"path"
"time"
"github.com/astaxie/beego/grace"
"github.com/astaxie/beego/utils"
)
var (
// BeeApp is an application instance
BeeApp *App
)
func init() {
// create beego application
BeeApp = NewApp()
}
// App defines beego application with a new PatternServeMux.
type App struct {
Handlers *ControllerRegistor
Handlers *ControllerRegister
Server *http.Server
}
@ -41,10 +52,10 @@ func NewApp() *App {
// Run beego application.
func (app *App) Run() {
addr := HttpAddr
addr := HTTPAddr
if HttpPort != 0 {
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort)
if HTTPPort != 0 {
addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPPort)
}
var (
@ -53,8 +64,8 @@ func (app *App) Run() {
)
endRunning := make(chan bool, 1)
if UseFcgi {
if UseStdIo {
if EnabelFcgi {
if EnableStdIo {
err = fcgi.Serve(nil, app.Handlers) // standard I/O
if err == nil {
BeeLogger.Info("Use FCGI via standard I/O")
@ -62,7 +73,7 @@ func (app *App) Run() {
BeeLogger.Info("Cannot use FCGI via standard I/O", err)
}
} else {
if HttpPort == 0 {
if HTTPPort == 0 {
// remove the Socket file before start
if utils.FileExists(addr) {
os.Remove(addr)
@ -80,18 +91,18 @@ func (app *App) Run() {
if Graceful {
app.Server.Addr = addr
app.Server.Handler = app.Handlers
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
if EnableHttpTLS {
app.Server.ReadTimeout = time.Duration(HTTPServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(HTTPServerTimeOut) * time.Second
if EnableHTTPTLS {
go func() {
time.Sleep(20 * time.Microsecond)
if HttpsPort != 0 {
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
if HTTPSPort != 0 {
addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPSPort)
app.Server.Addr = addr
}
server := grace.NewServer(addr, app.Handlers)
server.Server = app.Server
err := server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
err := server.ListenAndServeTLS(HTTPCertFile, HTTPKeyFile)
if err != nil {
BeeLogger.Critical("ListenAndServeTLS: ", err, fmt.Sprintf("%d", os.Getpid()))
time.Sleep(100 * time.Microsecond)
@ -99,11 +110,11 @@ func (app *App) Run() {
}
}()
}
if EnableHttpListen {
if EnableHTTPListen {
go func() {
server := grace.NewServer(addr, app.Handlers)
server.Server = app.Server
if ListenTCP4 && HttpAddr == "" {
if ListenTCP4 && HTTPAddr == "" {
server.Network = "tcp4"
}
err := server.ListenAndServe()
@ -117,17 +128,17 @@ func (app *App) Run() {
} else {
app.Server.Addr = addr
app.Server.Handler = app.Handlers
app.Server.ReadTimeout = time.Duration(HttpServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(HttpServerTimeOut) * time.Second
app.Server.ReadTimeout = time.Duration(HTTPServerTimeOut) * time.Second
app.Server.WriteTimeout = time.Duration(HTTPServerTimeOut) * time.Second
if EnableHttpTLS {
if EnableHTTPTLS {
go func() {
time.Sleep(20 * time.Microsecond)
if HttpsPort != 0 {
app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
if HTTPSPort != 0 {
app.Server.Addr = fmt.Sprintf("%s:%d", HTTPAddr, HTTPSPort)
}
BeeLogger.Info("https server Running on %s", app.Server.Addr)
err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
err := app.Server.ListenAndServeTLS(HTTPCertFile, HTTPKeyFile)
if err != nil {
BeeLogger.Critical("ListenAndServeTLS: ", err)
time.Sleep(100 * time.Microsecond)
@ -136,11 +147,11 @@ func (app *App) Run() {
}()
}
if EnableHttpListen {
if EnableHTTPListen {
go func() {
app.Server.Addr = addr
BeeLogger.Info("http server Running on %s", app.Server.Addr)
if ListenTCP4 && HttpAddr == "" {
if ListenTCP4 && HTTPAddr == "" {
ln, err := net.Listen("tcp4", app.Server.Addr)
if err != nil {
BeeLogger.Critical("ListenAndServe: ", err)
@ -170,3 +181,182 @@ func (app *App) Run() {
}
<-endRunning
}
// Router adds a patterned controller handler to BeeApp.
// 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 {
BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
return BeeApp
}
// Include will generate router file in the router/xxx.go from the controller's comments
// usage:
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
// type BankAccount struct{
// beego.Controller
// }
//
// register the function
// func (b *BankAccount)Mapping(){
// b.Mapping("ShowAccount" , b.ShowAccount)
// b.Mapping("ModifyAccount", b.ModifyAccount)
//}
//
// //@router /account/:id [get]
// func (b *BankAccount) ShowAccount(){
// //logic
// }
//
//
// //@router /account/:id [post]
// func (b *BankAccount) ModifyAccount(){
// //logic
// }
//
// the comments @router url methodlist
// url support all the function Router's pattern
// methodlist [get post head put delete options *]
func Include(cList ...ControllerInterface) *App {
BeeApp.Handlers.Include(cList...)
return BeeApp
}
// RESTRouter adds a restful controller handler to BeeApp.
// its' controller implements beego.ControllerInterface and
// defines a param "pattern/:objectId" to visit each resource.
func RESTRouter(rootpath string, c ControllerInterface) *App {
Router(rootpath, c)
Router(path.Join(rootpath, ":objectId"), c)
return BeeApp
}
// AutoRouter adds defined controller handler to BeeApp.
// 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 {
BeeApp.Handlers.AddAuto(c)
return BeeApp
}
// AutoPrefix adds controller handler to BeeApp with prefix.
// 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 {
BeeApp.Handlers.AddAutoPrefix(prefix, c)
return BeeApp
}
// Get used to register router for Get method
// usage:
// beego.Get("/", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func Get(rootpath string, f FilterFunc) *App {
BeeApp.Handlers.Get(rootpath, f)
return BeeApp
}
// Post used to 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 {
BeeApp.Handlers.Post(rootpath, f)
return BeeApp
}
// Delete used to 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 {
BeeApp.Handlers.Delete(rootpath, f)
return BeeApp
}
// Put used to 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 {
BeeApp.Handlers.Put(rootpath, f)
return BeeApp
}
// Head used to 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 {
BeeApp.Handlers.Head(rootpath, f)
return BeeApp
}
// Options used to 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 {
BeeApp.Handlers.Options(rootpath, f)
return BeeApp
}
// Patch used to 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 {
BeeApp.Handlers.Patch(rootpath, f)
return BeeApp
}
// Any used to register router for all methods
// usage:
// beego.Any("/api", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func Any(rootpath string, f FilterFunc) *App {
BeeApp.Handlers.Any(rootpath, f)
return BeeApp
}
// Handler used to register a Handler router
// usage:
// beego.Handler("/api", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
BeeApp.Handlers.Handler(rootpath, h, options...)
return BeeApp
}
// InsertFilter adds a FilterFunc with pattern condition and action constant.
// The pos means action constant including
// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
return BeeApp
}

298
beego.go
View File

@ -12,243 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// beego is an open-source, high-performance, modularity, full-stack web framework
//
// package main
//
// import "github.com/astaxie/beego"
//
// func main() {
// beego.Run()
// }
//
// more infomation: http://beego.me
package beego
import (
"net/http"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"github.com/astaxie/beego/session"
)
// beego web framework version.
const VERSION = "1.5.0"
type hookfunc func() error //hook function to run
var hooks []hookfunc //hook function slice to store the hookfunc
//hook function to run
type hookfunc func() error
// Router adds a patterned controller handler to BeeApp.
// 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 {
BeeApp.Handlers.Add(rootpath, c, mappingMethods...)
return BeeApp
}
var (
hooks = make([]hookfunc, 0) //hook function slice to store the hookfunc
)
// Router add list from
// usage:
// beego.Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
// type BankAccount struct{
// beego.Controller
// }
//
// register the function
// func (b *BankAccount)Mapping(){
// b.Mapping("ShowAccount" , b.ShowAccount)
// b.Mapping("ModifyAccount", b.ModifyAccount)
//}
//
// //@router /account/:id [get]
// func (b *BankAccount) ShowAccount(){
// //logic
// }
//
//
// //@router /account/:id [post]
// func (b *BankAccount) ModifyAccount(){
// //logic
// }
//
// the comments @router url methodlist
// url support all the function Router's pattern
// methodlist [get post head put delete options *]
func Include(cList ...ControllerInterface) *App {
BeeApp.Handlers.Include(cList...)
return BeeApp
}
// RESTRouter adds a restful controller handler to BeeApp.
// its' controller implements beego.ControllerInterface and
// defines a param "pattern/:objectId" to visit each resource.
func RESTRouter(rootpath string, c ControllerInterface) *App {
Router(rootpath, c)
Router(path.Join(rootpath, ":objectId"), c)
return BeeApp
}
// AutoRouter adds defined controller handler to BeeApp.
// 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 {
BeeApp.Handlers.AddAuto(c)
return BeeApp
}
// AutoPrefix adds controller handler to BeeApp with prefix.
// 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 {
BeeApp.Handlers.AddAutoPrefix(prefix, c)
return BeeApp
}
// register router for Get method
// usage:
// beego.Get("/", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func Get(rootpath string, f FilterFunc) *App {
BeeApp.Handlers.Get(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Post(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Delete(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Put(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Head(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Options(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Patch(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Any(rootpath, f)
return BeeApp
}
// 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 {
BeeApp.Handlers.Handler(rootpath, h, options...)
return BeeApp
}
// SetViewsPath sets view directory path in beego application.
func SetViewsPath(path string) *App {
ViewsPath = path
return BeeApp
}
// 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".
func SetStaticPath(url string, path string) *App {
if !strings.HasPrefix(url, "/") {
url = "/" + url
}
url = strings.TrimRight(url, "/")
StaticDir[url] = path
return BeeApp
}
// DelStaticPath removes the static folder setting in this url pattern in beego application.
func DelStaticPath(url string) *App {
if !strings.HasPrefix(url, "/") {
url = "/" + url
}
url = strings.TrimRight(url, "/")
delete(StaticDir, url)
return BeeApp
}
// InsertFilter adds a FilterFunc with pattern condition and action constant.
// The pos means action constant including
// beego.BeforeStatic, beego.BeforeRouter, beego.BeforeExec, beego.AfterExec and beego.FinishRouter.
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
func InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) *App {
BeeApp.Handlers.InsertFilter(pattern, pos, filter, params...)
return BeeApp
}
// The hookfunc will run in beego.Run()
// AddAPPStartHook is used to register the hookfunc
// The hookfuncs will run in beego.Run()
// such as sessionInit, middlerware start, buildtemplate, admin start
func AddAPPStartHook(hf hookfunc) {
hooks = append(hooks, hf)
@ -259,25 +43,22 @@ func AddAPPStartHook(hf hookfunc) {
// beego.Run(":8089")
// beego.Run("127.0.0.1:8089")
func Run(params ...string) {
initBeforeHTTPRun()
if len(params) > 0 && params[0] != "" {
strs := strings.Split(params[0], ":")
if len(strs) > 0 && strs[0] != "" {
HttpAddr = strs[0]
HTTPAddr = strs[0]
}
if len(strs) > 1 && strs[1] != "" {
HttpPort, _ = strconv.Atoi(strs[1])
HTTPPort, _ = strconv.Atoi(strs[1])
}
}
initBeforeHttpRun()
if EnableAdmin {
go beeAdminApp.Run()
}
BeeApp.Run()
}
func initBeforeHttpRun() {
func initBeforeHTTPRun() {
// if AppConfigPath not In the conf/app.conf reParse config
if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") {
err := ParseConfig()
@ -287,53 +68,22 @@ func initBeforeHttpRun() {
}
}
//init mime
AddAPPStartHook(initMime)
//init hooks
AddAPPStartHook(registerMime)
AddAPPStartHook(registerDefaultErrorHandler)
AddAPPStartHook(registerSession)
AddAPPStartHook(registerDocs)
AddAPPStartHook(registerTemplate)
AddAPPStartHook(registerAdmin)
// do hooks function
for _, hk := range hooks {
err := hk()
if err != nil {
if err := hk(); err != nil {
panic(err)
}
}
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + filepath.ToSlash(SessionSavePath) + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
}
GlobalSessions, err = session.NewManager(SessionProvider,
sessionConfig)
if err != nil {
panic(err)
}
go GlobalSessions.GC()
}
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
}
}
registerDefaultErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
}
}
// this function is for test package init
// TestBeegoInit is for test package init
func TestBeegoInit(apppath string) {
AppPath = apppath
os.Setenv("BEEGO_RUNMODE", "test")
@ -344,9 +94,5 @@ func TestBeegoInit(apppath string) {
Info(err)
}
os.Chdir(AppPath)
initBeforeHttpRun()
}
func init() {
hooks = make([]hookfunc, 0)
initBeforeHTTPRun()
}

4
cache/README.md vendored
View File

@ -43,7 +43,7 @@ interval means the gc time. The cache will check at each time interval, whether
## Memcache adapter
Memcache adapter use the vitess's [Memcache](http://code.google.com/p/vitess/go/memcache) client.
Memcache adapter use the [gomemcache](http://github.com/bradfitz/gomemcache) client.
Configure like this:
@ -52,7 +52,7 @@ Configure like this:
## Redis adapter
Redis adapter use the [redigo](http://github.com/garyburd/redigo/redis) client.
Redis adapter use the [redigo](http://github.com/garyburd/redigo) client.
Configure like this:

3
cache/cache.go vendored
View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Package cache provide a Cache interface and some implemetn engine
// Usage:
//
// import(
@ -80,7 +81,7 @@ func Register(name string, adapter Cache) {
adapters[name] = adapter
}
// Create a new cache driver by adapter name and config string.
// NewCache Create a new cache driver by adapter name and config string.
// config need to be correct JSON as string: {"interval":360}.
// it will start gc automatically.
func NewCache(adapterName, config string) (adapter Cache, err error) {

12
cache/conv.go vendored
View File

@ -19,7 +19,7 @@ import (
"strconv"
)
// convert interface to string.
// GetString convert interface to string.
func GetString(v interface{}) string {
switch result := v.(type) {
case string:
@ -34,7 +34,7 @@ func GetString(v interface{}) string {
return ""
}
// convert interface to int.
// GetInt convert interface to int.
func GetInt(v interface{}) int {
switch result := v.(type) {
case int:
@ -52,7 +52,7 @@ func GetInt(v interface{}) int {
return 0
}
// convert interface to int64.
// GetInt64 convert interface to int64.
func GetInt64(v interface{}) int64 {
switch result := v.(type) {
case int:
@ -71,7 +71,7 @@ func GetInt64(v interface{}) int64 {
return 0
}
// convert interface to float64.
// GetFloat64 convert interface to float64.
func GetFloat64(v interface{}) float64 {
switch result := v.(type) {
case float64:
@ -85,7 +85,7 @@ func GetFloat64(v interface{}) float64 {
return 0
}
// convert interface to bool.
// GetBool convert interface to bool.
func GetBool(v interface{}) bool {
switch result := v.(type) {
case bool:
@ -99,7 +99,7 @@ func GetBool(v interface{}) bool {
return false
}
// convert interface to byte slice.
// getByteArray convert interface to byte slice.
func getByteArray(v interface{}) []byte {
switch result := v.(type) {
case []byte:

14
cache/conv_test.go vendored
View File

@ -27,7 +27,7 @@ func TestGetString(t *testing.T) {
if "test2" != GetString(t2) {
t.Error("get string from byte array error")
}
var t3 int = 1
var t3 = 1
if "1" != GetString(t3) {
t.Error("get string from int error")
}
@ -35,7 +35,7 @@ func TestGetString(t *testing.T) {
if "1" != GetString(t4) {
t.Error("get string from int64 error")
}
var t5 float64 = 1.1
var t5 = 1.1
if "1.1" != GetString(t5) {
t.Error("get string from float64 error")
}
@ -46,7 +46,7 @@ func TestGetString(t *testing.T) {
}
func TestGetInt(t *testing.T) {
var t1 int = 1
var t1 = 1
if 1 != GetInt(t1) {
t.Error("get int from int error")
}
@ -69,7 +69,7 @@ func TestGetInt(t *testing.T) {
func TestGetInt64(t *testing.T) {
var i int64 = 1
var t1 int = 1
var t1 = 1
if i != GetInt64(t1) {
t.Error("get int64 from int error")
}
@ -91,12 +91,12 @@ func TestGetInt64(t *testing.T) {
}
func TestGetFloat64(t *testing.T) {
var f float64 = 1.11
var f = 1.11
var t1 float32 = 1.11
if f != GetFloat64(t1) {
t.Error("get float64 from float32 error")
}
var t2 float64 = 1.11
var t2 = 1.11
if f != GetFloat64(t2) {
t.Error("get float64 from float64 error")
}
@ -106,7 +106,7 @@ func TestGetFloat64(t *testing.T) {
}
var f2 float64 = 1
var t4 int = 1
var t4 = 1
if f2 != GetFloat64(t4) {
t.Error("get float64 from int error")
}

45
cache/file.go vendored
View File

@ -41,11 +41,12 @@ type FileCacheItem struct {
Expired int64
}
// FileCache Config
var (
FileCachePath string = "cache" // cache directory
FileCacheFileSuffix string = ".bin" // cache file suffix
FileCacheDirectoryLevel int = 2 // cache file deep level if auto generated cache files.
FileCacheEmbedExpiry int64 = 0 // cache expire time, default is no expire forever.
FileCachePath = "cache" // cache directory
FileCacheFileSuffix = ".bin" // cache file suffix
FileCacheDirectoryLevel = 2 // cache file deep level if auto generated cache files.
FileCacheEmbedExpiry int64 // cache expire time, default is no expire forever.
)
// FileCache is cache adapter for file storage.
@ -56,14 +57,14 @@ type FileCache struct {
EmbedExpiry int
}
// Create new file cache with no config.
// NewFileCache Create new file cache with no config.
// the level and expiry need set in method StartAndGC as config string.
func NewFileCache() *FileCache {
// return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
return &FileCache{}
}
// Start and begin gc for file cache.
// StartAndGC will start and begin gc for file cache.
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
func (fc *FileCache) StartAndGC(config string) error {
@ -120,12 +121,12 @@ func (fc *FileCache) getCacheFileName(key string) string {
// Get value from file cache.
// if non-exist or expired, return empty string.
func (fc *FileCache) Get(key string) interface{} {
fileData, err := File_get_contents(fc.getCacheFileName(key))
fileData, err := FileGetContents(fc.getCacheFileName(key))
if err != nil {
return ""
}
var to FileCacheItem
Gob_decode(fileData, &to)
GobDecode(fileData, &to)
if to.Expired < time.Now().Unix() {
return ""
}
@ -155,11 +156,11 @@ func (fc *FileCache) Put(key string, val interface{}, timeout int64) error {
item.Expired = time.Now().Unix() + timeout
}
item.Lastaccess = time.Now().Unix()
data, err := Gob_encode(item)
data, err := GobEncode(item)
if err != nil {
return err
}
return File_put_contents(fc.getCacheFileName(key), data)
return FilePutContents(fc.getCacheFileName(key), data)
}
// Delete file cache value.
@ -171,7 +172,7 @@ func (fc *FileCache) Delete(key string) error {
return nil
}
// Increase cached int value.
// Incr will increase cached int value.
// fc value is saving forever unless Delete.
func (fc *FileCache) Incr(key string) error {
data := fc.Get(key)
@ -185,7 +186,7 @@ func (fc *FileCache) Incr(key string) error {
return nil
}
// Decrease cached int value.
// Decr will decrease cached int value.
func (fc *FileCache) Decr(key string) error {
data := fc.Get(key)
var decr int
@ -198,13 +199,13 @@ func (fc *FileCache) Decr(key string) error {
return nil
}
// Check value is exist.
// IsExist check value is exist.
func (fc *FileCache) IsExist(key string) bool {
ret, _ := exists(fc.getCacheFileName(key))
return ret
}
// Clean cached files.
// ClearAll will clean cached files.
// not implemented.
func (fc *FileCache) ClearAll() error {
return nil
@ -222,9 +223,9 @@ func exists(path string) (bool, error) {
return false, err
}
// Get bytes to file.
// FileGetContents Get bytes to file.
// if non-exist, create this file.
func File_get_contents(filename string) (data []byte, e error) {
func FileGetContents(filename string) (data []byte, e error) {
f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
if e != nil {
return
@ -242,9 +243,9 @@ func File_get_contents(filename string) (data []byte, e error) {
return
}
// Put bytes to file.
// FilePutContents Put bytes to file.
// if non-exist, create this file.
func File_put_contents(filename string, content []byte) error {
func FilePutContents(filename string, content []byte) error {
fp, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
if err != nil {
return err
@ -254,8 +255,8 @@ func File_put_contents(filename string, content []byte) error {
return err
}
// Gob encodes file cache item.
func Gob_encode(data interface{}) ([]byte, error) {
// GobEncode Gob encodes file cache item.
func GobEncode(data interface{}) ([]byte, error) {
buf := bytes.NewBuffer(nil)
enc := gob.NewEncoder(buf)
err := enc.Encode(data)
@ -265,8 +266,8 @@ func Gob_encode(data interface{}) ([]byte, error) {
return buf.Bytes(), err
}
// Gob decodes file cache item.
func Gob_decode(data []byte, to *FileCacheItem) error {
// GobDecode Gob decodes file cache item.
func GobDecode(data []byte, to *FileCacheItem) error {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
return dec.Decode(&to)

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// package memcahe for cache provider
// Package memcache for cache provider
//
// depend on github.com/bradfitz/gomemcache/memcache
//
@ -39,19 +39,19 @@ import (
"github.com/astaxie/beego/cache"
)
// Memcache adapter.
type MemcacheCache struct {
// Cache Memcache adapter.
type Cache struct {
conn *memcache.Client
conninfo []string
}
// create new memcache adapter.
func NewMemCache() *MemcacheCache {
return &MemcacheCache{}
// NewMemCache create new memcache adapter.
func NewMemCache() *Cache {
return &Cache{}
}
// get value from memcache.
func (rc *MemcacheCache) Get(key string) interface{} {
// Get get value from memcache.
func (rc *Cache) Get(key string) interface{} {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -63,8 +63,8 @@ func (rc *MemcacheCache) Get(key string) interface{} {
return nil
}
// get value from memcache.
func (rc *MemcacheCache) GetMulti(keys []string) []interface{} {
// GetMulti get value from memcache.
func (rc *Cache) GetMulti(keys []string) []interface{} {
size := len(keys)
var rv []interface{}
if rc.conn == nil {
@ -81,16 +81,15 @@ func (rc *MemcacheCache) GetMulti(keys []string) []interface{} {
rv = append(rv, string(v.Value))
}
return rv
} else {
for i := 0; i < size; i++ {
rv = append(rv, err)
}
return rv
}
for i := 0; i < size; i++ {
rv = append(rv, err)
}
return rv
}
// put value to memcache. only support string.
func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error {
// Put put value to memcache. only support string.
func (rc *Cache) Put(key string, val interface{}, timeout int64) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -104,8 +103,8 @@ func (rc *MemcacheCache) Put(key string, val interface{}, timeout int64) error {
return rc.conn.Set(&item)
}
// delete value in memcache.
func (rc *MemcacheCache) Delete(key string) error {
// Delete delete value in memcache.
func (rc *Cache) Delete(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -114,8 +113,8 @@ func (rc *MemcacheCache) Delete(key string) error {
return rc.conn.Delete(key)
}
// increase counter.
func (rc *MemcacheCache) Incr(key string) error {
// Incr increase counter.
func (rc *Cache) Incr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -125,8 +124,8 @@ func (rc *MemcacheCache) Incr(key string) error {
return err
}
// decrease counter.
func (rc *MemcacheCache) Decr(key string) error {
// Decr decrease counter.
func (rc *Cache) Decr(key string) error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -136,8 +135,8 @@ func (rc *MemcacheCache) Decr(key string) error {
return err
}
// check value exists in memcache.
func (rc *MemcacheCache) IsExist(key string) bool {
// IsExist check value exists in memcache.
func (rc *Cache) IsExist(key string) bool {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return false
@ -150,8 +149,8 @@ func (rc *MemcacheCache) IsExist(key string) bool {
return true
}
// clear all cached in memcache.
func (rc *MemcacheCache) ClearAll() error {
// ClearAll clear all cached in memcache.
func (rc *Cache) ClearAll() error {
if rc.conn == nil {
if err := rc.connectInit(); err != nil {
return err
@ -160,10 +159,10 @@ func (rc *MemcacheCache) ClearAll() error {
return rc.conn.FlushAll()
}
// start memcache adapter.
// StartAndGC start memcache adapter.
// config string is like {"conn":"connection info"}.
// if connecting error, return.
func (rc *MemcacheCache) StartAndGC(config string) error {
func (rc *Cache) StartAndGC(config string) error {
var cf map[string]string
json.Unmarshal([]byte(config), &cf)
if _, ok := cf["conn"]; !ok {
@ -179,7 +178,7 @@ func (rc *MemcacheCache) StartAndGC(config string) error {
}
// connect to memcache and keep the connection.
func (rc *MemcacheCache) connectInit() error {
func (rc *Cache) connectInit() error {
rc.conn = memcache.New(rc.conninfo...)
return nil
}

View File

@ -23,7 +23,7 @@ import (
"time"
)
func TestRedisCache(t *testing.T) {
func TestMemcacheCache(t *testing.T) {
bm, err := cache.NewCache("memcache", `{"conn": "127.0.0.1:11211"}`)
if err != nil {
t.Error("init err")

26
cache/memory.go vendored
View File

@ -23,18 +23,18 @@ import (
)
var (
// clock time of recycling the expired cache items in memory.
DefaultEvery int = 60 // 1 minute
// DefaultEvery means the clock time of recycling the expired cache items in memory.
DefaultEvery = 60 // 1 minute
)
// Memory cache item.
// MemoryItem store enery cache item.
type MemoryItem struct {
val interface{}
Lastaccess time.Time
expired int64
}
// Memory cache adapter.
// MemoryCache is Memory cache adapter.
// it contains a RW locker for safe map storage.
type MemoryCache struct {
lock sync.RWMutex
@ -87,7 +87,7 @@ func (bc *MemoryCache) Put(name string, value interface{}, expired int64) error
return nil
}
/// Delete cache in memory.
// Delete cache in memory.
func (bc *MemoryCache) Delete(name string) error {
bc.lock.Lock()
defer bc.lock.Unlock()
@ -101,7 +101,7 @@ func (bc *MemoryCache) Delete(name string) error {
return nil
}
// Increase cache counter in memory.
// Incr increase cache counter in memory.
// it supports int,int64,int32,uint,uint64,uint32.
func (bc *MemoryCache) Incr(key string) error {
bc.lock.RLock()
@ -129,7 +129,7 @@ func (bc *MemoryCache) Incr(key string) error {
return nil
}
// Decrease counter in memory.
// Decr decrease counter in memory.
func (bc *MemoryCache) Decr(key string) error {
bc.lock.RLock()
defer bc.lock.RUnlock()
@ -168,7 +168,7 @@ func (bc *MemoryCache) Decr(key string) error {
return nil
}
// check cache exist in memory.
// IsExist check cache exist in memory.
func (bc *MemoryCache) IsExist(name string) bool {
bc.lock.RLock()
defer bc.lock.RUnlock()
@ -176,7 +176,7 @@ func (bc *MemoryCache) IsExist(name string) bool {
return ok
}
// delete all cache in memory.
// ClearAll will delete all cache in memory.
func (bc *MemoryCache) ClearAll() error {
bc.lock.Lock()
defer bc.lock.Unlock()
@ -184,7 +184,7 @@ func (bc *MemoryCache) ClearAll() error {
return nil
}
// start memory cache. it will check expiration in every clock time.
// StartAndGC start memory cache. it will check expiration in every clock time.
func (bc *MemoryCache) StartAndGC(config string) error {
var cf map[string]int
json.Unmarshal([]byte(config), &cf)
@ -213,13 +213,13 @@ func (bc *MemoryCache) vaccuum() {
return
}
for name := range bc.items {
bc.item_expired(name)
bc.itemExpired(name)
}
}
}
// item_expired returns true if an item is expired.
func (bc *MemoryCache) item_expired(name string) bool {
// itemExpired returns true if an item is expired.
func (bc *MemoryCache) itemExpired(name string) bool {
bc.lock.Lock()
defer bc.lock.Unlock()
itm, ok := bc.items[name]

52
cache/redis/redis.go vendored
View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// package redis for cache provider
// Package redis for cache provider
//
// depend on github.com/garyburd/redigo/redis
//
@ -41,12 +41,12 @@ import (
)
var (
// the collection name of redis for cache adapter.
DefaultKey string = "beecacheRedis"
// DefaultKey the collection name of redis for cache adapter.
DefaultKey = "beecacheRedis"
)
// Redis cache adapter.
type RedisCache struct {
// Cache is Redis cache adapter.
type Cache struct {
p *redis.Pool // redis connection pool
conninfo string
dbNum int
@ -54,13 +54,13 @@ type RedisCache struct {
password string
}
// create new redis cache with default collection name.
func NewRedisCache() *RedisCache {
return &RedisCache{key: DefaultKey}
// NewRedisCache create new redis cache with default collection name.
func NewRedisCache() *Cache {
return &Cache{key: DefaultKey}
}
// actually do the redis cmds
func (rc *RedisCache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
func (rc *Cache) do(commandName string, args ...interface{}) (reply interface{}, err error) {
c := rc.p.Get()
defer c.Close()
@ -68,7 +68,7 @@ func (rc *RedisCache) do(commandName string, args ...interface{}) (reply interfa
}
// Get cache from redis.
func (rc *RedisCache) Get(key string) interface{} {
func (rc *Cache) Get(key string) interface{} {
if v, err := rc.do("GET", key); err == nil {
return v
}
@ -76,7 +76,7 @@ func (rc *RedisCache) Get(key string) interface{} {
}
// GetMulti get cache from redis.
func (rc *RedisCache) GetMulti(keys []string) []interface{} {
func (rc *Cache) GetMulti(keys []string) []interface{} {
size := len(keys)
var rv []interface{}
c := rc.p.Get()
@ -108,8 +108,8 @@ ERROR:
return rv
}
// put cache to redis.
func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error {
// Put put cache to redis.
func (rc *Cache) Put(key string, val interface{}, timeout int64) error {
var err error
if _, err = rc.do("SETEX", key, timeout, val); err != nil {
return err
@ -121,8 +121,8 @@ func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error {
return err
}
// delete cache in redis.
func (rc *RedisCache) Delete(key string) error {
// Delete delete cache in redis.
func (rc *Cache) Delete(key string) error {
var err error
if _, err = rc.do("DEL", key); err != nil {
return err
@ -131,8 +131,8 @@ func (rc *RedisCache) Delete(key string) error {
return err
}
// check cache's existence in redis.
func (rc *RedisCache) IsExist(key string) bool {
// IsExist check cache's existence in redis.
func (rc *Cache) IsExist(key string) bool {
v, err := redis.Bool(rc.do("EXISTS", key))
if err != nil {
return false
@ -145,20 +145,20 @@ func (rc *RedisCache) IsExist(key string) bool {
return v
}
// increase counter in redis.
func (rc *RedisCache) Incr(key string) error {
// Incr increase counter in redis.
func (rc *Cache) Incr(key string) error {
_, err := redis.Bool(rc.do("INCRBY", key, 1))
return err
}
// decrease counter in redis.
func (rc *RedisCache) Decr(key string) error {
// Decr decrease counter in redis.
func (rc *Cache) Decr(key string) error {
_, err := redis.Bool(rc.do("INCRBY", key, -1))
return err
}
// clean all cache in redis. delete this redis collection.
func (rc *RedisCache) ClearAll() error {
// ClearAll clean all cache in redis. delete this redis collection.
func (rc *Cache) ClearAll() error {
cachedKeys, err := redis.Strings(rc.do("HKEYS", rc.key))
if err != nil {
return err
@ -172,11 +172,11 @@ func (rc *RedisCache) ClearAll() error {
return err
}
// start redis cache adapter.
// StartAndGC start redis cache adapter.
// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
// the cache item in redis are stored forever,
// so no gc operation.
func (rc *RedisCache) StartAndGC(config string) error {
func (rc *Cache) StartAndGC(config string) error {
var cf map[string]string
json.Unmarshal([]byte(config), &cf)
@ -206,7 +206,7 @@ func (rc *RedisCache) StartAndGC(config string) error {
}
// connect to redis.
func (rc *RedisCache) connectInit() {
func (rc *Cache) connectInit() {
dialFunc := func() (c redis.Conn, err error) {
c, err = redis.Dial("tcp", rc.conninfo)
if err != nil {

239
config.go
View File

@ -29,60 +29,115 @@ import (
)
var (
BeeApp *App // beego application
AppName string
AppPath string
workPath string
AppConfigPath string
StaticDir map[string]string
TemplateCache map[string]*template.Template // template caching map
StaticExtensionsToGzip []string // files with should be compressed with gzip (.js,.css,etc)
EnableHttpListen bool
HttpAddr string
HttpPort int
ListenTCP4 bool
EnableHttpTLS bool
HttpsPort int
HttpCertFile string
HttpKeyFile string
RecoverPanic bool // flag of auto recover panic
AutoRender bool // flag of render template automatically
ViewsPath string
AppConfig *beegoAppConfig
RunMode string // run mode, "dev" or "prod"
GlobalSessions *session.Manager // global session mananger
SessionOn bool // flag of starting session auto. default is false.
SessionProvider string // default session provider, memory, mysql , redis ,etc.
SessionName string // the cookie name when saving session id into cookie.
SessionGCMaxLifetime int64 // session gc time for auto cleaning expired session.
SessionSavePath string // if use mysql/redis/file provider, define save path to connection info.
SessionCookieLifeTime int // the life time of session id in cookie.
SessionAutoSetCookie bool // auto setcookie
SessionDomain string // the cookie domain default is empty
UseFcgi bool
UseStdIo bool
MaxMemory int64
EnableGzip bool // flag of enable gzip
DirectoryIndex bool // flag of display directory index. default is false.
HttpServerTimeOut int64
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.
EnableXSRF bool // flag of enable xsrf.
XSRFExpire int // the expiry of xsrf value.
CopyRequestBody bool // flag of copy raw request body in context.
TemplateLeft string
TemplateRight string
BeegoServerName string // beego server name exported in response header.
EnableAdmin bool // flag of enable admin module to log every request info.
AdminHttpAddr string // http server configurations for admin module.
AdminHttpPort int
FlashName string // name of the flash variable found in response header and cookie
FlashSeperator string // used to seperate flash key:value
AppConfigProvider string // config provider
EnableDocs bool // enable generate docs & server docs API Swagger
RouterCaseSensitive bool // router case sensitive default is true
AccessLogs bool // print access logs, default is false
Graceful bool // use graceful start the server
// AccessLogs represent whether output the access logs, default is false
AccessLogs bool
// AdminHTTPAddr is address for admin
AdminHTTPAddr string
// AdminHTTPPort is listens port for admin
AdminHTTPPort int
// AppConfig is the instance of Config, store the config information from file
AppConfig *beegoAppConfig
// AppName represent Application name, always the project folder name
AppName string
// AppPath is the path to the application
AppPath string
// AppConfigPath is the path to the config files
AppConfigPath string
// AppConfigProvider is the provider for the config, default is ini
AppConfigProvider string
// AutoRender is a flag of render template automatically. It's always turn off in API application
// default is true
AutoRender bool
// BeegoServerName exported in response header.
BeegoServerName string
// CopyRequestBody is just useful for raw request body in context. default is false
CopyRequestBody bool
// DirectoryIndex wheather display directory index. default is false.
DirectoryIndex bool
// EnableAdmin means turn on admin module to log every request info.
EnableAdmin bool
// EnableDocs enable generate docs & server docs API Swagger
EnableDocs bool
// EnableErrorsShow wheather show errors in page. if true, show error and trace info in page rendered with error template.
EnableErrorsShow bool
// EnabelFcgi turn on the fcgi Listen, default is false
EnabelFcgi bool
// EnableGzip means gzip the response
EnableGzip bool
// EnableHTTPListen represent whether turn on the HTTP, default is true
EnableHTTPListen bool
// EnableHTTPTLS represent whether turn on the HTTPS, default is true
EnableHTTPTLS bool
// EnableStdIo works with EnabelFcgi Use FCGI via standard I/O
EnableStdIo bool
// EnableXSRF whether turn on xsrf. default is false
EnableXSRF bool
// FlashName is the name of the flash variable found in response header and cookie
FlashName string
// FlashSeperator used to seperate flash key:value, default is BEEGOFLASH
FlashSeperator string
// GlobalSessions is the instance for the session manager
GlobalSessions *session.Manager
// Graceful means use graceful module to start the server
Graceful bool
// workPath is always the same as AppPath, but sometime when it started with other
// program, like supervisor
workPath string
// ListenTCP4 represent only Listen in TCP4, default is false
ListenTCP4 bool
// MaxMemory The whole request body is parsed and up to a total of maxMemory
// bytes of its file parts are stored in memory, with the remainder stored on disk in temporary files
MaxMemory int64
// HTTPAddr is the TCP network address addr for HTTP
HTTPAddr string
// HTTPPort is listens port for HTTP
HTTPPort int
// HTTPSPort is listens port for HTTPS
HTTPSPort int
// HTTPCertFile is the path to certificate file
HTTPCertFile string
// HTTPKeyFile is the path to private key file
HTTPKeyFile string
// HTTPServerTimeOut HTTP server timeout. default is 0, no timeout
HTTPServerTimeOut int64
// RecoverPanic is a flag for auto recover panic, default is true
RecoverPanic bool
// RouterCaseSensitive means whether router case sensitive, default is true
RouterCaseSensitive bool
// RunMode represent the staging, "dev" or "prod"
RunMode string
// SessionOn means whether turn on the session auto when application started. default is false.
SessionOn bool
// SessionProvider means session provider, e.q memory, mysql, redis,etc.
SessionProvider string
// SessionName is the cookie name when saving session id into cookie.
SessionName string
// SessionGCMaxLifetime for auto cleaning expired session.
SessionGCMaxLifetime int64
// SessionProviderConfig is for the provider config, define save path or connection info.
SessionProviderConfig string
// SessionCookieLifeTime means the life time of session id in cookie.
SessionCookieLifeTime int
// SessionAutoSetCookie auto setcookie
SessionAutoSetCookie bool
// SessionDomain means the cookie domain default is empty
SessionDomain string
// StaticDir store the static path, key is path, value is the folder
StaticDir map[string]string
// StaticExtensionsToGzip stores the extensions which need to gzip(.js,.css,etc)
StaticExtensionsToGzip []string
// TemplateCache store the caching template
TemplateCache map[string]*template.Template
// TemplateLeft left delimiter
TemplateLeft string
// TemplateRight right delimiter
TemplateRight string
// ViewsPath means the template folder
ViewsPath string
// XSRFKEY xsrf hash salt string.
XSRFKEY string
// XSRFExpire is the expiry of xsrf value.
XSRFExpire int
)
type beegoAppConfig struct {
@ -215,9 +270,6 @@ func (b *beegoAppConfig) SaveConfigFile(filename string) error {
}
func init() {
// create beego application
BeeApp = NewApp()
workPath, _ = os.Getwd()
workPath, _ = filepath.Abs(workPath)
// initialize default configurations
@ -243,12 +295,12 @@ func init() {
TemplateCache = make(map[string]*template.Template)
// set this to 0.0.0.0 to make this app available to externally
EnableHttpListen = true //default enable http Listen
EnableHTTPListen = true //default enable http Listen
HttpAddr = ""
HttpPort = 8080
HTTPAddr = ""
HTTPPort = 8080
HttpsPort = 10443
HTTPSPort = 10443
AppName = "beego"
@ -264,20 +316,15 @@ func init() {
SessionProvider = "memory"
SessionName = "beegosessionID"
SessionGCMaxLifetime = 3600
SessionSavePath = ""
SessionProviderConfig = ""
SessionCookieLifeTime = 0 //set cookie default is the brower life
SessionAutoSetCookie = true
UseFcgi = false
UseStdIo = false
MaxMemory = 1 << 26 //64MB
EnableGzip = false
HTTPServerTimeOut = 0
HttpServerTimeOut = 0
ErrorsShow = true
EnableErrorsShow = true
XSRFKEY = "beegoxsrf"
XSRFExpire = 0
@ -288,8 +335,8 @@ func init() {
BeegoServerName = "beegoServer:" + VERSION
EnableAdmin = false
AdminHttpAddr = "127.0.0.1"
AdminHttpPort = 8088
AdminHTTPAddr = "127.0.0.1"
AdminHTTPPort = 8088
FlashName = "BEEGO_FLASH"
FlashSeperator = "BEEGOFLASH"
@ -330,18 +377,18 @@ func ParseConfig() (err error) {
RunMode = runmode
}
HttpAddr = AppConfig.String("HttpAddr")
HTTPAddr = AppConfig.String("HTTPAddr")
if v, err := AppConfig.Int("HttpPort"); err == nil {
HttpPort = v
if v, err := AppConfig.Int("HTTPPort"); err == nil {
HTTPPort = v
}
if v, err := AppConfig.Bool("ListenTCP4"); err == nil {
ListenTCP4 = v
}
if v, err := AppConfig.Bool("EnableHttpListen"); err == nil {
EnableHttpListen = v
if v, err := AppConfig.Bool("EnableHTTPListen"); err == nil {
EnableHTTPListen = v
}
if maxmemory, err := AppConfig.Int64("MaxMemory"); err == nil {
@ -376,8 +423,8 @@ func ParseConfig() (err error) {
SessionName = sessName
}
if sesssavepath := AppConfig.String("SessionSavePath"); sesssavepath != "" {
SessionSavePath = sesssavepath
if sessProvConfig := AppConfig.String("SessionProviderConfig"); sessProvConfig != "" {
SessionProviderConfig = sessProvConfig
}
if sessMaxLifeTime, err := AppConfig.Int64("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 {
@ -388,8 +435,8 @@ func ParseConfig() (err error) {
SessionCookieLifeTime = sesscookielifetime
}
if usefcgi, err := AppConfig.Bool("UseFcgi"); err == nil {
UseFcgi = usefcgi
if enabelFcgi, err := AppConfig.Bool("EnabelFcgi"); err == nil {
EnabelFcgi = enabelFcgi
}
if enablegzip, err := AppConfig.Bool("EnableGzip"); err == nil {
@ -400,12 +447,12 @@ func ParseConfig() (err error) {
DirectoryIndex = directoryindex
}
if timeout, err := AppConfig.Int64("HttpServerTimeOut"); err == nil {
HttpServerTimeOut = timeout
if timeout, err := AppConfig.Int64("HTTPServerTimeOut"); err == nil {
HTTPServerTimeOut = timeout
}
if errorsshow, err := AppConfig.Bool("ErrorsShow"); err == nil {
ErrorsShow = errorsshow
if errorsshow, err := AppConfig.Bool("EnableErrorsShow"); err == nil {
EnableErrorsShow = errorsshow
}
if copyrequestbody, err := AppConfig.Bool("CopyRequestBody"); err == nil {
@ -432,20 +479,20 @@ func ParseConfig() (err error) {
TemplateRight = tplright
}
if httptls, err := AppConfig.Bool("EnableHttpTLS"); err == nil {
EnableHttpTLS = httptls
if httptls, err := AppConfig.Bool("EnableHTTPTLS"); err == nil {
EnableHTTPTLS = httptls
}
if httpsport, err := AppConfig.Int("HttpsPort"); err == nil {
HttpsPort = httpsport
if httpsport, err := AppConfig.Int("HTTPSPort"); err == nil {
HTTPSPort = httpsport
}
if certfile := AppConfig.String("HttpCertFile"); certfile != "" {
HttpCertFile = certfile
if certfile := AppConfig.String("HTTPCertFile"); certfile != "" {
HTTPCertFile = certfile
}
if keyfile := AppConfig.String("HttpKeyFile"); keyfile != "" {
HttpKeyFile = keyfile
if keyfile := AppConfig.String("HTTPKeyFile"); keyfile != "" {
HTTPKeyFile = keyfile
}
if serverName := AppConfig.String("BeegoServerName"); serverName != "" {
@ -495,12 +542,12 @@ func ParseConfig() (err error) {
EnableAdmin = enableadmin
}
if adminhttpaddr := AppConfig.String("AdminHttpAddr"); adminhttpaddr != "" {
AdminHttpAddr = adminhttpaddr
if adminhttpaddr := AppConfig.String("AdminHTTPAddr"); adminhttpaddr != "" {
AdminHTTPAddr = adminhttpaddr
}
if adminhttpport, err := AppConfig.Int("AdminHttpPort"); err == nil {
AdminHttpPort = adminhttpport
if adminhttpport, err := AppConfig.Int("AdminHTTPPort"); err == nil {
AdminHTTPPort = adminhttpport
}
if enabledocs, err := AppConfig.Bool("EnableDocs"); err == nil {

View File

@ -88,12 +88,12 @@ func Register(name string, adapter Config) {
// adapterName is ini/json/xml/yaml.
// filename is the config file path.
func NewConfig(adapterName, fileaname string) (ConfigContainer, error) {
func NewConfig(adapterName, filename string) (ConfigContainer, error) {
adapter, ok := adapters[adapterName]
if !ok {
return nil, fmt.Errorf("config: unknown adaptername %q (forgotten import?)", adapterName)
}
return adapter.Parse(fileaname)
return adapter.Parse(filename)
}
// adapterName is ini/json/xml/yaml.

View File

@ -353,7 +353,7 @@ func (input *BeegoInput) Bind(dest interface{}, key string) error {
}
func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
rv := reflect.Zero(reflect.TypeOf(0))
rv := reflect.Zero(typ)
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
val := input.Query(key)
@ -398,7 +398,7 @@ func (input *BeegoInput) bind(key string, typ reflect.Type) reflect.Value {
}
func (input *BeegoInput) bindValue(val string, typ reflect.Type) reflect.Value {
rv := reflect.Zero(reflect.TypeOf(0))
rv := reflect.Zero(typ)
switch typ.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
rv = input.bindInt(val, typ)

View File

@ -34,18 +34,19 @@ import (
//commonly used mime-types
const (
applicationJson = "application/json"
applicationXml = "application/xml"
textXml = "text/xml"
applicationJSON = "application/json"
applicationXML = "application/xml"
textXML = "text/xml"
)
var (
// custom error when user stop request handler manually.
USERSTOPRUN = errors.New("User stop run")
GlobalControllerRouter map[string][]ControllerComments = make(map[string][]ControllerComments) //pkgpath+controller:comments
// ErrAbort custom error when user stop request handler manually.
ErrAbort = errors.New("User stop run")
// GlobalControllerRouter store comments with controller. pkgpath+controller:comments
GlobalControllerRouter = make(map[string][]ControllerComments)
)
// store the comment for the controller method
// ControllerComments store the comment for the controller method
type ControllerComments struct {
Method string
Router string
@ -64,7 +65,7 @@ type Controller struct {
Layout string
LayoutSections map[string]string // the key is the section name and the value is the template name
TplExt string
_xsrf_token string
_xsrfToken string
gotofunc string
CruSession session.SessionStore
XSRFExpire int
@ -87,8 +88,8 @@ type ControllerInterface interface {
Options()
Finish()
Render() error
XsrfToken() string
CheckXsrfCookie() bool
XSRFToken() string
CheckXSRFCookie() bool
HandlerFunc(fn string) bool
URLMapping()
}
@ -153,20 +154,20 @@ func (c *Controller) Options() {
http.Error(c.Ctx.ResponseWriter, "Method Not Allowed", 405)
}
// call function fn
// HandlerFunc call function with the name
func (c *Controller) HandlerFunc(fnname string) bool {
if v, ok := c.methodMapping[fnname]; ok {
v()
return true
} else {
return false
}
return false
}
// URLMapping register the internal Controller router.
func (c *Controller) URLMapping() {
}
// Mapping the method to function
func (c *Controller) Mapping(method string, fn func()) {
c.methodMapping[method] = fn
}
@ -177,13 +178,11 @@ func (c *Controller) Render() error {
return nil
}
rb, err := c.RenderBytes()
if err != nil {
return err
} else {
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
c.Ctx.Output.Body(rb)
}
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
c.Ctx.Output.Body(rb)
return nil
}
@ -200,8 +199,19 @@ func (c *Controller) RenderBytes() ([]byte, error) {
if c.TplNames == "" {
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
}
if RunMode == "dev" {
BuildTemplate(ViewsPath)
buildFiles := make([]string, 1)
buildFiles = append(buildFiles, c.TplNames)
if c.LayoutSections != nil {
for _, sectionTpl := range c.LayoutSections {
if sectionTpl == "" {
continue
}
buildFiles = append(buildFiles, sectionTpl)
}
}
BuildTemplate(ViewsPath, buildFiles...)
}
newbytes := bytes.NewBufferString("")
if _, ok := BeeTemplates[c.TplNames]; !ok {
@ -241,25 +251,25 @@ func (c *Controller) RenderBytes() ([]byte, error) {
}
icontent, _ := ioutil.ReadAll(ibytes)
return icontent, nil
} else {
if c.TplNames == "" {
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
}
if RunMode == "dev" {
BuildTemplate(ViewsPath)
}
ibytes := bytes.NewBufferString("")
if _, ok := BeeTemplates[c.TplNames]; !ok {
panic("can't find templatefile in the path:" + c.TplNames)
}
err := BeeTemplates[c.TplNames].ExecuteTemplate(ibytes, c.TplNames, c.Data)
if err != nil {
Trace("template Execute err:", err)
return nil, err
}
icontent, _ := ioutil.ReadAll(ibytes)
return icontent, nil
}
if c.TplNames == "" {
c.TplNames = strings.ToLower(c.controllerName) + "/" + strings.ToLower(c.actionName) + "." + c.TplExt
}
if RunMode == "dev" {
BuildTemplate(ViewsPath, c.TplNames)
}
ibytes := bytes.NewBufferString("")
if _, ok := BeeTemplates[c.TplNames]; !ok {
panic("can't find templatefile in the path:" + c.TplNames)
}
err := BeeTemplates[c.TplNames].ExecuteTemplate(ibytes, c.TplNames, c.Data)
if err != nil {
Trace("template Execute err:", err)
return nil, err
}
icontent, _ := ioutil.ReadAll(ibytes)
return icontent, nil
}
// Redirect sends the redirection response to url with status code.
@ -267,7 +277,7 @@ func (c *Controller) Redirect(url string, code int) {
c.Ctx.Redirect(code, url)
}
// Aborts stops controller handler and show the error data if code is defined in ErrorMap or code string.
// Abort stops controller handler and show the error data if code is defined in ErrorMap or code string.
func (c *Controller) Abort(code string) {
status, err := strconv.Atoi(code)
if err != nil {
@ -285,29 +295,28 @@ func (c *Controller) CustomAbort(status int, body string) {
}
// last panic user string
c.Ctx.ResponseWriter.Write([]byte(body))
panic(USERSTOPRUN)
panic(ErrAbort)
}
// StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
func (c *Controller) StopRun() {
panic(USERSTOPRUN)
panic(ErrAbort)
}
// UrlFor does another controller handler in this request function.
// URLFor does another controller handler in this request function.
// it goes to this controller method if endpoint is not clear.
func (c *Controller) UrlFor(endpoint string, values ...interface{}) string {
func (c *Controller) URLFor(endpoint string, values ...interface{}) string {
if len(endpoint) <= 0 {
return ""
}
if endpoint[0] == '.' {
return UrlFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
} else {
return UrlFor(endpoint, values...)
return URLFor(reflect.Indirect(reflect.ValueOf(c.AppController)).Type().Name()+endpoint, values...)
}
return URLFor(endpoint, values...)
}
// ServeJson sends a json response with encoding charset.
func (c *Controller) ServeJson(encoding ...bool) {
// ServeJSON sends a json response with encoding charset.
func (c *Controller) ServeJSON(encoding ...bool) {
var hasIndent bool
var hasencoding bool
if RunMode == "prod" {
@ -321,8 +330,8 @@ func (c *Controller) ServeJson(encoding ...bool) {
c.Ctx.Output.Json(c.Data["json"], hasIndent, hasencoding)
}
// ServeJsonp sends a jsonp response.
func (c *Controller) ServeJsonp() {
// ServeJSONP sends a jsonp response.
func (c *Controller) ServeJSONP() {
var hasIndent bool
if RunMode == "prod" {
hasIndent = false
@ -332,8 +341,8 @@ func (c *Controller) ServeJsonp() {
c.Ctx.Output.Jsonp(c.Data["jsonp"], hasIndent)
}
// ServeXml sends xml response.
func (c *Controller) ServeXml() {
// ServeXML sends xml response.
func (c *Controller) ServeXML() {
var hasIndent bool
if RunMode == "prod" {
hasIndent = false
@ -347,12 +356,12 @@ func (c *Controller) ServeXml() {
func (c *Controller) ServeFormatted() {
accept := c.Ctx.Input.Header("Accept")
switch accept {
case applicationJson:
c.ServeJson()
case applicationXml, textXml:
c.ServeXml()
case applicationJSON:
c.ServeJSON()
case applicationXML, textXML:
c.ServeXML()
default:
c.ServeJson()
c.ServeJSON()
}
}
@ -378,9 +387,8 @@ func (c *Controller) GetString(key string, def ...string) string {
if v := c.Ctx.Input.Query(key); v != "" {
return v
} else {
return defv
}
return defv
}
// GetStrings returns the input string slice by key string or the default value while it's present and input is blank
@ -399,9 +407,8 @@ func (c *Controller) GetStrings(key string, def ...[]string) []string {
vs := f[key]
if len(vs) > 0 {
return vs
} else {
return defv
}
return defv
}
// GetInt returns input as an int or the default value while it's present and input is blank
@ -575,7 +582,7 @@ func (c *Controller) GetSession(name interface{}) interface{} {
return c.CruSession.Get(name)
}
// SetSession removes value from session.
// DelSession removes value from session.
func (c *Controller) DelSession(name interface{}) {
if c.CruSession == nil {
c.StartSession()
@ -614,34 +621,34 @@ func (c *Controller) SetSecureCookie(Secret, name, value string, others ...inter
c.Ctx.SetSecureCookie(Secret, name, value, others...)
}
// XsrfToken creates a xsrf token string and returns.
func (c *Controller) XsrfToken() string {
if c._xsrf_token == "" {
// XSRFToken creates a CSRF token string and returns.
func (c *Controller) XSRFToken() string {
if c._xsrfToken == "" {
var expire int64
if c.XSRFExpire > 0 {
expire = int64(c.XSRFExpire)
} else {
expire = int64(XSRFExpire)
}
c._xsrf_token = c.Ctx.XsrfToken(XSRFKEY, expire)
c._xsrfToken = c.Ctx.XsrfToken(XSRFKEY, expire)
}
return c._xsrf_token
return c._xsrfToken
}
// CheckXsrfCookie checks xsrf token in this request is valid or not.
// CheckXSRFCookie checks xsrf token in this request is valid or not.
// the token can provided in request header "X-Xsrftoken" and "X-CsrfToken"
// or in form field value named as "_xsrf".
func (c *Controller) CheckXsrfCookie() bool {
func (c *Controller) CheckXSRFCookie() bool {
if !c.EnableXSRF {
return true
}
return c.Ctx.CheckXsrfCookie()
}
// XsrfFormHtml writes an input field contains xsrf token value.
func (c *Controller) XsrfFormHtml() string {
// XSRFFormHTML writes an input field contains xsrf token value.
func (c *Controller) XSRFFormHTML() string {
return "<input type=\"hidden\" name=\"_xsrf\" value=\"" +
c._xsrf_token + "\"/>"
c._xsrfToken + "\"/>"
}
// GetControllerAndAction gets the executing controller name and action name.

17
doc.go Normal file
View File

@ -0,0 +1,17 @@
/*
Package beego provide a MVC framework
beego: an open-source, high-performance, modular, full-stack web framework
It is used for rapid development of RESTful APIs, web apps and backend services in Go.
beego is inspired by Tornado, Sinatra and Flask with the added benefit of some Go-specific features such as interfaces and struct embedding.
package main
import "github.com/astaxie/beego"
func main() {
beego.Run()
}
more infomation: http://beego.me
*/
package beego

View File

@ -20,20 +20,21 @@ import (
"github.com/astaxie/beego/context"
)
var GlobalDocApi map[string]interface{}
// GlobalDocAPI store the swagger api documents
var GlobalDocAPI map[string]interface{}
func init() {
if EnableDocs {
GlobalDocApi = make(map[string]interface{})
GlobalDocAPI = make(map[string]interface{})
}
}
func serverDocs(ctx *context.Context) {
var obj interface{}
if splat := ctx.Input.Param(":splat"); splat == "" {
obj = GlobalDocApi["Root"]
obj = GlobalDocAPI["Root"]
} else {
if v, ok := GlobalDocApi[splat]; ok {
if v, ok := GlobalDocAPI[splat]; ok {
obj = v
}
}

View File

@ -358,52 +358,11 @@ func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
t.Execute(rw, data)
}
// register default error http handlers, 404,401,403,500 and 503.
func registerDefaultErrorHandler() {
if _, ok := ErrorMaps["401"]; !ok {
Errorhandler("401", unauthorized)
}
if _, ok := ErrorMaps["402"]; !ok {
Errorhandler("402", paymentRequired)
}
if _, ok := ErrorMaps["403"]; !ok {
Errorhandler("403", forbidden)
}
if _, ok := ErrorMaps["404"]; !ok {
Errorhandler("404", notFound)
}
if _, ok := ErrorMaps["405"]; !ok {
Errorhandler("405", methodNotAllowed)
}
if _, ok := ErrorMaps["500"]; !ok {
Errorhandler("500", internalServerError)
}
if _, ok := ErrorMaps["501"]; !ok {
Errorhandler("501", notImplemented)
}
if _, ok := ErrorMaps["502"]; !ok {
Errorhandler("502", badGateway)
}
if _, ok := ErrorMaps["503"]; !ok {
Errorhandler("503", serviceUnavailable)
}
if _, ok := ErrorMaps["504"]; !ok {
Errorhandler("504", gatewayTimeout)
}
}
// ErrorHandler registers http.HandlerFunc to each http err code string.
// usage:
// beego.ErrorHandler("404",NotFound)
// beego.ErrorHandler("500",InternalServerError)
func Errorhandler(code string, h http.HandlerFunc) *App {
func ErrorHandler(code string, h http.HandlerFunc) *App {
errinfo := &errorInfo{}
errinfo.errorType = errorTypeHandler
errinfo.handler = h
@ -414,7 +373,7 @@ func Errorhandler(code string, h http.HandlerFunc) *App {
// ErrorController registers ControllerInterface to each http err code string.
// usage:
// beego.ErrorHandler(&controllers.ErrorController{})
// beego.ErrorController(&controllers.ErrorController{})
func ErrorController(c ControllerInterface) *App {
reflectVal := reflect.ValueOf(c)
rt := reflectVal.Type()
@ -453,7 +412,6 @@ func exception(errcode string, ctx *context.Context) {
func executeError(err *errorInfo, ctx *context.Context, code int) {
if err.errorType == errorTypeHandler {
ctx.ResponseWriter.WriteHeader(code)
err.handler(ctx.ResponseWriter, ctx.Request)
return
}
@ -473,7 +431,7 @@ func executeError(err *errorInfo, ctx *context.Context, code int) {
execController.URLMapping()
in := make([]reflect.Value, 0)
var in []reflect.Value
method := vc.MethodByName(err.method)
method.Call(in)

View File

@ -54,14 +54,13 @@ func (c *connection) readPump() {
}()
c.ws.SetReadLimit(maxMessageSize)
c.ws.SetReadDeadline(time.Now().Add(readWait))
c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(readWait)); return nil })
for {
op, r, err := c.ws.NextReader()
if err != nil {
break
}
switch op {
case websocket.PongMessage:
c.ws.SetReadDeadline(time.Now().Add(readWait))
case websocket.TextMessage:
message, err := ioutil.ReadAll(r)
if err != nil {

View File

@ -39,7 +39,6 @@ func (f *FilterRouter) ValidRouter(url string) (bool, map[string]string) {
}
if isok, ok := isok.(bool); ok {
return isok, params
} else {
return false, nil
}
return false, nil
}

View File

@ -30,7 +30,7 @@ func (t *TestFlashController) TestWriteFlash() {
flash.Notice("TestFlashString")
flash.Store(&t.Controller)
// we choose to serve json because we don't want to load a template html file
t.ServeJson(true)
t.ServeJSON(true)
}
func TestFlashHeader(t *testing.T) {

View File

@ -32,7 +32,7 @@
// mux := http.NewServeMux()
// mux.HandleFunc("/hello", handler)
//
// err := grace.ListenAndServe("localhost:8080", mux1)
// err := grace.ListenAndServe("localhost:8080", mux)
// if err != nil {
// log.Println(err)
// }

106
hooks.go Normal file
View File

@ -0,0 +1,106 @@
package beego
import (
"mime"
"path/filepath"
"strconv"
"github.com/astaxie/beego/session"
)
//
func registerMime() error {
for k, v := range mimemaps {
mime.AddExtensionType(k, v)
}
return nil
}
// register default error http handlers, 404,401,403,500 and 503.
func registerDefaultErrorHandler() error {
if _, ok := ErrorMaps["401"]; !ok {
ErrorHandler("401", unauthorized)
}
if _, ok := ErrorMaps["402"]; !ok {
ErrorHandler("402", paymentRequired)
}
if _, ok := ErrorMaps["403"]; !ok {
ErrorHandler("403", forbidden)
}
if _, ok := ErrorMaps["404"]; !ok {
ErrorHandler("404", notFound)
}
if _, ok := ErrorMaps["405"]; !ok {
ErrorHandler("405", methodNotAllowed)
}
if _, ok := ErrorMaps["500"]; !ok {
ErrorHandler("500", internalServerError)
}
if _, ok := ErrorMaps["501"]; !ok {
ErrorHandler("501", notImplemented)
}
if _, ok := ErrorMaps["502"]; !ok {
ErrorHandler("502", badGateway)
}
if _, ok := ErrorMaps["503"]; !ok {
ErrorHandler("503", serviceUnavailable)
}
if _, ok := ErrorMaps["504"]; !ok {
ErrorHandler("504", gatewayTimeout)
}
return nil
}
func registerSession() error {
if SessionOn {
var err error
sessionConfig := AppConfig.String("sessionConfig")
if sessionConfig == "" {
sessionConfig = `{"cookieName":"` + SessionName + `",` +
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + filepath.ToSlash(SessionProviderConfig) + `",` +
`"secure":` + strconv.FormatBool(EnableHTTPTLS) + `,` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
}
GlobalSessions, err = session.NewManager(SessionProvider, sessionConfig)
if err != nil {
return err
}
go GlobalSessions.GC()
}
return nil
}
func registerTemplate() error {
if AutoRender {
err := BuildTemplate(ViewsPath)
if err != nil && RunMode == "dev" {
Warn(err)
}
}
return nil
}
func registerDocs() error {
if EnableDocs {
Get("/docs", serverDocs)
Get("/docs/*", serverDocs)
}
return nil
}
func registerAdmin() error {
if EnableAdmin {
go beeAdminApp.Run()
}
return nil
}

View File

@ -74,12 +74,6 @@ 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
}
}
// return *BeegoHttpRequest with specific method
@ -100,7 +94,7 @@ func NewBeegoRequest(rawurl, method string) *BeegoHttpRequest {
return &BeegoHttpRequest{
url: rawurl,
req: &req,
params: map[string]string{},
params: map[string][]string{},
files: map[string]string{},
setting: defaultSetting,
resp: &resp,
@ -150,7 +144,7 @@ type BeegoHttpSettings struct {
type BeegoHttpRequest struct {
url string
req *http.Request
params map[string]string
params map[string][]string
files map[string]string
setting BeegoHttpSettings
resp *http.Response
@ -273,7 +267,11 @@ func (b *BeegoHttpRequest) SetProxy(proxy func(*http.Request) (*url.URL, error))
// Param adds query param in to request.
// params build query string as ?key1=value1&key2=value2...
func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest {
b.params[key] = value
if param, ok := b.params[key]; ok {
b.params[key] = append(param, value)
} else {
b.params[key] = []string{value}
}
return b
}
@ -348,7 +346,9 @@ func (b *BeegoHttpRequest) buildUrl(paramBody string) {
}
}
for k, v := range b.params {
bodyWriter.WriteField(k, v)
for _, vv := range v {
bodyWriter.WriteField(k, vv)
}
}
bodyWriter.Close()
pw.Close()
@ -383,10 +383,12 @@ func (b *BeegoHttpRequest) SendOut() (*http.Response, error) {
if len(b.params) > 0 {
var buf bytes.Buffer
for k, v := range b.params {
buf.WriteString(url.QueryEscape(k))
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(v))
buf.WriteByte('&')
for _, vv := range v {
buf.WriteString(url.QueryEscape(k))
buf.WriteByte('=')
buf.WriteString(url.QueryEscape(vv))
buf.WriteByte('&')
}
}
paramBody = buf.String()
paramBody = paramBody[0 : len(paramBody)-1]

View File

@ -19,6 +19,7 @@ import (
"os"
"strings"
"testing"
"time"
)
func TestResponse(t *testing.T) {
@ -153,6 +154,7 @@ func TestWithSetting(t *testing.T) {
setting.EnableCookie = true
setting.UserAgent = v
setting.Transport = nil
setting.ReadWriteTimeout = 5 * time.Second
SetDefaultSetting(setting)
str, err := Get("http://httpbin.org/get").String()

15
log.go
View File

@ -32,18 +32,18 @@ const (
LevelDebug
)
// SetLogLevel sets the global log level used by the simple
// logger.
// SetLevel sets the global log level used by the simple logger.
func SetLevel(l int) {
BeeLogger.SetLevel(l)
}
// SetLogFuncCall set the CallDepth, default is 3
func SetLogFuncCall(b bool) {
BeeLogger.EnableFuncCallDepth(b)
BeeLogger.SetLogFuncCallDepth(3)
}
// logger references the used application logger.
// BeeLogger references the used application logger.
var BeeLogger *logs.BeeLogger
// SetLogger sets a new logger.
@ -55,10 +55,12 @@ func SetLogger(adaptername string, config string) error {
return nil
}
// Emergency logs a message at emergency level.
func Emergency(v ...interface{}) {
BeeLogger.Emergency(generateFmtStr(len(v)), v...)
}
// Alert logs a message at alert level.
func Alert(v ...interface{}) {
BeeLogger.Alert(generateFmtStr(len(v)), v...)
}
@ -78,21 +80,22 @@ func Warning(v ...interface{}) {
BeeLogger.Warning(generateFmtStr(len(v)), v...)
}
// compatibility alias for Warning()
// Warn compatibility alias for Warning()
func Warn(v ...interface{}) {
BeeLogger.Warn(generateFmtStr(len(v)), v...)
}
// Notice logs a message at notice level.
func Notice(v ...interface{}) {
BeeLogger.Notice(generateFmtStr(len(v)), v...)
}
// Info logs a message at info level.
// Informational logs a message at info level.
func Informational(v ...interface{}) {
BeeLogger.Informational(generateFmtStr(len(v)), v...)
}
// compatibility alias for Warning()
// Info compatibility alias for Warning()
func Info(v ...interface{}) {
BeeLogger.Info(generateFmtStr(len(v)), v...)
}

View File

@ -205,15 +205,20 @@ func (w *FileLogWriter) lines() (int, error) {
}
// DoRotate means it need to write file in new file.
// new file name like xx.log.2013-01-01.2
// new file name like xx.2013-01-01.2.log
func (w *FileLogWriter) DoRotate() error {
_, err := os.Lstat(w.Filename)
if err == nil { // file exists
// Find the next available number
num := 1
fname := ""
suffix := filepath.Ext(w.Filename)
filenameOnly := strings.TrimSuffix(w.Filename, suffix)
if suffix == "" {
suffix = ".log"
}
for ; err == nil && num <= 999; num++ {
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num)
fname = filenameOnly + fmt.Sprintf(".%s.%03d%s", time.Now().Format("2006-01-02"), num, suffix)
_, err = os.Lstat(fname)
}
// return error if the last file checked still existed

View File

@ -103,7 +103,7 @@ func TestFileRotate(t *testing.T) {
log.Critical("critical")
log.Emergency("emergency")
time.Sleep(time.Second * 4)
rotatename := "test3.log" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1)
rotatename := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log"
b, err := exists(rotatename)
if !b || err != nil {
t.Fatal("rotate not generated")

View File

@ -31,9 +31,9 @@ const (
// smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server.
type SmtpWriter struct {
Username string `json:"Username"`
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"Host"`
Host string `json:"host"`
Subject string `json:"subject"`
FromAddress string `json:"fromAddress"`
RecipientAddresses []string `json:"sendTos"`

View File

@ -28,8 +28,10 @@ import (
"time"
)
var gmfim map[string]*memFileInfo = make(map[string]*memFileInfo)
var lock sync.RWMutex
var (
gmfim = make(map[string]*memFileInfo)
lock sync.RWMutex
)
// OpenMemZipFile returns MemFile object with a compressed static file.
// it's used for serve static file if gzip enable.

13
mime.go
View File

@ -14,11 +14,7 @@
package beego
import (
"mime"
)
var mimemaps map[string]string = map[string]string{
var mimemaps = map[string]string{
".3dm": "x-world/x-3dmf",
".3dmf": "x-world/x-3dmf",
".7z": "application/x-7z-compressed",
@ -558,10 +554,3 @@ var mimemaps map[string]string = map[string]string{
".oex": "application/x-opera-extension",
".mustache": "text/html",
}
func initMime() error {
for k, v := range mimemaps {
mime.AddExtensionType(k, v)
}
return nil
}

View File

@ -23,16 +23,17 @@ import (
type namespaceCond func(*beecontext.Context) bool
type innnerNamespace func(*Namespace)
// LinkNamespace used as link action
type LinkNamespace func(*Namespace)
// Namespace is store all the info
type Namespace struct {
prefix string
handlers *ControllerRegistor
handlers *ControllerRegister
}
// get new Namespace
func NewNamespace(prefix string, params ...innnerNamespace) *Namespace {
// NewNamespace get new Namespace
func NewNamespace(prefix string, params ...LinkNamespace) *Namespace {
ns := &Namespace{
prefix: prefix,
handlers: NewControllerRegister(),
@ -43,7 +44,7 @@ func NewNamespace(prefix string, params ...innnerNamespace) *Namespace {
return ns
}
// set condtion function
// Cond set condtion function
// if cond return true can run this namespace, else can't
// usage:
// ns.Cond(func (ctx *context.Context) bool{
@ -72,7 +73,7 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace {
return n
}
// add filter in the Namespace
// Filter add filter in the Namespace
// action has before & after
// FilterFunc
// usage:
@ -95,98 +96,98 @@ func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
return n
}
// same as beego.Rourer
// Router same as beego.Rourer
// refer: https://godoc.org/github.com/astaxie/beego#Router
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
n.handlers.Add(rootpath, c, mappingMethods...)
return n
}
// same as beego.AutoRouter
// AutoRouter same as beego.AutoRouter
// refer: https://godoc.org/github.com/astaxie/beego#AutoRouter
func (n *Namespace) AutoRouter(c ControllerInterface) *Namespace {
n.handlers.AddAuto(c)
return n
}
// same as beego.AutoPrefix
// AutoPrefix same as beego.AutoPrefix
// refer: https://godoc.org/github.com/astaxie/beego#AutoPrefix
func (n *Namespace) AutoPrefix(prefix string, c ControllerInterface) *Namespace {
n.handlers.AddAutoPrefix(prefix, c)
return n
}
// same as beego.Get
// Get same as beego.Get
// refer: https://godoc.org/github.com/astaxie/beego#Get
func (n *Namespace) Get(rootpath string, f FilterFunc) *Namespace {
n.handlers.Get(rootpath, f)
return n
}
// same as beego.Post
// Post same as beego.Post
// refer: https://godoc.org/github.com/astaxie/beego#Post
func (n *Namespace) Post(rootpath string, f FilterFunc) *Namespace {
n.handlers.Post(rootpath, f)
return n
}
// same as beego.Delete
// Delete same as beego.Delete
// refer: https://godoc.org/github.com/astaxie/beego#Delete
func (n *Namespace) Delete(rootpath string, f FilterFunc) *Namespace {
n.handlers.Delete(rootpath, f)
return n
}
// same as beego.Put
// Put same as beego.Put
// refer: https://godoc.org/github.com/astaxie/beego#Put
func (n *Namespace) Put(rootpath string, f FilterFunc) *Namespace {
n.handlers.Put(rootpath, f)
return n
}
// same as beego.Head
// Head same as beego.Head
// refer: https://godoc.org/github.com/astaxie/beego#Head
func (n *Namespace) Head(rootpath string, f FilterFunc) *Namespace {
n.handlers.Head(rootpath, f)
return n
}
// same as beego.Options
// Options same as beego.Options
// refer: https://godoc.org/github.com/astaxie/beego#Options
func (n *Namespace) Options(rootpath string, f FilterFunc) *Namespace {
n.handlers.Options(rootpath, f)
return n
}
// same as beego.Patch
// Patch same as beego.Patch
// refer: https://godoc.org/github.com/astaxie/beego#Patch
func (n *Namespace) Patch(rootpath string, f FilterFunc) *Namespace {
n.handlers.Patch(rootpath, f)
return n
}
// same as beego.Any
// Any same as beego.Any
// refer: https://godoc.org/github.com/astaxie/beego#Any
func (n *Namespace) Any(rootpath string, f FilterFunc) *Namespace {
n.handlers.Any(rootpath, f)
return n
}
// same as beego.Handler
// Handler same as beego.Handler
// refer: https://godoc.org/github.com/astaxie/beego#Handler
func (n *Namespace) Handler(rootpath string, h http.Handler) *Namespace {
n.handlers.Handler(rootpath, h)
return n
}
// add include class
// Include add include class
// refer: https://godoc.org/github.com/astaxie/beego#Include
func (n *Namespace) Include(cList ...ControllerInterface) *Namespace {
n.handlers.Include(cList...)
return n
}
// nest Namespace
// Namespace add nest Namespace
// usage:
//ns := beego.NewNamespace(“/v1”).
//Namespace(
@ -230,7 +231,7 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace {
return n
}
// register Namespace into beego.Handler
// AddNamespace register Namespace into beego.Handler
// support multi Namespace
func AddNamespace(nl ...*Namespace) {
for _, n := range nl {
@ -275,113 +276,113 @@ func addPrefix(t *Tree, prefix string) {
}
// Namespace Condition
func NSCond(cond namespaceCond) innnerNamespace {
// NSCond is Namespace Condition
func NSCond(cond namespaceCond) LinkNamespace {
return func(ns *Namespace) {
ns.Cond(cond)
}
}
// Namespace BeforeRouter filter
func NSBefore(filiterList ...FilterFunc) innnerNamespace {
// NSBefore Namespace BeforeRouter filter
func NSBefore(filiterList ...FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Filter("before", filiterList...)
}
}
// Namespace FinishRouter filter
func NSAfter(filiterList ...FilterFunc) innnerNamespace {
// NSAfter add Namespace FinishRouter filter
func NSAfter(filiterList ...FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Filter("after", filiterList...)
}
}
// Namespace Include ControllerInterface
func NSInclude(cList ...ControllerInterface) innnerNamespace {
// NSInclude Namespace Include ControllerInterface
func NSInclude(cList ...ControllerInterface) LinkNamespace {
return func(ns *Namespace) {
ns.Include(cList...)
}
}
// Namespace Router
func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) innnerNamespace {
// NSRouter call Namespace Router
func NSRouter(rootpath string, c ControllerInterface, mappingMethods ...string) LinkNamespace {
return func(ns *Namespace) {
ns.Router(rootpath, c, mappingMethods...)
}
}
// Namespace Get
func NSGet(rootpath string, f FilterFunc) innnerNamespace {
// NSGet call Namespace Get
func NSGet(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Get(rootpath, f)
}
}
// Namespace Post
func NSPost(rootpath string, f FilterFunc) innnerNamespace {
// NSPost call Namespace Post
func NSPost(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Post(rootpath, f)
}
}
// Namespace Head
func NSHead(rootpath string, f FilterFunc) innnerNamespace {
// NSHead call Namespace Head
func NSHead(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Head(rootpath, f)
}
}
// Namespace Put
func NSPut(rootpath string, f FilterFunc) innnerNamespace {
// NSPut call Namespace Put
func NSPut(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Put(rootpath, f)
}
}
// Namespace Delete
func NSDelete(rootpath string, f FilterFunc) innnerNamespace {
// NSDelete call Namespace Delete
func NSDelete(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Delete(rootpath, f)
}
}
// Namespace Any
func NSAny(rootpath string, f FilterFunc) innnerNamespace {
// NSAny call Namespace Any
func NSAny(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Any(rootpath, f)
}
}
// Namespace Options
func NSOptions(rootpath string, f FilterFunc) innnerNamespace {
// NSOptions call Namespace Options
func NSOptions(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Options(rootpath, f)
}
}
// Namespace Patch
func NSPatch(rootpath string, f FilterFunc) innnerNamespace {
// NSPatch call Namespace Patch
func NSPatch(rootpath string, f FilterFunc) LinkNamespace {
return func(ns *Namespace) {
ns.Patch(rootpath, f)
}
}
//Namespace AutoRouter
func NSAutoRouter(c ControllerInterface) innnerNamespace {
// NSAutoRouter call Namespace AutoRouter
func NSAutoRouter(c ControllerInterface) LinkNamespace {
return func(ns *Namespace) {
ns.AutoRouter(c)
}
}
// Namespace AutoPrefix
func NSAutoPrefix(prefix string, c ControllerInterface) innnerNamespace {
// NSAutoPrefix call Namespace AutoPrefix
func NSAutoPrefix(prefix string, c ControllerInterface) LinkNamespace {
return func(ns *Namespace) {
ns.AutoPrefix(prefix, c)
}
}
// Namespace add sub Namespace
func NSNamespace(prefix string, params ...innnerNamespace) innnerNamespace {
// NSNamespace add sub Namespace
func NSNamespace(prefix string, params ...LinkNamespace) LinkNamespace {
return func(ns *Namespace) {
n := NewNamespace(prefix, params...)
ns.Namespace(n)

View File

@ -802,6 +802,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
tables.parseRelated(qs.related, qs.relDepth)
where, args := tables.getCondSql(cond, false, tz)
groupBy := tables.getGroupSql(qs.groups)
orderBy := tables.getOrderSql(qs.orders)
limit := tables.getLimitSql(mi, offset, rlimit)
join := tables.getJoinSql()
@ -814,7 +815,11 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
}
}
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit)
sqlSelect := "SELECT"
if qs.distinct {
sqlSelect += " DISTINCT"
}
query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s", sqlSelect, sels, Q, mi.table, Q, join, where, groupBy, orderBy, limit)
d.ins.ReplaceMarks(&query)
@ -1444,13 +1449,14 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond
}
where, args := tables.getCondSql(cond, false, tz)
groupBy := tables.getGroupSql(qs.groups)
orderBy := tables.getOrderSql(qs.orders)
limit := tables.getLimitSql(mi, qs.offset, qs.limit)
join := tables.getJoinSql()
sels := strings.Join(cols, ", ")
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s", sels, Q, mi.table, Q, join, where, orderBy, limit)
query := fmt.Sprintf("SELECT %s FROM %s%s%s T0 %s%s%s%s%s", sels, Q, mi.table, Q, join, where, groupBy,orderBy, limit)
d.ins.ReplaceMarks(&query)

View File

@ -390,6 +390,30 @@ func (t *dbTables) getCondSql(cond *Condition, sub bool, tz *time.Location) (whe
return
}
// generate group sql.
func (t *dbTables) getGroupSql(groups []string) (groupSql string) {
if len(groups) == 0 {
return
}
Q := t.base.TableQuote()
groupSqls := make([]string, 0, len(groups))
for _, group := range groups {
exprs := strings.Split(group, ExprSep)
index, _, fi, suc := t.parseExprs(t.mi, exprs)
if suc == false {
panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep)))
}
groupSqls = append(groupSqls, fmt.Sprintf("%s.%s%s%s", index, Q, fi.column, Q))
}
groupSql = fmt.Sprintf("GROUP BY %s ", strings.Join(groupSqls, ", "))
return
}
// generate order sql.
func (t *dbTables) getOrderSql(orders []string) (orderSql string) {
if len(orders) == 0 {

View File

@ -60,7 +60,9 @@ type querySet struct {
relDepth int
limit int64
offset int64
groups []string
orders []string
distinct bool
orm *orm
}
@ -105,6 +107,12 @@ func (o querySet) Offset(offset interface{}) QuerySeter {
return &o
}
// add GROUP expression
func (o querySet) GroupBy(exprs ...string) QuerySeter {
o.groups = exprs
return &o
}
// add ORDER expression.
// "column" means ASC, "-column" means DESC.
func (o querySet) OrderBy(exprs ...string) QuerySeter {
@ -112,6 +120,12 @@ func (o querySet) OrderBy(exprs ...string) QuerySeter {
return &o
}
// add DISTINCT to SELECT
func (o querySet) Distinct() QuerySeter {
o.distinct = true
return &o
}
// set relation model to query together.
// it will query relation models and assign to parent model.
func (o querySet) RelatedSel(params ...interface{}) QuerySeter {

View File

@ -66,7 +66,9 @@ type QuerySeter interface {
SetCond(*Condition) QuerySeter
Limit(interface{}, ...interface{}) QuerySeter
Offset(interface{}) QuerySeter
GroupBy(...string) QuerySeter
OrderBy(...string) QuerySeter
Distinct() QuerySeter
RelatedSel(...interface{}) QuerySeter
Count() (int64, error)
Exist() bool

View File

@ -42,13 +42,13 @@ func init() {
`
var (
lastupdateFilename string = "lastupdate.tmp"
lastupdateFilename = "lastupdate.tmp"
commentFilename string
pkgLastupdate map[string]int64
genInfoList map[string][]ControllerComments
)
const COMMENTFL = "commentsRouter_"
const coomentPrefix = "commentsRouter_"
func init() {
pkgLastupdate = make(map[string]int64)
@ -56,7 +56,7 @@ func init() {
func parserPkg(pkgRealpath, pkgpath string) error {
rep := strings.NewReplacer("/", "_", ".", "_")
commentFilename = COMMENTFL + rep.Replace(pkgpath) + ".go"
commentFilename = coomentPrefix + rep.Replace(pkgpath) + ".go"
if !compareFile(pkgRealpath) {
Info(pkgRealpath + " has not changed, not reloading")
return nil
@ -132,9 +132,11 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
func genRouterCode() {
os.Mkdir(path.Join(workPath, "routers"), 0755)
Info("generate router from comments")
var globalinfo string
sortKey := make([]string, 0)
for k, _ := range genInfoList {
var (
globalinfo string
sortKey []string
)
for k := range genInfoList {
sortKey = append(sortKey, k)
}
sort.Strings(sortKey)

View File

@ -83,41 +83,41 @@ func APIBaiscAuth(appid, appkey string) beego.FilterFunc {
func APIAuthWithFunc(f AppIdToAppSecret, timeout int) beego.FilterFunc {
return func(ctx *context.Context) {
if ctx.Input.Query("appid") == "" {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: appid")
return
}
appsecret := f(ctx.Input.Query("appid"))
if appsecret == "" {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("not exist this appid")
return
}
if ctx.Input.Query("signature") == "" {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: signature")
return
}
if ctx.Input.Query("timestamp") == "" {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("miss query param: timestamp")
return
}
u, err := time.Parse("2006-01-02 15:04:05", ctx.Input.Query("timestamp"))
if err != nil {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("timestamp format is error, should 2006-01-02 15:04:05")
return
}
t := time.Now()
if t.Sub(u).Seconds() > float64(timeout) {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("timeout! the request time is long ago, please try again")
return
}
if ctx.Input.Query("signature") !=
Signature(appsecret, ctx.Input.Method(), ctx.Request.Form, ctx.Input.Uri()) {
ctx.Output.SetStatus(403)
ctx.ResponseWriter.WriteHeader(403)
ctx.WriteString("auth failed")
}
}

View File

@ -24,7 +24,7 @@
// // - PUT and PATCH methods
// // - Origin header
// // - Credentials share
// beego.InsertFilter("*", beego.BeforeRouter,cors.Allow(&cors.Options{
// beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{
// AllowOrigins: []string{"https://*.foo.com"},
// AllowMethods: []string{"PUT", "PATCH"},
// AllowHeaders: []string{"Origin"},
@ -36,7 +36,6 @@
package cors
import (
"net/http"
"regexp"
"strconv"
"strings"
@ -216,8 +215,6 @@ func Allow(opts *Options) beego.FilterFunc {
for key, value := range headers {
ctx.Output.Header(key, value)
}
ctx.Output.SetStatus(http.StatusOK)
ctx.WriteString("")
return
}
headers = opts.Header(origin)

135
plugins/jwt/jwt.go Normal file
View File

@ -0,0 +1,135 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package jwt provides JWT (Json Web Token) authentication
//
// Usage
// In file main.go
//
// import (
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/jwt"
// )
//
// func main() {
// // JWT for Url matching /v1/*
// // PrivateKeyPath: The path for the private RSA key used by JWT
// // PublicKeyPath: The path for the public RSA key used by JWT
// // The list of Urls should be excluded from the JWT Auth
// beego.InsertFilter("/v1/*", beego.BeforeRouter, jwt.AuthRequest(&jwt.Options{
// PrivateKeyPath: "conf/beeblog.rsa",
// PublicKeyPath: "conf/beeblog.rsa.pub",
// WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
// }))
// beego.Run()
// }
//
// In file routers/router.go
//
// import (
// "github.com/astaxie/beego"
// "github.com/astaxie/beego/plugins/jwt"
// )
// func init() {
// ns := beego.NSNamespace("/jwt",
// beego.NSInclude(
// &jwt.JwtController{},
// ),
// )
// beego.AddNamespace(ns)
// }
//
package jwt
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/logs"
goJwt "github.com/dgrijalva/jwt-go"
"io/ioutil"
"net/http"
"time"
)
// Options for the JWT Auth
type Options struct {
PrivateKeyPath string
PublicKeyPath string
WhiteList []string
}
var RSAKeys struct {
PrivateKey []byte
PublicKey []byte
}
func AuthRequest(o *Options) beego.FilterFunc {
RSAKeys.PrivateKey, _ = ioutil.ReadFile(o.PrivateKeyPath)
RSAKeys.PublicKey, _ = ioutil.ReadFile(o.PublicKeyPath)
return func(ctx *context.Context) {
// :TODO the url patterns should be considered here.
// Shouldn't only use the string equal
for _, method := range o.WhiteList {
if method == ctx.Request.URL.Path {
return
}
}
parsedToken, err := goJwt.ParseFromRequest(ctx.Request, func(t *goJwt.Token) (interface{}, error) {
return RSAKeys.PublicKey, nil
})
if err == nil && parsedToken.Valid {
ctx.Output.SetStatus(http.StatusOK)
} else {
ctx.Output.SetStatus(http.StatusUnauthorized)
}
}
}
// oprations for Jwt
type JwtController struct {
beego.Controller
}
func (this *JwtController) URLMapping() {
this.Mapping("IssueToken", this.IssueToken)
}
// @Title IssueToken
// @Description Issue a Json Web Token
// @Success 200 string
// @Failure 403 no privilege to access
// @Failure 500 server inner error
// @router /issue-token [get]
func (this *JwtController) IssueToken() {
this.Data["json"] = CreateToken()
this.ServeJson()
}
func CreateToken() map[string]string {
log := logs.NewLogger(10000)
log.SetLogger("console", "")
token := goJwt.New(goJwt.GetSigningMethod("RS256")) // Create a Token that will be signed with RSA 256.
token.Claims["ID"] = "This is my super fake ID"
token.Claims["exp"] = time.Now().Unix() + 36000
// The claims object allows you to store information in the actual token.
tokenString, _ := token.SignedString(RSAKeys.PrivateKey)
// tokenString Contains the actual token you should share with your client.
return map[string]string{"token": tokenString}
}

88
plugins/jwt/jwt_test.go Normal file
View File

@ -0,0 +1,88 @@
package jwt
import (
"github.com/astaxie/beego"
"net/http"
"net/http/httptest"
"testing"
)
func testRequest(method, path string) (*httptest.ResponseRecorder, *http.Request) {
request, _ := http.NewRequest(method, path, nil)
recorder := httptest.NewRecorder()
return recorder, request
}
func Test_IssueTokenAction(t *testing.T) {
url := "/v1/jwt/issue-token"
mux := beego.NewControllerRegister()
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
PrivateKeyPath: "test/jwt.rsa",
PublicKeyPath: "test/jwt.rsa.pub",
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
}))
mux.Add("/v1/jwt/issue-token", &JwtController{}, "get:IssueToken")
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if rw.Code != http.StatusOK {
t.Errorf("Shoud return 200")
}
}
func (tc *JwtController) Foo() {
tc.Ctx.Output.Body([]byte("ok"))
}
func Test_AuthRequestWithAuthorizationHeader(t *testing.T) {
url := "/foo"
mux := beego.NewControllerRegister()
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
PrivateKeyPath: "test/jwt.rsa",
PublicKeyPath: "test/jwt.rsa.pub",
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
}))
mux.Add("/foo", &JwtController{}, "get:Foo")
newToken := CreateToken()
rw, r := testRequest("GET", url)
r.Header.Add("Authorization", "Bearer "+newToken["token"])
mux.ServeHTTP(rw, r)
if rw.Code != http.StatusOK {
t.Errorf("Shoud return 200")
}
if rw.Body.String() != "ok" {
t.Errorf("Should output ok")
}
}
func Test_AuthRequestWithoutAuthorizationHeader(t *testing.T) {
url := "/foo"
mux := beego.NewControllerRegister()
mux.InsertFilter("*", beego.BeforeRouter, AuthRequest(&Options{
PrivateKeyPath: "test/jwt.rsa",
PublicKeyPath: "test/jwt.rsa.pub",
WhiteList: []string{"/v1/jwt/issue-token", "/docs"},
}))
mux.Add("/foo", &JwtController{}, "get:Foo")
rw, r := testRequest("GET", url)
mux.ServeHTTP(rw, r)
if rw.Code != http.StatusUnauthorized {
t.Errorf("Shoud return 401")
}
}

15
plugins/jwt/test/jwt.rsa Normal file
View File

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCdu+23Y/0J/FTQKnIPnxupoOo9/OYCv90DPXN/KLLRAMjYzgcC
DsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDhbaGWuTdQUX9zmiLoQ4I7X6h0
dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/tB3PVRG9j6B1Ibz5CnQIDAQAB
AoGAFGg+/i4ai9MwqeoD7c95Bb5C8BgrLgnir0uhCL+cOvwuABbPw01jRoLuEi58
Mp5vzaXLXByFSA+ts03/qMbvZkDGac5g5kLli5TjHIONMxVBrdfGQ1+OApnaPayN
N+HYjZKs6xao6J5iFqfA0FqzDR9kQhUoeosdQoo1GlxDckECQQDO/0LJrFiLzYWe
qS/DxfAnFu2BlClKZjxRJ3vIkRRaON6HPl8BeJW901bFKG5+WSfO+OwQ9egWaf3X
fFm/oEHRAkEAwxMor4fOkBZbL4KPW7sen169vwnXuYusqj0t3dIeiIVrCigkOMT4
OvX/63u4CTdXh1D5u/4Z/1HTYH92VCP7DQJAJPxbNKnE0IYSf/z++d4eQP3JxkNw
9Ug7Msz5QycZGd3bdRLh6uNe7iIa+PN2esD3afX0SDuIEqkxoBUp/CFoYQJAUmi3
mV+/7bLkFrALK+9iwmTdt+TKk4HkEY8C32CysW3biFDo7GqZix79XFfJqWsNuQaG
WdrA1NGWgH+YV3dTyQJAIWEZGAuUXRkQB20LfjGzpsKgQFbqjTisMS0qe3JjnDwu
0JR8sYXapgeEEEisH+OtkZKIfyeFOwoUyNC83bcvgw==
-----END RSA PRIVATE KEY-----

View File

@ -0,0 +1,6 @@
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdu+23Y/0J/FTQKnIPnxupoOo9
/OYCv90DPXN/KLLRAMjYzgcCDsBST2xVR5jlimI/gyfCpVB62dwpSzzr0cA3MoDh
baGWuTdQUX9zmiLoQ4I7X6h0dwyiihOz+CzOMlAg5+qBhiTGcKvIFlfEc1FUcn/t
B3PVRG9j6B1Ibz5CnQIDAQAB
-----END PUBLIC KEY-----

206
router.go
View File

@ -34,8 +34,8 @@ import (
"github.com/astaxie/beego/utils"
)
// default filter execution points
const (
// default filter execution points
BeforeStatic = iota
BeforeRouter
BeforeExec
@ -50,7 +50,7 @@ const (
)
var (
// supported http methods.
// HTTPMETHOD list the supported http methods.
HTTPMETHOD = map[string]string{
"GET": "GET",
"POST": "POST",
@ -71,10 +71,12 @@ var (
"SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml",
"GetControllerAndAction"}
url_placeholder = "{{placeholder}}"
DefaultLogFilter FilterHandler = &logFilter{}
urlPlaceholder = "{{placeholder}}"
// DefaultAccessLogFilter will skip the accesslog if return true
DefaultAccessLogFilter FilterHandler = &logFilter{}
)
// FilterHandler is an interface for
type FilterHandler interface {
Filter(*beecontext.Context) bool
}
@ -96,7 +98,7 @@ func (l *logFilter) Filter(ctx *beecontext.Context) bool {
return false
}
// To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter
// ExceptMethodAppend to append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter
func ExceptMethodAppend(action string) {
exceptMethod = append(exceptMethod, action)
}
@ -110,22 +112,22 @@ type controllerInfo struct {
routerType int
}
// ControllerRegistor containers registered router rules, controller handlers and filters.
type ControllerRegistor struct {
// ControllerRegister containers registered router rules, controller handlers and filters.
type ControllerRegister struct {
routers map[string]*Tree
enableFilter bool
filters map[int][]*FilterRouter
}
// NewControllerRegister returns a new ControllerRegistor.
func NewControllerRegister() *ControllerRegistor {
return &ControllerRegistor{
// NewControllerRegister returns a new ControllerRegister.
func NewControllerRegister() *ControllerRegister {
return &ControllerRegister{
routers: make(map[string]*Tree),
filters: make(map[int][]*FilterRouter),
}
}
// Add controller handler and pattern rules to ControllerRegistor.
// Add controller handler and pattern rules to ControllerRegister.
// usage:
// default methods is the same name as method
// Add("/user",&UserController{})
@ -135,7 +137,7 @@ func NewControllerRegister() *ControllerRegistor {
// Add("/api/delete",&RestController{},"delete:DeleteFood")
// Add("/api",&RestController{},"get,post:ApiFunc")
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
reflectVal := reflect.ValueOf(c)
t := reflect.Indirect(reflectVal).Type()
methods := make(map[string]string)
@ -183,7 +185,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
}
}
func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerInfo) {
func (p *ControllerRegister) addToRouter(method, pattern string, r *controllerInfo) {
if !RouterCaseSensitive {
pattern = strings.ToLower(pattern)
}
@ -196,9 +198,9 @@ func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerIn
}
}
// only when the Runmode is dev will generate router file in the router/auto.go from the controller
// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller
// Include(&BankAccount{}, &OrderController{},&RefundController{},&ReceiptController{})
func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
func (p *ControllerRegister) Include(cList ...ControllerInterface) {
if RunMode == "dev" {
skip := make(map[string]bool, 10)
for _, c := range cList {
@ -238,84 +240,84 @@ func (p *ControllerRegistor) Include(cList ...ControllerInterface) {
}
}
// add get method
// Get add get method
// usage:
// Get("/", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Get(pattern string, f FilterFunc) {
func (p *ControllerRegister) Get(pattern string, f FilterFunc) {
p.AddMethod("get", pattern, f)
}
// add post method
// Post add post method
// usage:
// Post("/api", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Post(pattern string, f FilterFunc) {
func (p *ControllerRegister) Post(pattern string, f FilterFunc) {
p.AddMethod("post", pattern, f)
}
// add put method
// Put add put method
// usage:
// Put("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Put(pattern string, f FilterFunc) {
func (p *ControllerRegister) Put(pattern string, f FilterFunc) {
p.AddMethod("put", pattern, f)
}
// add delete method
// Delete add delete method
// usage:
// Delete("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Delete(pattern string, f FilterFunc) {
func (p *ControllerRegister) Delete(pattern string, f FilterFunc) {
p.AddMethod("delete", pattern, f)
}
// add head method
// Head add head method
// usage:
// Head("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Head(pattern string, f FilterFunc) {
func (p *ControllerRegister) Head(pattern string, f FilterFunc) {
p.AddMethod("head", pattern, f)
}
// add patch method
// Patch add patch method
// usage:
// Patch("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Patch(pattern string, f FilterFunc) {
func (p *ControllerRegister) Patch(pattern string, f FilterFunc) {
p.AddMethod("patch", pattern, f)
}
// add options method
// Options add options method
// usage:
// Options("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Options(pattern string, f FilterFunc) {
func (p *ControllerRegister) Options(pattern string, f FilterFunc) {
p.AddMethod("options", pattern, f)
}
// add all method
// Any add all method
// usage:
// Any("/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) Any(pattern string, f FilterFunc) {
func (p *ControllerRegister) Any(pattern string, f FilterFunc) {
p.AddMethod("*", pattern, f)
}
// add http method router
// AddMethod add http method router
// usage:
// AddMethod("get","/api/:id", func(ctx *context.Context){
// ctx.Output.Body("hello world")
// })
func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) {
if _, ok := HTTPMETHOD[strings.ToUpper(method)]; method != "*" && !ok {
panic("not support http method: " + method)
}
@ -343,8 +345,8 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
}
}
// add user defined Handler
func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...interface{}) {
// Handler add user defined Handler
func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...interface{}) {
route := &controllerInfo{}
route.pattern = pattern
route.routerType = routerTypeHandler
@ -359,21 +361,21 @@ func (p *ControllerRegistor) Handler(pattern string, h http.Handler, options ...
}
}
// Add auto router to ControllerRegistor.
// AddAuto router to ControllerRegister.
// example beego.AddAuto(&MainContorlller{}),
// MainController has method List and Page.
// visit the url /main/list to execute List function
// /main/page to execute Page function.
func (p *ControllerRegistor) AddAuto(c ControllerInterface) {
func (p *ControllerRegister) AddAuto(c ControllerInterface) {
p.AddAutoPrefix("/", c)
}
// Add auto router to ControllerRegistor with prefix.
// AddAutoPrefix Add auto router to ControllerRegister with prefix.
// example beego.AddAutoPrefix("/admin",&MainContorlller{}),
// MainController has method List and Page.
// visit the url /admin/main/list to execute List function
// /admin/main/page to execute Page function.
func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface) {
func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) {
reflectVal := reflect.ValueOf(c)
rt := reflectVal.Type()
ct := reflect.Indirect(reflectVal).Type()
@ -399,9 +401,9 @@ func (p *ControllerRegistor) AddAutoPrefix(prefix string, c ControllerInterface)
}
}
// Add a FilterFunc with pattern rule and action constant.
// InsertFilter Add a FilterFunc with pattern rule and action constant.
// The bool params is for setting the returnOnOutput value (false allows multiple filters to execute)
func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error {
func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error {
mr := new(FilterRouter)
mr.tree = NewTree()
@ -420,15 +422,15 @@ func (p *ControllerRegistor) InsertFilter(pattern string, pos int, filter Filter
}
// add Filter into
func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error {
func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error {
p.filters[pos] = append(p.filters[pos], mr)
p.enableFilter = true
return nil
}
// UrlFor does another controller handler in this request function.
// URLFor does another controller handler in this request function.
// it can access any controller method.
func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) string {
func (p *ControllerRegister) URLFor(endpoint string, values ...interface{}) string {
paths := strings.Split(endpoint, ".")
if len(paths) <= 1 {
Warn("urlfor endpoint must like path.controller.method")
@ -460,7 +462,7 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) stri
return ""
}
func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) {
func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) {
for k, subtree := range t.fixrouters {
u := path.Join(url, k)
ok, u := p.geturl(subtree, u, controllName, methodName, params, httpMethod)
@ -469,7 +471,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
}
}
if t.wildcard != nil {
u := path.Join(url, url_placeholder)
u := path.Join(url, urlPlaceholder)
ok, u := p.geturl(t.wildcard, u, controllName, methodName, params, httpMethod)
if ok {
return ok, u
@ -499,22 +501,21 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
if find {
if l.regexps == nil {
if len(l.wildcards) == 0 {
return true, strings.Replace(url, "/"+url_placeholder, "", 1) + tourl(params)
return true, strings.Replace(url, "/"+urlPlaceholder, "", 1) + tourl(params)
}
if len(l.wildcards) == 1 {
if v, ok := params[l.wildcards[0]]; ok {
delete(params, l.wildcards[0])
return true, strings.Replace(url, url_placeholder, v, 1) + tourl(params)
} else {
return false, ""
return true, strings.Replace(url, urlPlaceholder, v, 1) + tourl(params)
}
return false, ""
}
if len(l.wildcards) == 3 && l.wildcards[0] == "." {
if p, ok := params[":path"]; ok {
if e, isok := params[":ext"]; isok {
delete(params, ":path")
delete(params, ":ext")
return true, strings.Replace(url, url_placeholder, p+"."+e, -1) + tourl(params)
return true, strings.Replace(url, urlPlaceholder, p+"."+e, -1) + tourl(params)
}
}
}
@ -526,45 +527,43 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
}
if u, ok := params[v]; ok {
delete(params, v)
url = strings.Replace(url, url_placeholder, u, 1)
url = strings.Replace(url, urlPlaceholder, u, 1)
} else {
if canskip {
canskip = false
continue
} else {
return false, ""
}
return false, ""
}
}
return true, url + tourl(params)
} else {
var i int
var startreg bool
regurl := ""
for _, v := range strings.Trim(l.regexps.String(), "^$") {
if v == '(' {
startreg = true
continue
} else if v == ')' {
startreg = false
if v, ok := params[l.wildcards[i]]; ok {
delete(params, l.wildcards[i])
regurl = regurl + v
i++
} else {
break
}
} else if !startreg {
regurl = string(append([]rune(regurl), v))
}
var i int
var startreg bool
regurl := ""
for _, v := range strings.Trim(l.regexps.String(), "^$") {
if v == '(' {
startreg = true
continue
} else if v == ')' {
startreg = false
if v, ok := params[l.wildcards[i]]; ok {
delete(params, l.wildcards[i])
regurl = regurl + v
i++
} else {
break
}
} else if !startreg {
regurl = string(append([]rune(regurl), v))
}
if l.regexps.MatchString(regurl) {
ps := strings.Split(regurl, "/")
for _, p := range ps {
url = strings.Replace(url, url_placeholder, p, 1)
}
return true, url + tourl(params)
}
if l.regexps.MatchString(regurl) {
ps := strings.Split(regurl, "/")
for _, p := range ps {
url = strings.Replace(url, urlPlaceholder, p, 1)
}
return true, url + tourl(params)
}
}
}
@ -575,7 +574,7 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
}
// Implement http.Handler interface.
func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
starttime := time.Now()
var runrouter reflect.Type
var findrouter bool
@ -607,7 +606,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
urlPath = r.URL.Path
}
// defined filter function
do_filter := func(pos int) (started bool) {
doFilter := func(pos int) (started bool) {
if p.enableFilter {
if l, ok := p.filters[pos]; ok {
for _, filterR := range l {
@ -617,7 +616,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
if ok, params := filterR.ValidRouter(urlPath); ok {
for k, v := range params {
if context.Input.Params == nil {
context.Input.Params = make(map[string]string)
context.Input.Params = make(map[string]string)
}
context.Input.Params[k] = v
}
@ -639,7 +638,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
// filter for static file
if do_filter(BeforeStatic) {
if doFilter(BeforeStatic) {
goto Admin
}
@ -670,7 +669,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
context.Input.ParseFormOrMulitForm(MaxMemory)
}
if do_filter(BeforeRouter) {
if doFilter(BeforeRouter) {
goto Admin
}
@ -681,17 +680,17 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
if !findrouter {
http_method := r.Method
httpMethod := r.Method
if http_method == "POST" && context.Input.Query("_method") == "PUT" {
http_method = "PUT"
if httpMethod == "POST" && context.Input.Query("_method") == "PUT" {
httpMethod = "PUT"
}
if http_method == "POST" && context.Input.Query("_method") == "DELETE" {
http_method = "DELETE"
if httpMethod == "POST" && context.Input.Query("_method") == "DELETE" {
httpMethod = "DELETE"
}
if t, ok := p.routers[http_method]; ok {
if t, ok := p.routers[httpMethod]; ok {
runObject, p := t.Match(urlPath)
if r, ok := runObject.(*controllerInfo); ok {
routerInfo = r
@ -718,7 +717,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
if findrouter {
//execute middleware filters
if do_filter(BeforeExec) {
if doFilter(BeforeExec) {
goto Admin
}
isRunable := false
@ -770,10 +769,10 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
//if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf
if EnableXSRF {
execController.XsrfToken()
execController.XSRFToken()
if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" ||
(r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) {
execController.CheckXsrfCookie()
execController.CheckXSRFCookie()
}
}
@ -798,7 +797,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
execController.Options()
default:
if !execController.HandlerFunc(runMethod) {
in := make([]reflect.Value, 0)
var in []reflect.Value
method := vc.MethodByName(runMethod)
method.Call(in)
}
@ -819,12 +818,12 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}
//execute middleware filters
if do_filter(AfterExec) {
if doFilter(AfterExec) {
goto Admin
}
}
do_filter(FinishRouter)
doFilter(FinishRouter)
Admin:
timeend := time.Since(starttime)
@ -850,7 +849,7 @@ Admin:
} else {
devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch")
}
if DefaultLogFilter == nil || !DefaultLogFilter.Filter(context) {
if DefaultAccessLogFilter == nil || !DefaultAccessLogFilter.Filter(context) {
Debug(devinfo)
}
}
@ -861,15 +860,15 @@ Admin:
}
}
func (p *ControllerRegistor) recoverPanic(context *beecontext.Context) {
func (p *ControllerRegister) recoverPanic(context *beecontext.Context) {
if err := recover(); err != nil {
if err == USERSTOPRUN {
if err == ErrAbort {
return
}
if !RecoverPanic {
panic(err)
} else {
if ErrorsShow {
if EnableErrorsShow {
if _, ok := ErrorMaps[fmt.Sprint(err)]; ok {
exception(fmt.Sprint(err), context)
return
@ -931,6 +930,13 @@ func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return hj.Hijack()
}
func (w *responseWriter) Flush() {
f, ok := w.writer.(http.Flusher)
if ok {
f.Flush()
}
}
func tourl(params map[string]string) string {
if len(params) == 0 {
return ""

View File

@ -52,17 +52,17 @@ func (tc *TestController) Myext() {
tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param(":ext")))
}
func (tc *TestController) GetUrl() {
tc.Ctx.Output.Body([]byte(tc.UrlFor(".Myext")))
func (tc *TestController) GetURL() {
tc.Ctx.Output.Body([]byte(tc.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 (tc *TestController) GetParams() {
tc.Ctx.WriteString(tc.Ctx.Input.Query(":last") + "+" +
tc.Ctx.Input.Query(":first") + "+" + tc.Ctx.Input.Query("learn"))
}
func (t *TestController) GetManyRouter() {
t.Ctx.WriteString(t.Ctx.Input.Query(":id") + t.Ctx.Input.Query(":page"))
func (tc *TestController) GetManyRouter() {
tc.Ctx.WriteString(tc.Ctx.Input.Query(":id") + tc.Ctx.Input.Query(":page"))
}
type ResStatus struct {
@ -70,29 +70,29 @@ type ResStatus struct {
Msg string
}
type JsonController struct {
type JSONController struct {
Controller
}
func (this *JsonController) Prepare() {
this.Data["json"] = "prepare"
this.ServeJson(true)
func (jc *JSONController) Prepare() {
jc.Data["json"] = "prepare"
jc.ServeJSON(true)
}
func (this *JsonController) Get() {
this.Data["Username"] = "astaxie"
this.Ctx.Output.Body([]byte("ok"))
func (jc *JSONController) Get() {
jc.Data["Username"] = "astaxie"
jc.Ctx.Output.Body([]byte("ok"))
}
func TestUrlFor(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/api/list", &TestController{}, "*:List")
handler.Add("/person/:last/:first", &TestController{}, "*:Param")
if a := handler.UrlFor("TestController.List"); a != "/api/list" {
if a := handler.URLFor("TestController.List"); a != "/api/list" {
Info(a)
t.Errorf("TestController.List must equal to /api/list")
}
if a := handler.UrlFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" {
if a := handler.URLFor("TestController.Param", ":last", "xie", ":first", "asta"); a != "/person/xie/asta" {
t.Errorf("TestController.Param must equal to /person/xie/asta, but get " + a)
}
}
@ -100,39 +100,39 @@ func TestUrlFor(t *testing.T) {
func TestUrlFor3(t *testing.T) {
handler := NewControllerRegister()
handler.AddAuto(&TestController{})
if a := handler.UrlFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" {
if a := handler.URLFor("TestController.Myext"); a != "/test/myext" && a != "/Test/Myext" {
t.Errorf("TestController.Myext must equal to /test/myext, but get " + a)
}
if a := handler.UrlFor("TestController.GetUrl"); a != "/test/geturl" && a != "/Test/GetUrl" {
t.Errorf("TestController.GetUrl must equal to /test/geturl, but get " + a)
if a := handler.URLFor("TestController.GetURL"); a != "/test/geturl" && a != "/Test/GetURL" {
t.Errorf("TestController.GetURL must equal to /test/geturl, but get " + a)
}
}
func TestUrlFor2(t *testing.T) {
handler := NewControllerRegister()
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, "*:List")
handler.Add("/v1/:username/edit", &TestController{}, "get:GetUrl")
handler.Add("/v1/:username/edit", &TestController{}, "get:GetURL")
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, "*:Param")
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
if handler.UrlFor("TestController.GetUrl", ":username", "astaxie") != "/v1/astaxie/edit" {
Info(handler.UrlFor("TestController.GetUrl"))
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
Info(handler.URLFor("TestController.GetURL"))
t.Errorf("TestController.List must equal to /v1/astaxie/edit")
}
if handler.UrlFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
if handler.URLFor("TestController.List", ":v", "za", ":id", "12", ":page", "123") !=
"/v1/za/cms_12_123.html" {
Info(handler.UrlFor("TestController.List"))
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") !=
if handler.URLFor("TestController.Param", ":v", "za", ":id", "12", ":page", "123") !=
"/v1/za_cms/ttt_12_123.html" {
Info(handler.UrlFor("TestController.Param"))
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",
if handler.URLFor("TestController.Get", ":year", "1111", ":month", "11",
":title", "aaaa", ":entid", "aaaa") !=
"/1111/11/aaaa/aaaa" {
Info(handler.UrlFor("TestController.Get"))
Info(handler.URLFor("TestController.Get"))
t.Errorf("TestController.Get must equal to /1111/11/aaaa/aaaa")
}
}
@ -270,7 +270,7 @@ func TestPrepare(t *testing.T) {
w := httptest.NewRecorder()
handler := NewControllerRegister()
handler.Add("/json/list", &JsonController{})
handler.Add("/json/list", &JSONController{})
handler.ServeHTTP(w, r)
if w.Body.String() != `"prepare"` {
t.Errorf(w.Body.String() + "user define func can't run")

View File

@ -51,7 +51,10 @@ import (
_ "github.com/go-sql-driver/mysql"
)
var mysqlpder = &MysqlProvider{}
var (
TableName = "session"
mysqlpder = &MysqlProvider{}
)
// mysql session store
type MysqlSessionStore struct {
@ -110,7 +113,7 @@ func (st *MysqlSessionStore) SessionRelease(w http.ResponseWriter) {
if err != nil {
return
}
st.c.Exec("UPDATE session set `session_data`=?, `session_expiry`=? where session_key=?",
st.c.Exec("UPDATE "+TableName+" set `session_data`=?, `session_expiry`=? where session_key=?",
b, time.Now().Unix(), st.sid)
}
@ -141,11 +144,11 @@ func (mp *MysqlProvider) SessionInit(maxlifetime int64, savePath string) error {
// get mysql session by sid
func (mp *MysqlProvider) SessionRead(sid string) (session.SessionStore, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from session where session_key=?", sid)
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)",
sid, "", time.Now().Unix())
}
var kv map[interface{}]interface{}
@ -165,7 +168,7 @@ func (mp *MysqlProvider) SessionRead(sid string) (session.SessionStore, error) {
func (mp *MysqlProvider) SessionExist(sid string) bool {
c := mp.connectInit()
defer c.Close()
row := c.QueryRow("select session_data from session where session_key=?", sid)
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
@ -178,13 +181,13 @@ func (mp *MysqlProvider) SessionExist(sid string) bool {
// generate new sid for mysql session
func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (session.SessionStore, error) {
c := mp.connectInit()
row := c.QueryRow("select session_data from session where session_key=?", oldsid)
row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid)
var sessiondata []byte
err := row.Scan(&sessiondata)
if err == sql.ErrNoRows {
c.Exec("insert into session(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
c.Exec("insert into "+TableName+"(`session_key`,`session_data`,`session_expiry`) values(?,?,?)", oldsid, "", time.Now().Unix())
}
c.Exec("update session set `session_key`=? where session_key=?", sid, oldsid)
c.Exec("update "+TableName+" set `session_key`=? where session_key=?", sid, oldsid)
var kv map[interface{}]interface{}
if len(sessiondata) == 0 {
kv = make(map[interface{}]interface{})
@ -201,7 +204,7 @@ func (mp *MysqlProvider) SessionRegenerate(oldsid, sid string) (session.SessionS
// delete mysql session by sid
func (mp *MysqlProvider) SessionDestroy(sid string) error {
c := mp.connectInit()
c.Exec("DELETE FROM session where session_key=?", sid)
c.Exec("DELETE FROM "+TableName+" where session_key=?", sid)
c.Close()
return nil
}
@ -209,7 +212,7 @@ func (mp *MysqlProvider) SessionDestroy(sid string) error {
// delete expired values in mysql session
func (mp *MysqlProvider) SessionGC() {
c := mp.connectInit()
c.Exec("DELETE from session where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime)
c.Close()
return
}
@ -219,7 +222,7 @@ func (mp *MysqlProvider) SessionAll() int {
c := mp.connectInit()
defer c.Close()
var total int
err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
err := c.QueryRow("SELECT count(*) as num from " + TableName).Scan(&total)
if err != nil {
return 0
}

View File

@ -40,15 +40,13 @@ func serverStaticRouter(ctx *context.Context) {
if utils.FileExists(file) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
return
} else {
i++
if i == len(StaticDir) {
http.NotFound(ctx.ResponseWriter, ctx.Request)
return
} else {
continue
}
}
i++
if i == len(StaticDir) {
http.NotFound(ctx.ResponseWriter, ctx.Request)
return
}
continue
}
if strings.HasPrefix(requestPath, prefix) {
if len(requestPath) > len(prefix) && requestPath[len(prefix)] != '/' {

View File

@ -28,17 +28,14 @@ import (
)
var (
beegoTplFuncMap template.FuncMap
// beego template caching map and supported template file extensions.
BeeTemplates map[string]*template.Template
BeeTemplateExt []string
beegoTplFuncMap = make(template.FuncMap)
// BeeTemplates caching map and supported template file extensions.
BeeTemplates = make(map[string]*template.Template)
// BeeTemplateExt stores the template extention which will build
BeeTemplateExt = []string{"tpl", "html"}
)
func init() {
BeeTemplates = make(map[string]*template.Template)
beegoTplFuncMap = make(template.FuncMap)
BeeTemplateExt = make([]string, 0)
BeeTemplateExt = append(BeeTemplateExt, "tpl", "html")
beegoTplFuncMap["dateformat"] = DateFormat
beegoTplFuncMap["date"] = Date
beegoTplFuncMap["compare"] = Compare
@ -46,14 +43,15 @@ func init() {
beegoTplFuncMap["not_nil"] = NotNil
beegoTplFuncMap["not_null"] = NotNil
beegoTplFuncMap["substr"] = Substr
beegoTplFuncMap["html2str"] = Html2str
beegoTplFuncMap["html2str"] = HTML2str
beegoTplFuncMap["str2html"] = Str2html
beegoTplFuncMap["htmlquote"] = Htmlquote
beegoTplFuncMap["htmlunquote"] = Htmlunquote
beegoTplFuncMap["renderform"] = RenderForm
beegoTplFuncMap["assets_js"] = AssetsJs
beegoTplFuncMap["assets_css"] = AssetsCss
beegoTplFuncMap["assets_css"] = AssetsCSS
beegoTplFuncMap["config"] = Config
beegoTplFuncMap["map_get"] = MapGet
// go1.2 added template funcs
// Comparisons
@ -64,7 +62,7 @@ func init() {
beegoTplFuncMap["lt"] = lt // <
beegoTplFuncMap["ne"] = ne // !=
beegoTplFuncMap["urlfor"] = UrlFor // !=
beegoTplFuncMap["urlfor"] = URLFor // !=
}
// AddFuncMap let user to register a func in the template.
@ -78,7 +76,7 @@ type templatefile struct {
files map[string][]string
}
func (self *templatefile) visit(paths string, f os.FileInfo, err error) error {
func (tf *templatefile) visit(paths string, f os.FileInfo, err error) error {
if f == nil {
return err
}
@ -91,21 +89,21 @@ func (self *templatefile) visit(paths string, f os.FileInfo, err error) error {
replace := strings.NewReplacer("\\", "/")
a := []byte(paths)
a = a[len([]byte(self.root)):]
a = a[len([]byte(tf.root)):]
file := strings.TrimLeft(replace.Replace(string(a)), "/")
subdir := filepath.Dir(file)
if _, ok := self.files[subdir]; ok {
self.files[subdir] = append(self.files[subdir], file)
if _, ok := tf.files[subdir]; ok {
tf.files[subdir] = append(tf.files[subdir], file)
} else {
m := make([]string, 1)
m[0] = file
self.files[subdir] = m
tf.files[subdir] = m
}
return nil
}
// return this path contains supported template extension of beego or not.
// HasTemplateExt return this path contains supported template extension of beego or not.
func HasTemplateExt(paths string) bool {
for _, v := range BeeTemplateExt {
if strings.HasSuffix(paths, "."+v) {
@ -115,7 +113,7 @@ func HasTemplateExt(paths string) bool {
return false
}
// add new extension for template.
// AddTemplateExt add new extension for template.
func AddTemplateExt(ext string) {
for _, v := range BeeTemplateExt {
if v == ext {
@ -125,15 +123,14 @@ func AddTemplateExt(ext string) {
BeeTemplateExt = append(BeeTemplateExt, ext)
}
// build all template files in a directory.
// BuildTemplate will build all template files in a directory.
// it makes beego can render any template file in view directory.
func BuildTemplate(dir string) error {
func BuildTemplate(dir string, files ...string) error {
if _, err := os.Stat(dir); err != nil {
if os.IsNotExist(err) {
return nil
} else {
return errors.New("dir open err")
}
return errors.New("dir open err")
}
self := &templatefile{
root: dir,
@ -148,11 +145,13 @@ func BuildTemplate(dir string) error {
}
for _, v := range self.files {
for _, file := range v {
t, err := getTemplate(self.root, file, v...)
if err != nil {
Trace("parse template err:", file, err)
} else {
BeeTemplates[file] = t
if len(files) == 0 || utils.InSlice(file, files) {
t, err := getTemplate(self.root, file, v...)
if err != nil {
Trace("parse template err:", file, err)
} else {
BeeTemplates[file] = t
}
}
}
}
@ -260,3 +259,30 @@ func _getTemplate(t0 *template.Template, root string, submods [][]string, others
}
return
}
// SetViewsPath sets view directory path in beego application.
func SetViewsPath(path string) *App {
ViewsPath = path
return BeeApp
}
// 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".
func SetStaticPath(url string, path string) *App {
if !strings.HasPrefix(url, "/") {
url = "/" + url
}
url = strings.TrimRight(url, "/")
StaticDir[url] = path
return BeeApp
}
// DelStaticPath removes the static folder setting in this url pattern in beego application.
func DelStaticPath(url string) *App {
if !strings.HasPrefix(url, "/") {
url = "/" + url
}
url = strings.TrimRight(url, "/")
delete(StaticDir, url)
return BeeApp
}

View File

@ -20,11 +20,11 @@ import (
"testing"
)
var header string = `{{define "header"}}
var header = `{{define "header"}}
<h1>Hello, astaxie!</h1>
{{end}}`
var index string = `<!DOCTYPE html>
var index = `<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
@ -37,7 +37,7 @@ var index string = `<!DOCTYPE html>
</html>
`
var block string = `{{define "block"}}
var block = `{{define "block"}}
<h1>Hello, blocks!</h1>
{{end}}`
@ -82,7 +82,7 @@ func TestTemplate(t *testing.T) {
os.RemoveAll(dir)
}
var menu string = `<div class="menu">
var menu = `<div class="menu">
<ul>
<li>menu1</li>
<li>menu2</li>
@ -90,7 +90,7 @@ var menu string = `<div class="menu">
</ul>
</div>
`
var user string = `<!DOCTYPE html>
var user = `<!DOCTYPE html>
<html>
<head>
<title>beego welcome template</title>
@ -123,7 +123,7 @@ func TestRelativeTemplate(t *testing.T) {
f.Close()
}
}
if err := BuildTemplate(dir); err != nil {
if err := BuildTemplate(dir, files[1]); err != nil {
t.Fatal(err)
}
if err := BeeTemplates["easyui/rbac/user.tpl"].ExecuteTemplate(os.Stdout, "easyui/rbac/user.tpl", nil); err != nil {

View File

@ -44,8 +44,8 @@ func Substr(s string, start, length int) string {
return string(bt[start:end])
}
// Html2str returns escaping text convert from html.
func Html2str(html string) string {
// HTML2str returns escaping text convert from html.
func HTML2str(html string) string {
src := string(html)
re, _ := regexp.Compile("\\<[\\S\\s]+?\\>")
@ -115,7 +115,7 @@ var datePatterns = []string{
"r", time.RFC1123Z,
}
// Parse Date use PHP time format.
// DateParse Parse Date use PHP time format.
func DateParse(dateString, format string) (time.Time, error) {
replacer := strings.NewReplacer(datePatterns...)
format = replacer.Replace(format)
@ -139,14 +139,17 @@ func Compare(a, b interface{}) (equal bool) {
return
}
// CompareNot !Compare
func CompareNot(a, b interface{}) (equal bool) {
return ! Compare(a, b)
return !Compare(a, b)
}
func NotNil(a interface{}) (is_nil bool) {
return CompareNot(a, nil)
// NotNil the same as CompareNot
func NotNil(a interface{}) (isNil bool) {
return CompareNot(a, nil)
}
// Config get the Appconfig
func Config(returnType, key string, defaultVal interface{}) (value interface{}, err error) {
switch returnType {
case "String":
@ -162,12 +165,12 @@ func Config(returnType, key string, defaultVal interface{}) (value interface{},
case "DIY":
value, err = AppConfig.DIY(key)
default:
err = errors.New("Config keys must be of type String, Bool, Int, Int64, Float, or DIY!")
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!")
err = errors.New("defaultVal type does not match returnType")
} else {
value, err = defaultVal, nil
}
@ -184,7 +187,7 @@ func Config(returnType, key string, defaultVal interface{}) (value interface{},
return
}
// Convert string to template.HTML type.
// Str2html Convert string to template.HTML type.
func Str2html(raw string) template.HTML {
return template.HTML(raw)
}
@ -237,14 +240,14 @@ func Htmlunquote(src string) string {
return strings.TrimSpace(text)
}
// UrlFor returns url string with another registered controller handler with params.
// URLFor returns url string with another registered controller handler with params.
// usage:
//
// UrlFor(".index")
// print UrlFor("index")
// URLFor(".index")
// print URLFor("index")
// router /login
// print UrlFor("login")
// print UrlFor("login", "next","/"")
// print URLFor("login")
// print URLFor("login", "next","/"")
// router /profile/:username
// print UrlFor("profile", ":username","John Doe")
// result:
@ -254,11 +257,11 @@ func Htmlunquote(src string) string {
// /user/John%20Doe
//
// more detail http://beego.me/docs/mvc/controller/urlbuilding.md
func UrlFor(endpoint string, values ...interface{}) string {
return BeeApp.Handlers.UrlFor(endpoint, values...)
func URLFor(endpoint string, values ...interface{}) string {
return BeeApp.Handlers.URLFor(endpoint, values...)
}
// returns script tag with src string.
// AssetsJs returns script tag with src string.
func AssetsJs(src string) template.HTML {
text := string(src)
@ -267,8 +270,8 @@ func AssetsJs(src string) template.HTML {
return template.HTML(text)
}
// returns stylesheet link tag with src string.
func AssetsCss(src string) template.HTML {
// AssetsCSS returns stylesheet link tag with src string.
func AssetsCSS(src string) template.HTML {
text := string(src)
text = "<link href=\"" + src + "\" rel=\"stylesheet\" />"
@ -276,7 +279,7 @@ func AssetsCss(src string) template.HTML {
return template.HTML(text)
}
// parse form values to struct via tag.
// ParseForm will parse form values to struct via tag.
func ParseForm(form url.Values, obj interface{}) error {
objT := reflect.TypeOf(obj)
objV := reflect.ValueOf(obj)
@ -352,7 +355,7 @@ func ParseForm(form url.Values, obj interface{}) error {
if len(tags) > 1 {
format = tags[1]
}
t, err := time.Parse(format, value)
t, err := time.ParseInLocation(format, value, time.Local)
if err != nil {
return err
}
@ -398,7 +401,7 @@ var unKind = map[reflect.Kind]bool{
reflect.UnsafePointer: true,
}
// render object to form html.
// RenderForm will render object to form html.
// obj must be a struct pointer.
func RenderForm(obj interface{}) template.HTML {
objT := reflect.TypeOf(obj)
@ -651,4 +654,77 @@ func ge(arg1, arg2 interface{}) (bool, error) {
return !lessThan, nil
}
// go1.2 added template funcs. end
// MapGet getting value from map by keys
// usage:
// Data["m"] = map[string]interface{} {
// "a": 1,
// "1": map[string]float64{
// "c": 4,
// },
// }
//
// {{ map_get m "a" }} // return 1
// {{ map_get m 1 "c" }} // return 4
func MapGet(arg1 interface{}, arg2 ...interface{}) (interface{}, error) {
arg1Type := reflect.TypeOf(arg1)
arg1Val := reflect.ValueOf(arg1)
if arg1Type.Kind() == reflect.Map && len(arg2) > 0 {
// check whether arg2[0] type equals to arg1 key type
// if they are different, make convertion
arg2Val := reflect.ValueOf(arg2[0])
arg2Type := reflect.TypeOf(arg2[0])
if arg2Type.Kind() != arg1Type.Key().Kind() {
// convert arg2Value to string
var arg2ConvertedVal interface{}
arg2String := fmt.Sprintf("%v", arg2[0])
// convert string representation to any other type
switch arg1Type.Key().Kind() {
case reflect.Bool:
arg2ConvertedVal, _ = strconv.ParseBool(arg2String)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
arg2ConvertedVal, _ = strconv.ParseInt(arg2String, 0, 64)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
arg2ConvertedVal, _ = strconv.ParseUint(arg2String, 0, 64)
case reflect.Float32, reflect.Float64:
arg2ConvertedVal, _ = strconv.ParseFloat(arg2String, 64)
case reflect.String:
arg2ConvertedVal = arg2String
default:
arg2ConvertedVal = arg2Val.Interface()
}
arg2Val = reflect.ValueOf(arg2ConvertedVal)
}
storedVal := arg1Val.MapIndex(arg2Val)
if storedVal.IsValid() {
var result interface{}
switch arg1Type.Elem().Kind() {
case reflect.Bool:
result = storedVal.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
result = storedVal.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
result = storedVal.Uint()
case reflect.Float32, reflect.Float64:
result = storedVal.Float()
case reflect.String:
result = storedVal.String()
default:
result = storedVal.Interface()
}
// if there is more keys, handle this recursively
if len(arg2) > 1 {
return MapGet(result, arg2[1:]...)
}
return result, nil
}
return nil, nil
}
return nil, nil
}

View File

@ -40,7 +40,7 @@ func TestHtml2str(t *testing.T) {
\n`
if Html2str(h) != "123\\n\n\\n" {
if HTML2str(h) != "123\\n\n\\n" {
t.Error("should be equal")
}
}
@ -82,15 +82,15 @@ func TestCompareRelated(t *testing.T) {
if !Compare("1", 1) {
t.Error("should be equal")
}
if CompareNot("abc", "abc") {
t.Error("should be equal")
}
if !CompareNot("abc", "aBc") {
t.Error("should be not equal")
}
if !NotNil("a string") {
t.Error("should not be nil")
}
if CompareNot("abc", "abc") {
t.Error("should be equal")
}
if !CompareNot("abc", "aBc") {
t.Error("should be not equal")
}
if !NotNil("a string") {
t.Error("should not be nil")
}
}
func TestHtmlquote(t *testing.T) {
@ -111,7 +111,7 @@ func TestHtmlunquote(t *testing.T) {
func TestParseForm(t *testing.T) {
type user struct {
Id int `form:"-"`
ID int `form:"-"`
tag string `form:"tag"`
Name interface{} `form:"username"`
Age int `form:"age,text"`
@ -123,7 +123,7 @@ func TestParseForm(t *testing.T) {
u := user{}
form := url.Values{
"Id": []string{"1"},
"ID": []string{"1"},
"-": []string{"1"},
"tag": []string{"no"},
"username": []string{"test"},
@ -139,8 +139,8 @@ func TestParseForm(t *testing.T) {
if err := ParseForm(form, &u); err != nil {
t.Fatal(err)
}
if u.Id != 0 {
t.Errorf("Id should equal 0 but got %v", u.Id)
if u.ID != 0 {
t.Errorf("ID should equal 0 but got %v", u.ID)
}
if len(u.tag) != 0 {
t.Errorf("tag's length should equal 0 but got %v", len(u.tag))
@ -168,7 +168,7 @@ func TestParseForm(t *testing.T) {
func TestRenderForm(t *testing.T) {
type user struct {
Id int `form:"-"`
ID int `form:"-"`
tag string `form:"tag"`
Name interface{} `form:"username"`
Age int `form:"age,text,年龄:"`
@ -244,3 +244,80 @@ func TestParseFormTag(t *testing.T) {
t.Errorf("Form Tag that should be ignored was not correctly parsed.")
}
}
func TestMapGet(t *testing.T) {
// test one level map
m1 := map[string]int64{
"a": 1,
"1": 2,
}
if res, err := MapGet(m1, "a"); err == nil {
if res.(int64) != 1 {
t.Errorf("Should return 1, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
if res, err := MapGet(m1, "1"); err == nil {
if res.(int64) != 2 {
t.Errorf("Should return 2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
if res, err := MapGet(m1, 1); err == nil {
if res.(int64) != 2 {
t.Errorf("Should return 2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// test 2 level map
m2 := map[string]interface{}{
"1": map[string]float64{
"2": 3.5,
},
}
if res, err := MapGet(m2, 1, 2); err == nil {
if res.(float64) != 3.5 {
t.Errorf("Should return 3.5, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// test 5 level map
m5 := map[string]interface{}{
"1": map[string]interface{}{
"2": map[string]interface{}{
"3": map[string]interface{}{
"4": map[string]interface{}{
"5": 1.2,
},
},
},
},
}
if res, err := MapGet(m5, 1, 2, 3, 4, 5); err == nil {
if res.(float64) != 1.2 {
t.Errorf("Should return 1.2, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
// check whether element not exists in map
if res, err := MapGet(m5, 5, 4, 3, 2, 1); err == nil {
if res != nil {
t.Errorf("Should return nil, but return %v", res)
}
} else {
t.Errorf("Error happens %v", err)
}
}

31
tree.go
View File

@ -22,6 +22,10 @@ import (
"github.com/astaxie/beego/utils"
)
// Tree has three elements: FixRouter/wildcard/leaves
// fixRouter sotres Fixed Router
// wildcard stores params
// leaves store the endpoint information
type Tree struct {
//search fix route first
fixrouters map[string]*Tree
@ -33,13 +37,14 @@ type Tree struct {
leaves []*leafInfo
}
// NewTree return a new Tree
func NewTree() *Tree {
return &Tree{
fixrouters: make(map[string]*Tree),
}
}
// add Tree to the exist Tree
// AddTree will 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, "")
@ -187,7 +192,7 @@ func filterTreeWithPrefix(t *Tree, wildcards []string, reg string) {
}
}
// call addseg function
// AddRouter call addseg function
func (t *Tree) AddRouter(pattern string, runObject interface{}) {
t.addseg(splitPath(pattern), runObject, nil, "")
}
@ -266,7 +271,7 @@ func (t *Tree) addseg(segments []string, route interface{}, wildcards []string,
}
}
// match router to runObject & params
// 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
@ -349,7 +354,7 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
continue
}
params[v] = ""
j += 1
j++
}
return true, params
}
@ -402,7 +407,7 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string
return false, nil
}
params[v] = wildcardValues[j]
j += 1
j++
}
if len(params) != len(wildcardValues) {
return false, nil
@ -453,9 +458,8 @@ func splitSegment(key string) (bool, []string, string) {
if strings.HasPrefix(key, "*") {
if key == "*.*" {
return true, []string{".", ":path", ":ext"}, ""
} else {
return true, []string{":splat"}, ""
}
return true, []string{":splat"}, ""
}
if strings.ContainsAny(key, ":") {
var paramsNum int
@ -469,7 +473,7 @@ func splitSegment(key string) (bool, []string, string) {
reg := regexp.MustCompile(`[a-zA-Z0-9_]+`)
for i, v := range key {
if skipnum > 0 {
skipnum -= 1
skipnum--
continue
}
if start {
@ -483,7 +487,7 @@ func splitSegment(key string) (bool, []string, string) {
startexp = false
skipnum = 3
param = make([]rune, 0)
paramsNum += 1
paramsNum++
continue
}
}
@ -491,7 +495,7 @@ func splitSegment(key string) (bool, []string, string) {
if key[i+1:i+7] == "string" {
out = append(out, []rune(`([\w]+)`)...)
params = append(params, ":"+string(param))
paramsNum += 1
paramsNum++
start = false
startexp = false
skipnum = 6
@ -509,7 +513,7 @@ func splitSegment(key string) (bool, []string, string) {
out = append(out, []rune(`(.+)`)...)
params = append(params, ":"+string(param))
param = make([]rune, 0)
paramsNum += 1
paramsNum++
start = false
startexp = false
}
@ -527,7 +531,7 @@ func splitSegment(key string) (bool, []string, string) {
startexp = true
start = false
params = append(params, ":"+string(param))
paramsNum += 1
paramsNum++
expt = make([]rune, 0)
expt = append(expt, '(')
} else if v == ')' {
@ -548,7 +552,6 @@ func splitSegment(key string) (bool, []string, string) {
params = append(params, ":"+string(param))
}
return true, params, string(out)
} else {
return false, nil, ""
}
return false, nil, ""
}

View File

@ -457,7 +457,7 @@ func (b Base64) GetLimitValue() interface{} {
}
// just for chinese mobile phone number
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][67]|[4][579]))\\d{8}$")
var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][067]|[4][579]))\\d{8}$")
type Mobile struct {
Match