Skip to content

Commit e7a0984

Browse files
byrootmatzbot
authored andcommitted
[ruby/json] Add allow_invalid_escape parsing option
Ref: ruby/json#939 ruby/json@05cec0cbee
1 parent e67f3f0 commit e7a0984

File tree

3 files changed

+28
-2
lines changed

3 files changed

+28
-2
lines changed

ext/json/lib/json.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@
194194
# When enabled:
195195
# JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
196196
#
197+
# ---
198+
#
199+
# Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
200+
# by an invalid escape character in strings;
201+
# defaults to +false+.
202+
#
203+
# With the default, +false+:
204+
# JSON.parse(%{"Hell\\o"}) # invalid escape character in string (JSON::ParserError)
205+
#
206+
# When enabled:
207+
# JSON.parse(%{"Hell\\o"}, allow_invalid_escape: true) # => "Hello"
208+
#
197209
# ====== Output Options
198210
#
199211
# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;

ext/json/parser/parser.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
77

88
static ID i_new, i_try_convert, i_uminus, i_encode;
99

10-
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters, sym_symbolize_names, sym_freeze,
11-
sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
10+
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
11+
sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
12+
sym_allow_duplicate_key;
1213

1314
static int binary_encindex;
1415
static int utf8_encindex;
@@ -336,6 +337,7 @@ typedef struct JSON_ParserStruct {
336337
bool allow_nan;
337338
bool allow_trailing_comma;
338339
bool allow_control_characters;
340+
bool allow_invalid_escape;
339341
bool symbolize_names;
340342
bool freeze;
341343
} JSON_ParserConfig;
@@ -746,6 +748,8 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
746748
}
747749
raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
748750
}
751+
} else if (config->allow_invalid_escape) {
752+
APPEND_CHAR(*pe);
749753
} else {
750754
raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
751755
}
@@ -1435,6 +1439,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
14351439
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
14361440
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
14371441
else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
1442+
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
14381443
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
14391444
else if (key == sym_freeze) { config->freeze = RTEST(val); }
14401445
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
@@ -1653,6 +1658,7 @@ void Init_parser(void)
16531658
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
16541659
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
16551660
sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
1661+
sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
16561662
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
16571663
sym_freeze = ID2SYM(rb_intern("freeze"));
16581664
sym_on_load = ID2SYM(rb_intern("on_load"));

test/json/json_parser_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,14 @@ def test_parse_allowed_control_chars_in_string
183183
end
184184
end
185185

186+
def test_parse_invalid_escape
187+
assert_raise JSON::ParserError do
188+
parse(%("fo\\o"))
189+
end
190+
191+
assert_equal "foo", parse(%("fo\\o"), allow_invalid_escape: true)
192+
end
193+
186194
def test_parse_arrays
187195
assert_equal([1,2,3], parse('[1,2,3]'))
188196
assert_equal([1.2,2,3], parse('[1.2,2,3]'))

0 commit comments

Comments
 (0)