mirror of https://github.com/gin-gonic/gin.git
commit
89378afa72
1085
BENCHMARKS.md
1085
BENCHMARKS.md
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,11 @@
|
||||||
|
# Gin ChangeLog
|
||||||
|
|
||||||
|
## Gin v1.6.3
|
||||||
|
|
||||||
|
### ENHANCEMENTS
|
||||||
|
|
||||||
|
* Improve performance: Change `*sync.RWMutex` to `sync.RWMutex` in context. [#2351](https://github.com/gin-gonic/gin/pull/2351)
|
||||||
|
|
||||||
## Gin v1.6.2
|
## Gin v1.6.2
|
||||||
|
|
||||||
### BUFIXES
|
### BUFIXES
|
||||||
|
|
66
README.md
66
README.md
|
@ -5,7 +5,7 @@
|
||||||
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
|
[![Build Status](https://travis-ci.org/gin-gonic/gin.svg)](https://travis-ci.org/gin-gonic/gin)
|
||||||
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
|
[![codecov](https://codecov.io/gh/gin-gonic/gin/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-gonic/gin)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
|
[![Go Report Card](https://goreportcard.com/badge/github.com/gin-gonic/gin)](https://goreportcard.com/report/github.com/gin-gonic/gin)
|
||||||
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://godoc.org/github.com/gin-gonic/gin)
|
[![GoDoc](https://godoc.org/github.com/gin-gonic/gin?status.svg)](https://pkg.go.dev/github.com/gin-gonic/gin?tab=doc)
|
||||||
[![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)
|
[![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)
|
[![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)
|
[![Open Source Helpers](https://www.codetriage.com/gin-gonic/gin/badges/users.svg)](https://www.codetriage.com/gin-gonic/gin)
|
||||||
|
@ -54,6 +54,7 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
||||||
- [AsciiJSON](#asciijson)
|
- [AsciiJSON](#asciijson)
|
||||||
- [PureJSON](#purejson)
|
- [PureJSON](#purejson)
|
||||||
- [Serving static files](#serving-static-files)
|
- [Serving static files](#serving-static-files)
|
||||||
|
- [Serving data from file](#serving-data-from-file)
|
||||||
- [Serving data from reader](#serving-data-from-reader)
|
- [Serving data from reader](#serving-data-from-reader)
|
||||||
- [HTML rendering](#html-rendering)
|
- [HTML rendering](#html-rendering)
|
||||||
- [Custom Template renderer](#custom-template-renderer)
|
- [Custom Template renderer](#custom-template-renderer)
|
||||||
|
@ -68,6 +69,8 @@ Gin is a web framework written in Go (Golang). It features a martini-like API wi
|
||||||
- [Support Let's Encrypt](#support-lets-encrypt)
|
- [Support Let's Encrypt](#support-lets-encrypt)
|
||||||
- [Run multiple service using Gin](#run-multiple-service-using-gin)
|
- [Run multiple service using Gin](#run-multiple-service-using-gin)
|
||||||
- [Graceful shutdown or restart](#graceful-shutdown-or-restart)
|
- [Graceful shutdown or restart](#graceful-shutdown-or-restart)
|
||||||
|
- [Third-party packages](#third-party-packages)
|
||||||
|
- [Manually](#manually)
|
||||||
- [Build a single binary with templates](#build-a-single-binary-with-templates)
|
- [Build a single binary with templates](#build-a-single-binary-with-templates)
|
||||||
- [Bind form-data request with custom struct](#bind-form-data-request-with-custom-struct)
|
- [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)
|
- [Try to bind body into different structs](#try-to-bind-body-into-different-structs)
|
||||||
|
@ -133,35 +136,38 @@ Gin uses a custom version of [HttpRouter](https://github.com/julienschmidt/httpr
|
||||||
|
|
||||||
[See all benchmarks](/BENCHMARKS.md)
|
[See all benchmarks](/BENCHMARKS.md)
|
||||||
|
|
||||||
Benchmark name | (1) | (2) | (3) | (4)
|
| Benchmark name | (1) | (2) | (3) | (4) |
|
||||||
--------------------------------------------|-----------:|------------:|-----------:|---------:
|
| ------------------------------ | ---------:| ---------------:| ------------:| ---------------:|
|
||||||
**BenchmarkGin_GithubAll** | **30000** | **48375** | **0** | **0**
|
| BenchmarkGin_GithubAll | **43550** | **27364 ns/op** | **0 B/op** | **0 allocs/op** |
|
||||||
BenchmarkAce_GithubAll | 10000 | 134059 | 13792 | 167
|
| BenchmarkAce_GithubAll | 40543 | 29670 ns/op | 0 B/op | 0 allocs/op |
|
||||||
BenchmarkBear_GithubAll | 5000 | 534445 | 86448 | 943
|
| BenchmarkAero_GithubAll | 57632 | 20648 ns/op | 0 B/op | 0 allocs/op |
|
||||||
BenchmarkBeego_GithubAll | 3000 | 592444 | 74705 | 812
|
| BenchmarkBear_GithubAll | 9234 | 216179 ns/op | 86448 B/op | 943 allocs/op |
|
||||||
BenchmarkBone_GithubAll | 200 | 6957308 | 698784 | 8453
|
| BenchmarkBeego_GithubAll | 7407 | 243496 ns/op | 71456 B/op | 609 allocs/op |
|
||||||
BenchmarkDenco_GithubAll | 10000 | 158819 | 20224 | 167
|
| BenchmarkBone_GithubAll | 420 | 2922835 ns/op | 720160 B/op | 8620 allocs/op |
|
||||||
BenchmarkEcho_GithubAll | 10000 | 154700 | 6496 | 203
|
| BenchmarkChi_GithubAll | 7620 | 238331 ns/op | 87696 B/op | 609 allocs/op |
|
||||||
BenchmarkGocraftWeb_GithubAll | 3000 | 570806 | 131656 | 1686
|
| BenchmarkDenco_GithubAll | 18355 | 64494 ns/op | 20224 B/op | 167 allocs/op |
|
||||||
BenchmarkGoji_GithubAll | 2000 | 818034 | 56112 | 334
|
| BenchmarkEcho_GithubAll | 31251 | 38479 ns/op | 0 B/op | 0 allocs/op |
|
||||||
BenchmarkGojiv2_GithubAll | 2000 | 1213973 | 274768 | 3712
|
| BenchmarkGocraftWeb_GithubAll | 4117 | 300062 ns/op | 131656 B/op | 1686 allocs/op |
|
||||||
BenchmarkGoJsonRest_GithubAll | 2000 | 785796 | 134371 | 2737
|
| BenchmarkGoji_GithubAll | 3274 | 416158 ns/op | 56112 B/op | 334 allocs/op |
|
||||||
BenchmarkGoRestful_GithubAll | 300 | 5238188 | 689672 | 4519
|
| BenchmarkGojiv2_GithubAll | 1402 | 870518 ns/op | 352720 B/op | 4321 allocs/op |
|
||||||
BenchmarkGorillaMux_GithubAll | 100 | 10257726 | 211840 | 2272
|
| BenchmarkGoJsonRest_GithubAll | 2976 | 401507 ns/op | 134371 B/op | 2737 allocs/op |
|
||||||
BenchmarkHttpRouter_GithubAll | 20000 | 105414 | 13792 | 167
|
| BenchmarkGoRestful_GithubAll | 410 | 2913158 ns/op | 910144 B/op | 2938 allocs/op |
|
||||||
BenchmarkHttpTreeMux_GithubAll | 10000 | 319934 | 65856 | 671
|
| BenchmarkGorillaMux_GithubAll | 346 | 3384987 ns/op | 251650 B/op | 1994 allocs/op |
|
||||||
BenchmarkKocha_GithubAll | 10000 | 209442 | 23304 | 843
|
| BenchmarkGowwwRouter_GithubAll | 10000 | 143025 ns/op | 72144 B/op | 501 allocs/op |
|
||||||
BenchmarkLARS_GithubAll | 20000 | 62565 | 0 | 0
|
| BenchmarkHttpRouter_GithubAll | 55938 | 21360 ns/op | 0 B/op | 0 allocs/op |
|
||||||
BenchmarkMacaron_GithubAll | 2000 | 1161270 | 204194 | 2000
|
| BenchmarkHttpTreeMux_GithubAll | 10000 | 153944 ns/op | 65856 B/op | 671 allocs/op |
|
||||||
BenchmarkMartini_GithubAll | 200 | 9991713 | 226549 | 2325
|
| BenchmarkKocha_GithubAll | 10000 | 106315 ns/op | 23304 B/op | 843 allocs/op |
|
||||||
BenchmarkPat_GithubAll | 200 | 5590793 | 1499568 | 27435
|
| BenchmarkLARS_GithubAll | 47779 | 25084 ns/op | 0 B/op | 0 allocs/op |
|
||||||
BenchmarkPossum_GithubAll | 10000 | 319768 | 84448 | 609
|
| BenchmarkMacaron_GithubAll | 3266 | 371907 ns/op | 149409 B/op | 1624 allocs/op |
|
||||||
BenchmarkR2router_GithubAll | 10000 | 305134 | 77328 | 979
|
| BenchmarkMartini_GithubAll | 331 | 3444706 ns/op | 226551 B/op | 2325 allocs/op |
|
||||||
BenchmarkRivet_GithubAll | 10000 | 132134 | 16272 | 167
|
| BenchmarkPat_GithubAll | 273 | 4381818 ns/op | 1483152 B/op | 26963 allocs/op |
|
||||||
BenchmarkTango_GithubAll | 3000 | 552754 | 63826 | 1618
|
| BenchmarkPossum_GithubAll | 10000 | 164367 ns/op | 84448 B/op | 609 allocs/op |
|
||||||
BenchmarkTigerTonic_GithubAll | 1000 | 1439483 | 239104 | 5374
|
| BenchmarkR2router_GithubAll | 10000 | 160220 ns/op | 77328 B/op | 979 allocs/op |
|
||||||
BenchmarkTraffic_GithubAll | 100 | 11383067 | 2659329 | 21848
|
| BenchmarkRivet_GithubAll | 14625 | 82453 ns/op | 16272 B/op | 167 allocs/op |
|
||||||
BenchmarkVulcan_GithubAll | 5000 | 394253 | 19894 | 609
|
| BenchmarkTango_GithubAll | 6255 | 279611 ns/op | 63826 B/op | 1618 allocs/op |
|
||||||
|
| BenchmarkTigerTonic_GithubAll | 2008 | 687874 ns/op | 193856 B/op | 4474 allocs/op |
|
||||||
|
| BenchmarkTraffic_GithubAll | 355 | 3478508 ns/op | 820744 B/op | 14114 allocs/op |
|
||||||
|
| BenchmarkVulcan_GithubAll | 6885 | 193333 ns/op | 19894 B/op | 609 allocs/op |
|
||||||
|
|
||||||
- (1): Total Repetitions achieved in constant time, higher means more confident result
|
- (1): Total Repetitions achieved in constant time, higher means more confident result
|
||||||
- (2): Single Repetition Duration (ns/op), lower is better
|
- (2): Single Repetition Duration (ns/op), lower is better
|
||||||
|
|
5
auth.go
5
auth.go
|
@ -70,8 +70,9 @@ func BasicAuth(accounts Accounts) HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
func processAccounts(accounts Accounts) authPairs {
|
func processAccounts(accounts Accounts) authPairs {
|
||||||
assert1(len(accounts) > 0, "Empty list of authorized credentials")
|
length := len(accounts)
|
||||||
pairs := make(authPairs, 0, len(accounts))
|
assert1(length > 0, "Empty list of authorized credentials")
|
||||||
|
pairs := make(authPairs, 0, length)
|
||||||
for user, password := range accounts {
|
for user, password := range accounts {
|
||||||
assert1(user != "", "User can not be empty")
|
assert1(user != "", "User can not be empty")
|
||||||
value := authorizationHeader(user, password)
|
value := authorizationHeader(user, password)
|
||||||
|
|
33
context.go
33
context.go
|
@ -34,9 +34,11 @@ const (
|
||||||
MIMEPOSTForm = binding.MIMEPOSTForm
|
MIMEPOSTForm = binding.MIMEPOSTForm
|
||||||
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
|
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
|
||||||
MIMEYAML = binding.MIMEYAML
|
MIMEYAML = binding.MIMEYAML
|
||||||
BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BodyBytesKey indicates a default body bytes key.
|
||||||
|
const BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
|
||||||
|
|
||||||
const abortIndex int8 = math.MaxInt8 / 2
|
const abortIndex int8 = math.MaxInt8 / 2
|
||||||
|
|
||||||
// Context is the most important part of gin. It allows us to pass variables between middleware,
|
// Context is the most important part of gin. It allows us to pass variables between middleware,
|
||||||
|
@ -54,7 +56,7 @@ type Context struct {
|
||||||
engine *Engine
|
engine *Engine
|
||||||
|
|
||||||
// This mutex protect Keys map
|
// This mutex protect Keys map
|
||||||
KeysMutex *sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
// Keys is a key/value pair exclusively for the context of each request.
|
// Keys is a key/value pair exclusively for the context of each request.
|
||||||
Keys map[string]interface{}
|
Keys map[string]interface{}
|
||||||
|
@ -86,7 +88,7 @@ func (c *Context) reset() {
|
||||||
c.Params = c.Params[0:0]
|
c.Params = c.Params[0:0]
|
||||||
c.handlers = nil
|
c.handlers = nil
|
||||||
c.index = -1
|
c.index = -1
|
||||||
c.KeysMutex = &sync.RWMutex{}
|
|
||||||
c.fullPath = ""
|
c.fullPath = ""
|
||||||
c.Keys = nil
|
c.Keys = nil
|
||||||
c.Errors = c.Errors[0:0]
|
c.Errors = c.Errors[0:0]
|
||||||
|
@ -98,7 +100,12 @@ func (c *Context) reset() {
|
||||||
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
// Copy returns a copy of the current context that can be safely used outside the request's scope.
|
||||||
// This has to be used when the context has to be passed to a goroutine.
|
// This has to be used when the context has to be passed to a goroutine.
|
||||||
func (c *Context) Copy() *Context {
|
func (c *Context) Copy() *Context {
|
||||||
var cp = *c
|
cp := Context{
|
||||||
|
writermem: c.writermem,
|
||||||
|
Request: c.Request,
|
||||||
|
Params: c.Params,
|
||||||
|
engine: c.engine,
|
||||||
|
}
|
||||||
cp.writermem.ResponseWriter = nil
|
cp.writermem.ResponseWriter = nil
|
||||||
cp.Writer = &cp.writermem
|
cp.Writer = &cp.writermem
|
||||||
cp.index = abortIndex
|
cp.index = abortIndex
|
||||||
|
@ -228,29 +235,21 @@ func (c *Context) Error(err error) *Error {
|
||||||
// Set is used to store a new key/value pair exclusively for this context.
|
// Set is used to store a new key/value pair exclusively for this context.
|
||||||
// It also lazy initializes c.Keys if it was not used previously.
|
// It also lazy initializes c.Keys if it was not used previously.
|
||||||
func (c *Context) Set(key string, value interface{}) {
|
func (c *Context) Set(key string, value interface{}) {
|
||||||
if c.KeysMutex == nil {
|
c.mu.Lock()
|
||||||
c.KeysMutex = &sync.RWMutex{}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.KeysMutex.Lock()
|
|
||||||
if c.Keys == nil {
|
if c.Keys == nil {
|
||||||
c.Keys = make(map[string]interface{})
|
c.Keys = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Keys[key] = value
|
c.Keys[key] = value
|
||||||
c.KeysMutex.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the value for the given key, ie: (value, true).
|
// Get returns the value for the given key, ie: (value, true).
|
||||||
// If the value does not exists it returns (nil, false)
|
// If the value does not exists it returns (nil, false)
|
||||||
func (c *Context) Get(key string) (value interface{}, exists bool) {
|
func (c *Context) Get(key string) (value interface{}, exists bool) {
|
||||||
if c.KeysMutex == nil {
|
c.mu.RLock()
|
||||||
c.KeysMutex = &sync.RWMutex{}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.KeysMutex.RLock()
|
|
||||||
value, exists = c.Keys[key]
|
value, exists = c.Keys[key]
|
||||||
c.KeysMutex.RUnlock()
|
c.mu.RUnlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -866,7 +865,7 @@ func (c *Context) IndentedJSON(code int, obj interface{}) {
|
||||||
// Default prepends "while(1)," to response body if the given struct is array values.
|
// Default prepends "while(1)," to response body if the given struct is array values.
|
||||||
// It also sets the Content-Type as "application/json".
|
// It also sets the Content-Type as "application/json".
|
||||||
func (c *Context) SecureJSON(code int, obj interface{}) {
|
func (c *Context) SecureJSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.SecureJSON{Prefix: c.engine.secureJsonPrefix, Data: obj})
|
c.Render(code, render.SecureJSON{Prefix: c.engine.secureJSONPrefix, Data: obj})
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONP serializes the given struct as JSON into the response body.
|
// JSONP serializes the given struct as JSON into the response body.
|
||||||
|
|
13
gin.go
13
gin.go
|
@ -22,9 +22,10 @@ const defaultMultipartMemory = 32 << 20 // 32 MB
|
||||||
var (
|
var (
|
||||||
default404Body = []byte("404 page not found")
|
default404Body = []byte("404 page not found")
|
||||||
default405Body = []byte("405 method not allowed")
|
default405Body = []byte("405 method not allowed")
|
||||||
defaultAppEngine bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defaultAppEngine bool
|
||||||
|
|
||||||
// HandlerFunc defines the handler used by gin middleware as return value.
|
// HandlerFunc defines the handler used by gin middleware as return value.
|
||||||
type HandlerFunc func(*Context)
|
type HandlerFunc func(*Context)
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ type Engine struct {
|
||||||
RemoveExtraSlash bool
|
RemoveExtraSlash bool
|
||||||
|
|
||||||
delims render.Delims
|
delims render.Delims
|
||||||
secureJsonPrefix string
|
secureJSONPrefix string
|
||||||
HTMLRender render.HTMLRender
|
HTMLRender render.HTMLRender
|
||||||
FuncMap template.FuncMap
|
FuncMap template.FuncMap
|
||||||
allNoRoute HandlersChain
|
allNoRoute HandlersChain
|
||||||
|
@ -144,7 +145,7 @@ func New() *Engine {
|
||||||
MaxMultipartMemory: defaultMultipartMemory,
|
MaxMultipartMemory: defaultMultipartMemory,
|
||||||
trees: make(methodTrees, 0, 9),
|
trees: make(methodTrees, 0, 9),
|
||||||
delims: render.Delims{Left: "{{", Right: "}}"},
|
delims: render.Delims{Left: "{{", Right: "}}"},
|
||||||
secureJsonPrefix: "while(1);",
|
secureJSONPrefix: "while(1);",
|
||||||
}
|
}
|
||||||
engine.RouterGroup.engine = engine
|
engine.RouterGroup.engine = engine
|
||||||
engine.pool.New = func() interface{} {
|
engine.pool.New = func() interface{} {
|
||||||
|
@ -162,7 +163,7 @@ func Default() *Engine {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (engine *Engine) allocateContext() *Context {
|
func (engine *Engine) allocateContext() *Context {
|
||||||
return &Context{engine: engine, KeysMutex: &sync.RWMutex{}}
|
return &Context{engine: engine}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delims sets template left and right delims and returns a Engine instance.
|
// Delims sets template left and right delims and returns a Engine instance.
|
||||||
|
@ -171,9 +172,9 @@ func (engine *Engine) Delims(left, right string) *Engine {
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecureJsonPrefix sets the secureJsonPrefix used in Context.SecureJSON.
|
// SecureJsonPrefix sets the secureJSONPrefix used in Context.SecureJSON.
|
||||||
func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
|
func (engine *Engine) SecureJsonPrefix(prefix string) *Engine {
|
||||||
engine.secureJsonPrefix = prefix
|
engine.secureJSONPrefix = prefix
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,13 +291,13 @@ func TestShouldBindUri(t *testing.T) {
|
||||||
|
|
||||||
type Person struct {
|
type Person struct {
|
||||||
Name string `uri:"name" binding:"required"`
|
Name string `uri:"name" binding:"required"`
|
||||||
Id string `uri:"id" binding:"required"`
|
ID string `uri:"id" binding:"required"`
|
||||||
}
|
}
|
||||||
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
|
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
|
||||||
var person Person
|
var person Person
|
||||||
assert.NoError(t, c.ShouldBindUri(&person))
|
assert.NoError(t, c.ShouldBindUri(&person))
|
||||||
assert.True(t, "" != person.Name)
|
assert.True(t, "" != person.Name)
|
||||||
assert.True(t, "" != person.Id)
|
assert.True(t, "" != person.ID)
|
||||||
c.String(http.StatusOK, "ShouldBindUri test OK")
|
c.String(http.StatusOK, "ShouldBindUri test OK")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -313,13 +313,13 @@ func TestBindUri(t *testing.T) {
|
||||||
|
|
||||||
type Person struct {
|
type Person struct {
|
||||||
Name string `uri:"name" binding:"required"`
|
Name string `uri:"name" binding:"required"`
|
||||||
Id string `uri:"id" binding:"required"`
|
ID string `uri:"id" binding:"required"`
|
||||||
}
|
}
|
||||||
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
|
router.Handle(http.MethodGet, "/rest/:name/:id", func(c *Context) {
|
||||||
var person Person
|
var person Person
|
||||||
assert.NoError(t, c.BindUri(&person))
|
assert.NoError(t, c.BindUri(&person))
|
||||||
assert.True(t, "" != person.Name)
|
assert.True(t, "" != person.Name)
|
||||||
assert.True(t, "" != person.Id)
|
assert.True(t, "" != person.ID)
|
||||||
c.String(http.StatusOK, "BindUri test OK")
|
c.String(http.StatusOK, "BindUri test OK")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
package json
|
package json
|
||||||
|
|
||||||
import "github.com/json-iterator/go"
|
import jsoniter "github.com/json-iterator/go"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
|
1
mode.go
1
mode.go
|
@ -22,6 +22,7 @@ const (
|
||||||
// TestMode indicates gin mode is test.
|
// TestMode indicates gin mode is test.
|
||||||
TestMode = "test"
|
TestMode = "test"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
debugCode = iota
|
debugCode = iota
|
||||||
releaseCode
|
releaseCode
|
||||||
|
|
7
path.go
7
path.go
|
@ -136,10 +136,11 @@ func bufApp(buf *[]byte, s string, w int, c byte) {
|
||||||
|
|
||||||
// Otherwise use either the stack buffer, if it is large enough, or
|
// Otherwise use either the stack buffer, if it is large enough, or
|
||||||
// allocate a new buffer on the heap, and copy all previous characters.
|
// allocate a new buffer on the heap, and copy all previous characters.
|
||||||
if l := len(s); l > cap(b) {
|
length := len(s)
|
||||||
*buf = make([]byte, len(s))
|
if length > cap(b) {
|
||||||
|
*buf = make([]byte, length)
|
||||||
} else {
|
} else {
|
||||||
*buf = (*buf)[:l]
|
*buf = (*buf)[:length]
|
||||||
}
|
}
|
||||||
b = *buf
|
b = *buf
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,6 @@ func function(pc uintptr) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func timeFormat(t time.Time) string {
|
func timeFormat(t time.Time) string {
|
||||||
var timeString = t.Format("2006/01/02 - 15:04:05")
|
timeString := t.Format("2006/01/02 - 15:04:05")
|
||||||
return timeString
|
return timeString
|
||||||
}
|
}
|
||||||
|
|
|
@ -514,7 +514,7 @@ func TestMiddlewareCalledOnceByRouterStaticFSNotFound(t *testing.T) {
|
||||||
// Middleware must be called just only once by per request.
|
// Middleware must be called just only once by per request.
|
||||||
middlewareCalledNum := 0
|
middlewareCalledNum := 0
|
||||||
router.Use(func(c *Context) {
|
router.Use(func(c *Context) {
|
||||||
middlewareCalledNum += 1
|
middlewareCalledNum++
|
||||||
})
|
})
|
||||||
|
|
||||||
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
|
router.StaticFS("/", http.FileSystem(http.Dir("/thisreallydoesntexist/")))
|
||||||
|
|
|
@ -5,4 +5,4 @@
|
||||||
package gin
|
package gin
|
||||||
|
|
||||||
// Version is the current gin framework's version.
|
// Version is the current gin framework's version.
|
||||||
const Version = "v1.6.2"
|
const Version = "v1.6.3"
|
||||||
|
|
Loading…
Reference in New Issue