From e55f6181f86e532d1ec05f68d6ef1cf280be6764 Mon Sep 17 00:00:00 2001 From: Rene Schallner Date: Tue, 12 Sep 2023 18:58:34 +0200 Subject: [PATCH] added example for bindataformpost --- README.md | 2 + build.zig | 1 + examples/bindataformpost/bindataformpost.zig | 93 ++++++++++++++++++++ targets.txt | 1 + 4 files changed, 97 insertions(+) create mode 100644 examples/bindataformpost/bindataformpost.zig diff --git a/README.md b/README.md index 0ba5c0a..702ced0 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ Here's what works: optional dynamic request handling - **[sendfile](examples/sendfile/sendfile.zig)**: simple example of how to send a file, honoring compression headers, etc. +- **[bindataformpost](examples/bindataformpost/bindataformpost.zig)**: example + to receive binary files via form post. - **[hello_json](examples/hello_json/hello_json.zig)**: serves you json dependent on HTTP path - **[endpoint](examples/endpoint/)**: a simple JSON REST API example featuring a diff --git a/build.zig b/build.zig index 6a17b97..a368cbb 100644 --- a/build.zig +++ b/build.zig @@ -60,6 +60,7 @@ pub fn build(b: *std.build.Builder) !void { .{ .name = "middleware", .src = "examples/middleware/middleware.zig" }, .{ .name = "middleware_with_endpoint", .src = "examples/middleware_with_endpoint/middleware_with_endpoint.zig" }, .{ .name = "senderror", .src = "examples/senderror/senderror.zig" }, + .{ .name = "bindataformpost", .src = "examples/bindataformpost/bindataformpost.zig" }, }) |excfg| { const ex_name = excfg.name; const ex_src = excfg.src; diff --git a/examples/bindataformpost/bindataformpost.zig b/examples/bindataformpost/bindataformpost.zig new file mode 100644 index 0000000..eced55c --- /dev/null +++ b/examples/bindataformpost/bindataformpost.zig @@ -0,0 +1,93 @@ +const std = @import("std"); +const zap = @import("zap"); + +const Handler = struct { + var alloc: std.mem.Allocator = undefined; + + pub fn on_request(r: zap.SimpleRequest) void { + // check for FORM parameters + r.parseBody() catch |err| { + std.log.err("Parse Body error: {any}. Expected if body is empty", .{err}); + }; + + if (r.body) |body| { + std.log.info("Body length is {any}\n", .{body.len}); + std.log.info("Body is {s}\n", .{body}); + } + // check for query params (for ?terminate=true) + r.parseQuery(); + + var param_count = r.getParamCount(); + std.log.info("param_count: {}", .{param_count}); + + // iterate over all params + // + // HERE WE HANDLE THE BINARY FILE + // + const params = r.parametersToOwnedList(Handler.alloc, false) catch unreachable; + defer params.deinit(); + for (params.items) |kv| { + if (kv.value) |v| { + std.debug.print("\n", .{}); + std.log.info("Param `{s}` in owned list is {any}\n", .{ kv.key.str, v }); + switch (v) { + zap.HttpParam.Hash_Binfile => |*file| { + const filename = file.filename orelse "(no filename)"; + const mimetype = file.mimetype orelse "(no mimetype)"; + const data = file.data orelse ""; + + std.log.debug(" filename: `{s}`\n", .{filename}); + std.log.debug(" mimetype: {s}\n", .{mimetype}); + std.log.debug(" contents: {any}\n", .{data}); + }, + else => { + // might be a string param, we don't care + }, + } + } + } + + // check if we received a terminate=true parameter + if (r.getParamStr("terminate", Handler.alloc, false)) |maybe_str| { + if (maybe_str) |*s| { + defer s.deinit(); + std.log.info("?terminate={s}\n", .{s.str}); + if (std.mem.eql(u8, s.str, "true")) { + zap.fio_stop(); + } + } + } else |err| { + std.log.err("cannot check for terminate param: {any}\n", .{err}); + } + } +}; + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{ + .thread_safe = true, + }){}; + var allocator = gpa.allocator(); + + Handler.alloc = allocator; + + // setup listener + var listener = zap.SimpleHttpListener.init( + .{ + .port = 3000, + .on_request = Handler.on_request, + .log = true, + .max_clients = 10, + .max_body_size = 1 * 1024, + }, + ); + zap.enableDebugLog(); + try listener.listen(); + std.log.info("\n\nURL is http://localhost:3000\n", .{}); + std.log.info("\ncurl -v --request POST -F img=@test012345.bin http://127.0.0.1:3000\n", .{}); + std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true\n", .{}); + + zap.start(.{ + .threads = 1, + .workers = 0, + }); +} diff --git a/targets.txt b/targets.txt index e27951e..3a69052 100644 --- a/targets.txt +++ b/targets.txt @@ -17,4 +17,5 @@ sendfile middleware middleware_with_endpoint senderror +bindataformpost announceybot