THRIFT-5211 Handle incomplete reads correctly
Client: Haskell
Patch: Philipp Hausmann

This closes #2108

The read functions for handles promise to return *up* to the requested
number of bytes. This means in case we read less bytes, we should try
again to read some more bytes.
diff --git a/lib/hs/src/Thrift/Transport/Framed.hs b/lib/hs/src/Thrift/Transport/Framed.hs
index 42fc43f..ad553ae 100644
--- a/lib/hs/src/Thrift/Transport/Framed.hs
+++ b/lib/hs/src/Thrift/Transport/Framed.hs
@@ -87,11 +87,11 @@
 readFrame :: Transport t => FramedTransport t -> IO Int
 readFrame trans = do
   -- Read and decode the frame size.
-  szBs <- tRead (wrappedTrans trans) 4
+  szBs <- tReadAll (wrappedTrans trans) 4
   let sz = fromIntegral (B.decode szBs :: Int32)
 
   -- Read the frame and stuff it into the read buffer.
-  bs <- tRead (wrappedTrans trans) sz
+  bs <- tReadAll (wrappedTrans trans) sz
   fillBuf (readBuffer trans) bs
 
   -- Return the frame size so that the caller knows whether to expect
diff --git a/lib/hs/src/Thrift/Transport/Handle.hs b/lib/hs/src/Thrift/Transport/Handle.hs
index ff6295b..528a027 100644
--- a/lib/hs/src/Thrift/Transport/Handle.hs
+++ b/lib/hs/src/Thrift/Transport/Handle.hs
@@ -28,6 +28,7 @@
     ) where
 
 import Control.Exception ( catch, throw )
+import Control.Monad ( when )
 import Data.ByteString.Internal (c2w)
 import Data.Functor
 
@@ -50,7 +51,13 @@
           hLookAhead h
           LBS.hGetNonBlocking h n
     tReadAll _ 0 = return mempty
-    tReadAll h n = LBS.hGet h n `Control.Exception.catch` throwTransportExn
+    tReadAll h n = do
+      result <- LBS.hGet h n `Control.Exception.catch` throwTransportExn
+      let rlen = fromIntegral $ LBS.length result
+      when (rlen == 0) (throw $ TransportExn "Cannot read. Remote side has closed." TE_UNKNOWN)
+      if n <= rlen
+        then return result
+        else (result `mappend`) <$> tReadAll h (n - rlen)
     tPeek h = (Just . c2w <$> hLookAhead h) `Control.Exception.catch` handleEOF Nothing
     tWrite = LBS.hPut
     tFlush = hFlush