Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

HttpClient.withBytesBody ignores byteOffset/byteLength and sends the whole backing buffer

Cerrado Apto para principiantes
#57 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
86/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Tranquilo
Stack tecnológico
javascript
Área
api

Línea de trabajo

Comienza en gren-lang/node/src/Gren/Kernel/HttpClient.js, en _HttpClient_prepBytes, y luego sigue _HttpClient_extractRequestBody y la ruta de streaming de chunks para confirmar que ambos lo utilizan. Ejecuta el run.sh de la reproducción, incluidos los casos de payload pequeño agrupados; se considera terminado cuando /relay informa de que los recuentos de bytes enviados y recibidos son iguales, mientras el manejo existente de HttpServer permanece sin cambios.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug

HttpClient.withBytesBody ignores byteOffset/byteLength and sends the whole backing buffer

_HttpClient_prepBytes builds its Uint8Array from bytes.buffer alone:

// gren-lang/node/src/Gren/Kernel/HttpClient.js
var _HttpClient_prepBytes = function (bytes) {
  return new Uint8Array(bytes.buffer);
};

A Bytes value is a DataView, and a DataView is a window onto an
ArrayBuffer — byteOffset and byteLength are part of the value. Dropping
them sends everything in the backing buffer instead of the bytes the caller
asked for.

HttpServer builds a request body withBuffer.concat, and Node serves any
allocation under 4096 bytes out of a shared
8 KiB pool, so request.body is essentially always a view. Forwarding one
with withBytesBody puts 8192 bytes on the wire regardless of how few were
received, and the extra bytes are whatever else is in the pool — other requests'
data, in a server that handles more than one.

  • Package: gren-lang/node (HttpClient kernel)
  • Versions: gren 0.6.6, gren-lang/core 7.4.2, gren-lang/node 6.1.3, Node.js
    v25.1.0, Linux x86-64

Reproducing

A minimal reproduction is in the https://github.com/gilramir/gren-bug-reports
repo.

$ git clone https://github.com/gilramir/gren-bug-reports.git
$ cd gren-bug-reports/2026-08-16-withBytesBody
$ ./run.sh

src/Relay.gren is one ~160-line program serving three paths on :8086:

  • POST /echo reports how many bytes it received — the observer, nothing under
    test;
  • POST /relay forwards the request body to /echo with withBytesBody;
  • POST /relay-compact does the same after re-encoding the body through
    Bytes.Encode.bytes, which allocates an exact-width buffer at offset zero.

Note that Bytes.length request.body already reports the right number — the
DataView's byteLength is intact, and every Gren-level operation agrees with
it. Only the kernel's new Uint8Array(bytes.buffer) disagrees, which is why
this cannot be caught from inside the language.

Bytes.Encode.encode (Bytes.Encode.bytes …) on the /relay-compact path is a
copy into a buffer the value owns, fixing the behavior.
Each path answers sent=<n> received=<n>.

=== POST /relay — withBytesBody on the request body (expected: sent == received)
    8 bytes: sent=8 received=8192
  100 bytes: sent=100 received=8192
 4095 bytes: sent=4095 received=8192
 4096 bytes: sent=4096 received=4096
 5000 bytes: sent=5000 received=5000

=== POST /relay-compact — same, after re-encoding through Bytes.Encode.bytes
    8 bytes: sent=8 received=8
  100 bytes: sent=100 received=100
 4095 bytes: sent=4095 received=4095
 4096 bytes: sent=4096 received=4096
 5000 bytes: sent=5000 received=5000

By hand:

gren make Relay --output relay
node relay &
curl -s --data-binary '12345678' localhost:8086/relay          # sent=8 received=8192
curl -s --data-binary '12345678' localhost:8086/relay-compact  # sent=8 received=8

Why the cutoff is at 4096

Node's Buffer.allocUnsafe serves requests smaller than Buffer.poolSize >>> 1
(4096, with the default 8192 pool) from a shared pool, and allocates
independently at or above it. run.sh prints this directly:

Buffer.poolSize = 8192 -> pooled when size < 4096
    8 byteOffset     8  buffer.byteLength 8192  new Uint8Array(b.buffer).byteLength 8192
 4095 byteOffset    16  buffer.byteLength 8192  new Uint8Array(b.buffer).byteLength 8192
 4096 byteOffset     0  buffer.byteLength 4096  new Uint8Array(b.buffer).byteLength 4096

So the bug affects small payloads and spares large ones.
A test suite that exercises withBytesBody
with a Bytes.fromString literal will also miss it, because
Bytes.fromString produces a fresh exact-width buffer at offset zero.

Suggested fix

HttpServer already does this correctly;
_HttpServer_setBodyAsBytes passes all three arguments:

// gren-lang/node/src/Gren/Kernel/HttpServer.js
var _HttpServer_setBodyAsBytes = F2(function (data, res) {
  let body = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
  res.write(body);
  return res;
});

_HttpClient_prepBytes should match:

var _HttpClient_prepBytes = function (bytes) {
  return new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength);
};

That one line covers both call sites: the one-shot body path
(_HttpClient_extractRequestBody, the BYTES case, line 323) and the streaming
chunk path (line 231) both go through prepBytes.

Those are the only two new Uint8Array( in gren-lang/node's kernels, and the
other one is HttpServer's correct version:

$ grep -rn 'new Uint8Array(' src/Gren/Kernel/
src/Gren/Kernel/HttpServer.js:84:  let body = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
src/Gren/Kernel/HttpClient.js:330:  return new Uint8Array(bytes.buffer);

Related

The sibling report for another issue in 2026-08-16-flatten/ is the same mistake —
new Uint8Array(view.buffer), with the offset dropped — in gren-lang/core's
Bytes.flatten. It behaves differently there: flatten takes its length from
byteLength and only its contents from the wrong place, so the result is the
right size and the wrong bytes, which is harder to notice than this one. They
are independent fixes in different packages.

Worth knowing here because Bytes.flatten is the obvious way to copy a Bytes
before handing it to withBytesBody, and it does not work. Bytes.Encode.bytes
does, which is what /relay-compact uses.

Lenguaje dominante
JavaScript
Estrellas
13
Forks
6
Merge medio
3 d 4 h
PR fusionados (30 d)
3

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de gren-lang/node

Todos los issues de gren-lang/node

Issues similares

Más issues de JavaScript

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.