020bfbcc by astaxie

Merge branch 'develop'

2 parents d536f5b8 3f8252bf
...@@ -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,
...@@ -28,8 +29,8 @@ var jsoncontext = `{ ...@@ -28,8 +29,8 @@ var jsoncontext = `{
28 "autorender": false, 29 "autorender": false,
29 "copyrequestbody": true, 30 "copyrequestbody": true,
30 "database": { 31 "database": {
31 "host": "host", 32 "host": "host",
32 "port": "port", 33 "port": "port",
33 "database": "database", 34 "database": "database",
34 "username": "username", 35 "username": "username",
35 "password": "password", 36 "password": "password",
...@@ -122,6 +123,12 @@ func TestJson(t *testing.T) { ...@@ -122,6 +123,12 @@ func TestJson(t *testing.T) {
122 if jsonconf.String("runmode") != "dev" { 123 if jsonconf.String("runmode") != "dev" {
123 t.Fatal("runmode not equal to dev") 124 t.Fatal("runmode not equal to dev")
124 } 125 }
126 if v := jsonconf.Strings("unknown"); len(v) > 0 {
127 t.Fatal("unknown strings, the length should be 0")
128 }
129 if v := jsonconf.Strings("testnames"); len(v) != 2 {
130 t.Fatal("testnames length should be 2")
131 }
125 if v, err := jsonconf.Bool("autorender"); err != nil || v != false { 132 if v, err := jsonconf.Bool("autorender"); err != nil || v != false {
126 t.Error(v) 133 t.Error(v)
127 t.Fatal(err) 134 t.Fatal(err)
...@@ -179,4 +186,8 @@ func TestJson(t *testing.T) { ...@@ -179,4 +186,8 @@ func TestJson(t *testing.T) {
179 if _, err := jsonconf.Bool("unknown"); err == nil { 186 if _, err := jsonconf.Bool("unknown"); err == nil {
180 t.Error("unknown keys should return an error when expecting a Bool") 187 t.Error("unknown keys should return an error when expecting a Bool")
181 } 188 }
189
190 if !jsonconf.DefaultBool("unknow", true) {
191 t.Error("unknown keys with default value wrong")
192 }
182 } 193 }
......
...@@ -31,7 +31,6 @@ import ( ...@@ -31,7 +31,6 @@ import (
31 "strings" 31 "strings"
32 "time" 32 "time"
33 33
34 "github.com/astaxie/beego/middleware"
35 "github.com/astaxie/beego/utils" 34 "github.com/astaxie/beego/utils"
36 ) 35 )
37 36
...@@ -53,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. 58 panic(body)
61 if _, ok := middleware.ErrorMaps[body]; ok {
62 panic(body)
63 }
64 // second panic from HTTPExceptionMaps, it is system defined functions.
65 if e, ok := middleware.HTTPExceptionMaps[status]; ok {
66 if len(body) >= 1 {
67 e.Description = body
68 }
69 panic(e)
70 }
71 // last panic user string
72 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
395 return i8, err 428 if strv := c.Ctx.Input.Query(key); strv != "" {
429 i64, err := strconv.ParseInt(strv, 10, 8)
430 i8 := int8(i64)
431 return i8, err
432 } else {
433 return defv, nil
434 }
396 } 435 }
397 436
398 // GetInt16 returns input as an int16 437 // GetInt16 returns input as an int16 or the default value while it's present and input is blank
399 func (c *Controller) GetInt16(key string) (int16, error) { 438 func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
400 i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 16) 439 var defv int16
401 i16 := int16(i64) 440 if len(def) > 0 {
441 defv = def[0]
442 }
443
444 if strv := c.Ctx.Input.Query(key); strv != "" {
445 i64, err := strconv.ParseInt(strv, 10, 16)
446 i16 := int16(i64)
402 447
403 return i16, err 448 return i16, err
449 } else {
450 return defv, nil
451 }
404 } 452 }
405 453
406 // GetInt32 returns input as an int32 454 // GetInt32 returns input as an int32 or the default value while it's present and input is blank
407 func (c *Controller) GetInt32(key string) (int32, error) { 455 func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
408 i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32) 456 var defv int32
409 i32 := int32(i64) 457 if len(def) > 0 {
458 defv = def[0]
459 }
410 460
411 return i32, err 461 if strv := c.Ctx.Input.Query(key); strv != "" {
462 i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32)
463 i32 := int32(i64)
464 return i32, err
465 } else {
466 return defv, nil
467 }
412 } 468 }
413 469
414 // GetInt64 returns input value as int64. 470 // GetInt64 returns input value as int64 or the default value while it's present and input is blank.
415 func (c *Controller) GetInt64(key string) (int64, error) { 471 func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
416 return strconv.ParseInt(c.Ctx.Input.Query(key), 10, 64) 472 var defv int64
473 if len(def) > 0 {
474 defv = def[0]
475 }
476
477 if strv := c.Ctx.Input.Query(key); strv != "" {
478 return strconv.ParseInt(strv, 10, 64)
479 } else {
480 return defv, nil
481 }
417 } 482 }
418 483
419 // GetBool returns input value as bool. 484 // GetBool returns input value as bool or the default value while it's present and input is blank.
420 func (c *Controller) GetBool(key string) (bool, error) { 485 func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
421 return strconv.ParseBool(c.Ctx.Input.Query(key)) 486 var defv bool
487 if len(def) > 0 {
488 defv = def[0]
489 }
490
491 if strv := c.Ctx.Input.Query(key); strv != "" {
492 return strconv.ParseBool(strv)
493 } else {
494 return defv, nil
495 }
422 } 496 }
423 497
424 // GetFloat returns input value as float64. 498 // GetFloat returns input value as float64 or the default value while it's present and input is blank.
425 func (c *Controller) GetFloat(key string) (float64, error) { 499 func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
426 return strconv.ParseFloat(c.Ctx.Input.Query(key), 64) 500 var defv float64
501 if len(def) > 0 {
502 defv = def[0]
503 }
504
505 if strv := c.Ctx.Input.Query(key); strv != "" {
506 return strconv.ParseFloat(c.Ctx.Input.Query(key), 64)
507 } else {
508 return defv, nil
509 }
427 } 510 }
428 511
429 // GetFile returns the file data in file upload field named as key. 512 // GetFile returns the file data in file upload field named as key.
......
...@@ -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 77 c.innerWriter.Close()
82 } 78 }
83 c.innerWriter.Close()
84 } 79 }
85 80
86 func (c *ConnWriter) connect() error { 81 func (c *ConnWriter) connect() error {
......
...@@ -50,9 +50,10 @@ type ConsoleWriter struct { ...@@ -50,9 +50,10 @@ type ConsoleWriter struct {
50 50
51 // create ConsoleWriter returning as LoggerInterface. 51 // create ConsoleWriter returning as LoggerInterface.
52 func NewConsole() LoggerInterface { 52 func NewConsole() LoggerInterface {
53 cw := new(ConsoleWriter) 53 cw := &ConsoleWriter{
54 cw.lg = log.New(os.Stdout, "", log.Ldate|log.Ltime) 54 lg: log.New(os.Stdout, "", log.Ldate|log.Ltime),
55 cw.Level = LevelDebug 55 Level: LevelDebug,
56 }
56 return cw 57 return cw
57 } 58 }
58 59
...@@ -62,11 +63,7 @@ func (c *ConsoleWriter) Init(jsonconfig string) error { ...@@ -62,11 +63,7 @@ func (c *ConsoleWriter) Init(jsonconfig string) error {
62 if len(jsonconfig) == 0 { 63 if len(jsonconfig) == 0 {
63 return nil 64 return nil
64 } 65 }
65 err := json.Unmarshal([]byte(jsonconfig), c) 66 return json.Unmarshal([]byte(jsonconfig), c)
66 if err != nil {
67 return err
68 }
69 return nil
70 } 67 }
71 68
72 // write message in console. 69 // write message in console.
...@@ -76,9 +73,10 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error { ...@@ -76,9 +73,10 @@ func (c *ConsoleWriter) WriteMsg(msg string, level int) error {
76 } 73 }
77 if goos := runtime.GOOS; goos == "windows" { 74 if goos := runtime.GOOS; goos == "windows" {
78 c.lg.Println(msg) 75 c.lg.Println(msg)
79 } else { 76 return nil
80 c.lg.Println(colors[level](msg))
81 } 77 }
78 c.lg.Println(colors[level](msg))
79
82 return nil 80 return nil
83 } 81 }
84 82
......
...@@ -15,10 +15,11 @@ ...@@ -15,10 +15,11 @@
15 package logs 15 package logs
16 16
17 import ( 17 import (
18 "bytes"
18 "encoding/json" 19 "encoding/json"
19 "errors" 20 "errors"
20 "fmt" 21 "fmt"
21 "io/ioutil" 22 "io"
22 "log" 23 "log"
23 "os" 24 "os"
24 "path/filepath" 25 "path/filepath"
...@@ -122,11 +123,7 @@ func (w *FileLogWriter) startLogger() error { ...@@ -122,11 +123,7 @@ func (w *FileLogWriter) startLogger() error {
122 return err 123 return err
123 } 124 }
124 w.mw.SetFd(fd) 125 w.mw.SetFd(fd)
125 err = w.initFd() 126 return w.initFd()
126 if err != nil {
127 return err
128 }
129 return nil
130 } 127 }
131 128
132 func (w *FileLogWriter) docheck(size int) { 129 func (w *FileLogWriter) docheck(size int) {
...@@ -169,18 +166,44 @@ func (w *FileLogWriter) initFd() error { ...@@ -169,18 +166,44 @@ func (w *FileLogWriter) initFd() error {
169 } 166 }
170 w.maxsize_cursize = int(finfo.Size()) 167 w.maxsize_cursize = int(finfo.Size())
171 w.daily_opendate = time.Now().Day() 168 w.daily_opendate = time.Now().Day()
169 w.maxlines_curlines = 0
172 if finfo.Size() > 0 { 170 if finfo.Size() > 0 {
173 content, err := ioutil.ReadFile(w.Filename) 171 count, err := w.lines()
174 if err != nil { 172 if err != nil {
175 return err 173 return err
176 } 174 }
177 w.maxlines_curlines = len(strings.Split(string(content), "\n")) 175 w.maxlines_curlines = count
178 } else {
179 w.maxlines_curlines = 0
180 } 176 }
181 return nil 177 return nil
182 } 178 }
183 179
180 func (w *FileLogWriter) lines() (int, error) {
181 fd, err := os.Open(w.Filename)
182 if err != nil {
183 return 0, err
184 }
185 defer fd.Close()
186
187 buf := make([]byte, 32768) // 32k
188 count := 0
189 lineSep := []byte{'\n'}
190
191 for {
192 c, err := fd.Read(buf)
193 if err != nil && err != io.EOF {
194 return count, err
195 }
196
197 count += bytes.Count(buf[:c], lineSep)
198
199 if err == io.EOF {
200 break
201 }
202 }
203
204 return count, nil
205 }
206
184 // DoRotate means it need to write file in new file. 207 // DoRotate means it need to write file in new file.
185 // new file name like xx.log.2013-01-01.2 208 // new file name like xx.log.2013-01-01.2
186 func (w *FileLogWriter) DoRotate() error { 209 func (w *FileLogWriter) DoRotate() error {
......
...@@ -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.
......
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.
...@@ -155,6 +159,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex ...@@ -155,6 +159,9 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
155 //if fi.initial.String() != "" { 159 //if fi.initial.String() != "" {
156 // column += " DEFAULT " + fi.initial.String() 160 // column += " DEFAULT " + fi.initial.String()
157 //} 161 //}
162
163 // Append attribute DEFAULT
164 column += getColumnDefault(fi)
158 165
159 if fi.unique { 166 if fi.unique {
160 column += " " + "UNIQUE" 167 column += " " + "UNIQUE"
...@@ -239,3 +246,44 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex ...@@ -239,3 +246,44 @@ func getDbCreateSql(al *alias) (sqls []string, tableIndexes map[string][]dbIndex
239 246
240 return 247 return
241 } 248 }
249
250
251 // Get string value for the attribute "DEFAULT" for the CREATE, ALTER commands
252 func getColumnDefault(fi *fieldInfo) string {
253 var (
254 v, t, d string
255 )
256
257 // Skip default attribute if field is in relations
258 if fi.rel || fi.reverse {
259 return v
260 }
261
262 t = " DEFAULT '%s' "
263
264 // These defaults will be useful if there no config value orm:"default" and NOT NULL is on
265 switch fi.fieldType {
266 case TypeDateField, TypeDateTimeField:
267 return v;
268
269 case TypeBooleanField, TypeBitField, TypeSmallIntegerField, TypeIntegerField,
270 TypeBigIntegerField, TypePositiveBitField, TypePositiveSmallIntegerField,
271 TypePositiveIntegerField, TypePositiveBigIntegerField, TypeFloatField,
272 TypeDecimalField:
273 d = "0"
274 }
275
276 if fi.colDefault {
277 if !fi.initial.Exist() {
278 v = fmt.Sprintf(t, "")
279 } else {
280 v = fmt.Sprintf(t, fi.initial.String())
281 }
282 } else {
283 if !fi.null {
284 v = fmt.Sprintf(t, d)
285 }
286 }
287
288 return v
289 }
......
...@@ -116,6 +116,7 @@ type fieldInfo struct { ...@@ -116,6 +116,7 @@ type fieldInfo struct {
116 null bool 116 null bool
117 index bool 117 index bool
118 unique bool 118 unique bool
119 colDefault bool
119 initial StrTo 120 initial StrTo
120 size int 121 size int
121 auto_now bool 122 auto_now bool
...@@ -280,6 +281,11 @@ checkType: ...@@ -280,6 +281,11 @@ checkType:
280 fi.pk = attrs["pk"] 281 fi.pk = attrs["pk"]
281 fi.unique = attrs["unique"] 282 fi.unique = attrs["unique"]
282 283
284 // Mark object property if there is attribute "default" in the orm configuration
285 if _, ok := tags["default"]; ok {
286 fi.colDefault = true
287 }
288
283 switch fieldType { 289 switch fieldType {
284 case RelManyToMany, RelReverseMany, RelReverseOne: 290 case RelManyToMany, RelReverseMany, RelReverseOne:
285 fi.null = false 291 fi.null = false
......
...@@ -489,10 +489,6 @@ func (o *orm) Driver() Driver { ...@@ -489,10 +489,6 @@ func (o *orm) Driver() Driver {
489 return driver(o.alias.Name) 489 return driver(o.alias.Name)
490 } 490 }
491 491
492 func (o *orm) GetDB() dbQuerier {
493 panic(ErrNotImplement)
494 }
495
496 // create new orm 492 // create new orm
497 func NewOrm() Ormer { 493 func NewOrm() Ormer {
498 BootStrap() // execute only once 494 BootStrap() // execute only once
......
...@@ -51,7 +51,6 @@ type Ormer interface { ...@@ -51,7 +51,6 @@ type Ormer interface {
51 Rollback() error 51 Rollback() error
52 Raw(string, ...interface{}) RawSeter 52 Raw(string, ...interface{}) RawSeter
53 Driver() Driver 53 Driver() Driver
54 GetDB() dbQuerier
55 } 54 }
56 55
57 // insert prepared statement 56 // insert prepared statement
......
...@@ -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,51 @@ Admin: ...@@ -852,28 +852,51 @@ 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 { 860 if RunMode == "dev" {
861 rw.WriteHeader(he.StatusCode) 861 if !RecoverPanic {
862 rw.Write([]byte(he.Description)) 862 panic(err)
863 // catch intented errors, only for HTTP 4XX and 5XX 863 } else {
864 if ErrorsShow {
865 if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok {
866 executeError(handler, context)
867 return
868 }
869 }
870 var stack string
871 Critical("the request url is ", context.Input.Url())
872 Critical("Handler crashed with error", err)
873 for i := 1; ; i++ {
874 _, file, line, ok := runtime.Caller(i)
875 if !ok {
876 break
877 }
878 Critical(fmt.Sprintf("%s:%d", file, line))
879 stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
880 }
881 showErr(err, context, stack)
882 }
864 } else { 883 } else {
865 if RunMode == "dev" { 884 if !RecoverPanic {
866 if !RecoverPanic { 885 panic(err)
867 panic(err) 886 } else {
868 } else { 887 // in production model show all infomation
869 if ErrorsShow { 888 if ErrorsShow {
870 if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok { 889 if handler, ok := ErrorMaps[fmt.Sprint(err)]; ok {
871 handler(rw, r) 890 executeError(handler, context)
872 return 891 return
873 } 892 } else if handler, ok := ErrorMaps["503"]; ok {
893 executeError(handler, context)
894 return
895 } else {
896 context.WriteString(fmt.Sprint(err))
874 } 897 }
875 var stack string 898 } else {
876 Critical("the request url is ", r.URL.Path) 899 Critical("the request url is ", context.Input.Url())
877 Critical("Handler crashed with error", err) 900 Critical("Handler crashed with error", err)
878 for i := 1; ; i++ { 901 for i := 1; ; i++ {
879 _, file, line, ok := runtime.Caller(i) 902 _, file, line, ok := runtime.Caller(i)
...@@ -881,39 +904,9 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques ...@@ -881,39 +904,9 @@ func (p *ControllerRegistor) recoverPanic(rw http.ResponseWriter, r *http.Reques
881 break 904 break
882 } 905 }
883 Critical(fmt.Sprintf("%s:%d", file, line)) 906 Critical(fmt.Sprintf("%s:%d", file, line))
884 stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line))
885 }
886 middleware.ShowErr(err, rw, r, stack)
887 }
888 } else {
889 if !RecoverPanic {
890 panic(err)
891 } else {
892 // in production model show all infomation
893 if ErrorsShow {
894 if handler, ok := middleware.ErrorMaps[fmt.Sprint(err)]; ok {
895 handler(rw, r)
896 return
897 } else if handler, ok := middleware.ErrorMaps["503"]; ok {
898 handler(rw, r)
899 return
900 } else {
901 rw.Write([]byte(fmt.Sprint(err)))
902 }
903 } else {
904 Critical("the request url is ", r.URL.Path)
905 Critical("Handler crashed with error", err)
906 for i := 1; ; i++ {
907 _, file, line, ok := runtime.Caller(i)
908 if !ok {
909 break
910 }
911 Critical(fmt.Sprintf("%s:%d", file, line))
912 }
913 } 907 }
914 } 908 }
915 } 909 }
916
917 } 910 }
918 } 911 }
919 } 912 }
......
...@@ -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")
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!