iodine 0.7.37 → 0.7.38

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: d09283cad97b84847493794f2245f7b477b6f0170a8332112c3836106d660373
4
- data.tar.gz: 3727db00462421260d06689ac5c578cda9203d2dc2c3d4daed53b4f9dc6b84f5
3
+ metadata.gz: 698e63218598fd769063529e151ab15aab31e413365a6e80130e464adac9eea3
4
+ data.tar.gz: d4b146805592a1ef5476461c349eeb31069a3213af7257caeaaccbd91b6f1929
5
5
  SHA512:
6
- metadata.gz: db93d224de064141cf4a422e05bba2e67c74ef0344dfce19579be48489cc16b070e24527e30aa4c081f9c38ca4aeb2c737f90d1edd8d157cf0d334b5f083965e
7
- data.tar.gz: 8b6e496da5af91bf59225798c41d00776caafb3aec55a57c5ee43a1ca943a0312e676e119a9a41387c4beba5350d0f71c1ec70868d29933be6b140ac1d814b64
6
+ metadata.gz: bc9d26dacd98d979d1e110eaa4c7ac04451c8332658a7be2004bd54b9d9f94adf1e55f2ee5407fd2e9f0c27295f32f9f40c3667ae42cee5fb6f76bd1a3000b8c
7
+ data.tar.gz: 224db61d880f272de498cd766d40e9641ade6fceb7c0626ba88a5cca3244561b542f846df8102a22dcb48b88b2bc2f4943a6b30d102391c36f3dde7f3ff8b9af
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: Bug report
3
+ about: Create a report to help us improve
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### System Information
11
+
12
+ - **OS**: [e.g. macOS 10.14.6]
13
+ - **Ruby**: [e.g. 2.6.1]
14
+ - **Version**: [e.g. 0.7.37]
15
+ - **OpenSSL**: [OpenSSL 1.1.1d 10 Sep 2019]
16
+
17
+ ### Description
18
+
19
+ A clear and concise description of what the bug is.
20
+
21
+ ### Rack App to Reproduce
22
+
23
+ ```ruby
24
+ APP = {|env| [200, {}, "Hello World"] }
25
+ run APP
26
+ ```
27
+
28
+ ### Testing code
29
+
30
+ ```sh
31
+ curl http://localhost:3000/
32
+ ```
33
+
34
+ ### Expected behavior
35
+
36
+ A clear and concise description of what you expected to happen.
37
+
38
+ ### Actual behavior
39
+
40
+ **Smartphone (please complete the following information):**
41
+ - Device: [e.g. iPhone6]
42
+ - OS: [e.g. iOS8.1]
43
+ - Browser [e.g. stock browser, safari]
44
+ - Version [e.g. 22]
45
+
46
+ **Additional context**
47
+ Add any other context about the problem here.
@@ -6,9 +6,9 @@ before_install:
6
6
  - gem install bundler -v 1.10.6
7
7
  - bundle install
8
8
  rvm:
9
- - 2.6.0
10
- - 2.5.3
11
- - 2.4.5
9
+ - 2.6.5
10
+ - 2.5.7
11
+ - 2.4.9
12
12
  - 2.3.8
13
13
  - 2.2.2
14
14
  notifications:
@@ -24,7 +24,8 @@ addons:
24
24
  script:
25
25
  - echo CFLAGS = $CFLAGS
26
26
  - echo cflags = $cflags
27
- - bundle exec rake compile && bundle exec rspec --format documentation
27
+ - bundle exec rake compile
28
+ - env VERBOSE=1 bundle exec rspec --format documentation
28
29
  - gem uninstall -x iodine
29
30
  - rake build
30
31
  - find pkg/iodine-*.gem -exec gem install -V {} +
@@ -6,6 +6,10 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.7.38
10
+
11
+ **Fix**: (`http`) fixes an issue and improves support for chunked encoded payloads. Credit to Ian Ker-Seymer ( @ianks ) for exposing this, writing tests and opening both the issue #87 and the PR #88.
12
+
9
13
  #### Change log v.0.7.37
10
14
 
11
15
  **Fix**: requests will fail when the path contains a dangling `?` (empty query). Credit to @adam12 for exposing this and opening issue #86.
@@ -22,6 +22,14 @@ module ShootoutApp
22
22
  len += out[-1].length
23
23
  request.params.each { |k,v| out << "#{k}: #{v}\n" ; len += out[-1].length }
24
24
  end
25
+ if(env['rack.input'])
26
+ env['rack.input'].rewind
27
+ out << "Body\n\n"
28
+ out << env['rack.input'].read
29
+ len += out[-1].length + 6
30
+ out << "\n\nBody Length: #{out[-1].length}\n\n"
31
+ len += out[-1].length
32
+ end
25
33
  [200, { 'Content-Length' => len.to_s, 'Content-Type' => 'text/plain; charset=UTF-8;' }, out]
26
34
  end
27
35
  # We'll base the shootout on the internal Pub/Sub service.
@@ -109,7 +109,7 @@ Version and helper macros
109
109
 
110
110
  #define FIO_VERSION_MAJOR 0
111
111
  #define FIO_VERSION_MINOR 7
112
- #define FIO_VERSION_PATCH 3
112
+ #define FIO_VERSION_PATCH 4
113
113
  #define FIO_VERSION_BETA 0
114
114
 
115
115
  /* Automatically convert version data to a string constant - ignore these two */
@@ -22,6 +22,10 @@ Seeking for characters in a string
22
22
  #define ALLOW_UNALIGNED_MEMORY_ACCESS 0
23
23
  #endif
24
24
 
25
+ #ifndef HTTP_ADD_CONTENT_LENGTH_HEADER_IF_MISSING
26
+ #define HTTP_ADD_CONTENT_LENGTH_HEADER_IF_MISSING 1
27
+ #endif
28
+
25
29
  #if FIO_MEMCHAR
26
30
 
27
31
  /**
@@ -31,6 +35,9 @@ Seeking for characters in a string
31
35
  */
32
36
  static int seek2ch(uint8_t **buffer, register uint8_t *const limit,
33
37
  const uint8_t c) {
38
+ if (*buffer >= limit)
39
+ return 0;
40
+
34
41
  if (**buffer == c) {
35
42
  #if HTTP1_PARSER_CONVERT_EOL2NUL
36
43
  **buffer = 0;
@@ -47,8 +54,6 @@ static int seek2ch(uint8_t **buffer, register uint8_t *const limit,
47
54
  {
48
55
  const uint8_t *alignment =
49
56
  (uint8_t *)(((uintptr_t)(*buffer) & (~(uintptr_t)7)) + 8);
50
- if (*buffer < alignment)
51
- *buffer += 1; /* already tested this char */
52
57
  if (limit >= alignment) {
53
58
  while (*buffer < alignment) {
54
59
  if (**buffer == c) {
@@ -94,7 +99,9 @@ finish:
94
99
  /* a helper that seeks any char, converts it to NUL and returns 1 if found. */
95
100
  inline static uint8_t seek2ch(uint8_t **pos, uint8_t *const limit, uint8_t ch) {
96
101
  /* This is library based alternative that is sometimes slower */
97
- if (*pos >= limit || **pos == ch) {
102
+ if (*pos >= limit)
103
+ return 0;
104
+ if (**pos == ch) {
98
105
  return 1;
99
106
  }
100
107
  uint8_t *tmp = memchr(*pos, ch, limit - (*pos));
@@ -125,6 +132,66 @@ inline static uint8_t seek2eol(uint8_t **pos, uint8_t *const limit) {
125
132
  return 1;
126
133
  }
127
134
 
135
+ /* *****************************************************************************
136
+ String to Number
137
+ ***************************************************************************** */
138
+
139
+ /** Converts a String to a number using base 10 */
140
+ static long long http1_atol(const uint8_t *buf, const uint8_t **end) {
141
+ register unsigned long long i = 0;
142
+ uint8_t inv = 0;
143
+ while (*buf == ' ' || *buf == '\t' || *buf == '\f')
144
+ ++buf;
145
+ while (*buf == '-' || *buf == '+')
146
+ inv ^= (*(buf++) == '-');
147
+ while (i <= ((((~0ULL) >> 1) / 10)) && *buf >= '0' && *buf <= '9') {
148
+ i = i * 10;
149
+ i += *buf - '0';
150
+ ++buf;
151
+ }
152
+ /* test for overflow */
153
+ if (i >= (~((~0ULL) >> 1)) || (*buf >= '0' && *buf <= '9'))
154
+ i = (~0ULL >> 1);
155
+ if (inv)
156
+ i = 0ULL - i;
157
+ if (end)
158
+ *end = buf;
159
+ return i;
160
+ }
161
+
162
+ /** Converts a String to a number using base 16, overflow limited to 113bytes */
163
+ static long long http1_atol16(const uint8_t *buf, const uint8_t **end) {
164
+ register unsigned long long i = 0;
165
+ uint8_t inv = 0;
166
+ for (int limit_ = 0;
167
+ (*buf == ' ' || *buf == '\t' || *buf == '\f') && limit_ < 32; ++limit_)
168
+ ++buf;
169
+ for (int limit_ = 0; (*buf == '-' || *buf == '+') && limit_ < 32; ++limit_)
170
+ inv ^= (*(buf++) == '-');
171
+ if (*buf == '0')
172
+ ++buf;
173
+ if ((*buf | 32) == 'x')
174
+ ++buf;
175
+ for (int limit_ = 0; (*buf == '0') && limit_ < 32; ++limit_)
176
+ ++buf;
177
+ while (!(i & (~((~(0ULL)) >> 4)))) {
178
+ if (*buf >= '0' && *buf <= '9') {
179
+ i <<= 4;
180
+ i |= *buf - '0';
181
+ } else if ((*buf | 32) >= 'a' && (*buf | 32) <= 'f') {
182
+ i <<= 4;
183
+ i |= (*buf | 32) - ('a' - 10);
184
+ } else
185
+ break;
186
+ ++buf;
187
+ }
188
+ if (inv)
189
+ i = 0ULL - i;
190
+ if (end)
191
+ *end = buf;
192
+ return i;
193
+ }
194
+
128
195
  /* *****************************************************************************
129
196
  HTTP/1.1 parsre stages
130
197
  ***************************************************************************** */
@@ -224,43 +291,113 @@ inline static int consume_header(struct http1_fio_parser_args_s *args,
224
291
  if (start_value[0] == ' ') {
225
292
  start_value++;
226
293
  };
227
- #if ALLOW_UNALIGNED_MEMORY_ACCESS && HTTP_HEADERS_LOWERCASE
228
- /* enable this section to test unaligned memory access */
294
+
229
295
  if ((end_name - start) == 14 &&
296
+ #if HTTP1_UNALIGNED_MEMORY_ACCESS_ENABLED && HTTP_HEADERS_LOWERCASE
230
297
  *((uint64_t *)start) == *((uint64_t *)"content-") &&
231
- *((uint64_t *)(start + 6)) == *((uint64_t *)"t-length")) {
298
+ *((uint64_t *)(start + 6)) == *((uint64_t *)"t-length")
299
+ #else
300
+ HEADER_NAME_IS_EQ((char *)start, "content-length", 14)
301
+ #endif
302
+ ) {
232
303
  /* handle the special `content-length` header */
233
- args->parser->state.content_length = atol((char *)start_value);
234
- } else if ((end_name - start) == 17 &&
304
+ args->parser->state.content_length = http1_atol(start_value, NULL);
305
+ } else if ((end_name - start) == 17 && (end - start_value) >= 7 &&
306
+ #if HTTP1_UNALIGNED_MEMORY_ACCESS_ENABLED && HTTP_HEADERS_LOWERCASE
235
307
  *((uint64_t *)start) == *((uint64_t *)"transfer") &&
236
- *((uint64_t *)(start + 8)) == *((uint64_t *)"-encodin") &&
237
- *((uint32_t *)start_value) == *((uint32_t *)"chun") &&
238
- *((uint32_t *)(start_value + 3)) == *((uint32_t *)"nked")) {
239
- /* handle the special `transfer-encoding: chunked` header */
240
- args->parser->state.reserved |= 64;
241
- } else if ((end_name - start) == 7 &&
242
- *((uint64_t *)start) == *((uint64_t *)"trailer")) {
243
- /* chunked data with trailer... */
244
- args->parser->state.reserved |= 64;
245
- args->parser->state.reserved |= 32;
246
- }
308
+ *((uint64_t *)(start + 8)) == *((uint64_t *)"-encodin")
247
309
  #else
248
- if ((end_name - start) == 14 &&
249
- HEADER_NAME_IS_EQ((char *)start, "content-length", 14)) {
250
- /* handle the special `content-length` header */
251
- args->parser->state.content_length = atol((char *)start_value);
252
- } else if ((end_name - start) == 17 &&
253
- HEADER_NAME_IS_EQ((char *)start, "transfer-encoding", 17) &&
254
- memcmp(start_value, "chunked", 7)) {
255
- /* handle the special `transfer-encoding: chunked` header */
256
- args->parser->state.reserved |= 64;
310
+ HEADER_NAME_IS_EQ((char *)start, "transfer-encoding", 17)
311
+ #endif
312
+ ) {
313
+ /* handle the special `transfer-encoding: chunked` header? */
314
+ /* this removes the `chunked` marker and "unchunks" the data */
315
+ if (
316
+ #if HTTP1_UNALIGNED_MEMORY_ACCESS_ENABLED
317
+ (((uint32_t *)(start_value))[0] | 0x20202020) ==
318
+ ((uint32_t *)"chun")[0] &&
319
+ (((uint32_t *)(start_value + 3))[0] | 0x20202020) ==
320
+ ((uint32_t *)"nked")[0]
321
+ #else
322
+ ((start_value[0] | 32) == 'c' && (start_value[1] | 32) == 'h' &&
323
+ (start_value[2] | 32) == 'u' && (start_value[3] | 32) == 'n' &&
324
+ (start_value[4] | 32) == 'k' && (start_value[5] | 32) == 'e' &&
325
+ (start_value[6] | 32) == 'd')
326
+ #endif
327
+ ) {
328
+ /* simple case,`chunked` at the beginning */
329
+ args->parser->state.reserved |= 64;
330
+ start_value += 7;
331
+ while (start_value < end && (*start_value == ',' || *start_value == ' '))
332
+ ++start_value;
333
+ if (!(end - start_value))
334
+ return 0;
335
+ } else if ((end - start_value) > 7 &&
336
+ ((end[(-7 + 0)] | 32) == 'c' && (end[(-7 + 1)] | 32) == 'h' &&
337
+ (end[(-7 + 2)] | 32) == 'u' && (end[(-7 + 3)] | 32) == 'n' &&
338
+ (end[(-7 + 4)] | 32) == 'k' && (end[(-7 + 5)] | 32) == 'e' &&
339
+ (end[(-7 + 6)] | 32) == 'd')) {
340
+ /* simple case,`chunked` at the end of list */
341
+ args->parser->state.reserved |= 64;
342
+ end -= 7;
343
+ while (start_value < end && (end[-1] == ',' || end[-1] == ' '))
344
+ --end;
345
+ if (!(end - start_value))
346
+ return 0;
347
+ } else if ((end - start_value) > 7 && (end - start_value) < 256) {
348
+ /* complex case, `the, chunked, marker, is in the middle of list */
349
+ uint8_t val[256];
350
+ size_t val_len = 0;
351
+ while (start_value < end) {
352
+ if (
353
+ #if HTTP1_UNALIGNED_MEMORY_ACCESS_ENABLED
354
+ (((uint32_t *)(start_value))[0] | 0x20202020) ==
355
+ ((uint32_t *)"chun")[0] &&
356
+ (((uint32_t *)(start_value + 3))[0] | 0x20202020) ==
357
+ ((uint32_t *)"nked")[0]
358
+ #else
359
+ ((start_value[0] | 32) == 'c' && (start_value[1] | 32) == 'h' &&
360
+ (start_value[2] | 32) == 'u' && (start_value[3] | 32) == 'n' &&
361
+ (start_value[4] | 32) == 'k' && (start_value[5] | 32) == 'e' &&
362
+ (start_value[6] | 32) == 'd')
363
+ #endif
364
+
365
+ ) {
366
+ args->parser->state.reserved |= 64;
367
+ start_value += 7;
368
+ /* skip comma / white space */
369
+ while (start_value < end &&
370
+ (*start_value == ',' || *start_value == ' '))
371
+ ++start_value;
372
+ break;
373
+ }
374
+ val[val_len++] = *start_value;
375
+ ++start_value;
376
+ }
377
+ while (start_value < end) {
378
+ val[val_len++] = *start_value;
379
+ ++start_value;
380
+ }
381
+ /* perform callback with `val` */
382
+ val[val_len] = 0;
383
+ if (val_len && args->on_header(args->parser, (char *)start,
384
+ (end_name - start), (char *)val, val_len))
385
+ return -1;
386
+ return 0;
387
+ }
257
388
  } else if ((end_name - start) == 7 &&
258
- HEADER_NAME_IS_EQ((char *)start, "trailer", 7)) {
389
+ #if HTTP1_UNALIGNED_MEMORY_ACCESS_ENABLED && HTTP_HEADERS_LOWERCASE
390
+ *((uint64_t *)start) == *((uint64_t *)"trailer")
391
+ #else
392
+ HEADER_NAME_IS_EQ((char *)start, "trailer", 7)
393
+ #endif
394
+ ) {
259
395
  /* chunked data with trailer... */
260
396
  args->parser->state.reserved |= 64;
261
397
  args->parser->state.reserved |= 32;
398
+ // return 0; /* hide Trailer header, since we process the headers? */
262
399
  }
263
- #endif
400
+
264
401
  /* perform callback */
265
402
  if (args->on_header(args->parser, (char *)start, (end_name - start),
266
403
  (char *)start_value, end - start_value))
@@ -295,27 +432,46 @@ inline static int consume_body_chunked(struct http1_fio_parser_args_s *args,
295
432
  uint8_t *end = *start;
296
433
  while (*start < stop) {
297
434
  if (args->parser->state.content_length == 0) {
298
- size_t eol_len;
299
- /* consume seperator */
300
- while (*start < stop && (**start == '\n' || **start == '\r'))
301
- ++(*start);
302
- /* collect chunked length */
303
- if (!(eol_len = seek2eol(&end, stop))) {
304
- /* requires length data to continue */
435
+ if (end + 2 >= stop)
305
436
  return 0;
437
+ if ((end[0] == '\r' && end[1] == '\n')) {
438
+ /* remove tailing EOL that wasn't processed and retest */
439
+ end += 2;
440
+ *start = end;
441
+ if (end + 2 >= stop)
442
+ return 0;
306
443
  }
307
- /* an empty EOL is possible in mid stream processing */
308
- if (*start + eol_len > end && (*start = end) && !seek2eol(&end, stop)) {
444
+ long long chunk_len = http1_atol16(end, (const uint8_t **)&end);
445
+ if (end + 2 > stop) /* overflowed? */
309
446
  return 0;
310
- }
311
- args->parser->state.content_length = 0 - strtol((char *)*start, NULL, 16);
312
- *start = end = end + 1;
447
+ if ((end[0] != '\r' || end[1] != '\n'))
448
+ return -1; /* required EOL after content length */
449
+ end += 2;
450
+
451
+ args->parser->state.content_length = 0 - chunk_len;
452
+ *start = end;
313
453
  if (args->parser->state.content_length == 0) {
314
- /* all chunked data was parsed */
454
+ /* all chunked data was parsed - update content-length */
315
455
  args->parser->state.content_length = args->parser->state.read;
316
456
  /* consume trailing EOL */
317
- if (seek2eol(start, stop))
318
- (*start)++;
457
+ if (*start + 2 <= stop)
458
+ *start += 2;
459
+ #ifdef HTTP_ADD_CONTENT_LENGTH_HEADER_IF_MISSING
460
+ { /* add virtual header ... ? */
461
+ char buf[512];
462
+ size_t buf_len = 512;
463
+ size_t tmp_len = args->parser->state.read;
464
+ buf[--buf_len] = 0;
465
+ while (tmp_len) {
466
+ size_t mod = tmp_len / 10;
467
+ buf[--buf_len] = '0' + (tmp_len - (mod * 10));
468
+ tmp_len = mod;
469
+ }
470
+ if (args->on_header(args->parser, "content-length", 14,
471
+ (char *)buf + buf_len, 511 - buf_len))
472
+ return -1;
473
+ }
474
+ #endif
319
475
  if (args->parser->state.reserved & 32) {
320
476
  /* remove the "headers complete" and "trailer" flags */
321
477
  args->parser->state.reserved &= 0xDD; /* 0xDD == ~2 & ~32 & 0xFF */
@@ -28,6 +28,8 @@ typedef struct {
28
28
  } iodine_http_settings_s;
29
29
 
30
30
  /* these three are used also by iodin_rack_io.c */
31
+ VALUE IODINE_R_INPUT_DEFAULT;
32
+ VALUE IODINE_R_INPUT;
31
33
  VALUE IODINE_R_HIJACK;
32
34
  VALUE IODINE_R_HIJACK_IO;
33
35
  VALUE IODINE_R_HIJACK_CB;
@@ -846,6 +848,7 @@ static void initialize_env_template(void) {
846
848
  }
847
849
  add_str_to_env(env_template_no_upgrade, "SCRIPT_NAME", sn);
848
850
  }
851
+ rb_hash_aset(env_template_no_upgrade, IODINE_R_INPUT, IODINE_R_INPUT_DEFAULT);
849
852
  add_value_to_env(env_template_no_upgrade, "rack.errors", rb_stderr);
850
853
  add_value_to_env(env_template_no_upgrade, "rack.hijack?", Qtrue);
851
854
  add_value_to_env(env_template_no_upgrade, "rack.multiprocess", Qtrue);
@@ -1111,6 +1114,7 @@ void iodine_init_http(void) {
1111
1114
  rack_set(XSENDFILE_TYPE_HEADER, "HTTP_X_SENDFILE_TYPE");
1112
1115
  rack_set(CONTENT_LENGTH_HEADER, "Content-Length");
1113
1116
 
1117
+ rack_set(IODINE_R_INPUT, "rack.input");
1114
1118
  rack_set(IODINE_R_HIJACK_IO, "rack.hijack_io");
1115
1119
  rack_set(IODINE_R_HIJACK, "rack.hijack");
1116
1120
  rack_set(IODINE_R_HIJACK_CB, "iodine.hijack_cb");
@@ -1132,5 +1136,12 @@ void iodine_init_http(void) {
1132
1136
  IodineUTF8Encoding = rb_enc_find("UTF-8");
1133
1137
  IodineBinaryEncoding = rb_enc_find("binary");
1134
1138
 
1139
+ {
1140
+ VALUE STRIO_CLASS = rb_const_get(rb_cObject, rb_intern("StringIO"));
1141
+ IODINE_R_INPUT_DEFAULT = rb_str_new_static("", 0);
1142
+ IODINE_R_INPUT_DEFAULT =
1143
+ rb_funcallv(STRIO_CLASS, rb_intern("new"), 1, &IODINE_R_INPUT_DEFAULT);
1144
+ rb_global_variable(&IODINE_R_INPUT_DEFAULT);
1145
+ }
1135
1146
  initialize_env_template();
1136
1147
  }
@@ -9,6 +9,8 @@ Feel free to copy, use and enjoy according to the license provided.
9
9
  #include "iodine.h"
10
10
 
11
11
  /* these three are used also by rb-rack-io.c */
12
+ extern VALUE IODINE_R_INPUT;
13
+ extern VALUE IODINE_R_INPUT_DEFAULT;
12
14
  extern VALUE IODINE_R_HIJACK;
13
15
  extern VALUE IODINE_R_HIJACK_IO;
14
16
  extern VALUE IODINE_R_HIJACK_CB;
@@ -216,7 +216,7 @@ static VALUE new_rack_io(http_s *h, VALUE env) {
216
216
  rb_ivar_set(rack_io, io_id, ULL2NUM(h->body));
217
217
  set_handle(rack_io, h);
218
218
  rb_ivar_set(rack_io, env_id, env);
219
- rb_hash_aset(env, R_INPUT, rack_io);
219
+ rb_hash_aset(env, IODINE_R_INPUT, rack_io);
220
220
  rb_hash_aset(env, IODINE_R_HIJACK, rb_obj_method(rack_io, hijack_func_sym));
221
221
  return rack_io;
222
222
  }
@@ -240,10 +240,6 @@ static void init_rack_io(void) {
240
240
  iodine_new_func_id = rb_intern("new");
241
241
  hijack_func_sym = ID2SYM(rb_intern("_hijack"));
242
242
 
243
- R_INPUT = rb_enc_str_new("rack.input", 10, rb_ascii8bit_encoding());
244
- rb_obj_freeze(R_INPUT);
245
- IodineStore.add(R_INPUT);
246
-
247
243
  TCPSOCKET_CLASS = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
248
244
  // IO methods
249
245
 
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
33
33
 
34
34
  spec.requirements << 'A Unix based system: Linux / macOS / BSD.'
35
35
  spec.requirements << 'An updated C compiler.'
36
- spec.requirements << 'Ruby >= 2.2.2 required for Rack 2.'
36
+ spec.requirements << 'Ruby >= 2.3.8 (Ruby EOL).'
37
37
  spec.requirements << 'Ruby >= 2.5.0 recommended.'
38
38
  spec.requirements << 'TLS requires OpenSSL >= 1.1.0'
39
39
 
@@ -1,3 +1,4 @@
1
+ require 'stringio' # Used internally as a default RackIO
1
2
  require 'socket' # TCPSocket is used internally for Hijack support
2
3
  # require 'openssl' # For SSL/TLS support using OpenSSL
3
4
 
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.37'.freeze
2
+ VERSION = '0.7.38'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.37
4
+ version: 0.7.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-13 00:00:00.000000000 Z
11
+ date: 2019-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -121,6 +121,7 @@ extensions:
121
121
  - ext/iodine/extconf.rb
122
122
  extra_rdoc_files: []
123
123
  files:
124
+ - ".github/ISSUE_TEMPLATE/bug_report.md"
124
125
  - ".gitignore"
125
126
  - ".rspec"
126
127
  - ".travis.yml"
@@ -243,7 +244,7 @@ licenses:
243
244
  metadata:
244
245
  allowed_push_host: https://rubygems.org
245
246
  post_install_message: |-
246
- Thank you for installing Iodine 0.7.37.
247
+ Thank you for installing Iodine 0.7.38.
247
248
  Remember: if iodine supports your business, it's only fair to give value back (code contributions / donations).
248
249
  rdoc_options: []
249
250
  require_paths:
@@ -262,7 +263,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
262
263
  requirements:
263
264
  - 'A Unix based system: Linux / macOS / BSD.'
264
265
  - An updated C compiler.
265
- - Ruby >= 2.2.2 required for Rack 2.
266
+ - Ruby >= 2.3.8 (Ruby EOL).
266
267
  - Ruby >= 2.5.0 recommended.
267
268
  - TLS requires OpenSSL >= 1.1.0
268
269
  rubygems_version: 3.0.1