From 5a7d3caf9cc4edace0176661102656adbf22f7be Mon Sep 17 00:00:00 2001 From: Robby Zambito Date: Fri, 2 Jan 2026 23:51:49 +0000 Subject: Subject validation --- src/server/message_parser.zig | 59 +++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'src/server/message_parser.zig') diff --git a/src/server/message_parser.zig b/src/server/message_parser.zig index 381dc2c..0d60df5 100644 --- a/src/server/message_parser.zig +++ b/src/server/message_parser.zig @@ -294,7 +294,7 @@ pub const Message = union(enum) { @branchHint(.unlikely); return error.InvalidStream; } - const subject = try readSubject(alloc, in); + const subject = try readSubject(alloc, in, .sub); errdefer alloc.free(subject); const second = blk: { // Drop whitespace @@ -392,7 +392,7 @@ fn parsePub(alloc: std.mem.Allocator, in: *std.Io.Reader) !Message { try in.discardAll(1); // throw away space // Parse subject - const subject: []const u8 = try readSubject(alloc, in); + const subject: []const u8 = try readSubject(alloc, in, .@"pub"); errdefer alloc.free(subject); const States = enum { @@ -526,7 +526,7 @@ fn parseHPub(alloc: std.mem.Allocator, in: *std.Io.Reader) !Message { try in.discardAll(1); // throw away space // Parse subject - const subject: []const u8 = try readSubject(alloc, in); + const subject: []const u8 = try readSubject(alloc, in, .@"pub"); errdefer alloc.free(subject); const States = enum { @@ -699,30 +699,57 @@ test parseHPub { } } -fn readSubject(alloc: std.mem.Allocator, in: *std.Io.Reader) ![]const u8 { +fn readSubject(alloc: std.mem.Allocator, in: *std.Io.Reader, comptime pub_or_sub: enum { @"pub", sub }) ![]const u8 { var subject_list: std.ArrayList(u8) = .empty; errdefer subject_list.deinit(alloc); // Handle the first character { const byte = try in.takeByte(); - if (std.ascii.isWhitespace(byte) or byte == '.') + if (std.ascii.isWhitespace(byte) or byte == '.' or (pub_or_sub == .@"pub" and (byte == '*' or byte == '>'))) return error.InvalidStream; try subject_list.append(alloc, byte); } - while (in.takeByte()) |byte| { - if (std.ascii.isWhitespace(byte)) break; - if (std.ascii.isAscii(byte)) { - if (byte == '.') { - const next_byte = try in.peekByte(); - if (next_byte == '.' or std.ascii.isWhitespace(next_byte)) - return error.InvalidSubject; - } - try subject_list.append(alloc, byte); - } - } else |err| return err; + switch (pub_or_sub) { + .sub => { + while (in.takeByte()) |byte| { + if (std.ascii.isWhitespace(byte)) break; + if (std.ascii.isAscii(byte)) { + if (byte == '.') { + const next_byte = try in.peekByte(); + if (next_byte == '.' or std.ascii.isWhitespace(next_byte)) + return error.InvalidStream; + } else if (byte == '>') { + const next_byte = try in.takeByte(); + if (!std.ascii.isWhitespace(next_byte)) + return error.InvalidStream; + } else if (byte == '*') { + const next_byte = try in.peekByte(); + if (next_byte != '.' and !std.ascii.isWhitespace(next_byte)) + return error.InvalidStream; + } + try subject_list.append(alloc, byte); + } + } else |err| return err; + }, + .@"pub" => { + while (in.takeByte()) |byte| { + if (std.ascii.isWhitespace(byte)) break; + if (std.ascii.isAscii(byte)) { + if (byte == '*' or byte == '>') return error.InvalidStream; + if (byte == '.') { + const next_byte = try in.peekByte(); + if (next_byte == '.' or std.ascii.isWhitespace(next_byte)) + return error.InvalidStream; + } + try subject_list.append(alloc, byte); + } + } else |err| return err; + }, + } + return subject_list.toOwnedSlice(alloc); } -- cgit