mirror of https://github.com/gin-gonic/gin.git
Fix context.Params race condition on Copy() (#1841)
* Fix context.Params race condition on Copy() Using context.Param(key) on a context.Copy inside a goroutine may lead to incorrect value on a high load, where another request overwrite a Param * Using waitgroup to wait asynchronous test case
This commit is contained in:
parent
35e33d3638
commit
6e320c97e8
|
@ -89,6 +89,9 @@ func (c *Context) Copy() *Context {
|
||||||
for k, v := range c.Keys {
|
for k, v := range c.Keys {
|
||||||
cp.Keys[k] = v
|
cp.Keys[k] = v
|
||||||
}
|
}
|
||||||
|
paramCopy := make([]Param, len(cp.Params))
|
||||||
|
copy(paramCopy, cp.Params)
|
||||||
|
cp.Params = paramCopy
|
||||||
return &cp
|
return &cp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,10 @@ import (
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -1821,3 +1823,24 @@ func TestContextResetInHandler(t *testing.T) {
|
||||||
c.Next()
|
c.Next()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRaceParamsContextCopy(t *testing.T) {
|
||||||
|
DefaultWriter = os.Stdout
|
||||||
|
router := Default()
|
||||||
|
nameGroup := router.Group("/:name")
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2)
|
||||||
|
{
|
||||||
|
nameGroup.GET("/api", func(c *Context) {
|
||||||
|
go func(c *Context, param string) {
|
||||||
|
defer wg.Done()
|
||||||
|
// First assert must be executed after the second request
|
||||||
|
time.Sleep(50 * time.Millisecond)
|
||||||
|
assert.Equal(t, c.Param("name"), param)
|
||||||
|
}(c.Copy(), c.Param("name"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
performRequest(router, "GET", "/name1/api")
|
||||||
|
performRequest(router, "GET", "/name2/api")
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue