mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
Fixes #25862 ### What does this PR do? When a client sends pipelined data immediately after CONNECT request headers in the same TCP segment, Bun now properly delivers this data to the `head` parameter of the 'connect' event handler, matching Node.js behavior. This enables compatibility with Cap'n Proto's KJ HTTP library used by Cloudflare's workerd runtime, which pipelines RPC data after CONNECT. ### How did you verify your code works? <img width="694" height="612" alt="CleanShot 2026-01-09 at 15 30 22@2x" src="https://github.com/user-attachments/assets/3ffe840e-1792-429c-8303-d98ac3e6912a" /> Tests --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { once } from "node:events";
|
|
import http from "node:http";
|
|
import type { AddressInfo } from "node:net";
|
|
import net from "node:net";
|
|
|
|
// Test for https://github.com/oven-sh/bun/issues/25862
|
|
// Pipelined data sent immediately after CONNECT request headers should be
|
|
// delivered to the `head` parameter of the 'connect' event handler.
|
|
|
|
test("CONNECT request should receive pipelined data in head parameter", async () => {
|
|
const PIPELINED_DATA = "PIPELINED_DATA";
|
|
const { promise: headReceived, resolve: resolveHead } = Promise.withResolvers<Buffer>();
|
|
|
|
await using server = http.createServer();
|
|
|
|
server.on("connect", (req, socket, head) => {
|
|
resolveHead(head);
|
|
socket.write("HTTP/1.1 200 Connection Established\r\n\r\n");
|
|
socket.end();
|
|
});
|
|
|
|
await once(server.listen(0, "127.0.0.1"), "listening");
|
|
const { port, address } = server.address() as AddressInfo;
|
|
|
|
const { promise: clientDone, resolve: resolveClient } = Promise.withResolvers<void>();
|
|
|
|
const client = net.connect({ port, host: address }, () => {
|
|
// Send CONNECT request with pipelined data in the same write
|
|
// This simulates what Cap'n Proto's KJ HTTP library does
|
|
client.write(`CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n${PIPELINED_DATA}`);
|
|
});
|
|
|
|
client.on("data", () => {
|
|
// We got the response, we can close
|
|
client.end();
|
|
});
|
|
|
|
client.on("close", () => {
|
|
resolveClient();
|
|
});
|
|
|
|
const head = await headReceived;
|
|
await clientDone;
|
|
|
|
expect(head).toBeInstanceOf(Buffer);
|
|
expect(head.length).toBe(PIPELINED_DATA.length);
|
|
expect(head.toString()).toBe(PIPELINED_DATA);
|
|
});
|