From bca2b1493873bcaa7964b55dc9a31a8680aacf84 Mon Sep 17 00:00:00 2001 From: Jeevanandam M Date: Sun, 22 Jul 2018 00:50:16 -0700 Subject: [PATCH 1/2] code optimize and cleanup --- aah.go | 15 ++++---- access_log.go | 2 +- bind.go | 2 +- dump.go | 2 +- error.go | 3 +- event.go | 2 +- http_engine.go | 19 +++------- http_engine_test.go | 87 ++++++++++++++++++++------------------------- render.go | 36 +++++-------------- render_test.go | 2 +- reply.go | 7 ++-- router.go | 19 +++++----- security.go | 4 +-- util.go | 2 +- view.go | 5 ++- 15 files changed, 81 insertions(+), 126 deletions(-) diff --git a/aah.go b/aah.go index 92d65f71..ce052ee6 100644 --- a/aah.go +++ b/aah.go @@ -54,7 +54,6 @@ type BuildInfo struct { func newApp() *app { aahApp := &app{ vfs: new(vfs.VFS), - mu: new(sync.Mutex), } aahApp.he = &HTTPEngine{ @@ -70,7 +69,7 @@ func newApp() *app { aahApp.eventStore = &EventStore{ a: aahApp, subscribers: make(map[string]EventCallbacks), - mu: new(sync.Mutex), + mu: sync.RWMutex{}, } return aahApp @@ -90,6 +89,7 @@ type app struct { initialized bool hotReload bool authSchemeExists bool + redirect bool pid int httpMaxHdrBytes int importPath string @@ -128,8 +128,6 @@ type app struct { logger log.Loggerer accessLog *accessLogger dumpLog *dumpLogger - - mu *sync.Mutex } func (a *app) Init(importPath string) error { @@ -283,8 +281,6 @@ func (a *app) Profile() string { } func (a *app) SetProfile(profile string) error { - a.mu.Lock() - defer a.mu.Unlock() if err := a.Config().SetProfile(profilePrefix + profile); err != nil { return err } @@ -335,8 +331,6 @@ func (a *app) NewChildLogger(fields log.Fields) log.Loggerer { } func (a *app) SetTLSConfig(tlsCfg *tls.Config) { - a.mu.Lock() - defer a.mu.Unlock() a.tlsCfg = tlsCfg } @@ -434,6 +428,8 @@ func (a *app) initConfigValues() (err error) { return err } + a.redirect = cfg.BoolDefault("server.redirect.enable", false) + readTimeout := cfg.StringDefault("server.timeout.read", "90s") writeTimeout := cfg.StringDefault("server.timeout.write", "90s") if !isValidTimeUnit(readTimeout, "s", "m") || !isValidTimeUnit(writeTimeout, "s", "m") { @@ -589,7 +585,8 @@ func (a *app) aahRecover() { // ServeHTTP method implementation of http.Handler interface. func (a *app) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer a.aahRecover() - if a.he.doRedirect(w, r) { + if a.redirect { + a.he.doRedirect(w, r) return } diff --git a/access_log.go b/access_log.go index b9b453b4..cd50a7ec 100644 --- a/access_log.go +++ b/access_log.go @@ -228,7 +228,7 @@ func (al *accessLog) GetResponseHdr(hdrKey string) string { func (al *accessLog) GetQueryString() string { queryStr := al.Request.URL().Query().Encode() - if ess.IsStrEmpty(queryStr) { + if len(queryStr) == 0 { return "-" } return `"` + queryStr + `"` diff --git a/bind.go b/bind.go index 150ed973..8c883cf1 100644 --- a/bind.go +++ b/bind.go @@ -100,7 +100,7 @@ func BindMiddleware(ctx *Context, m *Middleware) { // Note: Query parameter takes precedence of all. if locale := firstNonZeroString( ctx.Req.QueryValue(ctx.a.bindMgr.keyQueryParamName), - ctx.Req.PathValue(ctx.a.bindMgr.keyPathParamName)); !ess.IsStrEmpty(locale) { + ctx.Req.PathValue(ctx.a.bindMgr.keyPathParamName)); len(locale) > 0 { ctx.Req.SetLocale(ahttp.NewLocale(locale)) } } diff --git a/dump.go b/dump.go index 949efc01..a25e288a 100644 --- a/dump.go +++ b/dump.go @@ -77,7 +77,7 @@ func (d *dumpLogger) Dump(ctx *Context) { // Request uri := fmt.Sprintf("%s://%s%s", ctx.Req.Scheme, ctx.Req.Host, ctx.Req.Path) - if qs := ctx.Req.URL().RawQuery; !ess.IsStrEmpty(qs) { + if qs := ctx.Req.URL().RawQuery; len(qs) > 0 { uri += "?" + qs } diff --git a/error.go b/error.go index 19b40892..b2dd9f01 100644 --- a/error.go +++ b/error.go @@ -11,7 +11,6 @@ import ( "net/http" "aahframework.org/ahttp.v0" - "aahframework.org/essentials.v0" ) // aah errors @@ -161,7 +160,7 @@ func (er *errorManager) Handle(ctx *Context) { // in the aah. It writes the response based on HTTP Content-Type. func (er *errorManager) DefaultHandler(ctx *Context, err *Error) bool { ct := ctx.Reply().ContType - if ess.IsStrEmpty(ct) { + if len(ct) == 0 { ct = ctx.detectContentType().Mime if ctx.a.viewMgr == nil && ct == ahttp.ContentTypeHTML.Mime { ct = ahttp.ContentTypePlainText.Mime diff --git a/event.go b/event.go index 5f5ce124..7a496668 100644 --- a/event.go +++ b/event.go @@ -177,7 +177,7 @@ func (a *app) EventStore() *EventStore { // EventStore type holds all the events belongs to aah application. type EventStore struct { a *app - mu *sync.Mutex + mu sync.RWMutex subscribers map[string]EventCallbacks } diff --git a/http_engine.go b/http_engine.go index c267bb85..11070a9a 100644 --- a/http_engine.go +++ b/http_engine.go @@ -14,7 +14,6 @@ import ( "aahframework.org/ahttp.v0" "aahframework.org/ainsp.v0" "aahframework.org/aruntime.v0" - "aahframework.org/essentials.v0" "aahframework.org/log.v0" "aahframework.org/security.v0" "aahframework.org/security.v0/authc" @@ -73,14 +72,14 @@ func (e *HTTPEngine) Handle(w http.ResponseWriter, r *http.Request) { ctx := e.ctxPool.Get().(*Context) defer e.releaseContext(ctx) - ctx.Req, ctx.Res = ahttp.AcquireRequest(r), ahttp.AcquireResponseWriter(w) - ctx.Set(reqStartTimeKey, time.Now()) - // Record access log if e.a.accessLogEnabled { + ctx.Set(reqStartTimeKey, time.Now()) defer e.a.accessLog.Log(ctx) } + ctx.Req, ctx.Res = ahttp.AcquireRequest(r), ahttp.AcquireResponseWriter(w) + // Recovery handling defer e.handleRecovery(ctx) @@ -319,7 +318,7 @@ func (e *HTTPEngine) writeReply(ctx *Context) { } // Check ContentType and detect it if need be - if ess.IsStrEmpty(re.ContType) { + if len(re.ContType) == 0 { re.ContentType(ctx.detectContentType().String()) } ctx.Res.Header().Set(ahttp.HeaderContentType, re.ContType) @@ -433,12 +432,8 @@ const ( nonwww = "non-www" ) -func (e *HTTPEngine) doRedirect(w http.ResponseWriter, r *http.Request) bool { +func (e *HTTPEngine) doRedirect(w http.ResponseWriter, r *http.Request) { cfg := e.a.Config() - if !cfg.BoolDefault("server.redirect.enable", false) { - return false - } - redirectTo := cfg.StringDefault("server.redirect.to", nonwww) redirectCode := cfg.IntDefault("server.redirect.code", http.StatusMovedPermanently) host := ahttp.Host(r) @@ -447,14 +442,10 @@ func (e *HTTPEngine) doRedirect(w http.ResponseWriter, r *http.Request) bool { case www: if host[:3] != www { http.Redirect(w, r, ahttp.Scheme(r)+"://www."+host+r.URL.RequestURI(), redirectCode) - return true } case nonwww: if host[:3] == www { http.Redirect(w, r, ahttp.Scheme(r)+"://"+host[4:]+r.URL.RequestURI(), redirectCode) - return true } } - - return false } diff --git a/http_engine_test.go b/http_engine_test.go index 3fe18452..7d4842e6 100644 --- a/http_engine_test.go +++ b/http_engine_test.go @@ -164,7 +164,7 @@ func TestHTTPEngineTestRequests(t *testing.T) { assert.Nil(t, err) assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, "application/json; charset=utf-8", resp.Header.Get(ahttp.HeaderContentType)) - assert.Equal(t, "134", resp.Header.Get(ahttp.HeaderContentLength)) + assert.Equal(t, "135", resp.Header.Get(ahttp.HeaderContentLength)) assert.True(t, strings.HasPrefix(responseBody(resp), `)]}',`)) // GET Binary bytes - /binary-bytes @@ -221,7 +221,6 @@ func TestHTTPEngineTestRequests(t *testing.T) { func TestServerRedirect(t *testing.T) { a := newApp() a.cfg = config.NewEmpty() - a.he.doRedirect(nil, nil) // www redirect t.Log("www redirect") @@ -236,11 +235,10 @@ func TestServerRedirect(t *testing.T) { `) type redirectTestCase struct { - label string - fromURL string - didItHappen bool - status int - location string + label string + fromURL string + status int + location string } runtestcase := func(testcases []redirectTestCase) { @@ -248,8 +246,7 @@ func TestServerRedirect(t *testing.T) { t.Run(tc.label, func(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(ahttp.MethodGet, tc.fromURL, nil) - didItHappen := a.he.doRedirect(w, r) - assert.Equal(t, tc.didItHappen, didItHappen) + a.he.doRedirect(w, r) assert.Equal(t, tc.status, w.Code) assert.Equal(t, tc.location, w.Header().Get(ahttp.HeaderLocation)) }) @@ -258,32 +255,28 @@ func TestServerRedirect(t *testing.T) { testcases := []redirectTestCase{ { - label: "www domain", - fromURL: "http://aahframework.org/home.html?rt=login", - didItHappen: true, - status: http.StatusTemporaryRedirect, - location: "http://www.aahframework.org/home.html?rt=login", + label: "www domain", + fromURL: "http://aahframework.org/home.html?rt=login", + status: http.StatusTemporaryRedirect, + location: "http://www.aahframework.org/home.html?rt=login", }, { - label: "www subdomain", - fromURL: "http://docs.aahframework.org", - didItHappen: true, - status: http.StatusTemporaryRedirect, - location: "http://www.docs.aahframework.org/", + label: "www subdomain", + fromURL: "http://docs.aahframework.org", + status: http.StatusTemporaryRedirect, + location: "http://www.docs.aahframework.org/", }, { - label: "www domain already correct", - fromURL: "http://www.aahframework.org", - didItHappen: false, - status: http.StatusOK, - location: "", + label: "www domain already correct", + fromURL: "http://www.aahframework.org", + status: http.StatusOK, + location: "", }, { - label: "www subdomain already correct", - fromURL: "http://www.docs.aahframework.org", - didItHappen: false, - status: http.StatusOK, - location: "", + label: "www subdomain already correct", + fromURL: "http://www.docs.aahframework.org", + status: http.StatusOK, + location: "", }, } @@ -301,32 +294,28 @@ func TestServerRedirect(t *testing.T) { testcases = []redirectTestCase{ { - label: "non-www domain", - fromURL: "http://www.aahframework.org/home.html?rt=login", - didItHappen: true, - status: http.StatusMovedPermanently, - location: "http://aahframework.org/home.html?rt=login", + label: "non-www domain", + fromURL: "http://www.aahframework.org/home.html?rt=login", + status: http.StatusMovedPermanently, + location: "http://aahframework.org/home.html?rt=login", }, { - label: "non-www subdomain", - fromURL: "http://www.docs.aahframework.org", - didItHappen: true, - status: http.StatusMovedPermanently, - location: "http://docs.aahframework.org/", + label: "non-www subdomain", + fromURL: "http://www.docs.aahframework.org", + status: http.StatusMovedPermanently, + location: "http://docs.aahframework.org/", }, { - label: "non-www domain already correct", - fromURL: "http://aahframework.org", - didItHappen: false, - status: http.StatusOK, - location: "", + label: "non-www domain already correct", + fromURL: "http://aahframework.org", + status: http.StatusOK, + location: "", }, { - label: "non-www subdomain already correct", - fromURL: "http://docs.aahframework.org", - didItHappen: false, - status: http.StatusOK, - location: "", + label: "non-www subdomain already correct", + fromURL: "http://docs.aahframework.org", + status: http.StatusOK, + location: "", }, } diff --git a/render.go b/render.go index 57ff3db4..4804a5f3 100644 --- a/render.go +++ b/render.go @@ -1,5 +1,5 @@ // Copyright (c) Jeevanandam M. (https://github.com/jeevatkm) -// go-aah/aah source code and usage is governed by a MIT style +// aahframework.org/aah source code and usage is governed by a MIT style // license that can be found in the LICENSE file. package aah @@ -83,13 +83,7 @@ type jsonRender struct { // Render method writes JSON into HTTP response. func (j jsonRender) Render(w io.Writer) error { - jsonBytes, err := JSONMarshal(j.Data) - if err != nil { - return err - } - - _, err = w.Write(jsonBytes) - return err + return json.NewEncoder(w).Encode(j.Data) } //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ @@ -104,12 +98,12 @@ type jsonpRender struct { // Render method writes JSONP into HTTP response. func (j jsonpRender) Render(w io.Writer) error { - jsonBytes, err := JSONMarshal(j.Data) + jsonBytes, err := json.Marshal(j.Data) if err != nil { return err } - if ess.IsStrEmpty(j.Callback) { + if len(j.Callback) == 0 { _, err = w.Write(jsonBytes) } else { _, err = fmt.Fprintf(w, "%s(%s);", j.Callback, jsonBytes) @@ -128,17 +122,10 @@ type secureJSONRender struct { } func (s secureJSONRender) Render(w io.Writer) error { - jsonBytes, err := JSONMarshal(s.Data) - if err != nil { - return err - } - - if _, err = w.Write([]byte(s.Prefix)); err != nil { + if _, err := w.Write([]byte(s.Prefix)); err != nil { return err } - - _, err = w.Write(jsonBytes) - return err + return json.NewEncoder(w).Encode(s.Data) } //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ @@ -152,17 +139,10 @@ type xmlRender struct { // Render method writes XML into HTTP response. func (x xmlRender) Render(w io.Writer) error { - xmlBytes, err := xml.Marshal(x.Data) - if err != nil { - return err - } - - if _, err = w.Write(xmlHeaderBytes); err != nil { + if _, err := w.Write(xmlHeaderBytes); err != nil { return err } - - _, err = w.Write(xmlBytes) - return err + return xml.NewEncoder(w).Encode(x.Data) } //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ diff --git a/render_test.go b/render_test.go index 889c2342..00ee8693 100644 --- a/render_test.go +++ b/render_test.go @@ -50,7 +50,7 @@ func TestRenderJSON(t *testing.T) { err := json1.Render(buf) assert.FailOnError(t, err, "") assert.Equal(t, `{"Name":"John","Age":28,"Address":"this is my street"}`, - buf.String()) + strings.TrimSpace(buf.String())) } func TestRenderFailureXML(t *testing.T) { diff --git a/reply.go b/reply.go index 9efb1214..3813e222 100644 --- a/reply.go +++ b/reply.go @@ -13,7 +13,6 @@ import ( "sync" "aahframework.org/ahttp.v0" - "aahframework.org/essentials.v0" ) var ( @@ -144,7 +143,7 @@ func (r *Reply) ServiceUnavailable() *Reply { // By default aah framework try to determine response 'Content-Type' from // 'ahttp.Request.AcceptContentType()'. func (r *Reply) ContentType(contentType string) *Reply { - if ess.IsStrEmpty(r.ContType) { + if len(r.ContType) == 0 { r.ContType = strings.ToLower(contentType) } return r @@ -320,7 +319,7 @@ func (r *Reply) Render(rdr Render) *Reply { // // Note: It overwrites existing header value if it's present. func (r *Reply) Header(key, value string) *Reply { - if ess.IsStrEmpty(value) { + if len(value) == 0 { if key == ahttp.HeaderContentType { return r.ContentType("") } @@ -380,7 +379,7 @@ func (r *Reply) DisableGzip() *Reply { // IsContentTypeSet method returns true if Content-Type is set otherwise // false. func (r *Reply) IsContentTypeSet() bool { - return !ess.IsStrEmpty(r.ContType) + return len(r.ContType) > 0 } // Body method returns the response body buffer. diff --git a/router.go b/router.go index 3cc46966..a2256f23 100644 --- a/router.go +++ b/router.go @@ -13,7 +13,6 @@ import ( "strings" "aahframework.org/ahttp.v0" - "aahframework.org/essentials.v0" "aahframework.org/log.v0" "aahframework.org/router.v0" "aahframework.org/valpar.v0" @@ -118,7 +117,7 @@ func handleCORSPreflight(ctx *Context) { ctx.Reply().Header(ahttp.HeaderAccessControlAllowCredentials, "true") } - if !ess.IsStrEmpty(cors.MaxAge) { + if len(cors.MaxAge) > 0 { ctx.Reply().Header(ahttp.HeaderAccessControlMaxAge, cors.MaxAge) } @@ -198,17 +197,19 @@ func handleRoute(ctx *Context) flowResult { } // Apply route constraints - if errs := valpar.ValidateValues(ctx.Req.PathParams, ctx.route.Constraints); len(errs) > 0 { - ctx.Log().Errorf("Route constraints failed: %s", errs) - ctx.Reply().BadRequest().Error(newErrorWithData(router.ErrRouteConstraintFailed, http.StatusBadRequest, errs)) - return flowAbort + if len(ctx.route.Constraints) > 0 { + if errs := valpar.ValidateValues(ctx.Req.PathParams, ctx.route.Constraints); len(errs) > 0 { + ctx.Log().Errorf("Route constraints failed: %s", errs) + ctx.Reply().BadRequest().Error(newErrorWithData(router.ErrRouteConstraintFailed, http.StatusBadRequest, errs)) + return flowAbort + } } return flowCont } func appendAnchorLink(routePath, anchorLink string) string { - if ess.IsStrEmpty(anchorLink) { + if len(anchorLink) == 0 { return routePath } return routePath + "#" + anchorLink @@ -225,7 +226,7 @@ func getRouteNameAndAnchorLink(routeName string) (string, string) { } func composeRouteURL(domain *router.Domain, routePath, anchorLink string) string { - if ess.IsStrEmpty(domain.Port) { + if len(domain.Port) == 0 { routePath = fmt.Sprintf("//%s%s", domain.Host, routePath) } else { routePath = fmt.Sprintf("//%s:%s%s", domain.Host, domain.Port, routePath) @@ -327,7 +328,7 @@ func handleRtsOptionsMna(ctx *Context, domain *router.Domain, rts bool) error { } func processAllowedMethods(reply *Reply, allowed, prefix string) bool { - if !ess.IsStrEmpty(allowed) { + if len(allowed) > 0 { allowed += ", " + ahttp.MethodOptions reply.Header(ahttp.HeaderAllow, allowed) reply.ctx.Log().Debugf("%sAllowed HTTP Methods: %s", prefix, allowed) diff --git a/security.go b/security.go index ccb68ec5..f69219e0 100644 --- a/security.go +++ b/security.go @@ -161,7 +161,7 @@ func doFormAuth(authScheme scheme.Schemer, ctx *Context) flowResult { ctx.e.publishOnPostAuthEvent(ctx) rt := ctx.Req.FormValue("_rt") // redirect to requested URL - if formAuth.IsAlwaysToDefaultTarget || ess.IsStrEmpty(rt) { + if formAuth.IsAlwaysToDefaultTarget || len(rt) == 0 { ctx.Reply().Redirect(formAuth.DefaultTargetURL) } else { ctx.Log().Debugf("Redirecting to URL found in param '_rt': %s", rt) @@ -375,7 +375,7 @@ func AntiCSRFMiddleware(ctx *Context, m *Middleware) { return } - if ess.IsStrEmpty(referer.String()) { + if len(referer.String()) == 0 { ctx.Log().Warnf("anticsrf: No referer %s", ctx.Req.Referer) ctx.Reply().Forbidden().Error(newError(anticsrf.ErrNoReferer, http.StatusForbidden)) return diff --git a/util.go b/util.go index d93c2359..fa90b11c 100644 --- a/util.go +++ b/util.go @@ -229,7 +229,7 @@ func reason2String(reasons []*authz.Reason) string { // addQueryString method adds the given query string key value pair appropriately func addQueryString(u, k, v string) string { - if ess.IsStrEmpty(u) { + if len(u) == 0 { return "?" + k + "=" + v } if idx := strings.IndexByte(u, '?'); idx == -1 { diff --git a/view.go b/view.go index d3fe6806..e47a5fc6 100644 --- a/view.go +++ b/view.go @@ -12,7 +12,6 @@ import ( "strings" "aahframework.org/ahttp.v0" - "aahframework.org/essentials.v0" "aahframework.org/security.v0" "aahframework.org/view.v0" ) @@ -151,7 +150,7 @@ func (vm *viewManager) resolve(ctx *Context) { return } - if ess.IsStrEmpty(htmlRdr.Layout) && vm.defaultLayoutEnabled { + if len(htmlRdr.Layout) == 0 && vm.defaultLayoutEnabled { htmlRdr.Layout = vm.defaultTmplLayout } @@ -172,7 +171,7 @@ func (vm *viewManager) resolve(ctx *Context) { var tmplPath, tmplName string // If user not provided the template info, auto resolve by convention - if ess.IsStrEmpty(htmlRdr.Filename) { + if len(htmlRdr.Filename) == 0 { tmplName = ctx.action.Name + vm.fileExt tmplPath = filepath.Join(ctx.controller.Namespace, ctx.controller.NoSuffixName) } else { From c8d9a4f71bbe865d197e0baf25357d9dc1e6b386 Mon Sep 17 00:00:00 2001 From: Jeevanandam M Date: Sun, 22 Jul 2018 01:38:40 -0700 Subject: [PATCH 2/2] version bump and readme update for v0.11.1 --- README.md | 4 ++-- version.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 04811672..b83f450a 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,12 @@

Visit aah's official website https://aahframework.org to learn more

-

Build Status Code Coverage Go Report Card Release Version Godoc Docker Pulls Twitter @aahframework

+

Build Status Code Coverage Go Report Card Release Version Godoc Docker Pulls Twitter @aahframework

### News - * `v0.11.0` [released](https://docs.aahframework.org/release-notes.html) and tagged on Jul 06, 2018. + * `v0.11.1` [released](https://docs.aahframework.org/release-notes.html) and tagged on Jul 22, 2018. ### Stargazers over time diff --git a/version.go b/version.go index b6034610..471e9ced 100644 --- a/version.go +++ b/version.go @@ -5,4 +5,4 @@ package aah // Version no. of aah framework -const Version = "0.11.0" +const Version = "0.11.1"