mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
json: respect max_value_len when parsing std.json.Value (#17107)
This commit is contained in:
parent
a0968be83c
commit
7827265ea8
@ -81,7 +81,6 @@ pub const Value = union(enum) {
|
||||
}
|
||||
|
||||
pub fn jsonParse(allocator: Allocator, source: anytype, options: ParseOptions) ParseError(@TypeOf(source.*))!@This() {
|
||||
_ = options;
|
||||
// The grammar of the stack is:
|
||||
// (.array | .object .string)*
|
||||
var stack = Array.init(allocator);
|
||||
@ -93,21 +92,21 @@ pub const Value = union(enum) {
|
||||
stack.items[stack.items.len - 1] == .array or
|
||||
(stack.items[stack.items.len - 2] == .object and stack.items[stack.items.len - 1] == .string));
|
||||
|
||||
switch (try source.nextAlloc(allocator, .alloc_always)) {
|
||||
switch (try source.nextAllocMax(allocator, .alloc_always, options.max_value_len.?)) {
|
||||
.allocated_string => |s| {
|
||||
return try handleCompleteValue(&stack, allocator, source, Value{ .string = s }) orelse continue;
|
||||
return try handleCompleteValue(&stack, allocator, source, Value{ .string = s }, options) orelse continue;
|
||||
},
|
||||
.allocated_number => |slice| {
|
||||
return try handleCompleteValue(&stack, allocator, source, Value.parseFromNumberSlice(slice)) orelse continue;
|
||||
return try handleCompleteValue(&stack, allocator, source, Value.parseFromNumberSlice(slice), options) orelse continue;
|
||||
},
|
||||
|
||||
.null => return try handleCompleteValue(&stack, allocator, source, .null) orelse continue,
|
||||
.true => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = true }) orelse continue,
|
||||
.false => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = false }) orelse continue,
|
||||
.null => return try handleCompleteValue(&stack, allocator, source, .null, options) orelse continue,
|
||||
.true => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = true }, options) orelse continue,
|
||||
.false => return try handleCompleteValue(&stack, allocator, source, Value{ .bool = false }, options) orelse continue,
|
||||
|
||||
.object_begin => {
|
||||
switch (try source.nextAlloc(allocator, .alloc_always)) {
|
||||
.object_end => return try handleCompleteValue(&stack, allocator, source, Value{ .object = ObjectMap.init(allocator) }) orelse continue,
|
||||
switch (try source.nextAllocMax(allocator, .alloc_always, options.max_value_len.?)) {
|
||||
.object_end => return try handleCompleteValue(&stack, allocator, source, Value{ .object = ObjectMap.init(allocator) }, options) orelse continue,
|
||||
.allocated_string => |key| {
|
||||
try stack.appendSlice(&[_]Value{
|
||||
Value{ .object = ObjectMap.init(allocator) },
|
||||
@ -120,7 +119,7 @@ pub const Value = union(enum) {
|
||||
.array_begin => {
|
||||
try stack.append(Value{ .array = Array.init(allocator) });
|
||||
},
|
||||
.array_end => return try handleCompleteValue(&stack, allocator, source, stack.pop()) orelse continue,
|
||||
.array_end => return try handleCompleteValue(&stack, allocator, source, stack.pop(), options) orelse continue,
|
||||
|
||||
else => unreachable,
|
||||
}
|
||||
@ -134,7 +133,7 @@ pub const Value = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
fn handleCompleteValue(stack: *Array, allocator: Allocator, source: anytype, value_: Value) !?Value {
|
||||
fn handleCompleteValue(stack: *Array, allocator: Allocator, source: anytype, value_: Value, options: ParseOptions) !?Value {
|
||||
if (stack.items.len == 0) return value_;
|
||||
var value = value_;
|
||||
while (true) {
|
||||
@ -152,7 +151,7 @@ fn handleCompleteValue(stack: *Array, allocator: Allocator, source: anytype, val
|
||||
|
||||
// This is an invalid state to leave the stack in,
|
||||
// so we have to process the next token before we return.
|
||||
switch (try source.nextAlloc(allocator, .alloc_always)) {
|
||||
switch (try source.nextAllocMax(allocator, .alloc_always, options.max_value_len.?)) {
|
||||
.object_end => {
|
||||
// This object is complete.
|
||||
value = stack.pop();
|
||||
|
||||
@ -302,6 +302,20 @@ test "long object value" {
|
||||
try testing.expectEqualStrings(value, parsed.value.object.get("key").?.string);
|
||||
}
|
||||
|
||||
test "ParseOptions.max_value_len" {
|
||||
var arena = ArenaAllocator.init(testing.allocator);
|
||||
defer arena.deinit();
|
||||
|
||||
const str = "\"0800fc577294c34e0b28ad2839435945\"";
|
||||
|
||||
const value = try std.json.parseFromSliceLeaky(std.json.Value, arena.allocator(), str, .{ .max_value_len = 32 });
|
||||
|
||||
try testing.expect(value == .string);
|
||||
try testing.expect(value.string.len == 32);
|
||||
|
||||
try testing.expectError(error.ValueTooLong, std.json.parseFromSliceLeaky(std.json.Value, arena.allocator(), str, .{ .max_value_len = 31 }));
|
||||
}
|
||||
|
||||
test "many object keys" {
|
||||
const doc =
|
||||
\\{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user