THRIFT-3229 unexpected Timeout exception when desired bytes are only partially available
Client: Delphi
Patch Jens Geyer
diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas
index 96735ec..c485e70 100644
--- a/lib/delphi/src/Thrift.Transport.pas
+++ b/lib/delphi/src/Thrift.Transport.pas
@@ -160,7 +160,7 @@
     function Select( ReadReady, WriteReady, ExceptFlag: PBoolean;
                      TimeOut: Integer; var wsaError : Integer): Integer;
     function WaitForData( TimeOut : Integer; pBuf : Pointer; DesiredBytes: Integer;
-                          var wsaError : Integer): TWaitForData;
+                          var wsaError, bytesReady : Integer): TWaitForData;
   protected
     procedure Write( const buffer: TBytes; offset: Integer; count: Integer); override;
     function Read( var buffer: TBytes; offset: Integer; count: Integer): Integer; override;
@@ -1277,10 +1277,12 @@
 
 function TTcpSocketStreamImpl.WaitForData( TimeOut : Integer; pBuf : Pointer;
                                            DesiredBytes : Integer;
-                                           var wsaError : Integer): TWaitForData;
+                                           var wsaError, bytesReady : Integer): TWaitForData;
 var bCanRead, bError : Boolean;
     retval : Integer;
 begin
+  bytesReady := 0;
+
   // The select function returns the total number of socket handles that are ready
   // and contained in the fd_set structures, zero if the time limit expired,
   // or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR,
@@ -1297,42 +1299,48 @@
   if retval <= 0
   then Exit( TWaitForData.wfd_Error);
 
-  // Enough data ready to be read?
-  if retval = DesiredBytes
-  then result := TWaitForData.wfd_HaveData
-  else result := TWaitForData.wfd_Timeout;
+  // at least we have some data
+  bytesReady := Min( retval, DesiredBytes);
+  result := TWaitForData.wfd_HaveData;
 end;
 
 function TTcpSocketStreamImpl.Read(var buffer: TBytes; offset, count: Integer): Integer;
 var wfd : TWaitForData;
-    wsaError : Integer;
-    pDest : Pointer;
+    wsaError, nBytes : Integer;
+    pDest : PByte;
 const
   SLEEP_TIME = 200;
 begin
   inherited;
 
+  result := 0;
   pDest := Pointer(@buffer[offset]);
+  while count > 0 do begin
 
-  while TRUE do begin
-    if FTimeout > 0
-    then wfd := WaitForData( FTimeout,   pDest, count, wsaError)
-    else wfd := WaitForData( SLEEP_TIME, pDest, count, wsaError);
+    while TRUE do begin
+      if FTimeout > 0
+      then wfd := WaitForData( FTimeout,   pDest, count, wsaError, nBytes)
+      else wfd := WaitForData( SLEEP_TIME, pDest, count, wsaError, nBytes);
 
-    case wfd of
-      TWaitForData.wfd_Error    :  Exit(0);
-      TWaitForData.wfd_HaveData :  Break;
-      TWaitForData.wfd_Timeout  :  begin
-        if (FTimeout > 0)
-        then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
-                                               SysErrorMessage(Cardinal(wsaError)));
+      case wfd of
+        TWaitForData.wfd_Error    :  Exit(0);
+        TWaitForData.wfd_HaveData :  Break;
+        TWaitForData.wfd_Timeout  :  begin
+          if (FTimeout > 0)
+          then raise TTransportException.Create( TTransportException.TExceptionType.TimedOut,
+                                                 SysErrorMessage(Cardinal(wsaError)));
+        end;
+      else
+        ASSERT( FALSE);
       end;
-    else
-      ASSERT( FALSE);
     end;
-  end;
 
-  Result := FTcpClient.ReceiveBuf( pDest^, count);
+    ASSERT( nBytes <= count);
+    nBytes := FTcpClient.ReceiveBuf( pDest^, nBytes);
+    Inc( pDest, nBytes);
+    Dec( count, nBytes);
+    Inc( result, nBytes);
+  end;
 end;
 
 function TTcpSocketStreamImpl.ToArray: TBytes;