Skip to content

Instantly share code, notes, and snippets.

@AdriDevelopsThings
Created June 21, 2024 20:54
Show Gist options
  • Save AdriDevelopsThings/0eee88be85c13f799a813780e8b4889a to your computer and use it in GitHub Desktop.
Save AdriDevelopsThings/0eee88be85c13f799a813780e8b4889a to your computer and use it in GitHub Desktop.
A simple http server that answers all requests with an infinite big file
const std = @import("std");
pub const std_options = .{
.log_level = .info,
};
fn handle_connection(connection: std.net.Server.Connection, filename: []u8) !void {
std.log.info("Client {} connected", .{connection.address});
defer {
connection.stream.close();
std.log.info("Client {} disconnected", .{connection.address});
}
{
var buffer: [255]u8 = undefined;
_ = try connection.stream.read(&buffer);
}
var prng = std.rand.DefaultPrng.init(blk: {
var seed: u64 = undefined;
try std.posix.getrandom(std.mem.asBytes(&seed));
break :blk seed;
});
const random = prng.random();
try connection.stream.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});
var downloaded: usize = 0;
var out_counter: usize = 0;
while (true) {
var writeBuffer: [255]u8 = undefined;
random.bytes(&writeBuffer);
const wrote = connection.stream.write(&writeBuffer) catch |err| switch (err) {
error.BrokenPipe => break,
error.ConnectionResetByPeer => break,
else => return err,
};
downloaded += wrote;
out_counter += wrote;
if (out_counter >= 1024 * 1024 * 1024) {
std.log.info("Client {} downloaded {d} GiB", .{ connection.address, downloaded / (1024 * 1024 * 1024) });
out_counter = 0;
}
}
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = gpa.allocator();
defer {
const check = gpa.deinit();
if (check == .leak) @panic("memory leaks");
}
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
if (args.len != 4) {
const writer = std.io.getStdErr().writer();
try writer.print("Usage: {s} DOWNLOAD_FILENAME ADDRESS PORT\n", .{args[0]});
std.process.exit(1);
unreachable;
}
const listen_address = try std.net.Address.resolveIp(args[2], try std.fmt.parseInt(u16, args[3], 10));
var server = try listen_address.listen(.{ .reuse_address = true });
defer server.deinit();
std.log.info("Listening on http://{s}:{s}", .{ args[2], args[3] });
while (true) {
const connection = try server.accept();
_ = try std.Thread.spawn(.{}, handle_connection, .{ connection, args[1] });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment