mirror of
https://github.com/zigzap/zap.git
synced 2025-10-20 15:14:08 +00:00
121 lines
4.1 KiB
Zig
121 lines
4.1 KiB
Zig
//!
|
|
//! Part of the Zap examples.
|
|
//!
|
|
//! Build me with `zig build bindataformpost`.
|
|
//! Run me with `zig build run-bindataformpost`.
|
|
//!
|
|
const std = @import("std");
|
|
const zap = @import("zap");
|
|
|
|
// set default log level to .info and ZAP log level to .debug
|
|
pub const std_options: std.Options = .{
|
|
.log_level = .info,
|
|
.log_scope_levels = &[_]std.log.ScopeLevel{
|
|
.{ .scope = .zap, .level = .debug },
|
|
},
|
|
};
|
|
|
|
const Handler = struct {
|
|
var alloc: std.mem.Allocator = undefined;
|
|
|
|
pub fn on_request(r: zap.Request) !void {
|
|
// parse for FORM (body) parameters first
|
|
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}", .{body.len});
|
|
}
|
|
|
|
// parse potential query params (for ?terminate=true)
|
|
r.parseQuery();
|
|
|
|
const param_count = r.getParamCount();
|
|
std.log.info("param_count: {}", .{param_count});
|
|
|
|
// iterate over all params
|
|
//
|
|
// HERE WE HANDLE THE BINARY FILE
|
|
//
|
|
var params = try r.parametersToOwnedList(Handler.alloc);
|
|
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}", .{ kv.key, v });
|
|
switch (v.*) {
|
|
// single-file upload
|
|
zap.Request.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}`", .{filename});
|
|
std.log.debug(" mimetype: {s}", .{mimetype});
|
|
std.log.debug(" contents: {any}", .{data});
|
|
},
|
|
// multi-file upload
|
|
zap.Request.HttpParam.Array_Binfile => |*files| {
|
|
for (files.*.items) |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}`", .{filename});
|
|
std.log.debug(" mimetype: {s}", .{mimetype});
|
|
std.log.debug(" contents: {any}", .{data});
|
|
}
|
|
files.deinit(alloc);
|
|
},
|
|
else => {
|
|
// let's just get it as its raw slice
|
|
const value: []const u8 = r.getParamSlice(kv.key) orelse "(no value)";
|
|
std.log.debug(" {s} = {s}", .{ kv.key, value });
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if we received a terminate=true parameter
|
|
if (r.getParamSlice("terminate")) |str| {
|
|
std.log.info("?terminate={s}", .{str});
|
|
if (std.mem.eql(u8, str, "true")) {
|
|
zap.stop();
|
|
}
|
|
}
|
|
try r.sendJson("{ \"ok\": true }");
|
|
}
|
|
};
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{
|
|
.thread_safe = true,
|
|
}){};
|
|
defer _ = gpa.detectLeaks();
|
|
const allocator = gpa.allocator();
|
|
|
|
Handler.alloc = allocator;
|
|
|
|
// setup listener
|
|
var listener = zap.HttpListener.init(
|
|
.{
|
|
.port = 3000,
|
|
.on_request = Handler.on_request,
|
|
.log = true,
|
|
.max_clients = 10,
|
|
.max_body_size = 10 * 1024 * 1024,
|
|
.public_folder = ".",
|
|
},
|
|
);
|
|
|
|
try listener.listen();
|
|
std.log.info("\n\nURL is http://localhost:3000", .{});
|
|
std.log.info("\ncurl -v --request POST -F img=@test012345.bin http://127.0.0.1:3000", .{});
|
|
std.log.info("\n\nTerminate with CTRL+C or by sending query param terminate=true", .{});
|
|
|
|
zap.start(.{
|
|
.threads = 1,
|
|
.workers = 1,
|
|
});
|
|
}
|