iodine 0.7.27 → 0.7.28

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 271062484b7941686926625d08f09463c7f723a94c9a43b1ef9a3b85c2b0e2e2
4
- data.tar.gz: 7914c3a6e093c53bc2ff78ed1f6bc0f376d5dcb69bb2086187238fc9666894eb
3
+ metadata.gz: b76690963cd5e669bee41bd2859f60164c3a9ce4dbcc56706864fe05ce5db049
4
+ data.tar.gz: cebe9da9b5206d2229e1ecefac594c26ffb548e0ff25aefba5429f0724e8a97f
5
5
  SHA512:
6
- metadata.gz: 9ef504553715d08e8152e2a5195368965bdb71c9d6d52157a4796c58cb5533527008d29fa7fb03788df89f3a3c80db4210b4721b062291f0993529aae26f1347
7
- data.tar.gz: f7afb8f4c3a0fbe19e396798f917d2c3d039d8ff318b43be2c059b73ec8cb079c80f1d4daa777aafc7206360aee2373d767c3e1089676ffbc70226c6b294681f
6
+ metadata.gz: d9799ff98973047f253fafedcb3f5dc70b2e7f04409c0eb415093e1d984eea3996f6b2cd7ee2dc87fbdacd94653a95299857f4bae5146188c91e9a656add6b36
7
+ data.tar.gz: f422ac357af80a1a60a5ffe4940cf25afce4132aae41aae9f94048f8e6250e43b1d0aca09bedf4f9dbc1e7f733f5b7c6c3fab12d5fe4ef6cbaa48d4923196554
data/CHANGELOG.md CHANGED
@@ -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.28
10
+
11
+ **Fix**: fixed an issue where iodine would crush (or hang) if unprotected exceptions were raised within a response body's `each` loop. This also fixes Fiber support when streaming with Roda (note: iodine will concat the body in a buffer before sending it). Credit to @adam12 (Adam Daniels) both for exposing the issue (#70) and testing possible solutions.
12
+
9
13
  #### Change log v.0.7.27
10
14
 
11
15
  **Compatibility**: (`iodine`) fixed the HTTP request `SCRIPT_NAME` variable (in the Rack `env`) to default to the global environment variable `SCRIPT_NAME` when `SCRIPT_NAME` isn't root (`/`). Credit to @thexa4 (Max Maton) for exposing this compatibility concern (issue #68).
data/README.md CHANGED
@@ -36,6 +36,8 @@ Iodine is an **evented** framework with a simple API that ports much of the [C f
36
36
 
37
37
  Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but CI tests start at Ruby 2.2.2.
38
38
 
39
+ **Note**: iodine does **not** support the streaming when using Rack. Streaming over Rack should be avoided on any server, WebSockets, SSE and `Range` requests should always be preferred. On iodine no data will be sent before the whole of the data is available.
40
+
39
41
  ## Iodine - a fast & powerful HTTP + Websockets server with native Pub/Sub
40
42
 
41
43
  Iodine includes a light and fast HTTP and Websocket server written in C that was written according to the [Rack interface specifications](http://www.rubydoc.info/github/rack/rack/master/file/SPEC) and the [Websocket draft extension](./SPEC-Websocket-Draft.md).
data/ext/iodine/fio.h CHANGED
@@ -423,35 +423,43 @@ Logging and testing helpers
423
423
  #define FIO_LOG_LEVEL_DEBUG 5
424
424
 
425
425
  #if FIO_LOG_LENGTH_LIMIT > 128
426
- #define FIO_LOG_LENGTH_ON_STACK FIO_LOG_LENGTH_LIMIT
427
- #define FIO_LOG_LENGTH_BORDER (FIO_LOG_LENGTH_LIMIT - 32)
426
+ #define FIO_LOG____LENGTH_ON_STACK FIO_LOG_LENGTH_LIMIT
427
+ #define FIO_LOG____LENGTH_BORDER (FIO_LOG_LENGTH_LIMIT - 32)
428
428
  #else
429
- #define FIO_LOG_LENGTH_ON_STACK (FIO_LOG_LENGTH_LIMIT + 32)
430
- #define FIO_LOG_LENGTH_BORDER FIO_LOG_LENGTH_LIMIT
429
+ #define FIO_LOG____LENGTH_ON_STACK (FIO_LOG_LENGTH_LIMIT + 32)
430
+ #define FIO_LOG____LENGTH_BORDER FIO_LOG_LENGTH_LIMIT
431
431
  #endif
432
432
  /** The logging level */
433
433
  int __attribute__((weak)) FIO_LOG_LEVEL;
434
434
 
435
+ #pragma weak FIO_LOG2STDERR
436
+ void __attribute__((format(printf, 1, 0), weak))
437
+ FIO_LOG2STDERR(const char *format, ...) {
438
+ char tmp___log[FIO_LOG____LENGTH_ON_STACK];
439
+ va_list argv;
440
+ va_start(argv, format);
441
+ int len___log = vsnprintf(tmp___log, FIO_LOG_LENGTH_LIMIT - 2, format, argv);
442
+ va_end(argv);
443
+ if (len___log <= 0 || len___log >= FIO_LOG_LENGTH_LIMIT - 2) {
444
+ if (len___log >= FIO_LOG_LENGTH_LIMIT - 2) {
445
+ memcpy(tmp___log + FIO_LOG____LENGTH_BORDER, "... (warning: truncated).",
446
+ 25);
447
+ len___log = FIO_LOG____LENGTH_BORDER + 25;
448
+ } else {
449
+ fwrite("ERROR: log output error (can't write).\n", 39, 1, stderr);
450
+ return;
451
+ }
452
+ }
453
+ tmp___log[len___log++] = '\n';
454
+ tmp___log[len___log] = '0';
455
+ fwrite(tmp___log, len___log, 1, stderr);
456
+ }
457
+
435
458
  #ifndef FIO_LOG_PRINT
436
459
  #define FIO_LOG_PRINT(level, ...) \
437
460
  do { \
438
461
  if (level <= FIO_LOG_LEVEL) { \
439
- char tmp___log[FIO_LOG_LENGTH_ON_STACK]; \
440
- int len___log = \
441
- snprintf(tmp___log, FIO_LOG_LENGTH_LIMIT - 2, __VA_ARGS__); \
442
- if (len___log <= 0 || len___log >= FIO_LOG_LENGTH_LIMIT - 2) { \
443
- if (len___log >= FIO_LOG_LENGTH_LIMIT - 2) { \
444
- memcpy(tmp___log + FIO_LOG_LENGTH_BORDER, \
445
- "... (warning: truncated).", 25); \
446
- len___log = FIO_LOG_LENGTH_BORDER + 25; \
447
- } else { \
448
- fwrite("ERROR: log output error (can't write).\n", 39, 1, stderr); \
449
- break; \
450
- } \
451
- } \
452
- tmp___log[len___log++] = '\n'; \
453
- tmp___log[len___log] = '0'; \
454
- fwrite(tmp___log, len___log, 1, stderr); \
462
+ FIO_LOG2STDERR(__VA_ARGS__); \
455
463
  } \
456
464
  } while (0)
457
465
  #define FIO_LOG_DEBUG(...) \
@@ -18,6 +18,9 @@ typedef struct {
18
18
  VALUE *argv;
19
19
  ID method;
20
20
  int exception;
21
+ VALUE (*protected_task)(VALUE tsk_);
22
+ VALUE (*each_func)(VALUE block_arg, VALUE data, int argc, VALUE *argv);
23
+ VALUE each_udata;
21
24
  } iodine_rb_task_s;
22
25
 
23
26
  /* printout backtrace in case of exceptions */
@@ -47,6 +50,13 @@ static void *iodine_handle_exception(void *ignr) {
47
50
  return (void *)Qnil;
48
51
  }
49
52
 
53
+ /* calls the Ruby each method within the protection block */
54
+ static VALUE iodine_ruby_caller_perform_block(VALUE tsk_) {
55
+ iodine_rb_task_s *task = (void *)tsk_;
56
+ return rb_block_call(task->obj, task->method, task->argc, task->argv,
57
+ task->each_func, task->each_udata);
58
+ }
59
+
50
60
  /* calls the Ruby method within the protection block */
51
61
  static VALUE iodine_ruby_caller_perform(VALUE tsk_) {
52
62
  iodine_rb_task_s *task = (void *)tsk_;
@@ -56,7 +66,8 @@ static VALUE iodine_ruby_caller_perform(VALUE tsk_) {
56
66
  /* wrap the function call in exception handling block (uses longjmp) */
57
67
  static void *iodine_protect_ruby_call(void *task_) {
58
68
  int state = 0;
59
- VALUE ret = rb_protect(iodine_ruby_caller_perform, (VALUE)(task_), &state);
69
+ VALUE ret = rb_protect(((iodine_rb_task_s *)task_)->protected_task,
70
+ (VALUE)(task_), &state);
60
71
  if (state) {
61
72
  iodine_handle_exception(NULL);
62
73
  }
@@ -98,6 +109,7 @@ static VALUE iodine_call(VALUE obj, ID method) {
98
109
  .argc = 0,
99
110
  .argv = NULL,
100
111
  .method = method,
112
+ .protected_task = iodine_ruby_caller_perform,
101
113
  };
102
114
  void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
103
115
  return (VALUE)rv;
@@ -110,6 +122,25 @@ static VALUE iodine_call2(VALUE obj, ID method, int argc, VALUE *argv) {
110
122
  .argc = argc,
111
123
  .argv = argv,
112
124
  .method = method,
125
+ .protected_task = iodine_ruby_caller_perform,
126
+ };
127
+ void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
128
+ return (VALUE)rv;
129
+ }
130
+
131
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
132
+ static VALUE iodine_call_block(VALUE obj, ID method, int argc, VALUE *argv,
133
+ VALUE udata,
134
+ VALUE(each_func)(VALUE block_arg, VALUE udata,
135
+ int argc, VALUE *argv)) {
136
+ iodine_rb_task_s task = {
137
+ .obj = obj,
138
+ .argc = argc,
139
+ .argv = argv,
140
+ .method = method,
141
+ .protected_task = iodine_ruby_caller_perform_block,
142
+ .each_func = each_func,
143
+ .each_udata = udata,
113
144
  };
114
145
  void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
115
146
  return (VALUE)rv;
@@ -131,6 +162,8 @@ struct IodineCaller_s IodineCaller = {
131
162
  /** Calls a C function outside the GVL. */
132
163
  .leaveGVL = iodine_leaveGVL,
133
164
  /** Calls a Ruby method on a given object, protecting against exceptions. */
165
+ .call_with_block = iodine_call_block,
166
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
134
167
  .call = iodine_call,
135
168
  /** Calls a Ruby method on a given object, protecting against exceptions. */
136
169
  .call2 = iodine_call2,
@@ -14,6 +14,10 @@ extern struct IodineCaller_s {
14
14
  VALUE (*call)(VALUE obj, ID method);
15
15
  /** Calls a Ruby method on a given object, protecting against exceptions. */
16
16
  VALUE (*call2)(VALUE obj, ID method, int argc, VALUE *argv);
17
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
18
+ VALUE(*call_with_block)
19
+ (VALUE obj, ID method, int argc, VALUE *argv, VALUE udata,
20
+ VALUE (*block_func)(VALUE block_argv1, VALUE udata, int argc, VALUE *argv));
17
21
  /** Returns the GVL state flag. */
18
22
  uint8_t (*in_GVL)(void);
19
23
  /** Forces the GVL state flag. */
@@ -414,4 +414,6 @@ void iodine_defer_initialize(void) {
414
414
  fio_state_callback_add(FIO_CALL_ON_START, iodine_start_io_thread, NULL);
415
415
  /* stop the IO thread before exit */
416
416
  fio_state_callback_add(FIO_CALL_ON_FINISH, iodine_defer_on_finish, NULL);
417
+ /* kill IO thread even after a non-graceful iodine shutdown (force-quit) */
418
+ fio_state_callback_add(FIO_CALL_AT_EXIT, iodine_defer_on_finish, NULL);
417
419
  }
@@ -514,7 +514,8 @@ static int for_each_header_data(VALUE key, VALUE val, VALUE h_) {
514
514
  }
515
515
 
516
516
  // writes the body to the response object
517
- static VALUE for_each_body_string(VALUE str, VALUE body_) {
517
+ static VALUE for_each_body_string(VALUE str, VALUE body_, int argc,
518
+ VALUE *argv) {
518
519
  // fprintf(stderr, "For_each - body\n");
519
520
  // write body
520
521
  if (TYPE(str) != T_STRING) {
@@ -525,6 +526,8 @@ static VALUE for_each_body_string(VALUE str, VALUE body_) {
525
526
  fiobj_str_write((FIOBJ)body_, RSTRING_PTR(str), RSTRING_LEN(str));
526
527
  }
527
528
  return Qtrue;
529
+ (void)argc;
530
+ (void)argv;
528
531
  }
529
532
 
530
533
  static inline int ruby2c_response_send(iodine_http_request_handle_s *handle,
@@ -559,8 +562,8 @@ static inline int ruby2c_response_send(iodine_http_request_handle_s *handle,
559
562
  // fprintf(stderr, "Review body as for-each ...\n");
560
563
  handle->body = fiobj_str_buf(1);
561
564
  handle->type = IODINE_HTTP_SENDBODY;
562
- rb_block_call(body, each_method_id, 0, NULL, for_each_body_string,
563
- (VALUE)handle->body);
565
+ IodineCaller.call_with_block(body, each_method_id, 0, NULL,
566
+ (VALUE)handle->body, for_each_body_string);
564
567
  // we need to call `close` in case the object is an IO / BodyProxy
565
568
  if (rb_respond_to(body, close_method_id))
566
569
  IodineCaller.call(body, close_method_id);
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.7.27'.freeze
2
+ VERSION = '0.7.28'.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.27
4
+ version: 0.7.28
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-03-20 00:00:00.000000000 Z
11
+ date: 2019-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -202,7 +202,7 @@ licenses:
202
202
  - MIT
203
203
  metadata:
204
204
  allowed_push_host: https://rubygems.org
205
- post_install_message: 'Thank you for installing Iodine 0.7.27.
205
+ post_install_message: 'Thank you for installing Iodine 0.7.28.
206
206
 
207
207
  '
208
208
  rdoc_options: []