agoo 2.15.7 → 2.15.9
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 +4 -4
- data/CHANGELOG.md +18 -0
- data/bin/agoo +47 -39
- data/ext/agoo/bind.c +209 -198
- data/ext/agoo/con.c +19 -9
- data/ext/agoo/con.h +2 -0
- data/ext/agoo/req.c +7 -0
- data/ext/agoo/req.h +2 -0
- data/ext/agoo/request.c +29 -0
- data/ext/agoo/rgraphql.c +7 -4
- data/ext/agoo/rserver.c +714 -688
- data/ext/agoo/rserver.h +1 -0
- data/ext/agoo/server.c +255 -253
- data/lib/agoo/version.rb +1 -1
- data/lib/agoo.rb +1 -0
- data/lib/rack/handler/agoo.rb +138 -130
- metadata +2 -2
data/ext/agoo/rserver.c
CHANGED
@@ -35,64 +35,64 @@
|
|
35
35
|
#include "upgraded.h"
|
36
36
|
#include "websocket.h"
|
37
37
|
|
38
|
-
extern void
|
39
|
-
extern sig_atomic_t
|
38
|
+
extern void agoo_shutdown();
|
39
|
+
extern sig_atomic_t agoo_stop;
|
40
40
|
|
41
|
-
static VALUE
|
41
|
+
static VALUE server_mod = Qundef;
|
42
42
|
|
43
|
-
static VALUE
|
44
|
-
static VALUE
|
45
|
-
static VALUE
|
46
|
-
static VALUE
|
47
|
-
static VALUE
|
48
|
-
static VALUE
|
49
|
-
static VALUE
|
50
|
-
static VALUE
|
51
|
-
static VALUE
|
43
|
+
static VALUE connect_sym;
|
44
|
+
static VALUE delete_sym;
|
45
|
+
static VALUE get_sym;
|
46
|
+
static VALUE head_sym;
|
47
|
+
static VALUE options_sym;
|
48
|
+
static VALUE post_sym;
|
49
|
+
static VALUE push_env_key;
|
50
|
+
static VALUE put_sym;
|
51
|
+
static VALUE patch_sym;
|
52
52
|
|
53
|
-
static VALUE
|
53
|
+
static VALUE rserver;
|
54
54
|
|
55
|
-
static ID
|
56
|
-
static ID
|
57
|
-
static ID
|
58
|
-
static ID
|
59
|
-
static ID
|
60
|
-
static ID
|
61
|
-
static ID
|
62
|
-
static ID
|
55
|
+
static ID call_id;
|
56
|
+
static ID each_id;
|
57
|
+
static ID on_close_id;
|
58
|
+
static ID on_drained_id;
|
59
|
+
static ID on_error_id;
|
60
|
+
static ID on_message_id;
|
61
|
+
static ID on_request_id;
|
62
|
+
static ID to_i_id;
|
63
63
|
|
64
|
-
static const char
|
64
|
+
static const char err500[] = "HTTP/1.1 500 Internal Server Error\r\n";
|
65
65
|
|
66
|
-
static double
|
67
|
-
struct _rServer
|
66
|
+
static double poll_timeout = 0.1;
|
67
|
+
struct _rServer the_rserver = {};
|
68
68
|
|
69
69
|
static void
|
70
70
|
server_mark(void *ptr) {
|
71
|
-
agooUpgraded
|
71
|
+
agooUpgraded up;
|
72
72
|
|
73
73
|
rb_gc_mark(rserver);
|
74
74
|
pthread_mutex_lock(&agoo_server.up_lock);
|
75
75
|
for (up = agoo_server.up_list; NULL != up; up = up->next) {
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
76
|
+
if (Qnil != (VALUE)up->ctx) {
|
77
|
+
rb_gc_mark((VALUE)up->ctx);
|
78
|
+
}
|
79
|
+
if (Qnil != (VALUE)up->env) {
|
80
|
+
rb_gc_mark((VALUE)up->env);
|
81
|
+
}
|
82
|
+
if (Qnil != (VALUE)up->wrap) {
|
83
|
+
rb_gc_mark((VALUE)up->wrap);
|
84
|
+
}
|
85
85
|
}
|
86
86
|
pthread_mutex_unlock(&agoo_server.up_lock);
|
87
87
|
}
|
88
88
|
|
89
89
|
static void
|
90
90
|
url_bind(VALUE rurl) {
|
91
|
-
struct _agooErr
|
92
|
-
agooBind
|
91
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
92
|
+
agooBind b = agoo_bind_url(&err, StringValuePtr(rurl));
|
93
93
|
|
94
94
|
if (AGOO_ERR_OK != err.code) {
|
95
|
-
|
95
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
96
96
|
}
|
97
97
|
agoo_server_bind(b);
|
98
98
|
}
|
@@ -100,10 +100,11 @@ url_bind(VALUE rurl) {
|
|
100
100
|
static int
|
101
101
|
configure(agooErr err, int port, const char *root, VALUE options) {
|
102
102
|
if (AGOO_ERR_OK != agoo_pages_set_root(err, root)) {
|
103
|
-
|
103
|
+
return err->code;
|
104
104
|
}
|
105
105
|
agoo_server.thread_cnt = 0;
|
106
106
|
the_rserver.worker_cnt = 1;
|
107
|
+
the_rserver.forker = Qnil;
|
107
108
|
the_rserver.uses = NULL;
|
108
109
|
atomic_init(&agoo_server.running, 0);
|
109
110
|
agoo_server.listen_thread = 0;
|
@@ -112,165 +113,176 @@ configure(agooErr err, int port, const char *root, VALUE options) {
|
|
112
113
|
agoo_server.binds = NULL;
|
113
114
|
|
114
115
|
if (Qnil != options) {
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
116
|
+
VALUE v;
|
117
|
+
|
118
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("thread_count"))))) {
|
119
|
+
int tc = FIX2INT(v);
|
120
|
+
|
121
|
+
if (1 <= tc || tc < 1000) {
|
122
|
+
agoo_server.thread_cnt = tc;
|
123
|
+
} else {
|
124
|
+
rb_raise(rb_eArgError, "thread_count must be between 1 and 1000.");
|
125
|
+
}
|
126
|
+
}
|
127
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("worker_count"))))) {
|
128
|
+
int wc = FIX2INT(v);
|
129
|
+
|
130
|
+
if (1 <= wc || wc < MAX_WORKERS) {
|
131
|
+
the_rserver.worker_cnt = wc;
|
132
|
+
} else {
|
133
|
+
rb_raise(rb_eArgError, "thread_count must be between 1 and %d.", MAX_WORKERS);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
the_rserver.forker = rb_hash_lookup(options, ID2SYM(rb_intern("fork_wrap")));
|
137
|
+
|
138
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("poll_timeout"))))) {
|
139
|
+
double timeout = rb_num2dbl(v);
|
140
|
+
|
141
|
+
if (0.0001 <= timeout || timeout < 1.0) {
|
142
|
+
poll_timeout = timeout;
|
143
|
+
} else {
|
144
|
+
rb_raise(rb_eArgError, "poll_timeout must be between 0.0001 and 1.0.");
|
145
|
+
}
|
146
|
+
}
|
147
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("connection_timeout"))))) {
|
148
|
+
double timeout = rb_num2dbl(v);
|
149
|
+
|
150
|
+
if (0.1 <= timeout) {
|
151
|
+
con_timeout = timeout;
|
152
|
+
} else {
|
153
|
+
rb_raise(rb_eArgError, "connection_timeout must be greater than 0.1 seconds.");
|
154
|
+
}
|
155
|
+
}
|
156
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("max_push_pending"))))) {
|
157
|
+
int mpp = FIX2INT(v);
|
158
|
+
|
159
|
+
if (0 <= mpp || mpp < 1000) {
|
160
|
+
agoo_server.max_push_pending = mpp;
|
161
|
+
} else {
|
162
|
+
rb_raise(rb_eArgError, "max_push_pending must be between 0 and 1000.");
|
163
|
+
}
|
164
|
+
}
|
165
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("pedantic"))))) {
|
166
|
+
agoo_server.pedantic = (Qtrue == v);
|
167
|
+
}
|
168
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("root_first"))))) {
|
169
|
+
agoo_server.root_first = (Qtrue == v);
|
170
|
+
}
|
171
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("Port"))))) {
|
172
|
+
if (rb_cInteger == rb_obj_class(v)) {
|
173
|
+
port = NUM2INT(v);
|
174
|
+
} else {
|
175
|
+
switch (rb_type(v)) {
|
176
|
+
case T_STRING:
|
177
|
+
port = atoi(StringValuePtr(v));
|
178
|
+
break;
|
179
|
+
case T_FIXNUM:
|
180
|
+
port = NUM2INT(v);
|
181
|
+
break;
|
182
|
+
default:
|
183
|
+
break;
|
184
|
+
}
|
185
|
+
}
|
186
|
+
}
|
187
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("ssl_cert"))))) {
|
188
|
+
rb_check_type(v, T_STRING);
|
189
|
+
const char *cert =StringValuePtr(v);
|
190
|
+
|
191
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("ssl_key"))))) {
|
192
|
+
rb_check_type(v, T_STRING);
|
193
|
+
const char *key =StringValuePtr(v);
|
194
|
+
|
195
|
+
if (AGOO_ERR_OK != agoo_server_ssl_init(err, cert, key)) {
|
196
|
+
rb_raise(rb_eArgError, "%s", err->msg);
|
197
|
+
}
|
198
|
+
} else {
|
199
|
+
rb_raise(rb_eArgError, "An ssl_key must be provided if an ssl_cert was provided.");
|
200
|
+
}
|
201
|
+
}
|
202
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("bind"))))) {
|
203
|
+
int len;
|
204
|
+
int i;
|
205
|
+
|
206
|
+
switch (rb_type(v)) {
|
207
|
+
case T_STRING:
|
208
|
+
url_bind(v);
|
209
|
+
break;
|
210
|
+
case T_ARRAY:
|
211
|
+
len = (int)RARRAY_LEN(v);
|
212
|
+
for (i = 0; i < len; i++) {
|
213
|
+
url_bind(rb_ary_entry(v, i));
|
214
|
+
}
|
215
|
+
break;
|
216
|
+
default:
|
217
|
+
rb_raise(rb_eArgError, "bind option must be a String or Array of Strings.");
|
218
|
+
break;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("graphql"))))) {
|
222
|
+
const char *path;
|
223
|
+
agooHook get_hook;
|
224
|
+
agooHook post_hook;
|
225
|
+
agooHook options_hook;
|
226
|
+
agooHook head = NULL;
|
227
|
+
long plen;
|
228
|
+
VALUE hide_schema = Qnil;
|
229
|
+
|
230
|
+
rb_check_type(v, T_STRING);
|
231
|
+
if (AGOO_ERR_OK != gql_init(err)) {
|
232
|
+
return err->code;
|
233
|
+
}
|
234
|
+
path = StringValuePtr(v);
|
235
|
+
plen = (long)RSTRING_LEN(v);
|
236
|
+
|
237
|
+
get_hook = agoo_hook_func_create(AGOO_GET, path, gql_eval_get_hook, &agoo_server.eval_queue);
|
238
|
+
post_hook = agoo_hook_func_create(AGOO_POST, path, gql_eval_post_hook, &agoo_server.eval_queue);
|
239
|
+
options_hook = agoo_hook_func_create(AGOO_OPTIONS, path, gql_eval_options_hook, &agoo_server.eval_queue);
|
240
|
+
if (Qnil != (hide_schema = rb_hash_lookup(options, ID2SYM(rb_intern("hide_schema")))) && Qtrue == hide_schema) {
|
241
|
+
head = get_hook;
|
242
|
+
} else {
|
243
|
+
char schema_path[256];
|
244
|
+
agooHook dump_hook;
|
245
|
+
|
246
|
+
if ((int)sizeof(schema_path) - 8 < plen) {
|
247
|
+
rb_raise(rb_eArgError, "A graphql schema path is limited to %d characters.", (int)(sizeof(schema_path) - 8));
|
248
|
+
}
|
249
|
+
memcpy(schema_path, path, plen);
|
250
|
+
memcpy(schema_path + plen, "/schema", 8);
|
251
|
+
dump_hook = agoo_hook_func_create(AGOO_GET, schema_path, gql_dump_hook, &agoo_server.eval_queue);
|
252
|
+
dump_hook->next = get_hook;
|
253
|
+
head = dump_hook;
|
254
|
+
}
|
255
|
+
get_hook->next = post_hook;
|
256
|
+
post_hook->next = options_hook;
|
257
|
+
options_hook->next = agoo_server.hooks;
|
258
|
+
agoo_server.hooks = head;
|
259
|
+
}
|
260
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("quiet"))))) {
|
261
|
+
if (Qtrue == v) {
|
262
|
+
agoo_info_cat.on = false;
|
263
|
+
}
|
264
|
+
}
|
265
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("debug"))))) {
|
266
|
+
if (Qtrue == v) {
|
267
|
+
agoo_error_cat.on = true;
|
268
|
+
agoo_warn_cat.on = true;
|
269
|
+
agoo_info_cat.on = true;
|
270
|
+
agoo_debug_cat.on = true;
|
271
|
+
agoo_con_cat.on = true;
|
272
|
+
agoo_req_cat.on = true;
|
273
|
+
agoo_resp_cat.on = true;
|
274
|
+
agoo_eval_cat.on = true;
|
275
|
+
agoo_push_cat.on = true;
|
276
|
+
}
|
277
|
+
}
|
266
278
|
}
|
267
279
|
if (0 < port) {
|
268
|
-
|
280
|
+
agooBind b = agoo_bind_port(err, port);
|
269
281
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
282
|
+
if (AGOO_ERR_OK != err->code) {
|
283
|
+
rb_raise(rb_eArgError, "%s", err->msg);
|
284
|
+
}
|
285
|
+
agoo_server_bind(b);
|
274
286
|
}
|
275
287
|
return AGOO_ERR_OK;
|
276
288
|
}
|
@@ -295,13 +307,15 @@ configure(agooErr err, int port, const char *root, VALUE options) {
|
|
295
307
|
*
|
296
308
|
* - *:poll_timeout* [_Float_] timeout seconds when polling. Default is 0.1. Lower gives faster response times but uses more CPU.
|
297
309
|
*
|
310
|
+
* - *:connection_timeout* [_Float_] timeout seconds for connections. Default is 30.
|
311
|
+
*
|
298
312
|
* - *:bind* [_String_|_Array_] a binding or array of binds. Examples are: "http ://127.0.0.1:6464", "unix:///tmp/agoo.socket", "http ://[::1]:6464, or to not restrict the address "http ://:6464".
|
299
313
|
*
|
300
314
|
* - *:graphql* [_String_] path to GraphQL endpoint if support for GraphQL is desired.
|
301
315
|
*
|
302
316
|
* - *:max_push_pending* [_Integer_] maximum number or outstanding push messages, less than 1000.
|
303
317
|
*
|
304
|
-
* - *:
|
318
|
+
* - *:ssl_cert* [_String_] filepath to the SSL certificate file.
|
305
319
|
*
|
306
320
|
* - *:ssl_key* [_String_] filepath to the SSL private key file.
|
307
321
|
*
|
@@ -309,83 +323,83 @@ configure(agooErr err, int port, const char *root, VALUE options) {
|
|
309
323
|
*/
|
310
324
|
static VALUE
|
311
325
|
rserver_init(int argc, VALUE *argv, VALUE self) {
|
312
|
-
struct _agooErr
|
313
|
-
int
|
314
|
-
const char
|
315
|
-
VALUE
|
326
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
327
|
+
int port;
|
328
|
+
const char *root;
|
329
|
+
VALUE options = Qnil;
|
316
330
|
|
317
331
|
if (argc < 2 || 3 < argc) {
|
318
|
-
|
332
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to Agoo::Server.configure.");
|
319
333
|
}
|
320
334
|
port = FIX2INT(argv[0]);
|
321
335
|
rb_check_type(argv[1], T_STRING);
|
322
336
|
root = StringValuePtr(argv[1]);
|
323
337
|
if (3 <= argc) {
|
324
|
-
|
338
|
+
options = argv[2];
|
325
339
|
}
|
326
340
|
if (AGOO_ERR_OK != agoo_server_setup(&err)) {
|
327
|
-
|
341
|
+
rb_raise(rb_eStandardError, "%s", err.msg);
|
328
342
|
}
|
329
343
|
agoo_server.ctx_nil_value = (void*)Qnil;
|
330
344
|
agoo_server.env_nil_value = (void*)Qnil;
|
331
345
|
|
332
346
|
if (AGOO_ERR_OK != configure(&err, port, root, options)) {
|
333
|
-
|
347
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
334
348
|
}
|
335
349
|
agoo_server.inited = true;
|
336
350
|
|
337
351
|
return Qnil;
|
338
352
|
}
|
339
353
|
|
340
|
-
static const char
|
354
|
+
static const char bad500[] = "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: ";
|
341
355
|
|
342
356
|
static VALUE
|
343
357
|
rescue_error(VALUE x, VALUE ignore) {
|
344
|
-
agooReq
|
345
|
-
volatile VALUE
|
346
|
-
volatile VALUE
|
347
|
-
const char
|
348
|
-
const char
|
358
|
+
agooReq req = (agooReq)x;
|
359
|
+
volatile VALUE info = rb_errinfo();
|
360
|
+
volatile VALUE msg = rb_funcall(info, rb_intern("message"), 0);
|
361
|
+
const char *classname = rb_obj_classname(info);
|
362
|
+
const char *ms = rb_string_value_ptr(&msg);
|
349
363
|
|
350
364
|
if (NULL == req->up) {
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
+
char buf[1024];
|
366
|
+
int len = (int)(strlen(classname) + 2 + strlen(ms));
|
367
|
+
int cnt;
|
368
|
+
agooText message;
|
369
|
+
|
370
|
+
if ((int)(sizeof(buf) - sizeof(bad500) + 7) <= len) {
|
371
|
+
len = sizeof(buf) - sizeof(bad500) + 7;
|
372
|
+
}
|
373
|
+
cnt = snprintf(buf, sizeof(buf), "%s%d\r\n\r\n%s: %s", bad500, len, classname, ms);
|
374
|
+
message = agoo_text_create(buf, cnt);
|
375
|
+
|
376
|
+
req->res->close = true;
|
377
|
+
agoo_res_message_push(req->res, message);
|
378
|
+
agoo_queue_wakeup(&agoo_server.con_queue);
|
365
379
|
} else {
|
366
380
|
/*
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
381
|
+
volatile VALUE bt = rb_funcall(info, rb_intern("backtrace"), 0);
|
382
|
+
int blen = RARRAY_LEN(bt);
|
383
|
+
int i;
|
384
|
+
VALUE rline;
|
385
|
+
|
386
|
+
for (i = 0; i < blen; i++) {
|
387
|
+
rline = rb_ary_entry(bt, i);
|
388
|
+
}
|
375
389
|
*/
|
376
|
-
|
390
|
+
agoo_log_cat(&agoo_error_cat, "%s: %s", classname, ms);
|
377
391
|
}
|
378
392
|
return Qfalse;
|
379
393
|
}
|
380
394
|
|
381
395
|
static VALUE
|
382
396
|
handle_base_inner(VALUE x) {
|
383
|
-
agooReq
|
384
|
-
volatile VALUE
|
385
|
-
volatile VALUE
|
397
|
+
agooReq req = (agooReq)(void*)x;
|
398
|
+
volatile VALUE rr = request_wrap(req);
|
399
|
+
volatile VALUE rres = response_new();
|
386
400
|
|
387
401
|
if (NULL != req->hook) {
|
388
|
-
|
402
|
+
rb_funcall((VALUE)req->hook->handler, on_request_id, 2, rr, rres);
|
389
403
|
}
|
390
404
|
DATA_PTR(rr) = NULL;
|
391
405
|
agoo_res_message_push(req->res, response_text(rres));
|
@@ -403,45 +417,45 @@ handle_base(void *x) {
|
|
403
417
|
|
404
418
|
static int
|
405
419
|
header_cb(VALUE key, VALUE value, VALUE tv) {
|
406
|
-
agooText
|
407
|
-
const char
|
408
|
-
int
|
409
|
-
const char
|
410
|
-
int
|
411
|
-
struct _agooErr
|
420
|
+
agooText *tp = (agooText*)tv;
|
421
|
+
const char *ks = StringValuePtr(key);
|
422
|
+
int klen = (int)RSTRING_LEN(key);
|
423
|
+
const char *vs = StringValuePtr(value);
|
424
|
+
int vlen = (int)RSTRING_LEN(value);
|
425
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
412
426
|
|
413
427
|
if (agoo_server.pedantic) {
|
414
|
-
|
415
|
-
|
416
|
-
|
428
|
+
if (AGOO_ERR_OK != agoo_http_header_ok(&err, ks, klen, vs, vlen)) {
|
429
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
430
|
+
}
|
417
431
|
}
|
418
432
|
if (0 != strcasecmp("Content-Length", ks)) {
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
433
|
+
char *end = index(vs, '\n');
|
434
|
+
|
435
|
+
do {
|
436
|
+
end = index(vs, '\n');
|
437
|
+
*tp = agoo_text_append(*tp, ks, klen);
|
438
|
+
*tp = agoo_text_append(*tp, ": ", 2);
|
439
|
+
if (NULL == end) {
|
440
|
+
if (0 < vlen) {
|
441
|
+
*tp = agoo_text_append(*tp, vs, vlen);
|
442
|
+
}
|
443
|
+
} else {
|
444
|
+
if (vs < end) {
|
445
|
+
*tp = agoo_text_append(*tp, vs, (int)(end - vs));
|
446
|
+
}
|
447
|
+
vlen -= end - vs + 1;
|
448
|
+
vs = end + 1;
|
449
|
+
}
|
450
|
+
*tp = agoo_text_append(*tp, "\r\n", 2);
|
451
|
+
} while (NULL != end && 0 < vlen);
|
438
452
|
}
|
439
453
|
return ST_CONTINUE;
|
440
454
|
}
|
441
455
|
|
442
456
|
static VALUE
|
443
457
|
header_each_cb(VALUE kv, VALUE cb_arg, int argc, const VALUE *argv, VALUE blockarg) {
|
444
|
-
agooText
|
458
|
+
agooText *tp = (agooText*)cb_arg;
|
445
459
|
|
446
460
|
header_cb(rb_ary_entry(kv, 0), rb_ary_entry(kv, 1), (VALUE)tp);
|
447
461
|
|
@@ -450,7 +464,7 @@ header_each_cb(VALUE kv, VALUE cb_arg, int argc, const VALUE *argv, VALUE blocka
|
|
450
464
|
|
451
465
|
static VALUE
|
452
466
|
body_len_cb(VALUE v, VALUE cb_arg, int argc, const VALUE *argv, VALUE blockarg) {
|
453
|
-
int
|
467
|
+
int *sizep = (int*)cb_arg;
|
454
468
|
|
455
469
|
*sizep += (int)RSTRING_LEN(v);
|
456
470
|
|
@@ -459,7 +473,7 @@ body_len_cb(VALUE v, VALUE cb_arg, int argc, const VALUE *argv, VALUE blockarg)
|
|
459
473
|
|
460
474
|
static VALUE
|
461
475
|
body_append_cb(VALUE v, VALUE cb_arg, int argc, const VALUE *argv, VALUE blockarg) {
|
462
|
-
agooText
|
476
|
+
agooText *tp = (agooText*)cb_arg;
|
463
477
|
|
464
478
|
*tp = agoo_text_append(*tp, StringValuePtr(v), (int)RSTRING_LEN(v));
|
465
479
|
|
@@ -468,81 +482,81 @@ body_append_cb(VALUE v, VALUE cb_arg, int argc, const VALUE *argv, VALUE blockar
|
|
468
482
|
|
469
483
|
static VALUE
|
470
484
|
handle_rack_inner(VALUE x) {
|
471
|
-
agooReq
|
472
|
-
agooText
|
473
|
-
volatile VALUE
|
474
|
-
volatile VALUE
|
475
|
-
volatile VALUE
|
476
|
-
volatile VALUE
|
477
|
-
int
|
478
|
-
const char
|
479
|
-
int
|
485
|
+
agooReq req = (agooReq)x;
|
486
|
+
agooText t;
|
487
|
+
volatile VALUE env = request_env(req, request_wrap(req));
|
488
|
+
volatile VALUE res = Qnil;
|
489
|
+
volatile VALUE hv;
|
490
|
+
volatile VALUE bv;
|
491
|
+
int code;
|
492
|
+
const char *status_msg;
|
493
|
+
int bsize = 0;
|
480
494
|
|
481
495
|
if (NULL == req->hook) {
|
482
|
-
|
496
|
+
return Qfalse;
|
483
497
|
}
|
484
498
|
res = rb_funcall((VALUE)req->hook->handler, call_id, 1, env);
|
485
499
|
if (req->res->con->hijacked) {
|
486
|
-
|
487
|
-
|
500
|
+
agoo_queue_wakeup(&agoo_server.con_queue);
|
501
|
+
return Qfalse;
|
488
502
|
}
|
489
503
|
rb_check_type(res, T_ARRAY);
|
490
504
|
if (3 != RARRAY_LEN(res)) {
|
491
|
-
|
505
|
+
rb_raise(rb_eArgError, "a rack call() response must be an array of 3 members.");
|
492
506
|
}
|
493
507
|
hv = rb_ary_entry(res, 0);
|
494
508
|
if (RUBY_T_FIXNUM == rb_type(hv)) {
|
495
|
-
|
509
|
+
code = NUM2INT(hv);
|
496
510
|
} else {
|
497
|
-
|
511
|
+
code = NUM2INT(rb_funcall(hv, to_i_id, 0));
|
498
512
|
}
|
499
513
|
status_msg = agoo_http_code_message(code);
|
500
514
|
if ('\0' == *status_msg) {
|
501
|
-
|
515
|
+
rb_raise(rb_eArgError, "invalid rack call() response status code (%d).", code);
|
502
516
|
}
|
503
517
|
hv = rb_ary_entry(res, 1);
|
504
518
|
if (!rb_respond_to(hv, each_id)) {
|
505
|
-
|
519
|
+
rb_raise(rb_eArgError, "invalid rack call() response headers does not respond to each.");
|
506
520
|
}
|
507
521
|
bv = rb_ary_entry(res, 2);
|
508
522
|
if (!rb_respond_to(bv, each_id)) {
|
509
|
-
|
523
|
+
rb_raise(rb_eArgError, "invalid rack call() response body does not respond to each.");
|
510
524
|
}
|
511
525
|
if (NULL == (t = agoo_text_allocate(1024))) {
|
512
|
-
|
526
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
|
513
527
|
}
|
514
528
|
if (T_ARRAY == rb_type(bv)) {
|
515
|
-
|
516
|
-
|
529
|
+
int i;
|
530
|
+
int bcnt = (int)RARRAY_LEN(bv);
|
517
531
|
|
518
|
-
|
519
|
-
|
520
|
-
|
532
|
+
for (i = 0; i < bcnt; i++) {
|
533
|
+
bsize += (int)RSTRING_LEN(rb_ary_entry(bv, i));
|
534
|
+
}
|
521
535
|
} else {
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
536
|
+
if (AGOO_HEAD == req->method) {
|
537
|
+
// Rack wraps the response in two layers, Rack::Lint and
|
538
|
+
// Rack::BodyProxy. It each is called on either with the HEAD
|
539
|
+
// method an exception is raised so the length can not be
|
540
|
+
// determined. This digs down to get the actual response so the
|
541
|
+
// length can be calculated. A very special case.
|
542
|
+
if (0 == strcmp("Rack::BodyProxy", rb_obj_classname(bv))) {
|
543
|
+
volatile VALUE body = rb_ivar_get(bv, rb_intern("@body"));
|
544
|
+
|
545
|
+
if (Qnil != body) {
|
546
|
+
body = rb_ivar_get(body, rb_intern("@body"));
|
547
|
+
}
|
548
|
+
if (Qnil != body) {
|
549
|
+
body = rb_ivar_get(body, rb_intern("@body"));
|
550
|
+
}
|
551
|
+
if (rb_respond_to(body, each_id)) {
|
552
|
+
rb_block_call(body, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
553
|
+
}
|
554
|
+
} else {
|
555
|
+
rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
556
|
+
}
|
557
|
+
} else {
|
558
|
+
rb_block_call(bv, each_id, 0, 0, body_len_cb, (VALUE)&bsize);
|
559
|
+
}
|
546
560
|
}
|
547
561
|
switch (code) {
|
548
562
|
case 100:
|
@@ -551,70 +565,70 @@ handle_rack_inner(VALUE x) {
|
|
551
565
|
case 204:
|
552
566
|
case 205:
|
553
567
|
case 304:
|
554
|
-
|
555
|
-
|
556
|
-
|
568
|
+
// Content-Type and Content-Length can not be present
|
569
|
+
t->len = snprintf(t->text, 1024, "HTTP/1.1 %d %s\r\n", code, status_msg);
|
570
|
+
break;
|
557
571
|
default:
|
558
|
-
|
559
|
-
|
560
|
-
|
572
|
+
// Note that using simply sprintf causes an abort with travis OSX tests.
|
573
|
+
t->len = snprintf(t->text, 1024, "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n", code, status_msg, bsize);
|
574
|
+
break;
|
561
575
|
}
|
562
576
|
if (code < 300) {
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
577
|
+
VALUE handler = Qnil;
|
578
|
+
|
579
|
+
switch (req->upgrade) {
|
580
|
+
case AGOO_UP_WS:
|
581
|
+
if (AGOO_CON_WS != req->res->con_kind ||
|
582
|
+
Qnil == (handler = rb_hash_lookup(env, push_env_key))) {
|
583
|
+
strcpy(t->text, err500);
|
584
|
+
t->len = sizeof(err500) - 1;
|
585
|
+
break;
|
586
|
+
}
|
587
|
+
req->hook = agoo_hook_create(AGOO_NONE, NULL, (void*)handler, PUSH_HOOK, &agoo_server.eval_queue);
|
588
|
+
rupgraded_create(req->res->con, handler, request_env(req, Qnil));
|
589
|
+
t->len = snprintf(t->text, 1024, "HTTP/1.1 101 %s\r\n", status_msg);
|
590
|
+
t = agoo_ws_add_headers(req, t);
|
591
|
+
break;
|
592
|
+
case AGOO_UP_SSE:
|
593
|
+
if (AGOO_CON_SSE != req->res->con_kind ||
|
594
|
+
Qnil == (handler = rb_hash_lookup(env, push_env_key))) {
|
595
|
+
strcpy(t->text, err500);
|
596
|
+
t->len = sizeof(err500) - 1;
|
597
|
+
break;
|
598
|
+
}
|
599
|
+
req->hook = agoo_hook_create(AGOO_NONE, NULL, (void*)handler, PUSH_HOOK, &agoo_server.eval_queue);
|
600
|
+
rupgraded_create(req->res->con, handler, request_env(req, Qnil));
|
601
|
+
t = agoo_sse_upgrade(req, t);
|
602
|
+
agoo_res_message_push(req->res, t);
|
603
|
+
agoo_queue_wakeup(&agoo_server.con_queue);
|
604
|
+
return Qfalse;
|
605
|
+
default:
|
606
|
+
break;
|
607
|
+
}
|
594
608
|
}
|
595
609
|
if (AGOO_HEAD == req->method) {
|
596
|
-
|
610
|
+
bsize = 0;
|
597
611
|
} else {
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
612
|
+
if (T_HASH == rb_type(hv)) {
|
613
|
+
rb_hash_foreach(hv, header_cb, (VALUE)&t);
|
614
|
+
} else {
|
615
|
+
rb_block_call(hv, each_id, 0, 0, header_each_cb, (VALUE)&t);
|
616
|
+
}
|
603
617
|
}
|
604
618
|
t = agoo_text_append(t, "\r\n", 2);
|
605
619
|
if (0 < bsize) {
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
620
|
+
if (T_ARRAY == rb_type(bv)) {
|
621
|
+
VALUE v;
|
622
|
+
int i;
|
623
|
+
int bcnt = (int)RARRAY_LEN(bv);
|
624
|
+
|
625
|
+
for (i = 0; i < bcnt; i++) {
|
626
|
+
v = rb_ary_entry(bv, i);
|
627
|
+
t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
|
628
|
+
}
|
629
|
+
} else {
|
630
|
+
rb_block_call(bv, each_id, 0, 0, body_append_cb, (VALUE)&t);
|
631
|
+
}
|
618
632
|
}
|
619
633
|
agoo_res_message_push(req->res, t);
|
620
634
|
agoo_queue_wakeup(&agoo_server.con_queue);
|
@@ -634,12 +648,12 @@ handle_rack(void *x) {
|
|
634
648
|
|
635
649
|
static VALUE
|
636
650
|
handle_wab_inner(VALUE x) {
|
637
|
-
agooReq
|
638
|
-
volatile VALUE
|
639
|
-
volatile VALUE
|
651
|
+
agooReq req = (agooReq)x;
|
652
|
+
volatile VALUE rr = request_wrap(req);
|
653
|
+
volatile VALUE rres = response_new();
|
640
654
|
|
641
655
|
if (NULL != req->hook) {
|
642
|
-
|
656
|
+
rb_funcall((VALUE)req->hook->handler, on_request_id, 2, rr, rres);
|
643
657
|
}
|
644
658
|
DATA_PTR(rr) = NULL;
|
645
659
|
agoo_res_message_push(req->res, response_text(rres));
|
@@ -657,49 +671,49 @@ handle_wab(void *x) {
|
|
657
671
|
|
658
672
|
static VALUE
|
659
673
|
handle_push_inner(VALUE x) {
|
660
|
-
agooReq
|
674
|
+
agooReq req = (agooReq)x;
|
661
675
|
|
662
676
|
switch (req->method) {
|
663
677
|
case AGOO_ON_MSG:
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
678
|
+
if (req->up->on_msg && NULL != req->hook) {
|
679
|
+
rb_funcall((VALUE)req->hook->handler, on_message_id, 2, (VALUE)req->up->wrap, rb_str_new(req->msg, req->mlen));
|
680
|
+
}
|
681
|
+
break;
|
668
682
|
case AGOO_ON_BIN:
|
669
|
-
|
670
|
-
|
683
|
+
if (req->up->on_msg && NULL != req->hook) {
|
684
|
+
volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
|
671
685
|
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
686
|
+
rb_enc_associate(rstr, rb_ascii8bit_encoding());
|
687
|
+
rb_funcall((VALUE)req->hook->handler, on_message_id, 2, (VALUE)req->up->wrap, rstr);
|
688
|
+
}
|
689
|
+
break;
|
676
690
|
case AGOO_ON_CLOSE:
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
691
|
+
agoo_upgraded_ref(req->up);
|
692
|
+
agoo_server_publish(agoo_pub_close(req->up));
|
693
|
+
if (req->up->on_close && NULL != req->hook) {
|
694
|
+
rb_funcall((VALUE)req->hook->handler, on_close_id, 1, (VALUE)req->up->wrap);
|
695
|
+
}
|
696
|
+
break;
|
683
697
|
case AGOO_ON_SHUTDOWN:
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
698
|
+
if (NULL != req->hook) {
|
699
|
+
rb_funcall((VALUE)req->hook->handler, rb_intern("on_shutdown"), 1, (VALUE)req->up->wrap);
|
700
|
+
}
|
701
|
+
break;
|
688
702
|
case AGOO_ON_ERROR:
|
689
|
-
|
690
|
-
|
703
|
+
if (req->up->on_error && NULL != req->hook) {
|
704
|
+
volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
|
691
705
|
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
706
|
+
rb_enc_associate(rstr, rb_ascii8bit_encoding());
|
707
|
+
rb_funcall((VALUE)req->hook->handler, on_error_id, 2, (VALUE)req->up->wrap, rstr);
|
708
|
+
}
|
709
|
+
break;
|
696
710
|
case AGOO_ON_EMPTY:
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
711
|
+
if (req->up->on_empty && NULL != req->hook) {
|
712
|
+
rb_funcall((VALUE)req->hook->handler, on_drained_id, 1, (VALUE)req->up->wrap);
|
713
|
+
}
|
714
|
+
break;
|
701
715
|
default:
|
702
|
-
|
716
|
+
break;
|
703
717
|
}
|
704
718
|
agoo_upgraded_release(req->up);
|
705
719
|
|
@@ -715,69 +729,69 @@ handle_push(void *x) {
|
|
715
729
|
static void
|
716
730
|
handle_protected(agooReq req, bool gvi) {
|
717
731
|
if (NULL == req->hook) {
|
718
|
-
|
732
|
+
return;
|
719
733
|
}
|
720
734
|
switch (req->hook->type) {
|
721
735
|
case BASE_HOOK:
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
736
|
+
if (gvi) {
|
737
|
+
rb_thread_call_with_gvl(handle_base, req);
|
738
|
+
} else {
|
739
|
+
handle_base(req);
|
740
|
+
}
|
741
|
+
break;
|
728
742
|
case RACK_HOOK:
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
743
|
+
if (gvi) {
|
744
|
+
rb_thread_call_with_gvl(handle_rack, req);
|
745
|
+
} else {
|
746
|
+
handle_rack(req);
|
747
|
+
}
|
748
|
+
break;
|
735
749
|
case WAB_HOOK:
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
750
|
+
if (gvi) {
|
751
|
+
rb_thread_call_with_gvl(handle_wab, req);
|
752
|
+
} else {
|
753
|
+
handle_wab(req);
|
754
|
+
}
|
755
|
+
break;
|
742
756
|
case PUSH_HOOK:
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
757
|
+
if (gvi) {
|
758
|
+
rb_thread_call_with_gvl(handle_push, req);
|
759
|
+
} else {
|
760
|
+
handle_push(req);
|
761
|
+
}
|
762
|
+
break;
|
749
763
|
case FUNC_HOOK:
|
750
|
-
|
751
|
-
|
752
|
-
|
764
|
+
req->hook->func(req);
|
765
|
+
agoo_queue_wakeup(&agoo_server.con_queue);
|
766
|
+
break;
|
753
767
|
default: {
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
768
|
+
char buf[256];
|
769
|
+
int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
|
770
|
+
agooText message = agoo_text_create(buf, cnt);
|
771
|
+
|
772
|
+
req->res->close = true;
|
773
|
+
agoo_res_message_push(req->res, message);
|
774
|
+
agoo_queue_wakeup(&agoo_server.con_queue);
|
775
|
+
break;
|
762
776
|
}
|
763
777
|
}
|
764
778
|
}
|
765
779
|
|
766
780
|
static void*
|
767
781
|
process_loop(void *ptr) {
|
768
|
-
agooReq
|
782
|
+
agooReq req;
|
769
783
|
|
770
784
|
atomic_fetch_add(&agoo_server.running, 1);
|
771
785
|
while (agoo_server.active) {
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
786
|
+
if (NULL != (req = (agooReq)agoo_queue_pop(&agoo_server.eval_queue, poll_timeout))) {
|
787
|
+
handle_protected(req, true);
|
788
|
+
agoo_req_destroy(req);
|
789
|
+
}
|
790
|
+
if (agoo_stop) {
|
791
|
+
agoo_shutdown();
|
792
|
+
break;
|
793
|
+
}
|
794
|
+
agoo_queue_wakeup(&agoo_server.con_queue); // TBD remove if it doesn't speed up the response time
|
781
795
|
}
|
782
796
|
atomic_fetch_sub(&agoo_server.running, 1);
|
783
797
|
|
@@ -798,84 +812,96 @@ wrap_process_loop(void *ptr) {
|
|
798
812
|
*/
|
799
813
|
static VALUE
|
800
814
|
rserver_start(VALUE self) {
|
801
|
-
VALUE
|
802
|
-
int
|
803
|
-
int
|
804
|
-
double
|
805
|
-
struct _agooErr
|
806
|
-
VALUE
|
807
|
-
VALUE
|
815
|
+
VALUE *vp;
|
816
|
+
int i;
|
817
|
+
int pid;
|
818
|
+
double giveup;
|
819
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
820
|
+
VALUE agoo = rb_const_get_at(rb_cObject, rb_intern("Agoo"));
|
821
|
+
VALUE v = rb_const_get_at(agoo, rb_intern("VERSION"));
|
822
|
+
ID after = rb_intern("after");
|
808
823
|
|
809
824
|
*the_rserver.worker_pids = getpid();
|
810
825
|
|
811
826
|
// If workers then set the loop_max based on the expected number of
|
812
827
|
// threads per worker.
|
813
828
|
if (1 < the_rserver.worker_cnt) {
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
829
|
+
agoo_server.loop_max /= the_rserver.worker_cnt;
|
830
|
+
if (agoo_server.loop_max < 1) {
|
831
|
+
agoo_server.loop_max = 1;
|
832
|
+
}
|
818
833
|
}
|
819
834
|
if (AGOO_ERR_OK != setup_listen(&err)) {
|
820
|
-
|
835
|
+
rb_raise(rb_eIOError, "%s", err.msg);
|
821
836
|
}
|
837
|
+
if (1 < the_rserver.worker_cnt && the_rserver.forker != Qnil) {
|
838
|
+
ID before = rb_intern("before");
|
839
|
+
|
840
|
+
if (rb_respond_to(the_rserver.forker, before)) {
|
841
|
+
rb_funcall(the_rserver.forker, before, 0);
|
842
|
+
}
|
843
|
+
}
|
822
844
|
for (i = 1; i < the_rserver.worker_cnt; i++) {
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
845
|
+
VALUE rpid = rb_funcall(rb_cObject, rb_intern("fork"), 0);
|
846
|
+
|
847
|
+
if (Qnil == rpid) {
|
848
|
+
pid = 0;
|
849
|
+
} else {
|
850
|
+
pid = NUM2INT(rpid);
|
851
|
+
}
|
852
|
+
if (0 > pid) { // error, use single process
|
853
|
+
agoo_log_cat(&agoo_error_cat, "Failed to fork. %s.", strerror(errno));
|
854
|
+
break;
|
855
|
+
} else if (0 == pid) {
|
856
|
+
if (AGOO_ERR_OK != agoo_log_start(&err, true)) {
|
857
|
+
rb_raise(rb_eStandardError, "%s", err.msg);
|
858
|
+
}
|
859
|
+
break;
|
860
|
+
} else {
|
861
|
+
the_rserver.worker_pids[i] = pid;
|
862
|
+
}
|
841
863
|
}
|
864
|
+
if (1 < the_rserver.worker_cnt && the_rserver.forker != Qnil && rb_respond_to(the_rserver.forker, after)) {
|
865
|
+
rb_funcall(the_rserver.forker, after, 0);
|
866
|
+
}
|
842
867
|
if (AGOO_ERR_OK != agoo_server_start(&err, "Agoo", StringValuePtr(v))) {
|
843
|
-
|
868
|
+
rb_raise(rb_eStandardError, "%s", err.msg);
|
844
869
|
}
|
845
870
|
if (0 >= agoo_server.thread_cnt) {
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
871
|
+
agooReq req;
|
872
|
+
|
873
|
+
while (agoo_server.active) {
|
874
|
+
if (NULL != (req = (agooReq)agoo_queue_pop(&agoo_server.eval_queue, poll_timeout))) {
|
875
|
+
handle_protected(req, false);
|
876
|
+
agoo_req_destroy(req);
|
877
|
+
} else {
|
878
|
+
rb_thread_schedule();
|
879
|
+
}
|
880
|
+
if (agoo_stop) {
|
881
|
+
agoo_shutdown();
|
882
|
+
break;
|
883
|
+
}
|
884
|
+
}
|
860
885
|
} else {
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
886
|
+
if (NULL == (the_rserver.eval_threads = (VALUE*)AGOO_MALLOC(sizeof(VALUE) * (agoo_server.thread_cnt + 1)))) {
|
887
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for the thread pool.");
|
888
|
+
}
|
889
|
+
for (i = agoo_server.thread_cnt, vp = the_rserver.eval_threads; 0 < i; i--, vp++) {
|
890
|
+
*vp = rb_thread_create(wrap_process_loop, NULL);
|
891
|
+
}
|
892
|
+
*vp = Qnil;
|
893
|
+
|
894
|
+
giveup = dtime() + 1.0;
|
895
|
+
while (dtime() < giveup) {
|
896
|
+
// The processing threads will not start until this thread
|
897
|
+
// releases ownership so do that and then see if the threads have
|
898
|
+
// been started yet.
|
899
|
+
rb_thread_schedule();
|
900
|
+
if (agoo_server.loop_cnt + 1 + agoo_server.thread_cnt <= (long)atomic_load(&agoo_server.running)) {
|
901
|
+
break;
|
902
|
+
}
|
903
|
+
dsleep(0.05);
|
904
|
+
}
|
879
905
|
}
|
880
906
|
return Qnil;
|
881
907
|
}
|
@@ -887,16 +913,16 @@ stop_runners() {
|
|
887
913
|
// cause a segfault. Instead we set a timeout and wait for the running
|
888
914
|
// counter to drop to zero.
|
889
915
|
if (NULL != the_rserver.eval_threads) {
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
916
|
+
double timeout = dtime() + 2.0;
|
917
|
+
|
918
|
+
while (dtime() < timeout) {
|
919
|
+
if (0 >= (long)atomic_load(&agoo_server.running)) {
|
920
|
+
break;
|
921
|
+
}
|
922
|
+
dsleep(0.02);
|
923
|
+
}
|
924
|
+
AGOO_FREE(the_rserver.eval_threads);
|
925
|
+
the_rserver.eval_threads = NULL;
|
900
926
|
}
|
901
927
|
}
|
902
928
|
|
@@ -909,43 +935,43 @@ stop_runners() {
|
|
909
935
|
VALUE
|
910
936
|
rserver_shutdown(VALUE self) {
|
911
937
|
if (agoo_server.inited) {
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
938
|
+
agoo_server_shutdown("Agoo", stop_runners);
|
939
|
+
|
940
|
+
if (1 < the_rserver.worker_cnt && getpid() == *the_rserver.worker_pids) {
|
941
|
+
int i;
|
942
|
+
int status;
|
943
|
+
int exit_cnt = 1;
|
944
|
+
int j;
|
945
|
+
|
946
|
+
for (i = 1; i < the_rserver.worker_cnt; i++) {
|
947
|
+
kill(the_rserver.worker_pids[i], SIGKILL);
|
948
|
+
}
|
949
|
+
for (j = 0; j < 20; j++) {
|
950
|
+
for (i = 1; i < the_rserver.worker_cnt; i++) {
|
951
|
+
if (0 == the_rserver.worker_pids[i]) {
|
952
|
+
continue;
|
953
|
+
}
|
954
|
+
if (0 < waitpid(the_rserver.worker_pids[i], &status, WNOHANG)) {
|
955
|
+
if (WIFEXITED(status)) {
|
956
|
+
//printf("exited, status=%d for %d\n", agoo_server.worker_pids[i], WEXITSTATUS(status));
|
957
|
+
the_rserver.worker_pids[i] = 0;
|
958
|
+
exit_cnt++;
|
959
|
+
} else if (WIFSIGNALED(status)) {
|
960
|
+
//printf("*** killed by signal %d for %d\n", agoo_server.worker_pids[i], WTERMSIG(status));
|
961
|
+
the_rserver.worker_pids[i] = 0;
|
962
|
+
exit_cnt++;
|
963
|
+
}
|
964
|
+
}
|
965
|
+
}
|
966
|
+
if (the_rserver.worker_cnt <= exit_cnt) {
|
967
|
+
break;
|
968
|
+
}
|
969
|
+
dsleep(0.2);
|
970
|
+
}
|
971
|
+
if (exit_cnt < the_rserver.worker_cnt) {
|
972
|
+
printf("*-*-* Some workers did not exit.\n");
|
973
|
+
}
|
974
|
+
}
|
949
975
|
}
|
950
976
|
return Qnil;
|
951
977
|
}
|
@@ -960,97 +986,97 @@ rserver_shutdown(VALUE self) {
|
|
960
986
|
*/
|
961
987
|
static VALUE
|
962
988
|
handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
963
|
-
agooHook
|
964
|
-
agooMethod
|
965
|
-
const char
|
966
|
-
ID
|
989
|
+
agooHook hook;
|
990
|
+
agooMethod meth = AGOO_ALL;
|
991
|
+
const char *pat;
|
992
|
+
ID static_id = rb_intern("static?");
|
967
993
|
|
968
994
|
rb_check_type(pattern, T_STRING);
|
969
995
|
pat = StringValuePtr(pattern);
|
970
996
|
|
971
997
|
if (connect_sym == method) {
|
972
|
-
|
998
|
+
meth = AGOO_CONNECT;
|
973
999
|
} else if (delete_sym == method) {
|
974
|
-
|
1000
|
+
meth = AGOO_DELETE;
|
975
1001
|
} else if (get_sym == method) {
|
976
|
-
|
1002
|
+
meth = AGOO_GET;
|
977
1003
|
} else if (head_sym == method) {
|
978
|
-
|
1004
|
+
meth = AGOO_HEAD;
|
979
1005
|
} else if (options_sym == method) {
|
980
|
-
|
1006
|
+
meth = AGOO_OPTIONS;
|
981
1007
|
} else if (post_sym == method) {
|
982
|
-
|
1008
|
+
meth = AGOO_POST;
|
983
1009
|
} else if (put_sym == method) {
|
984
|
-
|
1010
|
+
meth = AGOO_PUT;
|
985
1011
|
} else if (patch_sym == method) {
|
986
|
-
|
1012
|
+
meth = AGOO_PATCH;
|
987
1013
|
} else if (Qnil == method) {
|
988
|
-
|
1014
|
+
meth = AGOO_ALL;
|
989
1015
|
} else {
|
990
|
-
|
1016
|
+
rb_raise(rb_eArgError, "invalid method");
|
991
1017
|
}
|
992
1018
|
if (T_STRING == rb_type(handler)) {
|
993
|
-
|
1019
|
+
handler = resolve_classpath(StringValuePtr(handler), RSTRING_LEN(handler));
|
994
1020
|
}
|
995
1021
|
if (rb_respond_to(handler, static_id)) {
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1022
|
+
if (Qtrue == rb_funcall(handler, static_id, 0)) {
|
1023
|
+
VALUE res = rb_funcall(handler, call_id, 1, Qnil);
|
1024
|
+
VALUE bv;
|
1025
|
+
|
1026
|
+
rb_check_type(res, T_ARRAY);
|
1027
|
+
if (3 != RARRAY_LEN(res)) {
|
1028
|
+
rb_raise(rb_eArgError, "a rack call() response must be an array of 3 members.");
|
1029
|
+
}
|
1030
|
+
bv = rb_ary_entry(res, 2);
|
1031
|
+
if (T_ARRAY == rb_type(bv)) {
|
1032
|
+
int i;
|
1033
|
+
int bcnt = (int)RARRAY_LEN(bv);
|
1034
|
+
agooText t = agoo_text_allocate(1024);
|
1035
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
1036
|
+
VALUE v;
|
1037
|
+
|
1038
|
+
if (NULL == t) {
|
1039
|
+
rb_raise(rb_eArgError, "failed to allocate response.");
|
1040
|
+
}
|
1041
|
+
for (i = 0; i < bcnt; i++) {
|
1042
|
+
v = rb_ary_entry(bv, i);
|
1043
|
+
t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
|
1044
|
+
}
|
1045
|
+
if (NULL == t) {
|
1046
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
|
1047
|
+
}
|
1048
|
+
if (NULL == agoo_page_immutable(&err, pat, t->text, (int)t->len)) {
|
1049
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
1050
|
+
}
|
1051
|
+
agoo_text_release(t);
|
1052
|
+
|
1053
|
+
return Qnil;
|
1054
|
+
}
|
1055
|
+
}
|
1030
1056
|
}
|
1031
1057
|
if (NULL != the_rserver.uses) {
|
1032
|
-
|
1058
|
+
RUse u;
|
1033
1059
|
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1060
|
+
for (u = the_rserver.uses; NULL != u; u = u->next) {
|
1061
|
+
u->argv[0] = handler;
|
1062
|
+
handler = rb_funcall2(u->clas, rb_intern("new"), u->argc, u->argv);
|
1063
|
+
}
|
1038
1064
|
}
|
1039
1065
|
if (NULL == (hook = rhook_create(meth, pat, handler, &agoo_server.eval_queue))) {
|
1040
|
-
|
1066
|
+
rb_raise(rb_eStandardError, "out of memory.");
|
1041
1067
|
} else {
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1068
|
+
agooHook h;
|
1069
|
+
agooHook prev = NULL;
|
1070
|
+
|
1071
|
+
for (h = agoo_server.hooks; NULL != h; h = h->next) {
|
1072
|
+
prev = h;
|
1073
|
+
}
|
1074
|
+
if (NULL != prev) {
|
1075
|
+
prev->next = hook;
|
1076
|
+
} else {
|
1077
|
+
agoo_server.hooks = hook;
|
1078
|
+
}
|
1079
|
+
rb_gc_register_address((VALUE*)&hook->handler);
|
1054
1080
|
}
|
1055
1081
|
return Qnil;
|
1056
1082
|
}
|
@@ -1065,7 +1091,7 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
|
1065
1091
|
static VALUE
|
1066
1092
|
handle_not_found(VALUE self, VALUE handler) {
|
1067
1093
|
if (NULL == (agoo_server.hook404 = rhook_create(AGOO_GET, "/", handler, &agoo_server.eval_queue))) {
|
1068
|
-
|
1094
|
+
rb_raise(rb_eStandardError, "out of memory.");
|
1069
1095
|
}
|
1070
1096
|
rb_gc_register_address((VALUE*)&agoo_server.hook404->handler);
|
1071
1097
|
|
@@ -1081,10 +1107,10 @@ handle_not_found(VALUE self, VALUE handler) {
|
|
1081
1107
|
*/
|
1082
1108
|
static VALUE
|
1083
1109
|
add_mime(VALUE self, VALUE suffix, VALUE type) {
|
1084
|
-
struct _agooErr
|
1110
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
1085
1111
|
|
1086
1112
|
if (AGOO_ERR_OK != mime_set(&err, StringValuePtr(suffix), StringValuePtr(type))) {
|
1087
|
-
|
1113
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
1088
1114
|
}
|
1089
1115
|
return Qnil;
|
1090
1116
|
}
|
@@ -1099,26 +1125,26 @@ add_mime(VALUE self, VALUE suffix, VALUE type) {
|
|
1099
1125
|
*/
|
1100
1126
|
static VALUE
|
1101
1127
|
path_group(VALUE self, VALUE path, VALUE dirs) {
|
1102
|
-
struct _agooErr
|
1103
|
-
agooGroup
|
1128
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
1129
|
+
agooGroup g;
|
1104
1130
|
|
1105
1131
|
rb_check_type(path, T_STRING);
|
1106
1132
|
rb_check_type(dirs, T_ARRAY);
|
1107
1133
|
|
1108
1134
|
if (NULL != (g = agoo_group_create(StringValuePtr(path)))) {
|
1109
|
-
|
1110
|
-
|
1111
|
-
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
1116
|
-
|
1117
|
-
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
|
1135
|
+
int i;
|
1136
|
+
int dcnt = (int)RARRAY_LEN(dirs);
|
1137
|
+
VALUE entry;
|
1138
|
+
|
1139
|
+
for (i = dcnt - 1; 0 <= i; i--) {
|
1140
|
+
entry = rb_ary_entry(dirs, i);
|
1141
|
+
if (T_STRING != rb_type(entry)) {
|
1142
|
+
entry = rb_funcall(entry, rb_intern("to_s"), 0);
|
1143
|
+
}
|
1144
|
+
if (NULL == agoo_group_add(&err, g, StringValuePtr(entry))) {
|
1145
|
+
rb_raise(rb_eStandardError, "%s", err.msg);
|
1146
|
+
}
|
1147
|
+
}
|
1122
1148
|
}
|
1123
1149
|
return Qnil;
|
1124
1150
|
}
|
@@ -1141,7 +1167,7 @@ path_group(VALUE self, VALUE path, VALUE dirs) {
|
|
1141
1167
|
*/
|
1142
1168
|
static VALUE
|
1143
1169
|
header_rule(VALUE self, VALUE path, VALUE mime, VALUE key, VALUE value) {
|
1144
|
-
struct _agooErr
|
1170
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
1145
1171
|
|
1146
1172
|
rb_check_type(path, T_STRING);
|
1147
1173
|
rb_check_type(mime, T_STRING);
|
@@ -1149,7 +1175,7 @@ header_rule(VALUE self, VALUE path, VALUE mime, VALUE key, VALUE value) {
|
|
1149
1175
|
rb_check_type(value, T_STRING);
|
1150
1176
|
|
1151
1177
|
if (AGOO_ERR_OK != agoo_header_rule(&err, StringValuePtr(path), StringValuePtr(mime), StringValuePtr(key), StringValuePtr(value))) {
|
1152
|
-
|
1178
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
1153
1179
|
}
|
1154
1180
|
return Qnil;
|
1155
1181
|
}
|
@@ -1166,32 +1192,32 @@ header_rule(VALUE self, VALUE path, VALUE mime, VALUE key, VALUE value) {
|
|
1166
1192
|
*/
|
1167
1193
|
static VALUE
|
1168
1194
|
domain(VALUE self, VALUE host, VALUE path) {
|
1169
|
-
struct _agooErr
|
1195
|
+
struct _agooErr err = AGOO_ERR_INIT;
|
1170
1196
|
|
1171
1197
|
switch(rb_type(host)) {
|
1172
1198
|
case RUBY_T_STRING:
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1199
|
+
rb_check_type(path, T_STRING);
|
1200
|
+
if (AGOO_ERR_OK != agoo_domain_add(&err, rb_string_value_ptr((VALUE*)&host), rb_string_value_ptr((VALUE*)&path))) {
|
1201
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
1202
|
+
}
|
1203
|
+
break;
|
1178
1204
|
case RUBY_T_REGEXP: {
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
1183
|
-
|
1184
|
-
|
1185
|
-
|
1186
|
-
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1205
|
+
volatile VALUE v = rb_funcall(host, rb_intern("inspect"), 0);
|
1206
|
+
char rx[1024];
|
1207
|
+
|
1208
|
+
if (sizeof(rx) <= (size_t)RSTRING_LEN(v)) {
|
1209
|
+
rb_raise(rb_eArgError, "host Regex limited to %ld characters", sizeof(rx));
|
1210
|
+
}
|
1211
|
+
strcpy(rx, rb_string_value_ptr((VALUE*)&v) + 1);
|
1212
|
+
rx[RSTRING_LEN(v) - 2] = '\0';
|
1213
|
+
if (AGOO_ERR_OK != agoo_domain_add_regex(&err, rx, rb_string_value_ptr((VALUE*)&path))) {
|
1214
|
+
rb_raise(rb_eArgError, "%s", err.msg);
|
1215
|
+
}
|
1216
|
+
break;
|
1191
1217
|
}
|
1192
1218
|
default:
|
1193
|
-
|
1194
|
-
|
1219
|
+
rb_raise(rb_eArgError, "host must be a String or Regex");
|
1220
|
+
break;
|
1195
1221
|
}
|
1196
1222
|
return Qnil;
|
1197
1223
|
}
|
@@ -1206,13 +1232,13 @@ domain(VALUE self, VALUE host, VALUE path) {
|
|
1206
1232
|
static VALUE
|
1207
1233
|
rack_early_hints(VALUE self, VALUE on) {
|
1208
1234
|
if (Qtrue == on) {
|
1209
|
-
|
1235
|
+
agoo_server.rack_early_hints = true;
|
1210
1236
|
} else if (Qfalse == on) {
|
1211
|
-
|
1237
|
+
agoo_server.rack_early_hints = false;
|
1212
1238
|
} else if (Qnil == on) {
|
1213
|
-
|
1239
|
+
on = agoo_server.rack_early_hints ? Qtrue : Qfalse;
|
1214
1240
|
} else {
|
1215
|
-
|
1241
|
+
rb_raise(rb_eArgError, "rack_early_hints can only be set to true or false");
|
1216
1242
|
}
|
1217
1243
|
return on;
|
1218
1244
|
}
|
@@ -1226,23 +1252,23 @@ rack_early_hints(VALUE self, VALUE on) {
|
|
1226
1252
|
*/
|
1227
1253
|
static VALUE
|
1228
1254
|
use(int argc, VALUE *argv, VALUE self) {
|
1229
|
-
VALUE
|
1230
|
-
RUse
|
1255
|
+
VALUE mc;
|
1256
|
+
RUse u;
|
1231
1257
|
|
1232
1258
|
if (argc < 1) { // at least the middleware class must be provided.
|
1233
|
-
|
1259
|
+
rb_raise(rb_eArgError, "no middleware class provided");
|
1234
1260
|
}
|
1235
1261
|
mc = argv[0];
|
1236
1262
|
if (T_CLASS != rb_type(mc)) {
|
1237
|
-
|
1263
|
+
rb_raise(rb_eArgError, "the first argument to use must be a class");
|
1238
1264
|
}
|
1239
1265
|
if (NULL == (u = (RUse)AGOO_MALLOC(sizeof(struct _rUse)))) {
|
1240
|
-
|
1266
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for a middleware use.");
|
1241
1267
|
}
|
1242
1268
|
u->clas = mc;
|
1243
1269
|
u->argc = argc;
|
1244
1270
|
if (NULL == (u->argv = (VALUE*)AGOO_MALLOC(sizeof(VALUE) * u->argc))) {
|
1245
|
-
|
1271
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for a middleware use.");
|
1246
1272
|
}
|
1247
1273
|
memcpy(u->argv, argv, argc * sizeof(VALUE));
|
1248
1274
|
u->next = the_rserver.uses;
|
@@ -1283,16 +1309,16 @@ server_init(VALUE mod) {
|
|
1283
1309
|
on_request_id = rb_intern("on_request");
|
1284
1310
|
to_i_id = rb_intern("to_i");
|
1285
1311
|
|
1286
|
-
connect_sym = ID2SYM(rb_intern("CONNECT"));
|
1287
|
-
delete_sym = ID2SYM(rb_intern("DELETE"));
|
1288
|
-
get_sym = ID2SYM(rb_intern("GET"));
|
1289
|
-
head_sym = ID2SYM(rb_intern("HEAD"));
|
1290
|
-
options_sym = ID2SYM(rb_intern("OPTIONS"));
|
1291
|
-
post_sym = ID2SYM(rb_intern("POST"));
|
1292
|
-
put_sym = ID2SYM(rb_intern("PUT"));
|
1293
|
-
patch_sym = ID2SYM(rb_intern("PATCH"));
|
1312
|
+
connect_sym = ID2SYM(rb_intern("CONNECT")); rb_gc_register_address(&connect_sym);
|
1313
|
+
delete_sym = ID2SYM(rb_intern("DELETE")); rb_gc_register_address(&delete_sym);
|
1314
|
+
get_sym = ID2SYM(rb_intern("GET")); rb_gc_register_address(&get_sym);
|
1315
|
+
head_sym = ID2SYM(rb_intern("HEAD")); rb_gc_register_address(&head_sym);
|
1316
|
+
options_sym = ID2SYM(rb_intern("OPTIONS")); rb_gc_register_address(&options_sym);
|
1317
|
+
post_sym = ID2SYM(rb_intern("POST")); rb_gc_register_address(&post_sym);
|
1318
|
+
put_sym = ID2SYM(rb_intern("PUT")); rb_gc_register_address(&put_sym);
|
1319
|
+
patch_sym = ID2SYM(rb_intern("PATCH")); rb_gc_register_address(&patch_sym);
|
1294
1320
|
|
1295
|
-
push_env_key = rb_str_new_cstr("rack.upgrade");
|
1321
|
+
push_env_key = rb_str_new_cstr("rack.upgrade"); rb_gc_register_address(&push_env_key);
|
1296
1322
|
|
1297
1323
|
rserver = Data_Wrap_Struct(rb_cObject, server_mark, NULL, strdup("dummy"));
|
1298
1324
|
rb_gc_register_address(&rserver);
|