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_limit Integer | Nil

The encoded document size limit.

parameter depth_limit Integer | Nil

The document nesting depth limit.

parameter options Hash

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 input Object

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