9f70561f by Meaglith Ma

Merge remote-tracking branch 'upstream/master' into develop

2 parents e11a27f1 1c9898de
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
3 [![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest) 3 [![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest)
4 [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) 4 [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](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.
......
...@@ -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.
......
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{
......
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() {
......
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")
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!