Description
httpFancyWriter.ReadFrom in middleware/wrap_writer.go double-counts the bytes written when a Tee writer is set.
When tee != nil, ReadFrom uses io.Copy(&f.basicWriter, r) which routes writes through basicWriter.Write(). The Write method already increments basicWriter.bytes on line 112. However, after io.Copy returns, ReadFrom also adds n to basicWriter.bytes again on line 212:
func (f *httpFancyWriter) ReadFrom(r io.Reader) (int64, error) {
if f.basicWriter.tee != nil {
n, err := io.Copy(&f.basicWriter, r)
f.basicWriter.bytes += int(n) // BUG: double-counts, basicWriter.Write already incremented bytes
return n, err
}
// ...non-tee path correctly counts since rf.ReadFrom bypasses basicWriter.Write
}
This causes BytesWritten() to return double the actual number of bytes when using ReadFrom with a Tee writer.
Reproduction
func TestHttpFancyWriterReadFromWithTee(t *testing.T) {
original := &httptest.ResponseRecorder{
HeaderMap: make(http.Header),
Body: new(bytes.Buffer),
}
f := &httpFancyWriter{basicWriter: basicWriter{ResponseWriter: original}}
var teeBuf bytes.Buffer
f.Tee(&teeBuf)
input := "hello world"
n, err := f.ReadFrom(strings.NewReader(input))
// n == 11, err == nil
// f.BytesWritten() == 22 -- BUG: should be 11
}
Fix
Remove the redundant f.basicWriter.bytes += int(n) line in the tee branch, since io.Copy through basicWriter.Write already handles byte counting.
Description
httpFancyWriter.ReadFrominmiddleware/wrap_writer.godouble-counts the bytes written when aTeewriter is set.When
tee != nil,ReadFromusesio.Copy(&f.basicWriter, r)which routes writes throughbasicWriter.Write(). TheWritemethod already incrementsbasicWriter.byteson line 112. However, afterio.Copyreturns,ReadFromalso addsntobasicWriter.bytesagain on line 212:This causes
BytesWritten()to return double the actual number of bytes when usingReadFromwith aTeewriter.Reproduction
Fix
Remove the redundant
f.basicWriter.bytes += int(n)line in the tee branch, sinceio.CopythroughbasicWriter.Writealready handles byte counting.