From 549a39c4787afe9ab377d3373a271f94da3ba33a Mon Sep 17 00:00:00 2001 From: youngsterxyf Date: Mon, 14 Mar 2016 11:26:26 +0800 Subject: [PATCH 01/28] fix issue1789: when testing, load config explicitly and forcibly --- beego.go | 1 + config.go | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/beego.go b/beego.go index 8f82cdcf..a6074d22 100644 --- a/beego.go +++ b/beego.go @@ -87,5 +87,6 @@ func TestBeegoInit(ap string) { os.Setenv("BEEGO_RUNMODE", "test") appConfigPath = filepath.Join(ap, "conf", "app.conf") os.Chdir(ap) + LoadAppConfig(appConfigProvider, appConfigPath) initBeforeHTTPRun() } diff --git a/config.go b/config.go index 2761e7cb..0d4df95c 100644 --- a/config.go +++ b/config.go @@ -316,10 +316,6 @@ func LoadAppConfig(adapterName, configPath string) error { return fmt.Errorf("the target config file: %s don't exist", configPath) } - if absConfigPath == appConfigPath { - return nil - } - appConfigPath = absConfigPath appConfigProvider = adapterName From 8660a54facfff34b6f6297921fbe4808c8a7e8bc Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 11:49:23 +0800 Subject: [PATCH 02/28] make router fast --- admin.go | 2 +- namespace.go | 4 ++-- router.go | 55 +++++++++++++++++++++++++--------------------------- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/admin.go b/admin.go index 031e6421..cf5bc63a 100644 --- a/admin.go +++ b/admin.go @@ -196,7 +196,7 @@ func listConf(rw http.ResponseWriter, r *http.Request) { BeforeExec: "Before Exec", AfterExec: "After Exec", FinishRouter: "Finish Router"} { - if bf, ok := BeeApp.Handlers.filters[k]; ok { + if bf := BeeApp.Handlers.filters[k]; len(bf) > 0 { filterType = fr filterTypes = append(filterTypes, filterType) resultList := new([][]string) diff --git a/namespace.go b/namespace.go index 4007d44c..cfde0111 100644 --- a/namespace.go +++ b/namespace.go @@ -44,7 +44,7 @@ func NewNamespace(prefix string, params ...LinkNamespace) *Namespace { return ns } -// Cond set condtion function +// Cond set condition function // if cond return true can run this namespace, else can't // usage: // ns.Cond(func (ctx *context.Context) bool{ @@ -60,7 +60,7 @@ func (n *Namespace) Cond(cond namespaceCond) *Namespace { exception("405", ctx) } } - if v, ok := n.handlers.filters[BeforeRouter]; ok { + if v := n.handlers.filters[BeforeRouter]; len(v) > 0 { mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = "*" diff --git a/router.go b/router.go index 5b4b1ff9..597acbb9 100644 --- a/router.go +++ b/router.go @@ -114,7 +114,7 @@ type controllerInfo struct { type ControllerRegister struct { routers map[string]*Tree enableFilter bool - filters map[int][]*FilterRouter + filters [5][]*FilterRouter pool sync.Pool } @@ -122,7 +122,6 @@ type ControllerRegister struct { func NewControllerRegister() *ControllerRegister { cr := &ControllerRegister{ routers: make(map[string]*Tree), - filters: make(map[int][]*FilterRouter), } cr.pool.New = func() interface{} { return beecontext.NewContext() @@ -408,7 +407,6 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) // InsertFilter Add a FilterFunc with pattern rule and action constant. // The bool params is for setting the returnOnOutput value (false allows multiple filters to execute) func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter FilterFunc, params ...bool) error { - mr := new(FilterRouter) mr.tree = NewTree() mr.pattern = pattern @@ -426,9 +424,13 @@ func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter Filter } // add Filter into -func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) error { - p.filters[pos] = append(p.filters[pos], mr) +func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err error) { + if pos < BeforeStatic || pos > FinishRouter { + err = fmt.Errorf("can not find your filter postion") + return + } p.enableFilter = true + p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -577,20 +579,16 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin return false, "" } -func (p *ControllerRegister) execFilter(context *beecontext.Context, pos int, urlPath string) (started bool) { - if p.enableFilter { - if l, ok := p.filters[pos]; ok { - for _, filterR := range l { - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - if ok := filterR.ValidRouter(urlPath, context); ok { - filterR.filterFunc(context) - } - if filterR.returnOnOutput && context.ResponseWriter.Started { - return true - } - } +func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, l []*FilterRouter) (started bool) { + for _, filterR := range l { + if filterR.returnOnOutput && context.ResponseWriter.Started { + return true + } + if ok := filterR.ValidRouter(urlPath, context); ok { + filterR.filterFunc(context) + } + if filterR.returnOnOutput && context.ResponseWriter.Started { + return true } } return false @@ -617,11 +615,10 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) context.Output.Header("Server", BConfig.ServerName) } - var urlPath string + var urlPath = r.URL.Path + if !BConfig.RouterCaseSensitive { urlPath = strings.ToLower(r.URL.Path) - } else { - urlPath = r.URL.Path } // filter wrong http method @@ -631,7 +628,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if p.execFilter(context, BeforeStatic, urlPath) { + if fs := p.filters[BeforeStatic]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } @@ -663,8 +660,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - - if p.execFilter(context, BeforeRouter, urlPath) { + if fs := p.filters[BeforeRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } @@ -693,7 +689,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if p.execFilter(context, BeforeExec, urlPath) { + if fs := p.filters[BeforeExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } isRunnable := false @@ -794,12 +790,13 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if p.execFilter(context, AfterExec, urlPath) { + if fs := p.filters[AfterExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { goto Admin } } - - p.execFilter(context, FinishRouter, urlPath) + if fs := p.filters[FinishRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + goto Admin + } Admin: //admin module record QPS From c51bc86d3fd0dc38596017f8869b0bb2ff2b6733 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 16:51:21 +0800 Subject: [PATCH 03/28] goto bug fixed --- router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.go b/router.go index 597acbb9..9b62c4cc 100644 --- a/router.go +++ b/router.go @@ -652,7 +652,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if err != nil { Error(err) exception("503", context) - return + goto Admin } defer func() { if context.Input.CruSession != nil { From 34615ee8fcbb485574b181bd2bf9be86e3a97e87 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 18:37:54 +0800 Subject: [PATCH 04/28] add router filter enable flag --- router.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/router.go b/router.go index 9b62c4cc..9e75e013 100644 --- a/router.go +++ b/router.go @@ -114,7 +114,8 @@ type controllerInfo struct { type ControllerRegister struct { routers map[string]*Tree enableFilter bool - filters [5][]*FilterRouter + filters [FinishRouter + 1][]*FilterRouter + filterFlag [FinishRouter + 1]bool pool sync.Pool } @@ -430,6 +431,7 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err return } p.enableFilter = true + p.filterFlag[pos] = true p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -579,8 +581,8 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin return false, "" } -func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, l []*FilterRouter) (started bool) { - for _, filterR := range l { +func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath string, pos int) (started bool) { + for _, filterR := range p.filters[pos] { if filterR.returnOnOutput && context.ResponseWriter.Started { return true } @@ -628,11 +630,12 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if fs := p.filters[BeforeStatic]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeStatic] && p.execFilter(context, urlPath, BeforeStatic) { goto Admin } serverStaticRouter(context) + if context.ResponseWriter.Started { findRouter = true goto Admin @@ -660,7 +663,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - if fs := p.filters[BeforeRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeRouter] && p.execFilter(context, urlPath, BeforeRouter) { goto Admin } @@ -689,7 +692,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if fs := p.filters[BeforeExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[BeforeExec] && p.execFilter(context, urlPath, BeforeExec) { goto Admin } isRunnable := false @@ -790,11 +793,11 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if fs := p.filters[AfterExec]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[AfterExec] && p.execFilter(context, urlPath, AfterExec) { goto Admin } } - if fs := p.filters[FinishRouter]; len(fs) > 0 && p.execFilter(context, urlPath, fs) { + if p.filterFlag[FinishRouter] && p.execFilter(context, urlPath, FinishRouter) { goto Admin } From 565c4a4d592cf196610a3759d88b00822c87fef8 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 15 Mar 2016 18:50:18 +0800 Subject: [PATCH 05/28] make the code run more fast --- router.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/router.go b/router.go index 9e75e013..0da56464 100644 --- a/router.go +++ b/router.go @@ -115,7 +115,6 @@ type ControllerRegister struct { routers map[string]*Tree enableFilter bool filters [FinishRouter + 1][]*FilterRouter - filterFlag [FinishRouter + 1]bool pool sync.Pool } @@ -431,7 +430,6 @@ func (p *ControllerRegister) insertFilterRouter(pos int, mr *FilterRouter) (err return } p.enableFilter = true - p.filterFlag[pos] = true p.filters[pos] = append(p.filters[pos], mr) return nil } @@ -630,7 +628,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } // filter for static file - if p.filterFlag[BeforeStatic] && p.execFilter(context, urlPath, BeforeStatic) { + if len(p.filters[BeforeStatic]) > 0 && p.execFilter(context, urlPath, BeforeStatic) { goto Admin } @@ -663,7 +661,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } }() } - if p.filterFlag[BeforeRouter] && p.execFilter(context, urlPath, BeforeRouter) { + if len(p.filters[BeforeRouter]) > 0 && p.execFilter(context, urlPath, BeforeRouter) { goto Admin } @@ -692,7 +690,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if findRouter { //execute middleware filters - if p.filterFlag[BeforeExec] && p.execFilter(context, urlPath, BeforeExec) { + if len(p.filters[BeforeExec]) > 0 && p.execFilter(context, urlPath, BeforeExec) { goto Admin } isRunnable := false @@ -793,11 +791,11 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } //execute middleware filters - if p.filterFlag[AfterExec] && p.execFilter(context, urlPath, AfterExec) { + if len(p.filters[AfterExec]) > 0 && p.execFilter(context, urlPath, AfterExec) { goto Admin } } - if p.filterFlag[FinishRouter] && p.execFilter(context, urlPath, FinishRouter) { + if len(p.filters[FinishRouter]) > 0 && p.execFilter(context, urlPath, FinishRouter) { goto Admin } From 94599013fc8a932de20bba7ce2fce91f61634c16 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Wed, 16 Mar 2016 07:53:36 +0800 Subject: [PATCH 06/28] url to lower case --- router.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router.go b/router.go index 0da56464..71be4c16 100644 --- a/router.go +++ b/router.go @@ -618,7 +618,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) var urlPath = r.URL.Path if !BConfig.RouterCaseSensitive { - urlPath = strings.ToLower(r.URL.Path) + urlPath = strings.ToLower(urlPath) } // filter wrong http method From 443d71397cd33f8b18c7fc82b7b372bdf5b36539 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 09:35:14 +0800 Subject: [PATCH 07/28] write error to response --- error.go | 208 +++++++++++++++++++++++++------------------------------ 1 file changed, 94 insertions(+), 114 deletions(-) diff --git a/error.go b/error.go index 4f48fab2..6488fc6c 100644 --- a/error.go +++ b/error.go @@ -210,159 +210,139 @@ var ErrorMaps = make(map[string]*errorInfo, 10) // show 401 unauthorized error. func unauthorized(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(401), - "BeegoVersion": VERSION, - } - 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" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 401, + "
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"+ + "
", + ) } // show 402 Payment Required func paymentRequired(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(402), - "BeegoVersion": VERSION, - } - 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" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 402, + "
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"+ + "
", + ) } // show 403 forbidden error. func forbidden(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(403), - "BeegoVersion": VERSION, - } - 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" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 403, + "
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"+ + "
", + ) } -// show 404 notfound error. +// show 404 not found error. func notFound(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(404), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested has flown the coop." + - "
Perhaps you are here because:" + - "

    " + - "
    The page has moved" + - "
    The page no longer exists" + - "
    You were looking for your puppy and got lost" + - "
    You like 404 pages" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 404, + "
The page you have requested has flown the coop."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    The page has moved"+ + "
    The page no longer exists"+ + "
    You were looking for your puppy and got lost"+ + "
    You like 404 pages"+ + "
", + ) } // show 405 Method Not Allowed func methodNotAllowed(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(405), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The method you have requested Not Allowed." + - "
Perhaps you are here because:" + - "

    " + - "
    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." + - "
") - t.Execute(rw, data) + responseError(rw, r, + 405, + "
The method you have requested Not Allowed."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    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."+ + "
", + ) } // show 500 internal server error. func internalServerError(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(500), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is down right now." + - "

    " + - "
    Please try again later and report the error to the website administrator" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 500, + "
The page you have requested is down right now."+ + "

    "+ + "
    Please try again later and report the error to the website administrator"+ + "
", + ) } // show 501 Not Implemented. func notImplemented(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(504), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is Not Implemented." + - "

    " + - "
    Please try again later and report the error to the website administrator" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 501, + "
The page you have requested is Not Implemented."+ + "

    "+ + "
    Please try again later and report the error to the website administrator"+ + "
", + ) } // show 502 Bad Gateway. func badGateway(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(502), - "BeegoVersion": VERSION, - } - 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" + - "
") - t.Execute(rw, data) + responseError(rw, r, + 502, + "
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"+ + "
", + ) } // show 503 service unavailable error. func serviceUnavailable(rw http.ResponseWriter, r *http.Request) { - t, _ := template.New("beegoerrortemp").Parse(errtpl) - data := map[string]interface{}{ - "Title": http.StatusText(503), - "BeegoVersion": VERSION, - } - data["Content"] = template.HTML("
The page you have requested is unavailable." + - "
Perhaps you are here because:" + - "

    " + - "

    The page is overloaded" + - "
    Please try again later." + - "
") - t.Execute(rw, data) + responseError(rw, r, + 503, + "
The page you have requested is unavailable."+ + "
Perhaps you are here because:"+ + "

    "+ + "

    The page is overloaded"+ + "
    Please try again later."+ + "
", + ) } // show 504 Gateway Timeout. func gatewayTimeout(rw http.ResponseWriter, r *http.Request) { + responseError(rw, r, + 504, + "
The page you have requested is unavailable"+ + "
Perhaps you are here because:"+ + "

    "+ + "

    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."+ + "
", + ) +} + +func responseError(rw http.ResponseWriter, r *http.Request, errCode int, errContent string) { t, _ := template.New("beegoerrortemp").Parse(errtpl) data := map[string]interface{}{ - "Title": http.StatusText(504), + "Title": http.StatusText(errCode), "BeegoVersion": VERSION, + "Content": errContent, } - data["Content"] = template.HTML("
The page you have requested is unavailable." + - "
Perhaps you are here because:" + - "

    " + - "

    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." + - "
") t.Execute(rw, data) } From 0859ec570cba6327faf6881efc2eff2a136ced79 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 09:46:34 +0800 Subject: [PATCH 08/28] refactor of error response and fix err code bug --- controller.go | 3 ++- error.go | 5 ++++- router.go | 37 ++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/controller.go b/controller.go index 85894275..9d265758 100644 --- a/controller.go +++ b/controller.go @@ -261,12 +261,13 @@ func (c *Controller) Abort(code string) { // 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.Output.Status = status // first panic from ErrorMaps, is is user defined error functions. if _, ok := ErrorMaps[body]; ok { + c.Ctx.Output.Status = status panic(body) } // last panic user string + c.Ctx.ResponseWriter.WriteHeader(status) c.Ctx.ResponseWriter.Write([]byte(body)) panic(ErrAbort) } diff --git a/error.go b/error.go index 6488fc6c..8cfa0c67 100644 --- a/error.go +++ b/error.go @@ -388,7 +388,10 @@ func exception(errCode string, ctx *context.Context) { if err == nil { return v } - return 503 + if ctx.Output.Status == 0 { + return 503 + } + return ctx.Output.Status } for _, ec := range []string{errCode, "503", "500"} { diff --git a/router.go b/router.go index 5b4b1ff9..99780b5c 100644 --- a/router.go +++ b/router.go @@ -844,27 +844,26 @@ func (p *ControllerRegister) recoverPanic(context *beecontext.Context) { } if !BConfig.RecoverPanic { panic(err) - } else { - if BConfig.EnableErrorsShow { - if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { - exception(fmt.Sprint(err), context) - return - } + } + if BConfig.EnableErrorsShow { + if _, ok := ErrorMaps[fmt.Sprint(err)]; ok { + exception(fmt.Sprint(err), context) + return } - var stack string - Critical("the request url is ", context.Input.URL()) - Critical("Handler crashed with error", err) - for i := 1; ; i++ { - _, file, line, ok := runtime.Caller(i) - if !ok { - break - } - Critical(fmt.Sprintf("%s:%d", file, line)) - stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) - } - if BConfig.RunMode == DEV { - showErr(err, context, stack) + } + var stack string + Critical("the request url is ", context.Input.URL()) + Critical("Handler crashed with error", err) + for i := 1; ; i++ { + _, file, line, ok := runtime.Caller(i) + if !ok { + break } + Critical(fmt.Sprintf("%s:%d", file, line)) + stack = stack + fmt.Sprintln(fmt.Sprintf("%s:%d", file, line)) + } + if BConfig.RunMode == DEV { + showErr(err, context, stack) } } } From 48147f50d8e65838938adeffb239de45da4f91aa Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:09:21 +0800 Subject: [PATCH 09/28] add some gzip future --- context/acceptencoder.go | 93 ++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 033d9ca8..2e5af83a 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -25,8 +25,35 @@ import ( "strconv" "strings" "sync" + + "github.com/astaxie/beego/config" ) +var ( +//Content will only be compressed if content length is either unknown or greater than minGzipSize. + gzipMinLength int +//Default size==20B like nginx + defaultGzipMinLength=20 +//The compression level used for deflate compression. (0-9). + gzipCompressLevel int +//List of HTTP methods to compress. If not set, only GET requests are compressed. + includedMethods map[string]bool + getMethodOnly bool +) + +func InitGzip(cf config.Configer) { + gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) + gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.DefaultCompression) + if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { + gzipCompressLevel = flate.BestSpeed + } + methods := cf.DefaultStrings("includedMethods", []string{"GET"}) + getMethodOnly = len(methods) == 1 && strings.ToUpper(methods[0]) == "GET" + for _, v := range methods { + includedMethods[strings.ToUpper(v)] = true + } +} + type resetWriter interface { io.Writer Reset(w io.Writer) @@ -41,20 +68,20 @@ func (n nopResetWriter) Reset(w io.Writer) { } type acceptEncoder struct { - name string - levelEncode func(int) resetWriter - bestSpeedPool *sync.Pool - bestCompressionPool *sync.Pool + name string + levelEncode func(int) resetWriter + customCompressLevelPool *sync.Pool + bestCompressionPool *sync.Pool } func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { - if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { + if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { return nopResetWriter{wr} } var rwr resetWriter switch level { case flate.BestSpeed: - rwr = ac.bestSpeedPool.Get().(resetWriter) + rwr = ac.customCompressLevelPool.Get().(resetWriter) case flate.BestCompression: rwr = ac.bestCompressionPool.Get().(resetWriter) default: @@ -65,13 +92,16 @@ func (ac acceptEncoder) encode(wr io.Writer, level int) resetWriter { } func (ac acceptEncoder) put(wr resetWriter, level int) { - if ac.bestSpeedPool == nil || ac.bestCompressionPool == nil { + if ac.customCompressLevelPool == nil || ac.bestCompressionPool == nil { return } wr.Reset(nil) + //notice + //compressionLevel==BestCompression DOES NOT MATTER + //sync.Pool will not memory leak switch level { - case flate.BestSpeed: - ac.bestSpeedPool.Put(wr) + case gzipCompressLevel: + ac.customCompressLevelPool.Put(wr) case flate.BestCompression: ac.bestCompressionPool.Put(wr) } @@ -79,28 +109,22 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { var ( noneCompressEncoder = acceptEncoder{"", nil, nil, nil} - gzipCompressEncoder = acceptEncoder{"gzip", - func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, - &sync.Pool{ - New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestSpeed); return wr }, - }, - &sync.Pool{ - New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }, - }, + gzipCompressEncoder = acceptEncoder{ + name: "gzip", + levelEncode: func(level int) resetWriter { wr, _ := gzip.NewWriterLevel(nil, level); return wr }, + customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, gzipCompressLevel); return wr }}, + bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, } - //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed - //deflate - //The "zlib" format defined in RFC 1950 [31] in combination with - //the "deflate" compression mechanism described in RFC 1951 [29]. - deflateCompressEncoder = acceptEncoder{"deflate", - func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, - &sync.Pool{ - New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestSpeed); return wr }, - }, - &sync.Pool{ - New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }, - }, +//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed +//deflate +//The "zlib" format defined in RFC 1950 [31] in combination with +//the "deflate" compression mechanism described in RFC 1951 [29]. + deflateCompressEncoder = acceptEncoder{ + name: "deflate", + levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, + customCompressLevelPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, gzipCompressLevel); return wr }}, + bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := zlib.NewWriterLevel(nil, flate.BestCompression); return wr }}, } ) @@ -120,7 +144,11 @@ func WriteFile(encoding string, writer io.Writer, file *os.File) (bool, string, // WriteBody reads writes content to writer by the specific encoding(gzip/deflate) func WriteBody(encoding string, writer io.Writer, content []byte) (bool, string, error) { - return writeLevel(encoding, writer, bytes.NewReader(content), flate.BestSpeed) + if encoding == "" || len(content) < gzipMinLength { + _, err := writer.Write(content) + return false, "", err + } + return writeLevel(encoding, writer, bytes.NewReader(content), gzipCompressLevel) } // writeLevel reads from reader,writes to writer by specific encoding and compress level @@ -156,7 +184,10 @@ func ParseEncoding(r *http.Request) string { if r == nil { return "" } - return parseEncoding(r) + if (getMethodOnly && r.Method == "GET") || includedMethods[r.Method] { + return parseEncoding(r) + } + return "" } type q struct { From 5a9bff2000701fd565027c184cfa010c7c820592 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:09:38 +0800 Subject: [PATCH 10/28] init gzip level --- beego.go | 8 +++++--- hooks.go | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/beego.go b/beego.go index 8f82cdcf..89e4f671 100644 --- a/beego.go +++ b/beego.go @@ -22,12 +22,12 @@ import ( ) const ( - // VERSION represent beego web framework version. +// VERSION represent beego web framework version. VERSION = "1.6.1" - // DEV is for develop +// DEV is for develop DEV = "dev" - // PROD is for production +// PROD is for production PROD = "prod" ) @@ -51,6 +51,7 @@ func AddAPPStartHook(hf hookfunc) { // beego.Run(":8089") // beego.Run("127.0.0.1:8089") func Run(params ...string) { + initBeforeHTTPRun() if len(params) > 0 && params[0] != "" { @@ -74,6 +75,7 @@ func initBeforeHTTPRun() { AddAPPStartHook(registerDocs) AddAPPStartHook(registerTemplate) AddAPPStartHook(registerAdmin) + AddAPPStartHook(registerGzip) for _, hk := range hooks { if err := hk(); err != nil { diff --git a/hooks.go b/hooks.go index 59b10b32..1a7937b5 100644 --- a/hooks.go +++ b/hooks.go @@ -6,6 +6,7 @@ import ( "net/http" "path/filepath" + "github.com/astaxie/beego/context" "github.com/astaxie/beego/session" ) @@ -91,3 +92,10 @@ func registerAdmin() error { } return nil } + +func registerGzip() error { + if BConfig.EnableGzip { + context.InitGzip(AppConfig) + } + return nil +} From 35e34261abd45205becb700e302c7a5972c98fa1 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:40:29 +0800 Subject: [PATCH 11/28] gzip method support --- context/acceptencoder.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 2e5af83a..21ede1a5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -30,13 +30,13 @@ import ( ) var ( -//Content will only be compressed if content length is either unknown or greater than minGzipSize. + //Content will only be compressed if content length is either unknown or greater than minGzipSize. gzipMinLength int -//Default size==20B like nginx - defaultGzipMinLength=20 -//The compression level used for deflate compression. (0-9). + //Default size==20B like nginx + defaultGzipMinLength = 20 + //The compression level used for deflate compression. (0-9). gzipCompressLevel int -//List of HTTP methods to compress. If not set, only GET requests are compressed. + //List of HTTP methods to compress. If not set, only GET requests are compressed. includedMethods map[string]bool getMethodOnly bool ) @@ -96,9 +96,11 @@ func (ac acceptEncoder) put(wr resetWriter, level int) { return } wr.Reset(nil) + //notice //compressionLevel==BestCompression DOES NOT MATTER //sync.Pool will not memory leak + switch level { case gzipCompressLevel: ac.customCompressLevelPool.Put(wr) @@ -116,10 +118,10 @@ var ( bestCompressionPool: &sync.Pool{New: func() interface{} { wr, _ := gzip.NewWriterLevel(nil, flate.BestCompression); return wr }}, } -//according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed -//deflate -//The "zlib" format defined in RFC 1950 [31] in combination with -//the "deflate" compression mechanism described in RFC 1951 [29]. + //according to the sec :http://tools.ietf.org/html/rfc2616#section-3.5 ,the deflate compress in http is zlib indeed + //deflate + //The "zlib" format defined in RFC 1950 [31] in combination with + //the "deflate" compression mechanism described in RFC 1951 [29]. deflateCompressEncoder = acceptEncoder{ name: "deflate", levelEncode: func(level int) resetWriter { wr, _ := zlib.NewWriterLevel(nil, level); return wr }, From 57eace07a79f80aaeab7b0d06058a8e81ee05af3 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:52:09 +0800 Subject: [PATCH 12/28] comment update --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 21ede1a5..bc67bb5e 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -30,7 +30,7 @@ import ( ) var ( - //Content will only be compressed if content length is either unknown or greater than minGzipSize. + //Content will only be compressed if content length is either unknown or greater than gzipMinLength. gzipMinLength int //Default size==20B like nginx defaultGzipMinLength = 20 From 0b401481ef1c9abc920996d6cbe67818970984bf Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 19:59:48 +0800 Subject: [PATCH 13/28] go fmt the comment --- beego.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beego.go b/beego.go index 89e4f671..65dd79cb 100644 --- a/beego.go +++ b/beego.go @@ -22,12 +22,12 @@ import ( ) const ( -// VERSION represent beego web framework version. + // VERSION represent beego web framework version. VERSION = "1.6.1" -// DEV is for develop + // DEV is for develop DEV = "dev" -// PROD is for production + // PROD is for production PROD = "prod" ) From 9f21928a90e6782e92cfc26462d66223557b680d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Thu, 17 Mar 2016 20:07:24 +0800 Subject: [PATCH 14/28] some typo fixed --- context/acceptencoder.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index bc67bb5e..bc048e77 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -32,7 +32,7 @@ import ( var ( //Content will only be compressed if content length is either unknown or greater than gzipMinLength. gzipMinLength int - //Default size==20B like nginx + //Default size==20B same as nginx defaultGzipMinLength = 20 //The compression level used for deflate compression. (0-9). gzipCompressLevel int @@ -43,7 +43,7 @@ var ( func InitGzip(cf config.Configer) { gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) - gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.DefaultCompression) + gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.BestSpeed) if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } From a3d4218d9df28355dcfd0b1042e8dfae4615d97c Mon Sep 17 00:00:00 2001 From: miraclesu Date: Thu, 17 Mar 2016 21:34:49 +0800 Subject: [PATCH 15/28] orm: fix miss pk when pk is negative --- orm/db.go | 8 ++++---- orm/db_utils.go | 4 ++-- orm/models_fields.go | 8 ++++---- orm/orm.go | 2 +- orm/orm_object.go | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/orm/db.go b/orm/db.go index 314c3535..9ff84411 100644 --- a/orm/db.go +++ b/orm/db.go @@ -181,7 +181,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val } default: switch { - case fi.fieldType&IsPostiveIntegerField > 0: + case fi.fieldType&IsPositiveIntegerField > 0: if field.Kind() == reflect.Ptr { if field.IsNil() { value = nil @@ -516,7 +516,7 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time. } if num > 0 { if mi.fields.pk.auto { - if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(0) } else { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(0) @@ -1140,7 +1140,7 @@ setValue: tErr = err goto end } - if fieldType&IsPostiveIntegerField > 0 { + if fieldType&IsPositiveIntegerField > 0 { v, _ := str.Uint64() value = v } else { @@ -1292,7 +1292,7 @@ setValue: field.Set(reflect.ValueOf(&v)) } case fieldType&IsIntegerField > 0: - if fieldType&IsPostiveIntegerField > 0 { + if fieldType&IsPositiveIntegerField > 0 { if isNative { if value == nil { value = uint64(0) diff --git a/orm/db_utils.go b/orm/db_utils.go index c97caf36..ff36b286 100644 --- a/orm/db_utils.go +++ b/orm/db_utils.go @@ -33,13 +33,13 @@ func getExistPk(mi *modelInfo, ind reflect.Value) (column string, value interfac fi := mi.fields.pk v := ind.FieldByIndex(fi.fieldIndex) - if fi.fieldType&IsPostiveIntegerField > 0 { + if fi.fieldType&IsPositiveIntegerField > 0 { vu := v.Uint() exist = vu > 0 value = vu } else if fi.fieldType&IsIntegerField > 0 { vu := v.Int() - exist = vu > 0 + exist = true value = vu } else { vu := v.String() diff --git a/orm/models_fields.go b/orm/models_fields.go index a8cf8e4f..ad1fb6f9 100644 --- a/orm/models_fields.go +++ b/orm/models_fields.go @@ -46,10 +46,10 @@ const ( // Define some logic enum const ( - IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 - IsPostiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 - IsRelField = ^-RelReverseMany >> 14 << 15 - IsFieldType = ^-RelReverseMany<<1 + 1 + IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 + IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 + IsRelField = ^-RelReverseMany >> 14 << 15 + IsFieldType = ^-RelReverseMany<<1 + 1 ) // BooleanField A true/false field. diff --git a/orm/orm.go b/orm/orm.go index 0ffb6b86..38c89334 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -159,7 +159,7 @@ func (o *orm) Insert(md interface{}) (int64, error) { // set auto pk field func (o *orm) setPk(mi *modelInfo, ind reflect.Value, id int64) { if mi.fields.pk.auto { - if mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetUint(uint64(id)) } else { ind.FieldByIndex(mi.fields.pk.fieldIndex).SetInt(id) diff --git a/orm/orm_object.go b/orm/orm_object.go index 8a5d85e2..de3181ce 100644 --- a/orm/orm_object.go +++ b/orm/orm_object.go @@ -50,7 +50,7 @@ func (o *insertSet) Insert(md interface{}) (int64, error) { } if id > 0 { if o.mi.fields.pk.auto { - if o.mi.fields.pk.fieldType&IsPostiveIntegerField > 0 { + if o.mi.fields.pk.fieldType&IsPositiveIntegerField > 0 { ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetUint(uint64(id)) } else { ind.FieldByIndex(o.mi.fields.pk.fieldIndex).SetInt(id) From 4caf044be2e7b18d52a6c525c7d5d209ed7d987a Mon Sep 17 00:00:00 2001 From: JessonChan Date: Fri, 18 Mar 2016 15:18:00 +0800 Subject: [PATCH 16/28] getMethodOnly assign fixed --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index bc048e77..e73744f5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -48,7 +48,7 @@ func InitGzip(cf config.Configer) { gzipCompressLevel = flate.BestSpeed } methods := cf.DefaultStrings("includedMethods", []string{"GET"}) - getMethodOnly = len(methods) == 1 && strings.ToUpper(methods[0]) == "GET" + getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") for _, v := range methods { includedMethods[strings.ToUpper(v)] = true } From 84ae930c6490b1aa9b62ae7a6591ab859c6f150f Mon Sep 17 00:00:00 2001 From: miraclesu Date: Fri, 18 Mar 2016 21:58:11 +0800 Subject: [PATCH 17/28] orm: Add test case for integer pk --- orm/models_test.go | 5 +++++ orm/orm_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/orm/models_test.go b/orm/models_test.go index 4c8d32f8..b6ae21cf 100644 --- a/orm/models_test.go +++ b/orm/models_test.go @@ -387,6 +387,11 @@ func NewInLineOneToOne() *InLineOneToOne { return new(InLineOneToOne) } +type IntegerPk struct { + Id int64 `orm:"pk"` + Value string +} + var DBARGS = struct { Driver string Source string diff --git a/orm/orm_test.go b/orm/orm_test.go index 181106bb..832c7301 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -19,6 +19,7 @@ import ( "database/sql" "fmt" "io/ioutil" + "math" "os" "path/filepath" "reflect" @@ -189,6 +190,7 @@ func TestSyncDb(t *testing.T) { RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) + RegisterModel(new(IntegerPk)) err := RunSyncdb("default", true, Debug) throwFail(t, err) @@ -210,6 +212,7 @@ func TestRegisterModels(t *testing.T) { RegisterModel(new(GroupPermissions)) RegisterModel(new(InLine)) RegisterModel(new(InLineOneToOne)) + RegisterModel(new(IntegerPk)) BootStrap() @@ -1991,3 +1994,22 @@ func TestInLineOneToOne(t *testing.T) { throwFail(t, AssertIs(rinline.Name, name)) throwFail(t, AssertIs(rinline.Email, email)) } + +func TestIntegerPk(t *testing.T) { + its := []IntegerPk{ + {Id: math.MinInt64, Value: "-"}, + {Id: 0, Value: "0"}, + {Id: math.MaxInt64, Value: "+"}, + } + + num, err := dORM.InsertMulti(len(its), its) + throwFail(t, err) + throwFail(t, AssertIs(num, len(its))) + + for _, intPk := range its { + out := IntegerPk{Id: intPk.Id} + err = dORM.Read(&out) + throwFail(t, err) + throwFail(t, AssertIs(out.Value, intPk.Value)) + } +} From 33ae75b25197ee6f678b07a7d8970985c2e39510 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 08:50:56 +0800 Subject: [PATCH 18/28] golint check only works on Go 1.5 --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c821dcd..fbcb8a24 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ before_install: - cd ssdb - make - cd .. + - '[[ $(go version) == *1.[5-9]* ]] && go get github.com/golang/lint/golint' install: - go get github.com/lib/pq - go get github.com/go-sql-driver/mysql @@ -32,7 +33,6 @@ install: - go get github.com/siddontang/ledisdb/config - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - - go get github.com/golang/lint/golint - go get github.com/ssdb/gossdb/ssdb before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -45,7 +45,7 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - $HOME/gopath/bin/golint ./... + - '[[ $(go version) == *1.[5-9]* ]] && $HOME/gopath/bin/golint ./...' - go test -v ./... notifications: webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9 From 959b9a5a580e2e232b92680f640b1865bf3af24d Mon Sep 17 00:00:00 2001 From: JessonChan Date: Mon, 21 Mar 2016 09:32:41 +0800 Subject: [PATCH 19/28] config index out of range bug fixed --- config.go | 2 +- context/acceptencoder.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config.go b/config.go index 2761e7cb..15d11386 100644 --- a/config.go +++ b/config.go @@ -353,7 +353,7 @@ func (b *beegoAppConfig) String(key string) string { } func (b *beegoAppConfig) Strings(key string) []string { - if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); v[0] != "" { + if v := b.innerConfig.Strings(BConfig.RunMode + "::" + key); len(v) > 0 { return v } return b.innerConfig.Strings(key) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index e73744f5..fc2775ce 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -49,6 +49,7 @@ func InitGzip(cf config.Configer) { } methods := cf.DefaultStrings("includedMethods", []string{"GET"}) getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") + includedMethods = make(map[string]bool, len(methods)) for _, v := range methods { includedMethods[strings.ToUpper(v)] = true } From f2ed27cc8f6aabcc779009e1c670d1154df89afa Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 11:10:57 +0800 Subject: [PATCH 20/28] make sure works for travis --- .travis.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index fbcb8a24..d01dc3a9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,8 @@ language: go go: - - tip - - 1.6.0 + - 1.6 - 1.5.3 - - 1.4.3 services: - redis-server - mysql @@ -19,7 +17,6 @@ before_install: - cd ssdb - make - cd .. - - '[[ $(go version) == *1.[5-9]* ]] && go get github.com/golang/lint/golint' install: - go get github.com/lib/pq - go get github.com/go-sql-driver/mysql @@ -34,6 +31,7 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - go get github.com/ssdb/gossdb/ssdb + - go get github.com/golang/lint/golint before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" @@ -45,7 +43,5 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - '[[ $(go version) == *1.[5-9]* ]] && $HOME/gopath/bin/golint ./...' + - golint ./...' - go test -v ./... -notifications: - webhooks: https://hooks.pubu.im/services/z7m9bvybl3rgtg9 From 630f77bca34c353a713ea6c7d5a475ec41129907 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 21 Mar 2016 11:18:38 +0800 Subject: [PATCH 21/28] update travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d01dc3a9..92d9ac8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,7 @@ language: go go: - 1.6 - 1.5.3 + - 1.4.3 services: - redis-server - mysql @@ -31,11 +32,11 @@ install: - go get github.com/siddontang/ledisdb/ledis - go get golang.org/x/tools/cmd/vet - go get github.com/ssdb/gossdb/ssdb - - go get github.com/golang/lint/golint before_script: - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" - sh -c "if [ '$ORM_DRIVER' = 'mysql' ]; then mysql -u root -e 'create database orm_test;'; fi" - sh -c "if [ '$ORM_DRIVER' = 'sqlite' ]; then touch $TRAVIS_BUILD_DIR/orm_test.db; fi" + - sh -c "if [ $(go version) == *1.[5-9]* ]; then go get github.com/golang/lint/golint; golint ./...; fi" - mkdir -p res/var - ./ssdb/ssdb-server ./ssdb/ssdb.conf -d after_script: @@ -43,5 +44,4 @@ after_script: - rm -rf ./res/var/* script: - go vet -x ./... - - golint ./...' - go test -v ./... From 4db78f243e90b1eab3c4b78b6fb186ad0d18cbec Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 16:42:42 +0800 Subject: [PATCH 22/28] change the function args of init gzip method --- context/acceptencoder.go | 15 +++++++-------- hooks.go | 6 +++++- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index fc2775ce..1c3cf1d5 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -25,15 +25,13 @@ import ( "strconv" "strings" "sync" - - "github.com/astaxie/beego/config" ) var ( - //Content will only be compressed if content length is either unknown or greater than gzipMinLength. - gzipMinLength int //Default size==20B same as nginx defaultGzipMinLength = 20 + //Content will only be compressed if content length is either unknown or greater than gzipMinLength. + gzipMinLength = defaultGzipMinLength //The compression level used for deflate compression. (0-9). gzipCompressLevel int //List of HTTP methods to compress. If not set, only GET requests are compressed. @@ -41,13 +39,14 @@ var ( getMethodOnly bool ) -func InitGzip(cf config.Configer) { - gzipMinLength = cf.DefaultInt("gzipMinLength", defaultGzipMinLength) - gzipCompressLevel = cf.DefaultInt("gzipCompressLevel", flate.BestSpeed) +func InitGzip(minLength, compressLevel int, methods []string) { + if minLength >= 0 { + gzipMinLength = minLength + } + gzipCompressLevel = compressLevel if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } - methods := cf.DefaultStrings("includedMethods", []string{"GET"}) getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") includedMethods = make(map[string]bool, len(methods)) for _, v := range methods { diff --git a/hooks.go b/hooks.go index 1a7937b5..674f2858 100644 --- a/hooks.go +++ b/hooks.go @@ -95,7 +95,11 @@ func registerAdmin() error { func registerGzip() error { if BConfig.EnableGzip { - context.InitGzip(AppConfig) + context.InitGzip( + AppConfig.DefaultInt("gzipMinLength", -1), + AppConfig.DefaultInt("gzipCompressLevel", -1), + AppConfig.DefaultStrings("includedMethods", []string{"GET"}), + ) } return nil } From 7bad3d1c67f8d3da1ef12071e48e31c2d82f8095 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 16:47:11 +0800 Subject: [PATCH 23/28] change the compress leve to [0~9] --- context/acceptencoder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 1c3cf1d5..cb735445 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -44,7 +44,7 @@ func InitGzip(minLength, compressLevel int, methods []string) { gzipMinLength = minLength } gzipCompressLevel = compressLevel - if gzipCompressLevel < flate.DefaultCompression || gzipCompressLevel > flate.BestCompression { + if gzipCompressLevel < flate.NoCompression || gzipCompressLevel > flate.BestCompression { gzipCompressLevel = flate.BestSpeed } getMethodOnly = (len(methods) == 0) || (len(methods) == 1 && strings.ToUpper(methods[0]) == "GET") From b2098266a30d58acfffb4542c090eb173783828b Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:27:29 +0800 Subject: [PATCH 24/28] add error test --- context/context.go | 1 + error_test.go | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 error_test.go diff --git a/context/context.go b/context/context.go index ab3a3d3f..fee5e1c5 100644 --- a/context/context.go +++ b/context/context.go @@ -77,6 +77,7 @@ func (ctx *Context) Redirect(status int, localurl string) { // Abort stops this request. // if beego.ErrorMaps exists, panic body. func (ctx *Context) Abort(status int, body string) { + ctx.Output.SetStatus(status) panic(body) } diff --git a/error_test.go b/error_test.go new file mode 100644 index 00000000..85b6268d --- /dev/null +++ b/error_test.go @@ -0,0 +1,73 @@ +package beego + +import ( + "net/http" + "net/http/httptest" + "strconv" + "strings" + "testing" +) + +type errorTestController struct { + Controller +} + +func (ec *errorTestController) Get() { + errorCode, err := ec.GetInt("code") + if err != nil { + ec.Abort("parse code error") + } + if errorCode != 0 { + ec.CustomAbort(errorCode, ec.GetString("code")) + } + ec.Abort("404") +} + +func TestErrorCode_01(t *testing.T) { + registerDefaultErrorHandler() + for k, _ := range ErrorMaps { + r, _ := http.NewRequest("GET", "/error?code="+k, nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + code, _ := strconv.Atoi(k) + if w.Code != code { + t.Fail() + } + if !strings.Contains(string(w.Body.Bytes()), http.StatusText(code)) { + t.Fail() + } + } +} + +func TestErrorCode_02(t *testing.T) { + registerDefaultErrorHandler() + r, _ := http.NewRequest("GET", "/error?code=0", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + if w.Code != 404 { + t.Fail() + + } +} + +func TestErrorCode_03(t *testing.T) { + registerDefaultErrorHandler() + r, _ := http.NewRequest("GET", "/error?code=crash", nil) + w := httptest.NewRecorder() + + handler := NewControllerRegister() + handler.Add("/error", &errorTestController{}) + handler.ServeHTTP(w, r) + if w.Code != 200 { + t.Fail() + } + if string(w.Body.Bytes()) != "parse code error" { + t.Fail() + } +} From 1a401af23bd9f5e3e005216abbda8de8966b2846 Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:28:44 +0800 Subject: [PATCH 25/28] copyright --- error_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/error_test.go b/error_test.go index 85b6268d..713c0a45 100644 --- a/error_test.go +++ b/error_test.go @@ -1,3 +1,17 @@ +// Copyright 2016 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package beego import ( From 5858607f49000b095506a46255653f586714df5c Mon Sep 17 00:00:00 2001 From: JessonChan Date: Tue, 22 Mar 2016 18:32:14 +0800 Subject: [PATCH 26/28] go fmt error_test.go --- error_test.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/error_test.go b/error_test.go index 713c0a45..f6e40c80 100644 --- a/error_test.go +++ b/error_test.go @@ -26,10 +26,12 @@ type errorTestController struct { Controller } +const parseCodeError = "parse code error" + func (ec *errorTestController) Get() { errorCode, err := ec.GetInt("code") if err != nil { - ec.Abort("parse code error") + ec.Abort(parseCodeError) } if errorCode != 0 { ec.CustomAbort(errorCode, ec.GetString("code")) @@ -66,13 +68,12 @@ func TestErrorCode_02(t *testing.T) { handler.ServeHTTP(w, r) if w.Code != 404 { t.Fail() - } } func TestErrorCode_03(t *testing.T) { registerDefaultErrorHandler() - r, _ := http.NewRequest("GET", "/error?code=crash", nil) + r, _ := http.NewRequest("GET", "/error?code=panic", nil) w := httptest.NewRecorder() handler := NewControllerRegister() @@ -81,7 +82,7 @@ func TestErrorCode_03(t *testing.T) { if w.Code != 200 { t.Fail() } - if string(w.Body.Bytes()) != "parse code error" { + if string(w.Body.Bytes()) != parseCodeError { t.Fail() } } From b78de2b44092b5582240bef4ead42f6e7dcc6208 Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 23 Mar 2016 16:56:40 +0800 Subject: [PATCH 27/28] add ISSUE_TEMPLATE --- .github/ISSUE_TEMPLATE | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE new file mode 100644 index 00000000..b11d6e23 --- /dev/null +++ b/.github/ISSUE_TEMPLATE @@ -0,0 +1,18 @@ +Please answer these questions before submitting your issue. Thanks! + +1. What version of Go and beego are you using (`bee version`)? + + +2. What operating system and processor architecture are you using (`go env`)? + + +3. What did you do? +If possible, provide a recipe for reproducing the error. +A complete runnable program is good. +A link on play.golang.org is best. + + +4. What did you expect to see? + + +5. What did you see instead? \ No newline at end of file From 88c5dfa6ead42e624c2e7d9e04eab6cb2d07412a Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 23 Mar 2016 17:05:40 +0800 Subject: [PATCH 28/28] update issue template --- .github/ISSUE_TEMPLATE | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE index b11d6e23..db349198 100644 --- a/.github/ISSUE_TEMPLATE +++ b/.github/ISSUE_TEMPLATE @@ -9,7 +9,6 @@ Please answer these questions before submitting your issue. Thanks! 3. What did you do? If possible, provide a recipe for reproducing the error. A complete runnable program is good. -A link on play.golang.org is best. 4. What did you expect to see?