struct ChunkParser [src]

Alias for std.http.ChunkParser

Parser for transfer-encoding: chunked.

Fields

state: State
chunk_len: u64

Members

Source

//! Parser for transfer-encoding: chunked. state: State, chunk_len: u64, pub const init: ChunkParser = .{ .state = .head_size, .chunk_len = 0, }; pub const State = enum { head_size, head_ext, head_r, data, data_suffix, data_suffix_r, invalid, }; /// Returns the number of bytes consumed by the chunk size. This is always /// less than or equal to `bytes.len`. /// /// After this function returns, `chunk_len` will contain the parsed chunk size /// in bytes when `state` is `data`. Alternately, `state` may become `invalid`, /// indicating a syntax error in the input stream. /// /// If the amount returned is less than `bytes.len`, the parser is in the /// `chunk_data` state and the first byte of the chunk is at `bytes[result]`. /// /// Asserts `state` is neither `data` nor `invalid`. pub fn feed(p: *ChunkParser, bytes: []const u8) usize { for (bytes, 0..) |c, i| switch (p.state) { .data_suffix => switch (c) { '\r' => p.state = .data_suffix_r, '\n' => p.state = .head_size, else => { p.state = .invalid; return i; }, }, .data_suffix_r => switch (c) { '\n' => p.state = .head_size, else => { p.state = .invalid; return i; }, }, .head_size => { const digit = switch (c) { '0'...'9' => |b| b - '0', 'A'...'Z' => |b| b - 'A' + 10, 'a'...'z' => |b| b - 'a' + 10, '\r' => { p.state = .head_r; continue; }, '\n' => { p.state = .data; return i + 1; }, else => { p.state = .head_ext; continue; }, }; const new_len = p.chunk_len *% 16 +% digit; if (new_len <= p.chunk_len and p.chunk_len != 0) { p.state = .invalid; return i; } p.chunk_len = new_len; }, .head_ext => switch (c) { '\r' => p.state = .head_r, '\n' => { p.state = .data; return i + 1; }, else => continue, }, .head_r => switch (c) { '\n' => { p.state = .data; return i + 1; }, else => { p.state = .invalid; return i; }, }, .data => unreachable, .invalid => unreachable, }; return bytes.len; } const ChunkParser = @This(); const std = @import("std"); test feed { const testing = std.testing; const data = "Ff\r\nf0f000 ; ext\n0\r\nffffffffffffffffffffffffffffffffffffffff\r\n"; var p = init; const first = p.feed(data[0..]); try testing.expectEqual(@as(u32, 4), first); try testing.expectEqual(@as(u64, 0xff), p.chunk_len); try testing.expectEqual(.data, p.state); p = init; const second = p.feed(data[first..]); try testing.expectEqual(@as(u32, 13), second); try testing.expectEqual(@as(u64, 0xf0f000), p.chunk_len); try testing.expectEqual(.data, p.state); p = init; const third = p.feed(data[first + second ..]); try testing.expectEqual(@as(u32, 3), third); try testing.expectEqual(@as(u64, 0), p.chunk_len); try testing.expectEqual(.data, p.state); p = init; const fourth = p.feed(data[first + second + third ..]); try testing.expectEqual(@as(u32, 16), fourth); try testing.expectEqual(@as(u64, 0xffffffffffffffff), p.chunk_len); try testing.expectEqual(.invalid, p.state); }