rage-iodine 1.7.58
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- data/.github/workflows/ruby.yml +42 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.yardopts +8 -0
- data/CHANGELOG.md +1098 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/LIMITS.md +41 -0
- data/README.md +782 -0
- data/Rakefile +23 -0
- data/SPEC-PubSub-Draft.md +159 -0
- data/SPEC-WebSocket-Draft.md +239 -0
- data/bin/console +22 -0
- data/bin/info.md +353 -0
- data/bin/mustache_bench.rb +100 -0
- data/bin/poc/Gemfile.lock +23 -0
- data/bin/poc/README.md +37 -0
- data/bin/poc/config.ru +66 -0
- data/bin/poc/gemfile +1 -0
- data/bin/poc/www/index.html +57 -0
- data/examples/async_task.ru +92 -0
- data/examples/bates/README.md +3 -0
- data/examples/bates/config.ru +342 -0
- data/examples/bates/david+bold.pdf +0 -0
- data/examples/bates/public/drop-pdf.png +0 -0
- data/examples/bates/public/index.html +600 -0
- data/examples/config.ru +59 -0
- data/examples/echo.ru +59 -0
- data/examples/etag.ru +16 -0
- data/examples/hello.ru +29 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/rack3.ru +12 -0
- data/examples/redis.ru +70 -0
- data/examples/shootout.ru +73 -0
- data/examples/sub-protocols.ru +90 -0
- data/examples/tcp_client.rb +66 -0
- data/examples/x-sendfile.ru +14 -0
- data/exe/iodine +280 -0
- data/ext/iodine/extconf.rb +110 -0
- data/ext/iodine/fio.c +12096 -0
- data/ext/iodine/fio.h +6390 -0
- data/ext/iodine/fio_cli.c +431 -0
- data/ext/iodine/fio_cli.h +189 -0
- data/ext/iodine/fio_json_parser.h +687 -0
- data/ext/iodine/fio_siphash.c +157 -0
- data/ext/iodine/fio_siphash.h +37 -0
- data/ext/iodine/fio_tls.h +129 -0
- data/ext/iodine/fio_tls_missing.c +649 -0
- data/ext/iodine/fio_tls_openssl.c +1056 -0
- data/ext/iodine/fio_tmpfile.h +50 -0
- data/ext/iodine/fiobj.h +44 -0
- data/ext/iodine/fiobj4fio.h +21 -0
- data/ext/iodine/fiobj_ary.c +333 -0
- data/ext/iodine/fiobj_ary.h +139 -0
- data/ext/iodine/fiobj_data.c +1185 -0
- data/ext/iodine/fiobj_data.h +167 -0
- data/ext/iodine/fiobj_hash.c +409 -0
- data/ext/iodine/fiobj_hash.h +176 -0
- data/ext/iodine/fiobj_json.c +622 -0
- data/ext/iodine/fiobj_json.h +68 -0
- data/ext/iodine/fiobj_mem.h +71 -0
- data/ext/iodine/fiobj_mustache.c +317 -0
- data/ext/iodine/fiobj_mustache.h +62 -0
- data/ext/iodine/fiobj_numbers.c +344 -0
- data/ext/iodine/fiobj_numbers.h +127 -0
- data/ext/iodine/fiobj_str.c +433 -0
- data/ext/iodine/fiobj_str.h +172 -0
- data/ext/iodine/fiobject.c +620 -0
- data/ext/iodine/fiobject.h +654 -0
- data/ext/iodine/hpack.h +1923 -0
- data/ext/iodine/http.c +2736 -0
- data/ext/iodine/http.h +1019 -0
- data/ext/iodine/http1.c +825 -0
- data/ext/iodine/http1.h +29 -0
- data/ext/iodine/http1_parser.h +1835 -0
- data/ext/iodine/http_internal.c +1279 -0
- data/ext/iodine/http_internal.h +248 -0
- data/ext/iodine/http_mime_parser.h +350 -0
- data/ext/iodine/iodine.c +1433 -0
- data/ext/iodine/iodine.h +64 -0
- data/ext/iodine/iodine_caller.c +218 -0
- data/ext/iodine/iodine_caller.h +27 -0
- data/ext/iodine/iodine_connection.c +941 -0
- data/ext/iodine/iodine_connection.h +55 -0
- data/ext/iodine/iodine_defer.c +420 -0
- data/ext/iodine/iodine_defer.h +6 -0
- data/ext/iodine/iodine_fiobj2rb.h +120 -0
- data/ext/iodine/iodine_helpers.c +282 -0
- data/ext/iodine/iodine_helpers.h +12 -0
- data/ext/iodine/iodine_http.c +1280 -0
- data/ext/iodine/iodine_http.h +23 -0
- data/ext/iodine/iodine_json.c +302 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_mustache.c +567 -0
- data/ext/iodine/iodine_mustache.h +6 -0
- data/ext/iodine/iodine_pubsub.c +580 -0
- data/ext/iodine/iodine_pubsub.h +26 -0
- data/ext/iodine/iodine_rack_io.c +273 -0
- data/ext/iodine/iodine_rack_io.h +20 -0
- data/ext/iodine/iodine_store.c +142 -0
- data/ext/iodine/iodine_store.h +20 -0
- data/ext/iodine/iodine_tcp.c +346 -0
- data/ext/iodine/iodine_tcp.h +13 -0
- data/ext/iodine/iodine_tls.c +261 -0
- data/ext/iodine/iodine_tls.h +13 -0
- data/ext/iodine/mustache_parser.h +1546 -0
- data/ext/iodine/redis_engine.c +957 -0
- data/ext/iodine/redis_engine.h +79 -0
- data/ext/iodine/resp_parser.h +317 -0
- data/ext/iodine/scheduler.c +173 -0
- data/ext/iodine/scheduler.h +6 -0
- data/ext/iodine/websocket_parser.h +506 -0
- data/ext/iodine/websockets.c +752 -0
- data/ext/iodine/websockets.h +185 -0
- data/iodine.gemspec +50 -0
- data/lib/iodine/connection.rb +61 -0
- data/lib/iodine/json.rb +42 -0
- data/lib/iodine/mustache.rb +113 -0
- data/lib/iodine/pubsub.rb +55 -0
- data/lib/iodine/rack_utils.rb +43 -0
- data/lib/iodine/tls.rb +16 -0
- data/lib/iodine/version.rb +3 -0
- data/lib/iodine.rb +274 -0
- data/lib/rack/handler/iodine.rb +33 -0
- data/logo.png +0 -0
- metadata +284 -0
data/ext/iodine/iodine.h
ADDED
@@ -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
|