diff --git a/README.md b/README.md
index 0d7414b8..7b650887 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
[![Build Status](https://drone.io/github.com/astaxie/beego/status.png)](https://drone.io/github.com/astaxie/beego/latest)
[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego)
-beego is an open-source, high-performance, modularity, full-stack web framework.
+beego is an open-source, high-performance, modular, full-stack web framework.
More info [beego.me](http://beego.me)
@@ -19,7 +19,7 @@ More info [beego.me](http://beego.me)
* Auto API documents
* Annotation router
* Namespace
-* Powerful develop tools
+* Powerful development tools
* Full stack for Web & API
## Documentation
diff --git a/admin.go b/admin.go
index a0905dd3..90142c55 100644
--- a/admin.go
+++ b/admin.go
@@ -113,8 +113,6 @@ func listConf(rw http.ResponseWriter, r *http.Request) {
m["SessionName"] = SessionName
m["SessionGCMaxLifetime"] = SessionGCMaxLifetime
m["SessionSavePath"] = SessionSavePath
- m["SessionHashFunc"] = SessionHashFunc
- m["SessionHashKey"] = SessionHashKey
m["SessionCookieLifeTime"] = SessionCookieLifeTime
m["UseFcgi"] = UseFcgi
m["MaxMemory"] = MaxMemory
@@ -399,7 +397,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
if err != nil {
data["Message"] = []string{"error", fmt.Sprintf("%s", err)}
}
- data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is %s", taskname, t.GetStatus())}
+ data["Message"] = []string{"success", fmt.Sprintf("%s run success,Now the Status is
%s", taskname, t.GetStatus())}
} else {
data["Message"] = []string{"warning", fmt.Sprintf("there's no task which named: %s", taskname)}
}
@@ -412,12 +410,14 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) {
var fields = []string{
fmt.Sprintf("Task Name"),
fmt.Sprintf("Task Spec"),
- fmt.Sprintf("Task Function"),
+ fmt.Sprintf("Task Status"),
+ fmt.Sprintf("Last Time"),
fmt.Sprintf(""),
}
for tname, tk := range toolbox.AdminTaskList {
result = []string{
fmt.Sprintf("%s", tname),
+ fmt.Sprintf("%s", tk.GetSpec()),
fmt.Sprintf("%s", tk.GetStatus()),
fmt.Sprintf("%s", tk.GetPrev().String()),
}
@@ -458,7 +458,7 @@ func (admin *adminApp) Run() {
for p, f := range admin.routers {
http.Handle(p, f)
}
- BeeLogger.Info("Running on %s", addr)
+ BeeLogger.Info("Admin server Running on %s", addr)
err := http.ListenAndServe(addr, nil)
if err != nil {
BeeLogger.Critical("Admin ListenAndServe: ", err)
diff --git a/adminui.go b/adminui.go
index 77b5cd33..7bb32b34 100644
--- a/adminui.go
+++ b/adminui.go
@@ -186,7 +186,7 @@ bg-warning
{{end}}
- Run
+ Run
|
{{end}}
diff --git a/app.go b/app.go
index 0b89d89e..35040f33 100644
--- a/app.go
+++ b/app.go
@@ -19,14 +19,12 @@ import (
"net"
"net/http"
"net/http/fcgi"
+ "os"
"time"
- "github.com/astaxie/beego/context"
+ "github.com/astaxie/beego/utils"
)
-// FilterFunc defines filter function type.
-type FilterFunc func(*context.Context)
-
// App defines beego application with a new PatternServeMux.
type App struct {
Handlers *ControllerRegistor
@@ -64,6 +62,10 @@ func (app *App) Run() {
}
} else {
if HttpPort == 0 {
+ // remove the Socket file before start
+ if utils.FileExists(addr) {
+ os.Remove(addr)
+ }
l, err = net.Listen("unix", addr)
} else {
l, err = net.Listen("tcp", addr)
@@ -85,7 +87,7 @@ func (app *App) Run() {
if HttpsPort != 0 {
app.Server.Addr = fmt.Sprintf("%s:%d", HttpAddr, HttpsPort)
}
- BeeLogger.Info("Running on %s", app.Server.Addr)
+ BeeLogger.Info("https server Running on %s", app.Server.Addr)
err := app.Server.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
if err != nil {
BeeLogger.Critical("ListenAndServeTLS: ", err)
@@ -98,12 +100,29 @@ func (app *App) Run() {
if EnableHttpListen {
go func() {
app.Server.Addr = addr
- BeeLogger.Info("Running on %s", app.Server.Addr)
- err := app.Server.ListenAndServe()
- if err != nil {
- BeeLogger.Critical("ListenAndServe: ", err)
- time.Sleep(100 * time.Microsecond)
- endRunning <- true
+ BeeLogger.Info("http server Running on %s", app.Server.Addr)
+ if ListenTCP4 && HttpAddr == "" {
+ ln, err := net.Listen("tcp4", app.Server.Addr)
+ if err != nil {
+ BeeLogger.Critical("ListenAndServe: ", err)
+ time.Sleep(100 * time.Microsecond)
+ endRunning <- true
+ return
+ }
+ err = app.Server.Serve(ln)
+ if err != nil {
+ BeeLogger.Critical("ListenAndServe: ", err)
+ time.Sleep(100 * time.Microsecond)
+ endRunning <- true
+ return
+ }
+ } else {
+ err := app.Server.ListenAndServe()
+ if err != nil {
+ BeeLogger.Critical("ListenAndServe: ", err)
+ time.Sleep(100 * time.Microsecond)
+ endRunning <- true
+ }
}
}()
}
diff --git a/beego.go b/beego.go
index f23174c7..9c34c9f9 100644
--- a/beego.go
+++ b/beego.go
@@ -33,83 +33,15 @@ import (
"strconv"
"strings"
- "github.com/astaxie/beego/middleware"
"github.com/astaxie/beego/session"
)
// beego web framework version.
-const VERSION = "1.4.1"
+const VERSION = "1.4.3"
type hookfunc func() error //hook function to run
var hooks []hookfunc //hook function slice to store the hookfunc
-type groupRouter struct {
- pattern string
- controller ControllerInterface
- mappingMethods string
-}
-
-// RouterGroups which will store routers
-type GroupRouters []groupRouter
-
-// Get a new GroupRouters
-func NewGroupRouters() GroupRouters {
- return make(GroupRouters, 0)
-}
-
-// Add Router in the GroupRouters
-// it is for plugin or module to register router
-func (gr *GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingMethod ...string) {
- var newRG groupRouter
- if len(mappingMethod) > 0 {
- newRG = groupRouter{
- pattern,
- c,
- mappingMethod[0],
- }
- } else {
- newRG = groupRouter{
- pattern,
- c,
- "",
- }
- }
- *gr = append(*gr, newRG)
-}
-
-func (gr *GroupRouters) AddAuto(c ControllerInterface) {
- newRG := groupRouter{
- "",
- c,
- "",
- }
- *gr = append(*gr, newRG)
-}
-
-// AddGroupRouter with the prefix
-// it will register the router in BeeApp
-// the follow code is write in modules:
-// GR:=NewGroupRouters()
-// GR.AddRouter("/login",&UserController,"get:Login")
-// GR.AddRouter("/logout",&UserController,"get:Logout")
-// GR.AddRouter("/register",&UserController,"get:Reg")
-// the follow code is write in app:
-// import "github.com/beego/modules/auth"
-// AddRouterGroup("/admin", auth.GR)
-func AddGroupRouter(prefix string, groups GroupRouters) *App {
- for _, v := range groups {
- if v.pattern == "" {
- BeeApp.Handlers.AddAutoPrefix(prefix, v.controller)
- } else if v.mappingMethods != "" {
- BeeApp.Handlers.Add(prefix+v.pattern, v.controller, v.mappingMethods)
- } else {
- BeeApp.Handlers.Add(prefix+v.pattern, v.controller)
- }
-
- }
- return BeeApp
-}
-
// Router adds a patterned controller handler to BeeApp.
// it's an alias method of App.Router.
// usage:
@@ -280,15 +212,6 @@ func Handler(rootpath string, h http.Handler, options ...interface{}) *App {
return BeeApp
}
-// ErrorHandler registers http.HandlerFunc to each http err code string.
-// usage:
-// beego.ErrorHandler("404",NotFound)
-// beego.ErrorHandler("500",InternalServerError)
-func Errorhandler(err string, h http.HandlerFunc) *App {
- middleware.Errorhandler(err, h)
- return BeeApp
-}
-
// SetViewsPath sets view directory path in beego application.
func SetViewsPath(path string) *App {
ViewsPath = path
@@ -383,8 +306,6 @@ func initBeforeHttpRun() {
`"gclifetime":` + strconv.FormatInt(SessionGCMaxLifetime, 10) + `,` +
`"providerConfig":"` + filepath.ToSlash(SessionSavePath) + `",` +
`"secure":` + strconv.FormatBool(EnableHttpTLS) + `,` +
- `"sessionIDHashFunc":"` + SessionHashFunc + `",` +
- `"sessionIDHashKey":"` + SessionHashKey + `",` +
`"enableSetCookie":` + strconv.FormatBool(SessionAutoSetCookie) + `,` +
`"domain":"` + SessionDomain + `",` +
`"cookieLifeTime":` + strconv.Itoa(SessionCookieLifeTime) + `}`
@@ -404,9 +325,7 @@ func initBeforeHttpRun() {
}
}
- middleware.VERSION = VERSION
- middleware.AppName = AppName
- middleware.RegisterErrorHandler()
+ registerDefaultErrorHandler()
if EnableDocs {
Get("/docs", serverDocs)
diff --git a/cache/cache_test.go b/cache/cache_test.go
index bf9e79c2..7c43e539 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -15,6 +15,7 @@
package cache
import (
+ "os"
"testing"
"time"
)
@@ -67,7 +68,7 @@ func TestCache(t *testing.T) {
}
func TestFileCache(t *testing.T) {
- bm, err := NewCache("file", `{"CachePath":"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
+ bm, err := NewCache("file", `{"CachePath":"cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}`)
if err != nil {
t.Error("init err")
}
@@ -112,4 +113,5 @@ func TestFileCache(t *testing.T) {
if v := bm.Get("astaxie"); v.(string) != "author" {
t.Error("get err")
}
+ os.RemoveAll("cache")
}
diff --git a/cache/file.go b/cache/file.go
index 6ecf6568..bbbbbad2 100644
--- a/cache/file.go
+++ b/cache/file.go
@@ -92,8 +92,6 @@ func (fc *FileCache) StartAndGC(config string) error {
// Init will make new dir for file cache if not exist.
func (fc *FileCache) Init() {
- app := filepath.Dir(os.Args[0])
- fc.CachePath = filepath.Join(app, fc.CachePath)
if ok, _ := exists(fc.CachePath); !ok { // todo : error handle
_ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle
}
diff --git a/cache/redis/redis.go b/cache/redis/redis.go
index 35cf88cd..0e07eaed 100644
--- a/cache/redis/redis.go
+++ b/cache/redis/redis.go
@@ -32,6 +32,7 @@ package redis
import (
"encoding/json"
"errors"
+ "strconv"
"time"
"github.com/garyburd/redigo/redis"
@@ -48,6 +49,7 @@ var (
type RedisCache struct {
p *redis.Pool // redis connection pool
conninfo string
+ dbNum int
key string
}
@@ -75,14 +77,13 @@ func (rc *RedisCache) Get(key string) interface{} {
// put cache to redis.
func (rc *RedisCache) Put(key string, val interface{}, timeout int64) error {
var err error
- if _, err = rc.do("SET", key, val); err != nil {
+ if _, err = rc.do("SETEX", key, timeout, val); err != nil {
return err
}
if _, err = rc.do("HSET", rc.key, key, true); err != nil {
return err
}
- _, err = rc.do("EXPIRE", key, timeout)
return err
}
@@ -138,7 +139,7 @@ func (rc *RedisCache) ClearAll() error {
}
// start redis cache adapter.
-// config is like {"key":"collection key","conn":"connection info"}
+// config is like {"key":"collection key","conn":"connection info","dbNum":"0"}
// the cache item in redis are stored forever,
// so no gc operation.
func (rc *RedisCache) StartAndGC(config string) error {
@@ -152,9 +153,12 @@ func (rc *RedisCache) StartAndGC(config string) error {
if _, ok := cf["conn"]; !ok {
return errors.New("config has no conn key")
}
-
+ if _, ok := cf["dbNum"]; !ok {
+ cf["dbNum"] = "0"
+ }
rc.key = cf["key"]
rc.conninfo = cf["conn"]
+ rc.dbNum, _ = strconv.Atoi(cf["dbNum"])
rc.connectInit()
c := rc.p.Get()
@@ -167,6 +171,11 @@ func (rc *RedisCache) StartAndGC(config string) error {
func (rc *RedisCache) connectInit() {
dialFunc := func() (c redis.Conn, err error) {
c, err = redis.Dial("tcp", rc.conninfo)
+ _, selecterr := c.Do("SELECT", rc.dbNum)
+ if selecterr != nil {
+ c.Close()
+ return nil, selecterr
+ }
return
}
// initialize a new pool
diff --git a/config.go b/config.go
index 84f8cf39..f326ad22 100644
--- a/config.go
+++ b/config.go
@@ -40,6 +40,7 @@ var (
EnableHttpListen bool
HttpAddr string
HttpPort int
+ ListenTCP4 bool
EnableHttpTLS bool
HttpsPort int
HttpCertFile string
@@ -55,8 +56,6 @@ var (
SessionName string // the cookie name when saving session id into cookie.
SessionGCMaxLifetime int64 // session gc time for auto cleaning expired session.
SessionSavePath string // if use mysql/redis/file provider, define save path to connection info.
- SessionHashFunc string // session hash generation func.
- SessionHashKey string // session hash salt string.
SessionCookieLifeTime int // the life time of session id in cookie.
SessionAutoSetCookie bool // auto setcookie
SessionDomain string // the cookie domain default is empty
@@ -82,6 +81,7 @@ var (
AppConfigProvider string // config provider
EnableDocs bool // enable generate docs & server docs API Swagger
RouterCaseSensitive bool // router case sensitive default is true
+ AccessLogs bool // print access logs, default is false
)
type beegoAppConfig struct {
@@ -111,7 +111,7 @@ func (b *beegoAppConfig) String(key string) string {
func (b *beegoAppConfig) Strings(key string) []string {
v := b.innerConfig.Strings(RunMode + "::" + key)
- if len(v) == 0 {
+ if v[0] == "" {
return b.innerConfig.Strings(key)
}
return v
@@ -236,8 +236,6 @@ func init() {
SessionName = "beegosessionID"
SessionGCMaxLifetime = 3600
SessionSavePath = ""
- SessionHashFunc = "sha1"
- SessionHashKey = "beegoserversessionkey"
SessionCookieLifeTime = 0 //set cookie default is the brower life
SessionAutoSetCookie = true
@@ -277,9 +275,10 @@ func init() {
if err != nil {
fmt.Println("init console log error:", err)
}
+ SetLogFuncCall(true)
err = ParseConfig()
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && os.IsNotExist(err) {
// for init if doesn't have app.conf will not panic
ac := config.NewFakeConfig()
AppConfig = &beegoAppConfig{ac}
@@ -308,6 +307,10 @@ func ParseConfig() (err error) {
HttpPort = v
}
+ if v, err := AppConfig.Bool("ListenTCP4"); err == nil {
+ ListenTCP4 = v
+ }
+
if v, err := AppConfig.Bool("EnableHttpListen"); err == nil {
EnableHttpListen = v
}
@@ -348,14 +351,6 @@ func ParseConfig() (err error) {
SessionSavePath = sesssavepath
}
- if sesshashfunc := AppConfig.String("SessionHashFunc"); sesshashfunc != "" {
- SessionHashFunc = sesshashfunc
- }
-
- if sesshashkey := AppConfig.String("SessionHashKey"); sesshashkey != "" {
- SessionHashKey = sesshashkey
- }
-
if sessMaxLifeTime, err := AppConfig.Int64("SessionGCMaxLifetime"); err == nil && sessMaxLifeTime != 0 {
SessionGCMaxLifetime = sessMaxLifeTime
}
diff --git a/config/json.go b/config/json.go
index ae86ea53..e2b53793 100644
--- a/config/json.go
+++ b/config/json.go
@@ -17,13 +17,10 @@ package config
import (
"encoding/json"
"errors"
- "fmt"
"io/ioutil"
"os"
- "path"
"strings"
"sync"
- "time"
)
// JsonConfig is a json config parser and implements Config interface.
@@ -41,13 +38,19 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) {
if err != nil {
return nil, err
}
+
+ return js.ParseData(content)
+}
+
+// ParseData returns a ConfigContainer with json string
+func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) {
x := &JsonConfigContainer{
data: make(map[string]interface{}),
}
- err = json.Unmarshal(content, &x.data)
+ err := json.Unmarshal(data, &x.data)
if err != nil {
var wrappingArray []interface{}
- err2 := json.Unmarshal(content, &wrappingArray)
+ err2 := json.Unmarshal(data, &wrappingArray)
if err2 != nil {
return nil, err
}
@@ -56,16 +59,6 @@ func (js *JsonConfig) Parse(filename string) (ConfigContainer, error) {
return x, nil
}
-func (js *JsonConfig) ParseData(data []byte) (ConfigContainer, error) {
- // Save memory data to temporary file
- tmpName := path.Join(os.TempDir(), "beego", fmt.Sprintf("%d", time.Now().Nanosecond()))
- os.MkdirAll(path.Dir(tmpName), os.ModePerm)
- if err := ioutil.WriteFile(tmpName, data, 0655); err != nil {
- return nil, err
- }
- return js.Parse(tmpName)
-}
-
// A Config represents the json configuration.
// Only when get value, support key as section:name type.
type JsonConfigContainer struct {
@@ -88,11 +81,10 @@ func (c *JsonConfigContainer) Bool(key string) (bool, error) {
// DefaultBool return the bool value if has no error
// otherwise return the defaultval
func (c *JsonConfigContainer) DefaultBool(key string, defaultval bool) bool {
- if v, err := c.Bool(key); err != nil {
- return defaultval
- } else {
+ if v, err := c.Bool(key); err == nil {
return v
}
+ return defaultval
}
// Int returns the integer value for a given key.
@@ -110,11 +102,10 @@ func (c *JsonConfigContainer) Int(key string) (int, error) {
// DefaultInt returns the integer value for a given key.
// if err != nil return defaltval
func (c *JsonConfigContainer) DefaultInt(key string, defaultval int) int {
- if v, err := c.Int(key); err != nil {
- return defaultval
- } else {
+ if v, err := c.Int(key); err == nil {
return v
}
+ return defaultval
}
// Int64 returns the int64 value for a given key.
@@ -132,11 +123,10 @@ func (c *JsonConfigContainer) Int64(key string) (int64, error) {
// DefaultInt64 returns the int64 value for a given key.
// if err != nil return defaltval
func (c *JsonConfigContainer) DefaultInt64(key string, defaultval int64) int64 {
- if v, err := c.Int64(key); err != nil {
- return defaultval
- } else {
+ if v, err := c.Int64(key); err == nil {
return v
}
+ return defaultval
}
// Float returns the float value for a given key.
@@ -154,11 +144,10 @@ func (c *JsonConfigContainer) Float(key string) (float64, error) {
// DefaultFloat returns the float64 value for a given key.
// if err != nil return defaltval
func (c *JsonConfigContainer) DefaultFloat(key string, defaultval float64) float64 {
- if v, err := c.Float(key); err != nil {
- return defaultval
- } else {
+ if v, err := c.Float(key); err == nil {
return v
}
+ return defaultval
}
// String returns the string value for a given key.
@@ -175,35 +164,37 @@ func (c *JsonConfigContainer) String(key string) string {
// DefaultString returns the string value for a given key.
// if err != nil return defaltval
func (c *JsonConfigContainer) DefaultString(key string, defaultval string) string {
- if v := c.String(key); v == "" {
- return defaultval
- } else {
+ // TODO FIXME should not use "" to replace non existance
+ if v := c.String(key); v != "" {
return v
}
+ return defaultval
}
// Strings returns the []string value for a given key.
func (c *JsonConfigContainer) Strings(key string) []string {
+ stringVal := c.String(key)
+ if stringVal == "" {
+ return []string{}
+ }
return strings.Split(c.String(key), ";")
}
// DefaultStrings returns the []string value for a given key.
// if err != nil return defaltval
func (c *JsonConfigContainer) DefaultStrings(key string, defaultval []string) []string {
- if v := c.Strings(key); len(v) == 0 {
- return defaultval
- } else {
+ if v := c.Strings(key); len(v) > 0 {
return v
}
+ return defaultval
}
// GetSection returns map for the given section
func (c *JsonConfigContainer) GetSection(section string) (map[string]string, error) {
if v, ok := c.data[section]; ok {
return v.(map[string]string), nil
- } else {
- return nil, errors.New("not exist setction")
}
+ return nil, errors.New("nonexist section " + section)
}
// SaveConfigFile save the config into file
@@ -222,7 +213,7 @@ func (c *JsonConfigContainer) SaveConfigFile(filename string) (err error) {
return err
}
-// WriteValue writes a new value for key.
+// Set writes a new value for key.
func (c *JsonConfigContainer) Set(key, val string) error {
c.Lock()
defer c.Unlock()
@@ -241,18 +232,20 @@ func (c *JsonConfigContainer) DIY(key string) (v interface{}, err error) {
// section.key or key
func (c *JsonConfigContainer) getData(key string) interface{} {
- c.RLock()
- defer c.RUnlock()
if len(key) == 0 {
return nil
}
- sectionKey := strings.Split(key, "::")
- if len(sectionKey) >= 2 {
- curValue, ok := c.data[sectionKey[0]]
+
+ c.RLock()
+ defer c.RUnlock()
+
+ sectionKeys := strings.Split(key, "::")
+ if len(sectionKeys) >= 2 {
+ curValue, ok := c.data[sectionKeys[0]]
if !ok {
return nil
}
- for _, key := range sectionKey[1:] {
+ for _, key := range sectionKeys[1:] {
if v, ok := curValue.(map[string]interface{}); ok {
if curValue, ok = v[key]; !ok {
return nil
diff --git a/config/json_test.go b/config/json_test.go
index 409e2c12..5aedae36 100644
--- a/config/json_test.go
+++ b/config/json_test.go
@@ -21,6 +21,7 @@ import (
var jsoncontext = `{
"appname": "beeapi",
+"testnames": "foo;bar",
"httpport": 8080,
"mysqlport": 3600,
"PI": 3.1415976,
@@ -28,8 +29,8 @@ var jsoncontext = `{
"autorender": false,
"copyrequestbody": true,
"database": {
- "host": "host",
- "port": "port",
+ "host": "host",
+ "port": "port",
"database": "database",
"username": "username",
"password": "password",
@@ -122,6 +123,12 @@ func TestJson(t *testing.T) {
if jsonconf.String("runmode") != "dev" {
t.Fatal("runmode not equal to dev")
}
+ if v := jsonconf.Strings("unknown"); len(v) > 0 {
+ t.Fatal("unknown strings, the length should be 0")
+ }
+ if v := jsonconf.Strings("testnames"); len(v) != 2 {
+ t.Fatal("testnames length should be 2")
+ }
if v, err := jsonconf.Bool("autorender"); err != nil || v != false {
t.Error(v)
t.Fatal(err)
@@ -179,4 +186,8 @@ func TestJson(t *testing.T) {
if _, err := jsonconf.Bool("unknown"); err == nil {
t.Error("unknown keys should return an error when expecting a Bool")
}
+
+ if !jsonconf.DefaultBool("unknow", true) {
+ t.Error("unknown keys with default value wrong")
+ }
}
diff --git a/context/context.go b/context/context.go
index d31076d4..f6aa85d6 100644
--- a/context/context.go
+++ b/context/context.go
@@ -31,7 +31,6 @@ import (
"strings"
"time"
- "github.com/astaxie/beego/middleware"
"github.com/astaxie/beego/utils"
)
@@ -53,22 +52,9 @@ func (ctx *Context) Redirect(status int, localurl string) {
}
// Abort stops this request.
-// if middleware.ErrorMaps exists, panic body.
-// if middleware.HTTPExceptionMaps exists, panic HTTPException struct with status and body string.
+// if beego.ErrorMaps exists, panic body.
func (ctx *Context) Abort(status int, body string) {
ctx.ResponseWriter.WriteHeader(status)
- // first panic from ErrorMaps, is is user defined error functions.
- if _, ok := middleware.ErrorMaps[body]; ok {
- panic(body)
- }
- // second panic from HTTPExceptionMaps, it is system defined functions.
- if e, ok := middleware.HTTPExceptionMaps[status]; ok {
- if len(body) >= 1 {
- e.Description = body
- }
- panic(e)
- }
- // last panic user string
panic(body)
}
@@ -154,8 +140,11 @@ func (ctx *Context) CheckXsrfCookie() bool {
}
if token == "" {
ctx.Abort(403, "'_xsrf' argument missing from POST")
- } else if ctx._xsrf_token != token {
+ return false
+ }
+ if ctx._xsrf_token != token {
ctx.Abort(403, "XSRF cookie does not match POST argument")
+ return false
}
return true
}
diff --git a/context/input.go b/context/input.go
index 6c662820..f535e6a2 100644
--- a/context/input.go
+++ b/context/input.go
@@ -27,7 +27,7 @@ import (
"github.com/astaxie/beego/session"
)
-// BeegoInput operates the http request header ,data ,cookie and body.
+// BeegoInput operates the http request header, data, cookie and body.
// it also contains router params and current session.
type BeegoInput struct {
CruSession session.SessionStore
@@ -72,11 +72,11 @@ func (input *BeegoInput) Site() string {
func (input *BeegoInput) Scheme() string {
if input.Request.URL.Scheme != "" {
return input.Request.URL.Scheme
- } else if input.Request.TLS == nil {
- return "http"
- } else {
- return "https"
}
+ if input.Request.TLS == nil {
+ return "http"
+ }
+ return "https"
}
// Domain returns host name.
@@ -153,12 +153,12 @@ func (input *BeegoInput) IsSecure() bool {
return input.Scheme() == "https"
}
-// IsSecure returns boolean of this request is in webSocket.
+// IsWebsocket returns boolean of this request is in webSocket.
func (input *BeegoInput) IsWebsocket() bool {
return input.Header("Upgrade") == "websocket"
}
-// IsSecure returns boolean of whether file uploads in this request or not..
+// IsUpload returns boolean of whether file uploads in this request or not..
func (input *BeegoInput) IsUpload() bool {
return strings.Contains(input.Header("Content-Type"), "multipart/form-data")
}
@@ -189,16 +189,24 @@ func (input *BeegoInput) Proxy() []string {
return []string{}
}
+// Referer returns http referer header.
+func (input *BeegoInput) Referer() string {
+ return input.Header("Referer")
+}
+
// Refer returns http referer header.
func (input *BeegoInput) Refer() string {
- return input.Header("Referer")
+ return input.Referer()
}
// SubDomains returns sub domain string.
// if aa.bb.domain.com, returns aa.bb .
func (input *BeegoInput) SubDomains() string {
parts := strings.Split(input.Host(), ".")
- return strings.Join(parts[len(parts)-2:], ".")
+ if len(parts) >= 3 {
+ return strings.Join(parts[:len(parts)-2], ".")
+ }
+ return ""
}
// Port returns request client port.
@@ -237,6 +245,7 @@ func (input *BeegoInput) Query(key string) string {
}
// Header returns request header item string by a given string.
+// if non-existed, return empty string.
func (input *BeegoInput) Header(key string) string {
return input.Request.Header.Get(key)
}
@@ -252,11 +261,12 @@ func (input *BeegoInput) Cookie(key string) string {
}
// Session returns current session item value by a given key.
+// if non-existed, return empty string.
func (input *BeegoInput) Session(key interface{}) interface{} {
return input.CruSession.Get(key)
}
-// Body returns the raw request body data as bytes.
+// CopyBody returns the raw request body data as bytes.
func (input *BeegoInput) CopyBody() []byte {
requestbody, _ := ioutil.ReadAll(input.Request.Body)
input.Request.Body.Close()
diff --git a/context/input_test.go b/context/input_test.go
index ddd1a056..4566f6d6 100644
--- a/context/input_test.go
+++ b/context/input_test.go
@@ -70,3 +70,45 @@ func TestParse(t *testing.T) {
}
fmt.Println(user)
}
+
+func TestSubDomain(t *testing.T) {
+ 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)
+ beegoInput := NewInput(r)
+
+ subdomain := beegoInput.SubDomains()
+ if subdomain != "www" {
+ t.Fatal("Subdomain parse error, got" + subdomain)
+ }
+
+ r, _ = http.NewRequest("GET", "http://localhost/", nil)
+ beegoInput.Request = r
+ if beegoInput.SubDomains() != "" {
+ t.Fatal("Subdomain parse error, should be empty, got " + beegoInput.SubDomains())
+ }
+
+ r, _ = http.NewRequest("GET", "http://aa.bb.example.com/", nil)
+ beegoInput.Request = r
+ if beegoInput.SubDomains() != "aa.bb" {
+ t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+ }
+
+ /* TODO Fix this
+ r, _ = http.NewRequest("GET", "http://127.0.0.1/", nil)
+ beegoInput.Request = r
+ if beegoInput.SubDomains() != "" {
+ t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+ }
+ */
+
+ r, _ = http.NewRequest("GET", "http://example.com/", nil)
+ beegoInput.Request = r
+ if beegoInput.SubDomains() != "" {
+ t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+ }
+
+ r, _ = http.NewRequest("GET", "http://aa.bb.cc.dd.example.com/", nil)
+ beegoInput.Request = r
+ if beegoInput.SubDomains() != "aa.bb.cc.dd" {
+ t.Fatal("Subdomain parse error, got " + beegoInput.SubDomains())
+ }
+}
diff --git a/context/output.go b/context/output.go
index 6298ee77..2141513d 100644
--- a/context/output.go
+++ b/context/output.go
@@ -188,7 +188,7 @@ func sanitizeValue(v string) string {
// Json writes json to response body.
// if coding is true, it converts utf-8 to \u0000 type.
func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) error {
- output.Header("Content-Type", "application/json;charset=UTF-8")
+ output.Header("Content-Type", "application/json; charset=utf-8")
var content []byte
var err error
if hasIndent {
@@ -209,7 +209,7 @@ func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) e
// Jsonp writes jsonp to response body.
func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error {
- output.Header("Content-Type", "application/javascript;charset=UTF-8")
+ output.Header("Content-Type", "application/javascript; charset=utf-8")
var content []byte
var err error
if hasIndent {
@@ -235,7 +235,7 @@ func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error {
// Xml writes xml string to response body.
func (output *BeegoOutput) Xml(data interface{}, hasIndent bool) error {
- output.Header("Content-Type", "application/xml;charset=UTF-8")
+ output.Header("Content-Type", "application/xml; charset=utf-8")
var content []byte
var err error
if hasIndent {
diff --git a/controller.go b/controller.go
index 72ba323b..e056f52d 100644
--- a/controller.go
+++ b/controller.go
@@ -270,16 +270,22 @@ func (c *Controller) Redirect(url string, code int) {
// Aborts stops controller handler and show the error data if code is defined in ErrorMap or code string.
func (c *Controller) Abort(code string) {
status, err := strconv.Atoi(code)
- if err == nil {
- c.Ctx.Abort(status, code)
- } else {
- c.Ctx.Abort(200, code)
+ if err != nil {
+ status = 200
}
+ c.CustomAbort(status, code)
}
// CustomAbort stops controller handler and show the error data, it's similar Aborts, but support status code and body.
func (c *Controller) CustomAbort(status int, body string) {
- c.Ctx.Abort(status, body)
+ c.Ctx.ResponseWriter.WriteHeader(status)
+ // first panic from ErrorMaps, is is user defined error functions.
+ if _, ok := ErrorMaps[body]; ok {
+ panic(body)
+ }
+ // last panic user string
+ c.Ctx.ResponseWriter.Write([]byte(body))
+ panic(USERSTOPRUN)
}
// StopRun makes panic of USERSTOPRUN error and go to recover function if defined.
@@ -289,7 +295,7 @@ func (c *Controller) StopRun() {
// UrlFor does another controller handler in this request function.
// it goes to this controller method if endpoint is not clear.
-func (c *Controller) UrlFor(endpoint string, values ...string) string {
+func (c *Controller) UrlFor(endpoint string, values ...interface{}) string {
if len(endpoint) <= 0 {
return ""
}
@@ -363,67 +369,144 @@ func (c *Controller) ParseForm(obj interface{}) error {
return ParseForm(c.Input(), obj)
}
-// GetString returns the input value by key string.
-func (c *Controller) GetString(key string) string {
- return c.Ctx.Input.Query(key)
+// GetString returns the input value by key string or the default value while it's present and input is blank
+func (c *Controller) GetString(key string, def ...string) string {
+ var defv string
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
+ if v := c.Ctx.Input.Query(key); v != "" {
+ return v
+ } else {
+ return defv
+ }
}
-// GetStrings returns the input string slice by key string.
+// GetStrings returns the input string slice by key string or the default value while it's present and input is blank
// it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection.
-func (c *Controller) GetStrings(key string) []string {
+func (c *Controller) GetStrings(key string, def ...[]string) []string {
+ var defv []string
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
f := c.Input()
if f == nil {
- return []string{}
+ return defv
}
+
vs := f[key]
if len(vs) > 0 {
return vs
+ } else {
+ return defv
}
- return []string{}
}
-// GetInt returns input as an int
-func (c *Controller) GetInt(key string) (int, error) {
- return strconv.Atoi(c.Ctx.Input.Query(key))
+// GetInt returns input as an int or the default value while it's present and input is blank
+func (c *Controller) GetInt(key string, def ...int) (int, error) {
+ var defv int
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ return strconv.Atoi(strv)
+ } else {
+ return defv, nil
+ }
}
-// GetInt8 return input as an int8
-func (c *Controller) GetInt8(key string) (int8, error) {
- i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 8)
- i8 := int8(i64)
+// GetInt8 return input as an int8 or the default value while it's present and input is blank
+func (c *Controller) GetInt8(key string, def ...int8) (int8, error) {
+ var defv int8
+ if len(def) > 0 {
+ defv = def[0]
+ }
- return i8, err
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ i64, err := strconv.ParseInt(strv, 10, 8)
+ i8 := int8(i64)
+ return i8, err
+ } else {
+ return defv, nil
+ }
}
-// GetInt16 returns input as an int16
-func (c *Controller) GetInt16(key string) (int16, error) {
- i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 16)
- i16 := int16(i64)
+// GetInt16 returns input as an int16 or the default value while it's present and input is blank
+func (c *Controller) GetInt16(key string, def ...int16) (int16, error) {
+ var defv int16
+ if len(def) > 0 {
+ defv = def[0]
+ }
- return i16, err
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ i64, err := strconv.ParseInt(strv, 10, 16)
+ i16 := int16(i64)
+
+ return i16, err
+ } else {
+ return defv, nil
+ }
}
-// GetInt32 returns input as an int32
-func (c *Controller) GetInt32(key string) (int32, error) {
- i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32)
- i32 := int32(i64)
+// GetInt32 returns input as an int32 or the default value while it's present and input is blank
+func (c *Controller) GetInt32(key string, def ...int32) (int32, error) {
+ var defv int32
+ if len(def) > 0 {
+ defv = def[0]
+ }
- return i32, err
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ i64, err := strconv.ParseInt(c.Ctx.Input.Query(key), 10, 32)
+ i32 := int32(i64)
+ return i32, err
+ } else {
+ return defv, nil
+ }
}
-// GetInt64 returns input value as int64.
-func (c *Controller) GetInt64(key string) (int64, error) {
- return strconv.ParseInt(c.Ctx.Input.Query(key), 10, 64)
+// GetInt64 returns input value as int64 or the default value while it's present and input is blank.
+func (c *Controller) GetInt64(key string, def ...int64) (int64, error) {
+ var defv int64
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ return strconv.ParseInt(strv, 10, 64)
+ } else {
+ return defv, nil
+ }
}
-// GetBool returns input value as bool.
-func (c *Controller) GetBool(key string) (bool, error) {
- return strconv.ParseBool(c.Ctx.Input.Query(key))
+// GetBool returns input value as bool or the default value while it's present and input is blank.
+func (c *Controller) GetBool(key string, def ...bool) (bool, error) {
+ var defv bool
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ return strconv.ParseBool(strv)
+ } else {
+ return defv, nil
+ }
}
-// GetFloat returns input value as float64.
-func (c *Controller) GetFloat(key string) (float64, error) {
- return strconv.ParseFloat(c.Ctx.Input.Query(key), 64)
+// GetFloat returns input value as float64 or the default value while it's present and input is blank.
+func (c *Controller) GetFloat(key string, def ...float64) (float64, error) {
+ var defv float64
+ if len(def) > 0 {
+ defv = def[0]
+ }
+
+ if strv := c.Ctx.Input.Query(key); strv != "" {
+ return strconv.ParseFloat(c.Ctx.Input.Query(key), 64)
+ } else {
+ return defv, nil
+ }
}
// GetFile returns the file data in file upload field named as key.
diff --git a/middleware/error.go b/error.go
similarity index 51%
rename from middleware/error.go
rename to error.go
index 3b7191e9..71be6916 100644
--- a/middleware/error.go
+++ b/error.go
@@ -12,20 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package middleware
+package beego
import (
"fmt"
"html/template"
"net/http"
+ "reflect"
"runtime"
"strconv"
+ "strings"
+
+ "github.com/astaxie/beego/context"
+ "github.com/astaxie/beego/utils"
)
-var (
- AppName string
- VERSION string
+const (
+ errorTypeHandler = iota
+ errorTypeController
)
+
var tpl = `
@@ -76,18 +82,18 @@ var tpl = `
`
// render default application error page with error and stack string.
-func ShowErr(err interface{}, rw http.ResponseWriter, r *http.Request, Stack string) {
+func showErr(err interface{}, ctx *context.Context, Stack string) {
t, _ := template.New("beegoerrortemp").Parse(tpl)
data := make(map[string]string)
data["AppError"] = AppName + ":" + fmt.Sprint(err)
- data["RequestMethod"] = r.Method
- data["RequestURL"] = r.RequestURI
- data["RemoteAddr"] = r.RemoteAddr
+ data["RequestMethod"] = ctx.Input.Method()
+ data["RequestURL"] = ctx.Input.Uri()
+ data["RemoteAddr"] = ctx.Input.IP()
data["Stack"] = Stack
data["BeegoVersion"] = VERSION
data["GoVersion"] = runtime.Version()
- rw.WriteHeader(500)
- t.Execute(rw, data)
+ ctx.Output.SetStatus(500)
+ t.Execute(ctx.ResponseWriter, data)
}
var errtpl = `
@@ -190,15 +196,68 @@ var errtpl = `
`
+type errorInfo struct {
+ controllerType reflect.Type
+ handler http.HandlerFunc
+ method string
+ errorType int
+}
+
// map of http handlers for each error string.
-var ErrorMaps map[string]http.HandlerFunc
+var ErrorMaps map[string]*errorInfo
func init() {
- ErrorMaps = make(map[string]http.HandlerFunc)
+ ErrorMaps = make(map[string]*errorInfo)
+}
+
+// show 401 unauthorized error.
+func unauthorized(rw http.ResponseWriter, r *http.Request) {
+ t, _ := template.New("beegoerrortemp").Parse(errtpl)
+ data := make(map[string]interface{})
+ data["Title"] = "Unauthorized"
+ data["Content"] = template.HTML("
The page you have requested can't be authorized." +
+ "
Perhaps you are here because:" +
+ "
" +
+ "
The credentials you supplied are incorrect" +
+ "
There are errors in the website address" +
+ "
")
+ data["BeegoVersion"] = VERSION
+ t.Execute(rw, data)
+}
+
+// show 402 Payment Required
+func paymentRequired(rw http.ResponseWriter, r *http.Request) {
+ t, _ := template.New("beegoerrortemp").Parse(errtpl)
+ data := make(map[string]interface{})
+ data["Title"] = "Payment Required"
+ data["Content"] = template.HTML("
The page you have requested Payment Required." +
+ "
Perhaps you are here because:" +
+ "
" +
+ "
The credentials you supplied are incorrect" +
+ "
There are errors in the website address" +
+ "
")
+ data["BeegoVersion"] = VERSION
+ t.Execute(rw, data)
+}
+
+// show 403 forbidden error.
+func forbidden(rw http.ResponseWriter, r *http.Request) {
+ t, _ := template.New("beegoerrortemp").Parse(errtpl)
+ data := make(map[string]interface{})
+ data["Title"] = "Forbidden"
+ data["Content"] = template.HTML("
The page you have requested is forbidden." +
+ "
Perhaps you are here because:" +
+ "
" +
+ "
Your address may be blocked" +
+ "
The site may be disabled" +
+ "
You need to log in" +
+ "
")
+ data["BeegoVersion"] = VERSION
+ t.Execute(rw, data)
}
// show 404 notfound error.
-func NotFound(rw http.ResponseWriter, r *http.Request) {
+func notFound(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Page Not Found"
@@ -211,45 +270,66 @@ func NotFound(rw http.ResponseWriter, r *http.Request) {
"
You like 404 pages" +
"")
data["BeegoVersion"] = VERSION
- //rw.WriteHeader(http.StatusNotFound)
t.Execute(rw, data)
}
-// show 401 unauthorized error.
-func Unauthorized(rw http.ResponseWriter, r *http.Request) {
+// show 405 Method Not Allowed
+func methodNotAllowed(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
- data["Title"] = "Unauthorized"
- data["Content"] = template.HTML("
The page you have requested can't be authorized." +
+ data["Title"] = "Method Not Allowed"
+ data["Content"] = template.HTML("
The method you have requested Not Allowed." +
"
Perhaps you are here because:" +
"
" +
- "
The credentials you supplied are incorrect" +
- "
There are errors in the website address" +
+ "
The method specified in the Request-Line is not allowed for the resource identified by the Request-URI" +
+ "
The response MUST include an Allow header containing a list of valid methods for the requested resource." +
"
")
data["BeegoVersion"] = VERSION
- //rw.WriteHeader(http.StatusUnauthorized)
t.Execute(rw, data)
}
-// show 403 forbidden error.
-func Forbidden(rw http.ResponseWriter, r *http.Request) {
+// show 500 internal server error.
+func internalServerError(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
- data["Title"] = "Forbidden"
- data["Content"] = template.HTML("
The page you have requested is forbidden." +
- "
Perhaps you are here because:" +
+ data["Title"] = "Internal Server Error"
+ data["Content"] = template.HTML("
The page you have requested is down right now." +
"
" +
- "
Your address may be blocked" +
- "
The site may be disabled" +
- "
You need to log in" +
- "
")
+ "
Please try again later and report the error to the website administrator" +
+ "
")
+ data["BeegoVersion"] = VERSION
+ t.Execute(rw, data)
+}
+
+// show 501 Not Implemented.
+func notImplemented(rw http.ResponseWriter, r *http.Request) {
+ t, _ := template.New("beegoerrortemp").Parse(errtpl)
+ data := make(map[string]interface{})
+ data["Title"] = "Not Implemented"
+ data["Content"] = template.HTML("
The page you have requested is Not Implemented." +
+ "
" +
+ "
Please try again later and report the error to the website administrator" +
+ "
")
+ data["BeegoVersion"] = VERSION
+ t.Execute(rw, data)
+}
+
+// show 502 Bad Gateway.
+func badGateway(rw http.ResponseWriter, r *http.Request) {
+ t, _ := template.New("beegoerrortemp").Parse(errtpl)
+ data := make(map[string]interface{})
+ data["Title"] = "Bad Gateway"
+ data["Content"] = template.HTML("
The page you have requested is down right now." +
+ "
" +
+ "
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." +
+ "
Please try again later and report the error to the website administrator" +
+ "
")
data["BeegoVersion"] = VERSION
- //rw.WriteHeader(http.StatusForbidden)
t.Execute(rw, data)
}
// show 503 service unavailable error.
-func ServiceUnavailable(rw http.ResponseWriter, r *http.Request) {
+func serviceUnavailable(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Service Unavailable"
@@ -260,80 +340,151 @@ func ServiceUnavailable(rw http.ResponseWriter, r *http.Request) {
"
Please try again later." +
"")
data["BeegoVersion"] = VERSION
- //rw.WriteHeader(http.StatusServiceUnavailable)
t.Execute(rw, data)
}
-// show 500 internal server error.
-func InternalServerError(rw http.ResponseWriter, r *http.Request) {
+// show 504 Gateway Timeout.
+func gatewayTimeout(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
- data["Title"] = "Internal Server Error"
- data["Content"] = template.HTML("
The page you have requested is down right now." +
+ data["Title"] = "Gateway Timeout"
+ data["Content"] = template.HTML("
The page you have requested is unavailable." +
+ "
Perhaps you are here because:" +
"
" +
- "
Please try again later and report the error to the website administrator" +
- "
")
+ "
The server, while acting as a gateway or proxy, did not receive a timely response from the upstream server specified by the URI." +
+ "
Please try again later." +
+ "")
data["BeegoVersion"] = VERSION
- //rw.WriteHeader(http.StatusInternalServerError)
t.Execute(rw, data)
}
-// show 500 internal error with simple text string.
-func SimpleServerError(rw http.ResponseWriter, r *http.Request) {
- http.Error(rw, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
-}
-
-// add http handler for given error string.
-func Errorhandler(err string, h http.HandlerFunc) {
- ErrorMaps[err] = h
-}
-
// register default error http handlers, 404,401,403,500 and 503.
-func RegisterErrorHandler() {
- if _, ok := ErrorMaps["404"]; !ok {
- ErrorMaps["404"] = NotFound
+func registerDefaultErrorHandler() {
+ if _, ok := ErrorMaps["401"]; !ok {
+ Errorhandler("401", unauthorized)
}
- if _, ok := ErrorMaps["401"]; !ok {
- ErrorMaps["401"] = Unauthorized
+ if _, ok := ErrorMaps["402"]; !ok {
+ Errorhandler("402", paymentRequired)
}
if _, ok := ErrorMaps["403"]; !ok {
- ErrorMaps["403"] = Forbidden
+ Errorhandler("403", forbidden)
}
- if _, ok := ErrorMaps["503"]; !ok {
- ErrorMaps["503"] = ServiceUnavailable
+ if _, ok := ErrorMaps["404"]; !ok {
+ Errorhandler("404", notFound)
+ }
+
+ if _, ok := ErrorMaps["405"]; !ok {
+ Errorhandler("405", methodNotAllowed)
}
if _, ok := ErrorMaps["500"]; !ok {
- ErrorMaps["500"] = InternalServerError
+ Errorhandler("500", internalServerError)
}
+ if _, ok := ErrorMaps["501"]; !ok {
+ Errorhandler("501", notImplemented)
+ }
+ if _, ok := ErrorMaps["502"]; !ok {
+ Errorhandler("502", badGateway)
+ }
+
+ if _, ok := ErrorMaps["503"]; !ok {
+ Errorhandler("503", serviceUnavailable)
+ }
+
+ if _, ok := ErrorMaps["504"]; !ok {
+ Errorhandler("504", gatewayTimeout)
+ }
+}
+
+// ErrorHandler registers http.HandlerFunc to each http err code string.
+// usage:
+// beego.ErrorHandler("404",NotFound)
+// beego.ErrorHandler("500",InternalServerError)
+func Errorhandler(code string, h http.HandlerFunc) *App {
+ errinfo := &errorInfo{}
+ errinfo.errorType = errorTypeHandler
+ errinfo.handler = h
+ errinfo.method = code
+ ErrorMaps[code] = errinfo
+ return BeeApp
+}
+
+// ErrorController registers ControllerInterface to each http err code string.
+// usage:
+// beego.ErrorHandler(&controllers.ErrorController{})
+func ErrorController(c ControllerInterface) *App {
+ reflectVal := reflect.ValueOf(c)
+ rt := reflectVal.Type()
+ ct := reflect.Indirect(reflectVal).Type()
+ for i := 0; i < rt.NumMethod(); i++ {
+ if !utils.InSlice(rt.Method(i).Name, exceptMethod) && strings.HasPrefix(rt.Method(i).Name, "Error") {
+ errinfo := &errorInfo{}
+ errinfo.errorType = errorTypeController
+ errinfo.controllerType = ct
+ errinfo.method = rt.Method(i).Name
+ errname := strings.TrimPrefix(rt.Method(i).Name, "Error")
+ ErrorMaps[errname] = errinfo
+ }
+ }
+ return BeeApp
}
// show error string as simple text message.
// if error string is empty, show 500 error as default.
-func Exception(errcode string, w http.ResponseWriter, r *http.Request, msg string) {
+func exception(errcode string, ctx *context.Context) {
+ code, err := strconv.Atoi(errcode)
+ if err != nil {
+ code = 503
+ }
+ ctx.ResponseWriter.WriteHeader(code)
if h, ok := ErrorMaps[errcode]; ok {
- isint, err := strconv.Atoi(errcode)
- if err != nil {
- isint = 500
- }
- w.Header().Set("Content-Type", "text/html; charset=utf-8")
- w.WriteHeader(isint)
- h(w, r)
+ executeError(h, ctx)
+ return
+ } else if h, ok := ErrorMaps["503"]; ok {
+ executeError(h, ctx)
return
} else {
- isint, err := strconv.Atoi(errcode)
- if err != nil {
- isint = 500
- }
- if isint == 400 {
- msg = "404 page not found"
- }
- w.Header().Set("Content-Type", "text/plain; charset=utf-8")
- w.WriteHeader(isint)
- fmt.Fprintln(w, msg)
- return
+ ctx.WriteString(errcode)
+ }
+}
+
+func executeError(err *errorInfo, ctx *context.Context) {
+ if err.errorType == errorTypeHandler {
+ err.handler(ctx.ResponseWriter, ctx.Request)
+ return
+ }
+ if err.errorType == errorTypeController {
+ //Invoke the request handler
+ vc := reflect.New(err.controllerType)
+ execController, ok := vc.Interface().(ControllerInterface)
+ if !ok {
+ panic("controller is not ControllerInterface")
+ }
+ //call the controller init function
+ execController.Init(ctx, err.controllerType.Name(), err.method, vc.Interface())
+
+ //call prepare function
+ execController.Prepare()
+
+ execController.URLMapping()
+
+ in := make([]reflect.Value, 0)
+ method := vc.MethodByName(err.method)
+ method.Call(in)
+
+ //render template
+ if ctx.Output.Status == 0 {
+ if AutoRender {
+ if err := execController.Render(); err != nil {
+ panic(err)
+ }
+ }
+ }
+
+ // finish all runrouter. release resource
+ execController.Finish()
}
}
diff --git a/example/beeapi/controllers/default.go b/example/beeapi/controllers/default.go
index c6e53e74..a2184075 100644
--- a/example/beeapi/controllers/default.go
+++ b/example/beeapi/controllers/default.go
@@ -17,47 +17,47 @@ type ObjectController struct {
beego.Controller
}
-func (this *ObjectController) Post() {
+func (o *ObjectController) Post() {
var ob models.Object
- json.Unmarshal(this.Ctx.Input.RequestBody, &ob)
+ json.Unmarshal(o.Ctx.Input.RequestBody, &ob)
objectid := models.AddOne(ob)
- this.Data["json"] = map[string]string{"ObjectId": objectid}
- this.ServeJson()
+ o.Data["json"] = map[string]string{"ObjectId": objectid}
+ o.ServeJson()
}
-func (this *ObjectController) Get() {
- objectId := this.Ctx.Input.Params[":objectId"]
+func (o *ObjectController) Get() {
+ objectId := o.Ctx.Input.Params[":objectId"]
if objectId != "" {
ob, err := models.GetOne(objectId)
if err != nil {
- this.Data["json"] = err
+ o.Data["json"] = err
} else {
- this.Data["json"] = ob
+ o.Data["json"] = ob
}
} else {
obs := models.GetAll()
- this.Data["json"] = obs
+ o.Data["json"] = obs
}
- this.ServeJson()
+ o.ServeJson()
}
-func (this *ObjectController) Put() {
- objectId := this.Ctx.Input.Params[":objectId"]
+func (o *ObjectController) Put() {
+ objectId := o.Ctx.Input.Params[":objectId"]
var ob models.Object
- json.Unmarshal(this.Ctx.Input.RequestBody, &ob)
+ json.Unmarshal(o.Ctx.Input.RequestBody, &ob)
err := models.Update(objectId, ob.Score)
if err != nil {
- this.Data["json"] = err
+ o.Data["json"] = err
} else {
- this.Data["json"] = "update success!"
+ o.Data["json"] = "update success!"
}
- this.ServeJson()
+ o.ServeJson()
}
-func (this *ObjectController) Delete() {
- objectId := this.Ctx.Input.Params[":objectId"]
+func (o *ObjectController) Delete() {
+ objectId := o.Ctx.Input.Params[":objectId"]
models.Delete(objectId)
- this.Data["json"] = "delete success!"
- this.ServeJson()
+ o.Data["json"] = "delete success!"
+ o.ServeJson()
}
diff --git a/example/chat/controllers/default.go b/example/chat/controllers/default.go
index 370e6db1..95ef8a9b 100644
--- a/example/chat/controllers/default.go
+++ b/example/chat/controllers/default.go
@@ -14,7 +14,7 @@ type MainController struct {
beego.Controller
}
-func (this *MainController) Get() {
- this.Data["host"] = this.Ctx.Request.Host
- this.TplNames = "index.tpl"
+func (m *MainController) Get() {
+ m.Data["host"] = m.Ctx.Request.Host
+ m.TplNames = "index.tpl"
}
diff --git a/example/chat/controllers/ws.go b/example/chat/controllers/ws.go
index 862f89c9..fc3917b3 100644
--- a/example/chat/controllers/ws.go
+++ b/example/chat/controllers/ws.go
@@ -150,14 +150,14 @@ type WSController struct {
}
var upgrader = websocket.Upgrader{
- ReadBufferSize: 1024,
- WriteBufferSize: 1024,
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
}
-func (this *WSController) Get() {
- ws, err := upgrader.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request,nil)
+func (w *WSController) Get() {
+ ws, err := upgrader.Upgrade(w.Ctx.ResponseWriter, w.Ctx.Request, nil)
if _, ok := err.(websocket.HandshakeError); ok {
- http.Error(this.Ctx.ResponseWriter, "Not a websocket handshake", 400)
+ http.Error(w.Ctx.ResponseWriter, "Not a websocket handshake", 400)
return
} else if err != nil {
return
diff --git a/example/chat/views/index.tpl b/example/chat/views/index.tpl
index 75bffa62..3a9d8838 100644
--- a/example/chat/views/index.tpl
+++ b/example/chat/views/index.tpl
@@ -2,7 +2,7 @@
Chat Example
-
+