Form File support
This commit is contained in:
parent
e6f57495c0
commit
2206cd6ac9
2 changed files with 37 additions and 10 deletions
|
@ -110,6 +110,11 @@ const MultipartFormField = struct {
|
||||||
content_type: ?[]const u8 = null,
|
content_type: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FormFile = struct {
|
||||||
|
data: []const u8,
|
||||||
|
filename: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn MultipartForm(comptime ReaderType: type) type {
|
pub fn MultipartForm(comptime ReaderType: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
stream: MultipartStream(ReaderType),
|
stream: MultipartStream(ReaderType),
|
||||||
|
@ -145,27 +150,49 @@ pub fn openForm(multipart_stream: anytype) MultipartForm(@TypeOf(multipart_strea
|
||||||
return .{ .stream = multipart_stream };
|
return .{ .stream = multipart_stream };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn Deserializer(comptime Result: type) type {
|
||||||
|
return util.DeserializerContext(Result, MultipartFormField, struct {
|
||||||
|
pub const options = .{ .isScalar = isScalar, .embed_unions = true };
|
||||||
|
|
||||||
|
pub fn isScalar(comptime T: type) bool {
|
||||||
|
if (T == FormFile or T == ?FormFile) return true;
|
||||||
|
return util.serialize.defaultIsScalar(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserializeScalar(_: @This(), alloc: std.mem.Allocator, comptime T: type, val: MultipartFormField) !T {
|
||||||
|
if (T == FormFile or T == ?FormFile) return try deserializeFormFile(alloc, val);
|
||||||
|
|
||||||
|
if (val.filename != null) return error.FilenameProvidedForNonFile;
|
||||||
|
return try util.serialize.deserializeString(alloc, T, val.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserializeFormFile(alloc: std.mem.Allocator, val: MultipartFormField) !FormFile {
|
||||||
|
const data = try util.deepClone(alloc, val.value);
|
||||||
|
errdefer util.deepFree(alloc, data);
|
||||||
|
const filename = try util.deepClone(alloc, val.filename orelse "(untitled)");
|
||||||
|
return FormFile{
|
||||||
|
.data = data,
|
||||||
|
.filename = filename,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parseFormData(comptime T: type, boundary: []const u8, reader: anytype, alloc: std.mem.Allocator) !T {
|
pub fn parseFormData(comptime T: type, boundary: []const u8, reader: anytype, alloc: std.mem.Allocator) !T {
|
||||||
var form = openForm(try openMultipart(boundary, reader));
|
var form = openForm(try openMultipart(boundary, reader));
|
||||||
|
|
||||||
var ds = util.Deserializer(T){};
|
var ds = Deserializer(T){};
|
||||||
defer {
|
defer {
|
||||||
var iter = ds.iterator();
|
var iter = ds.iterator();
|
||||||
while (iter.next()) |pair| {
|
while (iter.next()) |pair| {
|
||||||
alloc.free(pair.value);
|
util.deepFree(alloc, pair.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
var part = (try form.next(alloc)) orelse break;
|
var part = (try form.next(alloc)) orelse break;
|
||||||
errdefer util.deepFree(alloc, part);
|
errdefer util.deepFree(alloc, part);
|
||||||
|
|
||||||
try ds.setSerializedField(part.name, part.value);
|
try ds.setSerializedField(part.name, part);
|
||||||
|
|
||||||
alloc.free(part.name);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
if (part.content_type) |v| alloc.free(v);
|
|
||||||
if (part.filename) |v| alloc.free(v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return try ds.finish(alloc);
|
return try ds.finish(alloc);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const util = @import("./lib.zig");
|
const util = @import("./lib.zig");
|
||||||
|
|
||||||
const FieldRef = []const []const u8;
|
pub const FieldRef = []const []const u8;
|
||||||
|
|
||||||
pub fn defaultIsScalar(comptime T: type) bool {
|
pub fn defaultIsScalar(comptime T: type) bool {
|
||||||
if (comptime std.meta.trait.is(.Optional)(T) and defaultIsScalar(std.meta.Child(T))) return true;
|
if (comptime std.meta.trait.is(.Optional)(T) and defaultIsScalar(std.meta.Child(T))) return true;
|
||||||
|
|
Loading…
Reference in a new issue