Commit 483b63d301

Andrew Kelley <andrew@ziglang.org>
2024-02-23 03:19:12
std.http: migrate remaining test/standalone/http.zig to std lib
These tests were not being actually run. Now they are run along with testing the standard library.
1 parent 10beb19
Changed files (4)
lib
test
lib/std/http/Client.zig
@@ -1676,3 +1676,7 @@ pub fn fetch(client: *Client, options: FetchOptions) !FetchResult {
         .status = req.response.status,
     };
 }
+
+test {
+    _ = &initDefaultProxies;
+}
lib/std/http/test.zig
@@ -1,5 +1,7 @@
 const builtin = @import("builtin");
 const std = @import("std");
+const http = std.http;
+const mem = std.mem;
 const native_endian = builtin.cpu.arch.endian();
 const expect = std.testing.expect;
 const expectEqual = std.testing.expectEqual;
@@ -15,7 +17,7 @@ test "trailers" {
                 const conn = try net_server.accept();
                 defer conn.stream.close();
 
-                var server = std.http.Server.init(conn, &header_buffer);
+                var server = http.Server.init(conn, &header_buffer);
 
                 try expectEqual(.ready, server.state);
                 var request = try server.receiveHead();
@@ -24,7 +26,7 @@ test "trailers" {
             }
         }
 
-        fn serve(request: *std.http.Server.Request) !void {
+        fn serve(request: *http.Server.Request) !void {
             try expectEqualStrings(request.head.target, "/trailer");
 
             var send_buffer: [1024]u8 = undefined;
@@ -46,7 +48,7 @@ test "trailers" {
 
     const gpa = std.testing.allocator;
 
-    var client: std.http.Client = .{ .allocator = gpa };
+    var client: http.Client = .{ .allocator = gpa };
     defer client.deinit();
 
     const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/trailer", .{
@@ -103,14 +105,14 @@ test "HTTP server handles a chunked transfer coding request" {
             const conn = try net_server.accept();
             defer conn.stream.close();
 
-            var server = std.http.Server.init(conn, &header_buffer);
+            var server = http.Server.init(conn, &header_buffer);
             var request = try server.receiveHead();
 
             try expect(request.head.transfer_encoding == .chunked);
 
             var buf: [128]u8 = undefined;
             const n = try (try request.reader()).readAll(&buf);
-            try expect(std.mem.eql(u8, buf[0..n], "ABCD"));
+            try expect(mem.eql(u8, buf[0..n], "ABCD"));
 
             try request.respond("message from server!\n", .{
                 .extra_headers = &.{
@@ -151,18 +153,18 @@ test "echo content server" {
                 const conn = try net_server.accept();
                 defer conn.stream.close();
 
-                var http_server = std.http.Server.init(conn, &read_buffer);
+                var http_server = http.Server.init(conn, &read_buffer);
 
                 while (http_server.state == .ready) {
                     var request = http_server.receiveHead() catch |err| switch (err) {
                         error.HttpConnectionClosing => continue :accept,
                         else => |e| return e,
                     };
-                    if (std.mem.eql(u8, request.head.target, "/end")) {
+                    if (mem.eql(u8, request.head.target, "/end")) {
                         return request.respond("", .{ .keep_alive = false });
                     }
                     if (request.head.expect) |expect_header_value| {
-                        if (std.mem.eql(u8, expect_header_value, "garbage")) {
+                        if (mem.eql(u8, expect_header_value, "garbage")) {
                             try expectError(error.HttpExpectationFailed, request.reader());
                             try request.respond("", .{ .keep_alive = false });
                             continue;
@@ -178,7 +180,7 @@ test "echo content server" {
             }
         }
 
-        fn handleRequest(request: *std.http.Server.Request) !void {
+        fn handleRequest(request: *http.Server.Request) !void {
             //std.debug.print("server received {s} {s} {s}\n", .{
             //    @tagName(request.head.method),
             //    @tagName(request.head.version),
@@ -188,7 +190,7 @@ test "echo content server" {
             const body = try (try request.reader()).readAllAlloc(std.testing.allocator, 8192);
             defer std.testing.allocator.free(body);
 
-            try expect(std.mem.startsWith(u8, request.head.target, "/echo-content"));
+            try expect(mem.startsWith(u8, request.head.target, "/echo-content"));
             try expectEqualStrings("Hello, World!\n", body);
             try expectEqualStrings("text/plain", request.head.content_type.?);
 
@@ -215,7 +217,7 @@ test "echo content server" {
     defer test_server.destroy();
 
     {
-        var client: std.http.Client = .{ .allocator = std.testing.allocator };
+        var client: http.Client = .{ .allocator = std.testing.allocator };
         defer client.deinit();
 
         try echoTests(&client, test_server.port());
@@ -233,7 +235,7 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" {
                 const conn = try net_server.accept();
                 defer conn.stream.close();
 
-                var server = std.http.Server.init(conn, &header_buffer);
+                var server = http.Server.init(conn, &header_buffer);
 
                 try expectEqual(.ready, server.state);
                 var request = try server.receiveHead();
@@ -288,7 +290,474 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" {
     try expectEqualStrings(expected_response.items, response);
 }
 
-fn echoTests(client: *std.http.Client, port: u16) !void {
+test "general client/server API coverage" {
+    const global = struct {
+        var handle_new_requests = true;
+    };
+    const test_server = try createTestServer(struct {
+        fn run(net_server: *std.net.Server) anyerror!void {
+            var client_header_buffer: [1024]u8 = undefined;
+            outer: while (global.handle_new_requests) {
+                var connection = try net_server.accept();
+                defer connection.stream.close();
+
+                var http_server = http.Server.init(connection, &client_header_buffer);
+
+                while (http_server.state == .ready) {
+                    var request = http_server.receiveHead() catch |err| switch (err) {
+                        error.HttpConnectionClosing => continue :outer,
+                        else => |e| return e,
+                    };
+
+                    try handleRequest(&request, net_server.listen_address.getPort());
+                }
+            }
+        }
+
+        fn handleRequest(request: *http.Server.Request, listen_port: u16) !void {
+            const log = std.log.scoped(.server);
+
+            log.info("{} {s} {s}", .{
+                request.head.method,
+                @tagName(request.head.version),
+                request.head.target,
+            });
+
+            const gpa = std.testing.allocator;
+            const body = try (try request.reader()).readAllAlloc(gpa, 8192);
+            defer gpa.free(body);
+
+            var send_buffer: [100]u8 = undefined;
+
+            if (mem.startsWith(u8, request.head.target, "/get")) {
+                var response = request.respondStreaming(.{
+                    .send_buffer = &send_buffer,
+                    .content_length = if (mem.indexOf(u8, request.head.target, "?chunked") == null)
+                        14
+                    else
+                        null,
+                    .respond_options = .{
+                        .extra_headers = &.{
+                            .{ .name = "content-type", .value = "text/plain" },
+                        },
+                    },
+                });
+                const w = response.writer();
+                try w.writeAll("Hello, ");
+                try w.writeAll("World!\n");
+                try response.end();
+                // Writing again would cause an assertion failure.
+            } else if (mem.startsWith(u8, request.head.target, "/large")) {
+                var response = request.respondStreaming(.{
+                    .send_buffer = &send_buffer,
+                    .content_length = 14 * 1024 + 14 * 10,
+                });
+
+                try response.flush(); // Test an early flush to send the HTTP headers before the body.
+
+                const w = response.writer();
+
+                var i: u32 = 0;
+                while (i < 5) : (i += 1) {
+                    try w.writeAll("Hello, World!\n");
+                }
+
+                try w.writeAll("Hello, World!\n" ** 1024);
+
+                i = 0;
+                while (i < 5) : (i += 1) {
+                    try w.writeAll("Hello, World!\n");
+                }
+
+                try response.end();
+            } else if (mem.eql(u8, request.head.target, "/redirect/1")) {
+                var response = request.respondStreaming(.{
+                    .send_buffer = &send_buffer,
+                    .respond_options = .{
+                        .status = .found,
+                        .extra_headers = &.{
+                            .{ .name = "location", .value = "../../get" },
+                        },
+                    },
+                });
+
+                const w = response.writer();
+                try w.writeAll("Hello, ");
+                try w.writeAll("Redirected!\n");
+                try response.end();
+            } else if (mem.eql(u8, request.head.target, "/redirect/2")) {
+                try request.respond("Hello, Redirected!\n", .{
+                    .status = .found,
+                    .extra_headers = &.{
+                        .{ .name = "location", .value = "/redirect/1" },
+                    },
+                });
+            } else if (mem.eql(u8, request.head.target, "/redirect/3")) {
+                const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/2", .{
+                    listen_port,
+                });
+                defer gpa.free(location);
+
+                try request.respond("Hello, Redirected!\n", .{
+                    .status = .found,
+                    .extra_headers = &.{
+                        .{ .name = "location", .value = location },
+                    },
+                });
+            } else if (mem.eql(u8, request.head.target, "/redirect/4")) {
+                try request.respond("Hello, Redirected!\n", .{
+                    .status = .found,
+                    .extra_headers = &.{
+                        .{ .name = "location", .value = "/redirect/3" },
+                    },
+                });
+            } else if (mem.eql(u8, request.head.target, "/redirect/invalid")) {
+                const invalid_port = try getUnusedTcpPort();
+                const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}", .{invalid_port});
+                defer gpa.free(location);
+
+                try request.respond("", .{
+                    .status = .found,
+                    .extra_headers = &.{
+                        .{ .name = "location", .value = location },
+                    },
+                });
+            } else {
+                try request.respond("", .{ .status = .not_found });
+            }
+        }
+
+        fn getUnusedTcpPort() !u16 {
+            const addr = try std.net.Address.parseIp("127.0.0.1", 0);
+            var s = try addr.listen(.{});
+            defer s.deinit();
+            return s.listen_address.in.getPort();
+        }
+    });
+    defer test_server.destroy();
+
+    const log = std.log.scoped(.client);
+
+    const gpa = std.testing.allocator;
+    var client: http.Client = .{ .allocator = gpa };
+    errdefer client.deinit();
+    // defer client.deinit(); handled below
+
+    const port = test_server.port();
+
+    { // read content-length response
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+        try expectEqualStrings("text/plain", req.response.content_type.?);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // read large content-length response
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/large", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192 * 1024);
+        defer gpa.free(body);
+
+        try expectEqual(@as(usize, 14 * 1024 + 14 * 10), body.len);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // send head request and not read chunked
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.HEAD, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("", body);
+        try expectEqualStrings("text/plain", req.response.content_type.?);
+        try expectEqual(14, req.response.content_length.?);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // read chunked response
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get?chunked", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+        try expectEqualStrings("text/plain", req.response.content_type.?);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // send head request and not read chunked
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get?chunked", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.HEAD, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("", body);
+        try expectEqualStrings("text/plain", req.response.content_type.?);
+        try expect(req.response.transfer_encoding == .chunked);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // read content-length response with connection close
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+            .keep_alive = false,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+        try expectEqualStrings("text/plain", req.response.content_type.?);
+    }
+
+    // connection has been closed
+    try expect(client.connection_pool.free_len == 0);
+
+    { // relative redirect
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/1", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // redirect from root
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/2", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // absolute redirect
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/3", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        try req.wait();
+
+        const body = try req.reader().readAllAlloc(gpa, 8192);
+        defer gpa.free(body);
+
+        try expectEqualStrings("Hello, World!\n", body);
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // too many redirects
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/4", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        req.wait() catch |err| switch (err) {
+            error.TooManyHttpRedirects => {},
+            else => return err,
+        };
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // check client without segfault by connection error after redirection
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/redirect/invalid", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        log.info("{s}", .{location});
+        var server_header_buffer: [1024]u8 = undefined;
+        var req = try client.open(.GET, uri, .{
+            .server_header_buffer = &server_header_buffer,
+        });
+        defer req.deinit();
+
+        try req.send(.{});
+        const result = req.wait();
+
+        // a proxy without an upstream is likely to return a 5xx status.
+        if (client.http_proxy == null) {
+            try expectError(error.ConnectionRefused, result); // expects not segfault but the regular error
+        }
+    }
+
+    // connection has been kept alive
+    try expect(client.http_proxy != null or client.connection_pool.free_len == 1);
+
+    { // issue 16282 *** This test leaves the client in an invalid state, it must be last ***
+        const location = try std.fmt.allocPrint(gpa, "http://127.0.0.1:{d}/get", .{port});
+        defer gpa.free(location);
+        const uri = try std.Uri.parse(location);
+
+        const total_connections = client.connection_pool.free_size + 64;
+        var requests = try gpa.alloc(http.Client.Request, total_connections);
+        defer gpa.free(requests);
+
+        var header_bufs = std.ArrayList([]u8).init(gpa);
+        defer header_bufs.deinit();
+        defer for (header_bufs.items) |item| gpa.free(item);
+
+        for (0..total_connections) |i| {
+            const headers_buf = try gpa.alloc(u8, 1024);
+            try header_bufs.append(headers_buf);
+            var req = try client.open(.GET, uri, .{
+                .server_header_buffer = headers_buf,
+            });
+            req.response.parser.done = true;
+            req.connection.?.closing = false;
+            requests[i] = req;
+        }
+
+        for (0..total_connections) |i| {
+            requests[i].deinit();
+        }
+
+        // free connections should be full now
+        try expect(client.connection_pool.free_len == client.connection_pool.free_size);
+    }
+
+    client.deinit();
+
+    {
+        global.handle_new_requests = false;
+
+        const conn = try std.net.tcpConnectToAddress(test_server.net_server.listen_address);
+        conn.close();
+    }
+}
+
+fn echoTests(client: *http.Client, port: u16) !void {
     const gpa = std.testing.allocator;
     var location_buffer: [100]u8 = undefined;
 
test/standalone/http.zig
@@ -1,510 +0,0 @@
-const std = @import("std");
-
-const http = std.http;
-
-const mem = std.mem;
-const testing = std.testing;
-
-pub const std_options = .{
-    .http_disable_tls = true,
-};
-
-const max_header_size = 8192;
-
-var gpa_server = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 12 }){};
-var gpa_client = std.heap.GeneralPurposeAllocator(.{ .stack_trace_frames = 12 }){};
-
-const salloc = gpa_server.allocator();
-const calloc = gpa_client.allocator();
-
-fn handleRequest(request: *http.Server.Request, listen_port: u16) !void {
-    const log = std.log.scoped(.server);
-
-    log.info("{} {s} {s}", .{
-        request.head.method,
-        @tagName(request.head.version),
-        request.head.target,
-    });
-
-    const body = try (try request.reader()).readAllAlloc(salloc, 8192);
-    defer salloc.free(body);
-
-    var send_buffer: [100]u8 = undefined;
-
-    if (mem.startsWith(u8, request.head.target, "/get")) {
-        var response = request.respondStreaming(.{
-            .send_buffer = &send_buffer,
-            .content_length = if (std.mem.indexOf(u8, request.head.target, "?chunked") == null)
-                14
-            else
-                null,
-            .respond_options = .{
-                .extra_headers = &.{
-                    .{ .name = "content-type", .value = "text/plain" },
-                },
-            },
-        });
-        const w = response.writer();
-        try w.writeAll("Hello, ");
-        try w.writeAll("World!\n");
-        try response.end();
-        // Writing again would cause an assertion failure.
-    } else if (mem.startsWith(u8, request.head.target, "/large")) {
-        var response = request.respondStreaming(.{
-            .send_buffer = &send_buffer,
-            .content_length = 14 * 1024 + 14 * 10,
-        });
-
-        try response.flush(); // Test an early flush to send the HTTP headers before the body.
-
-        const w = response.writer();
-
-        var i: u32 = 0;
-        while (i < 5) : (i += 1) {
-            try w.writeAll("Hello, World!\n");
-        }
-
-        try w.writeAll("Hello, World!\n" ** 1024);
-
-        i = 0;
-        while (i < 5) : (i += 1) {
-            try w.writeAll("Hello, World!\n");
-        }
-
-        try response.end();
-    } else if (mem.eql(u8, request.head.target, "/redirect/1")) {
-        var response = request.respondStreaming(.{
-            .send_buffer = &send_buffer,
-            .respond_options = .{
-                .status = .found,
-                .extra_headers = &.{
-                    .{ .name = "location", .value = "../../get" },
-                },
-            },
-        });
-
-        const w = response.writer();
-        try w.writeAll("Hello, ");
-        try w.writeAll("Redirected!\n");
-        try response.end();
-    } else if (mem.eql(u8, request.head.target, "/redirect/2")) {
-        try request.respond("Hello, Redirected!\n", .{
-            .status = .found,
-            .extra_headers = &.{
-                .{ .name = "location", .value = "/redirect/1" },
-            },
-        });
-    } else if (mem.eql(u8, request.head.target, "/redirect/3")) {
-        const location = try std.fmt.allocPrint(salloc, "http://127.0.0.1:{d}/redirect/2", .{
-            listen_port,
-        });
-        defer salloc.free(location);
-
-        try request.respond("Hello, Redirected!\n", .{
-            .status = .found,
-            .extra_headers = &.{
-                .{ .name = "location", .value = location },
-            },
-        });
-    } else if (mem.eql(u8, request.head.target, "/redirect/4")) {
-        try request.respond("Hello, Redirected!\n", .{
-            .status = .found,
-            .extra_headers = &.{
-                .{ .name = "location", .value = "/redirect/3" },
-            },
-        });
-    } else if (mem.eql(u8, request.head.target, "/redirect/invalid")) {
-        const invalid_port = try getUnusedTcpPort();
-        const location = try std.fmt.allocPrint(salloc, "http://127.0.0.1:{d}", .{invalid_port});
-        defer salloc.free(location);
-
-        try request.respond("", .{
-            .status = .found,
-            .extra_headers = &.{
-                .{ .name = "location", .value = location },
-            },
-        });
-    } else {
-        try request.respond("", .{ .status = .not_found });
-    }
-}
-
-var handle_new_requests = true;
-
-fn runServer(server: *std.net.Server) !void {
-    var client_header_buffer: [1024]u8 = undefined;
-    outer: while (handle_new_requests) {
-        var connection = try server.accept();
-        defer connection.stream.close();
-
-        var http_server = http.Server.init(connection, &client_header_buffer);
-
-        while (http_server.state == .ready) {
-            var request = http_server.receiveHead() catch |err| switch (err) {
-                error.HttpConnectionClosing => continue :outer,
-                else => |e| return e,
-            };
-
-            try handleRequest(&request, server.listen_address.getPort());
-        }
-    }
-}
-
-fn serverThread(server: *std.net.Server) void {
-    defer _ = gpa_server.deinit();
-
-    runServer(server) catch |err| {
-        std.debug.print("server error: {}\n", .{err});
-
-        if (@errorReturnTrace()) |trace| {
-            std.debug.dumpStackTrace(trace.*);
-        }
-
-        _ = gpa_server.deinit();
-        std.os.exit(1);
-    };
-}
-
-fn getUnusedTcpPort() !u16 {
-    const addr = try std.net.Address.parseIp("127.0.0.1", 0);
-    var s = try addr.listen(.{});
-    defer s.deinit();
-    return s.listen_address.in.getPort();
-}
-
-pub fn main() !void {
-    const log = std.log.scoped(.client);
-
-    defer _ = gpa_client.deinit();
-
-    const addr = std.net.Address.parseIp("127.0.0.1", 0) catch unreachable;
-    var server = try addr.listen(.{ .reuse_address = true });
-    defer server.deinit();
-
-    const port = server.listen_address.getPort();
-
-    const server_thread = try std.Thread.spawn(.{}, serverThread, .{&server});
-
-    var client: http.Client = .{ .allocator = calloc };
-    errdefer client.deinit();
-    // defer client.deinit(); handled below
-
-    var arena_instance = std.heap.ArenaAllocator.init(calloc);
-    defer arena_instance.deinit();
-    const arena = arena_instance.allocator();
-
-    try client.initDefaultProxies(arena);
-
-    { // read content-length response
-        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);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-        try testing.expectEqualStrings("text/plain", req.response.content_type.?);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // read large content-length response
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/large", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192 * 1024);
-        defer calloc.free(body);
-
-        try testing.expectEqual(@as(usize, 14 * 1024 + 14 * 10), body.len);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // send head request and not read chunked
-        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);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.HEAD, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("", body);
-        try testing.expectEqualStrings("text/plain", req.response.content_type.?);
-        try testing.expectEqual(14, req.response.content_length.?);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // read chunked response
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/get?chunked", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-        try testing.expectEqualStrings("text/plain", req.response.content_type.?);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // send head request and not read chunked
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/get?chunked", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.HEAD, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("", body);
-        try testing.expectEqualStrings("text/plain", req.response.content_type.?);
-        try testing.expect(req.response.transfer_encoding == .chunked);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // read content-length response with connection close
-        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);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-            .keep_alive = false,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-        try testing.expectEqualStrings("text/plain", req.response.content_type.?);
-    }
-
-    // connection has been closed
-    try testing.expect(client.connection_pool.free_len == 0);
-
-    { // relative redirect
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/redirect/1", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // redirect from root
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/redirect/2", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // absolute redirect
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/redirect/3", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        try req.wait();
-
-        const body = try req.reader().readAllAlloc(calloc, 8192);
-        defer calloc.free(body);
-
-        try testing.expectEqualStrings("Hello, World!\n", body);
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // too many redirects
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/redirect/4", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        req.wait() catch |err| switch (err) {
-            error.TooManyHttpRedirects => {},
-            else => return err,
-        };
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // check client without segfault by connection error after redirection
-        const location = try std.fmt.allocPrint(calloc, "http://127.0.0.1:{d}/redirect/invalid", .{port});
-        defer calloc.free(location);
-        const uri = try std.Uri.parse(location);
-
-        log.info("{s}", .{location});
-        var server_header_buffer: [1024]u8 = undefined;
-        var req = try client.open(.GET, uri, .{
-            .server_header_buffer = &server_header_buffer,
-        });
-        defer req.deinit();
-
-        try req.send(.{});
-        const result = req.wait();
-
-        // a proxy without an upstream is likely to return a 5xx status.
-        if (client.http_proxy == null) {
-            try testing.expectError(error.ConnectionRefused, result); // expects not segfault but the regular error
-        }
-    }
-
-    // connection has been kept alive
-    try testing.expect(client.http_proxy != null or client.connection_pool.free_len == 1);
-
-    { // issue 16282 *** This test leaves the client in an invalid state, it must be last ***
-        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);
-
-        var header_bufs = std.ArrayList([]u8).init(calloc);
-        defer header_bufs.deinit();
-        defer for (header_bufs.items) |item| calloc.free(item);
-
-        for (0..total_connections) |i| {
-            const headers_buf = try calloc.alloc(u8, 1024);
-            try header_bufs.append(headers_buf);
-            var req = try client.open(.GET, uri, .{
-                .server_header_buffer = headers_buf,
-            });
-            req.response.parser.done = true;
-            req.connection.?.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();
-
-    {
-        handle_new_requests = false;
-
-        const conn = std.net.tcpConnectToAddress(server.listen_address) catch return;
-        conn.close();
-    }
-
-    server_thread.join();
-}
test/standalone.zig
@@ -55,10 +55,6 @@ pub const simple_cases = [_]SimpleCase{
         .os_filter = .windows,
         .link_libc = true,
     },
-    .{
-        .src_path = "test/standalone/http.zig",
-        .all_modes = true,
-    },
 
     // Ensure the development tools are buildable. Alphabetically sorted.
     // No need to build `tools/spirv/grammar.zig`.