add multipart parser beginnings
This commit is contained in:
parent
fe07165792
commit
4ea0e086d9
84
src/main.zig
84
src/main.zig
|
@ -1,14 +1,16 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const http = @import("apple_pie");
|
const http = @import("apple_pie");
|
||||||
|
const hzzp = @import("hzzp");
|
||||||
|
|
||||||
const images_dir_path = "./images";
|
const images_dir_path = "./images";
|
||||||
|
|
||||||
pub fn main() anyerror!void {
|
pub fn main() anyerror!void {
|
||||||
std.log.info("All your codebase are belong to us.", .{});
|
std.log.info("welcome to webscale", .{});
|
||||||
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
|
|
||||||
|
// TODO: configurable addr via env var
|
||||||
const bind_addr = try std.net.Address.parseIp("0.0.0.0", 8080);
|
const bind_addr = try std.net.Address.parseIp("0.0.0.0", 8080);
|
||||||
std.log.info("serving on {}", .{bind_addr});
|
std.log.info("serving on {}", .{bind_addr});
|
||||||
|
|
||||||
|
@ -46,10 +48,20 @@ fn generateImageId(buffer: []u8) []const u8 {
|
||||||
return buffer[0..i];
|
return buffer[0..i];
|
||||||
}
|
}
|
||||||
|
|
||||||
const Part = struct {};
|
const StreamT = std.io.FixedBufferStream([]const u8);
|
||||||
|
|
||||||
|
const ContentDisposition = struct {
|
||||||
|
name: []const u8,
|
||||||
|
filename: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Part = struct {
|
||||||
|
disposition: ContentDisposition,
|
||||||
|
content_type: []const u8,
|
||||||
|
};
|
||||||
|
|
||||||
const Multipart = struct {
|
const Multipart = struct {
|
||||||
body: []const u8,
|
stream: StreamT,
|
||||||
boundary: []const u8,
|
boundary: []const u8,
|
||||||
cursor: usize = 0,
|
cursor: usize = 0,
|
||||||
|
|
||||||
|
@ -70,11 +82,68 @@ const Multipart = struct {
|
||||||
_ = boundary_it.next();
|
_ = boundary_it.next();
|
||||||
const boundary_value = boundary_it.next() orelse return error.InvalidBoundary;
|
const boundary_value = boundary_it.next() orelse return error.InvalidBoundary;
|
||||||
|
|
||||||
return Self{ .body = body, .boundary = boundary_value };
|
return Self{
|
||||||
|
.stream = StreamT{ .buffer = body, .pos = 0 },
|
||||||
|
.boundary = boundary_value,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(self: *Self) !?Part {
|
pub fn next(self: *Self, hzzp_buffer: []u8) !?Part {
|
||||||
return null;
|
var reader = self.stream.reader();
|
||||||
|
// first self.boundary.len+2 bytes MUST be boundary + \r + \n
|
||||||
|
var boundary_buffer: [512]u8 = undefined;
|
||||||
|
const maybe_boundary_raw = (try reader.readUntilDelimiterOrEof(&boundary_buffer, '\r')).?;
|
||||||
|
|
||||||
|
const maybe_boundary_strip1 = std.mem.trimRight(u8, maybe_boundary_raw, "\n");
|
||||||
|
const maybe_boundary_strip2 = std.mem.trimRight(u8, maybe_boundary_strip1, "\r");
|
||||||
|
if (!std.mem.eql(u8, maybe_boundary_strip2, self.boundary)) {
|
||||||
|
std.log.err("expected '{s}', got '{s}'", .{ self.boundary, maybe_boundary_strip2 });
|
||||||
|
return error.InvalidBoundaryBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from there ownwards, its just http!
|
||||||
|
var parser = hzzp.parser.request.create(hzzp_buffer, reader);
|
||||||
|
|
||||||
|
// This is a hack so that it doesnt try to parse an http header.
|
||||||
|
parser.state = .header;
|
||||||
|
|
||||||
|
var content_disposition: ?ContentDisposition = null;
|
||||||
|
var content_type: ?[]const u8 = null;
|
||||||
|
|
||||||
|
while (try parser.next()) |event| {
|
||||||
|
switch (event) {
|
||||||
|
.status => unreachable,
|
||||||
|
.header => |header| {
|
||||||
|
// TODO lowercase header name
|
||||||
|
if (std.mem.eql(u8, header.name, "Content-Disposition")) {
|
||||||
|
// parse disposition
|
||||||
|
var disposition_it = std.mem.split(header.value, ";");
|
||||||
|
_ = disposition_it.next();
|
||||||
|
|
||||||
|
var dispo_name: []const u8 = undefined;
|
||||||
|
var dispo_filename: []const u8 = undefined;
|
||||||
|
|
||||||
|
while (disposition_it.next()) |disposition_part_raw| {
|
||||||
|
const disposition_part = std.mem.trim(u8, disposition_part_raw, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
content_disposition = ContentDisposition{
|
||||||
|
.name = dispo_name,
|
||||||
|
.filename = dispo_filename,
|
||||||
|
};
|
||||||
|
} else if (std.mem.eql(u8, header.name, "Content-Type")) {
|
||||||
|
content_type = header.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.end => break,
|
||||||
|
else => @panic("shit"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Part{
|
||||||
|
.disposition = content_disposition.?,
|
||||||
|
.content_type = content_type.?,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,8 +163,9 @@ fn uploadFile(response: *http.Response, request: http.Request) !void {
|
||||||
|
|
||||||
// parse multipart data
|
// parse multipart data
|
||||||
var multipart = try Multipart.init(request.body, content_type.?);
|
var multipart = try Multipart.init(request.body, content_type.?);
|
||||||
|
var hzzp_buffer: [1024]u8 = undefined;
|
||||||
|
|
||||||
while (try multipart.next()) |part| {
|
while (try multipart.next(&hzzp_buffer)) |part| {
|
||||||
std.log.info("part: {}", .{part});
|
std.log.info("part: {}", .{part});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
zig.mod
4
zig.mod
|
@ -6,3 +6,7 @@ dev_dependencies:
|
||||||
- src: git https://github.com/Luukdegram/apple_pie
|
- src: git https://github.com/Luukdegram/apple_pie
|
||||||
name: apple_pie
|
name: apple_pie
|
||||||
main: src/apple_pie.zig
|
main: src/apple_pie.zig
|
||||||
|
|
||||||
|
- src: git https://github.com/truemedian/hzzp
|
||||||
|
name: hzzp
|
||||||
|
main: src/main.zig
|
||||||
|
|
Loading…
Reference in New Issue