From d27685e714cb0b9375e0c9d3ca3df5a6a4945a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Sat, 26 Jan 2019 02:28:39 +0800 Subject: [PATCH 01/18] chore: attempt to fix some gomod issue (#1751) #1604 #1566 #1700 #1737 because some dependencies only are used on example i.e. grpc. Or migrate `examples` to gin-gonic/examples`? --- go.mod | 39 +++++++++++++++--------------- go.sum | 64 ++++++++++++++++++-------------------------------- tools/tools.go | 25 -------------------- 3 files changed, 43 insertions(+), 85 deletions(-) delete mode 100644 tools/tools.go diff --git a/go.mod b/go.mod index ef4103fd..54573a8b 100644 --- a/go.mod +++ b/go.mod @@ -1,30 +1,31 @@ module github.com/gin-gonic/gin require ( - 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/gin-contrib/sse v0.0.0-20190124093953-61b50c2ef482 github.com/golang/protobuf v1.2.0 - 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.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-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-20181011152604-fa43e7bc11ba // indirect - google.golang.org/grpc v1.15.0 + github.com/stretchr/testify v1.3.0 + github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 + golang.org/x/net v0.0.0-20190119204137-ed066c81e75e + golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 + golang.org/x/sys v0.0.0-20190124100055-b90733256f2e // indirect 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 + gopkg.in/yaml.v2 v2.2.2 +) + +exclude ( + github.com/campoy/embedmd v0.0.0-20181127031020-97c13d6e4160 + github.com/client9/misspell v0.3.4 + github.com/dustin/go-broadcast v0.0.0-20171205050544-f664265f5a66 + github.com/gin-gonic/autotls v0.0.0-20190119125636-0b5f4fc15768 + github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 + github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 + github.com/thinkerou/favicon v0.1.0 + golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b + golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 + google.golang.org/grpc v1.18.0 ) diff --git a/go.sum b/go.sum index 2ef7f13b..95e2b4f6 100644 --- a/go.sum +++ b/go.sum @@ -1,72 +1,54 @@ 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/campoy/embedmd v0.0.0-20181127031020-97c13d6e4160 h1:HJpuhXOHC4EkXDARsLjmXAV9FhlY6qFDnKI/MJM6eoE= +github.com/campoy/embedmd v0.0.0-20181127031020-97c13d6e4160/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= 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 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= -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/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gin-contrib/sse v0.0.0-20190124093953-61b50c2ef482 h1:iOz5sIQUvuOlpiC7Q6+MmJQpWnlneYX98QIGf+2m50Y= +github.com/gin-contrib/sse v0.0.0-20190124093953-61b50c2ef482/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= 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 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= 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= 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.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-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/lint v0.0.0-20181011164241-5906bd5c48cd h1:cgsAvzdqkDKdI02tIvDjO225vDPHMDCgfKqx5KEVI7U= -golang.org/x/lint v0.0.0-20181011164241-5906bd5c48cd/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2 h1:EICbibRW4JNKMcY+LsWmuwob+CRS1BmdRdjphAm9mH4= +github.com/ugorji/go/codec v0.0.0-20181209151446-772ced7fd4c2/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3 h1:x/bBzNauLQAlE3fLku/xy92Y8QwKX5HZymrMz2IiKFc= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/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/net v0.0.0-20190119204137-ed066c81e75e h1:MDa3fSUp6MdYHouVmCCNz/zaH2a6CRcxY3VhT/K3C5Q= +golang.org/x/net v0.0.0-20190119204137-ed066c81e75e/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/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/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-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/sys v0.0.0-20190124100055-b90733256f2e h1:3GIlrlVLfkoipSReOMNAgApI0ajnalyLa/EZHHca/XI= +golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/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= 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= +google.golang.org/grpc v1.18.0 h1:IZl7mfBGfbhYx2p2rKRtYgDFw6SBz+kclmxYrCksPPA= +google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= 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= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/tools/tools.go b/tools/tools.go deleted file mode 100644 index 7113e71e..00000000 --- a/tools/tools.go +++ /dev/null @@ -1,25 +0,0 @@ -// 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 package 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 tools - -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 5acf6601170bb49a1958c055d66d54ba152dc34b Mon Sep 17 00:00:00 2001 From: Dmitry Kutakov Date: Mon, 4 Feb 2019 04:27:00 +0300 Subject: [PATCH 02/18] fix travis freeze on concurrent test (#1761) --- gin_integration_test.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/gin_integration_test.go b/gin_integration_test.go index 3ce6d80a..b80cbb24 100644 --- a/gin_integration_test.go +++ b/gin_integration_test.go @@ -188,15 +188,12 @@ func TestConcurrentHandleContext(t *testing.T) { }) 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+"/") + testGetRequestHandler(t, router, "/") wg.Done() }() } @@ -217,3 +214,14 @@ func TestConcurrentHandleContext(t *testing.T) { // testRequest(t, "http://localhost:8033/example") // } + +func testGetRequestHandler(t *testing.T, h http.Handler, url string) { + req, err := http.NewRequest("GET", url, nil) + assert.NoError(t, err) + + w := httptest.NewRecorder() + h.ServeHTTP(w, req) + + assert.Equal(t, "it worked", w.Body.String(), "resp body should match") + assert.Equal(t, 200, w.Code, "should get a 200") +} From a768f064d53c8010d902533927441be13b1bfe17 Mon Sep 17 00:00:00 2001 From: Dmitry Kutakov Date: Mon, 18 Feb 2019 04:35:08 +0300 Subject: [PATCH 03/18] fix many redirects (#1760) (#1764) * fix many redirects (#1760) * fix @thinkerou review --- gin.go | 3 +++ gin_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/gin.go b/gin.go index cd47200f..6e5ea6d7 100644 --- a/gin.go +++ b/gin.go @@ -355,8 +355,11 @@ func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { // This can be done by setting c.Request.URL.Path to your new target. // Disclaimer: You can loop yourself to death with this, use wisely. func (engine *Engine) HandleContext(c *Context) { + oldIndexValue := c.index c.reset() engine.handleHTTPRequest(c) + + c.index = oldIndexValue } func (engine *Engine) handleHTTPRequest(c *Context) { diff --git a/gin_test.go b/gin_test.go index e013df09..f9a1c6f5 100644 --- a/gin_test.go +++ b/gin_test.go @@ -12,6 +12,8 @@ import ( "net/http" "net/http/httptest" "reflect" + "strconv" + "sync/atomic" "testing" "time" @@ -488,6 +490,43 @@ func TestEngineHandleContext(t *testing.T) { }) } +func TestEngineHandleContextManyReEntries(t *testing.T) { + expectValue := 10000 + + var handlerCounter, middlewareCounter int64 + + r := New() + r.Use(func(c *Context) { + atomic.AddInt64(&middlewareCounter, 1) + }) + r.GET("/:count", func(c *Context) { + countStr := c.Param("count") + count, err := strconv.Atoi(countStr) + assert.NoError(t, err) + + n, err := c.Writer.Write([]byte(".")) + assert.NoError(t, err) + assert.Equal(t, 1, n) + + switch { + case count > 0: + c.Request.URL.Path = "/" + strconv.Itoa(count-1) + r.HandleContext(c) + } + }, func(c *Context) { + atomic.AddInt64(&handlerCounter, 1) + }) + + assert.NotPanics(t, func() { + w := performRequest(r, "GET", "/"+strconv.Itoa(expectValue-1)) // include 0 value + assert.Equal(t, 200, w.Code) + assert.Equal(t, expectValue, w.Body.Len()) + }) + + assert.Equal(t, int64(expectValue), handlerCounter) + assert.Equal(t, int64(expectValue), middlewareCounter) +} + func assertRoutePresent(t *testing.T, gotRoutes RoutesInfo, wantRoute RouteInfo) { for _, gotRoute := range gotRoutes { if gotRoute.Path == wantRoute.Path && gotRoute.Method == wantRoute.Method { From 31bbb10f34e4673815ab66099571bac95cf4113d Mon Sep 17 00:00:00 2001 From: Dmitry Kutakov Date: Mon, 18 Feb 2019 05:10:45 +0300 Subject: [PATCH 04/18] Make silent debug info on tests (#1765) * make silent log on tests * fix coverage: check end-of-line at the end of debug msg --- debug_test.go | 2 +- deprecated_test.go | 4 +++- gin_test.go | 29 +++++++++++++++++------------ githubapi_test.go | 10 +++++----- recovery_test.go | 1 + 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/debug_test.go b/debug_test.go index b3485d70..d338f0a0 100644 --- a/debug_test.go +++ b/debug_test.go @@ -39,7 +39,7 @@ func TestDebugPrint(t *testing.T) { SetMode(TestMode) debugPrint("DEBUG this!") SetMode(DebugMode) - debugPrint("these are %d %s\n", 2, "error messages") + debugPrint("these are %d %s", 2, "error messages") SetMode(TestMode) }) assert.Equal(t, "[GIN-debug] these are 2 error messages\n", re) diff --git a/deprecated_test.go b/deprecated_test.go index 7a875fe4..f8df651c 100644 --- a/deprecated_test.go +++ b/deprecated_test.go @@ -24,7 +24,9 @@ func TestBindWith(t *testing.T) { Foo string `form:"foo"` Bar string `form:"bar"` } - assert.NoError(t, c.BindWith(&obj, binding.Form)) + captureOutput(t, func() { + assert.NoError(t, c.BindWith(&obj, binding.Form)) + }) assert.Equal(t, "foo", obj.Bar) assert.Equal(t, "bar", obj.Foo) assert.Equal(t, 0, w.Body.Len()) diff --git a/gin_test.go b/gin_test.go index f9a1c6f5..11bdd79c 100644 --- a/gin_test.go +++ b/gin_test.go @@ -27,18 +27,23 @@ func formatAsDate(t time.Time) string { 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), + defer SetMode(TestMode) + + var router *Engine + captureOutput(t, func() { + 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), + }) }) }) diff --git a/githubapi_test.go b/githubapi_test.go index 50faca09..29aa1584 100644 --- a/githubapi_test.go +++ b/githubapi_test.go @@ -287,7 +287,7 @@ var githubAPI = []route{ func TestShouldBindUri(t *testing.T) { DefaultWriter = os.Stdout - router := Default() + router := New() type Person struct { Name string `uri:"name" binding:"required"` @@ -309,7 +309,7 @@ func TestShouldBindUri(t *testing.T) { func TestBindUri(t *testing.T) { DefaultWriter = os.Stdout - router := Default() + router := New() type Person struct { Name string `uri:"name" binding:"required"` @@ -331,7 +331,7 @@ func TestBindUri(t *testing.T) { func TestBindUriError(t *testing.T) { DefaultWriter = os.Stdout - router := Default() + router := New() type Member struct { Number string `uri:"num" binding:"required,uuid"` @@ -361,7 +361,7 @@ func githubConfigRouter(router *Engine) { func TestGithubAPI(t *testing.T) { DefaultWriter = os.Stdout - router := Default() + router := New() githubConfigRouter(router) for _, route := range githubAPI { @@ -436,7 +436,7 @@ func BenchmarkParallelGithub(b *testing.B) { func BenchmarkParallelGithubDefault(b *testing.B) { DefaultWriter = os.Stdout - router := Default() + router := New() githubConfigRouter(router) req, _ := http.NewRequest("POST", "/repos/manucorporat/sse/git/blobs", nil) diff --git a/recovery_test.go b/recovery_test.go index e886eaac..0a6d6271 100644 --- a/recovery_test.go +++ b/recovery_test.go @@ -43,6 +43,7 @@ func TestPanicInHandler(t *testing.T) { assert.Equal(t, http.StatusInternalServerError, w.Code) assert.Contains(t, buffer.String(), "GET /recovery") + SetMode(TestMode) } // TestPanicWithAbort assert that panic has been recovered even if context.Abort was used. From 5846ceba8b1074c4555491ef4df2a54e75442358 Mon Sep 17 00:00:00 2001 From: awkj Date: Wed, 20 Feb 2019 00:02:37 +0800 Subject: [PATCH 05/18] add notify accept signal (#1740) * add notify accept signal * add import * update readme,keep same with example --- README.md | 6 +++++- examples/graceful-shutdown/graceful-shutdown/server.go | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0dcaa8e9..3da8785b 100644 --- a/README.md +++ b/README.md @@ -1633,6 +1633,7 @@ import ( "net/http" "os" "os/signal" + "syscall" "time" "github.com/gin-gonic/gin" @@ -1660,7 +1661,10 @@ func main() { // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) - signal.Notify(quit, os.Interrupt) + // kill (no param) default send syscanll.SIGTERM + // kill -2 is syscall.SIGINT + // kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown Server ...") diff --git a/examples/graceful-shutdown/graceful-shutdown/server.go b/examples/graceful-shutdown/graceful-shutdown/server.go index af4f2146..33be0c8f 100644 --- a/examples/graceful-shutdown/graceful-shutdown/server.go +++ b/examples/graceful-shutdown/graceful-shutdown/server.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "os/signal" + "syscall" "time" "github.com/gin-gonic/gin" @@ -35,7 +36,10 @@ func main() { // Wait for interrupt signal to gracefully shutdown the server with // a timeout of 5 seconds. quit := make(chan os.Signal) - signal.Notify(quit, os.Interrupt) + // kill (no param) default send syscanll.SIGTERM + // kill -2 is syscall.SIGINT + // kill -9 is syscall. SIGKILL but can"t be catch, so don't need add it + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit log.Println("Shutdown Server ...") From fece76d93fd65f795bea75f59fb5e3e03320dc6d Mon Sep 17 00:00:00 2001 From: Jeremy Loy Date: Tue, 19 Feb 2019 21:41:46 -0500 Subject: [PATCH 06/18] Add NewRelic middleware example. (#1526) * Add NewRelic middleware example. * Update go.mod * Update main.go --- examples/new_relic/README.md | 30 ++++++++++++++++++++++++++ examples/new_relic/main.go | 42 ++++++++++++++++++++++++++++++++++++ go.mod | 1 + 3 files changed, 73 insertions(+) create mode 100644 examples/new_relic/README.md create mode 100644 examples/new_relic/main.go diff --git a/examples/new_relic/README.md b/examples/new_relic/README.md new file mode 100644 index 00000000..70f14942 --- /dev/null +++ b/examples/new_relic/README.md @@ -0,0 +1,30 @@ +The [New Relic Go Agent](https://github.com/newrelic/go-agent) provides a nice middleware for the stdlib handler signature. +The following is an adaptation of that middleware for Gin. + +```golang +const ( + // NewRelicTxnKey is the key used to retrieve the NewRelic Transaction from the context + NewRelicTxnKey = "NewRelicTxnKey" +) + +// NewRelicMonitoring is a middleware that starts a newrelic transaction, stores it in the context, then calls the next handler +func NewRelicMonitoring(app newrelic.Application) gin.HandlerFunc { + return func(ctx *gin.Context) { + txn := app.StartTransaction(ctx.Request.URL.Path, ctx.Writer, ctx.Request) + defer txn.End() + ctx.Set(NewRelicTxnKey, txn) + ctx.Next() + } +} +``` +and in `main.go` or equivalent... +```golang +router := gin.Default() +cfg := newrelic.NewConfig(os.Getenv("APP_NAME"), os.Getenv("NEW_RELIC_API_KEY")) +app, err := newrelic.NewApplication(cfg) +if err != nil { + log.Printf("failed to make new_relic app: %v", err) +} else { + router.Use(adapters.NewRelicMonitoring(app)) +} + ``` diff --git a/examples/new_relic/main.go b/examples/new_relic/main.go new file mode 100644 index 00000000..f85f7831 --- /dev/null +++ b/examples/new_relic/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "log" + "net/http" + "os" + + "github.com/gin-gonic/gin" + "github.com/newrelic/go-agent" +) + +const ( + // NewRelicTxnKey is the key used to retrieve the NewRelic Transaction from the context + NewRelicTxnKey = "NewRelicTxnKey" +) + +// NewRelicMonitoring is a middleware that starts a newrelic transaction, stores it in the context, then calls the next handler +func NewRelicMonitoring(app newrelic.Application) gin.HandlerFunc { + return func(ctx *gin.Context) { + txn := app.StartTransaction(ctx.Request.URL.Path, ctx.Writer, ctx.Request) + defer txn.End() + ctx.Set(NewRelicTxnKey, txn) + ctx.Next() + } +} + +func main() { + router := gin.Default() + + cfg := newrelic.NewConfig(os.Getenv("APP_NAME"), os.Getenv("NEW_RELIC_API_KEY")) + app, err := newrelic.NewApplication(cfg) + if err != nil { + log.Printf("failed to make new_relic app: %v", err) + } else { + router.Use(NewRelicMonitoring(app)) + } + + router.GET("/", func(c *gin.Context) { + c.String(http.StatusOK, "Hello World!\n") + }) + router.Run() +} diff --git a/go.mod b/go.mod index 54573a8b..6f9d68d1 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,7 @@ exclude ( github.com/gin-gonic/autotls v0.0.0-20190119125636-0b5f4fc15768 github.com/jessevdk/go-assets v0.0.0-20160921144138-4f4301a06e15 github.com/manucorporat/stats v0.0.0-20180402194714-3ba42d56d227 + github.com/newrelic/go-agent v2.5.0+incompatible github.com/thinkerou/favicon v0.1.0 golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 From 90587c7787a37e3b32375627717b936a17ab8e94 Mon Sep 17 00:00:00 2001 From: ffhelicopter <32922889+ffhelicopter@users.noreply.github.com> Date: Wed, 20 Feb 2019 13:24:29 +0800 Subject: [PATCH 07/18] Update: examples/graceful-shutdown/server.go (#1530) * Update server.go It's necessary that catching ctx.Done() * Update server.go * Update server.go * Update README.md * Update README.md --- README.md | 5 +++++ examples/graceful-shutdown/graceful-shutdown/server.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/README.md b/README.md index 3da8785b..90f6e1d1 100644 --- a/README.md +++ b/README.md @@ -1673,6 +1673,11 @@ func main() { if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } + // catching ctx.Done(). timeout of 5 seconds. + select { + case <-ctx.Done(): + log.Println("timeout of 5 seconds.") + } log.Println("Server exiting") } ``` diff --git a/examples/graceful-shutdown/graceful-shutdown/server.go b/examples/graceful-shutdown/graceful-shutdown/server.go index 33be0c8f..999a209e 100644 --- a/examples/graceful-shutdown/graceful-shutdown/server.go +++ b/examples/graceful-shutdown/graceful-shutdown/server.go @@ -48,5 +48,10 @@ func main() { if err := srv.Shutdown(ctx); err != nil { log.Fatal("Server Shutdown:", err) } + // catching ctx.Done(). timeout of 5 seconds. + select { + case <-ctx.Done(): + log.Println("timeout of 5 seconds.") + } log.Println("Server exiting") } From a58a2f9bf368a7976d26dba4c16c90fad4c1db6e Mon Sep 17 00:00:00 2001 From: Olivier Robardet Date: Wed, 20 Feb 2019 14:14:16 +0100 Subject: [PATCH 08/18] Add a function to force color in console output (#1724) Add a function `ForceConsoleColor`, like `DisableConsoleColor` but to force coloring the output. It usefull when some IDE's integrated console (like IntelliJ or Goland) are not detected as TTY, but can display colors. Also helps if one want to output color in log file (#1590) and as a workaround for #1547. --- README.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- logger.go | 10 ++++++++-- logger_test.go | 7 +++++++ 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 90f6e1d1..058eee2a 100644 --- a/README.md +++ b/README.md @@ -215,9 +215,6 @@ $ go build -tags=jsoniter . ```go func main() { - // Disable Console Color - // gin.DisableConsoleColor() - // Creates a gin router with default middleware: // logger and recovery (crash-free) middleware router := gin.Default() @@ -570,6 +567,48 @@ func main() { ::1 - [Fri, 07 Dec 2018 17:04:38 JST] "GET /ping HTTP/1.1 200 122.767µs "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36" " ``` +### Controlling Log output coloring + +By default, logs output on console should be colorized depending on the detected TTY. + +Never colorize logs: + +```go +func main() { + // Disable log's color + gin.DisableConsoleColor() + + // Creates a gin router with default middleware: + // logger and recovery (crash-free) middleware + router := gin.Default() + + router.GET("/ping", func(c *gin.Context) { + c.String(200, "pong") + }) + + router.Run(":8080") +} +``` + +Always colorize logs: + +```go +func main() { + // Force log's color + gin.ForceConsoleColor() + + // Creates a gin router with default middleware: + // logger and recovery (crash-free) middleware + router := gin.Default() + + router.GET("/ping", func(c *gin.Context) { + c.String(200, "pong") + }) + + router.Run(":8080") +} +``` + ### Model binding and validation To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz). diff --git a/logger.go b/logger.go index d2869f51..6d8f838e 100644 --- a/logger.go +++ b/logger.go @@ -24,6 +24,7 @@ var ( cyan = string([]byte{27, 91, 57, 55, 59, 52, 54, 109}) reset = string([]byte{27, 91, 48, 109}) disableColor = false + forceColor = false ) // LoggerConfig defines the config for Logger middleware. @@ -90,6 +91,11 @@ func DisableConsoleColor() { disableColor = true } +// ForceConsoleColor force color output in the console. +func ForceConsoleColor() { + forceColor = true +} + // ErrorLogger returns a handlerfunc for any error type. func ErrorLogger() HandlerFunc { return ErrorLoggerT(ErrorTypeAny) @@ -144,9 +150,9 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc { isTerm := true - if w, ok := out.(*os.File); !ok || + if w, ok := out.(*os.File); (!ok || (os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd()))) || - disableColor { + disableColor) && !forceColor { isTerm = false } diff --git a/logger_test.go b/logger_test.go index d0169251..8770b5fb 100644 --- a/logger_test.go +++ b/logger_test.go @@ -340,3 +340,10 @@ func TestDisableConsoleColor(t *testing.T) { DisableConsoleColor() assert.True(t, disableColor) } + +func TestForceConsoleColor(t *testing.T) { + New() + assert.False(t, forceColor) + ForceConsoleColor() + assert.True(t, forceColor) +} From e6886e1539d89365f9970e1b5d9af1a2ccea16d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Thu, 21 Feb 2019 20:32:55 +0800 Subject: [PATCH 09/18] chore: fix Make script when failed (#1774) --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7211144a..7ab57e27 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,10 @@ test: exit 1; \ elif grep -q "build failed" tmp.out; then \ rm tmp.out; \ - exit; \ + exit 1; \ + elif grep -q "setup failed" tmp.out; then \ + rm tmp.out; \ + exit 1; \ fi; \ if [ -f profile.out ]; then \ cat profile.out | grep -v "mode:" >> coverage.out; \ From 4e86b17e734074af0317f9b0c40167f45fd0ca91 Mon Sep 17 00:00:00 2001 From: Mara Kim Date: Thu, 21 Feb 2019 22:45:32 -0500 Subject: [PATCH 10/18] Set socket to recieve writes (#1134) * Set socket to recieve writes * Update gin.go --- gin.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gin.go b/gin.go index 6e5ea6d7..ad64c35f 100644 --- a/gin.go +++ b/gin.go @@ -318,6 +318,7 @@ func (engine *Engine) RunUnix(file string) (err error) { return } defer listener.Close() + os.Chmod(file, 0777) err = http.Serve(listener, engine) return } From 48f6c6137c9e326dc0aea110a43ad5a7a590073e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bazaglia?= Date: Fri, 22 Feb 2019 01:23:52 -0300 Subject: [PATCH 11/18] allow ignoring field on form mapping (#1733) --- binding/binding_test.go | 25 +++++++++++++++++++++++++ binding/form_mapping.go | 3 +++ 2 files changed, 28 insertions(+) diff --git a/binding/binding_test.go b/binding/binding_test.go index 1044e6c2..c9dea347 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -61,6 +61,10 @@ type FooStructForMapType struct { MapFoo map[string]interface{} `form:"map_foo"` } +type FooStructForIgnoreFormTag struct { + Foo *string `form:"-"` +} + type InvalidNameType struct { TestName string `invalid_name:"test_name"` } @@ -278,6 +282,12 @@ func TestBindingFormForTime2(t *testing.T) { "", "") } +func TestFormBindingIgnoreField(t *testing.T) { + testFormBindingIgnoreField(t, "POST", + "/", "/", + "-=bar", "") +} + func TestBindingFormInvalidName(t *testing.T) { testFormBindingInvalidName(t, "POST", "/", "/", @@ -860,6 +870,21 @@ func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, bod assert.Error(t, err) } +func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) { + b := Form + assert.Equal(t, "form", b.Name()) + + obj := FooStructForIgnoreFormTag{} + req := requestWithBody(method, path, body) + if method == "POST" { + req.Header.Add("Content-Type", MIMEPOSTForm) + } + err := b.Bind(req, &obj) + assert.NoError(t, err) + + assert.Nil(t, obj.Foo) +} + func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBody string) { b := Form assert.Equal(t, "form", b.Name()) diff --git a/binding/form_mapping.go b/binding/form_mapping.go index 8900ab70..8eb5c0d1 100644 --- a/binding/form_mapping.go +++ b/binding/form_mapping.go @@ -41,6 +41,9 @@ func mapFormByTag(ptr interface{}, form map[string][]string, tag string) error { defaultValue = defaultList[1] } } + if inputFieldName == "-" { + continue + } if inputFieldName == "" { inputFieldName = typeField.Name From d7daffc26b212514adb756e1ba807a6b8242dd37 Mon Sep 17 00:00:00 2001 From: David Zhang Date: Fri, 22 Feb 2019 12:53:47 +0800 Subject: [PATCH 12/18] Use camel case instead of ALL_CAPS (#1419) * Use camel case instead of ALL_CAPS * Update mode.go --- mode.go | 6 +++--- mode_test.go | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mode.go b/mode.go index f787b5ca..8aa84aa8 100644 --- a/mode.go +++ b/mode.go @@ -11,8 +11,8 @@ import ( "github.com/gin-gonic/gin/binding" ) -// ENV_GIN_MODE indicates environment name for gin mode. -const ENV_GIN_MODE = "GIN_MODE" +// EnvGinMode indicates environment name for gin mode. +const EnvGinMode = "GIN_MODE" const ( // DebugMode indicates gin mode is debug. @@ -44,7 +44,7 @@ var ginMode = debugCode var modeName = DebugMode func init() { - mode := os.Getenv(ENV_GIN_MODE) + mode := os.Getenv(EnvGinMode) SetMode(mode) } diff --git a/mode_test.go b/mode_test.go index cf27acd8..3dba5150 100644 --- a/mode_test.go +++ b/mode_test.go @@ -13,13 +13,13 @@ import ( ) func init() { - os.Setenv(ENV_GIN_MODE, TestMode) + os.Setenv(EnvGinMode, TestMode) } func TestSetMode(t *testing.T) { assert.Equal(t, testCode, ginMode) assert.Equal(t, TestMode, Mode()) - os.Unsetenv(ENV_GIN_MODE) + os.Unsetenv(EnvGinMode) SetMode("") assert.Equal(t, debugCode, ginMode) From 184661cfa2f5ad6000c9893a0ffba8da8c1bd2ec Mon Sep 17 00:00:00 2001 From: Pierre Massat Date: Thu, 21 Feb 2019 21:12:05 -0800 Subject: [PATCH 13/18] Add response size to LogFormatterParams (#1752) --- logger.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/logger.go b/logger.go index 6d8f838e..bd28a11c 100644 --- a/logger.go +++ b/logger.go @@ -64,6 +64,8 @@ type LogFormatterParams struct { ErrorMessage string // IsTerm shows whether does gin's output descriptor refers to a terminal. IsTerm bool + // BodySize is the size of the Response Body + BodySize int } // defaultLogFormatter is the default log format function Logger middleware uses. @@ -191,6 +193,8 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc { param.StatusCode = c.Writer.Status() param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String() + param.BodySize = c.Writer.Size() + if raw != "" { path = path + "?" + raw } From 7b1081a73fe4559697f4fb5a44261fbdc1d130b2 Mon Sep 17 00:00:00 2001 From: songjiayang Date: Fri, 22 Feb 2019 14:20:24 +0800 Subject: [PATCH 14/18] issue_1721: fix render writeHeaders to make it the same as http.Header.Set (#1722) --- render/reader.go | 4 ++-- render/render_test.go | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/render/reader.go b/render/reader.go index ab60e53a..312af741 100644 --- a/render/reader.go +++ b/render/reader.go @@ -36,8 +36,8 @@ func (r Reader) WriteContentType(w http.ResponseWriter) { func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) { header := w.Header() for k, v := range headers { - if val := header[k]; len(val) == 0 { - header[k] = []string{v} + if header.Get(k) == "" { + header.Set(k, v) } } } diff --git a/render/render_test.go b/render/render_test.go index 3df04a17..76e29eeb 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -470,6 +470,7 @@ func TestRenderReader(t *testing.T) { body := "#!PNG some raw data" headers := make(map[string]string) headers["Content-Disposition"] = `attachment; filename="filename.png"` + headers["x-request-id"] = "requestId" err := (Reader{ ContentLength: int64(len(body)), @@ -483,4 +484,5 @@ func TestRenderReader(t *testing.T) { 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")) + assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id")) } From e6288e90eb313122410bf1335d502a062c1ae610 Mon Sep 17 00:00:00 2001 From: Sai Date: Fri, 22 Feb 2019 17:48:55 +0900 Subject: [PATCH 15/18] Change color methods in using defaultLogger function to public (#1771) Fix https://github.com/gin-gonic/gin/issues/1768 --- logger.go | 85 ++++++++++++++++++++++++++++---------------------- logger_test.go | 19 +++++++++++ 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/logger.go b/logger.go index bd28a11c..dc639975 100644 --- a/logger.go +++ b/logger.go @@ -68,13 +68,58 @@ type LogFormatterParams struct { BodySize int } +// StatusCodeColor is the ANSI color for appropriately logging http status code to a terminal. +func (p *LogFormatterParams) StatusCodeColor() string { + code := p.StatusCode + + switch { + case code >= http.StatusOK && code < http.StatusMultipleChoices: + return green + case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: + return white + case code >= http.StatusBadRequest && code < http.StatusInternalServerError: + return yellow + default: + return red + } +} + +// MethodColor is the ANSI color for appropriately logging http method to a terminal. +func (p *LogFormatterParams) MethodColor() string { + method := p.Method + + switch method { + case "GET": + return blue + case "POST": + return cyan + case "PUT": + return yellow + case "DELETE": + return red + case "PATCH": + return green + case "HEAD": + return magenta + case "OPTIONS": + return white + default: + return reset + } +} + +// ResetColor resets all escape attributes. +func (p *LogFormatterParams) ResetColor() string { + return reset +} + // defaultLogFormatter is the default log format function Logger middleware uses. var defaultLogFormatter = func(param LogFormatterParams) string { var statusColor, methodColor, resetColor string if param.IsTerm { - statusColor = colorForStatus(param.StatusCode) - methodColor = colorForMethod(param.Method) - resetColor = reset + statusColor = param.StatusCodeColor() + methodColor = param.MethodColor() + resetColor = param.ResetColor() } return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s", @@ -205,37 +250,3 @@ func LoggerWithConfig(conf LoggerConfig) HandlerFunc { } } } - -func colorForStatus(code int) string { - switch { - case code >= http.StatusOK && code < http.StatusMultipleChoices: - return green - case code >= http.StatusMultipleChoices && code < http.StatusBadRequest: - return white - case code >= http.StatusBadRequest && code < http.StatusInternalServerError: - return yellow - default: - return red - } -} - -func colorForMethod(method string) string { - switch method { - case "GET": - return blue - case "POST": - return cyan - case "PUT": - return yellow - case "DELETE": - return red - case "PATCH": - return green - case "HEAD": - return magenta - case "OPTIONS": - return white - default: - return reset - } -} diff --git a/logger_test.go b/logger_test.go index 8770b5fb..c551677a 100644 --- a/logger_test.go +++ b/logger_test.go @@ -257,6 +257,13 @@ func TestDefaultLogFormatter(t *testing.T) { } func TestColorForMethod(t *testing.T) { + colorForMethod := func(method string) string { + p := LogFormatterParams{ + Method: method, + } + return p.MethodColor() + } + 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, 48, 59, 52, 51, 109}), colorForMethod("PUT"), "put should be yellow") @@ -268,12 +275,24 @@ func TestColorForMethod(t *testing.T) { } func TestColorForStatus(t *testing.T) { + colorForStatus := func(code int) string { + p := LogFormatterParams{ + StatusCode: code, + } + return p.StatusCodeColor() + } + 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, 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") } +func TestResetColor(t *testing.T) { + p := LogFormatterParams{} + assert.Equal(t, string([]byte{27, 91, 48, 109}), p.ResetColor()) +} + func TestErrorLogger(t *testing.T) { router := New() router.Use(ErrorLogger()) From d6adc8d0cc4e5a87e249923f511d093ffa552c14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=94=B0=E6=AC=A7?= Date: Tue, 26 Feb 2019 10:45:44 +0800 Subject: [PATCH 16/18] chore: add go1.12 support (#1780) * chore: add go1.12 support * Update .travis.yml --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2eeb0b3d..be196feb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ go: - 1.9.x - 1.10.x - 1.11.x + - 1.12.x - master matrix: @@ -14,6 +15,8 @@ matrix: include: - go: 1.11.x env: GO111MODULE=on + - go: 1.12.x + env: GO111MODULE=on git: depth: 10 From 62749f0db4aa5ee1045779b457fe1f28a553f467 Mon Sep 17 00:00:00 2001 From: Luis GG Date: Tue, 26 Feb 2019 01:15:40 -0300 Subject: [PATCH 17/18] Add context.HandlerNames() (#1729) * Add context.HandlerNames() This change adds a HandlerNames method that will return all registered handles in the context, in descending order This is useful for debugging and troubleshooting purposes, especially in large apps * Tests Add tests for HandlerNames * Fix HandlerNames test * Simplify test --- context.go | 10 ++++++++++ context_test.go | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/context.go b/context.go index 26badfc3..fa63ec8b 100644 --- a/context.go +++ b/context.go @@ -91,6 +91,16 @@ func (c *Context) HandlerName() string { return nameOfFunction(c.handlers.Last()) } +// HandlerNames returns a list of all registered handlers for this context in descending order, +// following the semantics of HandlerName() +func (c *Context) HandlerNames() []string { + hn := make([]string, 0, len(c.handlers)) + for _, val := range c.handlers { + hn = append(hn, nameOfFunction(val)) + } + return hn +} + // Handler returns the main handler. func (c *Context) Handler() HandlerFunc { return c.handlers.Last() diff --git a/context_test.go b/context_test.go index ea936b85..34cc71a5 100644 --- a/context_test.go +++ b/context_test.go @@ -340,10 +340,26 @@ func TestContextHandlerName(t *testing.T) { assert.Regexp(t, "^(.*/vendor/)?github.com/gin-gonic/gin.handlerNameTest$", c.HandlerName()) } +func TestContextHandlerNames(t *testing.T) { + c, _ := CreateTestContext(httptest.NewRecorder()) + c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest, func(c *Context) {}, handlerNameTest2} + + names := c.HandlerNames() + + assert.True(t, len(names) == 4) + for _, name := range names { + assert.Regexp(t, `^(.*/vendor/)?(github\.com/gin-gonic/gin\.){1}(TestContextHandlerNames\.func.*){0,1}(handlerNameTest.*){0,1}`, name) + } +} + func handlerNameTest(c *Context) { } +func handlerNameTest2(c *Context) { + +} + var handlerTest HandlerFunc = func(c *Context) { } From e207a3ce65323c3dda7cd8133fe14f4f1efd2500 Mon Sep 17 00:00:00 2001 From: Raphael Gavache Date: Tue, 26 Feb 2019 08:10:16 +0100 Subject: [PATCH 18/18] Fix context.Copy() race condition (#1020) * Fix context.Copy race condition * Update githubapi_test.go * fix code format --- context.go | 4 ++++ context_test.go | 2 ++ githubapi_test.go | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/context.go b/context.go index fa63ec8b..7618cef5 100644 --- a/context.go +++ b/context.go @@ -82,6 +82,10 @@ func (c *Context) Copy() *Context { cp.Writer = &cp.writermem cp.index = abortIndex cp.handlers = nil + cp.Keys = map[string]interface{}{} + for k, v := range c.Keys { + cp.Keys[k] = v + } return &cp } diff --git a/context_test.go b/context_test.go index 34cc71a5..dc8ac306 100644 --- a/context_test.go +++ b/context_test.go @@ -331,6 +331,8 @@ func TestContextCopy(t *testing.T) { assert.Equal(t, cp.Keys, c.Keys) assert.Equal(t, cp.engine, c.engine) assert.Equal(t, cp.Params, c.Params) + cp.Set("foo", "notBar") + assert.False(t, cp.Keys["foo"] == c.Keys["foo"]) } func TestContextHandlerName(t *testing.T) { diff --git a/githubapi_test.go b/githubapi_test.go index 29aa1584..fb74d659 100644 --- a/githubapi_test.go +++ b/githubapi_test.go @@ -346,6 +346,29 @@ func TestBindUriError(t *testing.T) { assert.Equal(t, http.StatusBadRequest, w1.Code) } +func TestRaceContextCopy(t *testing.T) { + DefaultWriter = os.Stdout + router := Default() + router.GET("/test/copy/race", func(c *Context) { + c.Set("1", 0) + c.Set("2", 0) + + // Sending a copy of the Context to two separate routines + go readWriteKeys(c.Copy()) + go readWriteKeys(c.Copy()) + c.String(http.StatusOK, "run OK, no panics") + }) + w := performRequest(router, "GET", "/test/copy/race") + assert.Equal(t, "run OK, no panics", w.Body.String()) +} + +func readWriteKeys(c *Context) { + for { + c.Set("1", rand.Int()) + c.Set("2", c.Value("1")) + } +} + func githubConfigRouter(router *Engine) { for _, route := range githubAPI { router.Handle(route.method, route.path, func(c *Context) {