mirror of https://github.com/gin-gonic/gin.git
Fix concurrent write bug in reader.Render
If a caller passed in a map retained within the callers context as extraHeaders to gin.Context.DataFromReader() then a race to write the "Content-Lenght" header would occur. // globalHeader is passed to gin.Context.DataFromReader var globalHeaders = map[string]string{ "cache-control": "public, max-age=3600", } func (c *gin.Context) { //... // DataFromReader must not write to globalHeaders c.DataFromReader(code, contentLength, contentType, reader, globalHeaders) }
This commit is contained in:
parent
a889c58de7
commit
50c29053dd
|
@ -21,13 +21,8 @@ type Reader struct {
|
|||
// Render (Reader) writes data with custom ContentType and headers.
|
||||
func (r Reader) Render(w http.ResponseWriter) (err error) {
|
||||
r.WriteContentType(w)
|
||||
if r.ContentLength >= 0 {
|
||||
if r.Headers == nil {
|
||||
r.Headers = map[string]string{}
|
||||
}
|
||||
r.Headers["Content-Length"] = strconv.FormatInt(r.ContentLength, 10)
|
||||
}
|
||||
r.writeHeaders(w, r.Headers)
|
||||
|
||||
_, err = io.Copy(w, r.Reader)
|
||||
return
|
||||
}
|
||||
|
@ -45,4 +40,8 @@ func (r Reader) writeHeaders(w http.ResponseWriter, headers map[string]string) {
|
|||
header.Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
if r.ContentLength > 0 {
|
||||
header.Set("Content-Length", strconv.FormatInt(r.ContentLength, 10))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package render
|
|||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
|
@ -21,3 +22,21 @@ func TestReaderRenderNoHeaders(t *testing.T) {
|
|||
err := r.Render(httptest.NewRecorder())
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestReaderRenderWithHeaders(t *testing.T) {
|
||||
content := "test"
|
||||
r := Reader{
|
||||
ContentLength: int64(len(content)),
|
||||
Reader: strings.NewReader(content),
|
||||
Headers: map[string]string{
|
||||
"Test-Content": "test/content",
|
||||
},
|
||||
}
|
||||
recorder := httptest.NewRecorder()
|
||||
err := r.Render(recorder)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Contains(t, recorder.Header()["Content-Length"], strconv.FormatInt(r.ContentLength, 10))
|
||||
|
||||
require.Contains(t, recorder.Header()["Test-Content"], "test/content")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue