THRIFT-2619 Go lib http transport does not handle EOF correctly
Patch: Frank Schroeder
diff --git a/lib/go/thrift/http_client.go b/lib/go/thrift/http_client.go
index cff5ea5..df66897 100644
--- a/lib/go/thrift/http_client.go
+++ b/lib/go/thrift/http_client.go
@@ -21,6 +21,7 @@
import (
"bytes"
+ "io"
"net/http"
"net/url"
"strconv"
@@ -150,6 +151,9 @@
return 0, NewTTransportException(NOT_OPEN, "Response buffer is empty, no request.")
}
n, err := p.response.Body.Read(buf)
+ if n > 0 && (err == nil || err == io.EOF) {
+ return n, nil
+ }
return n, NewTTransportExceptionFromError(err)
}
diff --git a/lib/go/thrift/protocol_test.go b/lib/go/thrift/protocol_test.go
index 67048fe..7e7950d 100644
--- a/lib/go/thrift/protocol_test.go
+++ b/lib/go/thrift/protocol_test.go
@@ -170,7 +170,6 @@
ReadWriteBinary(t, p, trans)
trans.Close()
}
-
for _, tf := range transports {
trans := tf.GetTransport(nil)
p := protocolFactory.GetProtocol(trans)
@@ -180,7 +179,6 @@
ReadWriteByte(t, p, trans)
trans.Close()
}
-
}
func ReadWriteBool(t testing.TB, p TProtocol, trans TTransport) {
diff --git a/lib/go/thrift/rich_transport.go b/lib/go/thrift/rich_transport.go
index c409ae0..d7268d9 100644
--- a/lib/go/thrift/rich_transport.go
+++ b/lib/go/thrift/rich_transport.go
@@ -19,9 +19,7 @@
package thrift
-import (
- "io"
-)
+import "io"
type RichTransport struct {
TTransport
@@ -46,7 +44,14 @@
func readByte(r io.Reader) (c byte, err error) {
v := [1]byte{0}
- if _, err := r.Read(v[0:1]); err != nil {
+ n, err := r.Read(v[0:1])
+ if n > 0 && (err == nil || err == io.EOF) {
+ return v[0], nil
+ }
+ if n > 0 && err != nil {
+ return v[0], err
+ }
+ if err != nil {
return 0, err
}
return v[0], nil
diff --git a/lib/go/thrift/rich_transport_test.go b/lib/go/thrift/rich_transport_test.go
index 3241167..41513f8 100644
--- a/lib/go/thrift/rich_transport_test.go
+++ b/lib/go/thrift/rich_transport_test.go
@@ -21,6 +21,8 @@
import (
"bytes"
+ "errors"
+ "io"
"reflect"
"testing"
)
@@ -42,3 +44,42 @@
}
}
}
+
+// TestReadByte tests whether readByte handles error cases correctly.
+func TestReadByte(t *testing.T) {
+ for i, test := range readByteTests {
+ v, err := readByte(test.r)
+ if v != test.v {
+ t.Fatalf("TestReadByte %d: value differs. Expected %d, got %d", i, test.v, test.r.v)
+ }
+ if err != test.err {
+ t.Fatalf("TestReadByte %d: error differs. Expected %s, got %s", i, test.err, test.r.err)
+ }
+ }
+}
+
+var someError = errors.New("Some error")
+var readByteTests = []struct {
+ r *mockReader
+ v byte
+ err error
+}{
+ {&mockReader{0, 55, io.EOF}, 0, io.EOF}, // reader sends EOF w/o data
+ {&mockReader{0, 55, someError}, 0, someError}, // reader sends some other error
+ {&mockReader{1, 55, nil}, 55, nil}, // reader sends data w/o error
+ {&mockReader{1, 55, io.EOF}, 55, nil}, // reader sends data with EOF
+ {&mockReader{1, 55, someError}, 55, someError}, // reader sends data withsome error
+}
+
+type mockReader struct {
+ n int
+ v byte
+ err error
+}
+
+func (r *mockReader) Read(p []byte) (n int, err error) {
+ if r.n > 0 {
+ p[0] = r.v
+ }
+ return r.n, r.err
+}