From 09d342abbc35e473bfbe11abaecdfe237df0630d Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Thu, 30 Aug 2018 14:22:51 +0800 Subject: [PATCH 01/34] Add golang 1.11.x testing (#1514) * Add golang 1.11.x testing * remove the latest golang testing See the issue: https://github.com/gin-gonic/gin/pull/1510 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e9101568..a93458f9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ go: - 1.8.x - 1.9.x - 1.10.x - - master + - 1.11.x git: depth: 10 From 708b76adf011840eb587d57804edf93b2ef4ba75 Mon Sep 17 00:00:00 2001 From: llgoer Date: Thu, 30 Aug 2018 14:29:26 +0800 Subject: [PATCH 02/34] Update README.md (#1509) change `ShouldBindXML` to `ShouldBindJSON` --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f66dd76..7d13cf20 100644 --- a/README.md +++ b/README.md @@ -557,7 +557,7 @@ func main() { // Example for binding JSON ({"user": "manu", "password": "123"}) router.POST("/loginJSON", func(c *gin.Context) { var json Login - if err := c.ShouldBindXML(&json); err != nil { + if err := c.ShouldBindJSON(&json); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } From 72db8acd99feab85e81ac6e2ebd16c76e0f986be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 30 Aug 2018 19:04:03 +0800 Subject: [PATCH 03/34] add internal package which includes json package (#1504) --- binding/json.go | 2 +- errors.go | 2 +- errors_test.go | 2 +- {json => internal/json}/json.go | 0 {json => internal/json}/jsoniter.go | 0 render/json.go | 2 +- render/json_17.go | 2 +- 7 files changed, 5 insertions(+), 5 deletions(-) rename {json => internal/json}/json.go (100%) rename {json => internal/json}/jsoniter.go (100%) diff --git a/binding/json.go b/binding/json.go index fea17bb2..310922c1 100644 --- a/binding/json.go +++ b/binding/json.go @@ -9,7 +9,7 @@ import ( "io" "net/http" - "github.com/gin-gonic/gin/json" + "github.com/gin-gonic/gin/internal/json" ) // EnableDecoderUseNumber is used to call the UseNumber method on the JSON diff --git a/errors.go b/errors.go index dbfccd85..6f90377e 100644 --- a/errors.go +++ b/errors.go @@ -9,7 +9,7 @@ import ( "fmt" "reflect" - "github.com/gin-gonic/gin/json" + "github.com/gin-gonic/gin/internal/json" ) type ErrorType uint64 diff --git a/errors_test.go b/errors_test.go index 0626611f..9351b578 100644 --- a/errors_test.go +++ b/errors_test.go @@ -8,7 +8,7 @@ import ( "errors" "testing" - "github.com/gin-gonic/gin/json" + "github.com/gin-gonic/gin/internal/json" "github.com/stretchr/testify/assert" ) diff --git a/json/json.go b/internal/json/json.go similarity index 100% rename from json/json.go rename to internal/json/json.go diff --git a/json/jsoniter.go b/internal/json/jsoniter.go similarity index 100% rename from json/jsoniter.go rename to internal/json/jsoniter.go diff --git a/render/json.go b/render/json.go index 4d1857f5..f6b7878e 100644 --- a/render/json.go +++ b/render/json.go @@ -10,7 +10,7 @@ import ( "html/template" "net/http" - "github.com/gin-gonic/gin/json" + "github.com/gin-gonic/gin/internal/json" ) type JSON struct { diff --git a/render/json_17.go b/render/json_17.go index df0dc145..75f7f374 100644 --- a/render/json_17.go +++ b/render/json_17.go @@ -9,7 +9,7 @@ package render import ( "net/http" - "github.com/gin-gonic/gin/json" + "github.com/gin-gonic/gin/internal/json" ) type PureJSON struct { From 7451a402bbab9dd439b09aa377f18638c7d8fd55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 30 Aug 2018 23:36:53 +0800 Subject: [PATCH 04/34] chore: update vendor version (#1520) #1491 adds some lib when upgrade json-iterator but it is not needed, and use `v1.1.5` not `1.1.5` version for json-iterator. --- vendor/vendor.json | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/vendor/vendor.json b/vendor/vendor.json index e6d038a4..86df11be 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -27,8 +27,8 @@ "path": "github.com/json-iterator/go", "revision": "1624edc4454b8682399def8740d46db5e4362ba4", "revisionTime": "2018-08-06T06:07:27Z", - "version": "1.1.5", - "versionExact": "1.1.5" + "version": "v1.1", + "versionExact": "v1.1.5" }, { "checksumSHA1": "y/A5iuvwjytQE2CqVuphQRXR2nI=", @@ -38,24 +38,6 @@ "version": "v0.0.3", "versionExact": "v0.0.3" }, - { - "checksumSHA1": "ZTcgWKWHsrX0RXYVXn5Xeb8Q0go=", - "path": "github.com/modern-go/concurrent", - "revision": "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94", - "revisionTime": "2018-03-06T01:26:44Z" - }, - { - "checksumSHA1": "qvH48wzTIV3QKSDqI0dLFtVjaDI=", - "path": "github.com/modern-go/reflect2", - "revision": "94122c33edd36123c84d5368cfb2b69df93a0ec8", - "revisionTime": "2018-07-18T01:23:57Z" - }, - { - "checksumSHA1": "LuFv4/jlrmFNnDb/5SCSEPAM9vU=", - "path": "github.com/pmezard/go-difflib/difflib", - "revision": "792786c7400a136282c1664665ae0a8db921c6c2", - "revisionTime": "2016-01-10T10:55:54Z" - }, { "checksumSHA1": "c6pbpF7eowwO59phRTpF8cQ80Z0=", "path": "github.com/stretchr/testify/assert", @@ -79,12 +61,6 @@ "revision": "d4c55e66d8c3a2f3382d264b08e3e3454a66355a", "revisionTime": "2016-10-18T08:54:36Z" }, - { - "checksumSHA1": "7Gocawl8bm27cpAILtuf21xvVD8=", - "path": "golang.org/x/sys/unix", - "revision": "1c9583448a9c3aa0f9a6a5241bf73c0bd8aafded", - "revisionTime": "2018-08-15T07:37:39Z" - }, { "checksumSHA1": "P/k5ZGf0lEBgpKgkwy++F7K1PSg=", "path": "gopkg.in/go-playground/validator.v8", From 705e1992981b974ce131303cdf415ff78114f728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sat, 1 Sep 2018 00:40:33 +0800 Subject: [PATCH 05/34] chore: update issue_implate (#1524) --- .github/ISSUE_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index de067ce0..9d49aa41 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -3,8 +3,8 @@ - Please provide source code and commit sha if you found a bug. - Review existing issues and provide feedback or react to them. +- go version: - gin version (or commit ref): -- git version: - operating system: ## Description From 500ebd9ea866c57427aeaddc31f374adedd4084b Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Fri, 31 Aug 2018 22:38:16 +0200 Subject: [PATCH 06/34] docs: add fnproject to gin's user list (#1505) --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d13cf20..a4bc4e76 100644 --- a/README.md +++ b/README.md @@ -1885,5 +1885,6 @@ func TestPingRoute(t *testing.T) { Awesome project lists using [Gin](https://github.com/gin-gonic/gin) web framework. -* [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go +* [drone](https://github.com/drone/drone): Drone is a Continuous Delivery platform built on Docker, written in Go. * [gorush](https://github.com/appleboy/gorush): A push notification server written in Go. +* [fnproject](https://github.com/fnproject/fn): The container native, cloud agnostic serverless platform. From df1e17c2f0ca7179b5acf03ce1da5c4f07c4dd7d Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Wed, 12 Sep 2018 02:13:16 +0100 Subject: [PATCH 07/34] remove debug print statements from test code (#1540) Found using https://go-critic.github.io/overview#commentedOutCode-ref --- tree_test.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tree_test.go b/tree_test.go index 5bc27171..152f6331 100644 --- a/tree_test.go +++ b/tree_test.go @@ -125,8 +125,6 @@ func TestTreeAddAndGet(t *testing.T) { tree.addRoute(route, fakeHandler(route)) } - //printChildren(tree, "") - checkRequests(t, tree, testRequests{ {"/a", false, "/a", nil}, {"/", true, "", nil}, @@ -168,8 +166,6 @@ func TestTreeWildcard(t *testing.T) { tree.addRoute(route, fakeHandler(route)) } - //printChildren(tree, "") - checkRequests(t, tree, testRequests{ {"/", false, "/", nil}, {"/cmd/test/", false, "/cmd/:tool/", Params{Param{"tool", "test"}}}, @@ -208,7 +204,6 @@ func TestUnescapeParameters(t *testing.T) { tree.addRoute(route, fakeHandler(route)) } - //printChildren(tree, "") unescape := true checkRequests(t, tree, testRequests{ {"/", false, "/", nil}, @@ -260,8 +255,6 @@ func testRoutes(t *testing.T, routes []testRoute) { t.Errorf("unexpected panic for route '%s': %v", route.path, recv) } } - - //printChildren(tree, "") } func TestTreeWildcardConflict(t *testing.T) { @@ -328,8 +321,6 @@ func TestTreeDupliatePath(t *testing.T) { } } - //printChildren(tree, "") - checkRequests(t, tree, testRequests{ {"/", false, "/", nil}, {"/doc/", false, "/doc/", nil}, @@ -444,8 +435,6 @@ func TestTreeTrailingSlashRedirect(t *testing.T) { } } - //printChildren(tree, "") - tsrRoutes := [...]string{ "/hi/", "/b", From 3f27866f806536be319b3e342001dd4e0fb81691 Mon Sep 17 00:00:00 2001 From: "Iskander (Alex) Sharipov" Date: Wed, 12 Sep 2018 14:21:26 +0100 Subject: [PATCH 08/34] simplify slice expressions: s[:] => s (#1541) Found using https://go-critic.github.io/overview#unslice-ref --- context_test.go | 2 +- gin_test.go | 20 ++++++++++---------- render/render_test.go | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/context_test.go b/context_test.go index 782f7bed..4c307080 100644 --- a/context_test.go +++ b/context_test.go @@ -978,7 +978,7 @@ func TestContextRenderProtoBuf(t *testing.T) { assert.NoError(t, err) assert.Equal(t, http.StatusCreated, w.Code) - assert.Equal(t, string(protoData[:]), w.Body.String()) + assert.Equal(t, string(protoData), w.Body.String()) assert.Equal(t, "application/x-protobuf", w.HeaderMap.Get("Content-Type")) } diff --git a/gin_test.go b/gin_test.go index b3cab715..95b9cc16 100644 --- a/gin_test.go +++ b/gin_test.go @@ -88,7 +88,7 @@ func TestLoadHTMLGlob(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -101,7 +101,7 @@ func TestLoadHTMLGlob2(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -114,7 +114,7 @@ func TestLoadHTMLGlob3(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -134,7 +134,7 @@ func TestLoadHTMLGlobUsingTLS(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -148,7 +148,7 @@ func TestLoadHTMLGlobFromFuncMap(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "Date: 2017/07/01\n", string(resp[:])) + assert.Equal(t, "Date: 2017/07/01\n", string(resp)) td() } @@ -187,7 +187,7 @@ func TestLoadHTMLFiles(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -199,7 +199,7 @@ func TestLoadHTMLFiles2(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -211,7 +211,7 @@ func TestLoadHTMLFiles3(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -230,7 +230,7 @@ func TestLoadHTMLFilesUsingTLS(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "

Hello world

", string(resp[:])) + assert.Equal(t, "

Hello world

", string(resp)) td() } @@ -243,7 +243,7 @@ func TestLoadHTMLFilesFuncMap(t *testing.T) { } resp, _ := ioutil.ReadAll(res.Body) - assert.Equal(t, "Date: 2017/07/01\n", string(resp[:])) + assert.Equal(t, "Date: 2017/07/01\n", string(resp)) td() } diff --git a/render/render_test.go b/render/render_test.go index fe9228e9..09ccc658 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -287,7 +287,7 @@ func TestRenderProtoBuf(t *testing.T) { err = (ProtoBuf{data}).Render(w) assert.NoError(t, err) - assert.Equal(t, string(protoData[:]), w.Body.String()) + assert.Equal(t, string(protoData), w.Body.String()) assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type")) } From d510595aa58c2417373d89a8d8ffa21cf58673cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sat, 15 Sep 2018 10:23:32 +0800 Subject: [PATCH 09/34] chore: add some annotations (#1544) ref: #1075 because I am not a native English, maybe have a bit problem. --- README.md | 1 + examples/basic/main.go | 6 +++--- examples/custom-validation/server.go | 1 + examples/realtime-advanced/main.go | 3 +++ examples/realtime-advanced/stats.go | 1 + ginS/gins.go | 9 ++++++++- internal/json/json.go | 10 +++++++--- internal/json/jsoniter.go | 12 ++++++++---- render/data.go | 2 ++ render/html.go | 14 +++++++++++++- render/json.go | 17 +++++++++++++++++ render/json_17.go | 3 +++ render/msgpack.go | 4 ++++ render/protobuf.go | 3 +++ render/reader.go | 3 +++ render/redirect.go | 3 +++ render/render.go | 3 +++ render/text.go | 4 ++++ render/xml.go | 3 +++ render/yaml.go | 3 +++ utils.go | 8 ++++---- 21 files changed, 97 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index a4bc4e76..9a97ec54 100644 --- a/README.md +++ b/README.md @@ -657,6 +657,7 @@ import ( "gopkg.in/go-playground/validator.v8" ) +// Booking contains binded and validated data. type Booking struct { CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` diff --git a/examples/basic/main.go b/examples/basic/main.go index 48fa7bba..1c9e0ac4 100644 --- a/examples/basic/main.go +++ b/examples/basic/main.go @@ -6,7 +6,7 @@ import ( "github.com/gin-gonic/gin" ) -var DB = make(map[string]string) +var db = make(map[string]string) func setupRouter() *gin.Engine { // Disable Console Color @@ -21,7 +21,7 @@ func setupRouter() *gin.Engine { // Get user value r.GET("/user/:name", func(c *gin.Context) { user := c.Params.ByName("name") - value, ok := DB[user] + value, ok := db[user] if ok { c.JSON(http.StatusOK, gin.H{"user": user, "value": value}) } else { @@ -50,7 +50,7 @@ func setupRouter() *gin.Engine { } if c.Bind(&json) == nil { - DB[user] = json.Value + db[user] = json.Value c.JSON(http.StatusOK, gin.H{"status": "ok"}) } }) diff --git a/examples/custom-validation/server.go b/examples/custom-validation/server.go index dea0c302..9238200b 100644 --- a/examples/custom-validation/server.go +++ b/examples/custom-validation/server.go @@ -10,6 +10,7 @@ import ( "gopkg.in/go-playground/validator.v8" ) +// Booking contains binded and validated data. type Booking struct { CheckIn time.Time `form:"check_in" binding:"required,bookabledate" time_format:"2006-01-02"` CheckOut time.Time `form:"check_out" binding:"required,gtfield=CheckIn" time_format:"2006-01-02"` diff --git a/examples/realtime-advanced/main.go b/examples/realtime-advanced/main.go index 1f3c8585..a16c58b0 100644 --- a/examples/realtime-advanced/main.go +++ b/examples/realtime-advanced/main.go @@ -13,16 +13,19 @@ func main() { StartGin() } +// ConfigRuntime sets the number of operating system threads. func ConfigRuntime() { nuCPU := runtime.NumCPU() runtime.GOMAXPROCS(nuCPU) fmt.Printf("Running with %d CPUs\n", nuCPU) } +// StartWrokers start starsWorker by goroutine. func StartWorkers() { go statsWorker() } +// StartGin starts gin web server with setting router. func StartGin() { gin.SetMode(gin.ReleaseMode) diff --git a/examples/realtime-advanced/stats.go b/examples/realtime-advanced/stats.go index 4afedcb5..a6488035 100644 --- a/examples/realtime-advanced/stats.go +++ b/examples/realtime-advanced/stats.go @@ -50,6 +50,7 @@ func connectedUsers() uint64 { return uint64(connected) } +// Stats returns savedStats data. func Stats() map[string]uint64 { mutexStats.RLock() defer mutexStats.RUnlock() diff --git a/ginS/gins.go b/ginS/gins.go index a7686f23..04cf131c 100644 --- a/ginS/gins.go +++ b/ginS/gins.go @@ -22,14 +22,17 @@ func engine() *gin.Engine { return internalEngine } +// LoadHTMLGlob is a wrapper for Engine.LoadHTMLGlob. func LoadHTMLGlob(pattern string) { engine().LoadHTMLGlob(pattern) } +// LoadHTMLFiles is a wrapper for Engine.LoadHTMLFiles. func LoadHTMLFiles(files ...string) { engine().LoadHTMLFiles(files...) } +// SetHTMLTemplate is a wrapper for Engine.SetHTMLTemplate. func SetHTMLTemplate(templ *template.Template) { engine().SetHTMLTemplate(templ) } @@ -39,7 +42,7 @@ func NoRoute(handlers ...gin.HandlerFunc) { engine().NoRoute(handlers...) } -// NoMethod sets the handlers called when... TODO +// NoMethod is a wrapper for Engine.NoMethod. func NoMethod(handlers ...gin.HandlerFunc) { engine().NoMethod(handlers...) } @@ -50,6 +53,7 @@ func Group(relativePath string, handlers ...gin.HandlerFunc) *gin.RouterGroup { return engine().Group(relativePath, handlers...) } +// Handle is a wrapper for Engine.Handle. func Handle(httpMethod, relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { return engine().Handle(httpMethod, relativePath, handlers...) } @@ -89,10 +93,12 @@ func HEAD(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { return engine().HEAD(relativePath, handlers...) } +// Any is a wrapper for Engine.Any. func Any(relativePath string, handlers ...gin.HandlerFunc) gin.IRoutes { return engine().Any(relativePath, handlers...) } +// StaticFile is a wrapper for Engine.StaticFile. func StaticFile(relativePath, filepath string) gin.IRoutes { return engine().StaticFile(relativePath, filepath) } @@ -107,6 +113,7 @@ func Static(relativePath, root string) gin.IRoutes { return engine().Static(relativePath, root) } +// StaticFS is a wrapper for Engine.StaticFS. func StaticFS(relativePath string, fs http.FileSystem) gin.IRoutes { return engine().StaticFS(relativePath, fs) } diff --git a/internal/json/json.go b/internal/json/json.go index 4f643c56..419d35f2 100644 --- a/internal/json/json.go +++ b/internal/json/json.go @@ -9,8 +9,12 @@ package json import "encoding/json" var ( - Marshal = json.Marshal + // Marshal is exported by gin/json package. + Marshal = json.Marshal + // MarshalIndent is exported by gin/json package. MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder + // NewDecoder is exported by gin/json package. + NewDecoder = json.NewDecoder + // NewEncoder is exported by gin/json package. + NewEncoder = json.NewEncoder ) diff --git a/internal/json/jsoniter.go b/internal/json/jsoniter.go index f1ed5bea..2021c53c 100644 --- a/internal/json/jsoniter.go +++ b/internal/json/jsoniter.go @@ -9,9 +9,13 @@ package json import "github.com/json-iterator/go" var ( - json = jsoniter.ConfigCompatibleWithStandardLibrary - Marshal = json.Marshal + json = jsoniter.ConfigCompatibleWithStandardLibrary + // Marshal is exported by gin/json package. + Marshal = json.Marshal + // MarshalIndent is exported by gin/json package. MarshalIndent = json.MarshalIndent - NewDecoder = json.NewDecoder - NewEncoder = json.NewEncoder + // NewDecoder is exported by gin/json package. + NewDecoder = json.NewDecoder + // NewEncoder is exported by gin/json package. + NewEncoder = json.NewEncoder ) diff --git a/render/data.go b/render/data.go index 33194913..6ba657ba 100644 --- a/render/data.go +++ b/render/data.go @@ -6,6 +6,7 @@ package render import "net/http" +// Data contains ContentType and bytes data. type Data struct { ContentType string Data []byte @@ -18,6 +19,7 @@ func (r Data) Render(w http.ResponseWriter) (err error) { return } +// WriteContentType (Data) writes custom ContentType. func (r Data) WriteContentType(w http.ResponseWriter) { writeContentType(w, []string{r.ContentType}) } diff --git a/render/html.go b/render/html.go index 1e3be65b..4d3d5812 100644 --- a/render/html.go +++ b/render/html.go @@ -9,20 +9,27 @@ import ( "net/http" ) +// Delims represents a set of Left and Right delimiters for HTML template rendering. type Delims struct { - Left string + // Left delimiter, defaults to {{. + Left string + // Right delimiter, defaults to }}. Right string } +// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug. type HTMLRender interface { + // Instance returns an HTML instance. Instance(string, interface{}) Render } +// HTMLProduction contains template reference and its delims. type HTMLProduction struct { Template *template.Template Delims Delims } +// HTMLDebug contains template delims and pattern and function with file list. type HTMLDebug struct { Files []string Glob string @@ -30,6 +37,7 @@ type HTMLDebug struct { FuncMap template.FuncMap } +// HTML contains template reference and its name with given interface object. type HTML struct { Template *template.Template Name string @@ -38,6 +46,7 @@ type HTML struct { var htmlContentType = []string{"text/html; charset=utf-8"} +// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.. func (r HTMLProduction) Instance(name string, data interface{}) Render { return HTML{ Template: r.Template, @@ -46,6 +55,7 @@ func (r HTMLProduction) Instance(name string, data interface{}) Render { } } +// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.. func (r HTMLDebug) Instance(name string, data interface{}) Render { return HTML{ Template: r.loadTemplate(), @@ -66,6 +76,7 @@ func (r HTMLDebug) loadTemplate() *template.Template { panic("the HTML debug render was created without files or glob pattern") } +// Render (HTML) executes template and writes its result with custom ContentType for response. func (r HTML) Render(w http.ResponseWriter) error { r.WriteContentType(w) @@ -75,6 +86,7 @@ func (r HTML) Render(w http.ResponseWriter) error { return r.Template.ExecuteTemplate(w, r.Name, r.Data) } +// WriteContentType (HTML) writes HTML ContentType. func (r HTML) WriteContentType(w http.ResponseWriter) { writeContentType(w, htmlContentType) } diff --git a/render/json.go b/render/json.go index f6b7878e..32d0fc42 100644 --- a/render/json.go +++ b/render/json.go @@ -13,34 +13,41 @@ import ( "github.com/gin-gonic/gin/internal/json" ) +// JSON contains the given interface object. type JSON struct { Data interface{} } +// IndentedJSON contains the given interface object. type IndentedJSON struct { Data interface{} } +// SecureJSON contains the given interface object and its prefix. type SecureJSON struct { Prefix string Data interface{} } +// JsonpJSON contains the given interface object its callback. type JsonpJSON struct { Callback string Data interface{} } +// AsciiJSON contains the given interface object. type AsciiJSON struct { Data interface{} } +// SecureJSONPrefix is a string which represents SecureJSON prefix. type SecureJSONPrefix string var jsonContentType = []string{"application/json; charset=utf-8"} var jsonpContentType = []string{"application/javascript; charset=utf-8"} var jsonAsciiContentType = []string{"application/json"} +// Render (JSON) writes data with custom ContentType. func (r JSON) Render(w http.ResponseWriter) (err error) { if err = WriteJSON(w, r.Data); err != nil { panic(err) @@ -48,10 +55,12 @@ func (r JSON) Render(w http.ResponseWriter) (err error) { return } +// WriteContentType (JSON) writes JSON ContentType. func (r JSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } +// WriteJSON marshals the given interface object and writes it with custom ContentType. func WriteJSON(w http.ResponseWriter, obj interface{}) error { writeContentType(w, jsonContentType) jsonBytes, err := json.Marshal(obj) @@ -62,6 +71,7 @@ func WriteJSON(w http.ResponseWriter, obj interface{}) error { return nil } +// Render (IndentedJSON) marshals the given interface object and writes it with custom ContentType. func (r IndentedJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.MarshalIndent(r.Data, "", " ") @@ -72,10 +82,12 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error { return nil } +// WriteContentType (IndentedJSON) writes JSON ContentType. func (r IndentedJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } +// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType. func (r SecureJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) jsonBytes, err := json.Marshal(r.Data) @@ -90,10 +102,12 @@ func (r SecureJSON) Render(w http.ResponseWriter) error { return nil } +// WriteContentType (SecureJSON) writes JSON ContentType. func (r SecureJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } +// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType. func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) @@ -115,10 +129,12 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) { return nil } +// WriteContentType (JsonpJSON) writes Javascript ContentType. func (r JsonpJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonpContentType) } +// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType. func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { r.WriteContentType(w) ret, err := json.Marshal(r.Data) @@ -139,6 +155,7 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) { return nil } +// WriteContentType (AsciiJSON) writes JSON ContentType. func (r AsciiJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonAsciiContentType) } diff --git a/render/json_17.go b/render/json_17.go index 75f7f374..208193c7 100644 --- a/render/json_17.go +++ b/render/json_17.go @@ -12,10 +12,12 @@ import ( "github.com/gin-gonic/gin/internal/json" ) +// PureJSON contains the given interface object. type PureJSON struct { Data interface{} } +// Render (PureJSON) writes custom ContentType and encodes the given interface object. func (r PureJSON) Render(w http.ResponseWriter) error { r.WriteContentType(w) encoder := json.NewEncoder(w) @@ -23,6 +25,7 @@ func (r PureJSON) Render(w http.ResponseWriter) error { return encoder.Encode(r.Data) } +// WriteContentType (PureJSON) writes custom ContentType. func (r PureJSON) WriteContentType(w http.ResponseWriter) { writeContentType(w, jsonContentType) } diff --git a/render/msgpack.go b/render/msgpack.go index b6b8aa0f..dc681fcf 100644 --- a/render/msgpack.go +++ b/render/msgpack.go @@ -10,20 +10,24 @@ import ( "github.com/ugorji/go/codec" ) +// MsgPack contains the given interface object. type MsgPack struct { Data interface{} } var msgpackContentType = []string{"application/msgpack; charset=utf-8"} +// WriteContentType (MsgPack) writes MsgPack ContentType. func (r MsgPack) WriteContentType(w http.ResponseWriter) { writeContentType(w, msgpackContentType) } +// Render (MsgPack) encodes the given interface object and writes data with custom ContentType. func (r MsgPack) Render(w http.ResponseWriter) error { return WriteMsgPack(w, r.Data) } +// WriteMsgPack writes MsgPack ContentType and encodes the given interface object. func WriteMsgPack(w http.ResponseWriter, obj interface{}) error { writeContentType(w, msgpackContentType) var mh codec.MsgpackHandle diff --git a/render/protobuf.go b/render/protobuf.go index 34f1e9b5..47895072 100644 --- a/render/protobuf.go +++ b/render/protobuf.go @@ -10,12 +10,14 @@ import ( "github.com/golang/protobuf/proto" ) +// ProtoBuf contains the given interface object. type ProtoBuf struct { Data interface{} } var protobufContentType = []string{"application/x-protobuf"} +// Render (ProtoBuf) marshals the given interface object and writes data with custom ContentType. func (r ProtoBuf) Render(w http.ResponseWriter) error { r.WriteContentType(w) @@ -28,6 +30,7 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error { return nil } +// WriteContentType (ProtoBuf) writes ProtoBuf ContentType. func (r ProtoBuf) WriteContentType(w http.ResponseWriter) { writeContentType(w, protobufContentType) } diff --git a/render/reader.go b/render/reader.go index 7a06cce4..ab60e53a 100644 --- a/render/reader.go +++ b/render/reader.go @@ -10,6 +10,7 @@ import ( "strconv" ) +// Reader contains the IO reader and its length, and custom ContentType and other headers. type Reader struct { ContentType string ContentLength int64 @@ -26,10 +27,12 @@ func (r Reader) Render(w http.ResponseWriter) (err error) { return } +// WriteContentType (Reader) writes custom ContentType. func (r Reader) WriteContentType(w http.ResponseWriter) { writeContentType(w, []string{r.ContentType}) } +// writeHeaders writes custom Header. func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) { header := w.Header() for k, v := range headers { diff --git a/render/redirect.go b/render/redirect.go index a0634f5a..9c145fe2 100644 --- a/render/redirect.go +++ b/render/redirect.go @@ -9,12 +9,14 @@ import ( "net/http" ) +// Redirect contains the http request reference and redirects status code and location. type Redirect struct { Code int Request *http.Request Location string } +// Render (Redirect) redirects the http request to new location and writes redirect response. func (r Redirect) Render(w http.ResponseWriter) error { // todo(thinkerou): go1.6 not support StatusPermanentRedirect(308) // when we upgrade go version we can use http.StatusPermanentRedirect @@ -25,4 +27,5 @@ func (r Redirect) Render(w http.ResponseWriter) error { return nil } +// WriteContentType (Redirect) don't write any ContentType. func (r Redirect) WriteContentType(http.ResponseWriter) {} diff --git a/render/render.go b/render/render.go index df0d1d7c..abfc79fc 100644 --- a/render/render.go +++ b/render/render.go @@ -6,8 +6,11 @@ package render import "net/http" +// Render interface is to be implemented by JSON, XML, HTML, YAML and so on. type Render interface { + // Render writes data with custom ContentType. Render(http.ResponseWriter) error + // WriteContentType writes custom ContentType. WriteContentType(w http.ResponseWriter) } diff --git a/render/text.go b/render/text.go index 7a6acc44..2ea7343c 100644 --- a/render/text.go +++ b/render/text.go @@ -10,6 +10,7 @@ import ( "net/http" ) +// String contains the given interface object slice and its format. type String struct { Format string Data []interface{} @@ -17,15 +18,18 @@ type String struct { var plainContentType = []string{"text/plain; charset=utf-8"} +// Render (String) writes data with custom ContentType. func (r String) Render(w http.ResponseWriter) error { WriteString(w, r.Format, r.Data) return nil } +// WriteContentType (String) writes Plain ContentType. func (r String) WriteContentType(w http.ResponseWriter) { writeContentType(w, plainContentType) } +// WriteString writes data according to its format and write custom ContentType. func WriteString(w http.ResponseWriter, format string, data []interface{}) { writeContentType(w, plainContentType) if len(data) > 0 { diff --git a/render/xml.go b/render/xml.go index cff1ac3e..cc5390a2 100644 --- a/render/xml.go +++ b/render/xml.go @@ -9,17 +9,20 @@ import ( "net/http" ) +// XML contains the given interface object. type XML struct { Data interface{} } var xmlContentType = []string{"application/xml; charset=utf-8"} +// Render (XML) encodes the given interface object and writes data with custom ContentType. func (r XML) Render(w http.ResponseWriter) error { r.WriteContentType(w) return xml.NewEncoder(w).Encode(r.Data) } +// WriteContentType (XML) writes XML ContentType for response. func (r XML) WriteContentType(w http.ResponseWriter) { writeContentType(w, xmlContentType) } diff --git a/render/yaml.go b/render/yaml.go index 25d0ebd4..33bc3254 100644 --- a/render/yaml.go +++ b/render/yaml.go @@ -10,12 +10,14 @@ import ( "gopkg.in/yaml.v2" ) +// YAML contains the given interface object. type YAML struct { Data interface{} } var yamlContentType = []string{"application/x-yaml; charset=utf-8"} +// Render (YAML) marshals the given interface object and writes data with custom ContentType. func (r YAML) Render(w http.ResponseWriter) error { r.WriteContentType(w) @@ -28,6 +30,7 @@ func (r YAML) Render(w http.ResponseWriter) error { return nil } +// WriteContentType (YAML) writes YAML ContentType for response. func (r YAML) WriteContentType(w http.ResponseWriter) { writeContentType(w, yamlContentType) } diff --git a/utils.go b/utils.go index bf32c775..f4532d56 100644 --- a/utils.go +++ b/utils.go @@ -14,8 +14,10 @@ import ( "strings" ) +// BindKey indicates a default bind key. const BindKey = "_gin-gonic/gin/bindkey" +// Bind is a helper function for given interface object and returns a Gin middleware. func Bind(val interface{}) HandlerFunc { value := reflect.ValueOf(val) if value.Kind() == reflect.Ptr { @@ -33,16 +35,14 @@ func Bind(val interface{}) HandlerFunc { } } -// WrapF is a helper function for wrapping http.HandlerFunc -// Returns a Gin middleware +// WrapF is a helper function for wrapping http.HandlerFunc and 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 +// WrapH is a helper function for wrapping http.Handler and returns a Gin middleware. func WrapH(h http.Handler) HandlerFunc { return func(c *Context) { h.ServeHTTP(c.Writer, c.Request) From 6db092f778277ef13da427acfa3501890e952436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sat, 15 Sep 2018 15:21:54 +0800 Subject: [PATCH 10/34] chore: add some annotations (#1550) ref #1075 should all annotations and can close #1075 . --- context.go | 6 ++++++ errors.go | 20 +++++++++++++++----- examples/realtime-advanced/main.go | 2 +- gin.go | 6 ++++++ mode.go | 13 +++++++++++-- render/html.go | 4 ++-- routergroup.go | 8 ++++++-- 7 files changed, 47 insertions(+), 12 deletions(-) diff --git a/context.go b/context.go index 063c72f0..809902a3 100644 --- a/context.go +++ b/context.go @@ -711,6 +711,7 @@ func (c *Context) Cookie(name string) (string, error) { return val, nil } +// Render writes the response headers and calls render.Render to render data. func (c *Context) Render(code int, r render.Render) { c.Status(code) @@ -833,6 +834,7 @@ func (c *Context) SSEvent(name string, message interface{}) { }) } +// Stream sends a streaming response. func (c *Context) Stream(step func(w io.Writer) bool) { w := c.Writer clientGone := w.CloseNotify() @@ -854,6 +856,7 @@ func (c *Context) Stream(step func(w io.Writer) bool) { /******** CONTENT NEGOTIATION *******/ /************************************/ +// Negotiate contains all negotiations data. type Negotiate struct { Offered []string HTMLName string @@ -863,6 +866,7 @@ type Negotiate struct { Data interface{} } +// Negotiate calls different Render according acceptable Accept format. func (c *Context) Negotiate(code int, config Negotiate) { switch c.NegotiateFormat(config.Offered...) { case binding.MIMEJSON: @@ -882,6 +886,7 @@ func (c *Context) Negotiate(code int, config Negotiate) { } } +// NegotiateFormat returns an acceptable Accept format. func (c *Context) NegotiateFormat(offered ...string) string { assert1(len(offered) > 0, "you must provide at least one offer") @@ -901,6 +906,7 @@ func (c *Context) NegotiateFormat(offered ...string) string { return "" } +// SetAccepted sets Accept header data. func (c *Context) SetAccepted(formats ...string) { c.Accepted = formats } diff --git a/errors.go b/errors.go index 6f90377e..477b9d58 100644 --- a/errors.go +++ b/errors.go @@ -12,18 +12,24 @@ import ( "github.com/gin-gonic/gin/internal/json" ) +// ErrorType is an unsigned 64-bit error code as defined in the gin spec. type ErrorType uint64 const ( - ErrorTypeBind ErrorType = 1 << 63 // used when c.Bind() fails - ErrorTypeRender ErrorType = 1 << 62 // used when c.Render() fails + // ErrorTypeBind is used when Context.Bind() fails. + ErrorTypeBind ErrorType = 1 << 63 + // ErrorTypeRender is used when Context.Render() fails. + ErrorTypeRender ErrorType = 1 << 62 + // ErrorTypePrivate indicates a private error. ErrorTypePrivate ErrorType = 1 << 0 - ErrorTypePublic ErrorType = 1 << 1 - + // ErrorTypePublic indicates a public error. + ErrorTypePublic ErrorType = 1 << 1 + // ErrorTypeAny indicates other any error. ErrorTypeAny ErrorType = 1<<64 - 1 ErrorTypeNu = 2 ) +// Error represents a error's specification. type Error struct { Err error Type ErrorType @@ -34,11 +40,13 @@ type errorMsgs []*Error var _ error = &Error{} +// SetType sets the error's type. func (msg *Error) SetType(flags ErrorType) *Error { msg.Type = flags return msg } +// SetMeta sets the error's meta data. func (msg *Error) SetMeta(data interface{}) *Error { msg.Meta = data return msg @@ -70,11 +78,12 @@ func (msg *Error) MarshalJSON() ([]byte, error) { return json.Marshal(msg.JSON()) } -// Error implements the error interface +// Error implements the error interface. func (msg Error) Error() string { return msg.Err.Error() } +// IsType judges one error. func (msg *Error) IsType(flags ErrorType) bool { return (msg.Type & flags) > 0 } @@ -138,6 +147,7 @@ func (a errorMsgs) JSON() interface{} { } } +// MarshalJSON implements the json.Marshaller interface. func (a errorMsgs) MarshalJSON() ([]byte, error) { return json.Marshal(a.JSON()) } diff --git a/examples/realtime-advanced/main.go b/examples/realtime-advanced/main.go index a16c58b0..f3ead476 100644 --- a/examples/realtime-advanced/main.go +++ b/examples/realtime-advanced/main.go @@ -20,7 +20,7 @@ func ConfigRuntime() { fmt.Printf("Running with %d CPUs\n", nuCPU) } -// StartWrokers start starsWorker by goroutine. +// StartWorkers start starsWorker by goroutine. func StartWorkers() { go statsWorker() } diff --git a/gin.go b/gin.go index aa62e014..6bff3bd5 100644 --- a/gin.go +++ b/gin.go @@ -26,7 +26,10 @@ var ( defaultAppEngine bool ) +// HandlerFunc defines the handler used by gin middleware as return value. type HandlerFunc func(*Context) + +// HandlersChain defines a HandlerFunc array. type HandlersChain []HandlerFunc // Last returns the last handler in the chain. ie. the last handler is the main own. @@ -37,12 +40,14 @@ func (c HandlersChain) Last() HandlerFunc { return nil } +// RouteInfo represents a request route's specification which contains method and path and its handler. type RouteInfo struct { Method string Path string Handler string } +// RoutesInfo defines a RouteInfo array. type RoutesInfo []RouteInfo // Engine is the framework's instance, it contains the muxer, middleware and configuration settings. @@ -155,6 +160,7 @@ func (engine *Engine) allocateContext() *Context { return &Context{engine: engine} } +// Delims sets template left and right delims and returns a Engine instance. func (engine *Engine) Delims(left, right string) *Engine { engine.delims = render.Delims{Left: left, Right: right} return engine diff --git a/mode.go b/mode.go index 9df4e45f..7cb0143a 100644 --- a/mode.go +++ b/mode.go @@ -11,12 +11,16 @@ import ( "github.com/gin-gonic/gin/binding" ) +// ENV_GIN_MODE indicates environment name for gin mode. const ENV_GIN_MODE = "GIN_MODE" const ( - DebugMode = "debug" + // DebugMode indicates gin mode is debug. + DebugMode = "debug" + // ReleaseMode indicates gin mode is relase. ReleaseMode = "release" - TestMode = "test" + // TestMode indicates gin mode is test. + TestMode = "test" ) const ( debugCode = iota @@ -42,6 +46,7 @@ func init() { SetMode(mode) } +// SetMode sets gin mode according to input string. func SetMode(value string) { switch value { case DebugMode, "": @@ -59,14 +64,18 @@ func SetMode(value string) { modeName = value } +// DisableBindValidation closes the default validator. func DisableBindValidation() { binding.Validator = nil } +// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumberto to +// call the UseNumber method on the JSON Decoder instance. func EnableJsonDecoderUseNumber() { binding.EnableDecoderUseNumber = true } +// Mode returns currently gin mode. func Mode() string { return modeName } diff --git a/render/html.go b/render/html.go index 4d3d5812..6696ece9 100644 --- a/render/html.go +++ b/render/html.go @@ -46,7 +46,7 @@ type HTML struct { var htmlContentType = []string{"text/html; charset=utf-8"} -// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.. +// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface. func (r HTMLProduction) Instance(name string, data interface{}) Render { return HTML{ Template: r.Template, @@ -55,7 +55,7 @@ func (r HTMLProduction) Instance(name string, data interface{}) Render { } } -// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.. +// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface. func (r HTMLDebug) Instance(name string, data interface{}) Render { return HTML{ Template: r.loadTemplate(), diff --git a/routergroup.go b/routergroup.go index 876a61b8..be561dee 100644 --- a/routergroup.go +++ b/routergroup.go @@ -11,11 +11,13 @@ import ( "strings" ) +// IRouter defines all router handle interface includes single and group router. type IRouter interface { IRoutes Group(string, ...HandlerFunc) *RouterGroup } +// Iroutes defins all router handle interface. type IRoutes interface { Use(...HandlerFunc) IRoutes @@ -34,8 +36,8 @@ type IRoutes interface { StaticFS(string, http.FileSystem) IRoutes } -// RouterGroup is used internally to configure router, a RouterGroup is associated with a prefix -// and an array of handlers (middleware). +// RouterGroup is used internally to configure router, a RouterGroup is associated with +// a prefix and an array of handlers (middleware). type RouterGroup struct { Handlers HandlersChain basePath string @@ -61,6 +63,8 @@ func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *R } } +// BasePath returns the base path of router group. +// For example, if v := router.Group("/rest/n/v1/api"), v.BasePath() is "/rest/n/v1/api". func (group *RouterGroup) BasePath() string { return group.basePath } From 7c7f703cc559af6c67fc82c3c39959a0c7d42b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sun, 16 Sep 2018 23:22:54 +0800 Subject: [PATCH 11/34] initial go.mod module definition (#1554) --- go.mod | 27 ++++++++++++++++++++++++ go.sum | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 00000000..bd4ad975 --- /dev/null +++ b/go.mod @@ -0,0 +1,27 @@ +module github.com/gin-gonic/gin + +require ( + github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16 // indirect + github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66 + github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 + github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b + github.com/golang/protobuf v1.2.0 + github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 + github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b + github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 + github.com/mattn/go-isatty v0.0.3 + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.2.2 + github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6 + github.com/ugorji/go v1.1.1 + golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b + golang.org/x/net v0.0.0-20180826012351-8a410e7b638d + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f + golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect + google.golang.org/grpc v1.15.0 + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect + gopkg.in/go-playground/validator.v8 v8.18.2 + gopkg.in/yaml.v2 v2.2.1 +) diff --git a/go.sum b/go.sum new file mode 100644 index 00000000..3382beed --- /dev/null +++ b/go.sum @@ -0,0 +1,65 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16 h1:HqkufMBR7waVfFFRABWqHa1WgTvjtVDJTLJe3CR576A= +github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66 h1:QnnoVdChKs+GeTvN4rPYTW6b5U6M3HMEvQ/+x4IGtfY= +github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66/go.mod h1:kTEh6M2J/mh7nsskr28alwLCXm/DSG5OSA/o31yy2XU= +github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= +github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b h1:dm/NYytoj7p8Jc6zMvyRz3PCQrTTCXnVRvEzyBcM890= +github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b/go.mod h1:vwfeXwKgEIWq63oVfwaBjoByS4dZzYbHHROHjV4IjNY= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 h1:cW/amwGEJK5MSKntPXRjX4dxs/nGxGT8gXKIsKFmHGc= +github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15/go.mod h1:Fdm/oWRW+CH8PRbLntksCNtmcCBximKPkVQYvmMl80k= +github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b h1:X61dhFTE1Au92SvyF8HyAwdjWqiSdfBgFR7wTxC0+uU= +github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 h1:KIaAZ/V+/0/6BOULrmBQ9T1ed8BkKqGIjIKW923nJuo= +github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227/go.mod h1:ruMr5t05gVho4tuDv0PbI0Bb8nOxc/5Y6JzRHe/yfA0= +github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6 h1:d/LEgOfWe+AlOCz/kzmkvlO+gq9LRGhjSHqt2nx8Muc= +github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6/go.mod h1:HL7Pap5kOluZv1ku34pZo/AJ44GaxMEPFZ3pmuexV2s= +github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= +github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= +golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ= +golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/grpc v1.15.0 h1:Az/KuahOM4NAidTEuJCv/RonAA7rYsTPkqXVjr+8OOw= +google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= From 90c680ef5c360ccd2f0f5f9f0ab1f44f3ce9eef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laforge?= Date: Mon, 17 Sep 2018 06:09:34 +0200 Subject: [PATCH 12/34] Let's user define how he wants to log his routes (eg. JSON, key value, or something else) (#1553) (#1555) --- README.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ debug.go | 8 +++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9a97ec54..45bfce5a 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi - [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct) - [Try to bind body into different structs](#try-to-bind-body-into-different-structs) - [http2 server push](#http2-server-push) + - [Define format for the log of routes](#define-format-for-the-log-of-routes) - [Testing](#testing) - [Users](#users) @@ -1836,6 +1837,49 @@ func main() { } ``` +### Define format for the log of routes + +The default log of routes is: +``` +[GIN-debug] POST /foo --> main.main.func1 (3 handlers) +[GIN-debug] GET /bar --> main.main.func2 (3 handlers) +[GIN-debug] GET /status --> main.main.func3 (3 handlers) +``` + +If you want to log this information in given format (e.g. JSON, key values or something else), then you can define this format with `gin.DebugPrintRouteFunc`. +In the example below, we log all routes with standard log package but you can use another log tools that suits of your needs. +```go +import ( + "log" + "net/http" + + "github.com/gin-gonic/gin" +) + +func main() { + r := gin.Default() + gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { + log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) + } + + r.POST("/foo", func(c *gin.Context) { + c.JSON(http.StatusOK, "foo") + }) + + r.GET("/bar", func(c *gin.Context) { + c.JSON(http.StatusOK, "bar") + }) + + r.GET("/status", func(c *gin.Context) { + c.JSON(http.StatusOK, "ok") + }) + + // Listen and Server in http://0.0.0.0:8080 + r.Run() +} +``` + + ## Testing The `net/http/httptest` package is preferable way for HTTP testing. diff --git a/debug.go b/debug.go index f11156b3..693486a9 100644 --- a/debug.go +++ b/debug.go @@ -20,11 +20,17 @@ func IsDebugging() bool { return ginMode == debugCode } +var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int) + func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { if IsDebugging() { nuHandlers := len(handlers) handlerName := nameOfFunction(handlers.Last()) - debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) + if DebugPrintRouteFunc == nil { + debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers) + } else { + DebugPrintRouteFunc(httpMethod, absolutePath, handlerName, nuHandlers) + } } } From b27b7026c70697d84226f15d6d433bdf07023c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Mon, 17 Sep 2018 15:08:11 +0800 Subject: [PATCH 13/34] chore: add a version file includes gin version (#1549) * chore: add a version file includes gin version * update version for dev version --- gin.go | 6 +----- version.go | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 version.go diff --git a/gin.go b/gin.go index 6bff3bd5..11f6d94a 100644 --- a/gin.go +++ b/gin.go @@ -14,11 +14,7 @@ import ( "github.com/gin-gonic/gin/render" ) -const ( - // Version is Framework's version. - Version = "v1.3.0" - defaultMultipartMemory = 32 << 20 // 32 MB -) +const defaultMultipartMemory = 32 << 20 // 32 MB var ( default404Body = []byte("404 page not found") diff --git a/version.go b/version.go new file mode 100644 index 00000000..028caebe --- /dev/null +++ b/version.go @@ -0,0 +1,8 @@ +// Copyright 2018 Gin Core Team. 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 + +// Version is the current gin framework's version. +const Version = "v1.4.0-dev" From 07f1bf0e63512fbf9c7d7984d235a399eb916244 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Wed, 19 Sep 2018 13:57:00 +0800 Subject: [PATCH 14/34] feat: replace debug log with fmt package. (#1560) --- context_test.go | 12 ++--- debug.go | 8 +-- debug_test.go | 140 +++++++++++++++++++++++++++--------------------- 3 files changed, 86 insertions(+), 74 deletions(-) diff --git a/context_test.go b/context_test.go index 4c307080..5a5bb6e1 100644 --- a/context_test.go +++ b/context_test.go @@ -784,14 +784,14 @@ func TestContextRenderHTML2(t *testing.T) { 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) + re := captureOutput(func() { + SetMode(DebugMode) + router.SetHTMLTemplate(templ) + SetMode(TestMode) + }) - 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()) + 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", re) c.HTML(http.StatusCreated, "t", H{"name": "alexandernyquist"}) diff --git a/debug.go b/debug.go index 693486a9..d6d8bce6 100644 --- a/debug.go +++ b/debug.go @@ -6,14 +6,10 @@ package gin import ( "bytes" + "fmt" "html/template" - "log" ) -func init() { - log.SetFlags(0) -} - // IsDebugging returns true if the framework is running in debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode. func IsDebugging() bool { @@ -48,7 +44,7 @@ func debugPrintLoadTemplate(tmpl *template.Template) { func debugPrint(format string, values ...interface{}) { if IsDebugging() { - log.Printf("[GIN-debug] "+format, values...) + fmt.Printf("[GIN-debug] "+format, values...) } } diff --git a/debug_test.go b/debug_test.go index ed5a6a54..0b9d7910 100644 --- a/debug_test.go +++ b/debug_test.go @@ -11,6 +11,7 @@ import ( "io" "log" "os" + "sync" "testing" "github.com/stretchr/testify/assert" @@ -30,86 +31,101 @@ func TestIsDebugging(t *testing.T) { } func TestDebugPrint(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - SetMode(ReleaseMode) - debugPrint("DEBUG this!") - SetMode(TestMode) - debugPrint("DEBUG this!") - assert.Empty(t, w.String()) - - SetMode(DebugMode) - debugPrint("these are %d %s\n", 2, "error messages") - assert.Equal(t, "[GIN-debug] these are 2 error messages\n", w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + SetMode(ReleaseMode) + debugPrint("DEBUG this!") + SetMode(TestMode) + debugPrint("DEBUG this!") + SetMode(DebugMode) + debugPrint("these are %d %s\n", 2, "error messages") + SetMode(TestMode) + }) + assert.Equal(t, "[GIN-debug] these are 2 error messages\n", re) } func TestDebugPrintError(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - SetMode(DebugMode) - debugPrintError(nil) - assert.Empty(t, w.String()) - - debugPrintError(errors.New("this is an error")) - assert.Equal(t, "[GIN-debug] [ERROR] this is an error\n", w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + debugPrintError(nil) + debugPrintError(errors.New("this is an error")) + SetMode(TestMode) + }) + assert.Equal(t, "[GIN-debug] [ERROR] this is an error\n", re) } func TestDebugPrintRoutes(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest}) - assert.Regexp(t, `^\[GIN-debug\] GET /path/to/route/:param --> (.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest \(2 handlers\)\n$`, w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + debugPrintRoute("GET", "/path/to/route/:param", HandlersChain{func(c *Context) {}, handlerNameTest}) + SetMode(TestMode) + }) + assert.Regexp(t, `^\[GIN-debug\] GET /path/to/route/:param --> (.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest \(2 handlers\)\n$`, re) } func TestDebugPrintLoadTemplate(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl")) - debugPrintLoadTemplate(templ) - assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + templ := template.Must(template.New("").Delims("{[{", "}]}").ParseGlob("./testdata/template/hello.tmpl")) + debugPrintLoadTemplate(templ) + SetMode(TestMode) + }) + assert.Regexp(t, `^\[GIN-debug\] Loaded HTML Templates \(2\): \n(\t- \n|\t- hello\.tmpl\n){2}\n`, re) } func TestDebugPrintWARNINGSetHTMLTemplate(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - debugPrintWARNINGSetHTMLTemplate() - 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", w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + debugPrintWARNINGSetHTMLTemplate() + SetMode(TestMode) + }) + 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", re) } func TestDebugPrintWARNINGDefault(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - debugPrintWARNINGDefault() - assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + debugPrintWARNINGDefault() + SetMode(TestMode) + }) + assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) } func TestDebugPrintWARNINGNew(t *testing.T) { - var w bytes.Buffer - setup(&w) - defer teardown() - - debugPrintWARNINGNew() - assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", w.String()) + re := captureOutput(func() { + SetMode(DebugMode) + debugPrintWARNINGNew() + SetMode(TestMode) + }) + assert.Equal(t, "[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\n - using env:\texport GIN_MODE=release\n - using code:\tgin.SetMode(gin.ReleaseMode)\n\n", re) } -func setup(w io.Writer) { - SetMode(DebugMode) - log.SetOutput(w) -} - -func teardown() { - SetMode(TestMode) - log.SetOutput(os.Stdout) +func captureOutput(f func()) string { + reader, writer, err := os.Pipe() + if err != nil { + panic(err) + } + stdout := os.Stdout + stderr := os.Stderr + defer func() { + os.Stdout = stdout + os.Stderr = stderr + log.SetOutput(os.Stderr) + }() + os.Stdout = writer + os.Stderr = writer + log.SetOutput(writer) + out := make(chan string) + wg := new(sync.WaitGroup) + wg.Add(1) + go func() { + var buf bytes.Buffer + wg.Done() + io.Copy(&buf, reader) + out <- buf.String() + }() + wg.Wait() + f() + writer.Close() + return <-out } From c617b6241a1891081b3632ed89c1887dc4c353af Mon Sep 17 00:00:00 2001 From: Javier Provecho Fernandez Date: Thu, 20 Sep 2018 03:13:04 +0200 Subject: [PATCH 15/34] chore: recover go master build, partial revert #1514 (#1561) * chore: recover go master build, partial revert #1514 * chore: add master to go branch build targets --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index a93458f9..398c1409 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,11 @@ go: - 1.9.x - 1.10.x - 1.11.x + - master + +matrix: + allow_failures: + - go: master git: depth: 10 From f2cd3fcb2a9b4b108f5ce34a9f121ec13ac1cc16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 20 Sep 2018 11:53:58 +0800 Subject: [PATCH 16/34] chore: fix typo and add a little anotation (#1562) --- debug.go | 1 + routergroup.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debug.go b/debug.go index d6d8bce6..ce908dc7 100644 --- a/debug.go +++ b/debug.go @@ -16,6 +16,7 @@ func IsDebugging() bool { return ginMode == debugCode } +// DebugPrintRouteFunc indicates debug log output format. var DebugPrintRouteFunc func(httpMethod, absolutePath, handlerName string, nuHandlers int) func debugPrintRoute(httpMethod, absolutePath string, handlers HandlersChain) { diff --git a/routergroup.go b/routergroup.go index be561dee..579aa7dc 100644 --- a/routergroup.go +++ b/routergroup.go @@ -17,7 +17,7 @@ type IRouter interface { Group(string, ...HandlerFunc) *RouterGroup } -// Iroutes defins all router handle interface. +// IRoutes defines all router handle interface. type IRoutes interface { Use(...HandlerFunc) IRoutes From a210eea3bd1c3766d76968108dfcd83c331f549c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Fri, 21 Sep 2018 10:21:59 +0800 Subject: [PATCH 17/34] improve panic information when a catch-all wildcard conflict occurs (#1529) --- tree.go | 11 +++++++++-- tree_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/tree.go b/tree.go index b6530665..ada62ceb 100644 --- a/tree.go +++ b/tree.go @@ -193,9 +193,16 @@ func (n *node) addRoute(path string, handlers HandlersChain) { } } - panic("path segment '" + path + + pathSeg := path + if n.nType != catchAll { + pathSeg = strings.SplitN(path, "/", 2)[0] + } + prefix := fullPath[:strings.Index(fullPath, pathSeg)] + n.path + panic("'" + pathSeg + + "' in new path '" + fullPath + "' conflicts with existing wildcard '" + n.path + - "' in path '" + fullPath + "'") + "' in existing prefix '" + prefix + + "'") } c := path[0] diff --git a/tree_test.go b/tree_test.go index 152f6331..a1b3bbe7 100644 --- a/tree_test.go +++ b/tree_test.go @@ -5,7 +5,9 @@ package gin import ( + "fmt" "reflect" + "regexp" "strings" "testing" ) @@ -653,3 +655,43 @@ func TestTreeInvalidNodeType(t *testing.T) { t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) } } + +func TestTreeWildcardConflictEx(t *testing.T) { + conflicts := [...]struct { + route string + segPath string + existPath string + existSegPath string + }{ + {"/who/are/foo", "/foo", `/who/are/\*you`, `/\*you`}, + {"/who/are/foo/", "/foo/", `/who/are/\*you`, `/\*you`}, + {"/who/are/foo/bar", "/foo/bar", `/who/are/\*you`, `/\*you`}, + {"/conxxx", "xxx", `/con:tact`, `:tact`}, + {"/conooo/xxx", "ooo", `/con:tact`, `:tact`}, + } + + for _, conflict := range conflicts { + // I have to re-create a 'tree', because the 'tree' will be + // in an inconsistent state when the loop recovers from the + // panic which threw by 'addRoute' function. + tree := &node{} + routes := [...]string{ + "/con:tact", + "/who/are/*you", + "/who/foo/hello", + } + + for _, route := range routes { + tree.addRoute(route, fakeHandler(route)) + } + + recv := catchPanic(func() { + tree.addRoute(conflict.route, fakeHandler(conflict.route)) + }) + + if !regexp.MustCompile(fmt.Sprintf("'%s' in new path .* conflicts with existing wildcard '%s' in existing prefix '%s'", + conflict.segPath, conflict.existSegPath, conflict.existPath)).MatchString(fmt.Sprint(recv)) { + t.Fatalf("invalid wildcard conflict error (%v)", recv) + } + } +} From 5a75dc712705510ab39fe7c448e7ab11459ce5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sat, 22 Sep 2018 11:37:28 +0800 Subject: [PATCH 18/34] add release badge for readme (#1533) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 45bfce5a..6fd2dd34 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ [![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) [![Sourcegraph](https://sourcegraph.com/github.com/gin-gonic/gin/-/badge.svg)](https://sourcegraph.com/github.com/gin-gonic/gin?badge) [![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin) +[![Release](https://img.shields.io/github/release/gin-gonic/gin.svg?style=flat-square)](https://github.com/gin-gonic/gin/releases) 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. From ad53619b15fda20df57c16cf19fe83f4a428cefa Mon Sep 17 00:00:00 2001 From: Dustin Decker Date: Sun, 23 Sep 2018 00:15:23 -0700 Subject: [PATCH 19/34] Don't log requests (#1370) Fixes #1331 HTTP logging leaks sensitive request information. This PR removes HTTP request logging during panics. --- recovery.go | 8 ++++++-- recovery_test.go | 12 +++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/recovery.go b/recovery.go index 61c5bd53..6c28b4fa 100644 --- a/recovery.go +++ b/recovery.go @@ -39,8 +39,12 @@ func RecoveryWithWriter(out io.Writer) HandlerFunc { if err := recover(); err != nil { if logger != nil { stack := stack(3) - httprequest, _ := httputil.DumpRequest(c.Request, false) - logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s", timeFormat(time.Now()), string(httprequest), err, stack, reset) + if IsDebugging() { + httprequest, _ := httputil.DumpRequest(c.Request, false) + logger.Printf("[Recovery] %s panic recovered:\n%s\n%s\n%s%s", timeFormat(time.Now()), string(httprequest), err, stack, reset) + } else { + logger.Printf("[Recovery] %s panic recovered:\n%s\n%s%s", timeFormat(time.Now()), err, stack, reset) + } } c.AbortWithStatus(http.StatusInternalServerError) } diff --git a/recovery_test.go b/recovery_test.go index 53f4a071..7d422b74 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -24,9 +24,19 @@ func TestPanicInHandler(t *testing.T) { w := performRequest(router, "GET", "/recovery") // TEST assert.Equal(t, http.StatusInternalServerError, w.Code) - assert.Contains(t, buffer.String(), "GET /recovery") + assert.Contains(t, buffer.String(), "panic recovered") assert.Contains(t, buffer.String(), "Oupps, Houston, we have a problem") assert.Contains(t, buffer.String(), "TestPanicInHandler") + assert.NotContains(t, buffer.String(), "GET /recovery") + + // Debug mode prints the request + SetMode(DebugMode) + // RUN + w = performRequest(router, "GET", "/recovery") + // TEST + assert.Equal(t, http.StatusInternalServerError, w.Code) + assert.Contains(t, buffer.String(), "GET /recovery") + } // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used. From b02e4f2ed68e1bd9598b8eced0b21c9aacfed5ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Tue, 25 Sep 2018 21:52:21 +0800 Subject: [PATCH 20/34] ci: fast finish when build failed (#1568) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 398c1409..f9e241d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ go: matrix: allow_failures: - go: master + fast_finish: true git: depth: 10 From fd599fcceadba48be39ded04d1e2fb3181b43e8c Mon Sep 17 00:00:00 2001 From: andrea Date: Tue, 25 Sep 2018 21:28:25 -0500 Subject: [PATCH 21/34] Make logger use a yellow background and a darkgray text for legibility (#1570) 1. Why is this change neccesary? White text on a yellow background was illegible with most terminal color schemes 2. How does it address the issue? The white text was replaced with a bash compatible dark gray while keeping the yellow background colour 3. What side effects does this change have? Resolves #1552 --- logger.go | 2 +- logger_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/logger.go b/logger.go index 1a8df601..5f986853 100644 --- a/logger.go +++ b/logger.go @@ -17,7 +17,7 @@ import ( var ( green = string([]byte{27, 91, 57, 55, 59, 52, 50, 109}) white = string([]byte{27, 91, 57, 48, 59, 52, 55, 109}) - yellow = string([]byte{27, 91, 57, 55, 59, 52, 51, 109}) + yellow = string([]byte{27, 91, 57, 48, 59, 52, 51, 109}) red = string([]byte{27, 91, 57, 55, 59, 52, 49, 109}) blue = string([]byte{27, 91, 57, 55, 59, 52, 52, 109}) magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109}) diff --git a/logger_test.go b/logger_test.go index 7dbbf7b1..6118cb04 100644 --- a/logger_test.go +++ b/logger_test.go @@ -85,7 +85,7 @@ func TestLogger(t *testing.T) { func TestColorForMethod(t *testing.T) { assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 52, 109}), colorForMethod("GET"), "get should be blue") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 54, 109}), colorForMethod("POST"), "post should be cyan") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow") + assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForMethod("DELETE"), "delete should be red") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForMethod("PATCH"), "patch should be green") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 53, 109}), colorForMethod("HEAD"), "head should be magenta") @@ -96,7 +96,7 @@ func TestColorForMethod(t *testing.T) { func TestColorForStatus(t *testing.T) { assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 50, 109}), colorForStatus(http.StatusOK), "2xx should be green") assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 55, 109}), colorForStatus(http.StatusMovedPermanently), "3xx should be white") - assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow") + assert.Equal(t, string([]byte{27, 91, 57, 48, 59, 52, 51, 109}), colorForStatus(http.StatusNotFound), "4xx should be yellow") assert.Equal(t, string([]byte{27, 91, 57, 55, 59, 52, 49, 109}), colorForStatus(2), "other things should be red") } From 834a2ec64ca1ce077e4bdeb5edec019df1c01e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Wed, 26 Sep 2018 13:49:11 +0800 Subject: [PATCH 22/34] feat: add go version judge when print debug warning log (#1572) * feat: add go version judge when print debug warning log * remove invalid statement * use one const --- debug.go | 18 +++++++++++++++++- debug_test.go | 24 +++++++++++++++++++++++- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/debug.go b/debug.go index ce908dc7..4fd23fa1 100644 --- a/debug.go +++ b/debug.go @@ -8,8 +8,13 @@ import ( "bytes" "fmt" "html/template" + "runtime" + "strconv" + "strings" ) +const ginSupportMinGoVer = 6 + // IsDebugging returns true if the framework is running in debug mode. // Use SetMode(gin.ReleaseMode) to disable debug mode. func IsDebugging() bool { @@ -49,10 +54,21 @@ func debugPrint(format string, values ...interface{}) { } } +func getMinVer(v string) (uint64, error) { + first := strings.IndexByte(v, '.') + last := strings.LastIndexByte(v, '.') + if first == last { + return strconv.ParseUint(v[first+1:], 10, 64) + } + return strconv.ParseUint(v[first+1:last], 10, 64) +} + func debugPrintWARNINGDefault() { - debugPrint(`[WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon. + if v, e := getMinVer(runtime.Version()); e == nil && v <= ginSupportMinGoVer { + debugPrint(`[WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon. `) + } debugPrint(`[WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached. `) diff --git a/debug_test.go b/debug_test.go index 0b9d7910..c8a010ff 100644 --- a/debug_test.go +++ b/debug_test.go @@ -11,6 +11,7 @@ import ( "io" "log" "os" + "runtime" "sync" "testing" @@ -88,7 +89,13 @@ func TestDebugPrintWARNINGDefault(t *testing.T) { debugPrintWARNINGDefault() SetMode(TestMode) }) - assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) + m, e := getMinVer(runtime.Version()) + assert.Nil(t, e) + if m <= ginSupportMinGoVer { + assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) + } else { + assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) + } } func TestDebugPrintWARNINGNew(t *testing.T) { @@ -129,3 +136,18 @@ func captureOutput(f func()) string { writer.Close() return <-out } + +func TestGetMinVer(t *testing.T) { + var m uint64 + var e error + _, e = getMinVer("go1") + assert.NotNil(t, e) + m, e = getMinVer("go1.1") + assert.Equal(t, uint64(1), m) + assert.Nil(t, e) + m, e = getMinVer("go1.1.1") + assert.Nil(t, e) + assert.Equal(t, uint64(1), m) + _, e = getMinVer("go1.1.1.1") + assert.NotNil(t, e) +} From 402ef120e19218544152502d1ea20709ff5adbc8 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Thu, 27 Sep 2018 08:59:44 +0800 Subject: [PATCH 23/34] fix: fmt output log to os.Stderr (#1571) fix #1560 changes are breaking in App Engine. cc @giulianobr @philippgille --- debug.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debug.go b/debug.go index 4fd23fa1..c5e65b22 100644 --- a/debug.go +++ b/debug.go @@ -8,6 +8,7 @@ import ( "bytes" "fmt" "html/template" + "os" "runtime" "strconv" "strings" @@ -50,7 +51,7 @@ func debugPrintLoadTemplate(tmpl *template.Template) { func debugPrint(format string, values ...interface{}) { if IsDebugging() { - fmt.Printf("[GIN-debug] "+format, values...) + fmt.Fprintf(os.Stderr, "[GIN-debug] "+format, values...) } } From b7314d943c81052dd7155499c7313d7524cb024c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 27 Sep 2018 09:42:41 +0800 Subject: [PATCH 24/34] chore: fix debug test error (#1574) --- debug_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/debug_test.go b/debug_test.go index c8a010ff..97ff166b 100644 --- a/debug_test.go +++ b/debug_test.go @@ -90,8 +90,7 @@ func TestDebugPrintWARNINGDefault(t *testing.T) { SetMode(TestMode) }) m, e := getMinVer(runtime.Version()) - assert.Nil(t, e) - if m <= ginSupportMinGoVer { + if e == nil && m <= ginSupportMinGoVer { assert.Equal(t, "[GIN-debug] [WARNING] Now Gin requires Go 1.6 or later and Go 1.7 will be required soon.\n\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) } else { assert.Equal(t, "[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\n\n", re) From 91a4459dd27a311c2b959708f328d60177fa4046 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Thu, 27 Sep 2018 09:58:47 +0800 Subject: [PATCH 25/34] remove allow fail flag (#1573) golang team revert the net/url issue: https://github.com/golang/go/issues/27302 --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9e241d7..a765f37f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,6 @@ go: - master matrix: - allow_failures: - - go: master fast_finish: true git: From e9f187f60a27477e54c177f314db00d6a1abf062 Mon Sep 17 00:00:00 2001 From: James Pettyjohn Date: Sun, 30 Sep 2018 19:49:39 -0700 Subject: [PATCH 26/34] removed use of sync.pool from HandleContext and added test coverage (#1565) As per #1230 there is an issue when using HandleContext where the context of the request is returned to the context sync.Pool before the parent request has finished, causing context to be used in a non-thread safe manner. I've removed the bug by not entering the context back in the pool and leaving that to ServeHTTP. There was no test coverage for this function so I've also added the test to cover it. As the bug only happens when there are concurrent requests, the tests issues hundreds of concurrent requests. Without the bug fixed the tests do consistently recreate the error. --- gin.go | 1 - gin_integration_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/gin.go b/gin.go index 11f6d94a..92c24ba2 100644 --- a/gin.go +++ b/gin.go @@ -336,7 +336,6 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (engine *Engine) HandleContext(c *Context) { c.reset() engine.handleHTTPRequest(c) - engine.pool.Put(c) } func (engine *Engine) handleHTTPRequest(c *Context) { diff --git a/gin_integration_test.go b/gin_integration_test.go index 52f78842..12a943b0 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -12,6 +12,7 @@ import ( "net/http" "net/http/httptest" "os" + "sync" "testing" "time" @@ -119,6 +120,29 @@ func TestWithHttptestWithAutoSelectedPort(t *testing.T) { testRequest(t, ts.URL+"/example") } +func TestConcurrentHandleContext(t *testing.T) { + router := New() + router.GET("/", func(c *Context) { + c.Request.URL.Path = "/example" + router.HandleContext(c) + }) + router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) + + ts := httptest.NewServer(router) + defer ts.Close() + + var wg sync.WaitGroup + iterations := 200 + wg.Add(iterations) + for i := 0; i < iterations; i++ { + go func() { + testRequest(t, ts.URL+"/") + wg.Done() + }() + } + wg.Wait() +} + // func TestWithHttptestWithSpecifiedPort(t *testing.T) { // router := New() // router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) From fbdcbd22751c7174d4f363995fca296e4670726b Mon Sep 17 00:00:00 2001 From: zesani <7sin@outlook.co.th> Date: Tue, 9 Oct 2018 06:14:21 +0700 Subject: [PATCH 27/34] Update README.md (#1583) change "hava" to "have" --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6fd2dd34..95bd3204 100644 --- a/README.md +++ b/README.md @@ -1721,11 +1721,11 @@ type StructX struct { } type StructY struct { - Y StructX `form:"name_y"` // HERE hava form + Y StructX `form:"name_y"` // HERE have form } type StructZ struct { - Z *StructZ `form:"name_z"` // HERE hava form + Z *StructZ `form:"name_z"` // HERE have form } ``` From 6ab50f944ca52bdd4d982d0bec454d94bf7b802a Mon Sep 17 00:00:00 2001 From: andriikushch Date: Fri, 12 Oct 2018 01:31:31 +0200 Subject: [PATCH 28/34] replace deprecated HeaderMap with Header() (#1585) --- auth_test.go | 4 +-- context_17_test.go | 2 +- context_test.go | 64 +++++++++++++++++++++---------------------- render/render_test.go | 6 ++-- routes_test.go | 12 ++++---- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/auth_test.go b/auth_test.go index ab7e94be..197e9208 100644 --- a/auth_test.go +++ b/auth_test.go @@ -122,7 +122,7 @@ func TestBasicAuth401(t *testing.T) { assert.False(t, called) assert.Equal(t, http.StatusUnauthorized, w.Code) - assert.Equal(t, "Basic realm=\"Authorization Required\"", w.HeaderMap.Get("WWW-Authenticate")) + assert.Equal(t, "Basic realm=\"Authorization Required\"", w.Header().Get("WWW-Authenticate")) } func TestBasicAuth401WithCustomRealm(t *testing.T) { @@ -142,5 +142,5 @@ func TestBasicAuth401WithCustomRealm(t *testing.T) { assert.False(t, called) assert.Equal(t, http.StatusUnauthorized, w.Code) - assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.HeaderMap.Get("WWW-Authenticate")) + assert.Equal(t, "Basic realm=\"My Custom \\\"Realm\\\"\"", w.Header().Get("WWW-Authenticate")) } diff --git a/context_17_test.go b/context_17_test.go index d2251904..5b9ebcdc 100644 --- a/context_17_test.go +++ b/context_17_test.go @@ -23,5 +23,5 @@ func TestContextRenderPureJSON(t *testing.T) { c.PureJSON(http.StatusCreated, H{"foo": "bar", "html": ""}) assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\"}\n", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } diff --git a/context_test.go b/context_test.go index 5a5bb6e1..2e972f18 100644 --- a/context_test.go +++ b/context_test.go @@ -628,7 +628,7 @@ func TestContextRenderJSON(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that the response is serialized as JSONP @@ -642,7 +642,7 @@ func TestContextRenderJSONP(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "x({\"foo\":\"bar\"})", w.Body.String()) - assert.Equal(t, "application/javascript; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that the response is serialized as JSONP @@ -656,7 +656,7 @@ func TestContextRenderJSONPWithoutCallback(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no JSON is rendered if code is 204 @@ -668,7 +668,7 @@ func TestContextRenderNoContentJSON(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that the response is serialized as JSON @@ -682,7 +682,7 @@ func TestContextRenderAPIJSON(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) - assert.Equal(t, "application/vnd.api+json", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/vnd.api+json", w.Header().Get("Content-Type")) } // Tests that no Custom JSON is rendered if code is 204 @@ -695,7 +695,7 @@ func TestContextRenderNoContentAPIJSON(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, w.HeaderMap.Get("Content-Type"), "application/vnd.api+json") + assert.Equal(t, w.Header().Get("Content-Type"), "application/vnd.api+json") } // Tests that the response is serialized as JSON @@ -708,7 +708,7 @@ func TestContextRenderIndentedJSON(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\",\n \"nested\": {\n \"foo\": \"bar\"\n }\n}", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no Custom JSON is rendered if code is 204 @@ -720,7 +720,7 @@ func TestContextRenderNoContentIndentedJSON(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that the response is serialized as Secure JSON @@ -734,7 +734,7 @@ func TestContextRenderSecureJSON(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "&&&START&&&[\"foo\",\"bar\"]", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no Custom JSON is rendered if code is 204 @@ -746,7 +746,7 @@ func TestContextRenderNoContentSecureJSON(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } func TestContextRenderNoContentAsciiJSON(t *testing.T) { @@ -757,7 +757,7 @@ func TestContextRenderNoContentAsciiJSON(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "application/json", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json", w.Header().Get("Content-Type")) } // Tests that the response executes the templates @@ -773,7 +773,7 @@ func TestContextRenderHTML(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } func TestContextRenderHTML2(t *testing.T) { @@ -797,7 +797,7 @@ func TestContextRenderHTML2(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "Hello alexandernyquist", w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no HTML is rendered if code is 204 @@ -811,7 +811,7 @@ func TestContextRenderNoContentHTML(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextXML tests that the response is serialized as XML @@ -824,7 +824,7 @@ func TestContextRenderXML(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "bar", w.Body.String()) - assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no XML is rendered if code is 204 @@ -836,7 +836,7 @@ func TestContextRenderNoContentXML(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextString tests that the response is returned @@ -849,7 +849,7 @@ func TestContextRenderString(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "test string 2", w.Body.String()) - assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no String is rendered if code is 204 @@ -861,7 +861,7 @@ func TestContextRenderNoContentString(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextString tests that the response is returned @@ -875,7 +875,7 @@ func TestContextRenderHTMLString(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "string 3", w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } // Tests that no HTML String is rendered if code is 204 @@ -888,7 +888,7 @@ func TestContextRenderNoContentHTMLString(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextData tests that the response can be written from `bytesting` @@ -901,7 +901,7 @@ func TestContextRenderData(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo,bar", w.Body.String()) - assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/csv", w.Header().Get("Content-Type")) } // Tests that no Custom Data is rendered if code is 204 @@ -913,7 +913,7 @@ func TestContextRenderNoContentData(t *testing.T) { assert.Equal(t, http.StatusNoContent, w.Code) assert.Empty(t, w.Body.String()) - assert.Equal(t, "text/csv", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/csv", w.Header().Get("Content-Type")) } func TestContextRenderSSE(t *testing.T) { @@ -942,7 +942,7 @@ func TestContextRenderFile(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "func New() *Engine {") - assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextRenderYAML tests that the response is serialized as YAML @@ -955,7 +955,7 @@ func TestContextRenderYAML(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, "foo: bar\n", w.Body.String()) - assert.Equal(t, "application/x-yaml; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) } // TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf @@ -979,7 +979,7 @@ func TestContextRenderProtoBuf(t *testing.T) { assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, string(protoData), w.Body.String()) - assert.Equal(t, "application/x-protobuf", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type")) } func TestContextHeaders(t *testing.T) { @@ -1062,7 +1062,7 @@ func TestContextNegotiationWithJSON(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String()) - assert.Equal(t, "application/json; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type")) } func TestContextNegotiationWithXML(t *testing.T) { @@ -1077,7 +1077,7 @@ func TestContextNegotiationWithXML(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "bar", w.Body.String()) - assert.Equal(t, "application/xml; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type")) } func TestContextNegotiationWithHTML(t *testing.T) { @@ -1095,7 +1095,7 @@ func TestContextNegotiationWithHTML(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "Hello gin", w.Body.String()) - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } func TestContextNegotiationNotSupport(t *testing.T) { @@ -1131,7 +1131,7 @@ func TestContextNegotiationFormatWithAccept(t *testing.T) { assert.Empty(t, c.NegotiateFormat(MIMEJSON)) } -func TestContextNegotiationFormatCustum(t *testing.T) { +func TestContextNegotiationFormatCustom(t *testing.T) { c, _ := CreateTestContext(httptest.NewRecorder()) c.Request, _ = http.NewRequest("POST", "/", nil) c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") @@ -1627,9 +1627,9 @@ func TestContextRenderDataFromReader(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, body, w.Body.String()) - assert.Equal(t, contentType, w.HeaderMap.Get("Content-Type")) - assert.Equal(t, fmt.Sprintf("%d", contentLength), w.HeaderMap.Get("Content-Length")) - assert.Equal(t, extraHeaders["Content-Disposition"], w.HeaderMap.Get("Content-Disposition")) + assert.Equal(t, contentType, w.Header().Get("Content-Type")) + assert.Equal(t, fmt.Sprintf("%d", contentLength), w.Header().Get("Content-Length")) + assert.Equal(t, extraHeaders["Content-Disposition"], w.Header().Get("Content-Disposition")) } type TestResponseRecorder struct { diff --git a/render/render_test.go b/render/render_test.go index 09ccc658..4c9b180d 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -480,7 +480,7 @@ func TestRenderReader(t *testing.T) { assert.NoError(t, err) assert.Equal(t, body, w.Body.String()) - assert.Equal(t, "image/png", w.HeaderMap.Get("Content-Type")) - assert.Equal(t, strconv.Itoa(len(body)), w.HeaderMap.Get("Content-Length")) - assert.Equal(t, headers["Content-Disposition"], w.HeaderMap.Get("Content-Disposition")) + assert.Equal(t, "image/png", w.Header().Get("Content-Type")) + assert.Equal(t, strconv.Itoa(len(body)), w.Header().Get("Content-Length")) + assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition")) } diff --git a/routes_test.go b/routes_test.go index 23e749e2..60f1c81b 100644 --- a/routes_test.go +++ b/routes_test.go @@ -267,7 +267,7 @@ func TestRouteStaticFile(t *testing.T) { assert.Equal(t, w, w2) assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, "Gin Web Framework", w.Body.String()) - assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) w3 := performRequest(router, "HEAD", "/using_static/"+filename) w4 := performRequest(router, "HEAD", "/result") @@ -285,7 +285,7 @@ func TestRouteStaticListingDir(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "gin.go") - assert.Equal(t, "text/html; charset=utf-8", w.HeaderMap.Get("Content-Type")) + assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type")) } // TestHandleHeadToDir - ensure the root/sub dir handles properly @@ -312,10 +312,10 @@ func TestRouterMiddlewareAndStatic(t *testing.T) { assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), "package gin") - assert.Equal(t, "text/plain; charset=utf-8", w.HeaderMap.Get("Content-Type")) - assert.NotEqual(t, w.HeaderMap.Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST") - assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.HeaderMap.Get("Expires")) - assert.Equal(t, "Gin Framework", w.HeaderMap.Get("x-GIN")) + assert.Equal(t, "text/plain; charset=utf-8", w.Header().Get("Content-Type")) + assert.NotEqual(t, w.Header().Get("Last-Modified"), "Mon, 02 Jan 2006 15:04:05 MST") + assert.Equal(t, "Mon, 02 Jan 2006 15:04:05 MST", w.Header().Get("Expires")) + assert.Equal(t, "Gin Framework", w.Header().Get("x-GIN")) } func TestRouteNotAllowedEnabled(t *testing.T) { From 268e30710b77e1cd48b25df235cf702dc8e942a2 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 14 Oct 2018 11:05:24 +0800 Subject: [PATCH 29/34] fix(Makefile): golint to new URL (#1592) as title. Just update the golint to new URL. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 51b9969f..ea7b4f7c 100644 --- a/Makefile +++ b/Makefile @@ -43,7 +43,7 @@ embedmd: .PHONY: lint lint: @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u github.com/golang/lint/golint; \ + go get -u golang.org/x/lint/golint; \ fi for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; From 01ca2530d4b6c44c718b00c06f0e1d092572d49e Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Sun, 14 Oct 2018 12:39:16 +0800 Subject: [PATCH 30/34] refactor(Makefile): allow overriding default go program (#1593) --- Makefile | 28 ++++++++++++++++++---------- coverage.sh | 13 ------------- 2 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 coverage.sh diff --git a/Makefile b/Makefile index ea7b4f7c..c20429a1 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ +GO ?= go GOFMT ?= gofmt "-s" -PACKAGES ?= $(shell go list ./... | grep -v /vendor/) -VETPACKAGES ?= $(shell go list ./... | grep -v /vendor/ | grep -v /examples/) +PACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/) +VETPACKAGES ?= $(shell $(GO) list ./... | grep -v /vendor/ | grep -v /examples/) GOFILES := $(shell find . -name "*.go" -type f -not -path "./vendor/*") +TESTFOLDER := $(shell $(GO) list ./... | grep -E 'gin$$|binding$$|render$$' | grep -v examples) all: install @@ -10,7 +12,14 @@ install: deps .PHONY: test test: - sh coverage.sh + echo "mode: count" > coverage.out + for d in $(TESTFOLDER); do \ + $(GO) test -v -covermode=count -coverprofile=profile.out $$d; \ + if [ -f profile.out ]; then \ + cat profile.out | grep -v "mode:" >> coverage.out; \ + rm profile.out; \ + fi; \ + done .PHONY: fmt fmt: @@ -18,7 +27,6 @@ fmt: .PHONY: fmt-check fmt-check: - # get all go files and run go fmt on them @diff=$$($(GOFMT) -d $(GOFILES)); \ if [ -n "$$diff" ]; then \ echo "Please run 'make fmt' and commit the result:"; \ @@ -27,14 +35,14 @@ fmt-check: fi; vet: - go vet $(VETPACKAGES) + $(GO) vet $(VETPACKAGES) deps: @hash govendor > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u github.com/kardianos/govendor; \ + $(GO) get -u github.com/kardianos/govendor; \ fi @hash embedmd > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u github.com/campoy/embedmd; \ + $(GO) get -u github.com/campoy/embedmd; \ fi embedmd: @@ -43,20 +51,20 @@ embedmd: .PHONY: lint lint: @hash golint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u golang.org/x/lint/golint; \ + $(GO) get -u golang.org/x/lint/golint; \ fi for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; .PHONY: misspell-check misspell-check: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u github.com/client9/misspell/cmd/misspell; \ + $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -error $(GOFILES) .PHONY: misspell misspell: @hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ - go get -u github.com/client9/misspell/cmd/misspell; \ + $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -w $(GOFILES) diff --git a/coverage.sh b/coverage.sh deleted file mode 100644 index 4d1ee036..00000000 --- a/coverage.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -set -e - -echo "mode: count" > coverage.out - -for d in $(go list ./... | grep -E 'gin$|binding$|render$' | grep -v 'examples'); do - go test -v -covermode=count -coverprofile=profile.out $d - if [ -f profile.out ]; then - cat profile.out | grep -v "mode:" >> coverage.out - rm profile.out - fi -done From 523435e5245faade0a43a33bd3faab32456bab32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Mon, 15 Oct 2018 12:52:51 +0800 Subject: [PATCH 31/34] attempt to support go module (#1569) * support go module * update golint package url * update golint --- .travis.yml | 10 +++++++++- Makefile | 6 ++++++ go.mod | 13 ++++++++----- go.sum | 26 ++++++++++++++++---------- tools.go | 25 +++++++++++++++++++++++++ 5 files changed, 64 insertions(+), 16 deletions(-) create mode 100644 tools.go diff --git a/.travis.yml b/.travis.yml index a765f37f..2eeb0b3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,12 +11,20 @@ go: matrix: fast_finish: true + include: + - go: 1.11.x + env: GO111MODULE=on git: depth: 10 +before_install: + - if [[ "${GO111MODULE}" = "on" ]]; then mkdir "${HOME}/go"; export GOPATH="${HOME}/go"; fi + install: - - make install + - if [[ "${GO111MODULE}" = "on" ]]; then go mod download; else make install; fi + - if [[ "${GO111MODULE}" = "on" ]]; then export PATH="${GOPATH}/bin:${GOROOT}/bin:${PATH}"; fi + - if [[ "${GO111MODULE}" = "on" ]]; then make tools; fi go_import_path: github.com/gin-gonic/gin diff --git a/Makefile b/Makefile index c20429a1..b698ac09 100644 --- a/Makefile +++ b/Makefile @@ -68,3 +68,9 @@ misspell: $(GO) get -u github.com/client9/misspell/cmd/misspell; \ fi misspell -w $(GOFILES) + +.PHONY: tools +tools: + go install golang.org/x/lint/golint; \ + go install github.com/client9/misspell/cmd/misspell; \ + go install github.com/campoy/embedmd; diff --git a/go.mod b/go.mod index bd4ad975..0797b934 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,28 @@ module github.com/gin-gonic/gin require ( - github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16 // indirect + github.com/campoy/embedmd v0.0.0-20171205015432-c59ce00e0296 + github.com/client9/misspell v0.3.4 + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66 github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b github.com/golang/protobuf v1.2.0 github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 - github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b + github.com/json-iterator/go v1.1.5 github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 github.com/mattn/go-isatty v0.0.3 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 - github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6 + github.com/thinkerou/favicon v0.1.0 github.com/ugorji/go v1.1.1 - golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b + golang.org/x/crypto v0.0.0-20180927165925-5295e8364332 + golang.org/x/lint v0.0.0-20180702182130-06c8688daad7 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f - golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e // indirect + golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 // indirect google.golang.org/grpc v1.15.0 gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 diff --git a/go.sum b/go.sum index 3382beed..2d307e7e 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,10 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/campoy/embedmd v0.0.0-20171205015432-c59ce00e0296 h1:tRsilif6pbtt+PX6uRoyGd+qR+4ZPucFZLHlc3Ak6z8= +github.com/campoy/embedmd v0.0.0-20171205015432-c59ce00e0296/go.mod h1:/dBk8ICkslPCmyRdn4azP+QvBxL6Eg3EYxUGI9xMMFw= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16 h1:HqkufMBR7waVfFFRABWqHa1WgTvjtVDJTLJe3CR576A= -github.com/davecgh/go-spew v0.0.0-20180221232628-8991bc29aa16/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66 h1:QnnoVdChKs+GeTvN4rPYTW6b5U6M3HMEvQ/+x4IGtfY= github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66/go.mod h1:kTEh6M2J/mh7nsskr28alwLCXm/DSG5OSA/o31yy2XU= github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY= @@ -10,14 +13,15 @@ github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b h1:dm/NYytoj7p8J github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b/go.mod h1:vwfeXwKgEIWq63oVfwaBjoByS4dZzYbHHROHjV4IjNY= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 h1:cW/amwGEJK5MSKntPXRjX4dxs/nGxGT8gXKIsKFmHGc= github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15/go.mod h1:Fdm/oWRW+CH8PRbLntksCNtmcCBximKPkVQYvmMl80k= -github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b h1:X61dhFTE1Au92SvyF8HyAwdjWqiSdfBgFR7wTxC0+uU= -github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 h1:KIaAZ/V+/0/6BOULrmBQ9T1ed8BkKqGIjIKW923nJuo= github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227/go.mod h1:ruMr5t05gVho4tuDv0PbI0Bb8nOxc/5Y6JzRHe/yfA0= @@ -31,12 +35,13 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6 h1:d/LEgOfWe+AlOCz/kzmkvlO+gq9LRGhjSHqt2nx8Muc= -github.com/thinkerou/favicon v0.0.0-20170710140520-94a442a49da6/go.mod h1:HL7Pap5kOluZv1ku34pZo/AJ44GaxMEPFZ3pmuexV2s= +github.com/thinkerou/favicon v0.1.0 h1:eWMISKTpHq2G8HOuKn7ydD55j5DDehx94b0C2y8ABMs= +github.com/thinkerou/favicon v0.1.0/go.mod h1:HL7Pap5kOluZv1ku34pZo/AJ44GaxMEPFZ3pmuexV2s= github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= -golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b h1:2b9XGzhjiYsYPnKXoEfL7klWZQIt8IfyRCz62gCqqlQ= -golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180927165925-5295e8364332 h1:hvQVdF6P9DX4OiKA5tpehlG6JsgzmyQiThG7q5Bn3UQ= +golang.org/x/crypto v0.0.0-20180927165925-5295e8364332/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/lint v0.0.0-20180702182130-06c8688daad7 h1:00BeQWmeaGazuOrq8Q5K5d3/cHaGuFrZzpaHBXfrsUA= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -44,10 +49,11 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0= +golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= diff --git a/tools.go b/tools.go new file mode 100644 index 00000000..9f96406a --- /dev/null +++ b/tools.go @@ -0,0 +1,25 @@ +// Copyright 2018 Gin Core Team. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +// +build tools + +// This file exists to cause `go mod` and `go get` to believe these tools +// are dependencies, even though they are not runtime dependencies of any +// gin package. This means they will appear in `go.mod` file, but will not +// be a part of the build. + +package gin + +import ( + _ "github.com/campoy/embedmd" + _ "github.com/client9/misspell/cmd/misspell" + _ "github.com/dustin/go-broadcast" + _ "github.com/gin-gonic/autotls" + _ "github.com/jessevdk/go-assets" + _ "github.com/manucorporat/stats" + _ "github.com/thinkerou/favicon" + _ "golang.org/x/crypto/acme/autocert" + _ "golang.org/x/lint/golint" + _ "google.golang.org/grpc" +) From 98082fd590798eda8bdada82fd1550dfe6941964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Mon, 15 Oct 2018 13:01:44 +0800 Subject: [PATCH 32/34] document: add docs dir and middleware document (#1521) * init docs dir * add middleware document * fix indent * update docs --- docs/how-to-build-an-effective-middleware.md | 137 +++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 docs/how-to-build-an-effective-middleware.md diff --git a/docs/how-to-build-an-effective-middleware.md b/docs/how-to-build-an-effective-middleware.md new file mode 100644 index 00000000..db04428c --- /dev/null +++ b/docs/how-to-build-an-effective-middleware.md @@ -0,0 +1,137 @@ +# How to build one effective middleware? + +## Consitituent part + +The middleware has two parts: + + - part one is what is executed once, when you initalize your middleware. That's where you set up all the global objects, logicals etc. Everything that happens one per application lifetime. + + - part two is what executes on every request. For example, a database middleware you simply inject your "global" database object into the context. Once it's inside the context, you can retrieve it from within other middlewares and your handler furnction. + +```go +func funcName(params string) gin.HandlerFunc { + // <--- + // This is part one + // ---> + // The follow code is an example + if err := check(params); err != nil { + panic(err) + } + + return func(c *gin.Context) { + // <--- + // This is part two + // ---> + // The follow code is an example + c.Set("TestVar", params) + c.Next() + } +} +``` + +## Execution process + +Firstly, we have the follow example code: + +```go +func main() { + router := gin.Default() + + router.Use(globalMiddleware()) + + router.GET("/rest/n/api/*some", mid1(), mid2(), handler) + + router.Run() +} + +func globalMiddleware() gin.HandlerFunc { + fmt.Println("globalMiddleware...1") + + return func(c *gin.Context) { + fmt.Println("globalMiddleware...2") + c.Next() + fmt.Println("globalMiddleware...3") + } +} + +func handler(c *gin.Context) { + fmt.Println("exec handler.") +} + +func mid1() gin.HandlerFunc { + fmt.Println("mid1...1") + + return func(c *gin.Context) { + + fmt.Println("mid1...2") + c.Next() + fmt.Println("mid1...3") + } +} + +func mid2() gin.HandlerFunc { + fmt.Println("mid2...1") + + return func(c *gin.Context) { + fmt.Println("mid2...2") + c.Next() + fmt.Println("mid2...3") + } +} +``` + +According to [Consitituent part](#consitituent-part) said, when we run the gin process, **part one** will execute firstly and will print the follow information: + +```go +globalMiddleware...1 +mid1...1 +mid2...1 +``` + +And init order are: + +```go +globalMiddleware...1 + | + v +mid1...1 + | + v +mid2...1 +``` + +When we curl one request `curl -v localhost:8080/rest/n/api/some`, **part two** will execute their middleware and output the following information: + +```go +globalMiddleware...2 +mid1...2 +mid2...2 +exec handler. +mid2...3 +mid1...3 +globalMiddleware...3 +``` + +In other words, run order are: + +```go +globalMiddleware...2 + | + v +mid1...2 + | + v +mid2...2 + | + v +exec handler. + | + v +mid2...3 + | + v +mid1...3 + | + v +globalMiddleware...3 +``` From 524757b81c99e51a64e6ecc7ee0c181abc39bd79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Mon, 15 Oct 2018 20:24:32 +0800 Subject: [PATCH 33/34] vendor: upgrade some dependency package version (#1596) ref https://github.com/gin-gonic/gin/pull/1569#issuecomment-429731722 --- go.mod | 10 +++++----- go.sum | 19 ++++++++++--------- vendor/vendor.json | 43 +++++++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 0797b934..ef4103fd 100644 --- a/go.mod +++ b/go.mod @@ -11,18 +11,18 @@ require ( github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 github.com/json-iterator/go v1.1.5 github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 - github.com/mattn/go-isatty v0.0.3 + github.com/mattn/go-isatty v0.0.4 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.2.2 github.com/thinkerou/favicon v0.1.0 github.com/ugorji/go v1.1.1 - golang.org/x/crypto v0.0.0-20180927165925-5295e8364332 - golang.org/x/lint v0.0.0-20180702182130-06c8688daad7 - golang.org/x/net v0.0.0-20180826012351-8a410e7b638d + golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e + golang.org/x/lint v0.0.0-20181011164241-5906bd5c48cd + golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f - golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 // indirect + golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba // indirect google.golang.org/grpc v1.15.0 gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 diff --git a/go.sum b/go.sum index 2d307e7e..2ef7f13b 100644 --- a/go.sum +++ b/go.sum @@ -13,7 +13,6 @@ github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b h1:dm/NYytoj7p8J github.com/gin-gonic/autotls v0.0.0-20180426091246-be87bd5ef97b/go.mod h1:vwfeXwKgEIWq63oVfwaBjoByS4dZzYbHHROHjV4IjNY= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7 h1:2hRPrmiwPrp3fQX967rNJIhQPtiGXdlQWAxKbKw3VHA= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= @@ -25,8 +24,8 @@ github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 h1:KIaAZ/V+/0/6BOULrmBQ9T1ed8BkKqGIjIKW923nJuo= github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227/go.mod h1:ruMr5t05gVho4tuDv0PbI0Bb8nOxc/5Y6JzRHe/yfA0= -github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= @@ -39,18 +38,20 @@ github.com/thinkerou/favicon v0.1.0 h1:eWMISKTpHq2G8HOuKn7ydD55j5DDehx94b0C2y8AB github.com/thinkerou/favicon v0.1.0/go.mod h1:HL7Pap5kOluZv1ku34pZo/AJ44GaxMEPFZ3pmuexV2s= github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w= github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= -golang.org/x/crypto v0.0.0-20180927165925-5295e8364332 h1:hvQVdF6P9DX4OiKA5tpehlG6JsgzmyQiThG7q5Bn3UQ= -golang.org/x/crypto v0.0.0-20180927165925-5295e8364332/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7 h1:00BeQWmeaGazuOrq8Q5K5d3/cHaGuFrZzpaHBXfrsUA= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e h1:IzypfodbhbnViNUO/MEh0FzCUooG97cIGfdggUrUSyU= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I= +golang.org/x/lint v0.0.0-20181011164241-5906bd5c48cd h1:cgsAvzdqkDKdI02tIvDjO225vDPHMDCgfKqx5KEVI7U= +golang.org/x/lint v0.0.0-20181011164241-5906bd5c48cd/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1 h1:Y/KGZSOdz/2r0WJ9Mkmz6NJBusp0kiNx1Cn82lzJQ6w= +golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0= -golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba h1:nZJIJPGow0Kf9bU9QTc1U6OXbs/7Hu4e+cNv+hxH+Zc= +golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52 h1:JG/0uqcGdTNgq7FdU+61l5Pdmb8putNZlXb65bJBROs= diff --git a/vendor/vendor.json b/vendor/vendor.json index 86df11be..af1a0148 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -6,7 +6,9 @@ "checksumSHA1": "CSPbwbyzqA6sfORicn4HFtIhF/c=", "path": "github.com/davecgh/go-spew/spew", "revision": "8991bc29aa16c548c550c7ff78260e27b9ab7c73", - "revisionTime": "2018-02-21T22:46:20Z" + "revisionTime": "2018-02-21T22:46:20Z", + "version": "v1.1", + "versionExact": "v1.1.1" }, { "checksumSHA1": "QeKwBtN2df+j+4stw3bQJ6yO4EY=", @@ -15,12 +17,12 @@ "revisionTime": "2017-01-09T09:34:21Z" }, { - "checksumSHA1": "Pyou8mceOASSFxc7GeXZuVdSMi0=", + "checksumSHA1": "mE9XW26JSpe4meBObM6J/Oeq0eg=", "path": "github.com/golang/protobuf/proto", - "revision": "b4deda0973fb4c70b50d226b1af49f3da59f5265", - "revisionTime": "2018-04-30T18:52:41Z", - "version": "v1.1.0", - "versionExact": "v1.1.0" + "revision": "aa810b61a9c79d51363740d207bb46cf8e620ed5", + "revisionTime": "2018-08-14T21:14:27Z", + "version": "v1.2", + "versionExact": "v1.2.0" }, { "checksumSHA1": "WqeEgS7pqqkwK8mlrAZmDgtWJMY=", @@ -31,19 +33,19 @@ "versionExact": "v1.1.5" }, { - "checksumSHA1": "y/A5iuvwjytQE2CqVuphQRXR2nI=", + "checksumSHA1": "w5RcOnfv5YDr3j2bd1YydkPiZx4=", "path": "github.com/mattn/go-isatty", - "revision": "0360b2af4f38e8d38c7fce2a9f4e702702d73a39", - "revisionTime": "2017-09-25T05:34:41Z", - "version": "v0.0.3", - "versionExact": "v0.0.3" + "revision": "6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c", + "revisionTime": "2017-11-07T05:05:31Z", + "version": "v0.0", + "versionExact": "v0.0.4" }, { "checksumSHA1": "c6pbpF7eowwO59phRTpF8cQ80Z0=", "path": "github.com/stretchr/testify/assert", "revision": "f35b8ab0b5a2cef36673838d662e249dd9c94686", "revisionTime": "2018-05-06T18:05:49Z", - "version": "v1.2.2", + "version": "v1.2", "versionExact": "v1.2.2" }, { @@ -51,15 +53,20 @@ "path": "github.com/ugorji/go/codec", "revision": "b4c50a2b199d93b13dc15e78929cfb23bfdf21ab", "revisionTime": "2018-04-07T10:07:33Z", - "version": "v1.1.1", + "version": "v1.1", "versionExact": "v1.1.1" }, { - "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=", - "comment": "release-branch.go1.7", + "checksumSHA1": "GtamqiJoL7PGHsN454AoffBFMa8=", "path": "golang.org/x/net/context", - "revision": "d4c55e66d8c3a2f3382d264b08e3e3454a66355a", - "revisionTime": "2016-10-18T08:54:36Z" + "revision": "49bb7cea24b1df9410e1712aa6433dae904ff66a", + "revisionTime": "2018-10-11T05:27:23Z" + }, + { + "checksumSHA1": "SiJNkx+YGtq3Gtr6Ldu6OW83O+U=", + "path": "golang.org/x/sys/unix", + "revision": "fa43e7bc11baaae89f3f902b2b4d832b68234844", + "revisionTime": "2018-10-11T14:35:51Z" }, { "checksumSHA1": "P/k5ZGf0lEBgpKgkwy++F7K1PSg=", @@ -74,7 +81,7 @@ "path": "gopkg.in/yaml.v2", "revision": "5420a8b6744d3b0345ab293f6fcba19c978f1183", "revisionTime": "2018-03-28T19:50:20Z", - "version": "v2.2.1", + "version": "v2.2", "versionExact": "v2.2.1" } ], From cfa092f4f045d004b4c03d5b69af8bab7ed5fc1b Mon Sep 17 00:00:00 2001 From: Sergey Ponomarev Date: Tue, 16 Oct 2018 03:48:41 +0300 Subject: [PATCH 34/34] Fix LoadHTML* tests (#1559) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Digging into the test code base I've found out that some of the tests for `LoadHTML*` methods are not reliable and efficient. They use timeouts to be sure that goroutine with the server has started. And even more, in old implementation, the server started only once – all the new instances silently failed due to the occupied network port. Here is a short overview of the proposed changes: - it's not necessary to rely on timeouts, the server starts listening synchronously and returns control when it is ready - once the server is run, it's stopped after a test passes - dry out http server setup - magic with empty closure return is eliminated - preserve router.RunTLS coverage with integration tests --- gin_integration_test.go | 26 ++++- gin_test.go | 252 ++++++++++++++++++++++------------------ 2 files changed, 165 insertions(+), 113 deletions(-) diff --git a/gin_integration_test.go b/gin_integration_test.go index 12a943b0..038c8b7c 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -6,6 +6,7 @@ package gin import ( "bufio" + "crypto/tls" "fmt" "io/ioutil" "net" @@ -20,7 +21,14 @@ import ( ) func testRequest(t *testing.T, url string) { - resp, err := http.Get(url) + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } + client := &http.Client{Transport: tr} + + resp, err := client.Get(url) assert.NoError(t, err) defer resp.Body.Close() @@ -45,6 +53,22 @@ func TestRunEmpty(t *testing.T) { testRequest(t, "http://localhost:8080/example") } +func TestRunTLS(t *testing.T) { + router := New() + go func() { + router.GET("/example", func(c *Context) { c.String(http.StatusOK, "it worked") }) + + assert.NoError(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem")) + }() + + // have to wait for the goroutine to start and run the server + // otherwise the main thread will complete + time.Sleep(5 * time.Millisecond) + + assert.Error(t, router.RunTLS(":8443", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem")) + testRequest(t, "https://localhost:8443/example") +} + func TestRunEmptyWithEnv(t *testing.T) { os.Setenv("PORT", "3123") router := New() diff --git a/gin_test.go b/gin_test.go index 95b9cc16..353c9be1 100644 --- a/gin_test.go +++ b/gin_test.go @@ -10,6 +10,7 @@ import ( "html/template" "io/ioutil" "net/http" + "net/http/httptest" "reflect" "testing" "time" @@ -22,105 +23,105 @@ func formatAsDate(t time.Time) string { return fmt.Sprintf("%d/%02d/%02d", year, month, day) } -func setupHTMLFiles(t *testing.T, mode string, tls bool) func() { - go func() { - SetMode(mode) - router := New() - router.Delims("{[{", "}]}") - router.SetFuncMap(template.FuncMap{ - "formatAsDate": formatAsDate, +func setupHTMLFiles(t *testing.T, mode string, tls bool, loadMethod func(*Engine)) *httptest.Server { + SetMode(mode) + router := New() + router.Delims("{[{", "}]}") + router.SetFuncMap(template.FuncMap{ + "formatAsDate": formatAsDate, + }) + loadMethod(router) + router.GET("/test", func(c *Context) { + c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) + }) + router.GET("/raw", func(c *Context) { + c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ + "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), }) - router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") - router.GET("/test", func(c *Context) { - c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) - }) - router.GET("/raw", func(c *Context) { - c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ - "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), - }) - }) - if tls { - // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` - router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem") - } else { - router.Run(":8888") - } - }() - t.Log("waiting 1 second for server startup") - time.Sleep(1 * time.Second) - return func() {} + }) + + var ts *httptest.Server + + if tls { + ts = httptest.NewTLSServer(router) + } else { + ts = httptest.NewServer(router) + } + + return ts } -func setupHTMLGlob(t *testing.T, mode string, tls bool) func() { - go func() { - SetMode(mode) - router := New() - router.Delims("{[{", "}]}") - router.SetFuncMap(template.FuncMap{ - "formatAsDate": formatAsDate, - }) - router.LoadHTMLGlob("./testdata/template/*") - router.GET("/test", func(c *Context) { - c.HTML(http.StatusOK, "hello.tmpl", map[string]string{"name": "world"}) - }) - router.GET("/raw", func(c *Context) { - c.HTML(http.StatusOK, "raw.tmpl", map[string]interface{}{ - "now": time.Date(2017, 07, 01, 0, 0, 0, 0, time.UTC), - }) - }) - if tls { - // these files generated by `go run $GOROOT/src/crypto/tls/generate_cert.go --host 127.0.0.1` - router.RunTLS(":9999", "./testdata/certificate/cert.pem", "./testdata/certificate/key.pem") - } else { - router.Run(":8888") - } - }() - t.Log("waiting 1 second for server startup") - time.Sleep(1 * time.Second) - return func() {} -} +func TestLoadHTMLGlobDebugMode(t *testing.T) { + ts := setupHTMLFiles( + t, + DebugMode, + false, + func(router *Engine) { + router.LoadHTMLGlob("./testdata/template/*") + }, + ) + defer ts.Close() -func TestLoadHTMLGlob(t *testing.T) { - td := setupHTMLGlob(t, DebugMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - - td() } -func TestLoadHTMLGlob2(t *testing.T) { - td := setupHTMLGlob(t, TestMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") +func TestLoadHTMLGlobTestMode(t *testing.T) { + ts := setupHTMLFiles( + t, + TestMode, + false, + func(router *Engine) { + router.LoadHTMLGlob("./testdata/template/*") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - - td() } -func TestLoadHTMLGlob3(t *testing.T) { - td := setupHTMLGlob(t, ReleaseMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") +func TestLoadHTMLGlobReleaseMode(t *testing.T) { + ts := setupHTMLFiles( + t, + ReleaseMode, + false, + func(router *Engine) { + router.LoadHTMLGlob("./testdata/template/*") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - - td() } func TestLoadHTMLGlobUsingTLS(t *testing.T) { - td := setupHTMLGlob(t, DebugMode, true) + ts := setupHTMLFiles( + t, + DebugMode, + true, + func(router *Engine) { + router.LoadHTMLGlob("./testdata/template/*") + }, + ) + defer ts.Close() + // Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error tr := &http.Transport{ TLSClientConfig: &tls.Config{ @@ -128,29 +129,33 @@ func TestLoadHTMLGlobUsingTLS(t *testing.T) { }, } client := &http.Client{Transport: tr} - res, err := client.Get("https://127.0.0.1:9999/test") + res, err := client.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - - td() } func TestLoadHTMLGlobFromFuncMap(t *testing.T) { - time.Now() - td := setupHTMLGlob(t, DebugMode, false) - res, err := http.Get("http://127.0.0.1:8888/raw") + ts := setupHTMLFiles( + t, + DebugMode, + false, + func(router *Engine) { + router.LoadHTMLGlob("./testdata/template/*") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "Date: 2017/07/01\n", string(resp)) - - td() } func init() { @@ -164,59 +169,77 @@ func TestCreateEngine(t *testing.T) { assert.Empty(t, router.Handlers) } -// func TestLoadHTMLDebugMode(t *testing.T) { -// router := New() -// SetMode(DebugMode) -// router.LoadHTMLGlob("*.testtmpl") -// r := router.HTMLRender.(render.HTMLDebug) -// assert.Empty(t, r.Files) -// assert.Equal(t, "*.testtmpl", r.Glob) -// -// router.LoadHTMLFiles("index.html.testtmpl", "login.html.testtmpl") -// r = router.HTMLRender.(render.HTMLDebug) -// assert.Empty(t, r.Glob) -// assert.Equal(t, []string{"index.html", "login.html"}, r.Files) -// SetMode(TestMode) -// } +func TestLoadHTMLFilesTestMode(t *testing.T) { + ts := setupHTMLFiles( + t, + TestMode, + false, + func(router *Engine) { + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") + }, + ) + defer ts.Close() -func TestLoadHTMLFiles(t *testing.T) { - td := setupHTMLFiles(t, TestMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - td() } -func TestLoadHTMLFiles2(t *testing.T) { - td := setupHTMLFiles(t, DebugMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") +func TestLoadHTMLFilesDebugMode(t *testing.T) { + ts := setupHTMLFiles( + t, + DebugMode, + false, + func(router *Engine) { + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - td() } -func TestLoadHTMLFiles3(t *testing.T) { - td := setupHTMLFiles(t, ReleaseMode, false) - res, err := http.Get("http://127.0.0.1:8888/test") +func TestLoadHTMLFilesReleaseMode(t *testing.T) { + ts := setupHTMLFiles( + t, + ReleaseMode, + false, + func(router *Engine) { + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - td() } func TestLoadHTMLFilesUsingTLS(t *testing.T) { - td := setupHTMLFiles(t, TestMode, true) + ts := setupHTMLFiles( + t, + TestMode, + true, + func(router *Engine) { + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") + }, + ) + defer ts.Close() + // Use InsecureSkipVerify for avoiding `x509: certificate signed by unknown authority` error tr := &http.Transport{ TLSClientConfig: &tls.Config{ @@ -224,28 +247,33 @@ func TestLoadHTMLFilesUsingTLS(t *testing.T) { }, } client := &http.Client{Transport: tr} - res, err := client.Get("https://127.0.0.1:9999/test") + res, err := client.Get(fmt.Sprintf("%s/test", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "

Hello world

", string(resp)) - td() } func TestLoadHTMLFilesFuncMap(t *testing.T) { - time.Now() - td := setupHTMLFiles(t, TestMode, false) - res, err := http.Get("http://127.0.0.1:8888/raw") + ts := setupHTMLFiles( + t, + TestMode, + false, + func(router *Engine) { + router.LoadHTMLFiles("./testdata/template/hello.tmpl", "./testdata/template/raw.tmpl") + }, + ) + defer ts.Close() + + res, err := http.Get(fmt.Sprintf("%s/raw", ts.URL)) if err != nil { fmt.Println(err) } resp, _ := ioutil.ReadAll(res.Body) assert.Equal(t, "Date: 2017/07/01\n", string(resp)) - - td() } func TestAddRoute(t *testing.T) {