Compare commits

...

2 Commits

Author SHA1 Message Date
Jarred-Sumner
59700e230e bun run prettier 2025-05-18 18:56:14 +00:00
Jarred Sumner
e99a2dc928 fix chunked decoding 2025-05-18 11:53:41 -07:00
2 changed files with 44 additions and 10 deletions

View File

@@ -4165,21 +4165,23 @@ fn handleResponseBodyChunkedEncodingFromMultiplePackets(
var decoder = &this.state.chunked_decoder;
const buffer_ptr = this.state.getBodyBuffer();
var buffer = buffer_ptr.*;
const prev_len = buffer.list.items.len;
try buffer.appendSlice(incoming_data);
// set consume_trailer to 1 to discard the trailing header
// using content-encoding per chunk is not supported
decoder.consume_trailer = 1;
var bytes_decoded = incoming_data.len;
var buf_len = buffer.list.items.len;
// phr_decode_chunked mutates in-place
const pret = picohttp.phr_decode_chunked(
decoder,
buffer.list.items.ptr + (buffer.list.items.len -| incoming_data.len),
&bytes_decoded,
buffer.list.items.ptr,
&buf_len,
);
buffer.list.items.len -|= incoming_data.len - bytes_decoded;
this.state.total_body_received += bytes_decoded;
const consumed = buf_len - prev_len;
this.state.total_body_received += consumed;
buffer.list.items.len = buf_len;
buffer_ptr.* = buffer;
@@ -4249,15 +4251,16 @@ fn handleResponseBodyChunkedEncodingFromSinglePacket(
@memcpy(buffer[0..incoming_data.len], incoming_data);
}
var bytes_decoded = incoming_data.len;
var buf_len = buffer.len;
// phr_decode_chunked mutates in-place
const pret = picohttp.phr_decode_chunked(
decoder,
buffer.ptr + (buffer.len -| incoming_data.len),
&bytes_decoded,
buffer.ptr,
&buf_len,
);
buffer.len -|= incoming_data.len - bytes_decoded;
this.state.total_body_received += bytes_decoded;
const consumed = buf_len;
this.state.total_body_received += consumed;
buffer.len = buf_len;
switch (pret) {
// Invalid HTTP response body

View File

@@ -0,0 +1,31 @@
import { expect, it } from "bun:test";
it("handles trailing headers split across packets", async () => {
const server = await Bun.listen({
hostname: "localhost",
port: 0,
socket: {
open(socket) {
socket.write("HTTP/1.1 200 OK\r\n");
socket.write("Content-Type: text/plain\r\n");
socket.write("Transfer-Encoding: chunked\r\n");
socket.write("\r\n");
socket.write("5\r\nHello\r\n");
socket.write("7\r\n, world\r\n");
socket.write("0\r\n");
socket.flush();
setTimeout(() => {
socket.write("X-Trail: ok\r\n\r\n");
socket.end();
}, 10).unref();
},
data() {},
close() {},
},
});
const res = await fetch(`http://${server.hostname}:${server.port}`);
expect(res.status).toBe(200);
expect(await res.text()).toBe("Hello, world");
server.stop(true);
});