From 322c33a69b58d284684c49bb4fab9d73aa43aad4 Mon Sep 17 00:00:00 2001 From: Luna Date: Tue, 13 Apr 2021 16:13:49 -0300 Subject: [PATCH] add basic support for multiple files in multipart --- src/main.zig | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main.zig b/src/main.zig index bf19559..fa219fb 100644 --- a/src/main.zig +++ b/src/main.zig @@ -228,21 +228,43 @@ const Multipart = struct { // we can use the fact that we know the reader is FixedBufferStream // to extract the remaining body, then trim the boundary! // - // THIS ASSUMES ONLY ONE FILE IS IN THE WIRE. + // + // when we find a marker, we also need to know if its an ending marker, + // because the multipart files are prefixed with the boundary, not suffixed. + // + // bc of that we need to set the reader so that its directly on top of + // the next boundary marker for the next file to work const remaining_body = self.stream.buffer[self.stream.pos..self.stream.buffer.len]; - var end_boundary_buf: [512]u8 = undefined; - const boundary_end_marker = try std.fmt.bufPrint(&end_boundary_buf, "{s}--\r\n", .{self.boundary}); - const actual_body = std.mem.trim(u8, remaining_body, boundary_end_marker); + // read body until we find the boundary end marker (--{s} OR --{s}--) + var it = std.mem.split(remaining_body, self.boundary); + const body = it.next() orelse return error.MissingPartBody; - std.debug.warn("ctype out of this: '{s}'", .{content_type.?}); + const next_boundary_pos = self.stream.pos + body.len; + const next_boundary_body = self.stream.buffer[next_boundary_pos..self.stream.buffer.len]; + + // check out on the next 2 chars + const possible_end = it.next() orelse return error.MissingNextPrefixOrEndSuffix; + + if (std.mem.startsWith(u8, possible_end, "--")) { + return Part{ + .allocator = allocator, + .disposition = content_disposition.?, + .content_type = content_type.?, + .body = body, + }; + } + + // there is a next file, the reader should be shifted forward to the + // boundary marker + self.stream.pos = self.stream.pos + body.len; return Part{ .allocator = allocator, .disposition = content_disposition.?, .content_type = content_type.?, - .body = actual_body, + .body = body, }; } }; @@ -317,12 +339,13 @@ fn fetchFile(response: *http.Response, request: http.Request, filename: []const pub const log_level: std.log.Level = .debug; test "multipart" { + const PART1_REAL_BODY = "Hello!\n"; const body = "--1234\r\n" ++ "Content-Type: text/plain\r\n" ++ "Content-Disposition: form-data; name=file1; filename=ab.txt\r\n" ++ "\r\n" ++ - "Hello!\n" ++ + PART1_REAL_BODY ++ "--1234\r\n" ++ "Content-Type: application/json\r\n" ++ // TODO: add 'content-type' support to content-disposition as well @@ -350,7 +373,7 @@ test "multipart" { std.testing.expectEqualSlices(u8, "text/plain", part1.content_type); std.testing.expectEqualSlices(u8, "file1", part1.disposition.name); std.testing.expectEqualSlices(u8, "ab.txt", part1.disposition.filename); - std.testing.expectEqualSlices(u8, "Hello!", part1.body); + std.testing.expectEqualSlices(u8, PART1_REAL_BODY, part1.body); // var part2 = (try multipart.next(&hzzp_buffer)).?; }