Commit 7827265ea8
Changed files (2)
lib
std
lib/std/json/dynamic.zig
@@ -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();
lib/std/json/dynamic_test.zig
@@ -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 =
\\{