Function feed [src]
Returns the number of bytes consumed by headers. This is always less
than or equal to bytes.len.
If the amount returned is less than bytes.len, the parser is in a
content state and the first byte of content is located at
bytes[result].
Prototype
pub fn feed(p: *HeadParser, bytes: []const u8) usize
Parameters
p: *HeadParser
bytes: []const u8
Example
test feed {
const data = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\nHello";
for (0..36) |i| {
var p: HeadParser = .{};
try std.testing.expectEqual(i, p.feed(data[0..i]));
try std.testing.expectEqual(35 - i, p.feed(data[i..]));
}
}
Source
pub fn feed(p: *HeadParser, bytes: []const u8) usize {
const vector_len: comptime_int = @max(std.simd.suggestVectorLength(u8) orelse 1, 8);
var index: usize = 0;
while (true) {
switch (p.state) {
.finished => return index,
.start => switch (bytes.len - index) {
0 => return index,
1 => {
switch (bytes[index]) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
return index + 1;
},
2 => {
const b16 = int16(bytes[index..][0..2]);
const b8 = intShift(u8, b16);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
return index + 2;
},
3 => {
const b24 = int24(bytes[index..][0..3]);
const b16 = intShift(u16, b24);
const b8 = intShift(u8, b24);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
switch (b24) {
int24("\r\n\r") => p.state = .seen_rnr,
else => {},
}
return index + 3;
},
4...vector_len - 1 => {
const b32 = int32(bytes[index..][0..4]);
const b24 = intShift(u24, b32);
const b16 = intShift(u16, b32);
const b8 = intShift(u8, b32);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
switch (b24) {
int24("\r\n\r") => p.state = .seen_rnr,
else => {},
}
switch (b32) {
int32("\r\n\r\n") => p.state = .finished,
else => {},
}
index += 4;
continue;
},
else => {
const chunk = bytes[index..][0..vector_len];
const matches = if (use_vectors) matches: {
const Vector = @Vector(vector_len, u8);
// const BoolVector = @Vector(vector_len, bool);
const BitVector = @Vector(vector_len, u1);
const SizeVector = @Vector(vector_len, u8);
const v: Vector = chunk.*;
const matches_r: BitVector = @bitCast(v == @as(Vector, @splat('\r')));
const matches_n: BitVector = @bitCast(v == @as(Vector, @splat('\n')));
const matches_or: SizeVector = matches_r | matches_n;
break :matches @reduce(.Add, matches_or);
} else matches: {
var matches: u8 = 0;
for (chunk) |byte| switch (byte) {
'\r', '\n' => matches += 1,
else => {},
};
break :matches matches;
};
switch (matches) {
0 => {},
1 => switch (chunk[vector_len - 1]) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
},
2 => {
const b16 = int16(chunk[vector_len - 2 ..][0..2]);
const b8 = intShift(u8, b16);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
},
3 => {
const b24 = int24(chunk[vector_len - 3 ..][0..3]);
const b16 = intShift(u16, b24);
const b8 = intShift(u8, b24);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
switch (b24) {
int24("\r\n\r") => p.state = .seen_rnr,
else => {},
}
},
4...vector_len => {
inline for (0..vector_len - 3) |i_usize| {
const i = @as(u32, @truncate(i_usize));
const b32 = int32(chunk[i..][0..4]);
const b16 = intShift(u16, b32);
if (b32 == int32("\r\n\r\n")) {
p.state = .finished;
return index + i + 4;
} else if (b16 == int16("\n\n")) {
p.state = .finished;
return index + i + 2;
}
}
const b24 = int24(chunk[vector_len - 3 ..][0..3]);
const b16 = intShift(u16, b24);
const b8 = intShift(u8, b24);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => {},
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
switch (b24) {
int24("\r\n\r") => p.state = .seen_rnr,
else => {},
}
},
else => unreachable,
}
index += vector_len;
continue;
},
},
.seen_n => switch (bytes.len - index) {
0 => return index,
else => {
switch (bytes[index]) {
'\n' => p.state = .finished,
else => p.state = .start,
}
index += 1;
continue;
},
},
.seen_r => switch (bytes.len - index) {
0 => return index,
1 => {
switch (bytes[index]) {
'\n' => p.state = .seen_rn,
'\r' => p.state = .seen_r,
else => p.state = .start,
}
return index + 1;
},
2 => {
const b16 = int16(bytes[index..][0..2]);
const b8 = intShift(u8, b16);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_rn,
else => p.state = .start,
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\r") => p.state = .seen_rnr,
int16("\n\n") => p.state = .finished,
else => {},
}
return index + 2;
},
else => {
const b24 = int24(bytes[index..][0..3]);
const b16 = intShift(u16, b24);
const b8 = intShift(u8, b24);
switch (b8) {
'\r' => p.state = .seen_r,
'\n' => p.state = .seen_n,
else => p.state = .start,
}
switch (b16) {
int16("\r\n") => p.state = .seen_rn,
int16("\n\n") => p.state = .finished,
else => {},
}
switch (b24) {
int24("\n\r\n") => p.state = .finished,
else => {},
}
index += 3;
continue;
},
},
.seen_rn => switch (bytes.len - index) {
0 => return index,
1 => {
switch (bytes[index]) {
'\r' => p.state = .seen_rnr,
'\n' => p.state = .seen_n,
else => p.state = .start,
}
return index + 1;
},
else => {
const b16 = int16(bytes[index..][0..2]);
const b8 = intShift(u8, b16);
switch (b8) {
'\r' => p.state = .seen_rnr,
'\n' => p.state = .seen_n,
else => p.state = .start,
}
switch (b16) {
int16("\r\n") => p.state = .finished,
int16("\n\n") => p.state = .finished,
else => {},
}
index += 2;
continue;
},
},
.seen_rnr => switch (bytes.len - index) {
0 => return index,
else => {
switch (bytes[index]) {
'\n' => p.state = .finished,
else => p.state = .start,
}
index += 1;
continue;
},
},
}
return index;
}
}