mirror of
https://github.com/golang/go
synced 2024-11-23 20:40:07 -07:00
bufio: fix bug that ReadFrom stops before EOF or error
ReadFrom should not return until it receives a non-nil error or too many contiguous (0, nil)s from a given reader. Currently it immediately returns if it receives one (0, nil). Fixes #7611. LGTM=bradfitz R=golang-codereviews, bradfitz CC=golang-codereviews https://golang.org/cl/76400048
This commit is contained in:
parent
a43673cf8a
commit
4ffc799295
@ -38,6 +38,7 @@ type Reader struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const minReadBufferSize = 16
|
const minReadBufferSize = 16
|
||||||
|
const maxConsecutiveEmptyReads = 100
|
||||||
|
|
||||||
// NewReaderSize returns a new Reader whose buffer has at least the specified
|
// NewReaderSize returns a new Reader whose buffer has at least the specified
|
||||||
// size. If the argument io.Reader is already a Reader with large enough
|
// size. If the argument io.Reader is already a Reader with large enough
|
||||||
@ -625,9 +626,16 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
return n, err1
|
return n, err1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m, err = r.Read(b.buf[b.n:])
|
nr := 0
|
||||||
if m == 0 {
|
for nr < maxConsecutiveEmptyReads {
|
||||||
break
|
m, err = r.Read(b.buf[b.n:])
|
||||||
|
if m != 0 || err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nr++
|
||||||
|
}
|
||||||
|
if nr == maxConsecutiveEmptyReads {
|
||||||
|
return n, io.ErrNoProgress
|
||||||
}
|
}
|
||||||
b.n += m
|
b.n += m
|
||||||
n += int64(m)
|
n += int64(m)
|
||||||
|
@ -1060,6 +1060,60 @@ func TestWriterReadFromWhileFull(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type emptyThenNonEmptyReader struct {
|
||||||
|
r io.Reader
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *emptyThenNonEmptyReader) Read(p []byte) (int, error) {
|
||||||
|
if r.n <= 0 {
|
||||||
|
return r.r.Read(p)
|
||||||
|
}
|
||||||
|
r.n--
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for golang.org/issue/7611
|
||||||
|
func TestWriterReadFromUntilEOF(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
w := NewWriterSize(buf, 5)
|
||||||
|
|
||||||
|
// Partially fill buffer
|
||||||
|
n, err := w.Write([]byte("0123"))
|
||||||
|
if n != 4 || err != nil {
|
||||||
|
t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use ReadFrom to read in some data.
|
||||||
|
r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 3}
|
||||||
|
n2, err := w.ReadFrom(r)
|
||||||
|
if n2 != 4 || err != nil {
|
||||||
|
t.Fatalf("ReadFrom returned (%v, %v), want (4, nil)", n2, err)
|
||||||
|
}
|
||||||
|
w.Flush()
|
||||||
|
if got, want := string(buf.Bytes()), "0123abcd"; got != want {
|
||||||
|
t.Fatalf("buf.Bytes() returned %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriterReadFromErrNoProgress(t *testing.T) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
w := NewWriterSize(buf, 5)
|
||||||
|
|
||||||
|
// Partially fill buffer
|
||||||
|
n, err := w.Write([]byte("0123"))
|
||||||
|
if n != 4 || err != nil {
|
||||||
|
t.Fatalf("Write returned (%v, %v), want (4, nil)", n, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use ReadFrom to read in some data.
|
||||||
|
r := &emptyThenNonEmptyReader{r: strings.NewReader("abcd"), n: 100}
|
||||||
|
n2, err := w.ReadFrom(r)
|
||||||
|
if n2 != 0 || err != io.ErrNoProgress {
|
||||||
|
t.Fatalf("buf.Bytes() returned (%v, %v), want (0, io.ErrNoProgress)", n2, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReaderReset(t *testing.T) {
|
func TestReaderReset(t *testing.T) {
|
||||||
r := NewReader(strings.NewReader("foo foo"))
|
r := NewReader(strings.NewReader("foo foo"))
|
||||||
buf := make([]byte, 3)
|
buf := make([]byte, 3)
|
||||||
|
@ -172,7 +172,7 @@ func (s *Scanner) Scan() bool {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
loop++
|
loop++
|
||||||
if loop > 100 {
|
if loop > maxConsecutiveEmptyReads {
|
||||||
s.setErr(io.ErrNoProgress)
|
s.setErr(io.ErrNoProgress)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user