class JSONParser
Parses JSON content with bounded input size and nesting depth.
Definitions
SIZE_LIMIT = 2 * 1024 * 1024
The encoded JSON document size limit.
DEPTH_LIMIT = 32
The JSON document nesting depth limit.
def initialize(size_limit: SIZE_LIMIT, depth_limit: DEPTH_LIMIT, **options)
Initialize the JSON parser.
Signature
-
parameter
size_limitInteger | Nil The encoded document size limit.
-
parameter
depth_limitInteger | Nil The document nesting depth limit.
-
parameter
optionsHash Options passed to
JSON.parse.
Implementation
def initialize(size_limit: SIZE_LIMIT, depth_limit: DEPTH_LIMIT, **options)
@size_limit = size_limit
options[:max_nesting] = depth_limit || false
@options = options
end
def parse(input)
Parse JSON content.
Signature
-
parameter
inputObject The readable input.
-
returns
Object The decoded JSON value.
Implementation
def parse(input)
if @size_limit
buffer = String.new.b
# Read up to the size limit, allowing for partial reads:
while buffer.bytesize < @size_limit
chunk = input.read(@size_limit - buffer.bytesize)
break unless chunk
# An empty chunk cannot make progress, so stop reading:
break if chunk.empty?
buffer << chunk
end
if buffer.bytesize == @size_limit && input.read(1)
raise ContentTooLargeError, "JSON content size exceeded limit of #{@size_limit}!"
end
else
buffer = input.read
end
return JSON.parse(buffer, **@options)
rescue JSON::NestingError
raise ContentTooLargeError
end