diff --git a/internal/proto/reader.go b/internal/proto/reader.go index 6dda42d3..ebe85ff3 100644 --- a/internal/proto/reader.go +++ b/internal/proto/reader.go @@ -55,13 +55,10 @@ func (r *Reader) Reset(rd io.Reader) { } func (r *Reader) ReadLine() ([]byte, error) { - line, err := r.rd.ReadBytes('\n') - if err != nil && err != io.EOF { + line, err := r.readLine() + if err != nil { return nil, err } - if len(line) == 0 { - return nil, fmt.Errorf("redis: reply is empty") - } if isNilReply(line) { return nil, Nil } @@ -72,15 +69,29 @@ func (r *Reader) ReadLine() ([]byte, error) { // - there is a pending read error; // - or line does not end with \r\n. func (r *Reader) readLine() ([]byte, error) { - b, err := r.rd.ReadSlice('\n') - if err != nil { - return nil, err + var s []byte + multi := false + for { + b, err := r.rd.ReadSlice('\n') + if err != nil { + // in case the end of the buffer is not reached + if err == bufio.ErrBufferFull { + s = append(s, b...) + multi = true + continue + } else { + return nil, err + } + } + if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' { + return nil, fmt.Errorf("redis: invalid reply: %q", b) + } + if multi { + b = append(s, b...) + } + b = b[:len(b)-2] + return b, nil } - if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' { - return nil, fmt.Errorf("redis: invalid reply: %q", b) - } - b = b[:len(b)-2] - return b, nil } func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) { diff --git a/internal/proto/reader_test.go b/internal/proto/reader_test.go index a57b38b6..b8c99dd6 100644 --- a/internal/proto/reader_test.go +++ b/internal/proto/reader_test.go @@ -2,6 +2,7 @@ package proto_test import ( "bytes" + "io" "testing" "github.com/go-redis/redis/v8/internal/proto" @@ -29,14 +30,16 @@ func BenchmarkReader_ParseReply_Slice(b *testing.B) { func TestReader_ReadLine(t *testing.T) { original := bytes.Repeat([]byte("a"), 8192) + original[len(original)-2] = '\r' + original[len(original)-1] = '\n' r := proto.NewReader(bytes.NewReader(original)) read, err := r.ReadLine() - if err != nil { + if err != nil && err != io.EOF { t.Errorf("Should be able to read the full buffer: %v", err) } - if bytes.Compare(read, original) != 0 { - t.Errorf("Values must be equal: %q", read) + if bytes.Compare(read, original[:len(original)-2]) != 0 { + t.Errorf("Values must be equal: %d expected %d", len(read), len(original[:len(original)-2])) } }