| ... | ... | @@ -11,13 +11,18 @@ const expectError = std.testing.expectError; |
| 11 | 11 | test "trailers" { |
| 12 | 12 | const test_server = try createTestServer(struct { |
| 13 | 13 | fn run(net_server: *std.net.Server) anyerror!void { |
| 14 | | var header_buffer: [1024]u8 = undefined; |
| 14 | var recv_buffer: [1024]u8 = undefined; |
| 15 | var send_buffer: [1024]u8 = undefined; |
| 15 | 16 | var remaining: usize = 1; |
| 16 | 17 | while (remaining != 0) : (remaining -= 1) { |
| 17 | | const conn = try net_server.accept(); |
| 18 | | defer conn.stream.close(); |
| 18 | const connection = try net_server.accept(); |
| 19 | defer connection.stream.close(); |
| 19 | 20 | |
| 20 | | var server = http.Server.init(conn, &header_buffer); |
| 21 | var stream_reader = connection.stream.reader(); |
| 22 | var stream_writer = connection.stream.writer(); |
| 23 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 24 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 25 | var server = http.Server.init(&connection_br, &connection_bw); |
| 21 | 26 | |
| 22 | 27 | try expectEqual(.ready, server.state); |
| 23 | 28 | var request = try server.receiveHead(); |
| ... | ... | @@ -29,13 +34,11 @@ test "trailers" { |
| 29 | 34 | fn serve(request: *http.Server.Request) !void { |
| 30 | 35 | try expectEqualStrings(request.head.target, "/trailer"); |
| 31 | 36 | |
| 32 | | var send_buffer: [1024]u8 = undefined; |
| 33 | | var response = request.respondStreaming(.{ |
| 34 | | .send_buffer = &send_buffer, |
| 35 | | }); |
| 36 | | try response.writeAll("Hello, "); |
| 37 | var response = try request.respondStreaming(.{}); |
| 38 | var bw = response.writer().unbuffered(); |
| 39 | try bw.writeAll("Hello, "); |
| 37 | 40 | try response.flush(); |
| 38 | | try response.writeAll("World!\n"); |
| 41 | try bw.writeAll("World!\n"); |
| 39 | 42 | try response.flush(); |
| 40 | 43 | try response.endChunked(.{ |
| 41 | 44 | .trailers = &.{ |
| ... | ... | @@ -95,11 +98,16 @@ test "trailers" { |
| 95 | 98 | test "HTTP server handles a chunked transfer coding request" { |
| 96 | 99 | const test_server = try createTestServer(struct { |
| 97 | 100 | fn run(net_server: *std.net.Server) !void { |
| 98 | | var header_buffer: [8192]u8 = undefined; |
| 99 | | const conn = try net_server.accept(); |
| 100 | | defer conn.stream.close(); |
| 101 | | |
| 102 | | var server = http.Server.init(conn, &header_buffer); |
| 101 | var recv_buffer: [8192]u8 = undefined; |
| 102 | var send_buffer: [500]u8 = undefined; |
| 103 | const connection = try net_server.accept(); |
| 104 | defer connection.stream.close(); |
| 105 | |
| 106 | var stream_reader = connection.stream.reader(); |
| 107 | var stream_writer = connection.stream.writer(); |
| 108 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 109 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 110 | var server = http.Server.init(&connection_br, &connection_bw); |
| 103 | 111 | var request = try server.receiveHead(); |
| 104 | 112 | |
| 105 | 113 | try expect(request.head.transfer_encoding == .chunked); |
| ... | ... | @@ -153,13 +161,18 @@ test "HTTP server handles a chunked transfer coding request" { |
| 153 | 161 | test "echo content server" { |
| 154 | 162 | const test_server = try createTestServer(struct { |
| 155 | 163 | fn run(net_server: *std.net.Server) anyerror!void { |
| 156 | | var read_buffer: [1024]u8 = undefined; |
| 164 | var recv_buffer: [1024]u8 = undefined; |
| 165 | var send_buffer: [100]u8 = undefined; |
| 157 | 166 | |
| 158 | 167 | accept: while (true) { |
| 159 | | const conn = try net_server.accept(); |
| 160 | | defer conn.stream.close(); |
| 168 | const connection = try net_server.accept(); |
| 169 | defer connection.stream.close(); |
| 161 | 170 | |
| 162 | | var http_server = http.Server.init(conn, &read_buffer); |
| 171 | var stream_reader = connection.stream.reader(); |
| 172 | var stream_writer = connection.stream.writer(); |
| 173 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 174 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 175 | var http_server = http.Server.init(&connection_br, &connection_bw); |
| 163 | 176 | |
| 164 | 177 | while (http_server.state == .ready) { |
| 165 | 178 | var request = http_server.receiveHead() catch |err| switch (err) { |
| ... | ... | @@ -200,9 +213,7 @@ test "echo content server" { |
| 200 | 213 | try expectEqualStrings("Hello, World!\n", body); |
| 201 | 214 | try expectEqualStrings("text/plain", request.head.content_type.?); |
| 202 | 215 | |
| 203 | | var send_buffer: [100]u8 = undefined; |
| 204 | | var response = request.respondStreaming(.{ |
| 205 | | .send_buffer = &send_buffer, |
| 216 | var response = try request.respondStreaming(.{ |
| 206 | 217 | .content_length = switch (request.head.transfer_encoding) { |
| 207 | 218 | .chunked => null, |
| 208 | 219 | .none => len: { |
| ... | ... | @@ -211,11 +222,10 @@ test "echo content server" { |
| 211 | 222 | }, |
| 212 | 223 | }, |
| 213 | 224 | }); |
| 214 | | |
| 215 | 225 | try response.flush(); // Test an early flush to send the HTTP headers before the body. |
| 216 | | const w = response.writer(); |
| 217 | | try w.writeAll("Hello, "); |
| 218 | | try w.writeAll("World!\n"); |
| 226 | var bw = response.writer().unbuffered(); |
| 227 | try bw.writeAll("Hello, "); |
| 228 | try bw.writeAll("World!\n"); |
| 219 | 229 | try response.end(); |
| 220 | 230 | //std.debug.print(" server finished responding\n", .{}); |
| 221 | 231 | } |
| ... | ... | @@ -240,32 +250,33 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" { |
| 240 | 250 | // closed, indicating the end of the body. |
| 241 | 251 | const test_server = try createTestServer(struct { |
| 242 | 252 | fn run(net_server: *std.net.Server) anyerror!void { |
| 243 | | var header_buffer: [1000]u8 = undefined; |
| 253 | var recv_buffer: [1000]u8 = undefined; |
| 254 | var send_buffer: [500]u8 = undefined; |
| 244 | 255 | var remaining: usize = 1; |
| 245 | 256 | while (remaining != 0) : (remaining -= 1) { |
| 246 | | const conn = try net_server.accept(); |
| 247 | | defer conn.stream.close(); |
| 257 | const connection = try net_server.accept(); |
| 258 | defer connection.stream.close(); |
| 248 | 259 | |
| 249 | | var server = http.Server.init(conn, &header_buffer); |
| 260 | var stream_reader = connection.stream.reader(); |
| 261 | var stream_writer = connection.stream.writer(); |
| 262 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 263 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 264 | var server = http.Server.init(&connection_br, &connection_bw); |
| 250 | 265 | |
| 251 | 266 | try expectEqual(.ready, server.state); |
| 252 | 267 | var request = try server.receiveHead(); |
| 253 | 268 | try expectEqualStrings(request.head.target, "/foo"); |
| 254 | | var send_buffer: [500]u8 = undefined; |
| 255 | | var response = request.respondStreaming(.{ |
| 256 | | .send_buffer = &send_buffer, |
| 269 | var response = try request.respondStreaming(.{ |
| 257 | 270 | .respond_options = .{ |
| 258 | 271 | .transfer_encoding = .none, |
| 259 | 272 | }, |
| 260 | 273 | }); |
| 261 | | var total: usize = 0; |
| 274 | var buf: [30]u8 = undefined; |
| 275 | var bw = response.writer().buffered(&buf); |
| 262 | 276 | for (0..500) |i| { |
| 263 | | var buf: [30]u8 = undefined; |
| 264 | | const line = try std.fmt.bufPrint(&buf, "{d}, ah ha ha!\n", .{i}); |
| 265 | | try response.writeAll(line); |
| 266 | | total += line.len; |
| 277 | try bw.print("{d}, ah ha ha!\n", .{i}); |
| 267 | 278 | } |
| 268 | | try expectEqual(7390, total); |
| 279 | try expectEqual(7390, bw.count); |
| 269 | 280 | try response.end(); |
| 270 | 281 | try expectEqual(.closing, server.state); |
| 271 | 282 | } |
| ... | ... | @@ -305,13 +316,19 @@ test "Server.Request.respondStreaming non-chunked, unknown content-length" { |
| 305 | 316 | test "receiving arbitrary http headers from the client" { |
| 306 | 317 | const test_server = try createTestServer(struct { |
| 307 | 318 | fn run(net_server: *std.net.Server) anyerror!void { |
| 308 | | var read_buffer: [666]u8 = undefined; |
| 319 | var recv_buffer: [666]u8 = undefined; |
| 320 | var send_buffer: [777]u8 = undefined; |
| 309 | 321 | var remaining: usize = 1; |
| 310 | 322 | while (remaining != 0) : (remaining -= 1) { |
| 311 | | const conn = try net_server.accept(); |
| 312 | | defer conn.stream.close(); |
| 323 | const connection = try net_server.accept(); |
| 324 | defer connection.stream.close(); |
| 325 | |
| 326 | var stream_reader = connection.stream.reader(); |
| 327 | var stream_writer = connection.stream.writer(); |
| 328 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 329 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 330 | var server = http.Server.init(&connection_br, &connection_bw); |
| 313 | 331 | |
| 314 | | var server = http.Server.init(conn, &read_buffer); |
| 315 | 332 | try expectEqual(.ready, server.state); |
| 316 | 333 | var request = try server.receiveHead(); |
| 317 | 334 | try expectEqualStrings("/bar", request.head.target); |
| ... | ... | @@ -341,7 +358,8 @@ test "receiving arbitrary http headers from the client" { |
| 341 | 358 | const gpa = std.testing.allocator; |
| 342 | 359 | const stream = try std.net.tcpConnectToHost(gpa, "127.0.0.1", test_server.port()); |
| 343 | 360 | defer stream.close(); |
| 344 | | var writer = stream.writer().unbuffered(); |
| 361 | var stream_writer = stream.writer(); |
| 362 | var writer = stream_writer.interface().unbuffered(); |
| 345 | 363 | try writer.writeAll(request_bytes); |
| 346 | 364 | |
| 347 | 365 | const response = try stream.reader().readAllAlloc(gpa, 8192); |
| ... | ... | @@ -367,12 +385,18 @@ test "general client/server API coverage" { |
| 367 | 385 | }; |
| 368 | 386 | const test_server = try createTestServer(struct { |
| 369 | 387 | fn run(net_server: *std.net.Server) anyerror!void { |
| 370 | | var client_header_buffer: [1024]u8 = undefined; |
| 388 | var recv_buffer: [1024]u8 = undefined; |
| 389 | var send_buffer: [100]u8 = undefined; |
| 390 | |
| 371 | 391 | outer: while (global.handle_new_requests) { |
| 372 | 392 | var connection = try net_server.accept(); |
| 373 | 393 | defer connection.stream.close(); |
| 374 | 394 | |
| 375 | | var http_server = http.Server.init(connection, &client_header_buffer); |
| 395 | var stream_reader = connection.stream.reader(); |
| 396 | var stream_writer = connection.stream.writer(); |
| 397 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 398 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 399 | var http_server = http.Server.init(&connection_br, &connection_bw); |
| 376 | 400 | |
| 377 | 401 | while (http_server.state == .ready) { |
| 378 | 402 | var request = http_server.receiveHead() catch |err| switch (err) { |
| ... | ... | @@ -398,11 +422,8 @@ test "general client/server API coverage" { |
| 398 | 422 | const body = try (try request.reader()).readAllAlloc(gpa, 8192); |
| 399 | 423 | defer gpa.free(body); |
| 400 | 424 | |
| 401 | | var send_buffer: [100]u8 = undefined; |
| 402 | | |
| 403 | 425 | if (mem.startsWith(u8, request.head.target, "/get")) { |
| 404 | | var response = request.respondStreaming(.{ |
| 405 | | .send_buffer = &send_buffer, |
| 426 | var response = try request.respondStreaming(.{ |
| 406 | 427 | .content_length = if (mem.indexOf(u8, request.head.target, "?chunked") == null) |
| 407 | 428 | 14 |
| 408 | 429 | else |
| ... | ... | @@ -413,37 +434,35 @@ test "general client/server API coverage" { |
| 413 | 434 | }, |
| 414 | 435 | }, |
| 415 | 436 | }); |
| 416 | | const w = response.writer(); |
| 417 | | try w.writeAll("Hello, "); |
| 418 | | try w.writeAll("World!\n"); |
| 437 | var bw = response.writer().unbuffered(); |
| 438 | try bw.writeAll("Hello, "); |
| 439 | try bw.writeAll("World!\n"); |
| 419 | 440 | try response.end(); |
| 420 | 441 | // Writing again would cause an assertion failure. |
| 421 | 442 | } else if (mem.startsWith(u8, request.head.target, "/large")) { |
| 422 | | var response = request.respondStreaming(.{ |
| 423 | | .send_buffer = &send_buffer, |
| 443 | var response = try request.respondStreaming(.{ |
| 424 | 444 | .content_length = 14 * 1024 + 14 * 10, |
| 425 | 445 | }); |
| 426 | 446 | |
| 427 | 447 | try response.flush(); // Test an early flush to send the HTTP headers before the body. |
| 428 | 448 | |
| 429 | | const w = response.writer(); |
| 449 | var bw = response.writer().unbuffered(); |
| 430 | 450 | |
| 431 | 451 | var i: u32 = 0; |
| 432 | 452 | while (i < 5) : (i += 1) { |
| 433 | | try w.writeAll("Hello, World!\n"); |
| 453 | try bw.writeAll("Hello, World!\n"); |
| 434 | 454 | } |
| 435 | 455 | |
| 436 | | try w.writeAll("Hello, World!\n" ** 1024); |
| 456 | try bw.writeAll("Hello, World!\n" ** 1024); |
| 437 | 457 | |
| 438 | 458 | i = 0; |
| 439 | 459 | while (i < 5) : (i += 1) { |
| 440 | | try w.writeAll("Hello, World!\n"); |
| 460 | try bw.writeAll("Hello, World!\n"); |
| 441 | 461 | } |
| 442 | 462 | |
| 443 | 463 | try response.end(); |
| 444 | 464 | } else if (mem.eql(u8, request.head.target, "/redirect/1")) { |
| 445 | | var response = request.respondStreaming(.{ |
| 446 | | .send_buffer = &send_buffer, |
| 465 | var response = try request.respondStreaming(.{ |
| 447 | 466 | .respond_options = .{ |
| 448 | 467 | .status = .found, |
| 449 | 468 | .extra_headers = &.{ |
| ... | ... | @@ -452,9 +471,9 @@ test "general client/server API coverage" { |
| 452 | 471 | }, |
| 453 | 472 | }); |
| 454 | 473 | |
| 455 | | const w = response.writer(); |
| 456 | | try w.writeAll("Hello, "); |
| 457 | | try w.writeAll("Redirected!\n"); |
| 474 | var bw = response.writer().unbuffered(); |
| 475 | try bw.writeAll("Hello, "); |
| 476 | try bw.writeAll("Redirected!\n"); |
| 458 | 477 | try response.end(); |
| 459 | 478 | } else if (mem.eql(u8, request.head.target, "/redirect/2")) { |
| 460 | 479 | try request.respond("Hello, Redirected!\n", .{ |
| ... | ... | @@ -914,31 +933,36 @@ test "general client/server API coverage" { |
| 914 | 933 | test "Server streams both reading and writing" { |
| 915 | 934 | const test_server = try createTestServer(struct { |
| 916 | 935 | fn run(net_server: *std.net.Server) anyerror!void { |
| 917 | | var header_buffer: [1024]u8 = undefined; |
| 918 | | const conn = try net_server.accept(); |
| 919 | | defer conn.stream.close(); |
| 936 | var recv_buffer: [1024]u8 = undefined; |
| 937 | var send_buffer: [777]u8 = undefined; |
| 920 | 938 | |
| 921 | | var server = http.Server.init(conn, &header_buffer); |
| 922 | | var request = try server.receiveHead(); |
| 923 | | const reader = try request.reader(); |
| 939 | const connection = try net_server.accept(); |
| 940 | defer connection.stream.close(); |
| 924 | 941 | |
| 925 | | var send_buffer: [777]u8 = undefined; |
| 926 | | var response = request.respondStreaming(.{ |
| 927 | | .send_buffer = &send_buffer, |
| 942 | var stream_reader = connection.stream.reader(); |
| 943 | var stream_writer = connection.stream.writer(); |
| 944 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 945 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 946 | var server = http.Server.init(&connection_br, &connection_bw); |
| 947 | var request = try server.receiveHead(); |
| 948 | var read_buffer: [100]u8 = undefined; |
| 949 | var br = try request.reader().buffered(&read_buffer); |
| 950 | var response = try request.respondStreaming(.{ |
| 928 | 951 | .respond_options = .{ |
| 929 | 952 | .transfer_encoding = .none, // Causes keep_alive=false |
| 930 | 953 | }, |
| 931 | 954 | }); |
| 932 | | const writer = response.writer(); |
| 955 | var bw = response.writer().unbuffered(); |
| 933 | 956 | |
| 934 | 957 | while (true) { |
| 935 | 958 | try response.flush(); |
| 936 | | var buf: [100]u8 = undefined; |
| 937 | | const n = try reader.read(&buf); |
| 938 | | if (n == 0) break; |
| 939 | | const sub_buf = buf[0..n]; |
| 940 | | for (sub_buf) |*b| b.* = std.ascii.toUpper(b.*); |
| 941 | | try writer.writeAll(sub_buf); |
| 959 | const buf = br.peekGreedy(1) catch |err| switch (err) { |
| 960 | error.EndOfStream => break, |
| 961 | error.ReadFailed => return error.ReadFailed, |
| 962 | }; |
| 963 | br.toss(buf.len); |
| 964 | for (buf) |*b| b.* = std.ascii.toUpper(b.*); |
| 965 | try bw.writeAll(buf); |
| 942 | 966 | } |
| 943 | 967 | try response.end(); |
| 944 | 968 | } |
| ... | ... | @@ -1161,12 +1185,17 @@ fn createTestServer(S: type) !*TestServer { |
| 1161 | 1185 | test "redirect to different connection" { |
| 1162 | 1186 | const test_server_new = try createTestServer(struct { |
| 1163 | 1187 | fn run(net_server: *std.net.Server) anyerror!void { |
| 1164 | | var header_buffer: [888]u8 = undefined; |
| 1188 | var recv_buffer: [888]u8 = undefined; |
| 1189 | var send_buffer: [777]u8 = undefined; |
| 1165 | 1190 | |
| 1166 | | const conn = try net_server.accept(); |
| 1167 | | defer conn.stream.close(); |
| 1191 | const connection = try net_server.accept(); |
| 1192 | defer connection.stream.close(); |
| 1168 | 1193 | |
| 1169 | | var server = http.Server.init(conn, &header_buffer); |
| 1194 | var stream_reader = connection.stream.reader(); |
| 1195 | var stream_writer = connection.stream.writer(); |
| 1196 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 1197 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 1198 | var server = http.Server.init(&connection_br, &connection_bw); |
| 1170 | 1199 | var request = try server.receiveHead(); |
| 1171 | 1200 | try expectEqualStrings(request.head.target, "/ok"); |
| 1172 | 1201 | try request.respond("good job, you pass", .{}); |
| ... | ... | @@ -1181,17 +1210,21 @@ test "redirect to different connection" { |
| 1181 | 1210 | |
| 1182 | 1211 | const test_server_orig = try createTestServer(struct { |
| 1183 | 1212 | fn run(net_server: *std.net.Server) anyerror!void { |
| 1184 | | var header_buffer: [999]u8 = undefined; |
| 1213 | var recv_buffer: [999]u8 = undefined; |
| 1185 | 1214 | var send_buffer: [100]u8 = undefined; |
| 1186 | 1215 | |
| 1187 | | const conn = try net_server.accept(); |
| 1188 | | defer conn.stream.close(); |
| 1216 | const connection = try net_server.accept(); |
| 1217 | defer connection.stream.close(); |
| 1189 | 1218 | |
| 1190 | 1219 | const new_loc = try std.fmt.bufPrint(&send_buffer, "http://127.0.0.1:{d}/ok", .{ |
| 1191 | 1220 | global.other_port.?, |
| 1192 | 1221 | }); |
| 1193 | 1222 | |
| 1194 | | var server = http.Server.init(conn, &header_buffer); |
| 1223 | var stream_reader = connection.stream.reader(); |
| 1224 | var stream_writer = connection.stream.writer(); |
| 1225 | var connection_br = stream_reader.interface().buffered(&recv_buffer); |
| 1226 | var connection_bw = stream_writer.interface().buffered(&send_buffer); |
| 1227 | var server = http.Server.init(&connection_br, &connection_bw); |
| 1195 | 1228 | var request = try server.receiveHead(); |
| 1196 | 1229 | try expectEqualStrings(request.head.target, "/help"); |
| 1197 | 1230 | try request.respond("", .{ |