Merge branch 'develop'
Showing
43 changed files
with
746 additions
and
428 deletions
| ... | @@ -397,7 +397,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { | ... | @@ -397,7 +397,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { |
| 397 | if err != nil { | 397 | if err != nil { |
| 398 | data["Message"] = []string{"error", fmt.Sprintf("%s", err)} | 398 | data["Message"] = []string{"error", fmt.Sprintf("%s", err)} |
| 399 | } | 399 | } |
| 400 | 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())} |
| 401 | } else { | 401 | } else { |
| 402 | 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)} |
| 403 | } | 403 | } |
| ... | @@ -410,12 +410,14 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { | ... | @@ -410,12 +410,14 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { |
| 410 | var fields = []string{ | 410 | var fields = []string{ |
| 411 | fmt.Sprintf("Task Name"), | 411 | fmt.Sprintf("Task Name"), |
| 412 | fmt.Sprintf("Task Spec"), | 412 | fmt.Sprintf("Task Spec"), |
| 413 | fmt.Sprintf("Task Function"), | 413 | fmt.Sprintf("Task Status"), |
| 414 | fmt.Sprintf("Last Time"), | ||
| 414 | fmt.Sprintf(""), | 415 | fmt.Sprintf(""), |
| 415 | } | 416 | } |
| 416 | for tname, tk := range toolbox.AdminTaskList { | 417 | for tname, tk := range toolbox.AdminTaskList { |
| 417 | result = []string{ | 418 | result = []string{ |
| 418 | fmt.Sprintf("%s", tname), | 419 | fmt.Sprintf("%s", tname), |
| 420 | fmt.Sprintf("%s", tk.GetSpec()), | ||
| 419 | fmt.Sprintf("%s", tk.GetStatus()), | 421 | fmt.Sprintf("%s", tk.GetStatus()), |
| 420 | fmt.Sprintf("%s", tk.GetPrev().String()), | 422 | fmt.Sprintf("%s", tk.GetPrev().String()), |
| 421 | } | 423 | } | ... | ... |
| ... | @@ -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,7 +19,10 @@ import ( | ... | @@ -19,7 +19,10 @@ 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" |
| 24 | |||
| 25 | "github.com/astaxie/beego/utils" | ||
| 23 | ) | 26 | ) |
| 24 | 27 | ||
| 25 | // App defines beego application with a new PatternServeMux. | 28 | // App defines beego application with a new PatternServeMux. |
| ... | @@ -59,6 +62,10 @@ func (app *App) Run() { | ... | @@ -59,6 +62,10 @@ func (app *App) Run() { |
| 59 | } | 62 | } |
| 60 | } else { | 63 | } else { |
| 61 | if HttpPort == 0 { | 64 | if HttpPort == 0 { |
| 65 | // remove the Socket file before start | ||
| 66 | if utils.FileExists(addr) { | ||
| 67 | os.Remove(addr) | ||
| 68 | } | ||
| 62 | l, err = net.Listen("unix", addr) | 69 | l, err = net.Listen("unix", addr) |
| 63 | } else { | 70 | } else { |
| 64 | l, err = net.Listen("tcp", addr) | 71 | l, err = net.Listen("tcp", addr) | ... | ... |
| ... | @@ -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.2" | 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 |
| ... | @@ -402,9 +325,7 @@ func initBeforeHttpRun() { | ... | @@ -402,9 +325,7 @@ func initBeforeHttpRun() { |
| 402 | } | 325 | } |
| 403 | } | 326 | } |
| 404 | 327 | ||
| 405 | middleware.VERSION = VERSION | 328 | registerDefaultErrorHandler() |
| 406 | middleware.AppName = AppName | ||
| 407 | middleware.RegisterErrorHandler() | ||
| 408 | 329 | ||
| 409 | if EnableDocs { | 330 | if EnableDocs { |
| 410 | 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 | ||
| ... | @@ -137,7 +139,7 @@ func (rc *RedisCache) ClearAll() error { | ... | @@ -137,7 +139,7 @@ func (rc *RedisCache) ClearAll() error { |
| 137 | } | 139 | } |
| 138 | 140 | ||
| 139 | // start redis cache adapter. | 141 | // start redis cache adapter. |
| 140 | // config is like {"key":"collection key","conn":"connection info"} | 142 | // config is like {"key":"collection key","conn":"connection info","dbNum":"0"} |
| 141 | // the cache item in redis are stored forever, | 143 | // the cache item in redis are stored forever, |
| 142 | // so no gc operation. | 144 | // so no gc operation. |
| 143 | func (rc *RedisCache) StartAndGC(config string) error { | 145 | func (rc *RedisCache) StartAndGC(config string) error { |
| ... | @@ -151,9 +153,12 @@ func (rc *RedisCache) StartAndGC(config string) error { | ... | @@ -151,9 +153,12 @@ func (rc *RedisCache) StartAndGC(config string) error { |
| 151 | if _, ok := cf["conn"]; !ok { | 153 | if _, ok := cf["conn"]; !ok { |
| 152 | return errors.New("config has no conn key") | 154 | return errors.New("config has no conn key") |
| 153 | } | 155 | } |
| 154 | 156 | if _, ok := cf["dbNum"]; !ok { | |
| 157 | cf["dbNum"] = "0" | ||
| 158 | } | ||
| 155 | rc.key = cf["key"] | 159 | rc.key = cf["key"] |
| 156 | rc.conninfo = cf["conn"] | 160 | rc.conninfo = cf["conn"] |
| 161 | rc.dbNum, _ = strconv.Atoi(cf["dbNum"]) | ||
| 157 | rc.connectInit() | 162 | rc.connectInit() |
| 158 | 163 | ||
| 159 | c := rc.p.Get() | 164 | c := rc.p.Get() |
| ... | @@ -166,6 +171,11 @@ func (rc *RedisCache) StartAndGC(config string) error { | ... | @@ -166,6 +171,11 @@ func (rc *RedisCache) StartAndGC(config string) error { |
| 166 | func (rc *RedisCache) connectInit() { | 171 | func (rc *RedisCache) connectInit() { |
| 167 | dialFunc := func() (c redis.Conn, err error) { | 172 | dialFunc := func() (c redis.Conn, err error) { |
| 168 | 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 | } | ||
| 169 | return | 179 | return |
| 170 | } | 180 | } |
| 171 | // initialize a new pool | 181 | // initialize a new pool | ... | ... |
| ... | @@ -81,6 +81,7 @@ var ( | ... | @@ -81,6 +81,7 @@ var ( |
| 81 | AppConfigProvider string // config provider | 81 | AppConfigProvider string // config provider |
| 82 | EnableDocs bool // enable generate docs & server docs API Swagger | 82 | EnableDocs bool // enable generate docs & server docs API Swagger |
| 83 | 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 | ||
| 84 | ) | 85 | ) |
| 85 | 86 | ||
| 86 | type beegoAppConfig struct { | 87 | type beegoAppConfig struct { |
| ... | @@ -110,7 +111,7 @@ func (b *beegoAppConfig) String(key string) string { | ... | @@ -110,7 +111,7 @@ func (b *beegoAppConfig) String(key string) string { |
| 110 | 111 | ||
| 111 | func (b *beegoAppConfig) Strings(key string) []string { | 112 | func (b *beegoAppConfig) Strings(key string) []string { |
| 112 | v := b.innerConfig.Strings(RunMode + "::" + key) | 113 | v := b.innerConfig.Strings(RunMode + "::" + key) |
| 113 | if len(v) == 0 { | 114 | if v[0] == "" { |
| 114 | return b.innerConfig.Strings(key) | 115 | return b.innerConfig.Strings(key) |
| 115 | } | 116 | } |
| 116 | return v | 117 | return v | ... | ... |
| ... | @@ -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, |
| ... | @@ -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,24 +52,10 @@ func (ctx *Context) Redirect(status int, localurl string) { | ... | @@ -53,24 +52,10 @@ 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) | 58 | 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 | ctx.ResponseWriter.Write([]byte(body)) | ||
| 73 | panic("User stop run") | ||
| 74 | } | 59 | } |
| 75 | 60 | ||
| 76 | // Write string to response body. | 61 | // Write string to response body. |
| ... | @@ -155,8 +140,11 @@ func (ctx *Context) CheckXsrfCookie() bool { | ... | @@ -155,8 +140,11 @@ func (ctx *Context) CheckXsrfCookie() bool { |
| 155 | } | 140 | } |
| 156 | if token == "" { | 141 | if token == "" { |
| 157 | ctx.Abort(403, "'_xsrf' argument missing from POST") | 142 | ctx.Abort(403, "'_xsrf' argument missing from POST") |
| 158 | } else if ctx._xsrf_token != token { | 143 | return false |
| 144 | } | ||
| 145 | if ctx._xsrf_token != token { | ||
| 159 | ctx.Abort(403, "XSRF cookie does not match POST argument") | 146 | ctx.Abort(403, "XSRF cookie does not match POST argument") |
| 147 | return false | ||
| 160 | } | 148 | } |
| 161 | return true | 149 | return true |
| 162 | } | 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 | ||
| 428 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 429 | i64, err := strconv.ParseInt(strv, 10, 8) | ||
| 430 | i8 := int8(i64) | ||
| 395 | return i8, err | 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 |
| 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) | ||
| 401 | i16 := int16(i64) | 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) { |
| 456 | var defv int32 | ||
| 457 | if len(def) > 0 { | ||
| 458 | defv = def[0] | ||
| 459 | } | ||
| 460 | |||
| 461 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 408 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32) | 462 | i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32) |
| 409 | i32 := int32(i64) | 463 | i32 := int32(i64) |
| 410 | |||
| 411 | return i32, err | 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) { |
| 500 | var defv float64 | ||
| 501 | if len(def) > 0 { | ||
| 502 | defv = def[0] | ||
| 503 | } | ||
| 504 | |||
| 505 | if strv := c.Ctx.Input.Query(key); strv != "" { | ||
| 426 | return strconv.ParseFloat(c.Ctx.Input.Query(key), 64) | 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. | ... | ... |
| ... | @@ -12,20 +12,26 @@ | ... | @@ -12,20 +12,26 @@ |
| 12 | // See the License for the specific language governing permissions and | 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. | 13 | // limitations under the License. |
| 14 | 14 | ||
| 15 | package middleware | 15 | package beego |
| 16 | 16 | ||
| 17 | import ( | 17 | import ( |
| 18 | "fmt" | 18 | "fmt" |
| 19 | "html/template" | 19 | "html/template" |
| 20 | "net/http" | 20 | "net/http" |
| 21 | "reflect" | ||
| 21 | "runtime" | 22 | "runtime" |
| 22 | "strconv" | 23 | "strconv" |
| 24 | "strings" | ||
| 25 | |||
| 26 | "github.com/astaxie/beego/context" | ||
| 27 | "github.com/astaxie/beego/utils" | ||
| 23 | ) | 28 | ) |
| 24 | 29 | ||
| 25 | var ( | 30 | const ( |
| 26 | AppName string | 31 | errorTypeHandler = iota |
| 27 | VERSION string | 32 | errorTypeController |
| 28 | ) | 33 | ) |
| 34 | |||
| 29 | var tpl = ` | 35 | var tpl = ` |
| 30 | <!DOCTYPE html> | 36 | <!DOCTYPE html> |
| 31 | <html> | 37 | <html> |
| ... | @@ -76,18 +82,18 @@ var tpl = ` | ... | @@ -76,18 +82,18 @@ var tpl = ` |
| 76 | ` | 82 | ` |
| 77 | 83 | ||
| 78 | // render default application error page with error and stack string. | 84 | // render default application error page with error and stack string. |
| 79 | func ShowErr(err interface{}, rw http.ResponseWriter, r *http.Request, Stack string) { | 85 | func showErr(err interface{}, ctx *context.Context, Stack string) { |
| 80 | t, _ := template.New("beegoerrortemp").Parse(tpl) | 86 | t, _ := template.New("beegoerrortemp").Parse(tpl) |
| 81 | data := make(map[string]string) | 87 | data := make(map[string]string) |
| 82 | data["AppError"] = AppName + ":" + fmt.Sprint(err) | 88 | data["AppError"] = AppName + ":" + fmt.Sprint(err) |
| 83 | data["RequestMethod"] = r.Method | 89 | data["RequestMethod"] = ctx.Input.Method() |
| 84 | data["RequestURL"] = r.RequestURI | 90 | data["RequestURL"] = ctx.Input.Uri() |
| 85 | data["RemoteAddr"] = r.RemoteAddr | 91 | data["RemoteAddr"] = ctx.Input.IP() |
| 86 | data["Stack"] = Stack | 92 | data["Stack"] = Stack |
| 87 | data["BeegoVersion"] = VERSION | 93 | data["BeegoVersion"] = VERSION |
| 88 | data["GoVersion"] = runtime.Version() | 94 | data["GoVersion"] = runtime.Version() |
| 89 | rw.WriteHeader(500) | 95 | ctx.Output.SetStatus(500) |
| 90 | t.Execute(rw, data) | 96 | t.Execute(ctx.ResponseWriter, data) |
| 91 | } | 97 | } |
| 92 | 98 | ||
| 93 | var errtpl = ` | 99 | var errtpl = ` |
| ... | @@ -190,49 +196,52 @@ var errtpl = ` | ... | @@ -190,49 +196,52 @@ var errtpl = ` |
| 190 | </html> | 196 | </html> |
| 191 | ` | 197 | ` |
| 192 | 198 | ||
| 199 | type errorInfo struct { | ||
| 200 | controllerType reflect.Type | ||
| 201 | handler http.HandlerFunc | ||
| 202 | method string | ||
| 203 | errorType int | ||
| 204 | } | ||
| 205 | |||
| 193 | // map of http handlers for each error string. | 206 | // map of http handlers for each error string. |
| 194 | var ErrorMaps map[string]http.HandlerFunc | 207 | var ErrorMaps map[string]*errorInfo |
| 195 | 208 | ||
| 196 | func init() { | 209 | func init() { |
| 197 | ErrorMaps = make(map[string]http.HandlerFunc) | 210 | ErrorMaps = make(map[string]*errorInfo) |
| 198 | } | 211 | } |
| 199 | 212 | ||
| 200 | // show 404 notfound error. | 213 | // show 401 unauthorized error. |
| 201 | func NotFound(rw http.ResponseWriter, r *http.Request) { | 214 | func unauthorized(rw http.ResponseWriter, r *http.Request) { |
| 202 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | 215 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 203 | data := make(map[string]interface{}) | 216 | data := make(map[string]interface{}) |
| 204 | data["Title"] = "Page Not Found" | 217 | data["Title"] = "Unauthorized" |
| 205 | data["Content"] = template.HTML("<br>The page you have requested has flown the coop." + | 218 | data["Content"] = template.HTML("<br>The page you have requested can't be authorized." + |
| 206 | "<br>Perhaps you are here because:" + | 219 | "<br>Perhaps you are here because:" + |
| 207 | "<br><br><ul>" + | 220 | "<br><br><ul>" + |
| 208 | "<br>The page has moved" + | 221 | "<br>The credentials you supplied are incorrect" + |
| 209 | "<br>The page no longer exists" + | 222 | "<br>There are errors in the website address" + |
| 210 | "<br>You were looking for your puppy and got lost" + | ||
| 211 | "<br>You like 404 pages" + | ||
| 212 | "</ul>") | 223 | "</ul>") |
| 213 | data["BeegoVersion"] = VERSION | 224 | data["BeegoVersion"] = VERSION |
| 214 | //rw.WriteHeader(http.StatusNotFound) | ||
| 215 | t.Execute(rw, data) | 225 | t.Execute(rw, data) |
| 216 | } | 226 | } |
| 217 | 227 | ||
| 218 | // show 401 unauthorized error. | 228 | // show 402 Payment Required |
| 219 | func Unauthorized(rw http.ResponseWriter, r *http.Request) { | 229 | func paymentRequired(rw http.ResponseWriter, r *http.Request) { |
| 220 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | 230 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 221 | data := make(map[string]interface{}) | 231 | data := make(map[string]interface{}) |
| 222 | data["Title"] = "Unauthorized" | 232 | data["Title"] = "Payment Required" |
| 223 | data["Content"] = template.HTML("<br>The page you have requested can't be authorized." + | 233 | data["Content"] = template.HTML("<br>The page you have requested Payment Required." + |
| 224 | "<br>Perhaps you are here because:" + | 234 | "<br>Perhaps you are here because:" + |
| 225 | "<br><br><ul>" + | 235 | "<br><br><ul>" + |
| 226 | "<br>The credentials you supplied are incorrect" + | 236 | "<br>The credentials you supplied are incorrect" + |
| 227 | "<br>There are errors in the website address" + | 237 | "<br>There are errors in the website address" + |
| 228 | "</ul>") | 238 | "</ul>") |
| 229 | data["BeegoVersion"] = VERSION | 239 | data["BeegoVersion"] = VERSION |
| 230 | //rw.WriteHeader(http.StatusUnauthorized) | ||
| 231 | t.Execute(rw, data) | 240 | t.Execute(rw, data) |
| 232 | } | 241 | } |
| 233 | 242 | ||
| 234 | // show 403 forbidden error. | 243 | // show 403 forbidden error. |
| 235 | func Forbidden(rw http.ResponseWriter, r *http.Request) { | 244 | func forbidden(rw http.ResponseWriter, r *http.Request) { |
| 236 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | 245 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 237 | data := make(map[string]interface{}) | 246 | data := make(map[string]interface{}) |
| 238 | data["Title"] = "Forbidden" | 247 | data["Title"] = "Forbidden" |
| ... | @@ -244,28 +253,43 @@ func Forbidden(rw http.ResponseWriter, r *http.Request) { | ... | @@ -244,28 +253,43 @@ func Forbidden(rw http.ResponseWriter, r *http.Request) { |
| 244 | "<br>You need to log in" + | 253 | "<br>You need to log in" + |
| 245 | "</ul>") | 254 | "</ul>") |
| 246 | data["BeegoVersion"] = VERSION | 255 | data["BeegoVersion"] = VERSION |
| 247 | //rw.WriteHeader(http.StatusForbidden) | ||
| 248 | t.Execute(rw, data) | 256 | t.Execute(rw, data) |
| 249 | } | 257 | } |
| 250 | 258 | ||
| 251 | // show 503 service unavailable error. | 259 | // show 404 notfound error. |
| 252 | func ServiceUnavailable(rw http.ResponseWriter, r *http.Request) { | 260 | func notFound(rw http.ResponseWriter, r *http.Request) { |
| 253 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | 261 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 254 | data := make(map[string]interface{}) | 262 | data := make(map[string]interface{}) |
| 255 | data["Title"] = "Service Unavailable" | 263 | data["Title"] = "Page Not Found" |
| 256 | data["Content"] = template.HTML("<br>The page you have requested is unavailable." + | 264 | data["Content"] = template.HTML("<br>The page you have requested has flown the coop." + |
| 257 | "<br>Perhaps you are here because:" + | 265 | "<br>Perhaps you are here because:" + |
| 258 | "<br><br><ul>" + | 266 | "<br><br><ul>" + |
| 259 | "<br><br>The page is overloaded" + | 267 | "<br>The page has moved" + |
| 260 | "<br>Please try again later." + | 268 | "<br>The page no longer exists" + |
| 269 | "<br>You were looking for your puppy and got lost" + | ||
| 270 | "<br>You like 404 pages" + | ||
| 271 | "</ul>") | ||
| 272 | data["BeegoVersion"] = VERSION | ||
| 273 | t.Execute(rw, data) | ||
| 274 | } | ||
| 275 | |||
| 276 | // show 405 Method Not Allowed | ||
| 277 | func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { | ||
| 278 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | ||
| 279 | data := make(map[string]interface{}) | ||
| 280 | data["Title"] = "Method Not Allowed" | ||
| 281 | data["Content"] = template.HTML("<br>The method you have requested Not Allowed." + | ||
| 282 | "<br>Perhaps you are here because:" + | ||
| 283 | "<br><br><ul>" + | ||
| 284 | "<br>The method specified in the Request-Line is not allowed for the resource identified by the Request-URI" + | ||
| 285 | "<br>The response MUST include an Allow header containing a list of valid methods for the requested resource." + | ||
| 261 | "</ul>") | 286 | "</ul>") |
| 262 | data["BeegoVersion"] = VERSION | 287 | data["BeegoVersion"] = VERSION |
| 263 | //rw.WriteHeader(http.StatusServiceUnavailable) | ||
| 264 | t.Execute(rw, data) | 288 | t.Execute(rw, data) |
| 265 | } | 289 | } |
| 266 | 290 | ||
| 267 | // show 500 internal server error. | 291 | // show 500 internal server error. |
| 268 | func InternalServerError(rw http.ResponseWriter, r *http.Request) { | 292 | func internalServerError(rw http.ResponseWriter, r *http.Request) { |
| 269 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | 293 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 270 | data := make(map[string]interface{}) | 294 | data := make(map[string]interface{}) |
| 271 | data["Title"] = "Internal Server Error" | 295 | data["Title"] = "Internal Server Error" |
| ... | @@ -274,66 +298,193 @@ func InternalServerError(rw http.ResponseWriter, r *http.Request) { | ... | @@ -274,66 +298,193 @@ func InternalServerError(rw http.ResponseWriter, r *http.Request) { |
| 274 | "<br>Please try again later and report the error to the website administrator" + | 298 | "<br>Please try again later and report the error to the website administrator" + |
| 275 | "<br></ul>") | 299 | "<br></ul>") |
| 276 | data["BeegoVersion"] = VERSION | 300 | data["BeegoVersion"] = VERSION |
| 277 | //rw.WriteHeader(http.StatusInternalServerError) | ||
| 278 | t.Execute(rw, data) | 301 | t.Execute(rw, data) |
| 279 | } | 302 | } |
| 280 | 303 | ||
| 281 | // show 500 internal error with simple text string. | 304 | // show 501 Not Implemented. |
| 282 | func SimpleServerError(rw http.ResponseWriter, r *http.Request) { | 305 | func notImplemented(rw http.ResponseWriter, r *http.Request) { |
| 283 | http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) | 306 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 307 | data := make(map[string]interface{}) | ||
| 308 | data["Title"] = "Not Implemented" | ||
| 309 | data["Content"] = template.HTML("<br>The page you have requested is Not Implemented." + | ||
| 310 | "<br><br><ul>" + | ||
| 311 | "<br>Please try again later and report the error to the website administrator" + | ||
| 312 | "<br></ul>") | ||
| 313 | data["BeegoVersion"] = VERSION | ||
| 314 | t.Execute(rw, data) | ||
| 315 | } | ||
| 316 | |||
| 317 | // show 502 Bad Gateway. | ||
| 318 | func badGateway(rw http.ResponseWriter, r *http.Request) { | ||
| 319 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | ||
| 320 | data := make(map[string]interface{}) | ||
| 321 | data["Title"] = "Bad Gateway" | ||
| 322 | data["Content"] = template.HTML("<br>The page you have requested is down right now." + | ||
| 323 | "<br><br><ul>" + | ||
| 324 | "<br>The server, while acting as a gateway or proxy, received an invalid response from the upstream server it accessed in attempting to fulfill the request." + | ||
| 325 | "<br>Please try again later and report the error to the website administrator" + | ||
| 326 | "<br></ul>") | ||
| 327 | data["BeegoVersion"] = VERSION | ||
| 328 | t.Execute(rw, data) | ||
| 329 | } | ||
| 330 | |||
| 331 | // show 503 service unavailable error. | ||
| 332 | func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { | ||
| 333 | t, _ := template.New("beegoerrortemp").Parse(errtpl) | ||
| 334 | data := make(map[string]interface{}) | ||
| 335 | data["Title"] = "Service Unavailable" | ||
| 336 | data["Content"] = template.HTML("<br>The page you have requested is unavailable." + | ||
| 337 | "<br>Perhaps you are here because:" + | ||
| 338 | "<br><br><ul>" + | ||
| 339 | "<br><br>The page is overloaded" + | ||
| 340 | "<br>Please try again later." + | ||
| 341 | "</ul>") | ||
| 342 | data["BeegoVersion"] = VERSION | ||
| 343 | t.Execute(rw, data) | ||
| 284 | } | 344 | } |
| 285 | 345 | ||
| 286 | // add http handler for given error string. | 346 | // show 504 Gateway Timeout. |
| 287 | func Errorhandler(err string, h http.HandlerFunc) { | 347 | func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { |
| 288 | ErrorMaps[err] = h | 348 | t, _ := template.New("beegoerrortemp").Parse(errtpl) |
| 349 | data := make(map[string]interface{}) | ||
| 350 | data["Title"] = "Gateway Timeout" | ||
| 351 | data["Content"] = template.HTML("<br>The page you have requested is unavailable." + | ||
| 352 | "<br>Perhaps you are here because:" + | ||
| 353 | "<br><br><ul>" + | ||
| 354 | "<br><br>The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI." + | ||
| 355 | "<br>Please try again later." + | ||
| 356 | "</ul>") | ||
| 357 | data["BeegoVersion"] = VERSION | ||
| 358 | t.Execute(rw, data) | ||
| 289 | } | 359 | } |
| 290 | 360 | ||
| 291 | // register default error http handlers, 404,401,403,500 and 503. | 361 | // register default error http handlers, 404,401,403,500 and 503. |
| 292 | func RegisterErrorHandler() { | 362 | func registerDefaultErrorHandler() { |
| 293 | if _, ok := ErrorMaps["404"]; !ok { | 363 | if _, ok := ErrorMaps["401"]; !ok { |
| 294 | ErrorMaps["404"] = NotFound | 364 | Errorhandler("401", unauthorized) |
| 295 | } | 365 | } |
| 296 | 366 | ||
| 297 | if _, ok := ErrorMaps["401"]; !ok { | 367 | if _, ok := ErrorMaps["402"]; !ok { |
| 298 | ErrorMaps["401"] = Unauthorized | 368 | Errorhandler("402", paymentRequired) |
| 299 | } | 369 | } |
| 300 | 370 | ||
| 301 | if _, ok := ErrorMaps["403"]; !ok { | 371 | if _, ok := ErrorMaps["403"]; !ok { |
| 302 | ErrorMaps["403"] = Forbidden | 372 | Errorhandler("403", forbidden) |
| 303 | } | 373 | } |
| 304 | 374 | ||
| 305 | if _, ok := ErrorMaps["503"]; !ok { | 375 | if _, ok := ErrorMaps["404"]; !ok { |
| 306 | ErrorMaps["503"] = ServiceUnavailable | 376 | Errorhandler("404", notFound) |
| 377 | } | ||
| 378 | |||
| 379 | if _, ok := ErrorMaps["405"]; !ok { | ||
| 380 | Errorhandler("405", methodNotAllowed) | ||
| 307 | } | 381 | } |
| 308 | 382 | ||
| 309 | if _, ok := ErrorMaps["500"]; !ok { | 383 | if _, ok := ErrorMaps["500"]; !ok { |
| 310 | ErrorMaps["500"] = InternalServerError | 384 | Errorhandler("500", internalServerError) |
| 385 | } | ||
| 386 | if _, ok := ErrorMaps["501"]; !ok { | ||
| 387 | Errorhandler("501", notImplemented) | ||
| 311 | } | 388 | } |
| 389 | if _, ok := ErrorMaps["502"]; !ok { | ||
| 390 | Errorhandler("502", badGateway) | ||
| 391 | } | ||
| 392 | |||
| 393 | if _, ok := ErrorMaps["503"]; !ok { | ||
| 394 | Errorhandler("503", serviceUnavailable) | ||
| 395 | } | ||
| 396 | |||
| 397 | if _, ok := ErrorMaps["504"]; !ok { | ||
| 398 | Errorhandler("504", gatewayTimeout) | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | // ErrorHandler registers http.HandlerFunc to each http err code string. | ||
| 403 | // usage: | ||
| 404 | // beego.ErrorHandler("404",NotFound) | ||
| 405 | // beego.ErrorHandler("500",InternalServerError) | ||
| 406 | func Errorhandler(code string, h http.HandlerFunc) *App { | ||
| 407 | errinfo := &errorInfo{} | ||
| 408 | errinfo.errorType = errorTypeHandler | ||
| 409 | errinfo.handler = h | ||
| 410 | errinfo.method = code | ||
| 411 | ErrorMaps[code] = errinfo | ||
| 412 | return BeeApp | ||
| 413 | } | ||
| 414 | |||
| 415 | // ErrorController registers ControllerInterface to each http err code string. | ||
| 416 | // usage: | ||
| 417 | // beego.ErrorHandler(&controllers.ErrorController{}) | ||
| 418 | func ErrorController(c ControllerInterface) *App { | ||
| 419 | reflectVal := reflect.ValueOf(c) | ||
| 420 | rt := reflectVal.Type() | ||
| 421 | ct := reflect.Indirect(reflectVal).Type() | ||
| 422 | for i := 0; i < rt.NumMethod(); i++ { | ||
| 423 | if !utils.InSlice(rt.Method(i).Name, exceptMethod) && strings.HasPrefix(rt.Method(i).Name, "Error") { | ||
| 424 | errinfo := &errorInfo{} | ||
| 425 | errinfo.errorType = errorTypeController | ||
| 426 | errinfo.controllerType = ct | ||
| 427 | errinfo.method = rt.Method(i).Name | ||
| 428 | errname := strings.TrimPrefix(rt.Method(i).Name, "Error") | ||
| 429 | ErrorMaps[errname] = errinfo | ||
| 430 | } | ||
| 431 | } | ||
| 432 | return BeeApp | ||
| 312 | } | 433 | } |
| 313 | 434 | ||
| 314 | // show error string as simple text message. | 435 | // show error string as simple text message. |
| 315 | // if error string is empty, show 500 error as default. | 436 | // if error string is empty, show 500 error as default. |
| 316 | func Exception(errcode string, w http.ResponseWriter, r *http.Request, msg string) { | 437 | func exception(errcode string, ctx *context.Context) { |
| 317 | if h, ok := ErrorMaps[errcode]; ok { | 438 | code, err := strconv.Atoi(errcode) |
| 318 | isint, err := strconv.Atoi(errcode) | ||
| 319 | if err != nil { | 439 | if err != nil { |
| 320 | isint = 500 | 440 | code = 503 |
| 321 | } | 441 | } |
| 322 | w.Header().Set("Content-Type", "text/html; charset=utf-8") | 442 | ctx.ResponseWriter.WriteHeader(code) |
| 323 | w.WriteHeader(isint) | 443 | if h, ok := ErrorMaps[errcode]; ok { |
| 324 | h(w, r) | 444 | executeError(h, ctx) |
| 445 | return | ||
| 446 | } else if h, ok := ErrorMaps["503"]; ok { | ||
| 447 | executeError(h, ctx) | ||
| 325 | return | 448 | return |
| 326 | } else { | 449 | } else { |
| 327 | isint, err := strconv.Atoi(errcode) | 450 | ctx.WriteString(errcode) |
| 328 | if err != nil { | ||
| 329 | isint = 500 | ||
| 330 | } | ||
| 331 | if isint == 400 { | ||
| 332 | msg = "404 page not found" | ||
| 333 | } | 451 | } |
| 334 | w.Header().Set("Content-Type", "text/plain; charset=utf-8") | 452 | } |
| 335 | w.WriteHeader(isint) | 453 | |
| 336 | fmt.Fprintln(w, msg) | 454 | func executeError(err *errorInfo, ctx *context.Context) { |
| 455 | if err.errorType == errorTypeHandler { | ||
| 456 | err.handler(ctx.ResponseWriter, ctx.Request) | ||
| 337 | return | 457 | return |
| 338 | } | 458 | } |
| 459 | if err.errorType == errorTypeController { | ||
| 460 | //Invoke the request handler | ||
| 461 | vc := reflect.New(err.controllerType) | ||
| 462 | execController, ok := vc.Interface().(ControllerInterface) | ||
| 463 | if !ok { | ||
| 464 | panic("controller is not ControllerInterface") | ||
| 465 | } | ||
| 466 | //call the controller init function | ||
| 467 | execController.Init(ctx, err.controllerType.Name(), err.method, vc.Interface()) | ||
| 468 | |||
| 469 | //call prepare function | ||
| 470 | execController.Prepare() | ||
| 471 | |||
| 472 | execController.URLMapping() | ||
| 473 | |||
| 474 | in := make([]reflect.Value, 0) | ||
| 475 | method := vc.MethodByName(err.method) | ||
| 476 | method.Call(in) | ||
| 477 | |||
| 478 | //render template | ||
| 479 | if ctx.Output.Status == 0 { | ||
| 480 | if AutoRender { | ||
| 481 | if err := execController.Render(); err != nil { | ||
| 482 | panic(err) | ||
| 483 | } | ||
| 484 | } | ||
| 485 | } | ||
| 486 | |||
| 487 | // finish all runrouter. release resource | ||
| 488 | execController.Finish() | ||
| 489 | } | ||
| 339 | } | 490 | } | ... | ... |
| ... | @@ -253,30 +253,20 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest { | ... | @@ -253,30 +253,20 @@ func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest { |
| 253 | return b | 253 | return b |
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | 256 | func (b *BeegoHttpRequest) buildUrl(paramBody string) { |
| 257 | if b.resp.StatusCode != 0 { | 257 | // build GET url with query string |
| 258 | return b.resp, nil | ||
| 259 | } | ||
| 260 | var paramBody string | ||
| 261 | if len(b.params) > 0 { | ||
| 262 | var buf bytes.Buffer | ||
| 263 | for k, v := range b.params { | ||
| 264 | buf.WriteString(url.QueryEscape(k)) | ||
| 265 | buf.WriteByte('=') | ||
| 266 | buf.WriteString(url.QueryEscape(v)) | ||
| 267 | buf.WriteByte('&') | ||
| 268 | } | ||
| 269 | paramBody = buf.String() | ||
| 270 | paramBody = paramBody[0 : len(paramBody)-1] | ||
| 271 | } | ||
| 272 | |||
| 273 | if b.req.Method == "GET" && len(paramBody) > 0 { | 258 | if b.req.Method == "GET" && len(paramBody) > 0 { |
| 274 | if strings.Index(b.url, "?") != -1 { | 259 | if strings.Index(b.url, "?") != -1 { |
| 275 | b.url += "&" + paramBody | 260 | b.url += "&" + paramBody |
| 276 | } else { | 261 | } else { |
| 277 | b.url = b.url + "?" + paramBody | 262 | b.url = b.url + "?" + paramBody |
| 278 | } | 263 | } |
| 279 | } else if b.req.Method == "POST" && b.req.Body == nil { | 264 | return |
| 265 | } | ||
| 266 | |||
| 267 | // build POST url and body | ||
| 268 | if b.req.Method == "POST" && b.req.Body == nil { | ||
| 269 | // with files | ||
| 280 | if len(b.files) > 0 { | 270 | if len(b.files) > 0 { |
| 281 | pr, pw := io.Pipe() | 271 | pr, pw := io.Pipe() |
| 282 | bodyWriter := multipart.NewWriter(pw) | 272 | bodyWriter := multipart.NewWriter(pw) |
| ... | @@ -305,12 +295,35 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ... | @@ -305,12 +295,35 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 305 | }() | 295 | }() |
| 306 | b.Header("Content-Type", bodyWriter.FormDataContentType()) | 296 | b.Header("Content-Type", bodyWriter.FormDataContentType()) |
| 307 | b.req.Body = ioutil.NopCloser(pr) | 297 | b.req.Body = ioutil.NopCloser(pr) |
| 308 | } else if len(paramBody) > 0 { | 298 | return |
| 299 | } | ||
| 300 | |||
| 301 | // with params | ||
| 302 | if len(paramBody) > 0 { | ||
| 309 | b.Header("Content-Type", "application/x-www-form-urlencoded") | 303 | b.Header("Content-Type", "application/x-www-form-urlencoded") |
| 310 | b.Body(paramBody) | 304 | b.Body(paramBody) |
| 311 | } | 305 | } |
| 312 | } | 306 | } |
| 307 | } | ||
| 313 | 308 | ||
| 309 | func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ||
| 310 | if b.resp.StatusCode != 0 { | ||
| 311 | return b.resp, nil | ||
| 312 | } | ||
| 313 | var paramBody string | ||
| 314 | if len(b.params) > 0 { | ||
| 315 | var buf bytes.Buffer | ||
| 316 | for k, v := range b.params { | ||
| 317 | buf.WriteString(url.QueryEscape(k)) | ||
| 318 | buf.WriteByte('=') | ||
| 319 | buf.WriteString(url.QueryEscape(v)) | ||
| 320 | buf.WriteByte('&') | ||
| 321 | } | ||
| 322 | paramBody = buf.String() | ||
| 323 | paramBody = paramBody[0 : len(paramBody)-1] | ||
| 324 | } | ||
| 325 | |||
| 326 | b.buildUrl(paramBody) | ||
| 314 | url, err := url.Parse(b.url) | 327 | url, err := url.Parse(b.url) |
| 315 | if err != nil { | 328 | if err != nil { |
| 316 | return nil, err | 329 | return nil, err |
| ... | @@ -342,14 +355,12 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ... | @@ -342,14 +355,12 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 342 | } | 355 | } |
| 343 | } | 356 | } |
| 344 | 357 | ||
| 345 | var jar http.CookieJar | 358 | var jar http.CookieJar = nil |
| 346 | if b.setting.EnableCookie { | 359 | if b.setting.EnableCookie { |
| 347 | if defaultCookieJar == nil { | 360 | if defaultCookieJar == nil { |
| 348 | createDefaultCookie() | 361 | createDefaultCookie() |
| 349 | } | 362 | } |
| 350 | jar = defaultCookieJar | 363 | jar = defaultCookieJar |
| 351 | } else { | ||
| 352 | jar = nil | ||
| 353 | } | 364 | } |
| 354 | 365 | ||
| 355 | client := &http.Client{ | 366 | client := &http.Client{ |
| ... | @@ -402,12 +413,11 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { | ... | @@ -402,12 +413,11 @@ func (b *BeegoHttpRequest) Bytes() ([]byte, error) { |
| 402 | return nil, nil | 413 | return nil, nil |
| 403 | } | 414 | } |
| 404 | defer resp.Body.Close() | 415 | defer resp.Body.Close() |
| 405 | data, err := ioutil.ReadAll(resp.Body) | 416 | b.body, err = ioutil.ReadAll(resp.Body) |
| 406 | if err != nil { | 417 | if err != nil { |
| 407 | return nil, err | 418 | return nil, err |
| 408 | } | 419 | } |
| 409 | b.body = data | 420 | return b.body, nil |
| 410 | return data, nil | ||
| 411 | } | 421 | } |
| 412 | 422 | ||
| 413 | // ToFile saves the body data in response to one file. | 423 | // ToFile saves the body data in response to one file. |
| ... | @@ -438,8 +448,7 @@ func (b *BeegoHttpRequest) ToJson(v interface{}) error { | ... | @@ -438,8 +448,7 @@ func (b *BeegoHttpRequest) ToJson(v interface{}) error { |
| 438 | if err != nil { | 448 | if err != nil { |
| 439 | return err | 449 | return err |
| 440 | } | 450 | } |
| 441 | err = json.Unmarshal(data, v) | 451 | return json.Unmarshal(data, v) |
| 442 | return err | ||
| 443 | } | 452 | } |
| 444 | 453 | ||
| 445 | // 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 . |
| ... | @@ -449,8 +458,7 @@ func (b *BeegoHttpRequest) ToXml(v interface{}) error { | ... | @@ -449,8 +458,7 @@ func (b *BeegoHttpRequest) ToXml(v interface{}) error { |
| 449 | if err != nil { | 458 | if err != nil { |
| 450 | return err | 459 | return err |
| 451 | } | 460 | } |
| 452 | err = xml.Unmarshal(data, v) | 461 | return xml.Unmarshal(data, v) |
| 453 | return err | ||
| 454 | } | 462 | } |
| 455 | 463 | ||
| 456 | // Response executes request client gets response mannually. | 464 | // Response executes request client gets response mannually. | ... | ... |
| ... | @@ -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 | ||
| 82 | } | ||
| 83 | c.innerWriter.Close() | 77 | c.innerWriter.Close() |
| 78 | } | ||
| 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 { | ... | ... |
| ... | @@ -292,9 +292,9 @@ func (bl *BeeLogger) Close() { | ... | @@ -292,9 +292,9 @@ func (bl *BeeLogger) Close() { |
| 292 | fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err) | 292 | fmt.Println("ERROR, unable to WriteMsg (while closing logger):", err) |
| 293 | } | 293 | } |
| 294 | } | 294 | } |
| 295 | } else { | 295 | continue |
| 296 | break | ||
| 297 | } | 296 | } |
| 297 | break | ||
| 298 | } | 298 | } |
| 299 | for _, l := range bl.outputs { | 299 | for _, l := range bl.outputs { |
| 300 | l.Flush() | 300 | l.Flush() | ... | ... |
| ... | @@ -25,7 +25,8 @@ import ( | ... | @@ -25,7 +25,8 @@ import ( |
| 25 | ) | 25 | ) |
| 26 | 26 | ||
| 27 | const ( | 27 | const ( |
| 28 | subjectPhrase = "Diagnostic message from server" | 28 | // no usage |
| 29 | // subjectPhrase = "Diagnostic message from server" | ||
| 29 | ) | 30 | ) |
| 30 | 31 | ||
| 31 | // smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. | 32 | // smtpWriter implements LoggerInterface and is used to send emails via given SMTP-server. |
| ... | @@ -146,9 +147,7 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error { | ... | @@ -146,9 +147,7 @@ func (s *SmtpWriter) WriteMsg(msg string, level int) error { |
| 146 | mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + | 147 | mailmsg := []byte("To: " + strings.Join(s.RecipientAddresses, ";") + "\r\nFrom: " + s.FromAddress + "<" + s.FromAddress + |
| 147 | ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) | 148 | ">\r\nSubject: " + s.Subject + "\r\n" + content_type + "\r\n\r\n" + fmt.Sprintf(".%s", time.Now().Format("2006-01-02 15:04:05")) + msg) |
| 148 | 149 | ||
| 149 | err := s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) | 150 | return s.sendMail(s.Host, auth, s.FromAddress, s.RecipientAddresses, mailmsg) |
| 150 | |||
| 151 | return err | ||
| 152 | } | 151 | } |
| 153 | 152 | ||
| 154 | // implementing method. empty. | 153 | // implementing method. empty. | ... | ... |
middleware/exceptions.go
deleted
100644 → 0
| 1 | // Copyright 2014 beego Author. All Rights Reserved. | ||
| 2 | // | ||
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 4 | // you may not use this file except in compliance with the License. | ||
| 5 | // You may obtain a copy of the License at | ||
| 6 | // | ||
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 | ||
| 8 | // | ||
| 9 | // Unless required by applicable law or agreed to in writing, software | ||
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, | ||
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 12 | // See the License for the specific language governing permissions and | ||
| 13 | // limitations under the License. | ||
| 14 | |||
| 15 | package middleware | ||
| 16 | |||
| 17 | import "fmt" | ||
| 18 | |||
| 19 | // http exceptions | ||
| 20 | type HTTPException struct { | ||
| 21 | StatusCode int // http status code 4xx, 5xx | ||
| 22 | Description string | ||
| 23 | } | ||
| 24 | |||
| 25 | // return http exception error string, e.g. "400 Bad Request". | ||
| 26 | func (e *HTTPException) Error() string { | ||
| 27 | return fmt.Sprintf("%d %s", e.StatusCode, e.Description) | ||
| 28 | } | ||
| 29 | |||
| 30 | // map of http exceptions for each http status code int. | ||
| 31 | // defined 400,401,403,404,405,500,502,503 and 504 default. | ||
| 32 | var HTTPExceptionMaps map[int]HTTPException | ||
| 33 | |||
| 34 | func init() { | ||
| 35 | HTTPExceptionMaps = make(map[int]HTTPException) | ||
| 36 | |||
| 37 | // Normal 4XX HTTP Status | ||
| 38 | HTTPExceptionMaps[400] = HTTPException{400, "Bad Request"} | ||
| 39 | HTTPExceptionMaps[401] = HTTPException{401, "Unauthorized"} | ||
| 40 | HTTPExceptionMaps[403] = HTTPException{403, "Forbidden"} | ||
| 41 | HTTPExceptionMaps[404] = HTTPException{404, "Not Found"} | ||
| 42 | HTTPExceptionMaps[405] = HTTPException{405, "Method Not Allowed"} | ||
| 43 | |||
| 44 | // Normal 5XX HTTP Status | ||
| 45 | HTTPExceptionMaps[500] = HTTPException{500, "Internal Server Error"} | ||
| 46 | HTTPExceptionMaps[502] = HTTPException{502, "Bad Gateway"} | ||
| 47 | HTTPExceptionMaps[503] = HTTPException{503, "Service Unavailable"} | ||
| 48 | HTTPExceptionMaps[504] = HTTPException{504, "Gateway Timeout"} | ||
| 49 | } |
| ... | @@ -34,7 +34,6 @@ type Translation struct { | ... | @@ -34,7 +34,6 @@ type Translation struct { |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | func NewLocale(filepath string, defaultlocal string) *Translation { | 36 | func NewLocale(filepath string, defaultlocal string) *Translation { |
| 37 | i18n := make(map[string]map[string]string) | ||
| 38 | file, err := os.Open(filepath) | 37 | file, err := os.Open(filepath) |
| 39 | if err != nil { | 38 | if err != nil { |
| 40 | panic("open " + filepath + " err :" + err.Error()) | 39 | panic("open " + filepath + " err :" + err.Error()) |
| ... | @@ -43,8 +42,9 @@ func NewLocale(filepath string, defaultlocal string) *Translation { | ... | @@ -43,8 +42,9 @@ func NewLocale(filepath string, defaultlocal string) *Translation { |
| 43 | if err != nil { | 42 | if err != nil { |
| 44 | panic("read " + filepath + " err :" + err.Error()) | 43 | panic("read " + filepath + " err :" + err.Error()) |
| 45 | } | 44 | } |
| 46 | err = json.Unmarshal(data, &i18n) | 45 | |
| 47 | if err != nil { | 46 | i18n := make(map[string]map[string]string) |
| 47 | if err = json.Unmarshal(data, &i18n); err != nil { | ||
| 48 | panic("json.Unmarshal " + filepath + " err :" + err.Error()) | 48 | panic("json.Unmarshal " + filepath + " err :" + err.Error()) |
| 49 | } | 49 | } |
| 50 | return &Translation{ | 50 | return &Translation{ | ... | ... |
| ... | @@ -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 { | ... | ... |
| ... | @@ -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. |
| ... | @@ -156,6 +160,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex | ... | @@ -156,6 +160,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex |
| 156 | // column += " DEFAULT " + fi.initial.String() | 160 | // column += " DEFAULT " + fi.initial.String() |
| 157 | //} | 161 | //} |
| 158 | 162 | ||
| 163 | // Append attribute DEFAULT | ||
| 164 | column += getColumnDefault(fi) | ||
| 165 | |||
| 159 | if fi.unique { | 166 | if fi.unique { |
| 160 | column += " " + "UNIQUE" | 167 | column += " " + "UNIQUE" |
| 161 | } | 168 | } |
| ... | @@ -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 | ... | ... |
| ... | @@ -57,7 +57,7 @@ func parserPkg(pkgRealpath, pkgpath string) error { | ... | @@ -57,7 +57,7 @@ func parserPkg(pkgRealpath, pkgpath string) error { |
| 57 | rep := strings.NewReplacer("/", "_", ".", "_") | 57 | rep := strings.NewReplacer("/", "_", ".", "_") |
| 58 | commentFilename = COMMENTFL + rep.Replace(pkgpath) + ".go" | 58 | commentFilename = COMMENTFL + rep.Replace(pkgpath) + ".go" |
| 59 | if !compareFile(pkgRealpath) { | 59 | if !compareFile(pkgRealpath) { |
| 60 | Info(pkgRealpath + " don't has updated") | 60 | Info(pkgRealpath + " has not changed, not reloading") |
| 61 | return nil | 61 | return nil |
| 62 | } | 62 | } |
| 63 | genInfoList = make(map[string][]ControllerComments) | 63 | genInfoList = make(map[string][]ControllerComments) | ... | ... |
| ... | @@ -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 | ) |
| ... | @@ -153,7 +152,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM | ... | @@ -153,7 +152,7 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM |
| 153 | if val := reflectVal.MethodByName(colon[1]); val.IsValid() { | 152 | if val := reflectVal.MethodByName(colon[1]); val.IsValid() { |
| 154 | methods[strings.ToUpper(m)] = colon[1] | 153 | methods[strings.ToUpper(m)] = colon[1] |
| 155 | } else { | 154 | } else { |
| 156 | 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()) |
| 157 | } | 156 | } |
| 158 | } else { | 157 | } else { |
| 159 | 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) |
| ... | @@ -429,7 +428,7 @@ func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error | ... | @@ -429,7 +428,7 @@ func (p *ControllerRegistor) insertFilterRouter(pos int, mr *FilterRouter) error |
| 429 | 428 | ||
| 430 | // UrlFor does another controller handler in this request function. | 429 | // UrlFor does another controller handler in this request function. |
| 431 | // it can access any controller method. | 430 | // it can access any controller method. |
| 432 | func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { | 431 | func (p *ControllerRegistor) UrlFor(endpoint string, values ...interface{}) string { |
| 433 | paths := strings.Split(endpoint, ".") | 432 | paths := strings.Split(endpoint, ".") |
| 434 | if len(paths) <= 1 { | 433 | if len(paths) <= 1 { |
| 435 | Warn("urlfor endpoint must like path.controller.method") | 434 | Warn("urlfor endpoint must like path.controller.method") |
| ... | @@ -444,9 +443,9 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { | ... | @@ -444,9 +443,9 @@ func (p *ControllerRegistor) UrlFor(endpoint string, values ...string) string { |
| 444 | key := "" | 443 | key := "" |
| 445 | for k, v := range values { | 444 | for k, v := range values { |
| 446 | if k%2 == 0 { | 445 | if k%2 == 0 { |
| 447 | key = v | 446 | key = fmt.Sprint(v) |
| 448 | } else { | 447 | } else { |
| 449 | params[key] = v | 448 | params[key] = fmt.Sprint(v) |
| 450 | } | 449 | } |
| 451 | } | 450 | } |
| 452 | } | 451 | } |
| ... | @@ -577,7 +576,6 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin | ... | @@ -577,7 +576,6 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin |
| 577 | 576 | ||
| 578 | // Implement http.Handler interface. | 577 | // Implement http.Handler interface. |
| 579 | func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { | 578 | func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { |
| 580 | defer p.recoverPanic(rw, r) | ||
| 581 | starttime := time.Now() | 579 | starttime := time.Now() |
| 582 | var runrouter reflect.Type | 580 | var runrouter reflect.Type |
| 583 | var findrouter bool | 581 | var findrouter bool |
| ... | @@ -600,6 +598,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -600,6 +598,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 600 | context.Output.Context = context | 598 | context.Output.Context = context |
| 601 | context.Output.EnableGzip = EnableGzip | 599 | context.Output.EnableGzip = EnableGzip |
| 602 | 600 | ||
| 601 | defer p.recoverPanic(context) | ||
| 602 | |||
| 603 | var urlPath string | 603 | var urlPath string |
| 604 | if !RouterCaseSensitive { | 604 | if !RouterCaseSensitive { |
| 605 | urlPath = strings.ToLower(r.URL.Path) | 605 | urlPath = strings.ToLower(r.URL.Path) |
| ... | @@ -648,7 +648,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -648,7 +648,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 648 | context.Input.CruSession, err = GlobalSessions.SessionStart(w, r) | 648 | context.Input.CruSession, err = GlobalSessions.SessionStart(w, r) |
| 649 | if err != nil { | 649 | if err != nil { |
| 650 | Error(err) | 650 | Error(err) |
| 651 | middleware.Exception("503", rw, r, "") | 651 | exception("503", context) |
| 652 | return | 652 | return |
| 653 | } | 653 | } |
| 654 | defer func() { | 654 | defer func() { |
| ... | @@ -703,7 +703,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -703,7 +703,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 703 | 703 | ||
| 704 | //if no matches to url, throw a not found exception | 704 | //if no matches to url, throw a not found exception |
| 705 | if !findrouter { | 705 | if !findrouter { |
| 706 | middleware.Exception("404", rw, r, "") | 706 | exception("404", context) |
| 707 | goto Admin | 707 | goto Admin |
| 708 | } | 708 | } |
| 709 | 709 | ||
| ... | @@ -719,7 +719,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -719,7 +719,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 719 | isRunable = true | 719 | isRunable = true |
| 720 | routerInfo.runfunction(context) | 720 | routerInfo.runfunction(context) |
| 721 | } else { | 721 | } else { |
| 722 | middleware.Exception("405", rw, r, "Method Not Allowed") | 722 | exception("405", context) |
| 723 | goto Admin | 723 | goto Admin |
| 724 | } | 724 | } |
| 725 | } else if routerInfo.routerType == routerTypeHandler { | 725 | } else if routerInfo.routerType == routerTypeHandler { |
| ... | @@ -830,7 +830,7 @@ Admin: | ... | @@ -830,7 +830,7 @@ Admin: |
| 830 | } | 830 | } |
| 831 | } | 831 | } |
| 832 | 832 | ||
| 833 | if RunMode == "dev" { | 833 | if RunMode == "dev" || AccessLogs { |
| 834 | var devinfo string | 834 | var devinfo string |
| 835 | if findrouter { | 835 | if findrouter { |
| 836 | if routerInfo != nil { | 836 | if routerInfo != nil { |
| ... | @@ -852,28 +852,23 @@ Admin: | ... | @@ -852,28 +852,23 @@ Admin: |
| 852 | } | 852 | } |
| 853 | } | 853 | } |
| 854 | 854 | ||
| 855 | func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Request) { | 855 | func (p *ControllerRegistor) recoverPanic(context *beecontext.Context) { |
| 856 | if err := recover(); err != nil { | 856 | if err := recover(); err != nil { |
| 857 | if err == USERSTOPRUN { | 857 | if err == USERSTOPRUN { |
| 858 | return | 858 | return |
| 859 | } | 859 | } |
| 860 | if he, ok := err.(middleware.HTTPException); ok { | ||
| 861 | rw.WriteHeader(he.StatusCode) | ||
| 862 | rw.Write([]byte(he.Description)) | ||
| 863 | // catch intented errors, only for HTTP 4XX and 5XX | ||
| 864 | } else { | ||
| 865 | if RunMode == "dev" { | 860 | if RunMode == "dev" { |
| 866 | if !RecoverPanic { | 861 | if !RecoverPanic { |
| 867 | panic(err) | 862 | panic(err) |
| 868 | } else { | 863 | } else { |
| 869 | if ErrorsShow { | 864 | if ErrorsShow { |
| 870 | if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok { | 865 | if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok { |
| 871 | handler(rw, r) | 866 | executeError(handler, context) |
| 872 | return | 867 | return |
| 873 | } | 868 | } |
| 874 | } | 869 | } |
| 875 | var stack string | 870 | var stack string |
| 876 | Critical("the request url is ", r.URL.Path) | 871 | Critical("the request url is ", context.Input.Url()) |
| 877 | Critical("Handler crashed with error", err) | 872 | Critical("Handler crashed with error", err) |
| 878 | for i := 1; ; i++ { | 873 | for i := 1; ; i++ { |
| 879 | _, file, line, ok := runtime.Caller(i) | 874 | _, file, line, ok := runtime.Caller(i) |
| ... | @@ -883,7 +878,7 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques | ... | @@ -883,7 +878,7 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques |
| 883 | Critical(fmt.Sprintf("%s:%d", file, line)) | 878 | Critical(fmt.Sprintf("%s:%d", file, line)) |
| 884 | stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) | 879 | stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) |
| 885 | } | 880 | } |
| 886 | middleware.ShowErr(err, rw, r, stack) | 881 | showErr(err, context, stack) |
| 887 | } | 882 | } |
| 888 | } else { | 883 | } else { |
| 889 | if !RecoverPanic { | 884 | if !RecoverPanic { |
| ... | @@ -891,17 +886,17 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques | ... | @@ -891,17 +886,17 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques |
| 891 | } else { | 886 | } else { |
| 892 | // in production model show all infomation | 887 | // in production model show all infomation |
| 893 | if ErrorsShow { | 888 | if ErrorsShow { |
| 894 | if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok { | 889 | if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok { |
| 895 | handler(rw, r) | 890 | executeError(handler, context) |
| 896 | return | 891 | return |
| 897 | } else if handler, ok := middleware.ErrorMaps["503"]; ok { | 892 | } else if handler, ok := ErrorMaps["503"]; ok { |
| 898 | handler(rw, r) | 893 | executeError(handler, context) |
| 899 | return | 894 | return |
| 900 | } else { | 895 | } else { |
| 901 | rw.Write([]byte(fmt.Sprint(err))) | 896 | context.WriteString(fmt.Sprint(err)) |
| 902 | } | 897 | } |
| 903 | } else { | 898 | } else { |
| 904 | Critical("the request url is ", r.URL.Path) | 899 | Critical("the request url is ", context.Input.Url()) |
| 905 | Critical("Handler crashed with error", err) | 900 | Critical("Handler crashed with error", err) |
| 906 | for i := 1; ; i++ { | 901 | for i := 1; ; i++ { |
| 907 | _, file, line, ok := runtime.Caller(i) | 902 | _, file, line, ok := runtime.Caller(i) |
| ... | @@ -913,8 +908,6 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques | ... | @@ -913,8 +908,6 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques |
| 913 | } | 908 | } |
| 914 | } | 909 | } |
| 915 | } | 910 | } |
| 916 | |||
| 917 | } | ||
| 918 | } | 911 | } |
| 919 | } | 912 | } |
| 920 | 913 | ... | ... |
| ... | @@ -2,6 +2,8 @@ package session | ... | @@ -2,6 +2,8 @@ package session |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "net/http" | 4 | "net/http" |
| 5 | "strconv" | ||
| 6 | "strings" | ||
| 5 | "sync" | 7 | "sync" |
| 6 | 8 | ||
| 7 | "github.com/astaxie/beego/session" | 9 | "github.com/astaxie/beego/session" |
| ... | @@ -74,19 +76,29 @@ func (ls *LedisSessionStore) SessionRelease(w http.ResponseWriter) { | ... | @@ -74,19 +76,29 @@ func (ls *LedisSessionStore) SessionRelease(w http.ResponseWriter) { |
| 74 | type LedisProvider struct { | 76 | type LedisProvider struct { |
| 75 | maxlifetime int64 | 77 | maxlifetime int64 |
| 76 | savePath string | 78 | savePath string |
| 79 | db int | ||
| 77 | } | 80 | } |
| 78 | 81 | ||
| 79 | // init ledis session | 82 | // init ledis session |
| 80 | // savepath like ledis server saveDataPath,pool size | 83 | // savepath like ledis server saveDataPath,pool size |
| 81 | // e.g. 127.0.0.1:6379,100,astaxie | 84 | // e.g. 127.0.0.1:6379,100,astaxie |
| 82 | func (lp *LedisProvider) SessionInit(maxlifetime int64, savePath string) error { | 85 | func (lp *LedisProvider) SessionInit(maxlifetime int64, savePath string) error { |
| 86 | var err error | ||
| 83 | lp.maxlifetime = maxlifetime | 87 | lp.maxlifetime = maxlifetime |
| 84 | lp.savePath = savePath | 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 | } | ||
| 85 | cfg := new(config.Config) | 98 | cfg := new(config.Config) |
| 86 | cfg.DataDir = lp.savePath | 99 | cfg.DataDir = lp.savePath |
| 87 | var err error | ||
| 88 | nowLedis, err := ledis.Open(cfg) | 100 | nowLedis, err := ledis.Open(cfg) |
| 89 | c, err = nowLedis.Select(0) | 101 | c, err = nowLedis.Select(lp.db) |
| 90 | if err != nil { | 102 | if err != nil { |
| 91 | println(err) | 103 | println(err) |
| 92 | return nil | 104 | return nil | ... | ... |
| ... | @@ -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 | ... | ... |
| ... | @@ -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 | ||
| ... | @@ -350,11 +358,32 @@ func ParseForm(form url.Values, obj interface{}) error { | ... | @@ -350,11 +358,32 @@ func ParseForm(form url.Values, obj interface{}) error { |
| 350 | } | 358 | } |
| 351 | fieldV.Set(reflect.ValueOf(t)) | 359 | fieldV.Set(reflect.ValueOf(t)) |
| 352 | } | 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 | } | ||
| 353 | } | 379 | } |
| 354 | } | 380 | } |
| 355 | return nil | 381 | return nil |
| 356 | } | 382 | } |
| 357 | 383 | ||
| 384 | var sliceOfInts = reflect.TypeOf([]int(nil)) | ||
| 385 | var sliceOfStrings = reflect.TypeOf([]string(nil)) | ||
| 386 | |||
| 358 | var unKind = map[reflect.Kind]bool{ | 387 | var unKind = map[reflect.Kind]bool{ |
| 359 | reflect.Uintptr: true, | 388 | reflect.Uintptr: true, |
| 360 | 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) { | ... | ... |
| ... | @@ -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 | } | ... | ... |
| ... | @@ -422,6 +422,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string | ... | @@ -422,6 +422,9 @@ func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params map[string |
| 422 | // "/admin/" -> ["admin"] | 422 | // "/admin/" -> ["admin"] |
| 423 | // "/admin/users" -> ["admin", "users"] | 423 | // "/admin/users" -> ["admin", "users"] |
| 424 | func splitPath(key string) []string { | 424 | func splitPath(key string) []string { |
| 425 | if key == "" { | ||
| 426 | return []string{} | ||
| 427 | } | ||
| 425 | elements := strings.Split(key, "/") | 428 | elements := strings.Split(key, "/") |
| 426 | if elements[0] == "" { | 429 | if elements[0] == "" { |
| 427 | elements = elements[1:] | 430 | elements = elements[1:] | ... | ... |
| ... | @@ -149,7 +149,11 @@ func TestAddTree2(t *testing.T) { | ... | @@ -149,7 +149,11 @@ func TestAddTree2(t *testing.T) { |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | func TestSplitPath(t *testing.T) { | 151 | func TestSplitPath(t *testing.T) { |
| 152 | a := splitPath("/") | 152 | a := splitPath("") |
| 153 | if len(a) != 0 { | ||
| 154 | t.Fatal("/ should retrun []") | ||
| 155 | } | ||
| 156 | a = splitPath("/") | ||
| 153 | if len(a) != 0 { | 157 | if len(a) != 0 { |
| 154 | t.Fatal("/ should retrun []") | 158 | t.Fatal("/ should retrun []") |
| 155 | } | 159 | } | ... | ... |
| ... | @@ -21,6 +21,6 @@ import ( | ... | @@ -21,6 +21,6 @@ import ( |
| 21 | // Instantiates a Paginator and assigns it to context.Input.Data["paginator"]. | 21 | // Instantiates a Paginator and assigns it to context.Input.Data["paginator"]. |
| 22 | func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { | 22 | func SetPaginator(context *context.Context, per int, nums int64) (paginator *Paginator) { |
| 23 | paginator = NewPaginator(context.Request, per, nums) | 23 | paginator = NewPaginator(context.Request, per, nums) |
| 24 | context.Input.Data["paginator"] = paginator | 24 | context.Input.Data["paginator"] = &paginator |
| 25 | return | 25 | return |
| 26 | } | 26 | } | ... | ... |
| ... | @@ -114,7 +114,7 @@ func (p *Paginator) Pages() []int { | ... | @@ -114,7 +114,7 @@ func (p *Paginator) Pages() []int { |
| 114 | 114 | ||
| 115 | // Returns URL for a given page index. | 115 | // Returns URL for a given page index. |
| 116 | func (p *Paginator) PageLink(page int) string { | 116 | func (p *Paginator) PageLink(page int) string { |
| 117 | link, _ := url.ParseRequestURI(p.Request.RequestURI) | 117 | link, _ := url.ParseRequestURI(p.Request.URL.String()) |
| 118 | values := link.Query() | 118 | values := link.Query() |
| 119 | if page == 1 { | 119 | if page == 1 { |
| 120 | values.Del("p") | 120 | values.Del("p") | ... | ... |
-
Please register or sign in to post a comment