diff options
| author | Robby Zambito <contact@robbyzambito.me> | 2026-01-02 23:51:49 +0000 |
|---|---|---|
| committer | Robby Zambito <contact@robbyzambito.me> | 2026-01-02 23:57:40 +0000 |
| commit | 5a7d3caf9cc4edace0176661102656adbf22f7be (patch) | |
| tree | 296739f7e4e07157fc9f88a65db215702777195a /src/server | |
| parent | a21dbfe3bb8354ae4b6327c4f02d6d1aa453c461 (diff) | |
Subject validation
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/message_parser.zig | 59 |
1 files changed, 43 insertions, 16 deletions
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); } |
