Merge remote-tracking branch 'upstream/master' into develop
Showing
57 changed files
with
1042 additions
and
603 deletions
| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | [](https://drone.io/github.com/astaxie/beego/latest) | 3 | [](https://drone.io/github.com/astaxie/beego/latest) |
| 4 | [](http://godoc.org/github.com/astaxie/beego) | 4 | [](http://godoc.org/github.com/astaxie/beego) |
| 5 | 5 | ||
| 6 | beego is an open-source, high-performance, modularity, full-stack web framework. | 6 | beego is an open-source, high-performance, modular, full-stack web framework. |
| 7 | 7 | ||
| 8 | More info [beego.me](http://beego.me) | 8 | More info [beego.me](http://beego.me) |
| 9 | 9 | ||
| ... | @@ -19,7 +19,7 @@ More info [beego.me](http://beego.me) | ... | @@ -19,7 +19,7 @@ More info [beego.me](http://beego.me) |
| 19 | * Auto API documents | 19 | * Auto API documents |
| 20 | * Annotation router | 20 | * Annotation router |
| 21 | * Namespace | 21 | * Namespace |
| 22 | * Powerful develop tools | 22 | * Powerful development tools |
| 23 | * Full stack for Web & API | 23 | * Full stack for Web & API |
| 24 | 24 | ||
| 25 | ## Documentation | 25 | ## Documentation | ... | ... |
| ... | @@ -113,8 +113,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) { | ... | @@ -113,8 +113,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) { |
| 113 | m["SessionName"] = SessionName | 113 | m["SessionName"] = SessionName |
| 114 | m["SessionGCMaxLifetime"] = SessionGCMaxLifetime | 114 | m["SessionGCMaxLifetime"] = SessionGCMaxLifetime |
| 115 | m["SessionSavePath"] = SessionSavePath | 115 | m["SessionSavePath"] = SessionSavePath |
| 116 | m["SessionHashFunc"] = SessionHashFunc | ||
| 117 | m["SessionHashKey"] = SessionHashKey | ||
| 118 | m["SessionCookieLifeTime"] = SessionCookieLifeTime | 116 | m["SessionCookieLifeTime"] = SessionCookieLifeTime |
| 119 | m["UseFcgi"] = UseFcgi | 117 | m["UseFcgi"] = UseFcgi |
| 120 | m["MaxMemory"] = MaxMemory | 118 | m["MaxMemory"] = MaxMemory |
| ... | @@ -399,7 +397,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { | ... | @@ -399,7 +397,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { |
| 399 | if err != nil { | 397 | if err != nil { |
| 400 | data["Message"] = []string{"error", fmt.Sprintf("%s", err)} | 398 | data["Message"] = []string{"error", fmt.Sprintf("%s", err)} |
| 401 | } | 399 | } |
| 402 | data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is %s", taskname, t.GetStatus())} | 400 | data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is <br>%s", taskname, t.GetStatus())} |
| 403 | } else { | 401 | } else { |
| 404 | data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} | 402 | data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)} |
| 405 | } | 403 | } |
| ... | @@ -412,12 +410,14 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { | ... | @@ -412,12 +410,14 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { |
| 412 | var fields = []string{ | 410 | var fields = []string{ |
| 413 | fmt.Sprintf("Task Name"), | 411 | fmt.Sprintf("Task Name"), |
| 414 | fmt.Sprintf("Task Spec"), | 412 | fmt.Sprintf("Task Spec"), |
| 415 | fmt.Sprintf("Task Function"), | 413 | fmt.Sprintf("Task Status"), |
| 414 | fmt.Sprintf("Last Time"), | ||
| 416 | fmt.Sprintf(""), | 415 | fmt.Sprintf(""), |
| 417 | } | 416 | } |
| 418 | for tname, tk := range toolbox.AdminTaskList { | 417 | for tname, tk := range toolbox.AdminTaskList { |
| 419 | result = []string{ | 418 | result = []string{ |
| 420 | fmt.Sprintf("%s", tname), | 419 | fmt.Sprintf("%s", tname), |
| 420 | fmt.Sprintf("%s", tk.GetSpec()), | ||
| 421 | fmt.Sprintf("%s", tk.GetStatus()), | 421 | fmt.Sprintf("%s", tk.GetStatus()), |
| 422 | fmt.Sprintf("%s", tk.GetPrev().String()), | 422 | fmt.Sprintf("%s", tk.GetPrev().String()), |
| 423 | } | 423 | } |
| ... | @@ -458,7 +458,7 @@ func (admin *adminApp) Run() { | ... | @@ -458,7 +458,7 @@ func (admin *adminApp) Run() { |
| 458 | for p, f := range admin.routers { | 458 | for p, f := range admin.routers { |
| 459 | http.Handle(p, f) | 459 | http.Handle(p, f) |
| 460 | } | 460 | } |
| 461 | BeeLogger.Info("Running on %s", addr) | 461 | BeeLogger.Info("Admin server Running on %s", addr) |
| 462 | err := http.ListenAndServe(addr, nil) | 462 | err := http.ListenAndServe(addr, nil) |
| 463 | if err != nil { | 463 | if err != nil { |
| 464 | BeeLogger.Critical("Admin ListenAndServe: ", err) | 464 | BeeLogger.Critical("Admin ListenAndServe: ", err) | ... | ... |
| ... | @@ -186,7 +186,7 @@ bg-warning | ... | @@ -186,7 +186,7 @@ bg-warning |
| 186 | </td> | 186 | </td> |
| 187 | {{end}} | 187 | {{end}} |
| 188 | <td> | 188 | <td> |
| 189 | <a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 1}}">Run</a> | 189 | <a class="btn btn-primary btn-sm" href="/task?taskname={{index $slice 0}}">Run</a> |
| 190 | </td> | 190 | </td> |
| 191 | </tr> | 191 | </tr> |
| 192 | {{end}} | 192 | {{end}} | ... | ... |
| ... | @@ -19,14 +19,12 @@ import ( | ... | @@ -19,14 +19,12 @@ import ( |
| 19 | "net" | 19 | "net" |
| 20 | "net/http" | 20 | "net/http" |
| 21 | "net/http/fcgi" | 21 | "net/http/fcgi" |
| 22 | "os" | ||
| 22 | "time" | 23 | "time" |
| 23 | 24 | ||
| 24 | "github.com/astaxie/beego/context" | 25 | "github.com/astaxie/beego/utils" |
| 25 | ) | 26 | ) |
| 26 | 27 | ||
| 27 | // FilterFunc defines filter function type. | ||
| 28 | type FilterFunc func(*context.Context) | ||
| 29 | |||
| 30 | // App defines beego application with a new PatternServeMux. | 28 | // App defines beego application with a new PatternServeMux. |
| 31 | type App struct { | 29 | type App struct { |
| 32 | Handlers *ControllerRegistor | 30 | Handlers *ControllerRegistor |
| ... | @@ -64,6 +62,10 @@ func (app *App) Run() { | ... | @@ -64,6 +62,10 @@ func (app *App) Run() { |
| 64 | } | 62 | } |
| 65 | } else { | 63 | } else { |
| 66 | if HttpPort == 0 { | 64 | if HttpPort == 0 { |
| 65 | // remove the Socket file before start | ||
| 66 | if utils.FileExists(addr) { | ||
| 67 | os.Remove(addr) | ||
| 68 | } | ||
| 67 | l, err = net.Listen("unix", addr) | 69 | l, err = net.Listen("unix", addr) |
| 68 | } else { | 70 | } else { |
| 69 | l, err = net.Listen("tcp", addr) | 71 | l, err = net.Listen("tcp", addr) |
| ... | @@ -85,7 +87,7 @@ func (app *App) Run() { | ... | @@ -85,7 +87,7 @@ func (app *App) Run() { |
| 85 | if HttpsPort != 0 { | 87 | if HttpsPort != 0 { |
| 86 | app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort) | 88 | app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort) |
| 87 | } | 89 | } |
| 88 | BeeLogger.Info("Running on %s", app.Server.Addr) | 90 | BeeLogger.Info("https server Running on %s", app.Server.Addr) |
| 89 | err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile) | 91 | err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile) |
| 90 | if err != nil { | 92 | if err != nil { |
| 91 | BeeLogger.Critical("ListenAndServeTLS: ", err) | 93 | BeeLogger.Critical("ListenAndServeTLS: ", err) |
| ... | @@ -98,12 +100,29 @@ func (app *App) Run() { | ... | @@ -98,12 +100,29 @@ func (app *App) Run() { |
| 98 | if EnableHttpListen { | 100 | if EnableHttpListen { |
| 99 | go func() { | 101 | go func() { |
| 100 | app.Server.Addr = addr | 102 | app.Server.Addr = addr |
| 101 | BeeLogger.Info("Running on %s", app.Server.Addr) | 103 | BeeLogger.Info("http server Running on %s", app.Server.Addr) |
| 102 | err := app.Server.ListenAndServe() | 104 | if ListenTCP4 && HttpAddr == "" { |
| 103 | if err != nil { | 105 | ln, err := net.Listen("tcp4", app.Server.Addr) |
| 104 | BeeLogger.Critical("ListenAndServe: ", err) | 106 | if err != nil { |
| 105 | time.Sleep(100 * time.Microsecond) | 107 | BeeLogger.Critical("ListenAndServe: ", err) |
| 106 | endRunning <- true | 108 | time.Sleep(100 * time.Microsecond) |
| 109 | endRunning <- true | ||
| 110 | return | ||
| 111 | } | ||
| 112 | err = app.Server.Serve(ln) | ||
| 113 | if err != nil { | ||
| 114 | BeeLogger.Critical("ListenAndServe: ", err) | ||
| 115 | time.Sleep(100 * time.Microsecond) | ||
| 116 | endRunning <- true | ||
| 117 | return | ||
| 118 | } | ||
| 119 | } else { | ||
| 120 | err := app.Server.ListenAndServe() | ||
| 121 | if err != nil { | ||
| 122 | BeeLogger.Critical("ListenAndServe: ", err) | ||
| 123 | time.Sleep(100 * time.Microsecond) | ||
| 124 | endRunning <- true | ||
| 125 | } | ||
| 107 | } | 126 | } |
| 108 | }() | 127 | }() |
| 109 | } | 128 | } | ... | ... |
| ... | @@ -33,83 +33,15 @@ import ( | ... | @@ -33,83 +33,15 @@ import ( |
| 33 | "strconv" | 33 | "strconv" |
| 34 | "strings" | 34 | "strings" |
| 35 | 35 | ||
| 36 | "github.com/astaxie/beego/middleware" | ||
| 37 | "github.com/astaxie/beego/session" | 36 | "github.com/astaxie/beego/session" |
| 38 | ) | 37 | ) |
| 39 | 38 | ||
| 40 | // beego web framework version. | 39 | // beego web framework version. |
| 41 | const VERSION = "1.4.1" | 40 | const VERSION = "1.4.3" |
| 42 | 41 | ||
| 43 | type hookfunc func() error //hook function to run | 42 | type hookfunc func() error //hook function to run |
| 44 | var hooks []hookfunc //hook function slice to store the hookfunc | 43 | var hooks []hookfunc //hook function slice to store the hookfunc |
| 45 | 44 | ||
| 46 | type groupRouter struct { | ||
| 47 | pattern string | ||
| 48 | controller ControllerInterface | ||
| 49 | mappingMethods string | ||
| 50 | } | ||
| 51 | |||
| 52 | // RouterGroups which will store routers | ||
| 53 | type GroupRouters []groupRouter | ||
| 54 | |||
| 55 | // Get a new GroupRouters | ||
| 56 | func NewGroupRouters() GroupRouters { | ||
| 57 | return make(GroupRouters, 0) | ||
| 58 | } | ||
| 59 | |||
| 60 | // Add Router in the GroupRouters | ||
| 61 | // it is for plugin or module to register router | ||
| 62 | func (gr *GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingMethod ...string) { | ||
| 63 | var newRG groupRouter | ||
| 64 | if len(mappingMethod) > 0 { | ||
| 65 | newRG = groupRouter{ | ||
| 66 | pattern, | ||
| 67 | c, | ||
| 68 | mappingMethod[0], | ||
| 69 | } | ||
| 70 | } else { | ||
| 71 | newRG = groupRouter{ | ||
| 72 | pattern, | ||
| 73 | c, | ||
| 74 | "", | ||
| 75 | } | ||
| 76 | } | ||
| 77 | *gr = append(*gr, newRG) | ||
| 78 | } | ||
| 79 | |||
| 80 | func (gr *GroupRouters) AddAuto(c ControllerInterface) { | ||
| 81 | newRG := groupRouter{ | ||
| 82 | "", | ||
| 83 | c, | ||
| 84 | "", | ||
| 85 | } | ||
| 86 | *gr = append(*gr, newRG) | ||
| 87 | } | ||
| 88 | |||
| 89 | // AddGroupRouter with the prefix | ||
| 90 | // it will register the router in BeeApp | ||
| 91 | // the follow code is write in modules: | ||
| 92 | // GR:=NewGroupRouters() | ||
| 93 | // GR.AddRouter("/login",&UserController,"get:Login") | ||
| 94 | // GR.AddRouter("/logout",&UserController,"get:Logout") | ||
| 95 | // GR.AddRouter("/register",&UserController,"get:Reg") | ||
| 96 | // the follow code is write in app: | ||
| 97 | // import "github.com/beego/modules/auth" | ||
| 98 | // AddRouterGroup("/admin", auth.GR) | ||
| 99 | func AddGroupRouter(prefix string, groups GroupRouters) *App { | ||
| 100 | for _, v := range groups { | ||
| 101 | if v.pattern == "" { | ||
| 102 | BeeApp.Handlers.AddAutoPrefix(prefix, v.controller) | ||
| 103 | } else if v.mappingMethods != "" { | ||
| 104 | BeeApp.Handlers.Add(prefix+v.pattern, v.controller, v.mappingMethods) | ||
| 105 | } else { | ||
| 106 | BeeApp.Handlers.Add(prefix+v.pattern, v.controller) | ||
| 107 | } | ||
| 108 | |||
| 109 | } | ||
| 110 | return BeeApp | ||
| 111 | } | ||
| 112 | |||
| 113 | // Router adds a patterned controller handler to BeeApp. | 45 | // Router adds a patterned controller handler to BeeApp. |
| 114 | // it's an alias method of App.Router. | 46 | // it's an alias method of App.Router. |
| 115 | // usage: | 47 | // usage: |
| ... | @@ -280,15 +212,6 @@ func Handler(rootpath string, h http.Handler, options ...interface{}) *App { | ... | @@ -280,15 +212,6 @@ func Handler(rootpath string, h http.Handler, options ...interface{}) *App { |
| 280 | return BeeApp | 212 | return BeeApp |
| 281 | } | 213 | } |
| 282 | 214 | ||
| 283 | // ErrorHandler registers http.HandlerFunc to each http err code string. | ||
| 284 | // usage: | ||
| 285 | // beego.ErrorHandler("404",NotFound) | ||
| 286 | // beego.ErrorHandler("500",InternalServerError) | ||
| 287 | func Errorhandler(err string, h http.HandlerFunc) *App { | ||
| 288 | middleware.Errorhandler(err, h) | ||
| 289 | return BeeApp | ||
| 290 | } | ||
| 291 | |||
| 292 | // SetViewsPath sets view directory path in beego application. | 215 | // SetViewsPath sets view directory path in beego application. |
| 293 | func SetViewsPath(path string) *App { | 216 | func SetViewsPath(path string) *App { |
| 294 | ViewsPath = path | 217 | ViewsPath = path |
| ... | @@ -383,8 +306,6 @@ func initBeforeHttpRun() { | ... | @@ -383,8 +306,6 @@ func initBeforeHttpRun() { |
| 383 | `"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` + | 306 | `"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` + |
| 384 | `"providerConfig":"` + filepath.ToSlash(SessionSavePath) + `",` + | 307 | `"providerConfig":"` + filepath.ToSlash(SessionSavePath) + `",` + |
| 385 | `"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` + | 308 | `"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` + |
| 386 | `"sessionIDHashFunc":"` + SessionHashFunc + `",` + | ||
| 387 | `"sessionIDHashKey":"` + SessionHashKey + `",` + | ||
| 388 | `"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` + | 309 | `"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` + |
| 389 | `"domain":"` + SessionDomain + `",` + | 310 | `"domain":"` + SessionDomain + `",` + |
| 390 | `"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}` | 311 | `"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}` |
| ... | @@ -404,9 +325,7 @@ func initBeforeHttpRun() { | ... | @@ -404,9 +325,7 @@ func initBeforeHttpRun() { |
| 404 | } | 325 | } |
| 405 | } | 326 | } |
| 406 | 327 | ||
| 407 | middleware.VERSION = VERSION | 328 | registerDefaultErrorHandler() |
| 408 | middleware.AppName = AppName | ||
| 409 | middleware.RegisterErrorHandler() | ||
| 410 | 329 | ||
| 411 | if EnableDocs { | 330 | if EnableDocs { |
| 412 | Get("/docs", serverDocs) | 331 | Get("/docs", serverDocs) | ... | ... |
| ... | @@ -15,6 +15,7 @@ | ... | @@ -15,6 +15,7 @@ |
| 15 | package cache | 15 | package cache |
| 16 | 16 | ||
| 17 | import ( | 17 | import ( |
| 18 | "os" | ||
| 18 | "testing" | 19 | "testing" |
| 19 | "time" | 20 | "time" |
| 20 | ) | 21 | ) |
| ... | @@ -67,7 +68,7 @@ func TestCache(t *testing.T) { | ... | @@ -67,7 +68,7 @@ func TestCache(t *testing.T) { |
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | func TestFileCache(t *testing.T) { | 70 | func TestFileCache(t *testing.T) { |
| 70 | bm, err := NewCache("file", `{"CachePath":"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`) | 71 | bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`) |
| 71 | if err != nil { | 72 | if err != nil { |
| 72 | t.Error("init err") | 73 | t.Error("init err") |
| 73 | } | 74 | } |
| ... | @@ -112,4 +113,5 @@ func TestFileCache(t *testing.T) { | ... | @@ -112,4 +113,5 @@ func TestFileCache(t *testing.T) { |
| 112 | if v := bm.Get("astaxie"); v.(string) != "author" { | 113 | if v := bm.Get("astaxie"); v.(string) != "author" { |
| 113 | t.Error("get err") | 114 | t.Error("get err") |
| 114 | } | 115 | } |
| 116 | os.RemoveAll("cache") | ||
| 115 | } | 117 | } | ... | ... |
| ... | @@ -92,8 +92,6 @@ func (fc *FileCache) StartAndGC(config string) error { | ... | @@ -92,8 +92,6 @@ func (fc *FileCache) StartAndGC(config string) error { |
| 92 | 92 | ||
| 93 | // Init will make new dir for file cache if not exist. | 93 | // Init will make new dir for file cache if not exist. |
| 94 | func (fc *FileCache) Init() { | 94 | func (fc *FileCache) Init() { |
| 95 | app := filepath.Dir(os.Args[0]) | ||
| 96 | fc.CachePath = filepath.Join(app, fc.CachePath) | ||
| 97 | if ok, _ := exists(fc.CachePath); !ok { // todo : error handle | 95 | if ok, _ := exists(fc.CachePath); !ok { // todo : error handle |
| 98 | _ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle | 96 | _ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle |
| 99 | } | 97 | } | ... | ... |
| ... | @@ -32,6 +32,7 @@ package redis | ... | @@ -32,6 +32,7 @@ package redis |
| 32 | import ( | 32 | import ( |
| 33 | "encoding/json" | 33 | "encoding/json" |
| 34 | "errors" | 34 | "errors" |
| 35 | "strconv" | ||
| 35 | "time" | 36 | "time" |
| 36 | 37 | ||
| 37 | "github.com/garyburd/redigo/redis" | 38 | "github.com/garyburd/redigo/redis" |
| ... | @@ -48,6 +49,7 @@ var ( | ... | @@ -48,6 +49,7 @@ var ( |
| 48 | type RedisCache struct { | 49 | type RedisCache struct { |
| 49 | p *redis.Pool // redis connection pool | 50 | p *redis.Pool // redis connection pool |
| 50 | conninfo string | 51 | conninfo string |
| 52 | dbNum int | ||
| 51 | key string | 53 | key string |
| 52 | } | 54 | } |
| 53 | 55 | ||
| ... | @@ -75,14 +77,13 @@ func (rc *RedisCache) Get(key string) interface{} { | ... | @@ -75,14 +77,13 @@ func (rc *RedisCache) Get(key string) interface{} { |
| 75 | // put cache to redis. | 77 | // put cache to redis. |
| 76 | func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error { | 78 | func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error { |
| 77 | var err error | 79 | var err error |
| 78 | if _, err = rc.do("SET", key, val); err != nil { | 80 | if _, err = rc.do("SETEX", key, timeout, val); err != nil { |
| 79 | return err | 81 | return err |
| 80 | } | 82 | } |
| 81 | 83 | ||
| 82 | if _, err = rc.do("HSET", rc.key, key, true); err != nil { | 84 | if _, err = rc.do("HSET", rc.key, key, true); err != nil { |
| 83 | return err | 85 | return err |
| 84 | } | 86 | } |
| 85 | _, err = rc.do("EXPIRE", key, timeout) | ||
| 86 | return err | 87 | return err |
| 87 | } | 88 | } |
| 88 | 89 | ||
| ... | @@ -138,7 +139,7 @@ func (rc *RedisCache) ClearAll() error { | ... | @@ -138,7 +139,7 @@ func (rc *RedisCache) ClearAll() error { |
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | // start redis cache adapter. | 141 | // start redis cache adapter. |
| 141 | // config is like {"key":"collection key","conn":"connection info"} | 142 | // config is like {"key":"collection key","conn":"connection info","dbNum":"0"} |
| 142 | // the cache item in redis are stored forever, | 143 | // the cache item in redis are stored forever, |
| 143 | // so no gc operation. | 144 | // so no gc operation. |
| 144 | func (rc *RedisCache) StartAndGC(config string) error { | 145 | func (rc *RedisCache) StartAndGC(config string) error { |
| ... | @@ -152,9 +153,12 @@ func (rc *RedisCache) StartAndGC(config string) error { | ... | @@ -152,9 +153,12 @@ func (rc *RedisCache) StartAndGC(config string) error { |
| 152 | if _, ok := cf["conn"]; !ok { | 153 | if _, ok := cf["conn"]; !ok { |
| 153 | return errors.New("config has no conn key") | 154 | return errors.New("config has no conn key") |
| 154 | } | 155 | } |
| 155 | 156 | if _, ok := cf["dbNum"]; !ok { | |
| 157 | cf["dbNum"] = "0" | ||
| 158 | } | ||
| 156 | rc.key = cf["key"] | 159 | rc.key = cf["key"] |
| 157 | rc.conninfo = cf["conn"] | 160 | rc.conninfo = cf["conn"] |
| 161 | rc.dbNum, _ = strconv.Atoi(cf["dbNum"]) | ||
| 158 | rc.connectInit() | 162 | rc.connectInit() |
| 159 | 163 | ||
| 160 | c := rc.p.Get() | 164 | c := rc.p.Get() |
| ... | @@ -167,6 +171,11 @@ func (rc *RedisCache) StartAndGC(config string) error { | ... | @@ -167,6 +171,11 @@ func (rc *RedisCache) StartAndGC(config string) error { |
| 167 | func (rc *RedisCache) connectInit() { | 171 | func (rc *RedisCache) connectInit() { |
| 168 | dialFunc := func() (c redis.Conn, err error) { | 172 | dialFunc := func() (c redis.Conn, err error) { |
| 169 | c, err = redis.Dial("tcp", rc.conninfo) | 173 | c, err = redis.Dial("tcp", rc.conninfo) |
| 174 | _, selecterr := c.Do("SELECT", rc.dbNum) | ||
| 175 | if selecterr != nil { | ||
| 176 | c.Close() | ||
| 177 | return nil, selecterr | ||
| 178 | } | ||
| 170 | return | 179 | return |
| 171 | } | 180 | } |
| 172 | // initialize a new pool | 181 | // initialize a new pool | ... | ... |
| ... | @@ -40,6 +40,7 @@ var ( | ... | @@ -40,6 +40,7 @@ var ( |
| 40 | EnableHttpListen bool | 40 | EnableHttpListen bool |
| 41 | HttpAddr string | 41 | HttpAddr string |
| 42 | HttpPort int | 42 | HttpPort int |
| 43 | ListenTCP4 bool | ||
| 43 | EnableHttpTLS bool | 44 | EnableHttpTLS bool |
| 44 | HttpsPort int | 45 | HttpsPort int |
| 45 | HttpCertFile string | 46 | HttpCertFile string |
| ... | @@ -55,8 +56,6 @@ var ( | ... | @@ -55,8 +56,6 @@ var ( |
| 55 | SessionName string // the cookie name when saving session id into cookie. | 56 | SessionName string // the cookie name when saving session id into cookie. |
| 56 | SessionGCMaxLifetime int64 // session gc time for auto cleaning expired session. | 57 | SessionGCMaxLifetime int64 // session gc time for auto cleaning expired session. |
| 57 | SessionSavePath string // if use mysql/redis/file provider, define save path to connection info. | 58 | SessionSavePath string // if use mysql/redis/file provider, define save path to connection info. |
| 58 | SessionHashFunc string // session hash generation func. | ||
| 59 | SessionHashKey string // session hash salt string. | ||
| 60 | SessionCookieLifeTime int // the life time of session id in cookie. | 59 | SessionCookieLifeTime int // the life time of session id in cookie. |
| 61 | SessionAutoSetCookie bool // auto setcookie | 60 | SessionAutoSetCookie bool // auto setcookie |
| 62 | SessionDomain string // the cookie domain default is empty | 61 | SessionDomain string // the cookie domain default is empty |
| ... | @@ -82,6 +81,7 @@ var ( | ... | @@ -82,6 +81,7 @@ var ( |
| 82 | AppConfigProvider string // config provider | 81 | AppConfigProvider string // config provider |
| 83 | EnableDocs bool // enable generate docs & server docs API Swagger | 82 | EnableDocs bool // enable generate docs & server docs API Swagger |
| 84 | RouterCaseSensitive bool // router case sensitive default is true | 83 | RouterCaseSensitive bool // router case sensitive default is true |
| 84 | AccessLogs bool // print access logs, default is false | ||
| 85 | ) | 85 | ) |
| 86 | 86 | ||
| 87 | type beegoAppConfig struct { | 87 | type beegoAppConfig struct { |
| ... | @@ -111,7 +111,7 @@ func (b *beegoAppConfig) String(key string) string { | ... | @@ -111,7 +111,7 @@ func (b *beegoAppConfig) String(key string) string { |
| 111 | 111 | ||
| 112 | func (b *beegoAppConfig) Strings(key string) []string { | 112 | func (b *beegoAppConfig) Strings(key string) []string { |
| 113 | v := b.innerConfig.Strings(RunMode + "::" + key) | 113 | v := b.innerConfig.Strings(RunMode + "::" + key) |
| 114 | if len(v) == 0 { | 114 | if v[0] == "" { |
| 115 | return b.innerConfig.Strings(key) | 115 | return b.innerConfig.Strings(key) |
| 116 | } | 116 | } |
| 117 | return v | 117 | return v |
| ... | @@ -236,8 +236,6 @@ func init() { | ... | @@ -236,8 +236,6 @@ func init() { |
| 236 | SessionName = "beegosessionID" | 236 | SessionName = "beegosessionID" |
| 237 | SessionGCMaxLifetime = 3600 | 237 | SessionGCMaxLifetime = 3600 |
| 238 | SessionSavePath = "" | 238 | SessionSavePath = "" |
| 239 | SessionHashFunc = "sha1" | ||
| 240 | SessionHashKey = "beegoserversessionkey" | ||
| 241 | SessionCookieLifeTime = 0 //set cookie default is the brower life | 239 | SessionCookieLifeTime = 0 //set cookie default is the brower life |
| 242 | SessionAutoSetCookie = true | 240 | SessionAutoSetCookie = true |
| 243 | 241 | ||
| ... | @@ -277,9 +275,10 @@ func init() { | ... | @@ -277,9 +275,10 @@ func init() { |
| 277 | if err != nil { | 275 | if err != nil { |
| 278 | fmt.Println("init console log error:", err) | 276 | fmt.Println("init console log error:", err) |
| 279 | } | 277 | } |
| 278 | SetLogFuncCall(true) | ||
| 280 | 279 | ||
| 281 | err = ParseConfig() | 280 | err = ParseConfig() |
| 282 | if err != nil && !os.IsNotExist(err) { | 281 | if err != nil && os.IsNotExist(err) { |
| 283 | // for init if doesn't have app.conf will not panic | 282 | // for init if doesn't have app.conf will not panic |
| 284 | ac := config.NewFakeConfig() | 283 | ac := config.NewFakeConfig() |
| 285 | AppConfig = &beegoAppConfig{ac} | 284 | AppConfig = &beegoAppConfig{ac} |
| ... | @@ -308,6 +307,10 @@ func ParseConfig() (err error) { | ... | @@ -308,6 +307,10 @@ func ParseConfig() (err error) { |
| 308 | HttpPort = v | 307 | HttpPort = v |
| 309 | } | 308 | } |
| 310 | 309 | ||
| 310 | if v, err := AppConfig.Bool("ListenTCP4"); err == nil { | ||
| 311 | ListenTCP4 = v | ||
| 312 | } | ||
| 313 | |||
| 311 | if v, err := AppConfig.Bool("EnableHttpListen"); err == nil { | 314 | if v, err := AppConfig.Bool("EnableHttpListen"); err == nil { |
| 312 | EnableHttpListen = v | 315 | EnableHttpListen = v |
| 313 | } | 316 | } |
| ... | @@ -348,14 +351,6 @@ func ParseConfig() (err error) { | ... | @@ -348,14 +351,6 @@ func ParseConfig() (err error) { |
| 348 | SessionSavePath = sesssavepath | 351 | SessionSavePath = sesssavepath |
| 349 | } | 352 | } |
| 350 | 353 | ||
| 351 | if sesshashfunc := AppConfig.String("SessionHashFunc"); sesshashfunc != "" { | ||
| 352 | SessionHashFunc = sesshashfunc | ||
| 353 | } | ||
| 354 | |||
| 355 | if sesshashkey := AppConfig.String("SessionHashKey"); sesshashkey != "" { | ||
| 356 | SessionHashKey = sesshashkey | ||
| 357 | } | ||
| 358 | |||
| 359 | if sessMaxLifeTime, err := AppConfig.Int64("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 { | 354 | if sessMaxLifeTime, err := AppConfig.Int64("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 { |
| 360 | SessionGCMaxLifetime = sessMaxLifeTime | 355 | SessionGCMaxLifetime = sessMaxLifeTime |
| 361 | } | 356 | } | ... | ... |
| ... | @@ -17,13 +17,10 @@ package config | ... | @@ -17,13 +17,10 @@ package config |
| 17 | import ( | 17 | import ( |
| 18 | "encoding/json" | 18 | "encoding/json" |
| 19 | "errors" | 19 | "errors" |
| 20 | "fmt" | ||
| 21 | "io/ioutil" | 20 | "io/ioutil" |
| 22 | "os" | 21 | "os" |
| 23 | "path" | ||
| 24 | "strings" | 22 | "strings" |
| 25 | "sync" | 23 | "sync" |
| 26 | "time" | ||
| 27 | ) | 24 | ) |
| 28 | 25 | ||
| 29 | // JsonConfig is a json config parser and implements Config interface. | 26 | // JsonConfig is a json config parser and implements Config interface. |
| ... | @@ -41,13 +38,19 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { | ... | @@ -41,13 +38,19 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { |
| 41 | if err != nil { | 38 | if err != nil { |
| 42 | return nil, err | 39 | return nil, err |
| 43 | } | 40 | } |
| 41 | |||
| 42 | return js.ParseData(content) | ||
| 43 | } | ||
| 44 | |||
| 45 | // ParseData returns a ConfigContainer with json string | ||
| 46 | func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) { | ||
| 44 | x := &JsonConfigContainer{ | 47 | x := &JsonConfigContainer{ |
| 45 | data: make(map[string]interface{}), | 48 | data: make(map[string]interface{}), |
| 46 | } | 49 | } |
| 47 | err = json.Unmarshal(content, &x.data) | 50 | err := json.Unmarshal(data, &x.data) |
| 48 | if err != nil { | 51 | if err != nil { |
| 49 | var wrappingArray []interface{} | 52 | var wrappingArray []interface{} |
| 50 | err2 := json.Unmarshal(content, &wrappingArray) | 53 | err2 := json.Unmarshal(data, &wrappingArray) |
| 51 | if err2 != nil { | 54 | if err2 != nil { |
| 52 | return nil, err | 55 | return nil, err |
| 53 | } | 56 | } |
| ... | @@ -56,16 +59,6 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { | ... | @@ -56,16 +59,6 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) { |
| 56 | return x, nil | 59 | return x, nil |
| 57 | } | 60 | } |
| 58 | 61 | ||
| 59 | func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) { | ||
| 60 | // Save memory data to temporary file | ||
| 61 | tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond())) | ||
| 62 | os.MkdirAll(path.Dir(tmpName), os.ModePerm) | ||
| 63 | if err := ioutil.WriteFile(tmpName, data, 0655); err != nil { | ||
| 64 | return nil, err | ||
| 65 | } | ||
| 66 | return js.Parse(tmpName) | ||
| 67 | } | ||
| 68 | |||
| 69 | // A Config represents the json configuration. | 62 | // A Config represents the json configuration. |
| 70 | // Only when get value, support key as section:name type. | 63 | // Only when get value, support key as section:name type. |
| 71 | type JsonConfigContainer struct { | 64 | type JsonConfigContainer struct { |
| ... | @@ -88,11 +81,10 @@ func (c *JsonConfigContainer) Bool(key string) (bool, error) { | ... | @@ -88,11 +81,10 @@ func (c *JsonConfigContainer) Bool(key string) (bool, error) { |
| 88 | // DefaultBool return the bool value if has no error | 81 | // DefaultBool return the bool value if has no error |
| 89 | // otherwise return the defaultval | 82 | // otherwise return the defaultval |
| 90 | func (c *JsonConfigContainer) DefaultBool(key string, defaultval bool) bool { | 83 | func (c *JsonConfigContainer) DefaultBool(key string, defaultval bool) bool { |
| 91 | if v, err := c.Bool(key); err != nil { | 84 | if v, err := c.Bool(key); err == nil { |
| 92 | return defaultval | ||
| 93 | } else { | ||
| 94 | return v | 85 | return v |
| 95 | } | 86 | } |
| 87 | return defaultval | ||
| 96 | } | 88 | } |
| 97 | 89 | ||
| 98 | // Int returns the integer value for a given key. | 90 | // Int returns the integer value for a given key. |
| ... | @@ -110,11 +102,10 @@ func (c *JsonConfigContainer) Int(key string) (int, error) { | ... | @@ -110,11 +102,10 @@ func (c *JsonConfigContainer) Int(key string) (int, error) { |
| 110 | // DefaultInt returns the integer value for a given key. | 102 | // DefaultInt returns the integer value for a given key. |
| 111 | // if err != nil return defaltval | 103 | // if err != nil return defaltval |
| 112 | func (c *JsonConfigContainer) DefaultInt(key string, defaultval int) int { | 104 | func (c *JsonConfigContainer) DefaultInt(key string, defaultval int) int { |
| 113 | if v, err := c.Int(key); err != nil { | 105 | if v, err := c.Int(key); err == nil { |
| 114 | return defaultval | ||
| 115 | } else { | ||
| 116 | return v | 106 | return v |
| 117 | } | 107 | } |
| 108 | return defaultval | ||
| 118 | } | 109 | } |
| 119 | 110 | ||
| 120 | // Int64 returns the int64 value for a given key. | 111 | // Int64 returns the int64 value for a given key. |
| ... | @@ -132,11 +123,10 @@ func (c *JsonConfigContainer) Int64(key string) (int64, error) { | ... | @@ -132,11 +123,10 @@ func (c *JsonConfigContainer) Int64(key string) (int64, error) { |
| 132 | // DefaultInt64 returns the int64 value for a given key. | 123 | // DefaultInt64 returns the int64 value for a given key. |
| 133 | // if err != nil return defaltval | 124 | // if err != nil return defaltval |
| 134 | func (c *JsonConfigContainer) DefaultInt64(key string, defaultval int64) int64 { | 125 | func (c *JsonConfigContainer) DefaultInt64(key string, defaultval int64) int64 { |
| 135 | if v, err := c.Int64(key); err != nil { | 126 | if v, err := c.Int64(key); err == nil { |
| 136 | return defaultval | ||
| 137 | } else { | ||
| 138 | return v | 127 | return v |
| 139 | } | 128 | } |
| 129 | return defaultval | ||
| 140 | } | 130 | } |
| 141 | 131 | ||
| 142 | // Float returns the float value for a given key. | 132 | // Float returns the float value for a given key. |
| ... | @@ -154,11 +144,10 @@ func (c *JsonConfigContainer) Float(key string) (float64, error) { | ... | @@ -154,11 +144,10 @@ func (c *JsonConfigContainer) Float(key string) (float64, error) { |
| 154 | // DefaultFloat returns the float64 value for a given key. | 144 | // DefaultFloat returns the float64 value for a given key. |
| 155 | // if err != nil return defaltval | 145 | // if err != nil return defaltval |
| 156 | func (c *JsonConfigContainer) DefaultFloat(key string, defaultval float64) float64 { | 146 | func (c *JsonConfigContainer) DefaultFloat(key string, defaultval float64) float64 { |
| 157 | if v, err := c.Float(key); err != nil { | 147 | if v, err := c.Float(key); err == nil { |
| 158 | return defaultval | ||
| 159 | } else { | ||
| 160 | return v | 148 | return v |
| 161 | } | 149 | } |
| 150 | return defaultval | ||
| 162 | } | 151 | } |
| 163 | 152 | ||
| 164 | // String returns the string value for a given key. | 153 | // String returns the string value for a given key. |
| ... | @@ -175,35 +164,37 @@ func (c *JsonConfigContainer) String(key string) string { | ... | @@ -175,35 +164,37 @@ func (c *JsonConfigContainer) String(key string) string { |
| 175 | // DefaultString returns the string value for a given key. | 164 | // DefaultString returns the string value for a given key. |
| 176 | // if err != nil return defaltval | 165 | // if err != nil return defaltval |
| 177 | func (c *JsonConfigContainer) DefaultString(key string, defaultval string) string { | 166 | func (c *JsonConfigContainer) DefaultString(key string, defaultval string) string { |
| 178 | if v := c.String(key); v == "" { | 167 | // TODO FIXME should not use "" to replace non existance |
| 179 | return defaultval | 168 | if v := c.String(key); v != "" { |
| 180 | } else { | ||
| 181 | return v | 169 | return v |
| 182 | } | 170 | } |
| 171 | return defaultval | ||
| 183 | } | 172 | } |
| 184 | 173 | ||
| 185 | // Strings returns the []string value for a given key. | 174 | // Strings returns the []string value for a given key. |
| 186 | func (c *JsonConfigContainer) Strings(key string) []string { | 175 | func (c *JsonConfigContainer) Strings(key string) []string { |
| 176 | stringVal := c.String(key) | ||
| 177 | if stringVal == "" { | ||
| 178 | return []string{} | ||
| 179 | } | ||
| 187 | return strings.Split(c.String(key), ";") | 180 | return strings.Split(c.String(key), ";") |
| 188 | } | 181 | } |
| 189 | 182 | ||
| 190 | // DefaultStrings returns the []string value for a given key. | 183 | // DefaultStrings returns the []string value for a given key. |
| 191 | // if err != nil return defaltval | 184 | // if err != nil return defaltval |
| 192 | func (c *JsonConfigContainer) DefaultStrings(key string, defaultval []string) []string { | 185 | func (c *JsonConfigContainer) DefaultStrings(key string, defaultval []string) []string { |
| 193 | if v := c.Strings(key); len(v) == 0 { | 186 | if v := c.Strings(key); len(v) > 0 { |
| 194 | return defaultval | ||
| 195 | } else { | ||
| 196 | return v | 187 | return v |
| 197 | } | 188 | } |
| 189 | return defaultval | ||
| 198 | } | 190 | } |
| 199 | 191 | ||
| 200 | // GetSection returns map for the given section | 192 | // GetSection returns map for the given section |
| 201 | func (c *JsonConfigContainer) GetSection(section string) (map[string]string, error) { | 193 | func (c *JsonConfigContainer) GetSection(section string) (map[string]string, error) { |
| 202 | if v, ok := c.data[section]; ok { | 194 | if v, ok := c.data[section]; ok { |
| 203 | return v.(map[string]string), nil | 195 | return v.(map[string]string), nil |
| 204 | } else { | ||
| 205 | return nil, errors.New("not exist setction") | ||
| 206 | } | 196 | } |
| 197 | return nil, errors.New("nonexist section " + section) | ||
| 207 | } | 198 | } |
| 208 | 199 | ||
| 209 | // SaveConfigFile save the config into file | 200 | // SaveConfigFile save the config into file |
| ... | @@ -222,7 +213,7 @@ func (c *JsonConfigContainer) SaveConfigFile(filename string) (err error) { | ... | @@ -222,7 +213,7 @@ func (c *JsonConfigContainer) SaveConfigFile(filename string) (err error) { |
| 222 | return err | 213 | return err |
| 223 | } | 214 | } |
| 224 | 215 | ||
| 225 | // WriteValue writes a new value for key. | 216 | // Set writes a new value for key. |
| 226 | func (c *JsonConfigContainer) Set(key, val string) error { | 217 | func (c *JsonConfigContainer) Set(key, val string) error { |
| 227 | c.Lock() | 218 | c.Lock() |
| 228 | defer c.Unlock() | 219 | defer c.Unlock() |
| ... | @@ -241,18 +232,20 @@ func (c *JsonConfigContainer) DIY(key string) (v interface{}, err error) { | ... | @@ -241,18 +232,20 @@ func (c *JsonConfigContainer) DIY(key string) (v interface{}, err error) { |
| 241 | 232 | ||
| 242 | // section.key or key | 233 | // section.key or key |
| 243 | func (c *JsonConfigContainer) getData(key string) interface{} { | 234 | func (c *JsonConfigContainer) getData(key string) interface{} { |
| 244 | c.RLock() | ||
| 245 | defer c.RUnlock() | ||
| 246 | if len(key) == 0 { | 235 | if len(key) == 0 { |
| 247 | return nil | 236 | return nil |
| 248 | } | 237 | } |
| 249 | sectionKey := strings.Split(key, "::") | 238 | |
| 250 | if len(sectionKey) >= 2 { | 239 | c.RLock() |
| 251 | curValue, ok := c.data[sectionKey[0]] | 240 | defer c.RUnlock() |
| 241 | |||
| 242 | sectionKeys := strings.Split(key, "::") | ||
| 243 | if len(sectionKeys) >= 2 { | ||
| 244 | curValue, ok := c.data[sectionKeys[0]] | ||
| 252 | if !ok { | 245 | if !ok { |
| 253 | return nil | 246 | return nil |
| 254 | } | 247 | } |
| 255 | for _, key := range sectionKey[1:] { | 248 | for _, key := range sectionKeys[1:] { |
| 256 | if v, ok := curValue.(map[string]interface{}); ok { | 249 | if v, ok := curValue.(map[string]interface{}); ok { |
| 257 | if curValue, ok = v[key]; !ok { | 250 | if curValue, ok = v[key]; !ok { |
| 258 | return nil | 251 | return nil | ... | ... |
| ... | @@ -21,6 +21,7 @@ import ( | ... | @@ -21,6 +21,7 @@ import ( |
| 21 | 21 | ||
| 22 | var jsoncontext = `{ | 22 | var jsoncontext = `{ |
| 23 | "appname": "beeapi", | 23 | "appname": "beeapi", |
| 24 | "testnames": "foo;bar", | ||
| 24 | "httpport": 8080, | 25 | "httpport": 8080, |
| 25 | "mysqlport": 3600, | 26 | "mysqlport": 3600, |
| 26 | "PI": 3.1415976, | 27 | "PI": 3.1415976, |
| ... | @@ -28,8 +29,8 @@ var jsoncontext = `{ | ... | @@ -28,8 +29,8 @@ var jsoncontext = `{ |
| 28 | "autorender": false, | 29 | "autorender": false, |
| 29 | "copyrequestbody": true, | 30 | "copyrequestbody": true, |
| 30 | "database": { | 31 | "database": { |
| 31 | "host": "host", | 32 | "host": "host", |
| 32 | "port": "port", | 33 | "port": "port", |
| 33 | "database": "database", | 34 | "database": "database", |
| 34 | "username": "username", | 35 | "username": "username", |
| 35 | "password": "password", | 36 | "password": "password", |
| ... | @@ -122,6 +123,12 @@ func TestJson(t *testing.T) { | ... | @@ -122,6 +123,12 @@ func TestJson(t *testing.T) { |
| 122 | if jsonconf.String("runmode") != "dev" { | 123 | if jsonconf.String("runmode") != "dev" { |
| 123 | t.Fatal("runmode not equal to dev") | 124 | t.Fatal("runmode not equal to dev") |
| 124 | } | 125 | } |
| 126 | if v := jsonconf.Strings("unknown"); len(v) > 0 { | ||
| 127 | t.Fatal("unknown strings, the length should be 0") | ||
| 128 | } | ||
| 129 | if v := jsonconf.Strings("testnames"); len(v) != 2 { | ||
| 130 | t.Fatal("testnames length should be 2") | ||
| 131 | } | ||
| 125 | if v, err := jsonconf.Bool("autorender"); err != nil || v != false { | 132 | if v, err := jsonconf.Bool("autorender"); err != nil || v != false { |
| 126 | t.Error(v) | 133 | t.Error(v) |
| 127 | t.Fatal(err) | 134 | t.Fatal(err) |
| ... | @@ -179,4 +186,8 @@ func TestJson(t *testing.T) { | ... | @@ -179,4 +186,8 @@ func TestJson(t *testing.T) { |
| 179 | if _, err := jsonconf.Bool("unknown"); err == nil { | 186 | if _, err := jsonconf.Bool("unknown"); err == nil { |
| 180 | t.Error("unknown keys should return an error when expecting a Bool") | 187 | t.Error("unknown keys should return an error when expecting a Bool") |
| 181 | } | 188 | } |
| 189 | |||
| 190 | if !jsonconf.DefaultBool("unknow", true) { | ||
| 191 | t.Error("unknown keys with default value wrong") | ||
| 192 | } | ||
| 182 | } | 193 | } | ... | ... |
| ... | @@ -31,7 +31,6 @@ import ( | ... | @@ -31,7 +31,6 @@ import ( |
| 31 | "strings" | 31 | "strings" |
| 32 | "time" | 32 | "time" |
| 33 | 33 | ||
| 34 | "github.com/astaxie/beego/middleware" | ||
| 35 | "github.com/astaxie/beego/utils" | 34 | "github.com/astaxie/beego/utils" |
| 36 | ) | 35 | ) |
| 37 | 36 | ||
| ... | @@ -53,22 +52,9 @@ func (ctx *Context) Redirect(status int, localurl string) { | ... | @@ -53,22 +52,9 @@ func (ctx *Context) Redirect(status int, localurl string) { |
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | // Abort stops this request. | 54 | // Abort stops this request. |
| 56 | // if middleware.ErrorMaps exists, panic body. | 55 | // if beego.ErrorMaps exists, panic body. |
| 57 | // if middleware.HTTPExceptionMaps exists, panic HTTPException struct with status and body string. | ||
| 58 | func (ctx *Context) Abort(status int, body string) { | 56 | func (ctx *Context) Abort(status int, body string) { |
| 59 | ctx.ResponseWriter.WriteHeader(status) | 57 | ctx.ResponseWriter.WriteHeader(status) |
| 60 | // first panic from ErrorMaps, is is user defined error functions. | ||
| 61 | if _, ok := middleware.ErrorMaps[body]; ok { | ||
| 62 | panic(body) | ||
| 63 | } | ||
| 64 | // second panic from HTTPExceptionMaps, it is system defined functions. | ||
| 65 | if e, ok := middleware.HTTPExceptionMaps[status]; ok { | ||
| 66 | if len(body) >= 1 { | ||
| 67 | e.Description = body | ||
| 68 | } | ||
| 69 | panic(e) | ||
| 70 | } | ||
| 71 | // last panic user string | ||
| 72 | panic(body) | 58 | panic(body) |
| 73 | } | 59 | } |
| 74 | 60 | ||
| ... | @@ -154,8 +140,11 @@ func (ctx *Context) CheckXsrfCookie() bool { | ... | @@ -154,8 +140,11 @@ func (ctx *Context) CheckXsrfCookie() bool { |
| 154 | } | 140 | } |
| 155 | if token == "" { | 141 | if token == "" { |
| 156 | ctx.Abort(403, "'_xsrf' argument missing from POST") | 142 | ctx.Abort(403, "'_xsrf' argument missing from POST") |
| 157 | } else if ctx._xsrf_token != token { | 143 | return false |
| 144 | } | ||
| 145 | if ctx._xsrf_token != token { | ||
| 158 | ctx.Abort(403, "XSRF cookie does not match POST argument") | 146 | ctx.Abort(403, "XSRF cookie does not match POST argument") |
| 147 | return false | ||
| 159 | } | 148 | } |
| 160 | return true | 149 | return true |
| 161 | } | 150 | } | ... | ... |
| ... | @@ -27,7 +27,7 @@ import ( | ... | @@ -27,7 +27,7 @@ import ( |
| 27 | "github.com/astaxie/beego/session" | 27 | "github.com/astaxie/beego/session" |
| 28 | ) | 28 | ) |
| 29 | 29 | ||
| 30 | // BeegoInput operates the http request header ,data ,cookie and body. | 30 | // BeegoInput operates the http request header, data, cookie and body. |
| 31 | // it also contains router params and current session. | 31 | // it also contains router params and current session. |
| 32 | type BeegoInput struct { | 32 | type BeegoInput struct { |
| 33 | CruSession session.SessionStore | 33 | CruSession session.SessionStore |
| ... | @@ -72,11 +72,11 @@ func (input *BeegoInput) Site() string { | ... | @@ -72,11 +72,11 @@ func (input *BeegoInput) Site() string { |
| 72 | func (input *BeegoInput) Scheme() string { | 72 | func (input *BeegoInput) Scheme() string { |
| 73 | if input.Request.URL.Scheme != "" { | 73 | if input.Request.URL.Scheme != "" { |
| 74 | return input.Request.URL.Scheme | 74 | return input.Request.URL.Scheme |
| 75 | } else if input.Request.TLS == nil { | 75 | } |
| 76 | if input.Request.TLS == nil { | ||
| 76 | return "http" | 77 | return "http" |
| 77 | } else { | ||
| 78 | return "https" | ||
| 79 | } | 78 | } |
| 79 | return "https" | ||
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | // Domain returns host name. | 82 | // Domain returns host name. |
| ... | @@ -153,12 +153,12 @@ func (input *BeegoInput) IsSecure() bool { | ... | @@ -153,12 +153,12 @@ func (input *BeegoInput) IsSecure() bool { |
| 153 | return input.Scheme() == "https" | 153 | return input.Scheme() == "https" |
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | // IsSecure returns boolean of this request is in webSocket. | 156 | // IsWebsocket returns boolean of this request is in webSocket. |
| 157 | func (input *BeegoInput) IsWebsocket() bool { | 157 | func (input *BeegoInput) IsWebsocket() bool { |
| 158 | return input.Header("Upgrade") == "websocket" | 158 | return input.Header("Upgrade") == "websocket" |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | // IsSecure returns boolean of whether file uploads in this request or not.. | 161 | // IsUpload returns boolean of whether file uploads in this request or not.. |
| 162 | func (input *BeegoInput) IsUpload() bool { | 162 | func (input *BeegoInput) IsUpload() bool { |
| 163 | return strings.Contains(input.Header("Content-Type"), "multipart/form-data") | 163 | return strings.Contains(input.Header("Content-Type"), "multipart/form-data") |
| 164 | } | 164 | } |
| ... | @@ -189,16 +189,24 @@ func (input *BeegoInput) Proxy() []string { | ... | @@ -189,16 +189,24 @@ func (input *BeegoInput) Proxy() []string { |
| 189 | return []string{} | 189 | return []string{} |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | // Referer returns http referer header. | ||
| 193 | func (input *BeegoInput) Referer() string { | ||
| 194 | return input.Header("Referer") | ||
| 195 | } | ||
| 196 | |||
| 192 | // Refer returns http referer header. | 197 | // Refer returns http referer header. |
| 193 | func (input *BeegoInput) Refer() string { | 198 | func (input *BeegoInput) Refer() string { |
| 194 | return input.Header("Referer") | 199 | return input.Referer() |
| 195 | } | 200 | } |
| 196 | 201 | ||
| 197 | // SubDomains returns sub domain string. | 202 | // SubDomains returns sub domain string. |
| 198 | // if aa.bb.domain.com, returns aa.bb . | 203 | // if aa.bb.domain.com, returns aa.bb . |
| 199 | func (input *BeegoInput) SubDomains() string { | 204 | func (input *BeegoInput) SubDomains() string { |
| 200 | parts := strings.Split(input.Host(), ".") | 205 | parts := strings.Split(input.Host(), ".") |
| 201 | return strings.Join(parts[len(parts)-2:], ".") | 206 | if len(parts) >= 3 { |
| 207 | return strings.Join(parts[:len(parts)-2], ".") | ||
| 208 | } | ||
| 209 | return "" | ||
| 202 | } | 210 | } |
| 203 | 211 | ||
| 204 | // Port returns request client port. | 212 | // Port returns request client port. |
| ... | @@ -237,6 +245,7 @@ func (input *BeegoInput) Query(key string) string { | ... | @@ -237,6 +245,7 @@ func (input *BeegoInput) Query(key string) string { |
| 237 | } | 245 | } |
| 238 | 246 | ||
| 239 | // Header returns request header item string by a given string. | 247 | // Header returns request header item string by a given string. |
| 248 | // if non-existed, return empty string. | ||
| 240 | func (input *BeegoInput) Header(key string) string { | 249 | func (input *BeegoInput) Header(key string) string { |
| 241 | return input.Request.Header.Get(key) | 250 | return input.Request.Header.Get(key) |
| 242 | } | 251 | } |
| ... | @@ -252,11 +261,12 @@ func (input *BeegoInput) Cookie(key string) string { | ... | @@ -252,11 +261,12 @@ func (input *BeegoInput) Cookie(key string) string { |
| 252 | } | 261 | } |
| 253 | 262 | ||
| 254 | // Session returns current session item value by a given key. | 263 | // Session returns current session item value by a given key. |
| 264 | // if non-existed, return empty string. | ||
| 255 | func (input *BeegoInput) Session(key interface{}) interface{} { | 265 | func (input *BeegoInput) Session(key interface{}) interface{} { |
| 256 | return input.CruSession.Get(key) | 266 | return input.CruSession.Get(key) |
| 257 | } | 267 | } |
| 258 | 268 | ||
| 259 | // Body returns the raw request body data as bytes. | 269 | // CopyBody returns the raw request body data as bytes. |
| 260 | func (input *BeegoInput) CopyBody() []byte { | 270 | func (input *BeegoInput) CopyBody() []byte { |
| 261 | requestbody, _ := ioutil.ReadAll(input.Request.Body) | 271 | requestbody, _ := ioutil.ReadAll(input.Request.Body) |
| 262 | input.Request.Body.Close() | 272 | input.Request.Body.Close() | ... | ... |
| ... | @@ -70,3 +70,45 @@ func TestParse(t *testing.T) { | ... | @@ -70,3 +70,45 @@ func TestParse(t *testing.T) { |
| 70 | } | 70 | } |
| 71 | fmt.Println(user) | 71 | fmt.Println(user) |
| 72 | } | 72 | } |
| 73 | |||
| 74 | func TestSubDomain(t *testing.T) { | ||
| 75 | r, _ := http.NewRequest("GET", "http://www.example.com/?id=123&isok=true&ft=1.2&ol[0]=1&ol[1]=2&ul[]=str&ul[]=array&user.Name=astaxie", nil) | ||
| 76 | beegoInput := NewInput(r) | ||
| 77 | |||
| 78 | subdomain := beegoInput.SubDomains() | ||
| 79 | if subdomain != "www" { | ||
| 80 | t.Fatal("Subdomain parse error, got" + subdomain) | ||
| 81 | } | ||
| 82 | |||
| 83 | r, _ = http.NewRequest("GET", "http://localhost/", nil) | ||
| 84 | beegoInput.Request = r | ||
| 85 | if beegoInput.SubDomains() != "" { | ||
| 86 | t.Fatal("Subdomain parse error, should be empty, got " + beegoInput.SubDomains()) | ||
| 87 | } | ||
| 88 | |||
| 89 | r, _ = http.NewRequest("GET", "http://aa.bb.example.com/", nil) | ||
| 90 | beegoInput.Request = r | ||
| 91 | if beegoInput.SubDomains() != "aa.bb" { | ||
| 92 | t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) | ||
| 93 | } | ||
| 94 | |||
| 95 | /* TODO Fix this | ||
| 96 | r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil) | ||
| 97 | beegoInput.Request = r | ||
| 98 | if beegoInput.SubDomains() != "" { | ||
| 99 | t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) | ||
| 100 | } | ||
| 101 | */ | ||
| 102 | |||
| 103 | r, _ = http.NewRequest("GET", "http://example.com/", nil) | ||
| 104 | beegoInput.Request = r | ||
| 105 | if beegoInput.SubDomains() != "" { | ||
| 106 | t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) | ||
| 107 | } | ||
| 108 | |||
| 109 | r, _ = http.NewRequest("GET", "http://aa.bb.cc.dd.example.com/", nil) | ||
| 110 | beegoInput.Request = r | ||
| 111 | if beegoInput.SubDomains() != "aa.bb.cc.dd" { | ||
| 112 | t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains()) | ||
| 113 | } | ||
| 114 | } | ... | ... |
| ... | @@ -188,7 +188,7 @@ func sanitizeValue(v string) string { | ... | @@ -188,7 +188,7 @@ func sanitizeValue(v string) string { |
| 188 | // Json writes json to response body. | 188 | // Json writes json to response body. |
| 189 | // if coding is true, it converts utf-8 to \u0000 type. | 189 | // if coding is true, it converts utf-8 to \u0000 type. |
| 190 | func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) error { | 190 | func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) error { |
| 191 | output.Header("Content-Type", "application/json;charset=UTF-8") | 191 | output.Header("Content-Type", "application/json; charset=utf-8") |
| 192 | var content []byte | 192 | var content []byte |
| 193 | var err error | 193 | var err error |
| 194 | if hasIndent { | 194 | if hasIndent { |
| ... | @@ -209,7 +209,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e | ... | @@ -209,7 +209,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e |
| 209 | 209 | ||
| 210 | // Jsonp writes jsonp to response body. | 210 | // Jsonp writes jsonp to response body. |
| 211 | func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { | 211 | func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { |
| 212 | output.Header("Content-Type", "application/javascript;charset=UTF-8") | 212 | output.Header("Content-Type", "application/javascript; charset=utf-8") |
| 213 | var content []byte | 213 | var content []byte |
| 214 | var err error | 214 | var err error |
| 215 | if hasIndent { | 215 | if hasIndent { |
| ... | @@ -235,7 +235,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { | ... | @@ -235,7 +235,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error { |
| 235 | 235 | ||
| 236 | // Xml writes xml string to response body. | 236 | // Xml writes xml string to response body. |
| 237 | func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error { | 237 | func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error { |
| 238 | output.Header("Content-Type", "application/xml;charset=UTF-8") | 238 | output.Header("Content-Type", "application/xml; charset=utf-8") |
| 239 | var content []byte | 239 | var content []byte |
| 240 | var err error | 240 | var err error |
| 241 | if hasIndent { | 241 | if hasIndent { | ... | ... |
| ... | @@ -270,16 +270,22 @@ func (c *Controller) Redirect(url string, code int) { | ... | @@ -270,16 +270,22 @@ func (c *Controller) Redirect(url string, code int) { |
| 270 | // Aborts stops controller handler and show the error data if code is defined in ErrorMap or code string. | 270 | // Aborts stops controller handler and show the error data if code is defined in ErrorMap or code string. |
| 271 | func (c *Controller) Abort(code string) { | 271 | func (c *Controller) Abort(code string) { |
| 272 | status, err := strconv.Atoi(code) | 272 | status, err := strconv.Atoi(code) |
| 273 | if err == nil { | 273 | if err != nil { |
| 274 | c.Ctx.Abort(status, code) | 274 | status = 200 |
| 275 | } else { | ||
| 276 | c.Ctx.Abort(200, code) | ||
| 277 | } | 275 | } |
| 276 | c.CustomAbort(status, code) | ||
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. | 279 | // CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body. |
| 281 | func (c *Controller) CustomAbort(status int, body string) { | 280 | func (c *Controller) CustomAbort(status int, body string) { |
| 282 | c.Ctx.Abort(status, body) | 281 | c.Ctx.ResponseWriter.WriteHeader(status) |
| 282 | // first panic from ErrorMaps, is is user defined error functions. | ||
| 283 | if _, ok := ErrorMaps[body]; ok { | ||
| 284 | panic(body) | ||
| 285 | } | ||
| 286 | // last panic user string | ||
| 287 | c.Ctx.ResponseWriter.Write([]byte(body)) | ||
| 288 | panic(USERSTOPRUN) | ||
| 283 | } | 289 | } |
| 284 | 290 | ||
| 285 | // StopRun makes panic of USERSTOPRUN error and go to recover function if defined. | 291 | // StopRun makes panic of USERSTOPRUN error and go to recover function if defined. |
| ... | @@ -289,7 +295,7 @@ func (c *Controller) StopRun() { | ... | @@ -289,7 +295,7 @@ func (c *Controller) StopRun() { |
| 289 | 295 | ||
| 290 | // UrlFor does another controller handler in this request function. | 296 | // UrlFor does another controller handler in this request function. |
| 291 | // it goes to this controller method if endpoint is not clear. | 297 | // it goes to this controller method if endpoint is not clear. |
| 292 | func (c *Controller) UrlFor(endpoint string, values ...string) string { | 298 | func (c *Controller) UrlFor(endpoint string, values ...interface{}) string { |
| 293 | if len(endpoint) <= 0 { | 299 | if len(endpoint) <= 0 { |
| 294 | return "" | 300 | return "" |
| 295 | } | 301 | } |
| ... | @@ -363,67 +369,144 @@ func (c *Controller) ParseForm(obj interface{}) error { | ... | @@ -363,67 +369,144 @@ func (c *Controller) ParseForm(obj interface{}) error { |
| 363 | return ParseForm(c.Input(), obj) | 369 | return ParseForm(c.Input(), obj) |
| 364 | } | 370 | } |
| 365 | 371 | ||
| 366 | // GetString returns the input value by key string. | 372 | // GetString returns the input value by key string or the default value while it's present and input is blank |
| 367 | func (c *Controller) GetString(key string) string { | 373 | func (c *Controller) GetString(key string, def ...string) string { |
| 368 | return c.Ctx.Input.Query(key) | 374 | var defv string |
| 375 | if len(def) > 0 { | ||
| 376 | defv = def[0] | ||
| 377 | } | ||
| 378 | |||
| 379 | if v := c.Ctx.Input.Query(key); v != "" { | ||
| 380 | return v | ||
| 381 | } else { | ||
| 382 | return defv | ||
| 383 | } | ||
| 369 | } | 384 | } |
| 370 | 385 | ||
| 371 | // GetStrings returns the input string slice by key string. | 386 | // GetStrings returns the input string slice by key string or the default value while it's present and input is blank |
| 372 | // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection. | 387 | // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection. |
| 373 | func (c *Controller) GetStrings(key string) []string { | 388 | func (c *Controller) GetStrings(key string, def ...[]string) []string { |
| 389 | var defv []string | ||
| 390 | if len(def) > 0 { | ||
| 391 | defv = def[0] | ||
| 392 | } | ||
| 393 | |||
| 374 | f := c.Input() | 394 | f := c.Input() |
| 375 | if f == nil { | 395 | if f == nil { |
| 376 | return []string{} | 396 | return defv |
| 377 | } | 397 | } |
| 398 | |||
| 378 | vs := f[key] | 399 | vs := f[key] |
| 379 | if len(vs) > 0 { | 400 | if len(vs) > 0 { |
| 380 | return vs | 401 | return vs |
| 402 | } else { | ||
| 403 | return defv | ||
| 381 | } | 404 | } |
| 382 | return []string{} | ||
| 383 | } | 405 | } |
| 384 | 406 | ||
| 385 | // GetInt returns input as an int | 407 | // GetInt returns input as an int or the default value while it's present and input is blank |
| 386 | func (c *Controller) GetInt(key string) (int, error) { | 408 | func (c *Controller) GetInt(key string, def ...int) (int, error) { |
| 387 | return strconv.Atoi(c.Ctx.Input.Query(key)) | 409 | var defv int |
| 410 | if len(def) > 0 { | ||
| 411 | defv = def[0] | ||
| 412 | } | ||
| 413 | |||
| 414 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 415 | return strconv.Atoi(strv) | ||
| 416 | } else { | ||
| 417 | return defv, nil | ||
| 418 | } | ||
| 388 | } | 419 | } |
| 389 | 420 | ||
| 390 | // GetInt8 return input as an int8 | 421 | // GetInt8 return input as an int8 or the default value while it's present and input is blank |
| 391 | func (c *Controller) GetInt8(key string) (int8, error) { | 422 | func (c *Controller) GetInt8(key string, def ...int8) (int8, error) { |
| 392 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 8) | 423 | var defv int8 |
| 393 | i8 := int8(i64) | 424 | if len(def) > 0 { |
| 425 | defv = def[0] | ||
| 426 | } | ||
| 394 | 427 | ||
| 395 | return i8, err | 428 | if strv := c.Ctx.Input.Query(key); strv != "" { |
| 429 | i64, err := strconv.ParseInt(strv, 10, 8) | ||
| 430 | i8 := int8(i64) | ||
| 431 | return i8, err | ||
| 432 | } else { | ||
| 433 | return defv, nil | ||
| 434 | } | ||
| 396 | } | 435 | } |
| 397 | 436 | ||
| 398 | // GetInt16 returns input as an int16 | 437 | // GetInt16 returns input as an int16 or the default value while it's present and input is blank |
| 399 | func (c *Controller) GetInt16(key string) (int16, error) { | 438 | func (c *Controller) GetInt16(key string, def ...int16) (int16, error) { |
| 400 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 16) | 439 | var defv int16 |
| 401 | i16 := int16(i64) | 440 | if len(def) > 0 { |
| 441 | defv = def[0] | ||
| 442 | } | ||
| 443 | |||
| 444 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 445 | i64, err := strconv.ParseInt(strv, 10, 16) | ||
| 446 | i16 := int16(i64) | ||
| 402 | 447 | ||
| 403 | return i16, err | 448 | return i16, err |
| 449 | } else { | ||
| 450 | return defv, nil | ||
| 451 | } | ||
| 404 | } | 452 | } |
| 405 | 453 | ||
| 406 | // GetInt32 returns input as an int32 | 454 | // GetInt32 returns input as an int32 or the default value while it's present and input is blank |
| 407 | func (c *Controller) GetInt32(key string) (int32, error) { | 455 | func (c *Controller) GetInt32(key string, def ...int32) (int32, error) { |
| 408 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32) | 456 | var defv int32 |
| 409 | i32 := int32(i64) | 457 | if len(def) > 0 { |
| 458 | defv = def[0] | ||
| 459 | } | ||
| 410 | 460 | ||
| 411 | return i32, err | 461 | if strv := c.Ctx.Input.Query(key); strv != "" { |
| 462 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32) | ||
| 463 | i32 := int32(i64) | ||
| 464 | return i32, err | ||
| 465 | } else { | ||
| 466 | return defv, nil | ||
| 467 | } | ||
| 412 | } | 468 | } |
| 413 | 469 | ||
| 414 | // GetInt64 returns input value as int64. | 470 | // GetInt64 returns input value as int64 or the default value while it's present and input is blank. |
| 415 | func (c *Controller) GetInt64(key string) (int64, error) { | 471 | func (c *Controller) GetInt64(key string, def ...int64) (int64, error) { |
| 416 | return strconv.ParseInt(c.Ctx.Input.Query(key), 10, 64) | 472 | var defv int64 |
| 473 | if len(def) > 0 { | ||
| 474 | defv = def[0] | ||
| 475 | } | ||
| 476 | |||
| 477 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 478 | return strconv.ParseInt(strv, 10, 64) | ||
| 479 | } else { | ||
| 480 | return defv, nil | ||
| 481 | } | ||
| 417 | } | 482 | } |
| 418 | 483 | ||
| 419 | // GetBool returns input value as bool. | 484 | // GetBool returns input value as bool or the default value while it's present and input is blank. |
| 420 | func (c *Controller) GetBool(key string) (bool, error) { | 485 | func (c *Controller) GetBool(key string, def ...bool) (bool, error) { |
| 421 | return strconv.ParseBool(c.Ctx.Input.Query(key)) | 486 | var defv bool |
| 487 | if len(def) > 0 { | ||
| 488 | defv = def[0] | ||
| 489 | } | ||
| 490 | |||
| 491 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 492 | return strconv.ParseBool(strv) | ||
| 493 | } else { | ||
| 494 | return defv, nil | ||
| 495 | } | ||
| 422 | } | 496 | } |
| 423 | 497 | ||
| 424 | // GetFloat returns input value as float64. | 498 | // GetFloat returns input value as float64 or the default value while it's present and input is blank. |
| 425 | func (c *Controller) GetFloat(key string) (float64, error) { | 499 | func (c *Controller) GetFloat(key string, def ...float64) (float64, error) { |
| 426 | return strconv.ParseFloat(c.Ctx.Input.Query(key), 64) | 500 | var defv float64 |
| 501 | if len(def) > 0 { | ||
| 502 | defv = def[0] | ||
| 503 | } | ||
| 504 | |||
| 505 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 506 | return strconv.ParseFloat(c.Ctx.Input.Query(key), 64) | ||
| 507 | } else { | ||
| 508 | return defv, nil | ||
| 509 | } | ||
| 427 | } | 510 | } |
| 428 | 511 | ||
| 429 | // GetFile returns the file data in file upload field named as key. | 512 | // GetFile returns the file data in file upload field named as key. | ... | ... |
This diff is collapsed.
Click to expand it.
| ... | @@ -17,47 +17,47 @@ type ObjectController struct { | ... | @@ -17,47 +17,47 @@ type ObjectController struct { |
| 17 | beego.Controller | 17 | beego.Controller |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | func (this *ObjectController) Post() { | 20 | func (o *ObjectController) Post() { |
| 21 | var ob models.Object | 21 | var ob models.Object |
| 22 | json.Unmarshal(this.Ctx.Input.RequestBody, &ob) | 22 | json.Unmarshal(o.Ctx.Input.RequestBody, &ob) |
| 23 | objectid := models.AddOne(ob) | 23 | objectid := models.AddOne(ob) |
| 24 | this.Data["json"] = map[string]string{"ObjectId": objectid} | 24 | o.Data["json"] = map[string]string{"ObjectId": objectid} |
| 25 | this.ServeJson() | 25 | o.ServeJson() |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | func (this *ObjectController) Get() { | 28 | func (o *ObjectController) Get() { |
| 29 | objectId := this.Ctx.Input.Params[":objectId"] | 29 | objectId := o.Ctx.Input.Params[":objectId"] |
| 30 | if objectId != "" { | 30 | if objectId != "" { |
| 31 | ob, err := models.GetOne(objectId) | 31 | ob, err := models.GetOne(objectId) |
| 32 | if err != nil { | 32 | if err != nil { |
| 33 | this.Data["json"] = err | 33 | o.Data["json"] = err |
| 34 | } else { | 34 | } else { |
| 35 | this.Data["json"] = ob | 35 | o.Data["json"] = ob |
| 36 | } | 36 | } |
| 37 | } else { | 37 | } else { |
| 38 | obs := models.GetAll() | 38 | obs := models.GetAll() |
| 39 | this.Data["json"] = obs | 39 | o.Data["json"] = obs |
| 40 | } | 40 | } |
| 41 | this.ServeJson() | 41 | o.ServeJson() |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | func (this *ObjectController) Put() { | 44 | func (o *ObjectController) Put() { |
| 45 | objectId := this.Ctx.Input.Params[":objectId"] | 45 | objectId := o.Ctx.Input.Params[":objectId"] |
| 46 | var ob models.Object | 46 | var ob models.Object |
| 47 | json.Unmarshal(this.Ctx.Input.RequestBody, &ob) | 47 | json.Unmarshal(o.Ctx.Input.RequestBody, &ob) |
| 48 | 48 | ||
| 49 | err := models.Update(objectId, ob.Score) | 49 | err := models.Update(objectId, ob.Score) |
| 50 | if err != nil { | 50 | if err != nil { |
| 51 | this.Data["json"] = err | 51 | o.Data["json"] = err |
| 52 | } else { | 52 | } else { |
| 53 | this.Data["json"] = "update success!" | 53 | o.Data["json"] = "update success!" |
| 54 | } | 54 | } |
| 55 | this.ServeJson() | 55 | o.ServeJson() |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | func (this *ObjectController) Delete() { | 58 | func (o *ObjectController) Delete() { |
| 59 | objectId := this.Ctx.Input.Params[":objectId"] | 59 | objectId := o.Ctx.Input.Params[":objectId"] |
| 60 | models.Delete(objectId) | 60 | models.Delete(objectId) |
| 61 | this.Data["json"] = "delete success!" | 61 | o.Data["json"] = "delete success!" |
| 62 | this.ServeJson() | 62 | o.ServeJson() |
| 63 | } | 63 | } | ... | ... |
| ... | @@ -14,7 +14,7 @@ type MainController struct { | ... | @@ -14,7 +14,7 @@ type MainController struct { |
| 14 | beego.Controller | 14 | beego.Controller |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | func (this *MainController) Get() { | 17 | func (m *MainController) Get() { |
| 18 | this.Data["host"] = this.Ctx.Request.Host | 18 | m.Data["host"] = m.Ctx.Request.Host |
| 19 | this.TplNames = "index.tpl" | 19 | m.TplNames = "index.tpl" |
| 20 | } | 20 | } | ... | ... |
| ... | @@ -150,14 +150,14 @@ type WSController struct { | ... | @@ -150,14 +150,14 @@ type WSController struct { |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | var upgrader = websocket.Upgrader{ | 152 | var upgrader = websocket.Upgrader{ |
| 153 | ReadBufferSize: 1024, | 153 | ReadBufferSize: 1024, |
| 154 | WriteBufferSize: 1024, | 154 | WriteBufferSize: 1024, |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | func (this *WSController) Get() { | 157 | func (w *WSController) Get() { |
| 158 | ws, err := upgrader.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request,nil) | 158 | ws, err := upgrader.Upgrade(w.Ctx.ResponseWriter, w.Ctx.Request, nil) |
| 159 | if _, ok := err.(websocket.HandshakeError); ok { | 159 | if _, ok := err.(websocket.HandshakeError); ok { |
| 160 | http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400) | 160 | http.Error(w.Ctx.ResponseWriter, "Not a websocket handshake", 400) |
| 161 | return | 161 | return |
| 162 | } else if err != nil { | 162 | } else if err != nil { |
| 163 | return | 163 | return | ... | ... |
| ... | @@ -2,7 +2,7 @@ | ... | @@ -2,7 +2,7 @@ |
| 2 | <html lang="en"> | 2 | <html lang="en"> |
| 3 | <head> | 3 | <head> |
| 4 | <title>Chat Example</title> | 4 | <title>Chat Example</title> |
| 5 | <script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> | 5 | <script src="//code.jquery.com/jquery-2.1.3.min.js"></script> |
| 6 | <script type="text/javascript"> | 6 | <script type="text/javascript"> |
| 7 | $(function() { | 7 | $(function() { |
| 8 | 8 | ... | ... |
| ... | @@ -14,6 +14,11 @@ | ... | @@ -14,6 +14,11 @@ |
| 14 | 14 | ||
| 15 | package beego | 15 | package beego |
| 16 | 16 | ||
| 17 | import "github.com/astaxie/beego/context" | ||
| 18 | |||
| 19 | // FilterFunc defines filter function type. | ||
| 20 | type FilterFunc func(*context.Context) | ||
| 21 | |||
| 17 | // FilterRouter defines filter operation before controller handler execution. | 22 | // FilterRouter defines filter operation before controller handler execution. |
| 18 | // it can match patterned url and do filter function when action arrives. | 23 | // it can match patterned url and do filter function when action arrives. |
| 19 | type FilterRouter struct { | 24 | type FilterRouter struct { | ... | ... |
| ... | @@ -25,12 +25,12 @@ type TestFlashController struct { | ... | @@ -25,12 +25,12 @@ type TestFlashController struct { |
| 25 | Controller | 25 | Controller |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | func (this *TestFlashController) TestWriteFlash() { | 28 | func (t *TestFlashController) TestWriteFlash() { |
| 29 | flash := NewFlash() | 29 | flash := NewFlash() |
| 30 | flash.Notice("TestFlashString") | 30 | flash.Notice("TestFlashString") |
| 31 | flash.Store(&this.Controller) | 31 | flash.Store(&t.Controller) |
| 32 | // we choose to serve json because we don't want to load a template html file | 32 | // we choose to serve json because we don't want to load a template html file |
| 33 | this.ServeJson(true) | 33 | t.ServeJson(true) |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | func TestFlashHeader(t *testing.T) { | 36 | func TestFlashHeader(t *testing.T) { | ... | ... |
| ... | @@ -37,6 +37,7 @@ import ( | ... | @@ -37,6 +37,7 @@ import ( |
| 37 | "encoding/xml" | 37 | "encoding/xml" |
| 38 | "io" | 38 | "io" |
| 39 | "io/ioutil" | 39 | "io/ioutil" |
| 40 | "log" | ||
| 40 | "mime/multipart" | 41 | "mime/multipart" |
| 41 | "net" | 42 | "net" |
| 42 | "net/http" | 43 | "net/http" |
| ... | @@ -252,6 +253,59 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest { | ... | @@ -252,6 +253,59 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest { |
| 252 | return b | 253 | return b |
| 253 | } | 254 | } |
| 254 | 255 | ||
| 256 | func (b *BeegoHttpRequest) buildUrl(paramBody string) { | ||
| 257 | // build GET url with query string | ||
| 258 | if b.req.Method == "GET" && len(paramBody) > 0 { | ||
| 259 | if strings.Index(b.url, "?") != -1 { | ||
| 260 | b.url += "&" + paramBody | ||
| 261 | } else { | ||
| 262 | b.url = b.url + "?" + paramBody | ||
| 263 | } | ||
| 264 | return | ||
| 265 | } | ||
| 266 | |||
| 267 | // build POST url and body | ||
| 268 | if b.req.Method == "POST" && b.req.Body == nil { | ||
| 269 | // with files | ||
| 270 | if len(b.files) > 0 { | ||
| 271 | pr, pw := io.Pipe() | ||
| 272 | bodyWriter := multipart.NewWriter(pw) | ||
| 273 | go func() { | ||
| 274 | for formname, filename := range b.files { | ||
| 275 | fileWriter, err := bodyWriter.CreateFormFile(formname, filename) | ||
| 276 | if err != nil { | ||
| 277 | log.Fatal(err) | ||
| 278 | } | ||
| 279 | fh, err := os.Open(filename) | ||
| 280 | if err != nil { | ||
| 281 | log.Fatal(err) | ||
| 282 | } | ||
| 283 | //iocopy | ||
| 284 | _, err = io.Copy(fileWriter, fh) | ||
| 285 | fh.Close() | ||
| 286 | if err != nil { | ||
| 287 | log.Fatal(err) | ||
| 288 | } | ||
| 289 | } | ||
| 290 | for k, v := range b.params { | ||
| 291 | bodyWriter.WriteField(k, v) | ||
| 292 | } | ||
| 293 | bodyWriter.Close() | ||
| 294 | pw.Close() | ||
| 295 | }() | ||
| 296 | b.Header("Content-Type", bodyWriter.FormDataContentType()) | ||
| 297 | b.req.Body = ioutil.NopCloser(pr) | ||
| 298 | return | ||
| 299 | } | ||
| 300 | |||
| 301 | // with params | ||
| 302 | if len(paramBody) > 0 { | ||
| 303 | b.Header("Content-Type", "application/x-www-form-urlencoded") | ||
| 304 | b.Body(paramBody) | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 255 | func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | 309 | func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 256 | if b.resp.StatusCode != 0 { | 310 | if b.resp.StatusCode != 0 { |
| 257 | return b.resp, nil | 311 | return b.resp, nil |
| ... | @@ -269,46 +323,7 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ... | @@ -269,46 +323,7 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 269 | paramBody = paramBody[0 : len(paramBody)-1] | 323 | paramBody = paramBody[0 : len(paramBody)-1] |
| 270 | } | 324 | } |
| 271 | 325 | ||
| 272 | if b.req.Method == "GET" && len(paramBody) > 0 { | 326 | b.buildUrl(paramBody) |
| 273 | if strings.Index(b.url, "?") != -1 { | ||
| 274 | b.url += "&" + paramBody | ||
| 275 | } else { | ||
| 276 | b.url = b.url + "?" + paramBody | ||
| 277 | } | ||
| 278 | } else if b.req.Method == "POST" && b.req.Body == nil && len(paramBody) > 0 { | ||
| 279 | if len(b.files) > 0 { | ||
| 280 | bodyBuf := &bytes.Buffer{} | ||
| 281 | bodyWriter := multipart.NewWriter(bodyBuf) | ||
| 282 | for formname, filename := range b.files { | ||
| 283 | fileWriter, err := bodyWriter.CreateFormFile(formname, filename) | ||
| 284 | if err != nil { | ||
| 285 | return nil, err | ||
| 286 | } | ||
| 287 | fh, err := os.Open(filename) | ||
| 288 | if err != nil { | ||
| 289 | return nil, err | ||
| 290 | } | ||
| 291 | //iocopy | ||
| 292 | _, err = io.Copy(fileWriter, fh) | ||
| 293 | fh.Close() | ||
| 294 | if err != nil { | ||
| 295 | return nil, err | ||
| 296 | } | ||
| 297 | } | ||
| 298 | for k, v := range b.params { | ||
| 299 | bodyWriter.WriteField(k, v) | ||
| 300 | } | ||
| 301 | contentType := bodyWriter.FormDataContentType() | ||
| 302 | bodyWriter.Close() | ||
| 303 | b.Header("Content-Type", contentType) | ||
| 304 | b.req.Body = ioutil.NopCloser(bodyBuf) | ||
| 305 | b.req.ContentLength = int64(bodyBuf.Len()) | ||
| 306 | } else { | ||
| 307 | b.Header("Content-Type", "application/x-www-form-urlencoded") | ||
| 308 | b.Body(paramBody) | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | url, err := url.Parse(b.url) | 327 | url, err := url.Parse(b.url) |
| 313 | if err != nil { | 328 | if err != nil { |
| 314 | return nil, err | 329 | return nil, err |
| ... | @@ -340,14 +355,12 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ... | @@ -340,14 +355,12 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 340 | } | 355 | } |
| 341 | } | 356 | } |
| 342 | 357 | ||
| 343 | var jar http.CookieJar | 358 | var jar http.CookieJar = nil |
| 344 | if b.setting.EnableCookie { | 359 | if b.setting.EnableCookie { |
| 345 | if defaultCookieJar == nil { | 360 | if defaultCookieJar == nil { |
| 346 | createDefaultCookie() | 361 | createDefaultCookie() |
| 347 | } | 362 | } |
| 348 | jar = defaultCookieJar | 363 | jar = defaultCookieJar |
| 349 | } else { | ||
| 350 | jar = nil | ||
| 351 | } | 364 | } |
| 352 | 365 | ||
| 353 | client := &http.Client{ | 366 | client := &http.Client{ |
| ... | @@ -400,12 +413,11 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { | ... | @@ -400,12 +413,11 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { |
| 400 | return nil, nil | 413 | return nil, nil |
| 401 | } | 414 | } |
| 402 | defer resp.Body.Close() | 415 | defer resp.Body.Close() |
| 403 | data, err := ioutil.ReadAll(resp.Body) | 416 | b.body, err = ioutil.ReadAll(resp.Body) |
| 404 | if err != nil { | 417 | if err != nil { |
| 405 | return nil, err | 418 | return nil, err |
| 406 | } | 419 | } |
| 407 | b.body = data | 420 | return b.body, nil |
| 408 | return data, nil | ||
| 409 | } | 421 | } |
| 410 | 422 | ||
| 411 | // ToFile saves the body data in response to one file. | 423 | // ToFile saves the body data in response to one file. |
| ... | @@ -436,8 +448,7 @@ func (b *BeegoHttpRequest) ToJson(v interface{}) error { | ... | @@ -436,8 +448,7 @@ func (b *BeegoHttpRequest) ToJson(v interface{}) error { |
| 436 | if err != nil { | 448 | if err != nil { |
| 437 | return err | 449 | return err |
| 438 | } | 450 | } |
| 439 | err = json.Unmarshal(data, v) | 451 | return json.Unmarshal(data, v) |
| 440 | return err | ||
| 441 | } | 452 | } |
| 442 | 453 | ||
| 443 | // ToXml returns the map that marshals from the body bytes as xml in response . | 454 | // ToXml returns the map that marshals from the body bytes as xml in response . |
| ... | @@ -447,8 +458,7 @@ func (b *BeegoHttpRequest) ToXml(v interface{}) error { | ... | @@ -447,8 +458,7 @@ func (b *BeegoHttpRequest) ToXml(v interface{}) error { |
| 447 | if err != nil { | 458 | if err != nil { |
| 448 | return err | 459 | return err |
| 449 | } | 460 | } |
| 450 | err = xml.Unmarshal(data, v) | 461 | return xml.Unmarshal(data, v) |
| 451 | return err | ||
| 452 | } | 462 | } |
| 453 | 463 | ||
| 454 | // Response executes request client gets response mannually. | 464 | // Response executes request client gets response mannually. | ... | ... |
| ... | @@ -66,23 +66,24 @@ func TestSimplePost(t *testing.T) { | ... | @@ -66,23 +66,24 @@ func TestSimplePost(t *testing.T) { |
| 66 | } | 66 | } |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | func TestPostFile(t *testing.T) { | 69 | //func TestPostFile(t *testing.T) { |
| 70 | v := "smallfish" | 70 | // v := "smallfish" |
| 71 | req := Post("http://httpbin.org/post") | 71 | // req := Post("http://httpbin.org/post") |
| 72 | req.Param("username", v) | 72 | // req.Debug(true) |
| 73 | req.PostFile("uploadfile", "httplib_test.go") | 73 | // req.Param("username", v) |
| 74 | 74 | // req.PostFile("uploadfile", "httplib_test.go") | |
| 75 | str, err := req.String() | 75 | |
| 76 | if err != nil { | 76 | // str, err := req.String() |
| 77 | t.Fatal(err) | 77 | // if err != nil { |
| 78 | } | 78 | // t.Fatal(err) |
| 79 | t.Log(str) | 79 | // } |
| 80 | 80 | // t.Log(str) | |
| 81 | n := strings.Index(str, v) | 81 | |
| 82 | if n == -1 { | 82 | // n := strings.Index(str, v) |
| 83 | t.Fatal(v + " not found in post") | 83 | // if n == -1 { |
| 84 | } | 84 | // t.Fatal(v + " not found in post") |
| 85 | } | 85 | // } |
| 86 | //} | ||
| 86 | 87 | ||
| 87 | func TestSimplePut(t *testing.T) { | 88 | func TestSimplePut(t *testing.T) { |
| 88 | str, err := Put("http://httpbin.org/put").String() | 89 | str, err := Put("http://httpbin.org/put").String() | ... | ... |
| ... | @@ -43,11 +43,7 @@ func NewConn() LoggerInterface { | ... | @@ -43,11 +43,7 @@ func NewConn() LoggerInterface { |
| 43 | // init connection writer with json config. | 43 | // init connection writer with json config. |
| 44 | // json config only need key "level". | 44 | // json config only need key "level". |
| 45 | func (c *ConnWriter) Init(jsonconfig string) error { | 45 | func (c *ConnWriter) Init(jsonconfig string) error { |
| 46 | err := json.Unmarshal([]byte(jsonconfig), c) | 46 | return json.Unmarshal([]byte(jsonconfig), c) |
| 47 | if err != nil { | ||
| 48 | return err | ||
| 49 | } | ||
| 50 | return nil | ||
| 51 | } | 47 | } |
| 52 | 48 | ||
| 53 | // write message in connection. | 49 | // write message in connection. |
| ... | @@ -77,10 +73,9 @@ func (c *ConnWriter) Flush() { | ... | @@ -77,10 +73,9 @@ func (c *ConnWriter) Flush() { |
| 77 | 73 | ||
| 78 | // destroy connection writer and close tcp listener. | 74 | // destroy connection writer and close tcp listener. |
| 79 | func (c *ConnWriter) Destroy() { | 75 | func (c *ConnWriter) Destroy() { |
| 80 | if c.innerWriter == nil { | 76 | if c.innerWriter != nil { |
| 81 | return | 77 | c.innerWriter.Close() |
| 82 | } | 78 | } |
| 83 | c.innerWriter.Close() | ||
| 84 | } | 79 | } |
| 85 | 80 | ||
| 86 | func (c *ConnWriter) connect() error { | 81 | func (c *ConnWriter) connect() error { | ... | ... |
| ... | @@ -50,9 +50,10 @@ type ConsoleWriter struct { | ... | @@ -50,9 +50,10 @@ type ConsoleWriter struct { |
| 50 | 50 | ||
| 51 | // create ConsoleWriter returning as LoggerInterface. | 51 | // create ConsoleWriter returning as LoggerInterface. |
| 52 | func NewConsole() LoggerInterface { | 52 | func NewConsole() LoggerInterface { |
| 53 | cw := new(ConsoleWriter) | 53 | cw := &ConsoleWriter{ |
| 54 | cw.lg = log.New(os.Stdout, "", log.Ldate|log.Ltime) | 54 | lg: log.New(os.Stdout, "", log.Ldate|log.Ltime), |
| 55 | cw.Level = LevelDebug | 55 | Level: LevelDebug, |
| 56 | } | ||
| 56 | return cw | 57 | return cw |
| 57 | } | 58 | } |
| 58 | 59 | ||
| ... | @@ -62,11 +63,7 @@ func (c *ConsoleWriter) Init(jsonconfig string) error { | ... | @@ -62,11 +63,7 @@ func (c *ConsoleWriter) Init(jsonconfig string) error { |
| 62 | if len(jsonconfig) == 0 { | 63 | if len(jsonconfig) == 0 { |
| 63 | return nil | 64 | return nil |
| 64 | } | 65 | } |
| 65 | err := json.Unmarshal([]byte(jsonconfig), c) | 66 | return json.Unmarshal([]byte(jsonconfig), c) |
| 66 | if err != nil { | ||
| 67 | return err | ||
| 68 | } | ||
| 69 | return nil | ||
| 70 | } | 67 | } |
| 71 | 68 | ||
| 72 | // write message in console. | 69 | // write message in console. |
| ... | @@ -76,9 +73,10 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error { | ... | @@ -76,9 +73,10 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error { |
| 76 | } | 73 | } |
| 77 | if goos := runtime.GOOS; goos == "windows" { | 74 | if goos := runtime.GOOS; goos == "windows" { |
| 78 | c.lg.Println(msg) | 75 | c.lg.Println(msg) |
| 79 | } else { | 76 | return nil |
| 80 | c.lg.Println(colors[level](msg)) | ||
| 81 | } | 77 | } |
| 78 | c.lg.Println(colors[level](msg)) | ||
| 79 | |||
| 82 | return nil | 80 | return nil |
| 83 | } | 81 | } |
| 84 | 82 | ... | ... |
| ... | @@ -15,10 +15,11 @@ | ... | @@ -15,10 +15,11 @@ |
| 15 | package logs | 15 | package logs |
| 16 | 16 | ||
| 17 | import ( | 17 | import ( |
| 18 | "bytes" | ||
| 18 | "encoding/json" | 19 | "encoding/json" |
| 19 | "errors" | 20 | "errors" |
| 20 | "fmt" | 21 | "fmt" |
| 21 | "io/ioutil" | 22 | "io" |
| 22 | "log" | 23 | "log" |
| 23 | "os" | 24 | "os" |
| 24 | "path/filepath" | 25 | "path/filepath" |
| ... | @@ -122,11 +123,7 @@ func (w *FileLogWriter) startLogger() error { | ... | @@ -122,11 +123,7 @@ func (w *FileLogWriter) startLogger() error { |
| 122 | return err | 123 | return err |
| 123 | } | 124 | } |
| 124 | w.mw.SetFd(fd) | 125 | w.mw.SetFd(fd) |
| 125 | err = w.initFd() | 126 | return w.initFd() |
| 126 | if err != nil { | ||
| 127 | return err | ||
| 128 | } | ||
| 129 | return nil | ||
| 130 | } | 127 | } |
| 131 | 128 | ||
| 132 | func (w *FileLogWriter) docheck(size int) { | 129 | func (w *FileLogWriter) docheck(size int) { |
| ... | @@ -169,18 +166,44 @@ func (w *FileLogWriter) initFd() error { | ... | @@ -169,18 +166,44 @@ func (w *FileLogWriter) initFd() error { |
| 169 | } | 166 | } |
| 170 | w.maxsize_cursize = int(finfo.Size()) | 167 | w.maxsize_cursize = int(finfo.Size()) |
| 171 | w.daily_opendate = time.Now().Day() | 168 | w.daily_opendate = time.Now().Day() |
| 169 | w.maxlines_curlines = 0 | ||
| 172 | if finfo.Size() > 0 { | 170 | if finfo.Size() > 0 { |
| 173 | content, err := ioutil.ReadFile(w.Filename) | 171 | count, err := w.lines() |
| 174 | if err != nil { | 172 | if err != nil { |
| 175 | return err | 173 | return err |
| 176 | } | 174 | } |
| 177 | w.maxlines_curlines = len(strings.Split(string(content), "\n")) | 175 | w.maxlines_curlines = count |
| 178 | } else { | ||
| 179 | w.maxlines_curlines = 0 | ||
| 180 | } | 176 | } |
| 181 | return nil | 177 | return nil |
| 182 | } | 178 | } |
| 183 | 179 | ||
| 180 | func (w *FileLogWriter) lines() (int, error) { | ||
| 181 | fd, err := os.Open(w.Filename) | ||
| 182 | if err != nil { | ||
| 183 | return 0, err | ||
| 184 | } | ||
| 185 | defer fd.Close() | ||
| 186 | |||
| 187 | buf := make([]byte, 32768) // 32k | ||
| 188 | count := 0 | ||
| 189 | lineSep := []byte{'\n'} | ||
| 190 | |||
| 191 | for { | ||
| 192 | c, err := fd.Read(buf) | ||
| 193 | if err != nil && err != io.EOF { | ||
| 194 | return count, err | ||
| 195 | } | ||
| 196 | |||
| 197 | count += bytes.Count(buf[:c], lineSep) | ||
| 198 | |||
| 199 | if err == io.EOF { | ||
| 200 | break | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | return count, nil | ||
| 205 | } | ||
| 206 | |||
| 184 | // DoRotate means it need to write file in new file. | 207 | // DoRotate means it need to write file in new file. |
| 185 | // new file name like xx.log.2013-01-01.2 | 208 | // new file name like xx.log.2013-01-01.2 |
| 186 | func (w *FileLogWriter) DoRotate() error { | 209 | func (w *FileLogWriter) DoRotate() error { | ... | ... |
| ... | @@ -155,6 +155,9 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { | ... | @@ -155,6 +155,9 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { |
| 155 | lm.level = loglevel | 155 | lm.level = loglevel |
| 156 | if bl.enableFuncCallDepth { | 156 | if bl.enableFuncCallDepth { |
| 157 | _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) | 157 | _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth) |
| 158 | if _, filename := path.Split(file); filename == "log.go" && (line == 97 || line == 83) { | ||
| 159 | _, file, line, ok = runtime.Caller(bl.loggerFuncCallDepth + 1) | ||
| 160 | } | ||
| 158 | if ok { | 161 | if ok { |
| 159 | _, filename := path.Split(file) | 162 | _, filename := path.Split(file) |
| 160 | lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg) | 163 | lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg) |
| ... | @@ -289,9 +292,9 @@ func (bl *BeeLogger) Close() { | ... | @@ -289,9 +292,9 @@ func (bl *BeeLogger) Close() { |
| 289 | fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err) | 292 | fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err) |
| 290 | } | 293 | } |
| 291 | } | 294 | } |
| 292 | } else { | 295 | continue |
| 293 | break | ||
| 294 | } | 296 | } |
| 297 | break | ||
| 295 | } | 298 | } |
| 296 | for _, l := range bl.outputs { | 299 | for _, l := range bl.outputs { |
| 297 | l.Flush() | 300 | l.Flush() | ... | ... |
| ... | @@ -25,7 +25,8 @@ import ( | ... | @@ -25,7 +25,8 @@ import ( |
| 25 | ) | 25 | ) |
| 26 | 26 | ||
| 27 | const ( | 27 | const ( |
| 28 | subjectPhrase = "Diagnostic message from server" | 28 | // no usage |
| 29 | // subjectPhrase = "Diagnostic message from server" | ||
| 29 | ) | 30 | ) |
| 30 | 31 | ||
| 31 | // smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. | 32 | // smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. |
| ... | @@ -146,9 +147,7 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error { | ... | @@ -146,9 +147,7 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error { |
| 146 | mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + | 147 | mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + |
| 147 | ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) | 148 | ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) |
| 148 | 149 | ||
| 149 | err := s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) | 150 | return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) |
| 150 | |||
| 151 | return err | ||
| 152 | } | 151 | } |
| 153 | 152 | ||
| 154 | // implementing method. empty. | 153 | // implementing method. empty. | ... | ... |
middleware/exceptions.go
deleted
100644 → 0
| 1 | // Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | package middleware | ||
| 16 | |||
| 17 | import "fmt" | ||
| 18 | |||
| 19 | // http exceptions | ||
| 20 | type HTTPException struct { | ||
| 21 | StatusCode int // http status code 4xx, 5xx | ||
| 22 | Description string | ||
| 23 | } | ||
| 24 | |||
| 25 | // return http exception error string, e.g. "400 Bad Request". | ||
| 26 | func (e *HTTPException) Error() string { | ||
| 27 | return fmt.Sprintf("%d %s", e.StatusCode, e.Description) | ||
| 28 | } | ||
| 29 | |||
| 30 | // map of http exceptions for each http status code int. | ||
| 31 | // defined 400,401,403,404,405,500,502,503 and 504 default. | ||
| 32 | var HTTPExceptionMaps map[int]HTTPException | ||
| 33 | |||
| 34 | func init() { | ||
| 35 | HTTPExceptionMaps = make(map[int]HTTPException) | ||
| 36 | |||
| 37 | // Normal 4XX HTTP Status | ||
| 38 | HTTPExceptionMaps[400] = HTTPException{400, "Bad Request"} | ||
| 39 | HTTPExceptionMaps[401] = HTTPException{401, "Unauthorized"} | ||
| 40 | HTTPExceptionMaps[403] = HTTPException{403, "Forbidden"} | ||
| 41 | HTTPExceptionMaps[404] = HTTPException{404, "Not Found"} | ||
| 42 | HTTPExceptionMaps[405] = HTTPException{405, "Method Not Allowed"} | ||
| 43 | |||
| 44 | // Normal 5XX HTTP Status | ||
| 45 | HTTPExceptionMaps[500] = HTTPException{500, "Internal Server Error"} | ||
| 46 | HTTPExceptionMaps[502] = HTTPException{502, "Bad Gateway"} | ||
| 47 | HTTPExceptionMaps[503] = HTTPException{503, "Service Unavailable"} | ||
| 48 | HTTPExceptionMaps[504] = HTTPException{504, "Gateway Timeout"} | ||
| 49 | } |
| ... | @@ -34,7 +34,6 @@ type Translation struct { | ... | @@ -34,7 +34,6 @@ type Translation struct { |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | func NewLocale(filepath string, defaultlocal string) *Translation { | 36 | func NewLocale(filepath string, defaultlocal string) *Translation { |
| 37 | i18n := make(map[string]map[string]string) | ||
| 38 | file, err := os.Open(filepath) | 37 | file, err := os.Open(filepath) |
| 39 | if err != nil { | 38 | if err != nil { |
| 40 | panic("open " + filepath + " err :" + err.Error()) | 39 | panic("open " + filepath + " err :" + err.Error()) |
| ... | @@ -43,8 +42,9 @@ func NewLocale(filepath string, defaultlocal string) *Translation { | ... | @@ -43,8 +42,9 @@ func NewLocale(filepath string, defaultlocal string) *Translation { |
| 43 | if err != nil { | 42 | if err != nil { |
| 44 | panic("read " + filepath + " err :" + err.Error()) | 43 | panic("read " + filepath + " err :" + err.Error()) |
| 45 | } | 44 | } |
| 46 | err = json.Unmarshal(data, &i18n) | 45 | |
| 47 | if err != nil { | 46 | i18n := make(map[string]map[string]string) |
| 47 | if err = json.Unmarshal(data, &i18n); err != nil { | ||
| 48 | panic("json.Unmarshal " + filepath + " err :" + err.Error()) | 48 | panic("json.Unmarshal " + filepath + " err :" + err.Error()) |
| 49 | } | 49 | } |
| 50 | return &Translation{ | 50 | return &Translation{ | ... | ... |
migration/ddl.go
0 → 100644
| 1 | // Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | package migration | ||
| 16 | |||
| 17 | type Table struct { | ||
| 18 | TableName string | ||
| 19 | Columns []*Column | ||
| 20 | } | ||
| 21 | |||
| 22 | func (t *Table) Create() string { | ||
| 23 | return "" | ||
| 24 | } | ||
| 25 | |||
| 26 | func (t *Table) Drop() string { | ||
| 27 | return "" | ||
| 28 | } | ||
| 29 | |||
| 30 | type Column struct { | ||
| 31 | Name string | ||
| 32 | Type string | ||
| 33 | Default interface{} | ||
| 34 | } | ||
| 35 | |||
| 36 | func Create(tbname string, columns ...Column) string { | ||
| 37 | return "" | ||
| 38 | } | ||
| 39 | |||
| 40 | func Drop(tbname string, columns ...Column) string { | ||
| 41 | return "" | ||
| 42 | } | ||
| 43 | |||
| 44 | func TableDDL(tbname string, columns ...Column) string { | ||
| 45 | return "" | ||
| 46 | } |
| ... | @@ -19,7 +19,6 @@ import ( | ... | @@ -19,7 +19,6 @@ import ( |
| 19 | "strings" | 19 | "strings" |
| 20 | 20 | ||
| 21 | beecontext "github.com/astaxie/beego/context" | 21 | beecontext "github.com/astaxie/beego/context" |
| 22 | "github.com/astaxie/beego/middleware" | ||
| 23 | ) | 22 | ) |
| 24 | 23 | ||
| 25 | type namespaceCond func(*beecontext.Context) bool | 24 | type namespaceCond func(*beecontext.Context) bool |
| ... | @@ -57,7 +56,7 @@ func NewNamespace(prefix string, params ...innnerNamespace) *Namespace { | ... | @@ -57,7 +56,7 @@ func NewNamespace(prefix string, params ...innnerNamespace) *Namespace { |
| 57 | func (n *Namespace) Cond(cond namespaceCond) *Namespace { | 56 | func (n *Namespace) Cond(cond namespaceCond) *Namespace { |
| 58 | fn := func(ctx *beecontext.Context) { | 57 | fn := func(ctx *beecontext.Context) { |
| 59 | if !cond(ctx) { | 58 | if !cond(ctx) { |
| 60 | middleware.Exception("405", ctx.ResponseWriter, ctx.Request, "Method not allowed") | 59 | exception("405", ctx) |
| 61 | } | 60 | } |
| 62 | } | 61 | } |
| 63 | if v, ok := n.handlers.filters[BeforeRouter]; ok { | 62 | if v, ok := n.handlers.filters[BeforeRouter]; ok { |
| ... | @@ -217,7 +216,7 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace { | ... | @@ -217,7 +216,7 @@ func (n *Namespace) Namespace(ns ...*Namespace) *Namespace { |
| 217 | n.handlers.routers[k] = t | 216 | n.handlers.routers[k] = t |
| 218 | } | 217 | } |
| 219 | } | 218 | } |
| 220 | if n.handlers.enableFilter { | 219 | if ni.handlers.enableFilter { |
| 221 | for pos, filterList := range ni.handlers.filters { | 220 | for pos, filterList := range ni.handlers.filters { |
| 222 | for _, mr := range filterList { | 221 | for _, mr := range filterList { |
| 223 | t := NewTree() | 222 | t := NewTree() | ... | ... |
| ... | @@ -117,7 +117,7 @@ o.Begin() | ... | @@ -117,7 +117,7 @@ o.Begin() |
| 117 | ... | 117 | ... |
| 118 | user := User{Name: "slene"} | 118 | user := User{Name: "slene"} |
| 119 | id, err := o.Insert(&user) | 119 | id, err := o.Insert(&user) |
| 120 | if err != nil { | 120 | if err == nil { |
| 121 | o.Commit() | 121 | o.Commit() |
| 122 | } else { | 122 | } else { |
| 123 | o.Rollback() | 123 | o.Rollback() | ... | ... |
| ... | @@ -104,7 +104,11 @@ func getColumnAddQuery(al *alias, fi *fieldInfo) string { | ... | @@ -104,7 +104,11 @@ func getColumnAddQuery(al *alias, fi *fieldInfo) string { |
| 104 | typ += " " + "NOT NULL" | 104 | typ += " " + "NOT NULL" |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | return fmt.Sprintf("ALTER TABLE %s%s%s ADD COLUMN %s%s%s %s", Q, fi.mi.table, Q, Q, fi.column, Q, typ) | 107 | return fmt.Sprintf("ALTER TABLE %s%s%s ADD COLUMN %s%s%s %s %s", |
| 108 | Q, fi.mi.table, Q, | ||
| 109 | Q, fi.column, Q, | ||
| 110 | typ, getColumnDefault(fi), | ||
| 111 | ) | ||
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | // create database creation string. | 114 | // create database creation string. |
| ... | @@ -155,6 +159,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex | ... | @@ -155,6 +159,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex |
| 155 | //if fi.initial.String() != "" { | 159 | //if fi.initial.String() != "" { |
| 156 | // column += " DEFAULT " + fi.initial.String() | 160 | // column += " DEFAULT " + fi.initial.String() |
| 157 | //} | 161 | //} |
| 162 | |||
| 163 | // Append attribute DEFAULT | ||
| 164 | column += getColumnDefault(fi) | ||
| 158 | 165 | ||
| 159 | if fi.unique { | 166 | if fi.unique { |
| 160 | column += " " + "UNIQUE" | 167 | column += " " + "UNIQUE" |
| ... | @@ -239,3 +246,44 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex | ... | @@ -239,3 +246,44 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex |
| 239 | 246 | ||
| 240 | return | 247 | return |
| 241 | } | 248 | } |
| 249 | |||
| 250 | |||
| 251 | // Get string value for the attribute "DEFAULT" for the CREATE, ALTER commands | ||
| 252 | func getColumnDefault(fi *fieldInfo) string { | ||
| 253 | var ( | ||
| 254 | v, t, d string | ||
| 255 | ) | ||
| 256 | |||
| 257 | // Skip default attribute if field is in relations | ||
| 258 | if fi.rel || fi.reverse { | ||
| 259 | return v | ||
| 260 | } | ||
| 261 | |||
| 262 | t = " DEFAULT '%s' " | ||
| 263 | |||
| 264 | // These defaults will be useful if there no config value orm:"default" and NOT NULL is on | ||
| 265 | switch fi.fieldType { | ||
| 266 | case TypeDateField, TypeDateTimeField: | ||
| 267 | return v; | ||
| 268 | |||
| 269 | case TypeBooleanField, TypeBitField, TypeSmallIntegerField, TypeIntegerField, | ||
| 270 | TypeBigIntegerField, TypePositiveBitField, TypePositiveSmallIntegerField, | ||
| 271 | TypePositiveIntegerField, TypePositiveBigIntegerField, TypeFloatField, | ||
| 272 | TypeDecimalField: | ||
| 273 | d = "0" | ||
| 274 | } | ||
| 275 | |||
| 276 | if fi.colDefault { | ||
| 277 | if !fi.initial.Exist() { | ||
| 278 | v = fmt.Sprintf(t, "") | ||
| 279 | } else { | ||
| 280 | v = fmt.Sprintf(t, fi.initial.String()) | ||
| 281 | } | ||
| 282 | } else { | ||
| 283 | if !fi.null { | ||
| 284 | v = fmt.Sprintf(t, d) | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | return v | ||
| 289 | } | ... | ... |
| ... | @@ -116,6 +116,7 @@ type fieldInfo struct { | ... | @@ -116,6 +116,7 @@ type fieldInfo struct { |
| 116 | null bool | 116 | null bool |
| 117 | index bool | 117 | index bool |
| 118 | unique bool | 118 | unique bool |
| 119 | colDefault bool | ||
| 119 | initial StrTo | 120 | initial StrTo |
| 120 | size int | 121 | size int |
| 121 | auto_now bool | 122 | auto_now bool |
| ... | @@ -280,6 +281,11 @@ checkType: | ... | @@ -280,6 +281,11 @@ checkType: |
| 280 | fi.pk = attrs["pk"] | 281 | fi.pk = attrs["pk"] |
| 281 | fi.unique = attrs["unique"] | 282 | fi.unique = attrs["unique"] |
| 282 | 283 | ||
| 284 | // Mark object property if there is attribute "default" in the orm configuration | ||
| 285 | if _, ok := tags["default"]; ok { | ||
| 286 | fi.colDefault = true | ||
| 287 | } | ||
| 288 | |||
| 283 | switch fieldType { | 289 | switch fieldType { |
| 284 | case RelManyToMany, RelReverseMany, RelReverseOne: | 290 | case RelManyToMany, RelReverseMany, RelReverseOne: |
| 285 | fi.null = false | 291 | fi.null = false | ... | ... |
| ... | @@ -489,10 +489,6 @@ func (o *orm) Driver() Driver { | ... | @@ -489,10 +489,6 @@ func (o *orm) Driver() Driver { |
| 489 | return driver(o.alias.Name) | 489 | return driver(o.alias.Name) |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | func (o *orm) GetDB() dbQuerier { | ||
| 493 | panic(ErrNotImplement) | ||
| 494 | } | ||
| 495 | |||
| 496 | // create new orm | 492 | // create new orm |
| 497 | func NewOrm() Ormer { | 493 | func NewOrm() Ormer { |
| 498 | BootStrap() // execute only once | 494 | BootStrap() // execute only once | ... | ... |
| ... | @@ -51,7 +51,6 @@ type Ormer interface { | ... | @@ -51,7 +51,6 @@ type Ormer interface { |
| 51 | Rollback() error | 51 | Rollback() error |
| 52 | Raw(string, ...interface{}) RawSeter | 52 | Raw(string, ...interface{}) RawSeter |
| 53 | Driver() Driver | 53 | Driver() Driver |
| 54 | GetDB() dbQuerier | ||
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | // insert prepared statement | 56 | // insert prepared statement | ... | ... |
| ... | @@ -42,20 +42,25 @@ func init() { | ... | @@ -42,20 +42,25 @@ func init() { |
| 42 | 42 | ||
| 43 | var ( | 43 | var ( |
| 44 | lastupdateFilename string = "lastupdate.tmp" | 44 | lastupdateFilename string = "lastupdate.tmp" |
| 45 | commentFilename string | ||
| 45 | pkgLastupdate map[string]int64 | 46 | pkgLastupdate map[string]int64 |
| 46 | genInfoList map[string][]ControllerComments | 47 | genInfoList map[string][]ControllerComments |
| 47 | ) | 48 | ) |
| 48 | 49 | ||
| 50 | const COMMENTFL = "commentsRouter_" | ||
| 51 | |||
| 49 | func init() { | 52 | func init() { |
| 50 | pkgLastupdate = make(map[string]int64) | 53 | pkgLastupdate = make(map[string]int64) |
| 51 | genInfoList = make(map[string][]ControllerComments) | ||
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | func parserPkg(pkgRealpath, pkgpath string) error { | 56 | func parserPkg(pkgRealpath, pkgpath string) error { |
| 57 | rep := strings.NewReplacer("/", "_", ".", "_") | ||
| 58 | commentFilename = COMMENTFL + rep.Replace(pkgpath) + ".go" | ||
| 55 | if !compareFile(pkgRealpath) { | 59 | if !compareFile(pkgRealpath) { |
| 56 | Info(pkgRealpath + " don't has updated") | 60 | Info(pkgRealpath + " has not changed, not reloading") |
| 57 | return nil | 61 | return nil |
| 58 | } | 62 | } |
| 63 | genInfoList = make(map[string][]ControllerComments) | ||
| 59 | fileSet := token.NewFileSet() | 64 | fileSet := token.NewFileSet() |
| 60 | astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool { | 65 | astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool { |
| 61 | name := info.Name() | 66 | name := info.Name() |
| ... | @@ -155,7 +160,7 @@ func genRouterCode() { | ... | @@ -155,7 +160,7 @@ func genRouterCode() { |
| 155 | } | 160 | } |
| 156 | } | 161 | } |
| 157 | if globalinfo != "" { | 162 | if globalinfo != "" { |
| 158 | f, err := os.Create(path.Join(workPath, "routers", "commentsRouter.go")) | 163 | f, err := os.Create(path.Join(workPath, "routers", commentFilename)) |
| 159 | if err != nil { | 164 | if err != nil { |
| 160 | panic(err) | 165 | panic(err) |
| 161 | } | 166 | } |
| ... | @@ -165,7 +170,7 @@ func genRouterCode() { | ... | @@ -165,7 +170,7 @@ func genRouterCode() { |
| 165 | } | 170 | } |
| 166 | 171 | ||
| 167 | func compareFile(pkgRealpath string) bool { | 172 | func compareFile(pkgRealpath string) bool { |
| 168 | if !utils.FileExists(path.Join(workPath, "routers", "commentsRouter.go")) { | 173 | if !utils.FileExists(path.Join(workPath, "routers", commentFilename)) { |
| 169 | return true | 174 | return true |
| 170 | } | 175 | } |
| 171 | if utils.FileExists(path.Join(workPath, lastupdateFilename)) { | 176 | if utils.FileExists(path.Join(workPath, lastupdateFilename)) { | ... | ... |
| ... | @@ -217,6 +217,7 @@ func Allow(opts *Options) beego.FilterFunc { | ... | @@ -217,6 +217,7 @@ func Allow(opts *Options) beego.FilterFunc { |
| 217 | ctx.Output.Header(key, value) | 217 | ctx.Output.Header(key, value) |
| 218 | } | 218 | } |
| 219 | ctx.Output.SetStatus(http.StatusOK) | 219 | ctx.Output.SetStatus(http.StatusOK) |
| 220 | ctx.WriteString("") | ||
| 220 | return | 221 | return |
| 221 | } | 222 | } |
| 222 | headers = opts.Header(origin) | 223 | headers = opts.Header(origin) | ... | ... |
| ... | @@ -30,7 +30,6 @@ import ( | ... | @@ -30,7 +30,6 @@ import ( |
| 30 | "time" | 30 | "time" |
| 31 | 31 | ||
| 32 | beecontext "github.com/astaxie/beego/context" | 32 | beecontext "github.com/astaxie/beego/context" |
| 33 | "github.com/astaxie/beego/middleware" | ||
| 34 | "github.com/astaxie/beego/toolbox" | 33 | "github.com/astaxie/beego/toolbox" |
| 35 | "github.com/astaxie/beego/utils" | 34 | "github.com/astaxie/beego/utils" |
| 36 | ) | 35 | ) |
| ... | @@ -72,11 +71,31 @@ var ( | ... | @@ -72,11 +71,31 @@ var ( |
| 72 | "SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml", | 71 | "SetSecureCookie", "XsrfToken", "CheckXsrfCookie", "XsrfFormHtml", |
| 73 | "GetControllerAndAction"} | 72 | "GetControllerAndAction"} |
| 74 | 73 | ||
| 75 | url_placeholder = "{{placeholder}}" | 74 | url_placeholder = "{{placeholder}}" |
| 76 | 75 | DefaultLogFilter FilterHandler = &logFilter{} | |
| 77 | FilterRouterLog func(*beecontext.Context) bool | ||
| 78 | ) | 76 | ) |
| 79 | 77 | ||
| 78 | type FilterHandler interface { | ||
| 79 | Filter(*beecontext.Context) bool | ||
| 80 | } | ||
| 81 | |||
| 82 | // default log filter static file will not show | ||
| 83 | type logFilter struct { | ||
| 84 | } | ||
| 85 | |||
| 86 | func (l *logFilter) Filter(ctx *beecontext.Context) bool { | ||
| 87 | requestPath := path.Clean(ctx.Input.Request.URL.Path) | ||
| 88 | if requestPath == "/favicon.ico" || requestPath == "/robots.txt" { | ||
| 89 | return true | ||
| 90 | } | ||
| 91 | for prefix, _ := range StaticDir { | ||
| 92 | if strings.HasPrefix(requestPath, prefix) { | ||
| 93 | return true | ||
| 94 | } | ||
| 95 | } | ||
| 96 | return false | ||
| 97 | } | ||
| 98 | |||
| 80 | // To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter | 99 | // To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter |
| 81 | func ExceptMethodAppend(action string) { | 100 | func ExceptMethodAppend(action string) { |
| 82 | exceptMethod = append(exceptMethod, action) | 101 | exceptMethod = append(exceptMethod, action) |
| ... | @@ -133,7 +152,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM | ... | @@ -133,7 +152,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM |
| 133 | if val := reflectVal.MethodByName(colon[1]); val.IsValid() { | 152 | if val := reflectVal.MethodByName(colon[1]); val.IsValid() { |
| 134 | methods[strings.ToUpper(m)] = colon[1] | 153 | methods[strings.ToUpper(m)] = colon[1] |
| 135 | } else { | 154 | } else { |
| 136 | panic(colon[1] + " method doesn't exist in the controller " + t.Name()) | 155 | panic("'" + colon[1] + "' method doesn't exist in the controller " + t.Name()) |
| 137 | } | 156 | } |
| 138 | } else { | 157 | } else { |
| 139 | panic(v + " is an invalid method mapping. Method doesn't exist " + m) | 158 | panic(v + " is an invalid method mapping. Method doesn't exist " + m) |
| ... | @@ -409,7 +428,7 @@ func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error | ... | @@ -409,7 +428,7 @@ func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error |
| 409 | 428 | ||
| 410 | // UrlFor does another controller handler in this request function. | 429 | // UrlFor does another controller handler in this request function. |
| 411 | // it can access any controller method. | 430 | // it can access any controller method. |
| 412 | func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { | 431 | func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) string { |
| 413 | paths := strings.Split(endpoint, ".") | 432 | paths := strings.Split(endpoint, ".") |
| 414 | if len(paths) <= 1 { | 433 | if len(paths) <= 1 { |
| 415 | Warn("urlfor endpoint must like path.controller.method") | 434 | Warn("urlfor endpoint must like path.controller.method") |
| ... | @@ -424,16 +443,16 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { | ... | @@ -424,16 +443,16 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { |
| 424 | key := "" | 443 | key := "" |
| 425 | for k, v := range values { | 444 | for k, v := range values { |
| 426 | if k%2 == 0 { | 445 | if k%2 == 0 { |
| 427 | key = v | 446 | key = fmt.Sprint(v) |
| 428 | } else { | 447 | } else { |
| 429 | params[key] = v | 448 | params[key] = fmt.Sprint(v) |
| 430 | } | 449 | } |
| 431 | } | 450 | } |
| 432 | } | 451 | } |
| 433 | controllName := strings.Join(paths[:len(paths)-1], "/") | 452 | controllName := strings.Join(paths[:len(paths)-1], "/") |
| 434 | methodName := paths[len(paths)-1] | 453 | methodName := paths[len(paths)-1] |
| 435 | for _, t := range p.routers { | 454 | for m, t := range p.routers { |
| 436 | ok, url := p.geturl(t, "/", controllName, methodName, params) | 455 | ok, url := p.geturl(t, "/", controllName, methodName, params, m) |
| 437 | if ok { | 456 | if ok { |
| 438 | return url | 457 | return url |
| 439 | } | 458 | } |
| ... | @@ -441,17 +460,17 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { | ... | @@ -441,17 +460,17 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { |
| 441 | return "" | 460 | return "" |
| 442 | } | 461 | } |
| 443 | 462 | ||
| 444 | func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string) (bool, string) { | 463 | func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName string, params map[string]string, httpMethod string) (bool, string) { |
| 445 | for k, subtree := range t.fixrouters { | 464 | for k, subtree := range t.fixrouters { |
| 446 | u := path.Join(url, k) | 465 | u := path.Join(url, k) |
| 447 | ok, u := p.geturl(subtree, u, controllName, methodName, params) | 466 | ok, u := p.geturl(subtree, u, controllName, methodName, params, httpMethod) |
| 448 | if ok { | 467 | if ok { |
| 449 | return ok, u | 468 | return ok, u |
| 450 | } | 469 | } |
| 451 | } | 470 | } |
| 452 | if t.wildcard != nil { | 471 | if t.wildcard != nil { |
| 453 | url = path.Join(url, url_placeholder) | 472 | u := path.Join(url, url_placeholder) |
| 454 | ok, u := p.geturl(t.wildcard, url, controllName, methodName, params) | 473 | ok, u := p.geturl(t.wildcard, u, controllName, methodName, params, httpMethod) |
| 455 | if ok { | 474 | if ok { |
| 456 | return ok, u | 475 | return ok, u |
| 457 | } | 476 | } |
| ... | @@ -471,8 +490,8 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin | ... | @@ -471,8 +490,8 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin |
| 471 | } | 490 | } |
| 472 | } | 491 | } |
| 473 | if !find { | 492 | if !find { |
| 474 | for _, md := range c.methods { | 493 | for m, md := range c.methods { |
| 475 | if md == methodName { | 494 | if (m == "*" || m == httpMethod) && md == methodName { |
| 476 | find = true | 495 | find = true |
| 477 | } | 496 | } |
| 478 | } | 497 | } |
| ... | @@ -557,7 +576,6 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin | ... | @@ -557,7 +576,6 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin |
| 557 | 576 | ||
| 558 | // Implement http.Handler interface. | 577 | // Implement http.Handler interface. |
| 559 | func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { | 578 | func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { |
| 560 | defer p.recoverPanic(rw, r) | ||
| 561 | starttime := time.Now() | 579 | starttime := time.Now() |
| 562 | var runrouter reflect.Type | 580 | var runrouter reflect.Type |
| 563 | var findrouter bool | 581 | var findrouter bool |
| ... | @@ -580,6 +598,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -580,6 +598,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 580 | context.Output.Context = context | 598 | context.Output.Context = context |
| 581 | context.Output.EnableGzip = EnableGzip | 599 | context.Output.EnableGzip = EnableGzip |
| 582 | 600 | ||
| 601 | defer p.recoverPanic(context) | ||
| 602 | |||
| 583 | var urlPath string | 603 | var urlPath string |
| 584 | if !RouterCaseSensitive { | 604 | if !RouterCaseSensitive { |
| 585 | urlPath = strings.ToLower(r.URL.Path) | 605 | urlPath = strings.ToLower(r.URL.Path) |
| ... | @@ -624,7 +644,13 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -624,7 +644,13 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 624 | 644 | ||
| 625 | // session init | 645 | // session init |
| 626 | if SessionOn { | 646 | if SessionOn { |
| 627 | context.Input.CruSession = GlobalSessions.SessionStart(w, r) | 647 | var err error |
| 648 | context.Input.CruSession, err = GlobalSessions.SessionStart(w, r) | ||
| 649 | if err != nil { | ||
| 650 | Error(err) | ||
| 651 | exception("503", context) | ||
| 652 | return | ||
| 653 | } | ||
| 628 | defer func() { | 654 | defer func() { |
| 629 | context.Input.CruSession.SessionRelease(w) | 655 | context.Input.CruSession.SessionRelease(w) |
| 630 | }() | 656 | }() |
| ... | @@ -677,7 +703,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -677,7 +703,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 677 | 703 | ||
| 678 | //if no matches to url, throw a not found exception | 704 | //if no matches to url, throw a not found exception |
| 679 | if !findrouter { | 705 | if !findrouter { |
| 680 | middleware.Exception("404", rw, r, "") | 706 | exception("404", context) |
| 681 | goto Admin | 707 | goto Admin |
| 682 | } | 708 | } |
| 683 | 709 | ||
| ... | @@ -693,7 +719,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -693,7 +719,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 693 | isRunable = true | 719 | isRunable = true |
| 694 | routerInfo.runfunction(context) | 720 | routerInfo.runfunction(context) |
| 695 | } else { | 721 | } else { |
| 696 | middleware.Exception("405", rw, r, "Method Not Allowed") | 722 | exception("405", context) |
| 697 | goto Admin | 723 | goto Admin |
| 698 | } | 724 | } |
| 699 | } else if routerInfo.routerType == routerTypeHandler { | 725 | } else if routerInfo.routerType == routerTypeHandler { |
| ... | @@ -804,7 +830,7 @@ Admin: | ... | @@ -804,7 +830,7 @@ Admin: |
| 804 | } | 830 | } |
| 805 | } | 831 | } |
| 806 | 832 | ||
| 807 | if RunMode == "dev" { | 833 | if RunMode == "dev" || AccessLogs { |
| 808 | var devinfo string | 834 | var devinfo string |
| 809 | if findrouter { | 835 | if findrouter { |
| 810 | if routerInfo != nil { | 836 | if routerInfo != nil { |
| ... | @@ -815,7 +841,7 @@ Admin: | ... | @@ -815,7 +841,7 @@ Admin: |
| 815 | } else { | 841 | } else { |
| 816 | devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch") | 842 | devinfo = fmt.Sprintf("| % -10s | % -40s | % -16s | % -10s |", r.Method, r.URL.Path, timeend.String(), "notmatch") |
| 817 | } | 843 | } |
| 818 | if FilterRouterLog == nil || !FilterRouterLog(context) { | 844 | if DefaultLogFilter == nil || !DefaultLogFilter.Filter(context) { |
| 819 | Debug(devinfo) | 845 | Debug(devinfo) |
| 820 | } | 846 | } |
| 821 | } | 847 | } |
| ... | @@ -826,26 +852,51 @@ Admin: | ... | @@ -826,26 +852,51 @@ Admin: |
| 826 | } | 852 | } |
| 827 | } | 853 | } |
| 828 | 854 | ||
| 829 | func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Request) { | 855 | func (p *ControllerRegistor) recoverPanic(context *beecontext.Context) { |
| 830 | if err := recover(); err != nil { | 856 | if err := recover(); err != nil { |
| 831 | if err == USERSTOPRUN { | 857 | if err == USERSTOPRUN { |
| 832 | return | 858 | return |
| 833 | } | 859 | } |
| 834 | if _, ok := err.(middleware.HTTPException); ok { | 860 | if RunMode == "dev" { |
| 835 | // catch intented errors, only for HTTP 4XX and 5XX | 861 | if !RecoverPanic { |
| 862 | panic(err) | ||
| 863 | } else { | ||
| 864 | if ErrorsShow { | ||
| 865 | if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok { | ||
| 866 | executeError(handler, context) | ||
| 867 | return | ||
| 868 | } | ||
| 869 | } | ||
| 870 | var stack string | ||
| 871 | Critical("the request url is ", context.Input.Url()) | ||
| 872 | Critical("Handler crashed with error", err) | ||
| 873 | for i := 1; ; i++ { | ||
| 874 | _, file, line, ok := runtime.Caller(i) | ||
| 875 | if !ok { | ||
| 876 | break | ||
| 877 | } | ||
| 878 | Critical(fmt.Sprintf("%s:%d", file, line)) | ||
| 879 | stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) | ||
| 880 | } | ||
| 881 | showErr(err, context, stack) | ||
| 882 | } | ||
| 836 | } else { | 883 | } else { |
| 837 | if RunMode == "dev" { | 884 | if !RecoverPanic { |
| 838 | if !RecoverPanic { | 885 | panic(err) |
| 839 | panic(err) | 886 | } else { |
| 840 | } else { | 887 | // in production model show all infomation |
| 841 | if ErrorsShow { | 888 | if ErrorsShow { |
| 842 | if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok { | 889 | if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok { |
| 843 | handler(rw, r) | 890 | executeError(handler, context) |
| 844 | return | 891 | return |
| 845 | } | 892 | } else if handler, ok := ErrorMaps["503"]; ok { |
| 893 | executeError(handler, context) | ||
| 894 | return | ||
| 895 | } else { | ||
| 896 | context.WriteString(fmt.Sprint(err)) | ||
| 846 | } | 897 | } |
| 847 | var stack string | 898 | } else { |
| 848 | Critical("the request url is ", r.URL.Path) | 899 | Critical("the request url is ", context.Input.Url()) |
| 849 | Critical("Handler crashed with error", err) | 900 | Critical("Handler crashed with error", err) |
| 850 | for i := 1; ; i++ { | 901 | for i := 1; ; i++ { |
| 851 | _, file, line, ok := runtime.Caller(i) | 902 | _, file, line, ok := runtime.Caller(i) |
| ... | @@ -853,53 +904,11 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques | ... | @@ -853,53 +904,11 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques |
| 853 | break | 904 | break |
| 854 | } | 905 | } |
| 855 | Critical(fmt.Sprintf("%s:%d", file, line)) | 906 | Critical(fmt.Sprintf("%s:%d", file, line)) |
| 856 | stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) | ||
| 857 | } | ||
| 858 | middleware.ShowErr(err, rw, r, stack) | ||
| 859 | } | ||
| 860 | } else { | ||
| 861 | if !RecoverPanic { | ||
| 862 | panic(err) | ||
| 863 | } else { | ||
| 864 | // in production model show all infomation | ||
| 865 | if ErrorsShow { | ||
| 866 | handler := p.getErrorHandler(fmt.Sprint(err)) | ||
| 867 | handler(rw, r) | ||
| 868 | return | ||
| 869 | } else { | ||
| 870 | Critical("the request url is ", r.URL.Path) | ||
| 871 | Critical("Handler crashed with error", err) | ||
| 872 | for i := 1; ; i++ { | ||
| 873 | _, file, line, ok := runtime.Caller(i) | ||
| 874 | if !ok { | ||
| 875 | break | ||
| 876 | } | ||
| 877 | Critical(fmt.Sprintf("%s:%d", file, line)) | ||
| 878 | } | ||
| 879 | } | 907 | } |
| 880 | } | 908 | } |
| 881 | } | 909 | } |
| 882 | |||
| 883 | } | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | // there always should be error handler that sets error code accordingly for all unhandled errors. | ||
| 888 | // in order to have custom UI for error page it's necessary to override "500" error. | ||
| 889 | func (p *ControllerRegistor) getErrorHandler(errorCode string) func(rw http.ResponseWriter, r *http.Request) { | ||
| 890 | handler := middleware.SimpleServerError | ||
| 891 | ok := true | ||
| 892 | if errorCode != "" { | ||
| 893 | handler, ok = middleware.ErrorMaps[errorCode] | ||
| 894 | if !ok { | ||
| 895 | handler, ok = middleware.ErrorMaps["500"] | ||
| 896 | } | ||
| 897 | if !ok || handler == nil { | ||
| 898 | handler = middleware.SimpleServerError | ||
| 899 | } | 910 | } |
| 900 | } | 911 | } |
| 901 | |||
| 902 | return handler | ||
| 903 | } | 912 | } |
| 904 | 913 | ||
| 905 | //responseWriter is a wrapper for the http.ResponseWriter | 914 | //responseWriter is a wrapper for the http.ResponseWriter | ... | ... |
| ... | @@ -27,33 +27,33 @@ type TestController struct { | ... | @@ -27,33 +27,33 @@ type TestController struct { |
| 27 | Controller | 27 | Controller |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | func (this *TestController) Get() { | 30 | func (tc *TestController) Get() { |
| 31 | this.Data["Username"] = "astaxie" | 31 | tc.Data["Username"] = "astaxie" |
| 32 | this.Ctx.Output.Body([]byte("ok")) | 32 | tc.Ctx.Output.Body([]byte("ok")) |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | func (this *TestController) Post() { | 35 | func (tc *TestController) Post() { |
| 36 | this.Ctx.Output.Body([]byte(this.Ctx.Input.Query(":name"))) | 36 | tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name"))) |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | func (this *TestController) Param() { | 39 | func (tc *TestController) Param() { |
| 40 | this.Ctx.Output.Body([]byte(this.Ctx.Input.Query(":name"))) | 40 | tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Query(":name"))) |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | func (this *TestController) List() { | 43 | func (tc *TestController) List() { |
| 44 | this.Ctx.Output.Body([]byte("i am list")) | 44 | tc.Ctx.Output.Body([]byte("i am list")) |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | func (this *TestController) Params() { | 47 | func (tc *TestController) Params() { |
| 48 | this.Ctx.Output.Body([]byte(this.Ctx.Input.Params["0"] + this.Ctx.Input.Params["1"] + this.Ctx.Input.Params["2"])) | 48 | tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Params["0"] + tc.Ctx.Input.Params["1"] + tc.Ctx.Input.Params["2"])) |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | func (this *TestController) Myext() { | 51 | func (tc *TestController) Myext() { |
| 52 | this.Ctx.Output.Body([]byte(this.Ctx.Input.Param(":ext"))) | 52 | tc.Ctx.Output.Body([]byte(tc.Ctx.Input.Param(":ext"))) |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | func (this *TestController) GetUrl() { | 55 | func (tc *TestController) GetUrl() { |
| 56 | this.Ctx.Output.Body([]byte(this.UrlFor(".Myext"))) | 56 | tc.Ctx.Output.Body([]byte(tc.UrlFor(".Myext"))) |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | func (t *TestController) GetParams() { | 59 | func (t *TestController) GetParams() { | ... | ... |
session/ledis/ledis_session.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "net/http" | ||
| 5 | "strconv" | ||
| 6 | "strings" | ||
| 7 | "sync" | ||
| 8 | |||
| 9 | "github.com/astaxie/beego/session" | ||
| 10 | "github.com/siddontang/ledisdb/config" | ||
| 11 | "github.com/siddontang/ledisdb/ledis" | ||
| 12 | ) | ||
| 13 | |||
| 14 | var ledispder = &LedisProvider{} | ||
| 15 | var c *ledis.DB | ||
| 16 | |||
| 17 | // ledis session store | ||
| 18 | type LedisSessionStore struct { | ||
| 19 | sid string | ||
| 20 | lock sync.RWMutex | ||
| 21 | values map[interface{}]interface{} | ||
| 22 | maxlifetime int64 | ||
| 23 | } | ||
| 24 | |||
| 25 | // set value in ledis session | ||
| 26 | func (ls *LedisSessionStore) Set(key, value interface{}) error { | ||
| 27 | ls.lock.Lock() | ||
| 28 | defer ls.lock.Unlock() | ||
| 29 | ls.values[key] = value | ||
| 30 | return nil | ||
| 31 | } | ||
| 32 | |||
| 33 | // get value in ledis session | ||
| 34 | func (ls *LedisSessionStore) Get(key interface{}) interface{} { | ||
| 35 | ls.lock.RLock() | ||
| 36 | defer ls.lock.RUnlock() | ||
| 37 | if v, ok := ls.values[key]; ok { | ||
| 38 | return v | ||
| 39 | } else { | ||
| 40 | return nil | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | // delete value in ledis session | ||
| 45 | func (ls *LedisSessionStore) Delete(key interface{}) error { | ||
| 46 | ls.lock.Lock() | ||
| 47 | defer ls.lock.Unlock() | ||
| 48 | delete(ls.values, key) | ||
| 49 | return nil | ||
| 50 | } | ||
| 51 | |||
| 52 | // clear all values in ledis session | ||
| 53 | func (ls *LedisSessionStore) Flush() error { | ||
| 54 | ls.lock.Lock() | ||
| 55 | defer ls.lock.Unlock() | ||
| 56 | ls.values = make(map[interface{}]interface{}) | ||
| 57 | return nil | ||
| 58 | } | ||
| 59 | |||
| 60 | // get ledis session id | ||
| 61 | func (ls *LedisSessionStore) SessionID() string { | ||
| 62 | return ls.sid | ||
| 63 | } | ||
| 64 | |||
| 65 | // save session values to ledis | ||
| 66 | func (ls *LedisSessionStore) SessionRelease(w http.ResponseWriter) { | ||
| 67 | b, err := session.EncodeGob(ls.values) | ||
| 68 | if err != nil { | ||
| 69 | return | ||
| 70 | } | ||
| 71 | c.Set([]byte(ls.sid), b) | ||
| 72 | c.Expire([]byte(ls.sid), ls.maxlifetime) | ||
| 73 | } | ||
| 74 | |||
| 75 | // ledis session provider | ||
| 76 | type LedisProvider struct { | ||
| 77 | maxlifetime int64 | ||
| 78 | savePath string | ||
| 79 | db int | ||
| 80 | } | ||
| 81 | |||
| 82 | // init ledis session | ||
| 83 | // savepath like ledis server saveDataPath,pool size | ||
| 84 | // e.g. 127.0.0.1:6379,100,astaxie | ||
| 85 | func (lp *LedisProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 86 | var err error | ||
| 87 | lp.maxlifetime = maxlifetime | ||
| 88 | configs := strings.Split(savepath, ",") | ||
| 89 | if len(configs) == 1 { | ||
| 90 | lp.savePath = configs[0] | ||
| 91 | } else if len(configs) == 2 { | ||
| 92 | lp.savePath = configs[0] | ||
| 93 | lp.db, err = strconv.Atoi(configs[1]) | ||
| 94 | if err != nil { | ||
| 95 | return err | ||
| 96 | } | ||
| 97 | } | ||
| 98 | cfg := new(config.Config) | ||
| 99 | cfg.DataDir = lp.savePath | ||
| 100 | nowLedis, err := ledis.Open(cfg) | ||
| 101 | c, err = nowLedis.Select(lp.db) | ||
| 102 | if err != nil { | ||
| 103 | println(err) | ||
| 104 | return nil | ||
| 105 | } | ||
| 106 | return nil | ||
| 107 | } | ||
| 108 | |||
| 109 | // read ledis session by sid | ||
| 110 | func (lp *LedisProvider) SessionRead(sid string) (session.SessionStore, error) { | ||
| 111 | kvs, err := c.Get([]byte(sid)) | ||
| 112 | var kv map[interface{}]interface{} | ||
| 113 | if len(kvs) == 0 { | ||
| 114 | kv = make(map[interface{}]interface{}) | ||
| 115 | } else { | ||
| 116 | kv, err = session.DecodeGob(kvs) | ||
| 117 | if err != nil { | ||
| 118 | return nil, err | ||
| 119 | } | ||
| 120 | } | ||
| 121 | ls := &LedisSessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime} | ||
| 122 | return ls, nil | ||
| 123 | } | ||
| 124 | |||
| 125 | // check ledis session exist by sid | ||
| 126 | func (lp *LedisProvider) SessionExist(sid string) bool { | ||
| 127 | count, _ := c.Exists([]byte(sid)) | ||
| 128 | if count == 0 { | ||
| 129 | return false | ||
| 130 | } else { | ||
| 131 | return true | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | // generate new sid for ledis session | ||
| 136 | func (lp *LedisProvider) SessionRegenerate(oldsid, sid string) (session.SessionStore, error) { | ||
| 137 | count, _ := c.Exists([]byte(sid)) | ||
| 138 | if count == 0 { | ||
| 139 | // oldsid doesn't exists, set the new sid directly | ||
| 140 | // ignore error here, since if it return error | ||
| 141 | // the existed value will be 0 | ||
| 142 | c.Set([]byte(sid), []byte("")) | ||
| 143 | c.Expire([]byte(sid), lp.maxlifetime) | ||
| 144 | } else { | ||
| 145 | data, _ := c.Get([]byte(oldsid)) | ||
| 146 | c.Set([]byte(sid), data) | ||
| 147 | c.Expire([]byte(sid), lp.maxlifetime) | ||
| 148 | } | ||
| 149 | kvs, err := c.Get([]byte(sid)) | ||
| 150 | var kv map[interface{}]interface{} | ||
| 151 | if len(kvs) == 0 { | ||
| 152 | kv = make(map[interface{}]interface{}) | ||
| 153 | } else { | ||
| 154 | kv, err = session.DecodeGob([]byte(kvs)) | ||
| 155 | if err != nil { | ||
| 156 | return nil, err | ||
| 157 | } | ||
| 158 | } | ||
| 159 | ls := &LedisSessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime} | ||
| 160 | return ls, nil | ||
| 161 | } | ||
| 162 | |||
| 163 | // delete ledis session by id | ||
| 164 | func (lp *LedisProvider) SessionDestroy(sid string) error { | ||
| 165 | c.Del([]byte(sid)) | ||
| 166 | return nil | ||
| 167 | } | ||
| 168 | |||
| 169 | // Impelment method, no used. | ||
| 170 | func (lp *LedisProvider) SessionGC() { | ||
| 171 | return | ||
| 172 | } | ||
| 173 | |||
| 174 | // @todo | ||
| 175 | func (lp *LedisProvider) SessionAll() int { | ||
| 176 | return 0 | ||
| 177 | } | ||
| 178 | func init() { | ||
| 179 | session.Register("ledis", ledispder) | ||
| 180 | } |
| ... | @@ -118,12 +118,13 @@ type RedisProvider struct { | ... | @@ -118,12 +118,13 @@ type RedisProvider struct { |
| 118 | savePath string | 118 | savePath string |
| 119 | poolsize int | 119 | poolsize int |
| 120 | password string | 120 | password string |
| 121 | dbNum int | ||
| 121 | poollist *redis.Pool | 122 | poollist *redis.Pool |
| 122 | } | 123 | } |
| 123 | 124 | ||
| 124 | // init redis session | 125 | // init redis session |
| 125 | // savepath like redis server addr,pool size,password | 126 | // savepath like redis server addr,pool size,password,dbnum |
| 126 | // e.g. 127.0.0.1:6379,100,astaxie | 127 | // e.g. 127.0.0.1:6379,100,astaxie,0 |
| 127 | func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { | 128 | func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { |
| 128 | rp.maxlifetime = maxlifetime | 129 | rp.maxlifetime = maxlifetime |
| 129 | configs := strings.Split(savePath, ",") | 130 | configs := strings.Split(savePath, ",") |
| ... | @@ -143,6 +144,16 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { | ... | @@ -143,6 +144,16 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { |
| 143 | if len(configs) > 2 { | 144 | if len(configs) > 2 { |
| 144 | rp.password = configs[2] | 145 | rp.password = configs[2] |
| 145 | } | 146 | } |
| 147 | if len(configs) > 3 { | ||
| 148 | dbnum, err := strconv.Atoi(configs[1]) | ||
| 149 | if err != nil || dbnum < 0 { | ||
| 150 | rp.dbNum = 0 | ||
| 151 | } else { | ||
| 152 | rp.dbNum = dbnum | ||
| 153 | } | ||
| 154 | } else { | ||
| 155 | rp.dbNum = 0 | ||
| 156 | } | ||
| 146 | rp.poollist = redis.NewPool(func() (redis.Conn, error) { | 157 | rp.poollist = redis.NewPool(func() (redis.Conn, error) { |
| 147 | c, err := redis.Dial("tcp", rp.savePath) | 158 | c, err := redis.Dial("tcp", rp.savePath) |
| 148 | if err != nil { | 159 | if err != nil { |
| ... | @@ -154,6 +165,11 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { | ... | @@ -154,6 +165,11 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { |
| 154 | return nil, err | 165 | return nil, err |
| 155 | } | 166 | } |
| 156 | } | 167 | } |
| 168 | _, err = c.Do("SELECT", rp.dbNum) | ||
| 169 | if err != nil { | ||
| 170 | c.Close() | ||
| 171 | return nil, err | ||
| 172 | } | ||
| 157 | return c, err | 173 | return c, err |
| 158 | }, rp.poolsize) | 174 | }, rp.poolsize) |
| 159 | 175 | ... | ... |
| ... | @@ -29,7 +29,10 @@ func TestCookie(t *testing.T) { | ... | @@ -29,7 +29,10 @@ func TestCookie(t *testing.T) { |
| 29 | } | 29 | } |
| 30 | r, _ := http.NewRequest("GET", "/", nil) | 30 | r, _ := http.NewRequest("GET", "/", nil) |
| 31 | w := httptest.NewRecorder() | 31 | w := httptest.NewRecorder() |
| 32 | sess := globalSessions.SessionStart(w, r) | 32 | sess, err := globalSessions.SessionStart(w, r) |
| 33 | if err != nil { | ||
| 34 | t.Fatal("set error,", err) | ||
| 35 | } | ||
| 33 | err = sess.Set("username", "astaxie") | 36 | err = sess.Set("username", "astaxie") |
| 34 | if err != nil { | 37 | if err != nil { |
| 35 | t.Fatal("set error,", err) | 38 | t.Fatal("set error,", err) | ... | ... |
| ... | @@ -26,9 +26,12 @@ func TestMem(t *testing.T) { | ... | @@ -26,9 +26,12 @@ func TestMem(t *testing.T) { |
| 26 | go globalSessions.GC() | 26 | go globalSessions.GC() |
| 27 | r, _ := http.NewRequest("GET", "/", nil) | 27 | r, _ := http.NewRequest("GET", "/", nil) |
| 28 | w := httptest.NewRecorder() | 28 | w := httptest.NewRecorder() |
| 29 | sess := globalSessions.SessionStart(w, r) | 29 | sess, err := globalSessions.SessionStart(w, r) |
| 30 | if err != nil { | ||
| 31 | t.Fatal("set error,", err) | ||
| 32 | } | ||
| 30 | defer sess.SessionRelease(w) | 33 | defer sess.SessionRelease(w) |
| 31 | err := sess.Set("username", "astaxie") | 34 | err = sess.Set("username", "astaxie") |
| 32 | if err != nil { | 35 | if err != nil { |
| 33 | t.Fatal("set error,", err) | 36 | t.Fatal("set error,", err) |
| 34 | } | 37 | } | ... | ... |
| ... | @@ -28,19 +28,13 @@ | ... | @@ -28,19 +28,13 @@ |
| 28 | package session | 28 | package session |
| 29 | 29 | ||
| 30 | import ( | 30 | import ( |
| 31 | "crypto/hmac" | ||
| 32 | "crypto/md5" | ||
| 33 | "crypto/rand" | 31 | "crypto/rand" |
| 34 | "crypto/sha1" | ||
| 35 | "encoding/hex" | 32 | "encoding/hex" |
| 36 | "encoding/json" | 33 | "encoding/json" |
| 37 | "fmt" | 34 | "fmt" |
| 38 | "io" | ||
| 39 | "net/http" | 35 | "net/http" |
| 40 | "net/url" | 36 | "net/url" |
| 41 | "time" | 37 | "time" |
| 42 | |||
| 43 | "github.com/astaxie/beego/utils" | ||
| 44 | ) | 38 | ) |
| 45 | 39 | ||
| 46 | // SessionStore contains all data for one session process with specific id. | 40 | // SessionStore contains all data for one session process with specific id. |
| ... | @@ -81,16 +75,15 @@ func Register(name string, provide Provider) { | ... | @@ -81,16 +75,15 @@ func Register(name string, provide Provider) { |
| 81 | } | 75 | } |
| 82 | 76 | ||
| 83 | type managerConfig struct { | 77 | type managerConfig struct { |
| 84 | CookieName string `json:"cookieName"` | 78 | CookieName string `json:"cookieName"` |
| 85 | EnableSetCookie bool `json:"enableSetCookie,omitempty"` | 79 | EnableSetCookie bool `json:"enableSetCookie,omitempty"` |
| 86 | Gclifetime int64 `json:"gclifetime"` | 80 | Gclifetime int64 `json:"gclifetime"` |
| 87 | Maxlifetime int64 `json:"maxLifetime"` | 81 | Maxlifetime int64 `json:"maxLifetime"` |
| 88 | Secure bool `json:"secure"` | 82 | Secure bool `json:"secure"` |
| 89 | SessionIDHashFunc string `json:"sessionIDHashFunc"` | 83 | CookieLifeTime int `json:"cookieLifeTime"` |
| 90 | SessionIDHashKey string `json:"sessionIDHashKey"` | 84 | ProviderConfig string `json:"providerConfig"` |
| 91 | CookieLifeTime int `json:"cookieLifeTime"` | 85 | Domain string `json:"domain"` |
| 92 | ProviderConfig string `json:"providerConfig"` | 86 | SessionIdLength int64 `json:"sessionIdLength"` |
| 93 | Domain string `json:"domain"` | ||
| 94 | } | 87 | } |
| 95 | 88 | ||
| 96 | // Manager contains Provider and its configuration. | 89 | // Manager contains Provider and its configuration. |
| ... | @@ -129,11 +122,9 @@ func NewManager(provideName, config string) (*Manager, error) { | ... | @@ -129,11 +122,9 @@ func NewManager(provideName, config string) (*Manager, error) { |
| 129 | if err != nil { | 122 | if err != nil { |
| 130 | return nil, err | 123 | return nil, err |
| 131 | } | 124 | } |
| 132 | if cf.SessionIDHashFunc == "" { | 125 | |
| 133 | cf.SessionIDHashFunc = "sha1" | 126 | if cf.SessionIdLength == 0 { |
| 134 | } | 127 | cf.SessionIdLength = 16 |
| 135 | if cf.SessionIDHashKey == "" { | ||
| 136 | cf.SessionIDHashKey = string(generateRandomKey(16)) | ||
| 137 | } | 128 | } |
| 138 | 129 | ||
| 139 | return &Manager{ | 130 | return &Manager{ |
| ... | @@ -144,11 +135,14 @@ func NewManager(provideName, config string) (*Manager, error) { | ... | @@ -144,11 +135,14 @@ func NewManager(provideName, config string) (*Manager, error) { |
| 144 | 135 | ||
| 145 | // Start session. generate or read the session id from http request. | 136 | // Start session. generate or read the session id from http request. |
| 146 | // if session id exists, return SessionStore with this id. | 137 | // if session id exists, return SessionStore with this id. |
| 147 | func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore) { | 138 | func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (session SessionStore, err error) { |
| 148 | cookie, err := r.Cookie(manager.config.CookieName) | 139 | cookie, errs := r.Cookie(manager.config.CookieName) |
| 149 | if err != nil || cookie.Value == "" { | 140 | if errs != nil || cookie.Value == "" { |
| 150 | sid := manager.sessionId(r) | 141 | sid, errs := manager.sessionId(r) |
| 151 | session, _ = manager.provider.SessionRead(sid) | 142 | if errs != nil { |
| 143 | return nil, errs | ||
| 144 | } | ||
| 145 | session, err = manager.provider.SessionRead(sid) | ||
| 152 | cookie = &http.Cookie{Name: manager.config.CookieName, | 146 | cookie = &http.Cookie{Name: manager.config.CookieName, |
| 153 | Value: url.QueryEscape(sid), | 147 | Value: url.QueryEscape(sid), |
| 154 | Path: "/", | 148 | Path: "/", |
| ... | @@ -163,12 +157,18 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se | ... | @@ -163,12 +157,18 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se |
| 163 | } | 157 | } |
| 164 | r.AddCookie(cookie) | 158 | r.AddCookie(cookie) |
| 165 | } else { | 159 | } else { |
| 166 | sid, _ := url.QueryUnescape(cookie.Value) | 160 | sid, errs := url.QueryUnescape(cookie.Value) |
| 161 | if errs != nil { | ||
| 162 | return nil, errs | ||
| 163 | } | ||
| 167 | if manager.provider.SessionExist(sid) { | 164 | if manager.provider.SessionExist(sid) { |
| 168 | session, _ = manager.provider.SessionRead(sid) | 165 | session, err = manager.provider.SessionRead(sid) |
| 169 | } else { | 166 | } else { |
| 170 | sid = manager.sessionId(r) | 167 | sid, err = manager.sessionId(r) |
| 171 | session, _ = manager.provider.SessionRead(sid) | 168 | if err != nil { |
| 169 | return nil, err | ||
| 170 | } | ||
| 171 | session, err = manager.provider.SessionRead(sid) | ||
| 172 | cookie = &http.Cookie{Name: manager.config.CookieName, | 172 | cookie = &http.Cookie{Name: manager.config.CookieName, |
| 173 | Value: url.QueryEscape(sid), | 173 | Value: url.QueryEscape(sid), |
| 174 | Path: "/", | 174 | Path: "/", |
| ... | @@ -219,7 +219,10 @@ func (manager *Manager) GC() { | ... | @@ -219,7 +219,10 @@ func (manager *Manager) GC() { |
| 219 | 219 | ||
| 220 | // Regenerate a session id for this SessionStore who's id is saving in http request. | 220 | // Regenerate a session id for this SessionStore who's id is saving in http request. |
| 221 | func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session SessionStore) { | 221 | func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Request) (session SessionStore) { |
| 222 | sid := manager.sessionId(r) | 222 | sid, err := manager.sessionId(r) |
| 223 | if err != nil { | ||
| 224 | return | ||
| 225 | } | ||
| 223 | cookie, err := r.Cookie(manager.config.CookieName) | 226 | cookie, err := r.Cookie(manager.config.CookieName) |
| 224 | if err != nil && cookie.Value == "" { | 227 | if err != nil && cookie.Value == "" { |
| 225 | //delete old cookie | 228 | //delete old cookie |
| ... | @@ -251,36 +254,16 @@ func (manager *Manager) GetActiveSession() int { | ... | @@ -251,36 +254,16 @@ func (manager *Manager) GetActiveSession() int { |
| 251 | return manager.provider.SessionAll() | 254 | return manager.provider.SessionAll() |
| 252 | } | 255 | } |
| 253 | 256 | ||
| 254 | // Set hash function for generating session id. | ||
| 255 | func (manager *Manager) SetHashFunc(hasfunc, hashkey string) { | ||
| 256 | manager.config.SessionIDHashFunc = hasfunc | ||
| 257 | manager.config.SessionIDHashKey = hashkey | ||
| 258 | } | ||
| 259 | |||
| 260 | // Set cookie with https. | 257 | // Set cookie with https. |
| 261 | func (manager *Manager) SetSecure(secure bool) { | 258 | func (manager *Manager) SetSecure(secure bool) { |
| 262 | manager.config.Secure = secure | 259 | manager.config.Secure = secure |
| 263 | } | 260 | } |
| 264 | 261 | ||
| 265 | // generate session id with rand string, unix nano time, remote addr by hash function. | 262 | func (manager *Manager) sessionId(r *http.Request) (string, error) { |
| 266 | func (manager *Manager) sessionId(r *http.Request) (sid string) { | 263 | b := make([]byte, manager.config.SessionIdLength) |
| 267 | bs := make([]byte, 32) | 264 | n, err := rand.Read(b) |
| 268 | if n, err := io.ReadFull(rand.Reader, bs); n != 32 || err != nil { | 265 | if n != len(b) || err != nil { |
| 269 | bs = utils.RandomCreateBytes(32) | 266 | return "", fmt.Errorf("Could not successfully read from the system CSPRNG.") |
| 270 | } | ||
| 271 | sig := fmt.Sprintf("%s%d%s", r.RemoteAddr, time.Now().UnixNano(), bs) | ||
| 272 | if manager.config.SessionIDHashFunc == "md5" { | ||
| 273 | h := md5.New() | ||
| 274 | h.Write([]byte(sig)) | ||
| 275 | sid = hex.EncodeToString(h.Sum(nil)) | ||
| 276 | } else if manager.config.SessionIDHashFunc == "sha1" { | ||
| 277 | h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey)) | ||
| 278 | fmt.Fprintf(h, "%s", sig) | ||
| 279 | sid = hex.EncodeToString(h.Sum(nil)) | ||
| 280 | } else { | ||
| 281 | h := hmac.New(sha1.New, []byte(manager.config.SessionIDHashKey)) | ||
| 282 | fmt.Fprintf(h, "%s", sig) | ||
| 283 | sid = hex.EncodeToString(h.Sum(nil)) | ||
| 284 | } | 267 | } |
| 285 | return | 268 | return hex.EncodeToString(b), nil |
| 286 | } | 269 | } | ... | ... |
| ... | @@ -22,7 +22,6 @@ import ( | ... | @@ -22,7 +22,6 @@ import ( |
| 22 | "strings" | 22 | "strings" |
| 23 | 23 | ||
| 24 | "github.com/astaxie/beego/context" | 24 | "github.com/astaxie/beego/context" |
| 25 | "github.com/astaxie/beego/middleware" | ||
| 26 | "github.com/astaxie/beego/utils" | 25 | "github.com/astaxie/beego/utils" |
| 27 | ) | 26 | ) |
| 28 | 27 | ||
| ... | @@ -67,7 +66,7 @@ func serverStaticRouter(ctx *context.Context) { | ... | @@ -67,7 +66,7 @@ func serverStaticRouter(ctx *context.Context) { |
| 67 | //if the request is dir and DirectoryIndex is false then | 66 | //if the request is dir and DirectoryIndex is false then |
| 68 | if finfo.IsDir() { | 67 | if finfo.IsDir() { |
| 69 | if !DirectoryIndex { | 68 | if !DirectoryIndex { |
| 70 | middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden") | 69 | exception("403", ctx) |
| 71 | return | 70 | return |
| 72 | } else if ctx.Input.Request.URL.Path[len(ctx.Input.Request.URL.Path)-1] != '/' { | 71 | } else if ctx.Input.Request.URL.Path[len(ctx.Input.Request.URL.Path)-1] != '/' { |
| 73 | http.Redirect(ctx.ResponseWriter, ctx.Request, ctx.Input.Request.URL.Path+"/", 302) | 72 | http.Redirect(ctx.ResponseWriter, ctx.Request, ctx.Input.Request.URL.Path+"/", 302) | ... | ... |
| ... | @@ -42,6 +42,9 @@ func init() { | ... | @@ -42,6 +42,9 @@ func init() { |
| 42 | beegoTplFuncMap["dateformat"] = DateFormat | 42 | beegoTplFuncMap["dateformat"] = DateFormat |
| 43 | beegoTplFuncMap["date"] = Date | 43 | beegoTplFuncMap["date"] = Date |
| 44 | beegoTplFuncMap["compare"] = Compare | 44 | beegoTplFuncMap["compare"] = Compare |
| 45 | beegoTplFuncMap["compare_not"] = CompareNot | ||
| 46 | beegoTplFuncMap["not_nil"] = NotNil | ||
| 47 | beegoTplFuncMap["not_null"] = NotNil | ||
| 45 | beegoTplFuncMap["substr"] = Substr | 48 | beegoTplFuncMap["substr"] = Substr |
| 46 | beegoTplFuncMap["html2str"] = Html2str | 49 | beegoTplFuncMap["html2str"] = Html2str |
| 47 | beegoTplFuncMap["str2html"] = Str2html | 50 | beegoTplFuncMap["str2html"] = Str2html | ... | ... |
| ... | @@ -139,6 +139,14 @@ func Compare(a, b interface{}) (equal bool) { | ... | @@ -139,6 +139,14 @@ func Compare(a, b interface{}) (equal bool) { |
| 139 | return | 139 | return |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | func CompareNot(a, b interface{}) (equal bool) { | ||
| 143 | return ! Compare(a, b) | ||
| 144 | } | ||
| 145 | |||
| 146 | func NotNil(a interface{}) (is_nil bool) { | ||
| 147 | return CompareNot(a, nil) | ||
| 148 | } | ||
| 149 | |||
| 142 | func Config(returnType, key string, defaultVal interface{}) (value interface{}, err error) { | 150 | func Config(returnType, key string, defaultVal interface{}) (value interface{}, err error) { |
| 143 | switch returnType { | 151 | switch returnType { |
| 144 | case "String": | 152 | case "String": |
| ... | @@ -246,7 +254,7 @@ func Htmlunquote(src string) string { | ... | @@ -246,7 +254,7 @@ func Htmlunquote(src string) string { |
| 246 | // /user/John%20Doe | 254 | // /user/John%20Doe |
| 247 | // | 255 | // |
| 248 | // more detail http://beego.me/docs/mvc/controller/urlbuilding.md | 256 | // more detail http://beego.me/docs/mvc/controller/urlbuilding.md |
| 249 | func UrlFor(endpoint string, values ...string) string { | 257 | func UrlFor(endpoint string, values ...interface{}) string { |
| 250 | return BeeApp.Handlers.UrlFor(endpoint, values...) | 258 | return BeeApp.Handlers.UrlFor(endpoint, values...) |
| 251 | } | 259 | } |
| 252 | 260 | ||
| ... | @@ -302,6 +310,14 @@ func ParseForm(form url.Values, obj interface{}) error { | ... | @@ -302,6 +310,14 @@ func ParseForm(form url.Values, obj interface{}) error { |
| 302 | 310 | ||
| 303 | switch fieldT.Type.Kind() { | 311 | switch fieldT.Type.Kind() { |
| 304 | case reflect.Bool: | 312 | case reflect.Bool: |
| 313 | if strings.ToLower(value) == "on" || strings.ToLower(value) == "1" || strings.ToLower(value) == "yes" { | ||
| 314 | fieldV.SetBool(true) | ||
| 315 | continue | ||
| 316 | } | ||
| 317 | if strings.ToLower(value) == "off" || strings.ToLower(value) == "0" || strings.ToLower(value) == "no" { | ||
| 318 | fieldV.SetBool(false) | ||
| 319 | continue | ||
| 320 | } | ||
| 305 | b, err := strconv.ParseBool(value) | 321 | b, err := strconv.ParseBool(value) |
| 306 | if err != nil { | 322 | if err != nil { |
| 307 | return err | 323 | return err |
| ... | @@ -329,11 +345,45 @@ func ParseForm(form url.Values, obj interface{}) error { | ... | @@ -329,11 +345,45 @@ func ParseForm(form url.Values, obj interface{}) error { |
| 329 | fieldV.Set(reflect.ValueOf(value)) | 345 | fieldV.Set(reflect.ValueOf(value)) |
| 330 | case reflect.String: | 346 | case reflect.String: |
| 331 | fieldV.SetString(value) | 347 | fieldV.SetString(value) |
| 348 | case reflect.Struct: | ||
| 349 | switch fieldT.Type.String() { | ||
| 350 | case "time.Time": | ||
| 351 | format := time.RFC3339 | ||
| 352 | if len(tags) > 1 { | ||
| 353 | format = tags[1] | ||
| 354 | } | ||
| 355 | t, err := time.Parse(format, value) | ||
| 356 | if err != nil { | ||
| 357 | return err | ||
| 358 | } | ||
| 359 | fieldV.Set(reflect.ValueOf(t)) | ||
| 360 | } | ||
| 361 | case reflect.Slice: | ||
| 362 | if fieldT.Type == sliceOfInts { | ||
| 363 | formVals := form[tag] | ||
| 364 | fieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(int(1))), len(formVals), len(formVals))) | ||
| 365 | for i := 0; i < len(formVals); i++ { | ||
| 366 | val, err := strconv.Atoi(formVals[i]) | ||
| 367 | if err != nil { | ||
| 368 | return err | ||
| 369 | } | ||
| 370 | fieldV.Index(i).SetInt(int64(val)) | ||
| 371 | } | ||
| 372 | } else if fieldT.Type == sliceOfStrings { | ||
| 373 | formVals := form[tag] | ||
| 374 | fieldV.Set(reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf("")), len(formVals), len(formVals))) | ||
| 375 | for i := 0; i < len(formVals); i++ { | ||
| 376 | fieldV.Index(i).SetString(formVals[i]) | ||
| 377 | } | ||
| 378 | } | ||
| 332 | } | 379 | } |
| 333 | } | 380 | } |
| 334 | return nil | 381 | return nil |
| 335 | } | 382 | } |
| 336 | 383 | ||
| 384 | var sliceOfInts = reflect.TypeOf([]int(nil)) | ||
| 385 | var sliceOfStrings = reflect.TypeOf([]string(nil)) | ||
| 386 | |||
| 337 | var unKind = map[reflect.Kind]bool{ | 387 | var unKind = map[reflect.Kind]bool{ |
| 338 | reflect.Uintptr: true, | 388 | reflect.Uintptr: true, |
| 339 | reflect.Complex64: true, | 389 | reflect.Complex64: true, | ... | ... |
| ... | @@ -72,7 +72,7 @@ func TestDate(t *testing.T) { | ... | @@ -72,7 +72,7 @@ func TestDate(t *testing.T) { |
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | func TestCompare(t *testing.T) { | 75 | func TestCompareRelated(t *testing.T) { |
| 76 | if !Compare("abc", "abc") { | 76 | if !Compare("abc", "abc") { |
| 77 | t.Error("should be equal") | 77 | t.Error("should be equal") |
| 78 | } | 78 | } |
| ... | @@ -82,6 +82,15 @@ func TestCompare(t *testing.T) { | ... | @@ -82,6 +82,15 @@ func TestCompare(t *testing.T) { |
| 82 | if !Compare("1", 1) { | 82 | if !Compare("1", 1) { |
| 83 | t.Error("should be equal") | 83 | t.Error("should be equal") |
| 84 | } | 84 | } |
| 85 | if CompareNot("abc", "abc") { | ||
| 86 | t.Error("should be equal") | ||
| 87 | } | ||
| 88 | if !CompareNot("abc", "aBc") { | ||
| 89 | t.Error("should be not equal") | ||
| 90 | } | ||
| 91 | if !NotNil("a string") { | ||
| 92 | t.Error("should not be nil") | ||
| 93 | } | ||
| 85 | } | 94 | } |
| 86 | 95 | ||
| 87 | func TestHtmlquote(t *testing.T) { | 96 | func TestHtmlquote(t *testing.T) { |
| ... | @@ -102,12 +111,14 @@ func TestHtmlunquote(t *testing.T) { | ... | @@ -102,12 +111,14 @@ func TestHtmlunquote(t *testing.T) { |
| 102 | 111 | ||
| 103 | func TestParseForm(t *testing.T) { | 112 | func TestParseForm(t *testing.T) { |
| 104 | type user struct { | 113 | type user struct { |
| 105 | Id int `form:"-"` | 114 | Id int `form:"-"` |
| 106 | tag string `form:"tag"` | 115 | tag string `form:"tag"` |
| 107 | Name interface{} `form:"username"` | 116 | Name interface{} `form:"username"` |
| 108 | Age int `form:"age,text"` | 117 | Age int `form:"age,text"` |
| 109 | Email string | 118 | Email string |
| 110 | Intro string `form:",textarea"` | 119 | Intro string `form:",textarea"` |
| 120 | StrBool bool `form:"strbool"` | ||
| 121 | Date time.Time `form:"date,2006-01-02"` | ||
| 111 | } | 122 | } |
| 112 | 123 | ||
| 113 | u := user{} | 124 | u := user{} |
| ... | @@ -119,6 +130,8 @@ func TestParseForm(t *testing.T) { | ... | @@ -119,6 +130,8 @@ func TestParseForm(t *testing.T) { |
| 119 | "age": []string{"40"}, | 130 | "age": []string{"40"}, |
| 120 | "Email": []string{"test@gmail.com"}, | 131 | "Email": []string{"test@gmail.com"}, |
| 121 | "Intro": []string{"I am an engineer!"}, | 132 | "Intro": []string{"I am an engineer!"}, |
| 133 | "strbool": []string{"yes"}, | ||
| 134 | "date": []string{"2014-11-12"}, | ||
| 122 | } | 135 | } |
| 123 | if err := ParseForm(form, u); err == nil { | 136 | if err := ParseForm(form, u); err == nil { |
| 124 | t.Fatal("nothing will be changed") | 137 | t.Fatal("nothing will be changed") |
| ... | @@ -144,6 +157,13 @@ func TestParseForm(t *testing.T) { | ... | @@ -144,6 +157,13 @@ func TestParseForm(t *testing.T) { |
| 144 | if u.Intro != "I am an engineer!" { | 157 | if u.Intro != "I am an engineer!" { |
| 145 | t.Errorf("Intro should equal `I am an engineer!` but got `%v`", u.Intro) | 158 | t.Errorf("Intro should equal `I am an engineer!` but got `%v`", u.Intro) |
| 146 | } | 159 | } |
| 160 | if u.StrBool != true { | ||
| 161 | t.Errorf("strboll should equal `true`, but got `%v`", u.StrBool) | ||
| 162 | } | ||
| 163 | y, m, d := u.Date.Date() | ||
| 164 | if y != 2014 || m.String() != "November" || d != 12 { | ||
| 165 | t.Errorf("Date should equal `2014-11-12`, but got `%v`", u.Date.String()) | ||
| 166 | } | ||
| 147 | } | 167 | } |
| 148 | 168 | ||
| 149 | func TestRenderForm(t *testing.T) { | 169 | func TestRenderForm(t *testing.T) { | ... | ... |
| ... | @@ -84,6 +84,7 @@ type TaskFunc func() error | ... | @@ -84,6 +84,7 @@ type TaskFunc func() error |
| 84 | 84 | ||
| 85 | // task interface | 85 | // task interface |
| 86 | type Tasker interface { | 86 | type Tasker interface { |
| 87 | GetSpec() string | ||
| 87 | GetStatus() string | 88 | GetStatus() string |
| 88 | Run() error | 89 | Run() error |
| 89 | SetNext(time.Time) | 90 | SetNext(time.Time) |
| ... | @@ -102,6 +103,7 @@ type taskerr struct { | ... | @@ -102,6 +103,7 @@ type taskerr struct { |
| 102 | type Task struct { | 103 | type Task struct { |
| 103 | Taskname string | 104 | Taskname string |
| 104 | Spec *Schedule | 105 | Spec *Schedule |
| 106 | SpecStr string | ||
| 105 | DoFunc TaskFunc | 107 | DoFunc TaskFunc |
| 106 | Prev time.Time | 108 | Prev time.Time |
| 107 | Next time.Time | 109 | Next time.Time |
| ... | @@ -116,16 +118,22 @@ func NewTask(tname string, spec string, f TaskFunc) *Task { | ... | @@ -116,16 +118,22 @@ func NewTask(tname string, spec string, f TaskFunc) *Task { |
| 116 | Taskname: tname, | 118 | Taskname: tname, |
| 117 | DoFunc: f, | 119 | DoFunc: f, |
| 118 | ErrLimit: 100, | 120 | ErrLimit: 100, |
| 121 | SpecStr: spec, | ||
| 119 | } | 122 | } |
| 120 | task.SetCron(spec) | 123 | task.SetCron(spec) |
| 121 | return task | 124 | return task |
| 122 | } | 125 | } |
| 123 | 126 | ||
| 127 | //get spec string | ||
| 128 | func (s *Task) GetSpec() string { | ||
| 129 | return s.SpecStr | ||
| 130 | } | ||
| 131 | |||
| 124 | // get current task status | 132 | // get current task status |
| 125 | func (tk *Task) GetStatus() string { | 133 | func (tk *Task) GetStatus() string { |
| 126 | var str string | 134 | var str string |
| 127 | for _, v := range tk.Errlist { | 135 | for _, v := range tk.Errlist { |
| 128 | str += v.t.String() + ":" + v.errinfo + "\n" | 136 | str += v.t.String() + ":" + v.errinfo + "<br>" |
| 129 | } | 137 | } |
| 130 | return str | 138 | return str |
| 131 | } | 139 | } | ... | ... |
| ... | @@ -394,6 +394,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string | ... | @@ -394,6 +394,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string |
| 394 | } | 394 | } |
| 395 | return true, params | 395 | return true, params |
| 396 | } | 396 | } |
| 397 | if len(wildcardValues) <= j { | ||
| 398 | return false, nil | ||
| 399 | } | ||
| 397 | params[v] = wildcardValues[j] | 400 | params[v] = wildcardValues[j] |
| 398 | j += 1 | 401 | j += 1 |
| 399 | } | 402 | } |
| ... | @@ -419,6 +422,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string | ... | @@ -419,6 +422,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string |
| 419 | // "/admin/" -> ["admin"] | 422 | // "/admin/" -> ["admin"] |
| 420 | // "/admin/users" -> ["admin", "users"] | 423 | // "/admin/users" -> ["admin", "users"] |
| 421 | func splitPath(key string) []string { | 424 | func splitPath(key string) []string { |
| 425 | if key == "" { | ||
| 426 | return []string{} | ||
| 427 | } | ||
| 422 | elements := strings.Split(key, "/") | 428 | elements := strings.Split(key, "/") |
| 423 | if elements[0] == "" { | 429 | if elements[0] == "" { |
| 424 | elements = elements[1:] | 430 | elements = elements[1:] | ... | ... |
| ... | @@ -149,7 +149,11 @@ func TestAddTree2(t *testing.T) { | ... | @@ -149,7 +149,11 @@ func TestAddTree2(t *testing.T) { |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | func TestSplitPath(t *testing.T) { | 151 | func TestSplitPath(t *testing.T) { |
| 152 | a := splitPath("/") | 152 | a := splitPath("") |
| 153 | if len(a) != 0 { | ||
| 154 | t.Fatal("/ should retrun []") | ||
| 155 | } | ||
| 156 | a = splitPath("/") | ||
| 153 | if len(a) != 0 { | 157 | if len(a) != 0 { |
| 154 | t.Fatal("/ should retrun []") | 158 | t.Fatal("/ should retrun []") |
| 155 | } | 159 | } | ... | ... |
| ... | @@ -21,6 +21,6 @@ import ( | ... | @@ -21,6 +21,6 @@ import ( |
| 21 | // Instantiates a Paginator and assigns it to context.Input.Data["paginator"]. | 21 | // Instantiates a Paginator and assigns it to context.Input.Data["paginator"]. |
| 22 | func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { | 22 | func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { |
| 23 | paginator = NewPaginator(context.Request, per, nums) | 23 | paginator = NewPaginator(context.Request, per, nums) |
| 24 | context.Input.Data["paginator"] = paginator | 24 | context.Input.Data["paginator"] = &paginator |
| 25 | return | 25 | return |
| 26 | } | 26 | } | ... | ... |
| ... | @@ -114,7 +114,7 @@ func (p *Paginator) Pages() []int { | ... | @@ -114,7 +114,7 @@ func (p *Paginator) Pages() []int { |
| 114 | 114 | ||
| 115 | // Returns URL for a given page index. | 115 | // Returns URL for a given page index. |
| 116 | func (p *Paginator) PageLink(page int) string { | 116 | func (p *Paginator) PageLink(page int) string { |
| 117 | link, _ := url.ParseRequestURI(p.Request.RequestURI) | 117 | link, _ := url.ParseRequestURI(p.Request.URL.String()) |
| 118 | values := link.Query() | 118 | values := link.Query() |
| 119 | if page == 1 { | 119 | if page == 1 { |
| 120 | values.Del("p") | 120 | values.Del("p") | ... | ... |
-
Please register or sign in to post a comment