const std = @import("std"); const httpz = @import("httpz"); const Allocator = std.mem.Allocator; const PORT = 8810; // This example demonstrates handling file uploads using multipart/form-data. // It shows how to: // 1. Parse multipart form data // 2. Access uploaded file content and metadata // 3. Save uploaded files to disk // 4. Handle both file and regular form fields pub fn main(init: std.process.Init) !void { const allocator = init.gpa; var server = try httpz.Server(void).init(init.io, allocator, .{ .address = .localhost(PORT), .request = .{ // Configure the maximum number of multipart form fields // This must be > 0 to use req.multiFormData() .max_multiform_count = 10, // Set a reasonable max body size for file uploads (10MB in this example) .max_body_size = 10 * 1024 * 1024, }, }, {}); defer server.deinit(); defer server.stop(); var router = try server.router(.{}); router.get("/", index, .{}); router.post("/upload", upload, .{}); std.debug.print("listening http://localhost:{d}/\n", .{PORT}); std.debug.print("Open http://localhost:{d}/ in your browser to test file uploads\n", .{PORT}); try server.listen(); } fn index(_: *httpz.Request, res: *httpz.Response) !void { res.content_type = .HTML; res.body = \\ \\

File Upload Example

\\
\\

Name:

\\

Description:

\\

File:

\\

File 2 (optional):

\\

\\
; } fn upload(req: *httpz.Request, res: *httpz.Response) !void { // Parse the multipart form data // This returns a MultiFormKeyValue which contains both regular fields and file uploads const form_data = try req.multiFormData(); // Access regular form fields const name = form_data.get("name"); const description = form_data.get("description"); // Access uploaded files // Each value has: // - .value: []const u8 (the file content) // - .filename: ?[]const u8 (the original filename, if provided) const file = form_data.get("file"); const file2 = form_data.get("file2"); // Build the response res.content_type = .HTML; const writer = res.writer(); try writer.writeAll("

Upload Successful!

"); // Display regular form fields try writer.writeAll("

Form Fields:

"); // Display file information and optionally save to disk if (file) |f| { try writer.writeAll("

File Upload:

"); // // Example: Save the file to disk // if (f.filename) |filename| { // const safe_filename = try std.fmt.allocPrint(res.arena, "uploaded_{s}", .{filename}); // const file_handle = try std.fs.cwd().createFile(safe_filename, .{}); // defer file_handle.close(); // try file_handle.writeAll(f.value); // try writer.print("

✓ File saved as: {s}

", .{safe_filename}); // } try writer.writeAll("

Content Preview:

");
        try writer.print("\\x{x}", .{f.value[0..@min(200, f.value.len)]});
        if (f.value.len > 200) {
            try writer.writeAll("...");
        }
        try writer.writeAll("
"); } // Handle optional second file if (file2) |f| { try writer.writeAll("

Second File Upload:

"); } // Iterate over all form fields (useful for debugging or when field names are dynamic) try writer.writeAll("

All Fields (Debug):

"); try writer.writeAll("

Upload another file

"); }