From 6f94fd05c98d1043e329398f6f742dc680be9b29 Mon Sep 17 00:00:00 2001 From: Boris Borshevsky Date: Wed, 29 Nov 2017 04:50:14 +0200 Subject: [PATCH 01/12] Linting and optimizing struct memory signature. (#1184) * fix cleanPath spell (#969) * linter and optimize structs --- README.md | 2 +- benchmarks_test.go | 2 -- binding/form_mapping.go | 9 --------- errors.go | 2 +- examples/custom-validation/server.go | 2 +- examples/realtime-advanced/stats.go | 4 ++-- gin.go | 21 +++++++++++---------- gin_integration_test.go | 2 +- mode.go | 6 +++--- tree.go | 14 +++++++------- tree_test.go | 11 ----------- 11 files changed, 27 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 7d3b9194..3ac051a4 100644 --- a/README.md +++ b/README.md @@ -540,7 +540,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" - validator "gopkg.in/go-playground/validator.v8" + "gopkg.in/go-playground/validator.v8" ) type Booking struct { diff --git a/benchmarks_test.go b/benchmarks_test.go index a2c62ba3..e7970034 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -59,8 +59,6 @@ func BenchmarkOneRouteJSON(B *testing.B) { runRequest(B, router, "GET", "/json") } -var htmlContentType = []string{"text/html; charset=utf-8"} - func BenchmarkOneRouteHTML(B *testing.B) { router := New() t := template.Must(template.New("index").Parse(` diff --git a/binding/form_mapping.go b/binding/form_mapping.go index c968dc08..dd8c6246 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -179,12 +179,3 @@ func setTimeField(val string, structField reflect.StructField, value reflect.Val value.Set(reflect.ValueOf(t)) return nil } - -// Don't pass in pointers to bind to. Can lead to bugs. See: -// https://github.com/codegangsta/martini-contrib/issues/40 -// https://github.com/codegangsta/martini-contrib/pull/34#issuecomment-29683659 -func ensureNotPointer(obj interface{}) { - if reflect.TypeOf(obj).Kind() == reflect.Ptr { - panic("Pointers are not accepted as binding models") - } -} diff --git a/errors.go b/errors.go index 6f3c9868..dbfccd85 100644 --- a/errors.go +++ b/errors.go @@ -148,7 +148,7 @@ func (a errorMsgs) String() string { } var buffer bytes.Buffer for i, msg := range a { - fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err) + fmt.Fprintf(&buffer, "Error #%02d: %s\n", i+1, msg.Err) if msg.Meta != nil { fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta) } diff --git a/examples/custom-validation/server.go b/examples/custom-validation/server.go index 0b67ce10..31d449f0 100644 --- a/examples/custom-validation/server.go +++ b/examples/custom-validation/server.go @@ -7,7 +7,7 @@ import ( "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" - validator "gopkg.in/go-playground/validator.v8" + "gopkg.in/go-playground/validator.v8" ) type Booking struct { diff --git a/examples/realtime-advanced/stats.go b/examples/realtime-advanced/stats.go index 4bca3ae4..4afedcb5 100644 --- a/examples/realtime-advanced/stats.go +++ b/examples/realtime-advanced/stats.go @@ -29,8 +29,8 @@ func statsWorker() { "timestamp": uint64(time.Now().Unix()), "HeapInuse": stats.HeapInuse, "StackInuse": stats.StackInuse, - "Mallocs": (stats.Mallocs - lastMallocs), - "Frees": (stats.Frees - lastFrees), + "Mallocs": stats.Mallocs - lastMallocs, + "Frees": stats.Frees - lastFrees, "Inbound": uint64(messages.Get("inbound")), "Outbound": uint64(messages.Get("outbound")), "Connected": connectedUsers(), diff --git a/gin.go b/gin.go index b59712bf..edcb9193 100644 --- a/gin.go +++ b/gin.go @@ -49,16 +49,6 @@ type RoutesInfo []RouteInfo // Create an instance of Engine, by using New() or Default() type Engine struct { RouterGroup - delims render.Delims - secureJsonPrefix string - HTMLRender render.HTMLRender - FuncMap template.FuncMap - allNoRoute HandlersChain - allNoMethod HandlersChain - noRoute HandlersChain - noMethod HandlersChain - pool sync.Pool - trees methodTrees // Enables automatic redirection if the current route can't be matched but a // handler for the path with (without) the trailing slash exists. @@ -102,6 +92,17 @@ type Engine struct { // Value of 'maxMemory' param that is given to http.Request's ParseMultipartForm // method call. MaxMultipartMemory int64 + + delims render.Delims + secureJsonPrefix string + HTMLRender render.HTMLRender + FuncMap template.FuncMap + allNoRoute HandlersChain + allNoMethod HandlersChain + noRoute HandlersChain + noMethod HandlersChain + pool sync.Pool + trees methodTrees } var _ IRouter = &Engine{} diff --git a/gin_integration_test.go b/gin_integration_test.go index f45dd6c1..52f78842 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -94,7 +94,7 @@ func TestUnixSocket(t *testing.T) { c, err := net.Dial("unix", "/tmp/unix_unit_test") assert.NoError(t, err) - fmt.Fprintf(c, "GET /example HTTP/1.0\r\n\r\n") + fmt.Fprint(c, "GET /example HTTP/1.0\r\n\r\n") scanner := bufio.NewScanner(c) var response string for scanner.Scan() { diff --git a/mode.go b/mode.go index 394bebee..9c4f0246 100644 --- a/mode.go +++ b/mode.go @@ -14,9 +14,9 @@ import ( const ENV_GIN_MODE = "GIN_MODE" const ( - DebugMode string = "debug" - ReleaseMode string = "release" - TestMode string = "test" + DebugMode = "debug" + ReleaseMode = "release" + TestMode = "test" ) const ( debugCode = iota diff --git a/tree.go b/tree.go index f67edd5d..20e3704b 100644 --- a/tree.go +++ b/tree.go @@ -87,13 +87,13 @@ const ( type node struct { path string - wildChild bool - nType nodeType - maxParams uint8 indices string children []*node handlers HandlersChain priority uint32 + nType nodeType + maxParams uint8 + wildChild bool } // increments priority of the given child and reorders if necessary. @@ -384,7 +384,7 @@ walk: // Outer loop for walking the tree // Nothing found. // We can recommend to redirect to the same URL without a // trailing slash if a leaf exists for that path. - tsr = (path == "/" && n.handlers != nil) + tsr = path == "/" && n.handlers != nil return } @@ -424,7 +424,7 @@ walk: // Outer loop for walking the tree } // ... but we can't - tsr = (len(path) == end+1) + tsr = len(path) == end+1 return } @@ -435,7 +435,7 @@ walk: // Outer loop for walking the tree // No handle found. Check if a handle for this path + a // trailing slash exists for TSR recommendation n = n.children[0] - tsr = (n.path == "/" && n.handlers != nil) + tsr = n.path == "/" && n.handlers != nil } return @@ -530,7 +530,7 @@ func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPa // Nothing found. We can recommend to redirect to the same URL // without a trailing slash if a leaf exists for that path - found = (fixTrailingSlash && path == "/" && n.handlers != nil) + found = fixTrailingSlash && path == "/" && n.handlers != nil return } diff --git a/tree_test.go b/tree_test.go index c0edd42b..5bc27171 100644 --- a/tree_test.go +++ b/tree_test.go @@ -5,22 +5,11 @@ package gin import ( - "fmt" "reflect" "strings" "testing" ) -func printChildren(n *node, prefix string) { - fmt.Printf(" %02d:%02d %s%s[%d] %v %t %d \r\n", n.priority, n.maxParams, prefix, n.path, len(n.children), n.handlers, n.wildChild, n.nType) - for l := len(n.path); l > 0; l-- { - prefix += " " - } - for _, child := range n.children { - printChildren(child, prefix) - } -} - // Used as a workaround since we can't compare functions or their addressses var fakeHandlerValue string From 9e895470ddd40a45f28dbe4e96bfb5e893d54f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Wed, 29 Nov 2017 16:42:51 +0800 Subject: [PATCH 02/12] add deprecated test case (#1176) * add deprecated test case * swap assert param * remove --- context_test.go | 25 +++++++++++++++++++++++++ deprecated_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 deprecated_test.go diff --git a/context_test.go b/context_test.go index 932d9b1d..9024cfc1 100644 --- a/context_test.go +++ b/context_test.go @@ -676,6 +676,7 @@ func TestContextRenderNoContentSecureJSON(t *testing.T) { func TestContextRenderHTML(t *testing.T) { w := httptest.NewRecorder() c, router := CreateTestContext(w) + templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) router.SetHTMLTemplate(templ) @@ -686,6 +687,30 @@ func TestContextRenderHTML(t *testing.T) { assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) } +func TestContextRenderHTML2(t *testing.T) { + w := httptest.NewRecorder() + c, router := CreateTestContext(w) + + // print debug warning log when Engine.trees > 0 + router.addRoute("GET", "/", HandlersChain{func(_ *Context) {}}) + assert.Len(t, router.trees, 1) + + var b bytes.Buffer + setup(&b) + defer teardown() + + templ := template.Must(template.New("t").Parse(`Hello {{.name}}`)) + router.SetHTMLTemplate(templ) + + assert.Equal(t, "[GIN-debug] [WARNING] Since SetHTMLTemplate() is NOT thread-safe. It should only be called\nat initialization. ie. before any route is registered or the router is listening in a socket:\n\n\trouter := gin.Default()\n\trouter.SetHTMLTemplate(template) // << good place\n\n", b.String()) + + c.HTML(201, "t", H{"name": "alexandernyquist"}) + + assert.Equal(t, 201, w.Code) + assert.Equal(t, "Hello alexandernyquist", w.Body.String()) + assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) +} + // Tests that no HTML is rendered if code is 204 func TestContextRenderNoContentHTML(t *testing.T) { w := httptest.NewRecorder() diff --git a/deprecated_test.go b/deprecated_test.go new file mode 100644 index 00000000..7a875fe4 --- /dev/null +++ b/deprecated_test.go @@ -0,0 +1,31 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package gin + +import ( + "bytes" + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin/binding" + "github.com/stretchr/testify/assert" +) + +func TestBindWith(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest("POST", "/?foo=bar&bar=foo", bytes.NewBufferString("foo=unused")) + + var obj struct { + Foo string `form:"foo"` + Bar string `form:"bar"` + } + assert.NoError(t, c.BindWith(&obj, binding.Form)) + assert.Equal(t, "foo", obj.Bar) + assert.Equal(t, "bar", obj.Foo) + assert.Equal(t, 0, w.Body.Len()) +} From 13a40fcd2c2807e872768b725d1abe32ecd4712f Mon Sep 17 00:00:00 2001 From: Max Hilbrunner Date: Sat, 16 Dec 2017 17:52:07 +0100 Subject: [PATCH 03/12] README: Small update to clarify on Goroutines (#1199) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ac051a4..046752f4 100644 --- a/README.md +++ b/README.md @@ -1071,7 +1071,7 @@ func main() { ### Goroutines inside a middleware -When starting inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. +When starting new Goroutines inside a middleware or handler, you **SHOULD NOT** use the original context inside it, you have to use a read-only copy. ```go func main() { From 25e7cd75ed51f2e3ef2315e836fe8100608a3c47 Mon Sep 17 00:00:00 2001 From: TaeJun Park Date: Sun, 17 Dec 2017 09:05:30 +0900 Subject: [PATCH 04/12] Update README.md (#1188) change path from '~/go/...' to '$GOPATH/...' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 046752f4..3e1af556 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ $ go get github.com/kardianos/govendor 2. Create your project folder and `cd` inside ```sh -$ mkdir -p ~/go/src/github.com/myusername/project && cd "$_" +$ mkdir -p $GOPATH/src/github.com/myusername/project && cd "$_" ``` 3. Vendor init your project and add gin From b70b8ab20c6f15732226fbd536e28f138629a046 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 17 Dec 2017 13:02:33 +0800 Subject: [PATCH 05/12] use lower if the struct is private (#1185) --- auth.go | 12 ++++++------ auth_test.go | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/auth.go b/auth.go index 302a4fad..c2143091 100644 --- a/auth.go +++ b/auth.go @@ -17,8 +17,8 @@ const AuthUserKey = "user" type Accounts map[string]string type authPair struct { - Value string - User string + value string + user string } type authPairs []authPair @@ -28,8 +28,8 @@ func (a authPairs) searchCredential(authValue string) (string, bool) { return "", false } for _, pair := range a { - if pair.Value == authValue { - return pair.User, true + if pair.value == authValue { + return pair.user, true } } return "", false @@ -74,8 +74,8 @@ func processAccounts(accounts Accounts) authPairs { assert1(user != "", "User can not be empty") value := authorizationHeader(user, password) pairs = append(pairs, authPair{ - Value: value, - User: user, + value: value, + user: user, }) } return pairs diff --git a/auth_test.go b/auth_test.go index 2f1ae70e..dc8523b0 100644 --- a/auth_test.go +++ b/auth_test.go @@ -22,16 +22,16 @@ func TestBasicAuth(t *testing.T) { assert.Len(t, pairs, 3) assert.Contains(t, pairs, authPair{ - User: "bar", - Value: "Basic YmFyOmZvbw==", + user: "bar", + value: "Basic YmFyOmZvbw==", }) assert.Contains(t, pairs, authPair{ - User: "foo", - Value: "Basic Zm9vOmJhcg==", + user: "foo", + value: "Basic Zm9vOmJhcg==", }) assert.Contains(t, pairs, authPair{ - User: "admin", - Value: "Basic YWRtaW46cGFzc3dvcmQ=", + user: "admin", + value: "Basic YWRtaW46cGFzc3dvcmQ=", }) } From 46662e700bd20289503475770dbf0384e43398eb Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Wed, 20 Dec 2017 07:02:39 +0530 Subject: [PATCH 06/12] Doc: Fix typo in documentation of Bind (#1204) --- context.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/context.go b/context.go index 1ed65fed..90d4c6e5 100644 --- a/context.go +++ b/context.go @@ -449,10 +449,10 @@ func (c *Context) SaveUploadedFile(file *multipart.FileHeader, dst string) error // Depending the "Content-Type" header different bindings are used: // "application/json" --> JSON binding // "application/xml" --> XML binding -// otherwise --> returns an error +// otherwise --> returns an error. // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input. // It decodes the json payload into the struct specified as a pointer. -// It will writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. +// It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid. func (c *Context) Bind(obj interface{}) error { b := binding.Default(c.Request.Method, c.ContentType()) return c.MustBindWith(obj, b) From 05547037e47317954d30d9858ef2015607483739 Mon Sep 17 00:00:00 2001 From: Levi Olson Date: Wed, 20 Dec 2017 20:48:11 -0600 Subject: [PATCH 07/12] Minor grammatical correction in README (#1206) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e1af556..63137883 100644 --- a/README.md +++ b/README.md @@ -385,7 +385,7 @@ func main() { r := gin.New() // Global middleware - // Logger middleware will write the logs to gin.DefaultWriter even you set with GIN_MODE=release. + // Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release. // By default gin.DefaultWriter = os.Stdout r.Use(gin.Logger()) From a816f9e9dbf820d7d01e8d363539da976fb8aa40 Mon Sep 17 00:00:00 2001 From: Weilin Shi <934587911@qq.com> Date: Thu, 21 Dec 2017 11:00:17 +0800 Subject: [PATCH 08/12] Remove redundant if err != nil check (#1202) * Remove redundant if err != nil check * Return e.EncodeToken instead of create a new variable --- render/render_test.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/render/render_test.go b/render/render_test.go index e4df5b6d..35662cf3 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -111,10 +111,8 @@ func (h xmlmap) MarshalXML(e *xml.Encoder, start xml.StartElement) error { return err } } - if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil { - return err - } - return nil + + return e.EncodeToken(xml.EndElement{Name: start.Name}) } func TestRenderXML(t *testing.T) { From 6626358d4fefa40ec37ca4b502c6c7d0cdea6d18 Mon Sep 17 00:00:00 2001 From: Weilin Shi <934587911@qq.com> Date: Mon, 25 Dec 2017 13:58:02 +0800 Subject: [PATCH 09/12] Fix golint warnings in utils.go (#1209) --- utils.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/utils.go b/utils.go index e909bb70..99d19af4 100644 --- a/utils.go +++ b/utils.go @@ -33,18 +33,23 @@ func Bind(val interface{}) HandlerFunc { } } +// WrapF is a helper function for wrapping http.HandlerFunc +// Returns a Gin middleware func WrapF(f http.HandlerFunc) HandlerFunc { return func(c *Context) { f(c.Writer, c.Request) } } +// WrapH is a helper function for wrapping http.Handler +// Returns a Gin middleware func WrapH(h http.Handler) HandlerFunc { return func(c *Context) { h.ServeHTTP(c.Writer, c.Request) } } +// H is a shortcup for map[string]interface{} type H map[string]interface{} // MarshalXML allows type H to be used with xml.Marshal. @@ -65,10 +70,8 @@ func (h H) MarshalXML(e *xml.Encoder, start xml.StartElement) error { return err } } - if err := e.EncodeToken(xml.EndElement{Name: start.Name}); err != nil { - return err - } - return nil + + return e.EncodeToken(xml.EndElement{Name: start.Name}) } func assert1(guard bool, text string) { From a712f77d7aaec7eb4766a663924aaa4e54d3fe70 Mon Sep 17 00:00:00 2001 From: Weilin Shi <934587911@qq.com> Date: Fri, 29 Dec 2017 17:10:28 +0800 Subject: [PATCH 10/12] Fix some golint warnings in gin.go (#1215) --- gin.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gin.go b/gin.go index edcb9193..4205eff0 100644 --- a/gin.go +++ b/gin.go @@ -160,11 +160,14 @@ func (engine *Engine) Delims(left, right string) *Engine { return engine } +// SecureJsonPrefix sets the secureJsonPrefix used in Context.SecureJSON. func (engine *Engine) SecureJsonPrefix(prefix string) *Engine { engine.secureJsonPrefix = prefix return engine } +// LoadHTMLGlob loads HTML files identified by glob pattern +// and associates the result with HTML renderer. func (engine *Engine) LoadHTMLGlob(pattern string) { left := engine.delims.Left right := engine.delims.Right @@ -179,6 +182,8 @@ func (engine *Engine) LoadHTMLGlob(pattern string) { engine.SetHTMLTemplate(templ) } +// LoadHTMLFiles loads a slice of HTML files +// and associates the result with HTML renderer. func (engine *Engine) LoadHTMLFiles(files ...string) { if IsDebugging() { engine.HTMLRender = render.HTMLDebug{Files: files, FuncMap: engine.FuncMap, Delims: engine.delims} @@ -189,6 +194,7 @@ func (engine *Engine) LoadHTMLFiles(files ...string) { engine.SetHTMLTemplate(templ) } +// SetHTMLTemplate associate a template with HTML renderer. func (engine *Engine) SetHTMLTemplate(templ *template.Template) { if len(engine.trees) > 0 { debugPrintWARNINGSetHTMLTemplate() @@ -197,6 +203,7 @@ func (engine *Engine) SetHTMLTemplate(templ *template.Template) { engine.HTMLRender = render.HTMLProduction{Template: templ.Funcs(engine.FuncMap)} } +// SetFuncMap sets the FuncMap used for template.FuncMap. func (engine *Engine) SetFuncMap(funcMap template.FuncMap) { engine.FuncMap = funcMap } From 8a6792d5162d449eb79743e372d5b651cc385561 Mon Sep 17 00:00:00 2001 From: Kevin Zhu Date: Tue, 23 Jan 2018 10:07:33 +0800 Subject: [PATCH 11/12] Fix README.md example code (#1231) r -> router --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 63137883..2ad2fc11 100644 --- a/README.md +++ b/README.md @@ -435,7 +435,7 @@ func main() { c.String(200, "pong") }) - r.Run(":8080") +    router.Run(":8080") } ``` From 7a9a290b36bb803a18874aa5c5b108be2d7eb34d Mon Sep 17 00:00:00 2001 From: MW Lim Date: Tue, 23 Jan 2018 10:36:36 +0800 Subject: [PATCH 12/12] minor typo in README.md (#1219) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ad2fc11..6e421f02 100644 --- a/README.md +++ b/README.md @@ -1190,7 +1190,7 @@ func main() { ### Run multiple service using Gin -See the [question](https://github.com/gin-gonic/gin/issues/346) and try the folling example: +See the [question](https://github.com/gin-gonic/gin/issues/346) and try the following example: [embedmd]:# (examples/multiple-service/main.go go) ```go