json 2.7.5 → 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8138305febf8acb1cc4533b5e5b071928167b88f17567cf18d99fc1dcbeef234
4
- data.tar.gz: 9648ecf580a9f686cd1fb879efbeb85509c800f13c1372e282298eb713dce740
3
+ metadata.gz: 8404bbc1f96ebfb471ebafc0fadef1f11125cd62c6cf1157091793183a8bdc32
4
+ data.tar.gz: 4c93c85a2575eda3308cf404f116d8e638605d884fb14cd3ab3ee511b649c211
5
5
  SHA512:
6
- metadata.gz: 6a34f95616a3ac364d06004e8b2049c36b760206553e2596993af96cf295755019c083f2e1a51b931829dc199c2ebc919dfbac2079be9c7198b8ed03ae999df6
7
- data.tar.gz: fbd73f6e5fa24dd5406556a0dba0ad8cb7d3c704700d29322eded2a2bc6405a16dd12d7cadd6792153970b7dfbbf013dddf70d626ae05609c57a76c4401de950
6
+ metadata.gz: 2043b99c8ca617249d1b3c81d899ebaf86dc2436196f08b0f9a32ee3ba7fa174c20124ca0f75157828049dc71f46fcd8937978cf463f952b2f2e6af113dfab42
7
+ data.tar.gz: bccae4170d82569a9018ef7497bfb5b228a9371e7c79d84cb4fcc7659be144e3a3ba455db40ecf509a31b576f311d1ad4f85989aea549f59c003210adf87fc77
data/CHANGES.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Changes
2
2
 
3
+ ### 2024-12-18 (2.9.1)
4
+
5
+ * Fix support for Solaris 10.
6
+
7
+ ### 2024-12-03 (2.9.0)
8
+
9
+ * Fix C implementation of `script_safe` escaping to not confuse some other 3 wide characters with `\u2028` and `\u2029`.
10
+ e.g. `JSON.generate(["倩", "瀨"], script_safe: true)` would generate the wrong JSON.
11
+ * `JSON.dump(object, some_io)` now write into the IO in chunks while previously it would buffer the entire JSON before writing.
12
+ * `JSON::GeneratorError` now has a `#invalid_object` attribute, making it easier to understand why an object tree cannot be serialized.
13
+ * Numerous improvements to the JRuby extension.
14
+
15
+ ### 2024-11-14 (2.8.2)
16
+
17
+ * `JSON.load_file` explictly read the file as UTF-8.
18
+
19
+ ### 2024-11-06 (2.8.1)
20
+
21
+ * Fix the java packages to include the extension.
22
+
23
+ ### 2024-11-06 (2.8.0)
24
+
25
+ * Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled.
26
+ * Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`.
27
+ * Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`.
28
+ * Bump required Ruby version to 2.7.
29
+ * Add support for optionally parsing trailing commas, via `allow_trailing_comma: true`, which in cunjunction with the
30
+ pre-existing support for comments, make it suitable to parse `jsonc` documents.
31
+ * Many performance improvements to `JSON.parse` and `JSON.load`, up to `1.7x` faster on real world documents.
32
+ * Some minor performance improvements to `JSON.dump` and `JSON.generate`.
33
+ * `JSON.pretty_generate` no longer include newline inside empty object and arrays.
34
+
35
+ ### 2024-11-04 (2.7.6)
36
+
37
+ * Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them.
38
+
3
39
  ### 2024-10-25 (2.7.5)
4
40
 
5
41
  * Fix a memory leak when `#to_json` methods raise an exception.
data/README.md CHANGED
@@ -5,16 +5,10 @@
5
5
  ## Description
6
6
 
7
7
  This is an implementation of the JSON specification according to RFC 7159
8
- http://www.ietf.org/rfc/rfc7159.txt . There is two variants available:
8
+ http://www.ietf.org/rfc/rfc7159.txt .
9
9
 
10
- * A pure ruby variant, that relies on the `strscan` extensions, which is
11
- part of the ruby standard library.
12
- * The quite a bit faster native extension variant, which is in parts
13
- implemented in C or Java and comes with a parser generated by the [Ragel]
14
- state machine compiler.
15
-
16
- Both variants of the JSON generator generate UTF-8 character sequences by
17
- default. If an :ascii\_only option with a true value is given, they escape all
10
+ The JSON generator generate UTF-8 character sequences by default.
11
+ If an :ascii\_only option with a true value is given, they escape all
18
12
  non-ASCII and control characters with \uXXXX escape sequences, and support
19
13
  UTF-16 surrogate pairs in order to be able to generate the whole range of
20
14
  unicode code points.
@@ -27,10 +21,6 @@ endpoint.
27
21
 
28
22
  ## Installation
29
23
 
30
- It's recommended to use the extension variant of JSON, because it's faster than
31
- the pure ruby variant. If you cannot build it on your system, you can settle
32
- for the latter.
33
-
34
24
  Install the gem and add to the application's Gemfile by executing:
35
25
 
36
26
  $ bundle add json
@@ -39,12 +29,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
39
29
 
40
30
  $ gem install json
41
31
 
42
-
43
- There is also a pure ruby json only variant of the gem, that can be installed
44
- with:
45
-
46
- $ gem install json_pure
47
-
48
32
  ## Usage
49
33
 
50
34
  To use JSON you can
@@ -53,20 +37,6 @@ To use JSON you can
53
37
  require 'json'
54
38
  ```
55
39
 
56
- to load the installed variant (either the extension `'json'` or the pure
57
- variant `'json_pure'`). If you have installed the extension variant, you can
58
- pick either the extension variant or the pure variant by typing
59
-
60
- ```ruby
61
- require 'json/ext'
62
- ```
63
-
64
- or
65
-
66
- ```ruby
67
- require 'json/pure'
68
- ```
69
-
70
40
  Now you can parse a JSON document into a ruby data structure by calling
71
41
 
72
42
  ```ruby
@@ -82,50 +52,11 @@ You can also use the `pretty_generate` method (which formats the output more
82
52
  verbosely and nicely) or `fast_generate` (which doesn't do any of the security
83
53
  checks generate performs, e. g. nesting deepness checks).
84
54
 
85
- There are also the JSON and JSON[] methods which use parse on a String or
86
- generate a JSON document from an array or hash:
87
-
88
- ```ruby
89
- document = JSON 'test' => 23 # => "{\"test\":23}"
90
- document = JSON['test' => 23] # => "{\"test\":23}"
91
- ```
92
-
93
- and
94
-
95
- ```ruby
96
- data = JSON '{"test":23}' # => {"test"=>23}
97
- data = JSON['{"test":23}'] # => {"test"=>23}
98
- ```
99
-
100
- You can choose to load a set of common additions to ruby core's objects if
101
- you
102
-
103
- ```ruby
104
- require 'json/add/core'
105
- ```
106
-
107
- After requiring this you can, e. g., serialise/deserialise Ruby ranges:
108
-
109
- ```ruby
110
- JSON JSON(1..10) # => 1..10
111
- ```
112
-
113
- To find out how to add JSON support to other or your own classes, read the
114
- section "More Examples" below.
115
-
116
- ## Serializing exceptions
117
-
118
- The JSON module doesn't extend `Exception` by default. If you convert an `Exception`
119
- object to JSON, it will by default only include the exception message.
120
-
121
- To include the full details, you must either load the `json/add/core` mentioned
122
- above, or specifically load the exception addition:
123
-
124
- ```ruby
125
- require 'json/add/exception'
126
- ```
55
+ ## Handling arbitrary types
127
56
 
128
- ## More Examples
57
+ > [!CAUTION]
58
+ > You should never use `JSON.unsafe_load` nor `JSON.parse(str, create_additions: true)` to parse untrusted user input,
59
+ > as it can lead to remote code execution vulnerabilities.
129
60
 
130
61
  To create a JSON document from a ruby data structure, you can call
131
62
  `JSON.generate` like that:
@@ -191,7 +122,7 @@ JSON.parse json
191
122
  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
192
123
  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
193
124
  # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
194
- JSON.parse json, :create_additions => true
125
+ JSON.unsafe_load json
195
126
  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
196
127
  ```
197
128
 
@@ -4,21 +4,60 @@
4
4
  #include "ruby.h"
5
5
  #include "ruby/encoding.h"
6
6
 
7
+ /* shims */
8
+ /* This is the fallback definition from Ruby 3.4 */
9
+
10
+ #ifndef RBIMPL_STDBOOL_H
11
+ #if defined(__cplusplus)
12
+ # if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
13
+ # include <cstdbool>
14
+ # endif
15
+ #elif defined(HAVE_STDBOOL_H)
16
+ # include <stdbool.h>
17
+ #elif !defined(HAVE__BOOL)
18
+ typedef unsigned char _Bool;
19
+ # define bool _Bool
20
+ # define true ((_Bool)+1)
21
+ # define false ((_Bool)+0)
22
+ # define __bool_true_false_are_defined
23
+ #endif
24
+ #endif
25
+
26
+ #ifndef RB_UNLIKELY
27
+ #define RB_UNLIKELY(expr) expr
28
+ #endif
29
+
30
+ #ifndef RB_LIKELY
31
+ #define RB_LIKELY(expr) expr
32
+ #endif
33
+
34
+ #ifndef MAYBE_UNUSED
35
+ # define MAYBE_UNUSED(x) x
36
+ #endif
37
+
38
+ enum fbuffer_type {
39
+ FBUFFER_HEAP_ALLOCATED = 0,
40
+ FBUFFER_STACK_ALLOCATED = 1,
41
+ };
42
+
7
43
  typedef struct FBufferStruct {
44
+ enum fbuffer_type type;
8
45
  unsigned long initial_length;
9
- char *ptr;
10
46
  unsigned long len;
11
47
  unsigned long capa;
48
+ char *ptr;
49
+ VALUE io;
12
50
  } FBuffer;
13
51
 
52
+ #define FBUFFER_STACK_SIZE 512
53
+ #define FBUFFER_IO_BUFFER_SIZE (16384 - 1)
14
54
  #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
15
55
 
16
- #define FBUFFER_PTR(fb) (fb->ptr)
17
- #define FBUFFER_LEN(fb) (fb->len)
18
- #define FBUFFER_CAPA(fb) (fb->capa)
56
+ #define FBUFFER_PTR(fb) ((fb)->ptr)
57
+ #define FBUFFER_LEN(fb) ((fb)->len)
58
+ #define FBUFFER_CAPA(fb) ((fb)->capa)
19
59
  #define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
20
60
 
21
- static FBuffer *fbuffer_alloc(unsigned long initial_length);
22
61
  static void fbuffer_free(FBuffer *fb);
23
62
  #ifndef JSON_GENERATOR
24
63
  static void fbuffer_clear(FBuffer *fb);
@@ -27,55 +66,85 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
27
66
  #ifdef JSON_GENERATOR
28
67
  static void fbuffer_append_long(FBuffer *fb, long number);
29
68
  #endif
30
- static void fbuffer_append_char(FBuffer *fb, char newchr);
69
+ static inline void fbuffer_append_char(FBuffer *fb, char newchr);
31
70
  #ifdef JSON_GENERATOR
32
- static VALUE fbuffer_to_s(FBuffer *fb);
33
- #endif
34
-
35
- #ifndef RB_UNLIKELY
36
- #define RB_UNLIKELY(expr) expr
71
+ static VALUE fbuffer_finalize(FBuffer *fb);
37
72
  #endif
38
73
 
39
- static FBuffer *fbuffer_alloc(unsigned long initial_length)
74
+ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
40
75
  {
41
- FBuffer *fb;
42
- if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
43
- fb = ALLOC(FBuffer);
44
- memset((void *) fb, 0, sizeof(FBuffer));
45
- fb->initial_length = initial_length;
46
- return fb;
76
+ fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
77
+ if (stack_buffer) {
78
+ fb->type = FBUFFER_STACK_ALLOCATED;
79
+ fb->ptr = stack_buffer;
80
+ fb->capa = stack_buffer_size;
81
+ }
47
82
  }
48
83
 
49
84
  static void fbuffer_free(FBuffer *fb)
50
85
  {
51
- if (fb->ptr) ruby_xfree(fb->ptr);
52
- ruby_xfree(fb);
86
+ if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
87
+ ruby_xfree(fb->ptr);
88
+ }
53
89
  }
54
90
 
55
- #ifndef JSON_GENERATOR
56
91
  static void fbuffer_clear(FBuffer *fb)
57
92
  {
58
93
  fb->len = 0;
59
94
  }
60
- #endif
61
95
 
62
- static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
96
+ static void fbuffer_flush(FBuffer *fb)
63
97
  {
64
- if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
65
- unsigned long required;
98
+ rb_io_write(fb->io, rb_utf8_str_new(fb->ptr, fb->len));
99
+ fbuffer_clear(fb);
100
+ }
66
101
 
67
- if (RB_UNLIKELY(!fb->ptr)) {
68
- fb->ptr = ALLOC_N(char, fb->initial_length);
69
- fb->capa = fb->initial_length;
102
+ static void fbuffer_realloc(FBuffer *fb, unsigned long required)
103
+ {
104
+ if (required > fb->capa) {
105
+ if (fb->type == FBUFFER_STACK_ALLOCATED) {
106
+ const char *old_buffer = fb->ptr;
107
+ fb->ptr = ALLOC_N(char, required);
108
+ fb->type = FBUFFER_HEAP_ALLOCATED;
109
+ MEMCPY(fb->ptr, old_buffer, char, fb->len);
110
+ } else {
111
+ REALLOC_N(fb->ptr, char, required);
70
112
  }
113
+ fb->capa = required;
114
+ }
115
+ }
71
116
 
72
- for (required = fb->capa; requested > required - fb->len; required <<= 1);
117
+ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
118
+ {
119
+ if (RB_UNLIKELY(fb->io)) {
120
+ if (fb->capa < FBUFFER_IO_BUFFER_SIZE) {
121
+ fbuffer_realloc(fb, FBUFFER_IO_BUFFER_SIZE);
122
+ } else {
123
+ fbuffer_flush(fb);
124
+ }
73
125
 
74
- if (required > fb->capa) {
75
- REALLOC_N(fb->ptr, char, required);
76
- fb->capa = required;
126
+ if (RB_LIKELY(requested < fb->capa)) {
127
+ return;
77
128
  }
78
129
  }
130
+
131
+ unsigned long required;
132
+
133
+ if (RB_UNLIKELY(!fb->ptr)) {
134
+ fb->ptr = ALLOC_N(char, fb->initial_length);
135
+ fb->capa = fb->initial_length;
136
+ }
137
+
138
+ for (required = fb->capa; requested > required - fb->len; required <<= 1);
139
+
140
+ fbuffer_realloc(fb, required);
141
+ }
142
+
143
+ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
144
+ {
145
+ if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
146
+ fbuffer_do_inc_capa(fb, requested);
147
+ }
79
148
  }
80
149
 
81
150
  static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
@@ -99,7 +168,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
99
168
  }
100
169
  #endif
101
170
 
102
- static void fbuffer_append_char(FBuffer *fb, char newchr)
171
+ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
103
172
  {
104
173
  fbuffer_inc_capa(fb, 1);
105
174
  *(fb->ptr + fb->len) = newchr;
@@ -107,40 +176,39 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
107
176
  }
108
177
 
109
178
  #ifdef JSON_GENERATOR
110
- static void freverse(char *start, char *end)
111
- {
112
- char c;
113
-
114
- while (end > start) {
115
- c = *end, *end-- = *start, *start++ = c;
116
- }
117
- }
118
-
119
179
  static long fltoa(long number, char *buf)
120
180
  {
121
- static char digits[] = "0123456789";
181
+ static const char digits[] = "0123456789";
122
182
  long sign = number;
123
183
  char* tmp = buf;
124
184
 
125
185
  if (sign < 0) number = -number;
126
- do *tmp++ = digits[number % 10]; while (number /= 10);
127
- if (sign < 0) *tmp++ = '-';
128
- freverse(buf, tmp - 1);
129
- return tmp - buf;
186
+ do *tmp-- = digits[number % 10]; while (number /= 10);
187
+ if (sign < 0) *tmp-- = '-';
188
+ return buf - tmp;
130
189
  }
131
190
 
191
+ #define LONG_BUFFER_SIZE 20
132
192
  static void fbuffer_append_long(FBuffer *fb, long number)
133
193
  {
134
- char buf[20];
135
- unsigned long len = fltoa(number, buf);
136
- fbuffer_append(fb, buf, len);
194
+ char buf[LONG_BUFFER_SIZE];
195
+ char *buffer_end = buf + LONG_BUFFER_SIZE;
196
+ long len = fltoa(number, buffer_end - 1);
197
+ fbuffer_append(fb, buffer_end - len, len);
137
198
  }
138
199
 
139
- static VALUE fbuffer_to_s(FBuffer *fb)
200
+ static VALUE fbuffer_finalize(FBuffer *fb)
140
201
  {
141
- VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
142
- fbuffer_free(fb);
143
- return result;
202
+ if (fb->io) {
203
+ fbuffer_flush(fb);
204
+ fbuffer_free(fb);
205
+ rb_io_flush(fb->io);
206
+ return fb->io;
207
+ } else {
208
+ VALUE result = rb_utf8_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
209
+ fbuffer_free(fb);
210
+ return result;
211
+ }
144
212
  }
145
213
  #endif
146
214
  #endif