mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 01:25:53 -04:00
schema: reject backslash escapes in quoted values
Explicitly reject backslash-escaped quotes with a clear error message, suggesting alternative quote styles or triple quotes. Bare backslashes (e.g. in Windows paths) remain supported.
This commit is contained in:
@@ -600,6 +600,7 @@ fn printSlashParseError(self: *Agent, err: Schema.ParseError, name: []const u8)
|
||||
error.UnknownField => "unknown field (typo?)",
|
||||
error.PositionalNotAllowed => "positional only works for tools with one required field. Use key=value",
|
||||
error.UnterminatedQuote => "unterminated quote",
|
||||
error.UnsupportedEscape => "backslash escapes aren't supported in quoted values; use the other quote style or `'''…'''`",
|
||||
error.OutOfMemory => return self.terminal.printError("out of memory", .{}),
|
||||
};
|
||||
self.terminal.printError("{s}: {s}. Try /help {s}.", .{ name, reason, name });
|
||||
|
||||
@@ -70,6 +70,7 @@ pub const ParseError = error{
|
||||
MalformedKv,
|
||||
PositionalNotAllowed,
|
||||
UnterminatedQuote,
|
||||
UnsupportedEscape,
|
||||
OutOfMemory,
|
||||
};
|
||||
|
||||
@@ -423,8 +424,15 @@ fn tokenize(arena: std.mem.Allocator, input: []const u8) ParseError![][]const u8
|
||||
const close = std.mem.indexOfPos(u8, input, i + 3, triple_delim) orelse return error.UnterminatedQuote;
|
||||
i = close + 2;
|
||||
} else {
|
||||
const close = std.mem.indexOfScalarPos(u8, input, i + 1, ch) orelse return error.UnterminatedQuote;
|
||||
i = close;
|
||||
// Scan for the closer. `\<quote>` is rejected rather
|
||||
// than decoded — choose the other quote style or a
|
||||
// triple-quoted block instead.
|
||||
var j = i + 1;
|
||||
while (j < input.len) : (j += 1) {
|
||||
if (input[j] == '\\' and j + 1 < input.len and input[j + 1] == ch) return error.UnsupportedEscape;
|
||||
if (input[j] == ch) break;
|
||||
} else return error.UnterminatedQuote;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,6 +775,21 @@ test "tokenize: inline triple quotes with spaces" {
|
||||
try testing.expectString("value=\"\"\"foo bar\"\"\"", tokens[1]);
|
||||
}
|
||||
|
||||
test "tokenize: rejects backslash-escaped quote inside same-style quote" {
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
try testing.expectError(error.UnsupportedEscape, tokenize(arena.allocator(), "value=\"hello \\\"world\\\"\""));
|
||||
try testing.expectError(error.UnsupportedEscape, tokenize(arena.allocator(), "value='it\\'s'"));
|
||||
}
|
||||
|
||||
test "tokenize: bare backslash inside quotes is allowed (e.g. Windows paths)" {
|
||||
var arena: std.heap.ArenaAllocator = .init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
const tokens = try tokenize(arena.allocator(), "value='C:\\Users\\bob'");
|
||||
try testing.expectEqual(@as(usize, 1), tokens.len);
|
||||
try testing.expectString("value='C:\\Users\\bob'", tokens[0]);
|
||||
}
|
||||
|
||||
test "hasUnclosedTripleQuote" {
|
||||
try testing.expect(!hasUnclosedTripleQuote(""));
|
||||
try testing.expect(!hasUnclosedTripleQuote("/goto https://x"));
|
||||
|
||||
Reference in New Issue
Block a user