json_pure 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,8 +7,9 @@ module JSON
7
7
  class Parser < StringScanner
8
8
  STRING = /" ((?:[^\x0-\x1f"\\] |
9
9
  \\["\\\/bfnrt] |
10
- \\u[0-9a-fA-F]{4})*)
11
- "/x
10
+ \\u[0-9a-fA-F]{4} |
11
+ \\[\x20-\xff])*)
12
+ "/nx
12
13
  INTEGER = /(-?0|-?[1-9]\d*)/
13
14
  FLOAT = /(-?
14
15
  (?:0|[1-9]\d*)
@@ -45,8 +46,20 @@ module JSON
45
46
  UNPARSED = Object.new
46
47
 
47
48
  # Creates a new JSON::Pure::Parser instance for the string _source_.
48
- def initialize(source)
49
+ #
50
+ # It will be configured by the _opts_ hash. _opts_ can have the following
51
+ # keys:
52
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
53
+ # structures. Disable depth checking with :max_nesting => false.
54
+ def initialize(source, opts = {})
49
55
  super
56
+ if !opts.key?(:max_nesting) # defaults to 19
57
+ @max_nesting = 19
58
+ elsif opts[:max_nesting]
59
+ @max_nesting = opts[:max_nesting]
60
+ else
61
+ @max_nesting = 0
62
+ end
50
63
  @create_id = JSON.create_id
51
64
  end
52
65
 
@@ -61,9 +74,11 @@ module JSON
61
74
  case
62
75
  when scan(OBJECT_OPEN)
63
76
  obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
77
+ @current_nesting = 1
64
78
  obj = parse_object
65
79
  when scan(ARRAY_OPEN)
66
80
  obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
81
+ @current_nesting = 1
67
82
  obj = parse_array
68
83
  when skip(IGNORE)
69
84
  ;
@@ -78,7 +93,8 @@ module JSON
78
93
  private
79
94
 
80
95
  # Unescape characters in strings.
81
- UNESCAPE_MAP = {
96
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
97
+ UNESCAPE_MAP.update({
82
98
  ?" => '"',
83
99
  ?\\ => '\\',
84
100
  ?/ => '/',
@@ -87,12 +103,13 @@ module JSON
87
103
  ?n => "\n",
88
104
  ?r => "\r",
89
105
  ?t => "\t",
90
- }
106
+ ?u => nil,
107
+ })
91
108
 
92
109
  def parse_string
93
110
  if scan(STRING)
94
111
  return '' if self[1].empty?
95
- self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+))) do |c|
112
+ self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
96
113
  if u = UNESCAPE_MAP[c[1]]
97
114
  u
98
115
  else # \uXXXX
@@ -127,15 +144,23 @@ module JSON
127
144
  when (string = parse_string) != UNPARSED
128
145
  string
129
146
  when scan(ARRAY_OPEN)
130
- parse_array
147
+ @current_nesting += 1
148
+ ary = parse_array
149
+ @current_nesting -= 1
150
+ ary
131
151
  when scan(OBJECT_OPEN)
132
- parse_object
152
+ @current_nesting += 1
153
+ obj = parse_object
154
+ @current_nesting -= 1
155
+ obj
133
156
  else
134
157
  UNPARSED
135
158
  end
136
159
  end
137
160
 
138
161
  def parse_array
162
+ raise NestingError, "nesting of #@current_nesting is to deep" if
163
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
139
164
  result = []
140
165
  delim = false
141
166
  until eos?
@@ -166,6 +191,8 @@ module JSON
166
191
  end
167
192
 
168
193
  def parse_object
194
+ raise NestingError, "nesting of #@current_nesting is to deep" if
195
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
169
196
  result = {}
170
197
  delim = false
171
198
  until eos?
data/lib/json/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module JSON
2
2
  # JSON version
3
- VERSION = '1.0.4'
3
+ VERSION = '1.1.0'
4
4
  VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
File without changes
File without changes
File without changes
File without changes
File without changes
data/tests/test_json.rb CHANGED
@@ -213,6 +213,10 @@ EOT
213
213
  data = JSON.parse(json)
214
214
  assert_equal ['"'], data
215
215
  assert_equal json, JSON.unparse(data)
216
+ json = '["\\\'"]'
217
+ data = JSON.parse(json)
218
+ assert_equal ["'"], data
219
+ assert_equal '["\'"]', JSON.unparse(data)
216
220
  end
217
221
 
218
222
  def test_wrong_inputs
@@ -232,5 +236,20 @@ EOT
232
236
  assert_raises(ParserError) { JSON.parse('[1.]') }
233
237
  assert_raises(ParserError) { JSON.parse(' ') }
234
238
  end
239
+
240
+ def test_nesting
241
+ to_deep = '[[[[[[[[[[[[[[[[[[[["Too deep"]]]]]]]]]]]]]]]]]]]]'
242
+ assert_raises(JSON::NestingError) { JSON.parse to_deep }
243
+ assert_raises(JSON::NestingError) { JSON.parser.new(to_deep).parse }
244
+ assert_raises(JSON::NestingError) { JSON.parse to_deep, :max_nesting => 19 }
245
+ ok = JSON.parse to_deep, :max_nesting => 20
246
+ assert_kind_of Array, ok
247
+ ok = JSON.parse to_deep, :max_nesting => nil
248
+ assert_kind_of Array, ok
249
+ ok = JSON.parse to_deep, :max_nesting => false
250
+ assert_kind_of Array, ok
251
+ ok = JSON.parse to_deep, :max_nesting => 0
252
+ assert_kind_of Array, ok
253
+ end
235
254
  end
236
255
  # vim: set et sw=2 ts=2:
@@ -21,7 +21,7 @@ class TC_JSONFixtures < Test::Unit::TestCase
21
21
 
22
22
  def test_failing
23
23
  for (name, source) in @failed
24
- assert_raises(JSON::ParserError,
24
+ assert_raises(JSON::ParserError, JSON::NestingError,
25
25
  "Did not fail for fixture '#{name}'") do
26
26
  JSON.parse(source)
27
27
  end
data/tools/fuzz.rb CHANGED
@@ -116,7 +116,7 @@ loop do
116
116
  puts json.size
117
117
  end
118
118
  begin
119
- o2 = JSON.parse(json)
119
+ o2 = JSON.parse(json, :max_nesting => false)
120
120
  rescue JSON::ParserError => e
121
121
  puts "Caught #{e.class}: #{e.message}\n#{e.backtrace * "\n"}"
122
122
  puts "o1 = #{o1.inspect}", "json = #{json}", "json_str = #{json.inspect}"
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: json_pure
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.0.4
7
- date: 2007-05-10 00:00:00 +02:00
6
+ version: 1.1.0
7
+ date: 2007-06-04 00:00:00 +02:00
8
8
  summary: A JSON implementation in Ruby
9
9
  require_paths:
10
10
  - lib
@@ -32,6 +32,7 @@ files:
32
32
  - VERSION
33
33
  - TODO
34
34
  - tests
35
+ - RUBY
35
36
  - GPL
36
37
  - install.rb
37
38
  - ext
@@ -53,12 +54,11 @@ files:
53
54
  - tests/test_json_generate.rb
54
55
  - tests/test_json_addition.rb
55
56
  - tests/fixtures/fail27.json
57
+ - tests/fixtures/pass26.json
56
58
  - tests/fixtures/fail22.json
57
- - tests/fixtures/fail26.json
58
- - tests/fixtures/fail16.json
59
+ - tests/fixtures/pass17.json
59
60
  - tests/fixtures/fail28.json
60
61
  - tests/fixtures/fail25.json
61
- - tests/fixtures/pass18.json
62
62
  - tests/fixtures/fail9.json
63
63
  - tests/fixtures/fail20.json
64
64
  - tests/fixtures/fail24.json
@@ -66,6 +66,8 @@ files:
66
66
  - tests/fixtures/fail4.json
67
67
  - tests/fixtures/fail7.json
68
68
  - tests/fixtures/fail10.json
69
+ - tests/fixtures/pass15.json
70
+ - tests/fixtures/fail18.json
69
71
  - tests/fixtures/fail13.json
70
72
  - tests/fixtures/fail6.json
71
73
  - tests/fixtures/fail21.json
@@ -76,11 +78,10 @@ files:
76
78
  - tests/fixtures/fail5.json
77
79
  - tests/fixtures/pass1.json
78
80
  - tests/fixtures/fail12.json
79
- - tests/fixtures/fail15.json
80
81
  - tests/fixtures/pass3.json
81
82
  - tests/fixtures/fail8.json
82
- - tests/fixtures/fail17.json
83
83
  - tests/fixtures/fail19.json
84
+ - tests/fixtures/pass16.json
84
85
  - tests/fixtures/pass2.json
85
86
  - tests/fixtures/fail2.json
86
87
  - ext/json