commit b9fc0d2908371dc4f7c95c03972d42e290d6e1e0 (tree)
parent 80404cc928c758f7063da42a0d68669998613969
Author: Nameless <truemedian@gmail.com>
Date: Fri, 7 Jul 2023 15:08:19 -0500
std.http: fix leaked connections (#16341)
The early return in pool release was causing leaked connections.
Closes #16282.
Diffstat:
2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
@@ -92,16 +92,15 @@ pub const ConnectionPool = struct {
if (node.data.closing) {
node.data.deinit(client);
-
return client.allocator.destroy(node);
}
- if (pool.free_len + 1 >= pool.free_size) {
+ if (pool.free_len >= pool.free_size) {
const popped = pool.free.popFirst() orelse unreachable;
+ pool.free_len -= 1;
popped.data.deinit(client);
-
- return client.allocator.destroy(popped);
+ client.allocator.destroy(popped);
}
if (node.data.proxied) {
diff --git a/test/standalone/http.zig b/test/standalone/http.zig
@@ -571,6 +571,30 @@ pub fn main() !void {
// connection has been kept alive
try testing.expect(client.connection_pool.free_len == 1);
+ { // issue 16282
+ const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/get", .{port});
+ defer calloc.free(location);
+ const uri = try std.Uri.parse(location);
+
+ const total_connections = client.connection_pool.free_size + 64;
+ var requests = try calloc.alloc(http.Client.Request, total_connections);
+ defer calloc.free(requests);
+
+ for (0..total_connections) |i| {
+ var req = try client.request(.GET, uri, .{ .allocator = calloc }, .{});
+ req.response.parser.done = true;
+ req.connection.?.data.closing = false;
+ requests[i] = req;
+ }
+
+ for (0..total_connections) |i| {
+ requests[i].deinit();
+ }
+
+ // free connections should be full now
+ try testing.expect(client.connection_pool.free_len == client.connection_pool.free_size);
+ }
+
client.deinit();
killServer(server.socket.listen_address);