Subject validation

This commit is contained in:
2026-01-02 23:51:49 +00:00
parent a21dbfe3bb
commit 5a7d3caf9c

View File

@@ -294,7 +294,7 @@ pub const Message = union(enum) {
@branchHint(.unlikely); @branchHint(.unlikely);
return error.InvalidStream; return error.InvalidStream;
} }
const subject = try readSubject(alloc, in); const subject = try readSubject(alloc, in, .sub);
errdefer alloc.free(subject); errdefer alloc.free(subject);
const second = blk: { const second = blk: {
// Drop whitespace // Drop whitespace
@@ -392,7 +392,7 @@ fn parsePub(alloc: std.mem.Allocator, in: *std.Io.Reader) !Message {
try in.discardAll(1); // throw away space try in.discardAll(1); // throw away space
// Parse subject // Parse subject
const subject: []const u8 = try readSubject(alloc, in); const subject: []const u8 = try readSubject(alloc, in, .@"pub");
errdefer alloc.free(subject); errdefer alloc.free(subject);
const States = enum { 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 try in.discardAll(1); // throw away space
// Parse subject // Parse subject
const subject: []const u8 = try readSubject(alloc, in); const subject: []const u8 = try readSubject(alloc, in, .@"pub");
errdefer alloc.free(subject); errdefer alloc.free(subject);
const States = enum { 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; var subject_list: std.ArrayList(u8) = .empty;
errdefer subject_list.deinit(alloc); errdefer subject_list.deinit(alloc);
// Handle the first character // Handle the first character
{ {
const byte = try in.takeByte(); 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; return error.InvalidStream;
try subject_list.append(alloc, byte); try subject_list.append(alloc, byte);
} }
while (in.takeByte()) |byte| { switch (pub_or_sub) {
if (std.ascii.isWhitespace(byte)) break; .sub => {
if (std.ascii.isAscii(byte)) { while (in.takeByte()) |byte| {
if (byte == '.') { if (std.ascii.isWhitespace(byte)) break;
const next_byte = try in.peekByte(); if (std.ascii.isAscii(byte)) {
if (next_byte == '.' or std.ascii.isWhitespace(next_byte)) if (byte == '.') {
return error.InvalidSubject; const next_byte = try in.peekByte();
} if (next_byte == '.' or std.ascii.isWhitespace(next_byte))
try subject_list.append(alloc, byte); return error.InvalidStream;
} } else if (byte == '>') {
} else |err| return err; 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); return subject_list.toOwnedSlice(alloc);
} }