I'm currently adding vibe.d support to the dlang-requests package (see https://github.com/ikod/dlang-requests/pull/23). The main problem is implementing timeouts. I've used waitForData for now, but I fear that this implementation is not completely correct:

if (!_sslStream.dataAvailableForRead) {
    if (!_conn.waitForData(_readTimeout)) {
        if (!_conn.connected) {
            return 0;
        }
        throw new TimeoutException("Timeout receiving data");
    }
}

if(_sslStream.empty) {
    return 0;
}

auto chunk = min(_sslStream.leastSize, buff.length);
assert(chunk != 0);
_sslStream.read(cast(ubyte[])buff[0 .. chunk]);
return chunk;

What happens if waitForData only reads SSL 'management' data? I guess then
leastSize will have to read from _conn as it's not known yet whether there might be more data. But in this case there's no timeout enforced.

I know that .readTimeout has slightly different semantics. But I think for dlang-requests the readTimeout semantics (i.e. total time no data received != time since last .read call) should work fine. However, I do have to throw TimeoutExceptions.

So what exactly happens when a readTimeout occurs? The docs say the connection gets closed, but what happens if there's a pending read (possibly in a wrapped TLSStream)?

  • Does the read throw an Exception?
  • What Type of Exception?
  • Is it possible to differentiate other errors from timeouts?

If there's no pending read, can I simply call read some time after a timeout and use the same error handling as above? If not, I guess I'd have to check the .connected property. But AFAICS there's no way to know if the user explicitly closed a connection? So I'd have to add a manuallyClosed flag somewhere in the wrapper. OTOH the docs say there can still be data in a closed stream, so if I check connected instead of empty I might miss some data?

TLDR;
I guess what I really want to know is how I can safely use .readTimeout with a wrapper stream and make sure a TimeoutException is thrown from my reading function:

  • if the timeout occurs during a call to this function
  • or if it occurred before.