brotli 0.9.2 → 0.9.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 035e04e32804b36b5525cf4ba7688e19a199288e0056fcfceeeac67f11f72c9f
4
- data.tar.gz: 8ce5e925a781060c0d46dfebd69beb367c62622fb808ef247906e0bf2229aaa8
3
+ metadata.gz: 69c5177d348df73fc4a46b6885e0432228c9050a0c003daa70ac19ec8a161c33
4
+ data.tar.gz: 80b2f49422f8e77dec0c297f2c74e5d3ee8f326f06f958c86d215f4391150527
5
5
  SHA512:
6
- metadata.gz: 70c2bdf0f5028d80f5f0c578f89bf2c6818de1c9c4f795fe61aeeffbbcf570353d97699ce02f9e44e713f54e34fd9c0a745d9b6f3ef9e7f9b62e5ffc6f1b0707
7
- data.tar.gz: dd17edfde50109928ca623452044288b6d369cd6a29706727248623f8ad6d03ea89857fd668e67ca01b22a1baf39b27fbd47c86635a2455ec1c1d2400c4c5d77
6
+ metadata.gz: 4574d6aaeecfcd073d3bb8bdfa21a766f71843f52d9e7e8446549fb93748a79775a7f296dcf2756e28b796daaef229d696c900d68e159c0dc3cee74357c1b1da
7
+ data.tar.gz: 86002231379c75386cce7da64fadae167c04afb5d635fcc46d1bad0b6137d4921e65736463c8585d6c7c8f6b3818db1a453bf1c7091ab59d482c9d7940f270ae
data/README.md CHANGED
@@ -192,6 +192,28 @@ You usually do not need `output_buffer_limit:` when:
192
192
  - you are using `Brotli::Reader`, which already handles incremental buffering for IO-style reads
193
193
  - you are happy for each `#process` call to return all currently available output
194
194
 
195
+ ### Large-window Brotli
196
+
197
+ RFC 9841 large-window streams are rejected by default. Applications that require
198
+ this extension, such as readers of the PDF Association Brotli extension, can opt
199
+ in for a single decoder:
200
+
201
+ ```ruby
202
+ Brotli.inflate(compressed, large_window: true)
203
+ Brotli::Reader.new(io, large_window: true)
204
+ Brotli::Decompressor.new(large_window: true)
205
+ ```
206
+
207
+ The option does not enable shared dictionaries or a framing format and does not
208
+ change the default for other decoders.
209
+
210
+ **Memory warning:** with `large_window: true`, the stream header may request a
211
+ window of up to 1 GiB (2^30 bytes), and the decoder allocates its ring buffer
212
+ to match. A small untrusted input can therefore make a single decoder reserve
213
+ close to 1 GiB. `output_buffer_limit:` does not bound this allocation. Enable
214
+ the option only for trusted input, or enforce a memory limit at the process or
215
+ container level.
216
+
195
217
  See test/brotli_test.rb for more examples.
196
218
 
197
219
  ## Development
data/ext/brotli/brotli.c CHANGED
@@ -3,6 +3,7 @@
3
3
  static VALUE rb_eBrotli;
4
4
  static ID id_cmp;
5
5
  static ID id_dictionary;
6
+ static ID id_large_window;
6
7
  static ID id_font;
7
8
  static ID id_generic;
8
9
  static ID id_lgblock;
@@ -144,6 +145,13 @@ brotli_inflate_take_result(VALUE arg)
144
145
  return rb_str_new(args->buffer->ptr, args->buffer->used);
145
146
  }
146
147
 
148
+ static VALUE
149
+ brotli_inflate_run(VALUE arg)
150
+ {
151
+ rb_thread_call_without_gvl(brotli_inflate_no_gvl, (void *)arg, NULL, NULL);
152
+ return Qnil;
153
+ }
154
+
147
155
  static VALUE
148
156
  brotli_inflate(int argc, VALUE *argv, VALUE self)
149
157
  {
@@ -153,6 +161,7 @@ brotli_inflate(int argc, VALUE *argv, VALUE self)
153
161
  VALUE dict = Qnil;
154
162
  const char *error = NULL;
155
163
  brotli_inflate_args_t args = {0};
164
+ int state = 0;
156
165
 
157
166
  (void)self;
158
167
 
@@ -178,6 +187,12 @@ brotli_inflate(int argc, VALUE *argv, VALUE self)
178
187
  }
179
188
  args.r = BROTLI_DECODER_RESULT_ERROR;
180
189
 
190
+ if (RTEST(brotli_hash_lookup(opts, id_large_window)) &&
191
+ !BrotliDecoderSetParameter(args.s, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1)) {
192
+ brotli_inflate_cleanup(&args);
193
+ rb_raise(rb_eBrotli, "Failed to enable large-window decompression");
194
+ }
195
+
181
196
  if (!NIL_P(dict)) {
182
197
  args.dict = (uint8_t*)RSTRING_PTR(dict);
183
198
  args.dict_len = (size_t)RSTRING_LEN(dict);
@@ -186,9 +201,18 @@ brotli_inflate(int argc, VALUE *argv, VALUE self)
186
201
  args.dict_len = 0;
187
202
  }
188
203
 
189
- rb_thread_call_without_gvl(brotli_inflate_no_gvl, &args, NULL, NULL);
204
+ /*
205
+ * rb_thread_call_without_gvl() handles pending interrupts (Thread#raise,
206
+ * Timeout, signals) around the worker and may raise from there. Catch it
207
+ * so the decoder state and output buffer are released before re-raising.
208
+ */
209
+ rb_protect(brotli_inflate_run, (VALUE)&args, &state);
190
210
  RB_GC_GUARD(str);
191
211
  RB_GC_GUARD(dict);
212
+ if (state) {
213
+ brotli_inflate_cleanup(&args);
214
+ rb_jump_tag(state);
215
+ }
192
216
 
193
217
  /* Check before args.r: a failed final append leaves r at SUCCESS. */
194
218
  if (args.oom) {
@@ -197,7 +221,6 @@ brotli_inflate(int argc, VALUE *argv, VALUE self)
197
221
  }
198
222
 
199
223
  if (args.r == BROTLI_DECODER_RESULT_SUCCESS) {
200
- int state = 0;
201
224
  value = rb_protect(brotli_inflate_take_result, (VALUE)&args, &state);
202
225
  if (state) {
203
226
  brotli_inflate_cleanup(&args);
@@ -406,6 +429,13 @@ brotli_deflate_take_result(VALUE arg)
406
429
  return rb_str_new(args->buffer->ptr, args->buffer->used);
407
430
  }
408
431
 
432
+ static VALUE
433
+ brotli_deflate_run(VALUE arg)
434
+ {
435
+ rb_thread_call_without_gvl(brotli_deflate_no_gvl, (void *)arg, NULL, NULL);
436
+ return Qnil;
437
+ }
438
+
409
439
  static VALUE
410
440
  brotli_deflate(int argc, VALUE *argv, VALUE self)
411
441
  {
@@ -416,6 +446,7 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
416
446
  brotli_deflate_args_t args = {0};
417
447
  size_t max_compressed_size;
418
448
  const char *err;
449
+ int state = 0;
419
450
 
420
451
  (void)self;
421
452
 
@@ -465,15 +496,19 @@ brotli_deflate(int argc, VALUE *argv, VALUE self)
465
496
  }
466
497
  }
467
498
 
468
- rb_thread_call_without_gvl(brotli_deflate_no_gvl, &args, NULL, NULL);
499
+ /* See brotli_inflate: an interrupt may raise out of the GVL release. */
500
+ rb_protect(brotli_deflate_run, (VALUE)&args, &state);
469
501
  RB_GC_GUARD(str);
470
502
  RB_GC_GUARD(dict);
503
+ if (state) {
504
+ brotli_deflate_cleanup(&args);
505
+ rb_jump_tag(state);
506
+ }
471
507
  if (args.oom) {
472
508
  brotli_deflate_cleanup(&args);
473
509
  rb_raise(rb_eNoMemError, "failed to allocate compression buffer");
474
510
  }
475
511
  if (args.finished == BROTLI_TRUE) {
476
- int state = 0;
477
512
  value = rb_protect(brotli_deflate_take_result, (VALUE)&args, &state);
478
513
  if (state) {
479
514
  brotli_deflate_cleanup(&args);
@@ -971,6 +1006,10 @@ rb_decompressor_initialize(int argc, VALUE* argv, VALUE self)
971
1006
  rb_scan_args(argc, argv, "01", &opts);
972
1007
  TypedData_Get_Struct(self, brotli_decompressor_t, &brotli_decompressor_data_type, br);
973
1008
  brotli_decompressor_reset(self, br);
1009
+ if (RTEST(brotli_hash_lookup(opts, id_large_window)) &&
1010
+ !BrotliDecoderSetParameter(br->state, BROTLI_DECODER_PARAM_LARGE_WINDOW, 1)) {
1011
+ rb_raise(rb_eBrotli, "Failed to enable large-window decompression");
1012
+ }
974
1013
  brotli_decompressor_attach_dictionary(br, opts);
975
1014
 
976
1015
  return self;
@@ -1216,6 +1255,7 @@ Init_brotli(void)
1216
1255
  rb_define_singleton_method(rb_mBrotli, "version", brotli_version, 0);
1217
1256
  id_cmp = rb_intern("<=>");
1218
1257
  id_dictionary = rb_intern("dictionary");
1258
+ id_large_window = rb_intern("large_window");
1219
1259
  id_font = rb_intern("font");
1220
1260
  id_generic = rb_intern("generic");
1221
1261
  id_lgblock = rb_intern("lgblock");
@@ -1,3 +1,3 @@
1
1
  module Brotli
2
- VERSION = '0.9.2'
2
+ VERSION = '0.9.3'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brotli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - miyucy