oj 3.16.17 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/oj/parser.c +27 -0
- data/ext/oj/safe.c +229 -0
- data/ext/oj/safe.h +79 -0
- data/lib/oj/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d153733a0b640e93e96e1dfc33acdf8d5036a84c25623724aa066c2bf7b788c
|
|
4
|
+
data.tar.gz: 93002145e84e03a96081403375a79f8de3c0e3c82f4fb7e66d9b5e23eb8017c1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03c04836b8ba02a0799e38ece9470d867b5dd3bd448046fffa2f11cae045bee5636bcc4e082b1b38559ca2b6d0199fe1bfc3c94fa5e09411d2105c3c2d9ae41c
|
|
7
|
+
data.tar.gz: 0ba707a91beeb52d1b3b6ebdcf23b193d575a20d6b323cd3d711ecb26774969644a111d5798d3c43092e6ce307d138f206859abb6143a1ba7a63cfe293c49a36
|
data/CHANGELOG.md
CHANGED
data/ext/oj/parser.c
CHANGED
|
@@ -1182,6 +1182,8 @@ extern void oj_set_parser_validator(ojParser p);
|
|
|
1182
1182
|
extern void oj_set_parser_saj(ojParser p);
|
|
1183
1183
|
extern void oj_set_parser_usual(ojParser p);
|
|
1184
1184
|
extern void oj_set_parser_debug(ojParser p);
|
|
1185
|
+
extern void oj_set_parser_safe(ojParser p, VALUE options);
|
|
1186
|
+
extern void oj_safe_init(VALUE parser_class);
|
|
1185
1187
|
|
|
1186
1188
|
static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
1187
1189
|
ojParser p = (ojParser)ptr;
|
|
@@ -1607,6 +1609,28 @@ static VALUE parser_validate(VALUE self) {
|
|
|
1607
1609
|
return validate_parser;
|
|
1608
1610
|
}
|
|
1609
1611
|
|
|
1612
|
+
static VALUE parser_safe(int argc, VALUE *argv, VALUE self) {
|
|
1613
|
+
VALUE options;
|
|
1614
|
+
|
|
1615
|
+
if (1 == argc) {
|
|
1616
|
+
options = argv[0];
|
|
1617
|
+
|
|
1618
|
+
Check_Type(options, T_HASH);
|
|
1619
|
+
} else {
|
|
1620
|
+
options = rb_hash_new();
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1624
|
+
|
|
1625
|
+
memset(p, 0, sizeof(struct _ojParser));
|
|
1626
|
+
buf_init(&p->key);
|
|
1627
|
+
buf_init(&p->buf);
|
|
1628
|
+
p->map = value_map;
|
|
1629
|
+
oj_set_parser_safe(p, options);
|
|
1630
|
+
|
|
1631
|
+
return TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1610
1634
|
/* Document-class: Oj::Parser
|
|
1611
1635
|
*
|
|
1612
1636
|
* A reusable parser that makes use of named delegates to determine the
|
|
@@ -1634,4 +1658,7 @@ void oj_parser_init(void) {
|
|
|
1634
1658
|
rb_define_module_function(parser_class, "usual", parser_usual, 0);
|
|
1635
1659
|
rb_define_module_function(parser_class, "saj", parser_saj, 0);
|
|
1636
1660
|
rb_define_module_function(parser_class, "validate", parser_validate, 0);
|
|
1661
|
+
rb_define_module_function(parser_class, "safe", parser_safe, -1);
|
|
1662
|
+
|
|
1663
|
+
oj_safe_init(parser_class);
|
|
1637
1664
|
}
|
data/ext/oj/safe.c
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
#include "safe.h"
|
|
2
|
+
|
|
3
|
+
static VALUE max_hash_size_sym, max_array_size_sym, max_depth_sym, max_total_elements_sym, max_hash_size_error_class,
|
|
4
|
+
max_array_size_error_class, max_depth_error_class, max_total_elements_error_class;
|
|
5
|
+
|
|
6
|
+
static void check_object_size(safe_T safe) {
|
|
7
|
+
if (NIL_P(safe->max_hash_size)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
struct _usual usual = safe->usual;
|
|
12
|
+
Col current_object_location = usual.ctail - 1;
|
|
13
|
+
|
|
14
|
+
long int number_of_items_in_stack = usual.vtail - usual.vhead;
|
|
15
|
+
long int number_of_items_in_hash = (number_of_items_in_stack - current_object_location->vi - 1) / 2;
|
|
16
|
+
|
|
17
|
+
if (safe->max_hash_size > number_of_items_in_hash) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
rb_raise(max_hash_size_error_class, "Too many object items!");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
static void check_array_size(safe_T safe) {
|
|
25
|
+
if (NIL_P(safe->max_array_size)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
struct _usual usual = safe->usual;
|
|
30
|
+
Col current_object_location = usual.ctail - 1;
|
|
31
|
+
|
|
32
|
+
long int number_of_items_in_stack = usual.vtail - usual.vhead;
|
|
33
|
+
long int number_of_items_in_array = number_of_items_in_stack - current_object_location->vi - 1;
|
|
34
|
+
|
|
35
|
+
if (safe->max_array_size > number_of_items_in_array) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
rb_raise(max_array_size_error_class, "Too many array items!");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static void check_max_depth(safe_T safe, ojParser p) {
|
|
43
|
+
if (NIL_P(safe->max_depth) || safe->max_depth >= (p->depth + 1)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
rb_raise(max_depth_error_class, "JSON is too deep!");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static void check_max_total_elements(safe_T safe) {
|
|
51
|
+
/*
|
|
52
|
+
* We check if `max_total_elements` is greater than `current_elements_count`
|
|
53
|
+
* (instead of greater than or equal) because top-level elements (e.g., [],
|
|
54
|
+
* null, true) are not counted. As a result, `current_elements_count`
|
|
55
|
+
* always holds one less than the actual total.
|
|
56
|
+
*/
|
|
57
|
+
if (NIL_P(safe->max_total_elements) || safe->max_total_elements > safe->current_elements_count) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
rb_raise(max_total_elements_error_class, "Too many elements!");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static void safe_start(ojParser p) {
|
|
65
|
+
safe_T safe = (safe_T)p->ctx;
|
|
66
|
+
|
|
67
|
+
safe->current_hash_size = 0;
|
|
68
|
+
safe->current_array_size = 0;
|
|
69
|
+
safe->current_elements_count = 0;
|
|
70
|
+
|
|
71
|
+
safe->delegated_start_func(p);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
static void safe_open_object(ojParser p) {
|
|
75
|
+
safe_T safe = (safe_T)p->ctx;
|
|
76
|
+
|
|
77
|
+
safe->current_hash_size++;
|
|
78
|
+
safe->current_elements_count++;
|
|
79
|
+
|
|
80
|
+
check_array_size(safe);
|
|
81
|
+
check_max_depth(safe, p);
|
|
82
|
+
check_max_total_elements(safe);
|
|
83
|
+
|
|
84
|
+
safe->delegated_open_object_func(p);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static void safe_open_array(ojParser p) {
|
|
88
|
+
safe_T safe = (safe_T)p->ctx;
|
|
89
|
+
|
|
90
|
+
safe->current_array_size++;
|
|
91
|
+
safe->current_elements_count++;
|
|
92
|
+
|
|
93
|
+
check_array_size(safe);
|
|
94
|
+
check_max_depth(safe, p);
|
|
95
|
+
check_max_total_elements(safe);
|
|
96
|
+
|
|
97
|
+
safe->delegated_open_array_func(p);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
DEFINE_DELEGATED_FUNCTION(add_null);
|
|
101
|
+
DEFINE_DELEGATED_FUNCTION(add_true);
|
|
102
|
+
DEFINE_DELEGATED_FUNCTION(add_false);
|
|
103
|
+
DEFINE_DELEGATED_FUNCTION(add_int);
|
|
104
|
+
DEFINE_DELEGATED_FUNCTION(add_float);
|
|
105
|
+
DEFINE_DELEGATED_FUNCTION(add_big);
|
|
106
|
+
DEFINE_DELEGATED_FUNCTION(add_str);
|
|
107
|
+
|
|
108
|
+
static void safe_open_object_key(ojParser p) {
|
|
109
|
+
safe_T safe = (safe_T)p->ctx;
|
|
110
|
+
|
|
111
|
+
safe->current_hash_size++;
|
|
112
|
+
safe->current_elements_count += 2;
|
|
113
|
+
|
|
114
|
+
check_object_size(safe);
|
|
115
|
+
check_max_depth(safe, p);
|
|
116
|
+
check_max_total_elements(safe);
|
|
117
|
+
|
|
118
|
+
safe->delegated_open_object_key_func(p);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static void safe_open_array_key(ojParser p) {
|
|
122
|
+
safe_T safe = (safe_T)p->ctx;
|
|
123
|
+
|
|
124
|
+
safe->current_array_size++;
|
|
125
|
+
safe->current_elements_count += 2;
|
|
126
|
+
|
|
127
|
+
check_object_size(safe);
|
|
128
|
+
check_max_depth(safe, p);
|
|
129
|
+
check_max_total_elements(safe);
|
|
130
|
+
|
|
131
|
+
safe->delegated_open_array_key_func(p);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_null);
|
|
135
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_true);
|
|
136
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_false);
|
|
137
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_int);
|
|
138
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_float);
|
|
139
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_big);
|
|
140
|
+
DEFINE_DELEGATED_OBJECT_FUNCTION(add_str);
|
|
141
|
+
|
|
142
|
+
void oj_init_safe_parser(ojParser p, safe_T safe, VALUE options) {
|
|
143
|
+
// Safe parser inherits all members of usual parser
|
|
144
|
+
oj_init_usual(p, &safe->usual);
|
|
145
|
+
|
|
146
|
+
safe->delegated_start_func = p->start;
|
|
147
|
+
p->start = safe_start;
|
|
148
|
+
|
|
149
|
+
Funcs f;
|
|
150
|
+
|
|
151
|
+
// Array parser functions
|
|
152
|
+
f = &p->funcs[ARRAY_FUN];
|
|
153
|
+
safe->delegated_open_object_func = f->open_object;
|
|
154
|
+
f->open_object = safe_open_object;
|
|
155
|
+
safe->delegated_open_array_func = f->open_array;
|
|
156
|
+
f->open_array = safe_open_array;
|
|
157
|
+
// The following overrides are done for counting objects
|
|
158
|
+
safe->delegated_add_null_func = f->add_null;
|
|
159
|
+
f->add_null = safe_add_null;
|
|
160
|
+
safe->delegated_add_true_func = f->add_true;
|
|
161
|
+
f->add_true = safe_add_true;
|
|
162
|
+
safe->delegated_add_false_func = f->add_false;
|
|
163
|
+
f->add_false = safe_add_false;
|
|
164
|
+
safe->delegated_add_int_func = f->add_int;
|
|
165
|
+
f->add_int = safe_add_int;
|
|
166
|
+
safe->delegated_add_float_func = f->add_float;
|
|
167
|
+
f->add_float = safe_add_float;
|
|
168
|
+
safe->delegated_add_big_func = f->add_big;
|
|
169
|
+
f->add_big = safe_add_big;
|
|
170
|
+
safe->delegated_add_str_func = f->add_str;
|
|
171
|
+
f->add_str = safe_add_str;
|
|
172
|
+
|
|
173
|
+
// Object parser functions
|
|
174
|
+
f = &p->funcs[OBJECT_FUN];
|
|
175
|
+
safe->delegated_open_object_key_func = f->open_object;
|
|
176
|
+
f->open_object = safe_open_object_key;
|
|
177
|
+
safe->delegated_open_array_key_func = f->open_array;
|
|
178
|
+
f->open_array = safe_open_array_key;
|
|
179
|
+
// The following overrides are done for counting objects
|
|
180
|
+
safe->delegated_add_null_key_func = f->add_null;
|
|
181
|
+
f->add_null = safe_add_null_key;
|
|
182
|
+
safe->delegated_add_true_key_func = f->add_true;
|
|
183
|
+
f->add_true = safe_add_true_key;
|
|
184
|
+
safe->delegated_add_false_key_func = f->add_false;
|
|
185
|
+
f->add_false = safe_add_false_key;
|
|
186
|
+
safe->delegated_add_int_key_func = f->add_int;
|
|
187
|
+
f->add_int = safe_add_int_key;
|
|
188
|
+
safe->delegated_add_float_key_func = f->add_float;
|
|
189
|
+
f->add_float = safe_add_float_key;
|
|
190
|
+
safe->delegated_add_big_key_func = f->add_big;
|
|
191
|
+
f->add_big = safe_add_big_key;
|
|
192
|
+
safe->delegated_add_str_key_func = f->add_str;
|
|
193
|
+
f->add_str = safe_add_str_key;
|
|
194
|
+
|
|
195
|
+
SET_CONFIG(max_hash_size);
|
|
196
|
+
SET_CONFIG(max_array_size);
|
|
197
|
+
SET_CONFIG(max_depth);
|
|
198
|
+
SET_CONFIG(max_total_elements);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void oj_set_parser_safe(ojParser p, VALUE options) {
|
|
202
|
+
safe_T s = OJ_R_ALLOC(struct _safe_S);
|
|
203
|
+
|
|
204
|
+
oj_init_safe_parser(p, s, options);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
void oj_safe_init(VALUE parser_class) {
|
|
208
|
+
VALUE validation_error_class = rb_define_class_under(parser_class, "ValidationError", rb_eRuntimeError);
|
|
209
|
+
|
|
210
|
+
max_hash_size_error_class = rb_define_class_under(parser_class, "HashSizeError", validation_error_class);
|
|
211
|
+
max_array_size_error_class = rb_define_class_under(parser_class, "ArraySizeError", validation_error_class);
|
|
212
|
+
max_depth_error_class = rb_define_class_under(parser_class, "DepthError", validation_error_class);
|
|
213
|
+
max_total_elements_error_class = rb_define_class_under(parser_class, "TotalElementsError", validation_error_class);
|
|
214
|
+
|
|
215
|
+
rb_gc_register_address(&max_hash_size_error_class);
|
|
216
|
+
rb_gc_register_address(&max_array_size_error_class);
|
|
217
|
+
rb_gc_register_address(&max_depth_error_class);
|
|
218
|
+
rb_gc_register_address(&max_total_elements_error_class);
|
|
219
|
+
|
|
220
|
+
max_hash_size_sym = ID2SYM(rb_intern("max_hash_size"));
|
|
221
|
+
max_array_size_sym = ID2SYM(rb_intern("max_array_size"));
|
|
222
|
+
max_depth_sym = ID2SYM(rb_intern("max_depth"));
|
|
223
|
+
max_total_elements_sym = ID2SYM(rb_intern("max_total_elements"));
|
|
224
|
+
|
|
225
|
+
rb_gc_register_address(&max_hash_size_sym);
|
|
226
|
+
rb_gc_register_address(&max_array_size_sym);
|
|
227
|
+
rb_gc_register_address(&max_depth_sym);
|
|
228
|
+
rb_gc_register_address(&max_total_elements_sym);
|
|
229
|
+
}
|
data/ext/oj/safe.h
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#include <ruby.h>
|
|
2
|
+
|
|
3
|
+
#include "parser.h"
|
|
4
|
+
#include "usual.h"
|
|
5
|
+
|
|
6
|
+
#define SET_CONFIG(config_name) \
|
|
7
|
+
do { \
|
|
8
|
+
VALUE rb_##config_name = rb_hash_aref(options, config_name##_sym); \
|
|
9
|
+
\
|
|
10
|
+
if (RB_INTEGER_TYPE_P(rb_##config_name)) { \
|
|
11
|
+
safe->config_name = NUM2LONG(rb_##config_name); \
|
|
12
|
+
} else if (!NIL_P(rb_##config_name)) { \
|
|
13
|
+
rb_raise(rb_eArgError, "Incorrect value provided for `" #config_name "`"); \
|
|
14
|
+
} else { \
|
|
15
|
+
safe->config_name = Qnil; \
|
|
16
|
+
} \
|
|
17
|
+
} while (0);
|
|
18
|
+
|
|
19
|
+
#define DEFINE_DELEGATED_FUNCTION(function_name) \
|
|
20
|
+
static void safe_##function_name(ojParser p) { \
|
|
21
|
+
safe_T safe = (safe_T)p->ctx; \
|
|
22
|
+
\
|
|
23
|
+
safe->current_elements_count++; \
|
|
24
|
+
\
|
|
25
|
+
check_array_size(safe); \
|
|
26
|
+
check_max_total_elements(safe); \
|
|
27
|
+
\
|
|
28
|
+
safe->delegated_##function_name##_func(p); \
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#define DEFINE_DELEGATED_OBJECT_FUNCTION(function_name) \
|
|
32
|
+
static void safe_##function_name##_key(ojParser p) { \
|
|
33
|
+
safe_T safe = (safe_T)p->ctx; \
|
|
34
|
+
\
|
|
35
|
+
safe->current_elements_count += 2; \
|
|
36
|
+
\
|
|
37
|
+
check_object_size(safe); \
|
|
38
|
+
check_max_total_elements(safe); \
|
|
39
|
+
\
|
|
40
|
+
safe->delegated_##function_name##_key_func(p); \
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
typedef struct _safe_S {
|
|
44
|
+
struct _usual usual;
|
|
45
|
+
|
|
46
|
+
long int max_hash_size;
|
|
47
|
+
long int max_array_size;
|
|
48
|
+
long int max_depth;
|
|
49
|
+
long int max_total_elements;
|
|
50
|
+
long int max_json_size_bytes;
|
|
51
|
+
|
|
52
|
+
long int current_hash_size;
|
|
53
|
+
long int current_array_size;
|
|
54
|
+
long int current_elements_count;
|
|
55
|
+
|
|
56
|
+
void (*delegated_start_func)(struct _ojParser *p);
|
|
57
|
+
|
|
58
|
+
// Array functions
|
|
59
|
+
void (*delegated_open_object_func)(struct _ojParser *p);
|
|
60
|
+
void (*delegated_open_array_func)(struct _ojParser *p);
|
|
61
|
+
void (*delegated_add_null_func)(struct _ojParser *p);
|
|
62
|
+
void (*delegated_add_true_func)(struct _ojParser *p);
|
|
63
|
+
void (*delegated_add_false_func)(struct _ojParser *p);
|
|
64
|
+
void (*delegated_add_int_func)(struct _ojParser *p);
|
|
65
|
+
void (*delegated_add_float_func)(struct _ojParser *p);
|
|
66
|
+
void (*delegated_add_big_func)(struct _ojParser *p);
|
|
67
|
+
void (*delegated_add_str_func)(struct _ojParser *p);
|
|
68
|
+
|
|
69
|
+
// Object functions
|
|
70
|
+
void (*delegated_open_object_key_func)(struct _ojParser *p);
|
|
71
|
+
void (*delegated_open_array_key_func)(struct _ojParser *p);
|
|
72
|
+
void (*delegated_add_null_key_func)(struct _ojParser *p);
|
|
73
|
+
void (*delegated_add_true_key_func)(struct _ojParser *p);
|
|
74
|
+
void (*delegated_add_false_key_func)(struct _ojParser *p);
|
|
75
|
+
void (*delegated_add_int_key_func)(struct _ojParser *p);
|
|
76
|
+
void (*delegated_add_float_key_func)(struct _ojParser *p);
|
|
77
|
+
void (*delegated_add_big_key_func)(struct _ojParser *p);
|
|
78
|
+
void (*delegated_add_str_key_func)(struct _ojParser *p);
|
|
79
|
+
} *safe_T;
|
data/lib/oj/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: oj
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Ohler
|
|
@@ -158,6 +158,8 @@ files:
|
|
|
158
158
|
- ext/oj/resolve.h
|
|
159
159
|
- ext/oj/rxclass.c
|
|
160
160
|
- ext/oj/rxclass.h
|
|
161
|
+
- ext/oj/safe.c
|
|
162
|
+
- ext/oj/safe.h
|
|
161
163
|
- ext/oj/saj.c
|
|
162
164
|
- ext/oj/saj2.c
|
|
163
165
|
- ext/oj/saj2.h
|