rage-iodine 1.7.58

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  3. data/.github/workflows/ruby.yml +42 -0
  4. data/.gitignore +20 -0
  5. data/.rspec +2 -0
  6. data/.yardopts +8 -0
  7. data/CHANGELOG.md +1098 -0
  8. data/Gemfile +11 -0
  9. data/LICENSE.txt +21 -0
  10. data/LIMITS.md +41 -0
  11. data/README.md +782 -0
  12. data/Rakefile +23 -0
  13. data/SPEC-PubSub-Draft.md +159 -0
  14. data/SPEC-WebSocket-Draft.md +239 -0
  15. data/bin/console +22 -0
  16. data/bin/info.md +353 -0
  17. data/bin/mustache_bench.rb +100 -0
  18. data/bin/poc/Gemfile.lock +23 -0
  19. data/bin/poc/README.md +37 -0
  20. data/bin/poc/config.ru +66 -0
  21. data/bin/poc/gemfile +1 -0
  22. data/bin/poc/www/index.html +57 -0
  23. data/examples/async_task.ru +92 -0
  24. data/examples/bates/README.md +3 -0
  25. data/examples/bates/config.ru +342 -0
  26. data/examples/bates/david+bold.pdf +0 -0
  27. data/examples/bates/public/drop-pdf.png +0 -0
  28. data/examples/bates/public/index.html +600 -0
  29. data/examples/config.ru +59 -0
  30. data/examples/echo.ru +59 -0
  31. data/examples/etag.ru +16 -0
  32. data/examples/hello.ru +29 -0
  33. data/examples/pubsub_engine.ru +81 -0
  34. data/examples/rack3.ru +12 -0
  35. data/examples/redis.ru +70 -0
  36. data/examples/shootout.ru +73 -0
  37. data/examples/sub-protocols.ru +90 -0
  38. data/examples/tcp_client.rb +66 -0
  39. data/examples/x-sendfile.ru +14 -0
  40. data/exe/iodine +280 -0
  41. data/ext/iodine/extconf.rb +110 -0
  42. data/ext/iodine/fio.c +12096 -0
  43. data/ext/iodine/fio.h +6390 -0
  44. data/ext/iodine/fio_cli.c +431 -0
  45. data/ext/iodine/fio_cli.h +189 -0
  46. data/ext/iodine/fio_json_parser.h +687 -0
  47. data/ext/iodine/fio_siphash.c +157 -0
  48. data/ext/iodine/fio_siphash.h +37 -0
  49. data/ext/iodine/fio_tls.h +129 -0
  50. data/ext/iodine/fio_tls_missing.c +649 -0
  51. data/ext/iodine/fio_tls_openssl.c +1056 -0
  52. data/ext/iodine/fio_tmpfile.h +50 -0
  53. data/ext/iodine/fiobj.h +44 -0
  54. data/ext/iodine/fiobj4fio.h +21 -0
  55. data/ext/iodine/fiobj_ary.c +333 -0
  56. data/ext/iodine/fiobj_ary.h +139 -0
  57. data/ext/iodine/fiobj_data.c +1185 -0
  58. data/ext/iodine/fiobj_data.h +167 -0
  59. data/ext/iodine/fiobj_hash.c +409 -0
  60. data/ext/iodine/fiobj_hash.h +176 -0
  61. data/ext/iodine/fiobj_json.c +622 -0
  62. data/ext/iodine/fiobj_json.h +68 -0
  63. data/ext/iodine/fiobj_mem.h +71 -0
  64. data/ext/iodine/fiobj_mustache.c +317 -0
  65. data/ext/iodine/fiobj_mustache.h +62 -0
  66. data/ext/iodine/fiobj_numbers.c +344 -0
  67. data/ext/iodine/fiobj_numbers.h +127 -0
  68. data/ext/iodine/fiobj_str.c +433 -0
  69. data/ext/iodine/fiobj_str.h +172 -0
  70. data/ext/iodine/fiobject.c +620 -0
  71. data/ext/iodine/fiobject.h +654 -0
  72. data/ext/iodine/hpack.h +1923 -0
  73. data/ext/iodine/http.c +2736 -0
  74. data/ext/iodine/http.h +1019 -0
  75. data/ext/iodine/http1.c +825 -0
  76. data/ext/iodine/http1.h +29 -0
  77. data/ext/iodine/http1_parser.h +1835 -0
  78. data/ext/iodine/http_internal.c +1279 -0
  79. data/ext/iodine/http_internal.h +248 -0
  80. data/ext/iodine/http_mime_parser.h +350 -0
  81. data/ext/iodine/iodine.c +1433 -0
  82. data/ext/iodine/iodine.h +64 -0
  83. data/ext/iodine/iodine_caller.c +218 -0
  84. data/ext/iodine/iodine_caller.h +27 -0
  85. data/ext/iodine/iodine_connection.c +941 -0
  86. data/ext/iodine/iodine_connection.h +55 -0
  87. data/ext/iodine/iodine_defer.c +420 -0
  88. data/ext/iodine/iodine_defer.h +6 -0
  89. data/ext/iodine/iodine_fiobj2rb.h +120 -0
  90. data/ext/iodine/iodine_helpers.c +282 -0
  91. data/ext/iodine/iodine_helpers.h +12 -0
  92. data/ext/iodine/iodine_http.c +1280 -0
  93. data/ext/iodine/iodine_http.h +23 -0
  94. data/ext/iodine/iodine_json.c +302 -0
  95. data/ext/iodine/iodine_json.h +6 -0
  96. data/ext/iodine/iodine_mustache.c +567 -0
  97. data/ext/iodine/iodine_mustache.h +6 -0
  98. data/ext/iodine/iodine_pubsub.c +580 -0
  99. data/ext/iodine/iodine_pubsub.h +26 -0
  100. data/ext/iodine/iodine_rack_io.c +273 -0
  101. data/ext/iodine/iodine_rack_io.h +20 -0
  102. data/ext/iodine/iodine_store.c +142 -0
  103. data/ext/iodine/iodine_store.h +20 -0
  104. data/ext/iodine/iodine_tcp.c +346 -0
  105. data/ext/iodine/iodine_tcp.h +13 -0
  106. data/ext/iodine/iodine_tls.c +261 -0
  107. data/ext/iodine/iodine_tls.h +13 -0
  108. data/ext/iodine/mustache_parser.h +1546 -0
  109. data/ext/iodine/redis_engine.c +957 -0
  110. data/ext/iodine/redis_engine.h +79 -0
  111. data/ext/iodine/resp_parser.h +317 -0
  112. data/ext/iodine/scheduler.c +173 -0
  113. data/ext/iodine/scheduler.h +6 -0
  114. data/ext/iodine/websocket_parser.h +506 -0
  115. data/ext/iodine/websockets.c +752 -0
  116. data/ext/iodine/websockets.h +185 -0
  117. data/iodine.gemspec +50 -0
  118. data/lib/iodine/connection.rb +61 -0
  119. data/lib/iodine/json.rb +42 -0
  120. data/lib/iodine/mustache.rb +113 -0
  121. data/lib/iodine/pubsub.rb +55 -0
  122. data/lib/iodine/rack_utils.rb +43 -0
  123. data/lib/iodine/tls.rb +16 -0
  124. data/lib/iodine/version.rb +3 -0
  125. data/lib/iodine.rb +274 -0
  126. data/lib/rack/handler/iodine.rb +33 -0
  127. data/logo.png +0 -0
  128. metadata +284 -0
@@ -0,0 +1,64 @@
1
+ #ifndef H_IODINE_H
2
+ #define H_IODINE_H
3
+
4
+ #include "ruby.h"
5
+
6
+ #include "fio.h"
7
+ #include "fio_tls.h"
8
+ #include "fiobj.h"
9
+ /* used for iodine_connect and iodine_listen routing */
10
+ typedef struct {
11
+ fio_str_info_s address;
12
+ fio_str_info_s port;
13
+ fio_str_info_s method;
14
+ fio_str_info_s path;
15
+ fio_str_info_s body;
16
+ fio_str_info_s public;
17
+ fio_str_info_s url;
18
+ #ifndef __MINGW32__
19
+ fio_tls_s *tls;
20
+ #endif
21
+ VALUE handler;
22
+ FIOBJ headers;
23
+ FIOBJ cookies;
24
+ size_t max_headers;
25
+ size_t max_body;
26
+ intptr_t max_clients;
27
+ size_t max_msg;
28
+ uint8_t timeout;
29
+ uint8_t ping;
30
+ uint8_t log;
31
+ enum {
32
+ IODINE_SERVICE_RAW,
33
+ IODINE_SERVICE_HTTP,
34
+ IODINE_SERVICE_WS,
35
+ } service;
36
+ } iodine_connection_args_s;
37
+
38
+ #include "iodine_caller.h"
39
+ #include "iodine_connection.h"
40
+ #include "iodine_defer.h"
41
+ #include "iodine_helpers.h"
42
+ #include "iodine_http.h"
43
+ #include "iodine_json.h"
44
+ #include "iodine_mustache.h"
45
+ #include "iodine_pubsub.h"
46
+ #include "iodine_rack_io.h"
47
+ #include "iodine_store.h"
48
+ #include "iodine_tcp.h"
49
+ #include "iodine_tls.h"
50
+ #include "scheduler.h"
51
+
52
+ /* *****************************************************************************
53
+ Constants
54
+ ***************************************************************************** */
55
+ extern VALUE IodineModule;
56
+ extern VALUE IodineBaseModule;
57
+ extern VALUE iodine_default_args;
58
+ extern ID iodine_call_id;
59
+ extern ID iodine_to_s_id;
60
+
61
+ #define IODINE_RSTRINFO(rstr) \
62
+ ((fio_str_info_s){.len = RSTRING_LEN(rstr), .data = RSTRING_PTR(rstr)})
63
+
64
+ #endif
@@ -0,0 +1,218 @@
1
+ #include "iodine_caller.h"
2
+
3
+ #include <ruby/thread.h>
4
+ #include <string.h>
5
+
6
+ #include <fio.h>
7
+
8
+ #include <pthread.h>
9
+
10
+ static pthread_key_t iodine_GVL_state_key;
11
+ static pthread_once_t iodine_GVL_state_once = PTHREAD_ONCE_INIT;
12
+ static void init_iodine_GVL_state_key(void) {
13
+ pthread_key_create(&iodine_GVL_state_key, NULL);
14
+ }
15
+ static void init_iodine_GVL_state_init(void) {
16
+ uint8_t *gvl = malloc(sizeof(uint8_t));
17
+ FIO_ASSERT_ALLOC(gvl);
18
+ *gvl = 1;
19
+ pthread_setspecific(iodine_GVL_state_key, gvl);
20
+ }
21
+
22
+ /* *****************************************************************************
23
+ Calling protected Ruby methods
24
+ ***************************************************************************** */
25
+
26
+ /* task container */
27
+ typedef struct {
28
+ VALUE obj;
29
+ int argc;
30
+ VALUE *argv;
31
+ ID method;
32
+ int exception;
33
+ VALUE (*protected_task)(VALUE tsk_);
34
+ VALUE (*each_func)(VALUE block_arg, VALUE data, int argc, VALUE *argv);
35
+ VALUE each_udata;
36
+ } iodine_rb_task_s;
37
+
38
+ /* printout backtrace in case of exceptions */
39
+ static void *iodine_handle_exception(void *ignr) {
40
+ (void)ignr;
41
+ VALUE exc = rb_errinfo();
42
+ if (exc != Qnil && rb_respond_to(exc, rb_intern("message")) &&
43
+ rb_respond_to(exc, rb_intern("backtrace"))) {
44
+ VALUE msg = rb_funcall2(exc, rb_intern("message"), 0, NULL);
45
+ VALUE exc_class = rb_class_name(CLASS_OF(exc));
46
+ VALUE bt = rb_funcall2(exc, rb_intern("backtrace"), 0, NULL);
47
+ if (TYPE(bt) == T_ARRAY) {
48
+ bt = rb_ary_join(bt, rb_str_new_literal("\n"));
49
+ FIO_LOG_ERROR("Iodine caught an unprotected exception - %.*s: %.*s\n%s",
50
+ (int)RSTRING_LEN(exc_class), RSTRING_PTR(exc_class),
51
+ (int)RSTRING_LEN(msg), RSTRING_PTR(msg),
52
+ StringValueCStr(bt));
53
+ } else {
54
+ FIO_LOG_ERROR("Iodine caught an unprotected exception - %.*s: %.*s\n"
55
+ "No backtrace available.\n",
56
+ (int)RSTRING_LEN(exc_class), RSTRING_PTR(exc_class),
57
+ (int)RSTRING_LEN(msg), RSTRING_PTR(msg));
58
+ }
59
+ rb_backtrace();
60
+ FIO_LOG_ERROR("\n");
61
+ rb_set_errinfo(Qnil);
62
+ } else if (exc != Qnil) {
63
+ FIO_LOG_ERROR(
64
+ "Iodine caught an unprotected exception - NO MESSAGE / DATA AVAILABLE");
65
+ }
66
+ return (void *)Qnil;
67
+ }
68
+
69
+ /* calls the Ruby each method within the protection block */
70
+ static VALUE iodine_ruby_caller_perform_block(VALUE tsk_) {
71
+ iodine_rb_task_s *task = (void *)tsk_;
72
+ return rb_block_call(task->obj, task->method, task->argc, task->argv,
73
+ task->each_func, task->each_udata);
74
+ }
75
+
76
+ /* calls the Ruby method within the protection block */
77
+ static VALUE iodine_ruby_caller_perform(VALUE tsk_) {
78
+ iodine_rb_task_s *task = (void *)tsk_;
79
+ return rb_funcall2(task->obj, task->method, task->argc, task->argv);
80
+ }
81
+
82
+ /* wrap the function call in exception handling block (uses longjmp) */
83
+ static void *iodine_protect_ruby_call(void *task_) {
84
+ int state = 0;
85
+ VALUE ret = rb_protect(((iodine_rb_task_s *)task_)->protected_task,
86
+ (VALUE)(task_), &state);
87
+ if (state) {
88
+ iodine_handle_exception(NULL);
89
+ }
90
+ return (void *)ret;
91
+ }
92
+
93
+ /* *****************************************************************************
94
+ API
95
+ ***************************************************************************** */
96
+
97
+ /** Calls a C function within the GVL. */
98
+ static void *iodine_enterGVL(void *(*func)(void *), void *arg) {
99
+ pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
100
+ uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
101
+ if (!iodine_GVL_state) {
102
+ init_iodine_GVL_state_init();
103
+ iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
104
+ }
105
+ if (*iodine_GVL_state) {
106
+ return func(arg);
107
+ }
108
+ void *rv = NULL;
109
+ *iodine_GVL_state = 1;
110
+ rv = rb_thread_call_with_gvl(func, arg);
111
+ *iodine_GVL_state = 0;
112
+ return rv;
113
+ }
114
+
115
+ /** Calls a C function outside the GVL. */
116
+ static void *iodine_leaveGVL(void *(*func)(void *), void *arg) {
117
+ pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
118
+ uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
119
+ if (!iodine_GVL_state) {
120
+ init_iodine_GVL_state_init();
121
+ iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
122
+ }
123
+ if (!*iodine_GVL_state) {
124
+ return func(arg);
125
+ }
126
+ void *rv = NULL;
127
+ *iodine_GVL_state = 0;
128
+ rv = rb_thread_call_without_gvl(func, arg, NULL, NULL);
129
+ *iodine_GVL_state = 1;
130
+ return rv;
131
+ }
132
+
133
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
134
+ static VALUE iodine_call(VALUE obj, ID method) {
135
+ iodine_rb_task_s task = {
136
+ .obj = obj,
137
+ .argc = 0,
138
+ .argv = NULL,
139
+ .method = method,
140
+ .protected_task = iodine_ruby_caller_perform,
141
+ };
142
+ void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
143
+ return (VALUE)rv;
144
+ }
145
+
146
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
147
+ static VALUE iodine_call2(VALUE obj, ID method, int argc, VALUE *argv) {
148
+ iodine_rb_task_s task = {
149
+ .obj = obj,
150
+ .argc = argc,
151
+ .argv = argv,
152
+ .method = method,
153
+ .protected_task = iodine_ruby_caller_perform,
154
+ };
155
+ void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
156
+ return (VALUE)rv;
157
+ }
158
+
159
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
160
+ static VALUE iodine_call_block(VALUE obj, ID method, int argc, VALUE *argv,
161
+ VALUE udata,
162
+ VALUE(each_func)(VALUE block_arg, VALUE udata,
163
+ int argc, VALUE *argv)) {
164
+ iodine_rb_task_s task = {
165
+ .obj = obj,
166
+ .argc = argc,
167
+ .argv = argv,
168
+ .method = method,
169
+ .protected_task = iodine_ruby_caller_perform_block,
170
+ .each_func = each_func,
171
+ .each_udata = udata,
172
+ };
173
+ void *rv = iodine_enterGVL(iodine_protect_ruby_call, &task);
174
+ return (VALUE)rv;
175
+ }
176
+
177
+ /** Returns the GVL state flag. */
178
+ static uint8_t iodine_in_GVL(void) {
179
+ pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
180
+ uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
181
+ if (!iodine_GVL_state) {
182
+ init_iodine_GVL_state_init();
183
+ iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
184
+ }
185
+ return *iodine_GVL_state;
186
+ }
187
+
188
+ /** Forces the GVL state flag. */
189
+ static void iodine_set_GVL(uint8_t state) {
190
+ pthread_once(&iodine_GVL_state_once, init_iodine_GVL_state_key);
191
+ uint8_t *iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
192
+ if (!iodine_GVL_state) {
193
+ init_iodine_GVL_state_init();
194
+ iodine_GVL_state = pthread_getspecific(iodine_GVL_state_key);
195
+ }
196
+ *iodine_GVL_state = state;
197
+ }
198
+
199
+ /* *****************************************************************************
200
+ Caller Initialization
201
+ ***************************************************************************** */
202
+
203
+ struct IodineCaller_s IodineCaller = {
204
+ /** Calls a C function within the GVL. */
205
+ .enterGVL = iodine_enterGVL,
206
+ /** Calls a C function outside the GVL. */
207
+ .leaveGVL = iodine_leaveGVL,
208
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
209
+ .call_with_block = iodine_call_block,
210
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
211
+ .call = iodine_call,
212
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
213
+ .call2 = iodine_call2,
214
+ /** Returns the GVL state flag. */
215
+ .in_GVL = iodine_in_GVL,
216
+ /** Forces the GVL state flag. */
217
+ .set_GVL = iodine_set_GVL,
218
+ };
@@ -0,0 +1,27 @@
1
+ #ifndef H_IODINE_CALLER_H
2
+ #define H_IODINE_CALLER_H
3
+
4
+ #include "ruby.h"
5
+
6
+ #include <stdint.h>
7
+
8
+ extern struct IodineCaller_s {
9
+ /** Calls a C function within the GVL (unprotected). */
10
+ void *(*enterGVL)(void *(*func)(void *), void *arg);
11
+ /** Calls a C function outside the GVL (no Ruby API calls allowed). */
12
+ void *(*leaveGVL)(void *(*func)(void *), void *arg);
13
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
14
+ VALUE (*call)(VALUE obj, ID method);
15
+ /** Calls a Ruby method on a given object, protecting against exceptions. */
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));
21
+ /** Returns the GVL state flag. */
22
+ uint8_t (*in_GVL)(void);
23
+ /** Forces the GVL state flag. */
24
+ void (*set_GVL)(uint8_t state);
25
+ } IodineCaller;
26
+
27
+ #endif