From 9366e33ffc2d89df1a5254716e1d26d0991b5a2a Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Tue, 29 Mar 2016 13:05:13 -0300 Subject: [PATCH 01/12] Implement QueryArray and PostArray methods --- context.go | 41 +++++++++++++++++++++++++++++++++++++++++ context_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/context.go b/context.go index 5db121a5..fb4fbde6 100644 --- a/context.go +++ b/context.go @@ -236,6 +236,23 @@ func (c *Context) GetQuery(key string) (string, bool) { return "", false } +// QueryArray returns a slice of strings for a given query key. +// The length of the slice depends on the number of params with the given key. +func (c *Context) QueryArray(key string) []string { + values, _ := c.GetQueryArray(key) + return values +} + +// GetQueryArray returns a slice of strings for a given query key, plus +// a boolean value whether at least one value exists for the given key. +func (c *Context) GetQueryArray(key string) ([]string, bool) { + req := c.Request + if values, ok := req.URL.Query()[key]; ok && len(values) > 0 { + return values, true + } + return []string{}, false +} + // PostForm returns the specified key from a POST urlencoded form or multipart form // when it exists, otherwise it returns an empty string `("")`. func (c *Context) PostForm(key string) string { @@ -274,6 +291,30 @@ func (c *Context) GetPostForm(key string) (string, bool) { return "", false } +// PostFormArray returns a slice of strings for a given form key. +// The length of the slice depends on the number of params with the given key. +func (c *Context) PostFormArray(key string) []string { + values, _ := c.GetPostFormArray(key) + return values +} + +// GetPostFormArray returns a slice of strings for a given form key, plus +// a boolean value whether at least one value exists for the given key. +func (c *Context) GetPostFormArray(key string) ([]string, bool) { + req := c.Request + req.ParseForm() + req.ParseMultipartForm(32 << 20) // 32 MB + if values := req.PostForm[key]; len(values) > 0 { + return values, true + } + if req.MultipartForm != nil && req.MultipartForm.File != nil { + if values := req.MultipartForm.Value[key]; len(values) > 0 { + return values, true + } + } + return []string{}, false +} + // Bind checks the Content-Type to select a binding engine automatically, // Depending the "Content-Type" header different bindings are used: // "application/json" --> JSON binding diff --git a/context_test.go b/context_test.go index 322c4829..3d0d9d38 100644 --- a/context_test.go +++ b/context_test.go @@ -251,6 +251,22 @@ func TestContextQueryAndPostForm(t *testing.T) { assert.Equal(t, obj.Page, 11) assert.Equal(t, obj.Both, "") assert.Equal(t, obj.Array, []string{"first", "second"}) + + values, ok := c.GetQueryArray("array[]") + assert.True(t, ok) + assert.Equal(t, "first", values[0]) + assert.Equal(t, "second", values[1]) + + values = c.QueryArray("array[]") + assert.Equal(t, "first", values[0]) + assert.Equal(t, "second", values[1]) + + values = c.QueryArray("nokey") + assert.Equal(t, 0, len(values)) + + values = c.QueryArray("both") + assert.Equal(t, 1, len(values)) + assert.Equal(t, "GET", values[0]) } func TestContextPostFormMultipart(t *testing.T) { @@ -299,6 +315,22 @@ func TestContextPostFormMultipart(t *testing.T) { assert.False(t, ok) assert.Empty(t, value) assert.Equal(t, c.DefaultPostForm("nokey", "nothing"), "nothing") + + values, ok := c.GetPostFormArray("array") + assert.True(t, ok) + assert.Equal(t, "first", values[0]) + assert.Equal(t, "second", values[1]) + + values = c.PostFormArray("array") + assert.Equal(t, "first", values[0]) + assert.Equal(t, "second", values[1]) + + values = c.PostFormArray("nokey") + assert.Equal(t, 0, len(values)) + + values = c.PostFormArray("foo") + assert.Equal(t, 1, len(values)) + assert.Equal(t, "bar", values[0]) } func TestContextSetCookie(t *testing.T) { From f3ff8f827ca3cb44aca5db8515d4dd4d530d50af Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Tue, 29 Mar 2016 21:54:21 -0300 Subject: [PATCH 02/12] Refactor GetQuery and GetPostForm --- context.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/context.go b/context.go index fb4fbde6..406afd9a 100644 --- a/context.go +++ b/context.go @@ -229,9 +229,8 @@ func (c *Context) DefaultQuery(key, defaultValue string) string { // ("", false) == c.GetQuery("id") // ("", true) == c.GetQuery("lastname") func (c *Context) GetQuery(key string) (string, bool) { - req := c.Request - if values, ok := req.URL.Query()[key]; ok && len(values) > 0 { - return values[0], true + if values, ok := c.GetQueryArray(key); ok { + return values[0], ok } return "", false } @@ -278,15 +277,8 @@ func (c *Context) DefaultPostForm(key, defaultValue string) string { // email= --> ("", true) := GetPostForm("email") // set email to "" // --> ("", false) := GetPostForm("email") // do nothing with email func (c *Context) GetPostForm(key string) (string, bool) { - req := c.Request - req.ParseMultipartForm(32 << 20) // 32 MB - if values := req.PostForm[key]; len(values) > 0 { - return values[0], true - } - if req.MultipartForm != nil && req.MultipartForm.File != nil { - if values := req.MultipartForm.Value[key]; len(values) > 0 { - return values[0], true - } + if values, ok := c.GetPostFormArray(key); ok { + return values[0], ok } return "", false } From 15fc943ba4604d757a56698432c59fa06b1437c0 Mon Sep 17 00:00:00 2001 From: ABHISHEK SONI Date: Thu, 29 Sep 2016 19:32:27 +0530 Subject: [PATCH 03/12] Removed additional Iota I think assigning iota to each constant is not required --- mode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mode.go b/mode.go index f44b071d..c600b7b5 100644 --- a/mode.go +++ b/mode.go @@ -20,8 +20,8 @@ const ( ) const ( debugCode = iota - releaseCode = iota - testCode = iota + releaseCode + testCode ) // DefaultWriter is the default io.Writer used the Gin for debug output and From 7ec7df8b93bb50b786ba07b3ee04f44c1e1086e2 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Wed, 12 Oct 2016 22:23:43 +0800 Subject: [PATCH 04/12] Add 1.7 test. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 2f78c8af..cfa47af0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ go: - 1.4 - 1.5 - 1.6 + - 1.7 - tip script: From eadf4da8f6d6d86b2be26ebd43a0a6ab080de458 Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Wed, 19 Oct 2016 11:22:08 +0200 Subject: [PATCH 05/12] Add codecov.io --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index cfa47af0..46cbbf52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ script: after_success: - goveralls -coverprofile=coverage.out -service=travis-ci -repotoken yFj7FrCeddvBzUaaCyG33jCLfWXeb93eA + - bash <(curl -s https://codecov.io/bash) notifications: webhooks: From 5c3c9c4f8c7fe0621c251444cba5949b035c3c31 Mon Sep 17 00:00:00 2001 From: mehdy Date: Fri, 28 Oct 2016 17:32:10 +0330 Subject: [PATCH 06/12] corrected a typo in README --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8023dc5a..5ec78f81 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ func main() { "message": "pong", }) }) - r.Run() // listen and server on 0.0.0.0:8080 + r.Run() // listen and serve on 0.0.0.0:8080 } ``` @@ -317,7 +317,7 @@ func main() { testing.GET("/analytics", analyticsEndpoint) } - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` @@ -367,7 +367,7 @@ func main() { } }) - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } ``` @@ -447,7 +447,7 @@ func main() { c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK}) }) - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` @@ -461,7 +461,7 @@ func main() { router.StaticFS("/more_static", http.Dir("my_file_system")) router.StaticFile("/favicon.ico", "./resources/favicon.ico") - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 router.Run(":8080") } ``` @@ -593,7 +593,7 @@ func main() { log.Println(example) }) - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` @@ -631,7 +631,7 @@ func main() { } }) - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` @@ -664,7 +664,7 @@ func main() { log.Println("Done! in path " + c.Request.URL.Path) }) - // Listen and server on 0.0.0.0:8080 + // Listen and serve on 0.0.0.0:8080 r.Run(":8080") } ``` From 504b119742a7cb3325244eece973fc9572dc239a Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Fri, 28 Oct 2016 23:14:06 +0800 Subject: [PATCH 07/12] remove coveralls services. Signed-off-by: Bo-Yi Wu --- .travis.yml | 3 --- README.md | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 46cbbf52..ca28c109 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,12 +8,9 @@ go: - tip script: - - go get golang.org/x/tools/cmd/cover - - go get github.com/mattn/goveralls - go test -v -covermode=count -coverprofile=coverage.out after_success: - - goveralls -coverprofile=coverage.out -service=travis-ci -repotoken yFj7FrCeddvBzUaaCyG33jCLfWXeb93eA - bash <(curl -s https://codecov.io/bash) notifications: diff --git a/README.md b/README.md index 5ec78f81..f47559b9 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,15 @@ #Gin Web Framework + [![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin) -[![Coverage Status](https://coveralls.io/repos/gin-gonic/gin/badge.svg?branch=master)](https://coveralls.io/r/gin-gonic/gin?branch=master) +[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin) [![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin) [![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin) [![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Gin is a web framework written in Go (Golang). It features a martini-like API with much better performance, up to 40 times faster thanks to [httprouter](https://github.com/julienschmidt/httprouter). If you need performance and good productivity, you will love Gin. - - ![Gin console logger](https://gin-gonic.github.io/gin/other/console.png) ```sh From 9d9fd0885934692825039492fac6183202f29dd3 Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Fri, 28 Oct 2016 21:31:58 +0200 Subject: [PATCH 08/12] Update TravisCI to Gitter webhook --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ca28c109..33051749 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ after_success: notifications: webhooks: urls: - - https://webhooks.gitter.im/e/acc2c57482e94b44f557 + - https://webhooks.gitter.im/e/7f95bf605c4d356372f4 on_success: change # options: [always|never|change] default: always on_failure: always # options: [always|never|change] default: always on_start: false # default: false From 3ad4c714a76ab83e3cc71fb6e532fb9c0e6e2d5a Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Fri, 28 Oct 2016 21:41:18 +0200 Subject: [PATCH 09/12] Add codecov.yml Gitter webhook --- codecov.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..c9c9a522 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,5 @@ +coverage: + notify: + gitter: + default: + url: https://webhooks.gitter.im/e/d90dcdeeab2f1e357165 From 9177f01c2843b91820780197f521ba48554b9df3 Mon Sep 17 00:00:00 2001 From: Pablo Moncada Date: Tue, 8 Nov 2016 18:38:28 +0100 Subject: [PATCH 10/12] Changed imports to gopkg instead of github in README (#733) * Add contribution guide * Update go get for stable version In the future, github default branch will be develop so running `go get github.com/gin-gonic/gin` will pull latest code from develop. * Changed imports to gopkg instead of github in README * Update README.md --- README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f47559b9..82ea6a58 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ $ cat test.go ```go package main -import "github.com/gin-gonic/gin" +import "gopkg.in/gin-gonic/gin.v1" func main() { r := gin.Default() @@ -87,13 +87,13 @@ BenchmarkZeus_GithubAll | 2000 | 944234 | 300688 | 2648 1. Download and install it: ```sh - $ go get github.com/gin-gonic/gin + $ go get gopkg.in/gin-gonic/gin.v1 ``` 2. Import it in your code: ```go - import "github.com/gin-gonic/gin" + import "gopkg.in/gin-gonic/gin.v1" ``` 3. (Optional) Import `net/http`. This is required for example if using constants such as `http.StatusOK`. @@ -377,8 +377,7 @@ func main() { package main import ( - "github.com/gin-gonic/gin" - "github.com/gin-gonic/gin/binding" + "gopkg.in/gin-gonic/gin.v1" ) type LoginForm struct { @@ -713,6 +712,19 @@ An alternative to endless: * [manners](https://github.com/braintree/manners): A polite Go HTTP server that shuts down gracefully. +## Contributing + +- With issues: + - Use the search tool before opening a new issue. + - Please provide source code and commit sha if you found a bug. + - Review existing issues and provide feedback or react to them. +- With pull requests: + - Open your pull request against develop + - Your pull request should have no more than two commits, if not you should squash them. + - It should pass all tests in the available continuous integrations systems such as TravisCI. + - You should add/modify tests to cover your proposed code changes. + - If your pull request contains a new feature, please document it on the README. + ## Example Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. From 70ada0c7b6a05d50e8508428d49a1274046d57a8 Mon Sep 17 00:00:00 2001 From: David Irvine Date: Thu, 17 Nov 2016 16:31:00 -0500 Subject: [PATCH 11/12] Logger: skip ANSI color commands if output is not a tty --- logger.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/logger.go b/logger.go index d56bc628..b4743a7f 100644 --- a/logger.go +++ b/logger.go @@ -7,7 +7,10 @@ package gin import ( "fmt" "io" + "os" "time" + + "golang.org/x/crypto/ssh/terminal" ) var ( @@ -44,6 +47,11 @@ func Logger() HandlerFunc { // LoggerWithWriter instance a Logger middleware with the specified writter buffer. // Example: os.Stdout, a file opened in write mode, a socket... func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { + isTerm := true + if outFile, ok := out.(*os.File); ok { + isTerm = terminal.IsTerminal(int(outFile.Fd())) + } + var skip map[string]struct{} if length := len(notlogged); length > 0 { @@ -71,8 +79,11 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { clientIP := c.ClientIP() method := c.Request.Method statusCode := c.Writer.Status() - statusColor := colorForStatus(statusCode) - methodColor := colorForMethod(method) + var statusColor, methodColor string + if isTerm { + statusColor = colorForStatus(statusCode) + methodColor = colorForMethod(method) + } comment := c.Errors.ByType(ErrorTypePrivate).String() fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s %s %-7s %s\n%s", From 19f271c86ba04f2d56d342c20a3f1b16fe785c23 Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Sat, 3 Dec 2016 22:03:39 +0100 Subject: [PATCH 12/12] Revert "Merge pull request #744 from aviddiviner/logger-fix" This reverts commit c3bfd69303d0fdaf2d43a7ff07cc8ee45ec7bb3f, reversing changes made to 9177f01c2843b91820780197f521ba48554b9df3. --- logger.go | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/logger.go b/logger.go index b4743a7f..d56bc628 100644 --- a/logger.go +++ b/logger.go @@ -7,10 +7,7 @@ package gin import ( "fmt" "io" - "os" "time" - - "golang.org/x/crypto/ssh/terminal" ) var ( @@ -47,11 +44,6 @@ func Logger() HandlerFunc { // LoggerWithWriter instance a Logger middleware with the specified writter buffer. // Example: os.Stdout, a file opened in write mode, a socket... func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { - isTerm := true - if outFile, ok := out.(*os.File); ok { - isTerm = terminal.IsTerminal(int(outFile.Fd())) - } - var skip map[string]struct{} if length := len(notlogged); length > 0 { @@ -79,11 +71,8 @@ func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc { clientIP := c.ClientIP() method := c.Request.Method statusCode := c.Writer.Status() - var statusColor, methodColor string - if isTerm { - statusColor = colorForStatus(statusCode) - methodColor = colorForMethod(method) - } + statusColor := colorForStatus(statusCode) + methodColor := colorForMethod(method) comment := c.Errors.ByType(ErrorTypePrivate).String() fmt.Fprintf(out, "[GIN] %v |%s %3d %s| %13v | %s |%s %s %-7s %s\n%s",