oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
74.07k stars 2.76k forks source link

node:http request events not firing #13373

Closed Lyall-A closed 1 month ago

Lyall-A commented 2 months ago

What version of Bun is running?

1.1.24+85a329911

What platform is your computer?

Linux 6.10.5-arch1-1 x86_64 unknown

What steps can reproduce the bug?

const http = require("http");
const server = http.createServer();

server.on("request", (req, res) => {
    console.log("opened");
    req.on("close", () => console.log("closed")); // doesnt fire with bun
    res.end("hi");
});

server.listen(5001);

What is the expected behavior?

$ node ./test.js $ curl http://localhost:5001 opened closed

What do you see instead?

$ bun ./test.js $ curl http://localhost:5001 opened

Additional information

No response

kevinmingtarja commented 2 months ago

i was able to repro this too on 1.1.25, and Darwin 23.6.0 arm64.

this may or may not be related, but i dug a bit deeper, and was able to see that with node, if i pass in a "Connection: close" header, the http connection does get closed, as seen by the verbose output of curl:

% curl 127.0.0.1:5001 -H "Connection: close" -v
* processing: 127.0.0.1:5001
*   Trying 127.0.0.1:5001...
* Connected to 127.0.0.1 (127.0.0.1) port 5001
> GET / HTTP/1.1
> Host: 127.0.0.1:5001
> User-Agent: curl/8.2.1
> Accept: */*
> Connection: close
> 
< HTTP/1.1 200 OK
< Date: Sun, 18 Aug 2024 03:54:19 GMT
< Connection: close
< Content-Length: 2
< 
* Closing connection
hi

but with Bun, it does not:

% curl 127.0.0.1:5001 -H "Connection: close" -v
* processing: 127.0.0.1:5001
*   Trying 127.0.0.1:5001...
* Connected to 127.0.0.1 (127.0.0.1) port 5001
> GET / HTTP/1.1
> Host: 127.0.0.1:5001
> User-Agent: curl/8.2.1
> Accept: */*
> Connection: close
> 
< HTTP/1.1 200 OK
< content-type: text/plain;charset=utf-8
< Date: Sun, 18 Aug 2024 03:55:17 GMT
< Content-Length: 2
< 
* Connection #0 to host 127.0.0.1 left intact
hi

also for reference (https://nodejs.org/api/http.html#event-close_3):

Emitted when the request has been completed.

kevinmingtarja commented 2 months ago

found another subtle difference on req.complete. so with node, req.complete is initially false, and only became true after the "close" event is fired. but with bun, req.complete is immediately true. maybe there's a race condition somewhere?

so if we modify the code to:

const http = require("http");
const server = http.createServer();

server.on("request", (req, res) => {
    console.log("opened");
    req.on("close", () => {
        console.log("closed")
        console.log(req.complete) // new
    }); // doesnt fire with bun
    console.log(req.complete) // new
    res.end("hi");
});

server.listen(5001);

node:

% node test.js
opened
false
closed
true

bun:

% bun run test.js 
opened
true
Lyall-A commented 2 months ago

there is some weird stuff with http.request too, but it changes depending on how stuff is written

const http = require("http");

const server = http.createServer();

// Server
server.on("request", (req, res) => {
    console.log("[Server] New request"); // gets fired with bun
    req.on("close", () => console.log("[Server] Request closed")); // nope
    res.end("hi");
});

server.listen(8080, () => {
    console.log("Listening at :8080\n");

    // Client
    const client = http.request({ host: "localhost", port: 8080 }).end();
    client.on("response", res => {
        res.on("data", data => console.log(`[Client] Got: ${data.toString()}`));
        console.log("[Client] Client connected");
    });
    client.on("close", () => console.log("[Client] Client closed")); // this is called before response on bun
});