lib/json/pure/parser.rb in json_pure-1.0.4 vs lib/json/pure/parser.rb in json_pure-1.1.0
- old
+ new
@@ -5,12 +5,13 @@
# This class implements the JSON parser that is used to parse a JSON string
# into a Ruby data structure.
class Parser < StringScanner
STRING = /" ((?:[^\x0-\x1f"\\] |
\\["\\\/bfnrt] |
- \\u[0-9a-fA-F]{4})*)
- "/x
+ \\u[0-9a-fA-F]{4} |
+ \\[\x20-\xff])*)
+ "/nx
INTEGER = /(-?0|-?[1-9]\d*)/
FLOAT = /(-?
(?:0|[1-9]\d*)
(?:
\.\d+(?i:e[+-]?\d+) |
@@ -43,12 +44,24 @@
)mx
UNPARSED = Object.new
# Creates a new JSON::Pure::Parser instance for the string _source_.
- def initialize(source)
+ #
+ # It will be configured by the _opts_ hash. _opts_ can have the following
+ # keys:
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+ # structures. Disable depth checking with :max_nesting => false.
+ def initialize(source, opts = {})
super
+ if !opts.key?(:max_nesting) # defaults to 19
+ @max_nesting = 19
+ elsif opts[:max_nesting]
+ @max_nesting = opts[:max_nesting]
+ else
+ @max_nesting = 0
+ end
@create_id = JSON.create_id
end
alias source string
@@ -59,13 +72,15 @@
obj = nil
until eos?
case
when scan(OBJECT_OPEN)
obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
obj = parse_object
when scan(ARRAY_OPEN)
obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+ @current_nesting = 1
obj = parse_array
when skip(IGNORE)
;
else
raise ParserError, "source '#{peek(20)}' not in JSON!"
@@ -76,25 +91,27 @@
end
private
# Unescape characters in strings.
- UNESCAPE_MAP = {
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
+ UNESCAPE_MAP.update({
?" => '"',
?\\ => '\\',
?/ => '/',
?b => "\b",
?f => "\f",
?n => "\n",
?r => "\r",
?t => "\t",
- }
+ ?u => nil,
+ })
def parse_string
if scan(STRING)
return '' if self[1].empty?
- self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+))) do |c|
+ self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
if u = UNESCAPE_MAP[c[1]]
u
else # \uXXXX
bytes = ''
i = 0
@@ -125,19 +142,27 @@
when scan(NULL)
nil
when (string = parse_string) != UNPARSED
string
when scan(ARRAY_OPEN)
- parse_array
+ @current_nesting += 1
+ ary = parse_array
+ @current_nesting -= 1
+ ary
when scan(OBJECT_OPEN)
- parse_object
+ @current_nesting += 1
+ obj = parse_object
+ @current_nesting -= 1
+ obj
else
UNPARSED
end
end
def parse_array
+ raise NestingError, "nesting of #@current_nesting is to deep" if
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
result = []
delim = false
until eos?
case
when (value = parse_value) != UNPARSED
@@ -164,9 +189,11 @@
end
result
end
def parse_object
+ raise NestingError, "nesting of #@current_nesting is to deep" if
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
result = {}
delim = false
until eos?
case
when (string = parse_string) != UNPARSED