You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
LimitedInputStream in vibe.stream.counting is used to limit the number of bytes available to readers in cases similar to when an HTTP response specifies the body content-length.
However, current implementation forbids the usage of the following pattern that uses IOMode.once:
// input is an instance of LimitedInputStream in case Content-length header is availableauto input = res.bodyReader();
// 1024 is larger than received content lengthconst bufferLength = exactBuffer ? res.headers["Content-length"].to!size_t() : 1024;
ubyte[] buffer = newubyte[](bufferLength);
while (!input.empty)
{
const chunk = input.read(buffer[], IOMode.once); // <---- IOMode.once is important
logInfo("received: %s", buffer[0.. chunk].assumeUTF);
}
My understanding of IOMode.once is that the stream will provide whatever data is currently available (limited by the provided buffer size of course) or will block until at least some data is available.
Current implementation of LimitedInputStream checks whether the provided buffer length exceeds the maximum allowed length to be read and errors if so without considering IOMode.
So is my understanding and my expectation of the pattern above to work correctly correct?
If so, I would change LimitedInputStream.read to:
always check length only in IOMode.all
provide whatever number of bytes is allowed in IOMode.immediate and IOMode.once.
only error out when read is called with IOMode.immediate and IOMode.once when all allowed bytes were consumed previously.
Below is a runnable test case:
import vibe.core.core;
import vibe.core.net;
import vibe.http.server, vibe.http.client;
import vibe.stream.operations;
import vibe.core.log;
importstd.format: format;
importstd.string: assumeUTF;
importstd.conv: to;
voidmain()
{
/* when exactBuffer is true, the buffer into which the data is being read has equal length to the content-length of the response. when exactBuffer is false, the buffer is 1024 bytes long. The problem manifests when a larger buffer than the data available on the stream is used: vibe.stream.counting.LimitedInputStream errors with `vibe.stream.counting.LimitException@../../stream/vibe/stream/counting.d(134): Size limit reached`*/bool exactBuffer = false;
auto server = setupServer();
runTask(&client, server.bindAddresses[0], exactBuffer);
runApplication();
server.stopListening();
}
HTTPListener setupServer()
{
auto settings = new HTTPServerSettings();
settings.port = 0;
settings.bindAddresses = ["127.0.0.1"];
returnlistenHTTP(settings, &handler);
}
boolclient(NetworkAddress addr, bool exactBuffer) nothrow
{
try
{
const url = "http://%s/".format(addr.toString());
requestHTTP(
url,
(scope req) {},
(scope res)
{
auto input = res.bodyReader();
// 1024 is larger than received content lengthconst bufferLength = exactBuffer ? res.headers["Content-length"].to!ulong() : 1024;
ubyte[] buffer = newubyte[](bufferLength);
while (!input.empty)
{
const chunk = input.read(buffer[], IOMode.once);
logInfo("received: %s", buffer[0.. chunk].assumeUTF);
}
}
);
returntrue;
}
catch (Exception ex)
{
logError("Exception thrown: %s", ex);
returnfalse;
}
finally
{
exitEventLoop();
}
}
voidhandler(scope HTTPServerRequest _, scope HTTPServerResponse res)
{
res.writeBody("my length is 15");
}
The text was updated successfully, but these errors were encountered:
Yes, that sounds correct! LimitedInputStream hasn't been fully adjusted when IOMode was introduced (and I think there are some more stream types, too).
yazd
added a commit
to yazd/vibe.d
that referenced
this issue
Dec 29, 2021
LimitedInputStream
invibe.stream.counting
is used to limit the number of bytes available to readers in cases similar to when an HTTP response specifies the body content-length.However, current implementation forbids the usage of the following pattern that uses
IOMode.once
:My understanding of
IOMode.once
is that the stream will provide whatever data is currently available (limited by the provided buffer size of course) or will block until at least some data is available.Current implementation of
LimitedInputStream
checks whether the provided buffer length exceeds the maximum allowed length to be read and errors if so without consideringIOMode
.So is my understanding and my expectation of the pattern above to work correctly correct?
If so, I would change
LimitedInputStream.read
to:IOMode.all
IOMode.immediate
andIOMode.once
.IOMode.immediate
andIOMode.once
when all allowed bytes were consumed previously.Below is a runnable test case:
The text was updated successfully, but these errors were encountered: