]> Cypherpunks.ru repositories - gostls13.git/commitdiff
bufio: Reader.Read may return io.EOF even when it has data buffered
authorDaniel Cormier <danielc@knowbe4.com>
Wed, 19 Jun 2019 16:32:30 +0000 (12:32 -0400)
committerRobert Griesemer <gri@golang.org>
Thu, 20 Jun 2019 20:04:54 +0000 (20:04 +0000)
If reading 0 bytes, don't return the error from the underlying
io.Reader if there is still data buffered.

Fixes #32693

Change-Id: I12a97bd6003c638c15d41028942f27edf88340e2
Reviewed-on: https://go-review.googlesource.com/c/go/+/182997
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/bufio/bufio.go
src/bufio/bufio_test.go

index 0125d729d1b31e679ab390d122e1c927c8d5a313..0f05d3b32211ea45417fd159d1817fcb82038d1b 100644 (file)
@@ -197,6 +197,9 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
 func (b *Reader) Read(p []byte) (n int, err error) {
        n = len(p)
        if n == 0 {
+               if b.Buffered() > 0 {
+                       return 0, nil
+               }
                return 0, b.readErr()
        }
        if b.r == b.w {
index f7a0682e7033dd2f4c6b6664b98fd7d1df9fea06..782ca2149aa57bc68aee7221435a57d102fe3e31 100644 (file)
@@ -1481,6 +1481,60 @@ func newScriptedReader(steps ...func(p []byte) (n int, err error)) io.Reader {
        return &sr
 }
 
+// eofReader returns the number of bytes read and io.EOF for the read that consumes the last of the content.
+type eofReader struct {
+       buf []byte
+}
+
+func (r *eofReader) Read(p []byte) (int, error) {
+       read := copy(p, r.buf)
+       r.buf = r.buf[read:]
+
+       switch read {
+       case 0, len(r.buf):
+               // As allowed in the documentation, this will return io.EOF
+               // in the same call that consumes the last of the data.
+               // https://godoc.org/io#Reader
+               return read, io.EOF
+       }
+
+       return read, nil
+}
+
+func TestPartialReadEOF(t *testing.T) {
+       src := make([]byte, 10)
+       eofR := &eofReader{buf: src}
+       r := NewReader(eofR)
+
+       // Start by reading 5 of the 10 available bytes.
+       dest := make([]byte, 5)
+       read, err := r.Read(dest)
+       if err != nil {
+               t.Fatalf("unexpected error: %v", err)
+       }
+       if n := len(dest); read != n {
+               t.Fatalf("read %d bytes; wanted %d bytes", read, n)
+       }
+
+       // The Reader should have buffered all the content from the io.Reader.
+       if n := len(eofR.buf); n != 0 {
+               t.Fatalf("got %d bytes left in bufio.Reader source; want 0 bytes", n)
+       }
+       // To prove the point, check that there are still 5 bytes available to read.
+       if n := r.Buffered(); n != 5 {
+               t.Fatalf("got %d bytes buffered in bufio.Reader; want 5 bytes", n)
+       }
+
+       // This is the second read of 0 bytes.
+       read, err = r.Read([]byte{})
+       if err != nil {
+               t.Fatalf("unexpected error: %v", err)
+       }
+       if read != 0 {
+               t.Fatalf("read %d bytes; want 0 bytes", read)
+       }
+}
+
 func BenchmarkReaderCopyOptimal(b *testing.B) {
        // Optimal case is where the underlying reader implements io.WriterTo
        srcBuf := bytes.NewBuffer(make([]byte, 8192))