Compare commits

...

5 Commits

Author SHA1 Message Date
autofix-ci[bot]
47827a9fef [autofix.ci] apply automated fixes 2025-09-01 01:00:43 +00:00
Claude Bot
f8371fdb78 Optimize http.Server.getConnections implementation
- Make callback asynchronous using process.nextTick to match Node.js behavior
- Remove socket.on('close') event listener to avoid performance overhead
- Use existing #onClose method in NodeHTTPServerSocket for connection cleanup
- Update regression tests to handle async callback behavior

Performance improvements:
- Eliminates adding/removing event listeners for each connection
- Uses existing socket cleanup mechanism instead of adding new listeners
- Callback now properly async via process.nextTick like Node.js

All tests pass and behavior matches Node.js exactly.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-01 00:58:22 +00:00
Claude Bot
2d3937609b Implement getConnections method for http.Server - fixes #4459
The issue was that http.Server in Bun didn't have the getConnections method,
unlike Node.js where http.Server inherits from net.Server. Users trying to
call server.getConnections() on HTTP servers would get "is not a function".

Changes:
- Add _connections counter to HTTP Server constructor
- Implement Server.prototype.getConnections() matching Node.js API
- Add connection tracking: increment on new connections, decrement on close
- Add comprehensive regression tests for both net.Server and http.Server

The implementation matches Node.js behavior exactly:
- Returns connection count via callback (err, count)
- Returns 0 when server is not listening
- Supports method chaining by returning 'this'
- Never errors (unlike Node.js which can error during worker polling)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 02:05:32 +00:00
Claude Bot
5051985f77 Fix async test pattern in issue #4459 regression test
Move expect() calls outside of async callbacks to follow proper Bun test
patterns. Instead of using expect() inside nested getConnections() callbacks,
collect results in an array and verify them after the promise resolves.

This ensures the test assertions are properly handled by Bun's test runner.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 01:40:55 +00:00
Claude Bot
645ac18814 Add regression test for issue #4459 - server.getConnections
This adds comprehensive regression tests for GitHub issue #4459 which
reported that server.getConnections was not implemented. The issue has
been resolved in the current codebase - the method is fully implemented
in src/js/node/net.ts and works identically to Node.js.

The tests verify:
- getConnections returns 0 when no clients are connected
- Connection count increases/decreases as clients connect/disconnect
- Method chaining works correctly
- Method works when server is not listening

Fixes #4459

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-31 01:34:58 +00:00
2 changed files with 179 additions and 0 deletions

View File

@@ -204,6 +204,7 @@ function Server(options, callback): void {
this[kInternalSocketData] = undefined;
this[tlsSymbol] = null;
this.noDelay = true;
this._connections = 0;
if (typeof options === "function") {
callback = options;
options = {};
@@ -361,6 +362,18 @@ Server.prototype.address = function () {
return this[serverSymbol].address;
};
Server.prototype.getConnections = function (callback) {
if (typeof callback === "function") {
// In Bun case we will never error on getConnections
// Node only errors if in the middle of counting the server got disconnected,
// which never happens in Bun
// If disconnected will only pass null as well and 0 connected
const count = this[serverSymbol] ? this._connections : 0;
process.nextTick(callback, null, count);
}
return this;
};
Server.prototype.listen = function () {
const server = this;
let port, host, onListen;
@@ -552,6 +565,7 @@ Server.prototype[kRealListen] = function (tls, port, host, socketPath, reusePort
}
if (isSocketNew && !reachedRequestsLimit) {
server._connections++;
server.emit("connection", socket);
}
@@ -820,6 +834,12 @@ const NodeHTTPServerSocket = class Socket extends Duplex {
}
#onClose() {
this[kHandle] = null;
// Decrement connection count when socket closes
if (this.server && this.server._connections > 0) {
this.server._connections--;
}
const message = this._httpMessage;
const req = message?.req;
if (req && !req.complete && !req[kHandle]?.upgraded) {

View File

@@ -0,0 +1,159 @@
/**
* Regression test for GitHub issue #4459
* https://github.com/oven-sh/bun/issues/4459
*
* Issue: "server.getConnections is not implemented"
* Expected: getConnections should work exactly like Node.js
*/
import { expect, test } from "bun:test";
import * as http from "http";
import * as net from "net";
test("issue #4459: server.getConnections should be implemented and work like Node.js", async () => {
const server = net.createServer();
const { promise, resolve, reject } = Promise.withResolvers<void>();
const results: Array<{ err: any; count: number }> = [];
server.listen(0, () => {
const port = server.address()!.port;
// Test 1: No connections initially
server.getConnections((err, count) => {
results.push({ err, count });
// Test 2: Create connection and verify count increases
const client1 = net.createConnection(port, () => {
setTimeout(() => {
server.getConnections((err, count) => {
results.push({ err, count });
// Test 3: Create second connection
const client2 = net.createConnection(port, () => {
setTimeout(() => {
server.getConnections((err, count) => {
results.push({ err, count });
// Test 4: Close one connection
client1.end();
setTimeout(() => {
server.getConnections((err, count) => {
results.push({ err, count });
// Test 5: Close second connection
client2.end();
setTimeout(() => {
server.getConnections((err, count) => {
results.push({ err, count });
server.close();
resolve();
});
}, 50);
});
}, 50);
});
}, 50);
});
client2.on("error", reject);
});
}, 50);
});
client1.on("error", reject);
});
});
server.on("error", reject);
await promise;
// Now we can safely use expect() outside the callbacks
expect(results).toHaveLength(5);
expect(results[0]).toEqual({ err: null, count: 0 }); // No connections initially
expect(results[1]).toEqual({ err: null, count: 1 }); // After client1 connects
expect(results[2]).toEqual({ err: null, count: 2 }); // After client2 connects
expect(results[3]).toEqual({ err: null, count: 1 }); // After client1 disconnects
expect(results[4]).toEqual({ err: null, count: 0 }); // After client2 disconnects
});
test("issue #4459: getConnections should support method chaining", () => {
const server = net.createServer();
// Method should return the server instance for chaining
const result = server.getConnections(() => {});
expect(result).toBe(server);
server.close();
});
test("issue #4459: getConnections should work when server is not listening", () => {
const server = net.createServer();
let callbackCalled = false;
let callbackErr: any = undefined;
let callbackCount: number = -1;
const callback = (err: any, count: number) => {
callbackCalled = true;
callbackErr = err;
callbackCount = count;
};
// Should call callback with 0 connections when not listening
server.getConnections(callback);
expect(callbackCalled).toBe(true);
expect(callbackErr).toBeNull();
expect(callbackCount).toBe(0);
});
test("issue #4459: http.Server.getConnections should be implemented", async () => {
const server = http.createServer();
// Test that the method exists
expect(typeof server.getConnections).toBe("function");
// Test basic functionality - should return 0 when not listening (async)
const { promise, resolve } = Promise.withResolvers<{ err: any; count: number }>();
const callback = (err: any, count: number) => {
resolve({ err, count });
};
server.getConnections(callback);
const result = await promise;
expect(result.err).toBeNull();
expect(result.count).toBe(0);
server.close();
});
test("issue #4459: http.Server.getConnections should support method chaining", () => {
const server = http.createServer();
// Method should return the server instance for chaining
const result = server.getConnections(() => {});
expect(result).toBe(server);
server.close();
});
test("issue #4459: http.Server.getConnections should work when server is not listening", async () => {
const server = http.createServer();
// Should call callback with 0 connections when not listening (async)
const { promise, resolve } = Promise.withResolvers<{ err: any; count: number }>();
const callback = (err: any, count: number) => {
resolve({ err, count });
};
server.getConnections(callback);
const result = await promise;
expect(result.err).toBeNull();
expect(result.count).toBe(0);
});