Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions lib/go/thrift/header_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,17 @@ func (t *THeaderTransport) Read(p []byte) (read int, err error) {
if err != nil {
return
}
if read < len(p) {
var nextRead int
nextRead, err = t.Read(p[read:])
read += nextRead
if read == 0 {
// Try to read the next frame when we hit EOF
// (end of frame) immediately.
// When we got here, it means the last read
// finished the previous frame, but didn't
// do endOfFrame handling yet.
// We have to read the next frame here,
// as otherwise we would return 0 and nil,
// which is a case not handled well by most
// protocol implementations.
return t.Read(p)
}
}
return
Expand Down
51 changes: 51 additions & 0 deletions lib/go/thrift/header_transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import (
"context"
"io"
"io/ioutil"
"strings"
"testing"
"testing/quick"
)

func TestTHeaderHeadersReadWrite(t *testing.T) {
Expand Down Expand Up @@ -128,3 +130,52 @@ func TestTHeaderTransportNoDoubleWrapping(t *testing.T) {
t.Errorf("NewTHeaderTransport double wrapped THeaderTransport")
}
}

func TestTHeaderTransportNoReadBeyondFrame(t *testing.T) {
trans := NewTMemoryBuffer()
writeContent := func(writer TTransport, content string) error {
if _, err := io.Copy(writer, strings.NewReader(content)); err != nil {
return err
}
if err := writer.Flush(context.Background()); err != nil {
return err
}
return nil
}
f := func(content string) bool {
defer trans.Reset()
if len(content) == 0 {
return true
}

reader := NewTHeaderTransport(trans)
writer := NewTHeaderTransport(trans)
// Write content twice
if err := writeContent(writer, content); err != nil {
t.Error(err)
}
if err := writeContent(writer, content); err != nil {
t.Error(err)
}
// buf is big enough to read both content out,
// but it shouldn't read beyond the first one in a single Read call.
buf := make([]byte, len(content)*3)
read, err := reader.Read(buf)
if err != nil {
t.Error(err)
}
if read == 0 || read > len(content) {
t.Errorf(
"Expected read in no more than %d:%q, got %d:%q",
len(content),
content,
read,
buf[:read],
)
}
return !t.Failed()
}
if err := quick.Check(f, nil); err != nil {
t.Error(err)
}
}