While using TCP stream was an option, in the end I went with original solution of writing custom TIdIOHandlerStack
descendant.
The motivation was that with TIdHTTP I know what doesn't work and only need to fix that, while switching to lower level TCP means new problems can arise.
Here's the code that I'm using, and I'm going to discuss the key points here.
New TIdStreamIoHandler
has to inherit from TIdIOHandlerStack
.
Two functions need to be rewritten: ReadBytes
and ReadStream
:
function TryReadBytes(var VBuffer: TIdBytes; AByteCount: Integer;
AAppend: Boolean = True): integer; virtual;
procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1;
AReadUntilDisconnect: Boolean = False); override;
Both are modified Indy functions which can be found in IdIOHandler.TIdIOHandler
. In ReadBytes
the while
clause has to be replaced with a singe ReadFromSource()
request, so that TryReadBytes
returns after reading up to AByteCount bytes in one go.
Based on this, ReadStream
has to handle all combinations of AByteCount (>0, <0) and ReadUntilDisconnect (true, false) to cyclically read and then write to stream chunks of data arriving from the socket.
Note that ReadStream
need not terminate prematurely even in this stream version if only part of the requested data is available in the socket. It just has to write that part to the stream instantly instead of caching it in FInputBuffer
, then block and wait for the next part of data.