fix(ext/http2): fix oob buffer reads in http2 requests (#29969)

This commit is contained in:
Divy Srivastava 2025-07-02 09:28:50 -07:00 committed by GitHub
parent 7a1e949c47
commit 3a94adf956
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 1 deletions

View file

@ -1041,7 +1041,7 @@ export class ClientHttp2Stream extends Duplex {
data = ENCODER.encode(chunk);
} else if (encoding === "buffer") {
this.#encoding = encoding;
data = chunk.buffer;
data = new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
}
this.#requestPromise

View file

@ -71,6 +71,7 @@ for (const url of ["http://localhost:4246", "https://localhost:4247"]) {
"abc": "def",
"opr": "stv",
"foo": "bar",
"req_body_len": "5",
});
});
}
@ -121,6 +122,64 @@ Deno.test(`[node/http2 client createConnection]`, {
assertEquals(receivedData, "hello world\n");
});
// https://github.com/denoland/deno/issues/29956
Deno.test(`[node/http2 client body overflow]`, {
ignore: Deno.build.os === "windows",
}, async () => {
const url = "http://127.0.0.1:4246";
const createConnDeferred = Promise.withResolvers<void>();
// Create a server to respond to the HTTP2 requests
const client = http2.connect(url, {
createConnection() {
const socket = net.connect({ host: "127.0.0.1", port: 4246 });
socket.on("connect", () => {
createConnDeferred.resolve();
});
return socket;
},
});
client.on("error", (err) => console.error(err));
const req = client.request({ ":method": "POST", ":path": "/" });
let receivedData = "";
let receivedTrailers;
const ab = new ArrayBuffer(100);
const view = new Uint8Array(ab, 0, 5);
req.write(view);
req.setEncoding("utf8");
req.on("data", (chunk) => {
receivedData += chunk;
});
req.on("trailers", (trailers, _flags) => {
receivedTrailers = trailers;
});
req.end();
const endPromise = Promise.withResolvers<void>();
setTimeout(() => {
try {
client.close();
} catch (_) {
// pass
}
endPromise.resolve();
}, 2000);
await createConnDeferred.promise;
await endPromise.promise;
assertEquals(receivedData, "hello world\n");
assertEquals(receivedTrailers?.["req_body_len"], "5");
});
Deno.test("[node/http2 client GET https://www.example.com]", async () => {
const clientSession = http2.connect("https://www.example.com");
const req = clientSession.request({

View file

@ -52,9 +52,11 @@ pub async fn h2_grpc_server(h2_grpc_port: u16, h2s_grpc_port: u16) {
mut respond: h2::server::SendResponse<bytes::Bytes>,
) -> Result<(), anyhow::Error> {
let body = request.body_mut();
let mut len = 0;
while let Some(data) = body.data().await {
let data = data?;
let _ = body.flow_control().release_capacity(data.len());
len += data.len();
}
let maybe_recv_trailers = body.trailers().await?;
@ -72,6 +74,10 @@ pub async fn h2_grpc_server(h2_grpc_port: u16, h2s_grpc_port: u16) {
HeaderName::from_static("opr"),
HeaderValue::from_static("stv"),
);
trailers.insert(
HeaderName::from_static("req_body_len"),
HeaderValue::from(len),
);
if let Some(recv_trailers) = maybe_recv_trailers {
for (key, value) in recv_trailers {
trailers.insert(key.unwrap(), value);