mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-28 14:43:28 +00:00
add a fast path for validating cookie strings
This prefers `suggestVectorLength` in order to pick a vector size; for cookie strings shorter than, say 64, this might cause it to fallback to slow path on architectures that support larger vector sizes (like AVX-512). We may also add checks for smaller vector sizes if desired in the future.
This commit is contained in:
@@ -207,16 +207,7 @@ pub const Cookie = struct {
|
||||
// Duplicate attributes - use the last valid
|
||||
// Value-less attributes with a value? Ignore the value
|
||||
pub fn parse(allocator: Allocator, uri: *const std.Uri, str: []const u8) !Cookie {
|
||||
if (str.len == 0) {
|
||||
// this check is necessary, `std.mem.minMax` asserts len > 0
|
||||
return error.Empty;
|
||||
}
|
||||
{
|
||||
const min, const max = std.mem.minMax(u8, str);
|
||||
if (min < 32 or max > 126) {
|
||||
return error.InvalidByteSequence;
|
||||
}
|
||||
}
|
||||
try validateCookieString(str);
|
||||
|
||||
const cookie_name, const cookie_value, const rest = parseNameValue(str) catch {
|
||||
return error.InvalidNameValue;
|
||||
@@ -321,6 +312,56 @@ pub const Cookie = struct {
|
||||
};
|
||||
}
|
||||
|
||||
const ValidateCookieError = error{ Empty, InvalidByteSequence };
|
||||
|
||||
/// Returns an error if cookie str length is 0
|
||||
/// or contains characters between 32...126.
|
||||
fn validateCookieString(str: []const u8) ValidateCookieError!void {
|
||||
if (str.len == 0) {
|
||||
return error.Empty;
|
||||
}
|
||||
|
||||
const vec_size_suggestion = std.simd.suggestVectorLength(u8);
|
||||
var offset: usize = 0;
|
||||
|
||||
// Fast path if possible.
|
||||
if (comptime vec_size_suggestion) |size| {
|
||||
while (str.len - offset >= size) : (offset += size) {
|
||||
const Vec = @Vector(size, u8);
|
||||
const space: Vec = @splat(32);
|
||||
const tilde: Vec = @splat(126);
|
||||
const chunk: Vec = str[offset..][0..size].*;
|
||||
|
||||
// This creates a mask where invalid characters represented
|
||||
// as ones and valid characters as zeros. We then bitCast this
|
||||
// into an unsigned integer. If the integer is not equal to 0,
|
||||
// we know that we've invalid characters in this chunk.
|
||||
// @popCount can also be used but using integers are simpler.
|
||||
const mask = (@intFromBool(chunk < space) | @intFromBool(chunk > tilde));
|
||||
const reduced: std.meta.Int(.unsigned, size) = @bitCast(mask);
|
||||
|
||||
// Got match.
|
||||
if (reduced != 0) {
|
||||
return error.InvalidByteSequence;
|
||||
}
|
||||
}
|
||||
|
||||
// Means str.len % size == 0; we also know str.len != 0.
|
||||
// Cookie is valid.
|
||||
if (offset == str.len) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Either remaining slice or the original if fast path not taken.
|
||||
const slice = str[offset..];
|
||||
// Slow path.
|
||||
const min, const max = std.mem.minMax(u8, slice);
|
||||
if (min < 32 or max > 126) {
|
||||
return error.InvalidByteSequence;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parsePath(arena: Allocator, uri: ?*const std.Uri, explicit_path: ?[]const u8) ![]const u8 {
|
||||
// path attribute value either begins with a '/' or we
|
||||
// ignore it and use the "default-path" algorithm
|
||||
|
||||
Reference in New Issue
Block a user