Respond BYOB request before enqueueing.

For WebTransport streams and datagrams, try to fill the buffer provided
by BYOB requests first. Enqueue received data in the controlled readable
stream only when buffer is not enough or no BYOB request exists. It
avoids the creation and use of an intermediate buffer.

Bug: 1259886
Change-Id: If07bca7709e7c5b55a274d3150f7c17b64fd14ec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3984631
Commit-Queue: Nidhi Jaju <nidhijaju@chromium.org>
Reviewed-by: Nidhi Jaju <nidhijaju@chromium.org>
Reviewed-by: Adam Rice <ricea@chromium.org>
Auto-Submit: Jianjun Zhu <jianjun.zhu@intel.com>
Cr-Commit-Position: refs/heads/main@{#1068038}
diff --git a/webtransport/datagrams.https.any.js b/webtransport/datagrams.https.any.js
index 32da926..b96b36f 100644
--- a/webtransport/datagrams.https.any.js
+++ b/webtransport/datagrams.https.any.js
@@ -23,7 +23,8 @@
   return sentTokens;
 }
 
-// Read datagrams until the consumer has received enough i.e. N datagrams.
+// Read datagrams until the consumer has received enough i.e. N datagrams. Call
+// abort() after reading.
 async function read_datagrams(reader, controller, N) {
   const decoder = new TextDecoder();
   const receivedTokens = [];
@@ -40,11 +41,10 @@
 async function write_numbers(writer, signal) {
   let counter = 0;
   const sentNumbers = [];
-  const aborted = new Promise((resolve) => {
-    signal.addEventListener('abort', resolve);
-  });
+  const aborted =
+    new Promise((resolve) => signal.addEventListener('abort', resolve));
   // Counter should be less than 256 because reader stores numbers in Uint8Array.
-  while (true && counter < 256) {
+  while (counter < 256) {
     await Promise.race([writer.ready, aborted])
     if (signal.aborted) {
       break;
@@ -58,7 +58,22 @@
   return sentNumbers;
 }
 
-// Read datagrams with BYOB reader until the consumer has received enough i.e. N datagrams.
+// Write large datagrams of size 10 until the producer receives the AbortSignal.
+async function write_large_datagrams(writer, signal) {
+  const aborted = new Promise((resolve) => {
+    signal.addEventListener('abort', resolve);
+  });
+  while (true) {
+    await Promise.race([writer.ready, aborted]);
+    if (signal.aborted) {
+      break;
+    }
+    writer.write(new Uint8Array(10));
+  }
+}
+
+// Read datagrams with BYOB reader until the consumer has received enough i.e. N
+// datagrams. Call abort() after reading.
 async function read_numbers_byob(reader, controller, N) {
   let buffer = new ArrayBuffer(N);
   buffer = await readInto(reader, buffer);
@@ -117,6 +132,30 @@
 }, 'Successfully reading datagrams with BYOB reader.');
 
 promise_test(async t => {
+  // Establish a WebTransport session.
+  const wt = new WebTransport(webtransport_url('echo.py'));
+  await wt.ready;
+
+  const writer = wt.datagrams.writable.getWriter();
+  const reader = wt.datagrams.readable.getReader({ mode: 'byob' });
+
+  const controller = new AbortController();
+  const signal = controller.signal;
+
+  // Write datagrams of size 10, but only 1 byte buffer is provided for BYOB
+  // reader. To avoid splitting a datagram, stream will be errored.
+  const buffer = new ArrayBuffer(1);
+  const [error, _] = await Promise.all([
+    reader.read(new Uint8Array(buffer)).catch(e => {
+      controller.abort();
+      return e;
+    }),
+    write_large_datagrams(writer, signal)
+  ]);
+  assert_equals(error.name, 'RangeError');
+}, 'Reading datagrams with insufficient buffer should be rejected.');
+
+promise_test(async t => {
   // Make a WebTransport connection, but session is not necessarily established.
   const wt = new WebTransport(webtransport_url('echo.py'));
 
diff --git a/webtransport/streams-echo.https.any.js b/webtransport/streams-echo.https.any.js
index 8ec698e..3278141 100644
--- a/webtransport/streams-echo.https.any.js
+++ b/webtransport/streams-echo.https.any.js
@@ -142,8 +142,8 @@
   const reader = recv_stream.getReader({mode: 'byob'});
   assert_true(reader instanceof ReadableStreamBYOBReader);
   const half_buffer_size = buffer_size / 2;
+  let buffer = new ArrayBuffer(half_buffer_size);
   for (let i = 0; i < 2; i++) {
-    let buffer = new ArrayBuffer(half_buffer_size);
     buffer = await readInto(reader, buffer);
     assert_array_equals(
         new Uint8Array(buffer),