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