Previously, Copy() only copied Keys and Params, leaving Errors and

Accepted as nil even when set on the original context. Goroutines
receiving a copied context could not observe errors attached before
the copy, and content-negotiation state set by middleware was silently
lost.
This commit is contained in:
Amirhf1 2026-06-05 00:33:08 +03:30
parent 5260de6a83
commit 7551df8b32
2 changed files with 54 additions and 0 deletions

View File

@ -141,6 +141,16 @@ func (c *Context) Copy() *Context {
cp.Params = make([]Param, len(cParams)) cp.Params = make([]Param, len(cParams))
copy(cp.Params, cParams) copy(cp.Params, cParams)
if c.Errors != nil {
cp.Errors = make(errorMsgs, len(c.Errors))
copy(cp.Errors, c.Errors)
}
if c.Accepted != nil {
cp.Accepted = make([]string, len(c.Accepted))
copy(cp.Accepted, c.Accepted)
}
return &cp return &cp
} }

View File

@ -688,6 +688,50 @@ func TestContextCopy(t *testing.T) {
assert.Equal(t, cp.fullPath, c.fullPath) assert.Equal(t, cp.fullPath, c.fullPath)
} }
func TestContextCopyCopiesErrors(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
_ = c.Error(errors.New("first error"))
_ = c.Error(errors.New("second error"))
cp := c.Copy()
// copied context has the same errors
assert.Equal(t, len(c.Errors), len(cp.Errors))
assert.Equal(t, c.Errors[0].Error(), cp.Errors[0].Error())
assert.Equal(t, c.Errors[1].Error(), cp.Errors[1].Error())
// mutations on the copy do not affect the original
_ = cp.Error(errors.New("third error"))
assert.Len(t, c.Errors, 2)
assert.Len(t, cp.Errors, 3)
}
func TestContextCopyCopiesAccepted(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
c.SetAccepted("application/json", "text/html")
cp := c.Copy()
assert.Equal(t, c.Accepted, cp.Accepted)
// mutations on the copy do not affect the original
cp.SetAccepted("text/plain")
assert.Equal(t, []string{"application/json", "text/html"}, c.Accepted)
assert.Equal(t, []string{"text/plain"}, cp.Accepted)
}
func TestContextCopyNilErrorsAndAccepted(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(http.MethodGet, "/", nil)
cp := c.Copy()
assert.Nil(t, cp.Errors)
assert.Nil(t, cp.Accepted)
}
func TestContextHandlerName(t *testing.T) { func TestContextHandlerName(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder()) c, _ := CreateTestContext(httptest.NewRecorder())
c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest} c.handlers = HandlersChain{func(c *Context) {}, handlerNameTest}