Ultima attività 1719876461

This is a http server that serves a infinitely big file filled with random content

adridoesthings's Avatar adridoesthings ha revisionato questo gist 1719876461. Vai alla revisione

1 file changed, 1 insertion, 1 deletion

unlimited-download.zig

@@ -102,7 +102,7 @@ pub fn main() !void {
102 102 unreachable;
103 103 }
104 104
105 - const listen_address = try std.net.Address.resolveIp(args[3], try std.fmt.parseInt(u16, args[4], 10));
105 + const listen_address = try std.net.Address.parseIp(args[3], try std.fmt.parseInt(u16, args[4], 10));
106 106 var server = try listen_address.listen(.{ .reuse_address = true });
107 107 defer server.deinit();
108 108 std.log.info("Listening on http://{s}:{s}", .{ args[3], args[4] });

adridoesthings's Avatar adridoesthings ha revisionato questo gist 1719864389. Vai alla revisione

Nessuna modifica

adridoesthings's Avatar adridoesthings ha revisionato questo gist 1719864300. Vai alla revisione

Nessuna modifica

AdriDoesThings ha revisionato questo gist 1719864205. Vai alla revisione

1 file changed, 114 insertions

unlimited-download.zig(file creato)

@@ -0,0 +1,114 @@
1 + const std = @import("std");
2 + const eql = std.mem.eql;
3 +
4 + pub const std_options = .{
5 + .log_level = .info,
6 + };
7 +
8 + fn http_error(writer: std.net.Stream.Writer, status_code: u16) !void {
9 + const status = switch (status_code) {
10 + 200 => "OK",
11 + 400 => "Bad Request",
12 + 404 => "Not Found",
13 + 405 => "Method Not Allowed",
14 + else => @panic("Invalid status"),
15 + };
16 +
17 + try writer.print("HTTP/1.1 {d} {s}\r\nServer: zig\r\nContent-Type: text/plain\r\nContent-Length: {d}\r\n\r\n{s}", .{ status_code, status, status.len, status });
18 + }
19 +
20 + fn format_bytes(buf: []u8, bytes: usize) ![]u8 {
21 + const fbytes: f32 = @floatFromInt(bytes);
22 + return switch (bytes) {
23 + 0...1024 => std.fmt.bufPrint(buf, "{d} B", .{bytes}),
24 + 1025...(1024 * 1024) => std.fmt.bufPrint(buf, "{d:.1} KiB", .{fbytes / 1024}),
25 + (1024 * 1024 + 1)...(1024 * 1024 * 1024) => std.fmt.bufPrint(buf, "{d:.1} MiB", .{fbytes / 1024 / 1024}),
26 + else => std.fmt.bufPrint(buf, "{d:.1} GiB", .{fbytes / 1024 / 1024 / 1024}),
27 + };
28 + }
29 +
30 + fn handle_connection(connection: std.net.Server.Connection, path: []u8, filename: []u8) !void {
31 + const writer = connection.stream.writer();
32 +
33 + {
34 + var buffer: [255]u8 = undefined;
35 + const n = try connection.stream.read(&buffer);
36 + if (n < 12) {
37 + return http_error(writer, 400);
38 + }
39 +
40 + if (!eql(u8, buffer[0..4], "GET ")) {
41 + return http_error(writer, 405);
42 + }
43 +
44 + if (n < (11 + path.len) or !eql(u8, buffer[4 .. 4 + path.len], path)) {
45 + return http_error(writer, 404);
46 + }
47 + }
48 +
49 + var prng = std.rand.DefaultPrng.init(blk: {
50 + var seed: u64 = undefined;
51 + try std.posix.getrandom(std.mem.asBytes(&seed));
52 + break :blk seed;
53 + });
54 + const random = prng.random();
55 +
56 + std.log.info("Client {} connected", .{connection.address});
57 + defer {
58 + connection.stream.close();
59 + std.log.info("Client {} disconnected", .{connection.address});
60 + }
61 +
62 + try writer.print("HTTP/1.1 200 OK\r\nServer: zig\r\nContent-Type: application/octet-stream\r\nContent-Disposition: attachment; filename=\"{s}\"\r\n\r\n", .{filename});
63 +
64 + var downloaded: usize = 0;
65 + var out_counter: usize = 0;
66 +
67 + while (true) {
68 + var writeBuffer: [1024]u8 = undefined;
69 + random.bytes(&writeBuffer);
70 + const wrote = connection.stream.write(&writeBuffer) catch |err| switch (err) {
71 + error.BrokenPipe => break,
72 + error.ConnectionResetByPeer => break,
73 + else => return err,
74 + };
75 + downloaded += wrote;
76 + out_counter += wrote;
77 +
78 + if (out_counter >= 1024 * 1024 * 100) {
79 + var buf: [16]u8 = undefined;
80 + const downloaded_fmt = try format_bytes(&buf, downloaded);
81 + std.log.info("Client {} downloaded {s}", .{ connection.address, downloaded_fmt });
82 + out_counter = 0;
83 + }
84 + }
85 + }
86 +
87 + pub fn main() !void {
88 + var gpa = std.heap.GeneralPurposeAllocator(.{}){};
89 + const allocator = gpa.allocator();
90 + defer {
91 + const check = gpa.deinit();
92 + if (check == .leak) @panic("memory leaks");
93 + }
94 +
95 + const args = try std.process.argsAlloc(allocator);
96 + defer std.process.argsFree(allocator, args);
97 +
98 + if (args.len != 5) {
99 + const writer = std.io.getStdErr().writer();
100 + try writer.print("Usage: {s} DOWNLOAD_PATH DOWNLOAD_FILENAME ADDRESS PORT\n", .{args[0]});
101 + std.process.exit(1);
102 + unreachable;
103 + }
104 +
105 + const listen_address = try std.net.Address.resolveIp(args[3], try std.fmt.parseInt(u16, args[4], 10));
106 + var server = try listen_address.listen(.{ .reuse_address = true });
107 + defer server.deinit();
108 + std.log.info("Listening on http://{s}:{s}", .{ args[3], args[4] });
109 +
110 + while (true) {
111 + const connection = try server.accept();
112 + _ = try std.Thread.spawn(.{}, handle_connection, .{ connection, args[1], args[2] });
113 + }
114 + }
Più nuovi Più vecchi