Fix chunked transfer encoding
This commit is contained in:
parent
d2151ae326
commit
cbf98c1cf3
2 changed files with 27 additions and 18 deletions
|
@ -148,11 +148,10 @@ fn prepareBody(headers: Fields, reader: anytype) !?TransferStream(@TypeOf(reader
|
||||||
},
|
},
|
||||||
.chunked => {
|
.chunked => {
|
||||||
if (headers.get("Content-Length") != null) return error.BadRequest;
|
if (headers.get("Content-Length") != null) return error.BadRequest;
|
||||||
|
std.log.debug("Using chunked T-E", .{});
|
||||||
return TransferStream(@TypeOf(reader)){
|
return TransferStream(@TypeOf(reader)){
|
||||||
.underlying = .{
|
.underlying = .{
|
||||||
.chunked = ChunkedStream(@TypeOf(reader)){
|
.chunked = try ChunkedStream(@TypeOf(reader)).init(reader),
|
||||||
.underlying = reader,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -163,29 +162,35 @@ fn ChunkedStream(comptime R: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
remaining: ?usize = null,
|
remaining: ?usize = 0,
|
||||||
underlying: R,
|
underlying: R,
|
||||||
|
|
||||||
const Error = R.Error || error{ Unexpected, InvalidChunkHeader, StreamTooLong, EndOfStream };
|
const Error = R.Error || error{ Unexpected, InvalidChunkHeader, StreamTooLong, EndOfStream };
|
||||||
|
fn init(reader: R) !Self {
|
||||||
|
var self: Self = .{ .underlying = reader };
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
fn read(self: *Self, buf: []u8) !usize {
|
fn read(self: *Self, buf: []u8) !usize {
|
||||||
if (self.remaining) |*remaining| {
|
|
||||||
var count: usize = 0;
|
var count: usize = 0;
|
||||||
while (count < buf.len) {
|
while (true) {
|
||||||
const max_read = std.math.min(buf.len, remaining.*);
|
if (count == buf.len) return count;
|
||||||
|
if (self.remaining == null) return count;
|
||||||
|
if (self.remaining.? == 0) self.remaining = try self.readChunkHeader();
|
||||||
|
|
||||||
|
const max_read = std.math.min(buf.len, self.remaining.?);
|
||||||
const amt = try self.underlying.read(buf[count .. count + max_read]);
|
const amt = try self.underlying.read(buf[count .. count + max_read]);
|
||||||
if (amt != max_read) return error.EndOfStream;
|
if (amt != max_read) return error.EndOfStream;
|
||||||
count += amt;
|
count += amt;
|
||||||
remaining.* -= amt;
|
self.remaining.? -= amt;
|
||||||
|
if (self.remaining.? == 0) {
|
||||||
if (count == buf.len) return count;
|
var crlf: [2]u8 = undefined;
|
||||||
|
_ = try self.underlying.readUntilDelimiter(&crlf, '\n');
|
||||||
self.remaining = try self.readChunkHeader();
|
self.remaining = try self.readChunkHeader();
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable;
|
if (count == buf.len) return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn readChunkHeader(self: *Self) !?usize {
|
fn readChunkHeader(self: *Self) !?usize {
|
||||||
|
@ -194,10 +199,13 @@ fn ChunkedStream(comptime R: type) type {
|
||||||
const line = self.underlying.readUntilDelimiter(&buf, '\n') catch |err| {
|
const line = self.underlying.readUntilDelimiter(&buf, '\n') catch |err| {
|
||||||
return if (err == error.StreamTooLong) error.InvalidChunkHeader else err;
|
return if (err == error.StreamTooLong) error.InvalidChunkHeader else err;
|
||||||
};
|
};
|
||||||
|
std.log.debug("{}: {s}", .{ line.len, line });
|
||||||
if (line.len < 2 or line[line.len - 1] != '\r') return error.InvalidChunkHeader;
|
if (line.len < 2 or line[line.len - 1] != '\r') return error.InvalidChunkHeader;
|
||||||
|
|
||||||
const size = std.fmt.parseInt(usize, line[0 .. line.len - 1], 16) catch return error.InvalidChunkHeader;
|
const size = std.fmt.parseInt(usize, line[0 .. line.len - 1], 16) catch return error.InvalidChunkHeader;
|
||||||
|
|
||||||
|
std.log.debug("Got chunk header of size {}: {s}", .{ size, line });
|
||||||
|
|
||||||
return if (size != 0) size else null;
|
return if (size != 0) size else null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -150,6 +150,7 @@ pub fn Context(comptime Route: type) type {
|
||||||
if (Body != void) {
|
if (Body != void) {
|
||||||
var stream = req.body orelse return error.NoBody;
|
var stream = req.body orelse return error.NoBody;
|
||||||
const body = try stream.reader().readAllAlloc(self.allocator, 1 << 16);
|
const body = try stream.reader().readAllAlloc(self.allocator, 1 << 16);
|
||||||
|
std.log.debug("{s}", .{body});
|
||||||
errdefer self.allocator.free(body);
|
errdefer self.allocator.free(body);
|
||||||
self.body = try json_utils.parse(Body, body, self.allocator);
|
self.body = try json_utils.parse(Body, body, self.allocator);
|
||||||
self.body_buf = body;
|
self.body_buf = body;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue