Skip to content

httpFancyWriter.ReadFrom double-counts BytesWritten when Tee is set #1067

@queelius

Description

@queelius

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions