Skip to content

Commit b66d05b

Browse files
authored
Merge pull request #1524 from eelcocramer/bufio-fix
Fixes bufio buffer full error when reading from an array larger than 4096 bytes
2 parents bdeca5f + 39571cc commit b66d05b

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

internal/proto/reader.go

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,29 @@ func (r *Reader) ReadLine() ([]byte, error) {
6969
// - there is a pending read error;
7070
// - or line does not end with \r\n.
7171
func (r *Reader) readLine() ([]byte, error) {
72-
b, err := r.rd.ReadSlice('\n')
73-
if err != nil {
74-
return nil, err
75-
}
76-
if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
77-
return nil, fmt.Errorf("redis: invalid reply: %q", b)
72+
var s []byte
73+
multi := false
74+
for {
75+
b, err := r.rd.ReadSlice('\n')
76+
if err != nil {
77+
// in case the end of the buffer is not reached
78+
if err == bufio.ErrBufferFull {
79+
s = append(s, b...)
80+
multi = true
81+
continue
82+
} else {
83+
return nil, err
84+
}
85+
}
86+
if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' {
87+
return nil, fmt.Errorf("redis: invalid reply: %q", b)
88+
}
89+
if multi {
90+
b = append(s, b...)
91+
}
92+
b = b[:len(b)-2]
93+
return b, nil
7894
}
79-
b = b[:len(b)-2]
80-
return b, nil
8195
}
8296

8397
func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) {

internal/proto/reader_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package proto_test
22

33
import (
44
"bytes"
5+
"io"
56
"testing"
67

78
"github.com/go-redis/redis/v8/internal/proto"
@@ -27,6 +28,21 @@ func BenchmarkReader_ParseReply_Slice(b *testing.B) {
2728
benchmarkParseReply(b, "*2\r\n$5\r\nhello\r\n$5\r\nworld\r\n", multiBulkParse, false)
2829
}
2930

31+
func TestReader_ReadLine(t *testing.T) {
32+
original := bytes.Repeat([]byte("a"), 8192)
33+
original[len(original)-2] = '\r'
34+
original[len(original)-1] = '\n'
35+
r := proto.NewReader(bytes.NewReader(original))
36+
read, err := r.ReadLine()
37+
if err != nil && err != io.EOF {
38+
t.Errorf("Should be able to read the full buffer: %v", err)
39+
}
40+
41+
if bytes.Compare(read, original[:len(original)-2]) != 0 {
42+
t.Errorf("Values must be equal: %d expected %d", len(read), len(original[:len(original)-2]))
43+
}
44+
}
45+
3046
func benchmarkParseReply(b *testing.B, reply string, m proto.MultiBulkParse, wanterr bool) {
3147
buf := new(bytes.Buffer)
3248
for i := 0; i < b.N; i++ {

0 commit comments

Comments
 (0)