Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/internal/quic/quic.js
Original file line number Diff line number Diff line change
Expand Up @@ -1243,7 +1243,7 @@ function invokeOnerror(fn, error) {
}

function validateBody(body) {
if (body === undefined) return body;
if (body === undefined || body === null) return body;
// ArrayBuffers, SharedArrayBuffers, and ArrayBufferViews are passed
// through to the C++ layer which copies the bytes into its own
// BackingStore. Callers can therefore safely reuse or mutate their
Expand Down Expand Up @@ -1280,6 +1280,7 @@ function validateBody(body) {
'ArrayBufferView',
'Blob',
'FileHandle',
'null',
], body);
}

Expand Down
5 changes: 4 additions & 1 deletion src/quic/streams.cc
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,14 @@ std::unique_ptr<DataQueue::Entry> CreateEntryFromBuffer(

Maybe<std::shared_ptr<DataQueue>> Stream::GetDataQueueFromSource(
Environment* env, Local<Value> value) {
DCHECK_IMPLIES(!value->IsUndefined(), value->IsObject());
DCHECK(value->IsUndefined() || value->IsNull() || value->IsObject());
std::vector<std::unique_ptr<DataQueue::Entry>> entries;
if (value->IsUndefined()) {
// Return an empty DataQueue.
return Just(std::shared_ptr<DataQueue>());
} else if (value->IsNull()) {
// Return an empty, completed data source.
return Just(DataQueue::CreateIdempotent(std::move(entries)));
} else if (value->IsArrayBuffer()) {
auto buffer = value.As<ArrayBuffer>();
auto length = buffer->ByteLength();
Expand Down
78 changes: 54 additions & 24 deletions test/parallel/test-quic-stream-zero-length.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,57 @@ if (!hasQuic) {
const { listen, connect } = await import('../common/quic.mjs');
const { bytes } = await import('stream/iter');

const serverDone = Promise.withResolvers();

const serverEndpoint = await listen(mustCall((serverSession) => {
serverSession.onstream = mustCall(async (stream) => {
const received = await bytes(stream);
assert.strictEqual(received.byteLength, 0);
stream.writer.endSync();
await stream.closed;
serverSession.close();
serverDone.resolve();
});
}));

const clientSession = await connect(serverEndpoint.address);
await clientSession.opened;

const stream = await clientSession.createBidirectionalStream();
stream.setBody(null);

await dump(stream);

await Promise.all([stream.closed, serverDone.promise]);
await clientSession.close();
await serverEndpoint.close();
{
const serverDone = Promise.withResolvers();

const serverEndpoint = await listen(mustCall((serverSession) => {
serverSession.onstream = mustCall(async (stream) => {
const received = await bytes(stream);
assert.strictEqual(received.byteLength, 0);
stream.writer.endSync();
await stream.closed;
serverSession.close();
serverDone.resolve();
});
}));

const clientSession = await connect(serverEndpoint.address);
await clientSession.opened;

const stream = await clientSession.createBidirectionalStream();
stream.setBody(null);

await dump(stream);

await Promise.all([stream.closed, serverDone.promise]);
await clientSession.close();
await serverEndpoint.close();
}

// Stream via createBidirectionalStream({ body: null }).
{
const serverDone = Promise.withResolvers();

const serverEndpoint = await listen(mustCall((serverSession) => {
serverSession.onstream = mustCall(async (stream) => {
const received = await bytes(stream);
assert.strictEqual(received.byteLength, 0);
stream.writer.endSync();
await stream.closed;
serverSession.close();
serverDone.resolve();
});
}));

const clientSession = await connect(serverEndpoint.address);
await clientSession.opened;

const stream =
await clientSession.createBidirectionalStream({ body: null });

await dump(stream);

await Promise.all([stream.closed, serverDone.promise]);
await clientSession.close();
await serverEndpoint.close();
}
Loading