| ... | @@ -1046,3 +1046,72 @@ test { | ... | @@ -1046,3 +1046,72 @@ test { |
| 1046 | | 1046 | |
| 1047 | std.testing.refAllDecls(@This()); | 1047 | std.testing.refAllDecls(@This()); |
| 1048 | } | 1048 | } |
| | 1049 | |
| | 1050 | test "client requests server" { |
| | 1051 | const builtin = @import("builtin"); |
| | 1052 | |
| | 1053 | // This test requires spawning threads. |
| | 1054 | if (builtin.single_threaded) { |
| | 1055 | return error.SkipZigTest; |
| | 1056 | } |
| | 1057 | |
| | 1058 | const native_endian = comptime builtin.cpu.arch.endian(); |
| | 1059 | if (builtin.zig_backend == .stage2_llvm and native_endian == .Big) { |
| | 1060 | // https://github.com/ziglang/zig/issues/13782 |
| | 1061 | return error.SkipZigTest; |
| | 1062 | } |
| | 1063 | |
| | 1064 | if (builtin.os.tag == .wasi) return error.SkipZigTest; |
| | 1065 | |
| | 1066 | const allocator = std.testing.allocator; |
| | 1067 | |
| | 1068 | const max_header_size = 8192; |
| | 1069 | var server = std.http.Server.init(allocator, .{ .reuse_address = true }); |
| | 1070 | defer server.deinit(); |
| | 1071 | |
| | 1072 | const address = try std.net.Address.parseIp("127.0.0.1", 0); |
| | 1073 | try server.listen(address); |
| | 1074 | const server_port = server.socket.listen_address.in.getPort(); |
| | 1075 | |
| | 1076 | const thread = try std.Thread.spawn(.{}, (struct { |
| | 1077 | fn apply(s: *std.http.Server) !void { |
| | 1078 | const res = try s.accept(.{ .dynamic = max_header_size }); |
| | 1079 | defer res.reset(); |
| | 1080 | try res.wait(); |
| | 1081 | |
| | 1082 | const server_body: []const u8 = "message from server!\n"; |
| | 1083 | res.transfer_encoding = .{ .content_length = server_body.len }; |
| | 1084 | try res.headers.append("content-type", "text/plain"); |
| | 1085 | try res.headers.append("connection", "close"); |
| | 1086 | try res.do(); |
| | 1087 | |
| | 1088 | var buf: [128]u8 = undefined; |
| | 1089 | const n = try res.readAll(&buf); |
| | 1090 | try testing.expect(std.mem.eql(u8, buf[0..n], "Hello, World!\n")); |
| | 1091 | _ = try res.writer().writeAll(server_body); |
| | 1092 | try res.finish(); |
| | 1093 | } |
| | 1094 | }).apply, .{&server}); |
| | 1095 | |
| | 1096 | var uri_buf: [22]u8 = undefined; |
| | 1097 | const uri = std.Uri.parse(try std.fmt.bufPrint(&uri_buf, "http://127.0.0.1:{d}", .{server_port})) catch unreachable; |
| | 1098 | var client = std.http.Client{ .allocator = allocator }; |
| | 1099 | defer client.deinit(); |
| | 1100 | var client_headers = std.http.Headers{ .allocator = allocator }; |
| | 1101 | defer client_headers.deinit(); |
| | 1102 | var client_req = try client.request(.POST, uri, client_headers, .{}); |
| | 1103 | defer client_req.deinit(); |
| | 1104 | |
| | 1105 | client_req.transfer_encoding = .{ .content_length = 14 }; // this will be checked to ensure you sent exactly 14 bytes |
| | 1106 | try client_req.start(); // this sends the request |
| | 1107 | try client_req.writeAll("Hello, "); |
| | 1108 | try client_req.writeAll("World!\n"); |
| | 1109 | try client_req.finish(); |
| | 1110 | try client_req.do(); // this waits for a response |
| | 1111 | |
| | 1112 | const body = try client_req.reader().readAllAlloc(allocator, 8192 * 1024); |
| | 1113 | defer allocator.free(body); |
| | 1114 | try testing.expect(std.mem.eql(u8, body, "message from server!\n")); |
| | 1115 | |
| | 1116 | thread.join(); |
| | 1117 | } |