Commit 107133ceb87 for nodejs
commit 107133ceb87ad9e7c33f3234a2cef652d69055ac
Author: Efe Karasakal <hi@efe.dev>
Date: Mon Oct 19 23:16:23 2026 +0200
quic: allow null body when opening streams
Signed-off-by: Efe Karasakal <hi@efe.dev>
PR-URL: https://github.com/nodejs/node/pull/66690
Reviewed-By: Tim Perry <pimterry@gmail.com>
diff --git a/lib/internal/quic/quic.js b/lib/internal/quic/quic.js
index d80b5846682..2d75c5cbe00 100644
--- a/lib/internal/quic/quic.js
+++ b/lib/internal/quic/quic.js
@@ -1253,7 +1253,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
@@ -1290,6 +1290,7 @@ function validateBody(body) {
'ArrayBufferView',
'Blob',
'FileHandle',
+ 'null',
], body);
}
diff --git a/src/quic/streams.cc b/src/quic/streams.cc
index 8e9d3570938..0a2af12d366 100644
--- a/src/quic/streams.cc
+++ b/src/quic/streams.cc
@@ -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();
diff --git a/test/parallel/test-quic-stream-zero-length.mjs b/test/parallel/test-quic-stream-zero-length.mjs
index 1c745ffc264..32f7bc52440 100644
--- a/test/parallel/test-quic-stream-zero-length.mjs
+++ b/test/parallel/test-quic-stream-zero-length.mjs
@@ -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();
+}