mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Merge pull request #1133 from lightpanda-io/nikneym/cookie-validation
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
Add a fast path for validating cookie strings
This commit is contained in:
@@ -207,16 +207,7 @@ pub const Cookie = struct {
|
|||||||
// Duplicate attributes - use the last valid
|
// Duplicate attributes - use the last valid
|
||||||
// Value-less attributes with a value? Ignore the value
|
// Value-less attributes with a value? Ignore the value
|
||||||
pub fn parse(allocator: Allocator, uri: *const std.Uri, str: []const u8) !Cookie {
|
pub fn parse(allocator: Allocator, uri: *const std.Uri, str: []const u8) !Cookie {
|
||||||
if (str.len == 0) {
|
try validateCookieString(str);
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cookie_name, const cookie_value, const rest = parseNameValue(str) catch {
|
const cookie_name, const cookie_value, const rest = parseNameValue(str) catch {
|
||||||
return error.InvalidNameValue;
|
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 outside of the ascii range 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 {
|
pub fn parsePath(arena: Allocator, uri: ?*const std.Uri, explicit_path: ?[]const u8) ![]const u8 {
|
||||||
// path attribute value either begins with a '/' or we
|
// path attribute value either begins with a '/' or we
|
||||||
// ignore it and use the "default-path" algorithm
|
// ignore it and use the "default-path" algorithm
|
||||||
|
|||||||
Reference in New Issue
Block a user