agoo 2.15.7 → 2.15.9

Sign up to get free protection for your applications and to get access to all the features.
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 agoo_shutdown();
39
- extern sig_atomic_t agoo_stop;
38
+ extern void agoo_shutdown();
39
+ extern sig_atomic_t agoo_stop;
40
40
 
41
- static VALUE server_mod = Qundef;
41
+ static VALUE server_mod = Qundef;
42
42
 
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;
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 rserver;
53
+ static VALUE rserver;
54
54
 
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;
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 err500[] = "HTTP/1.1 500 Internal Server Error\r\n";
64
+ static const char err500[] = "HTTP/1.1 500 Internal Server Error\r\n";
65
65
 
66
- static double poll_timeout = 0.1;
67
- struct _rServer the_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 up;
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
- 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
- }
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 err = AGOO_ERR_INIT;
92
- agooBind b = agoo_bind_url(&err, StringValuePtr(rurl));
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
- rb_raise(rb_eArgError, "%s", err.msg);
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
- return err->code;
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
- 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
- }
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
- agooBind b = agoo_bind_port(err, port);
280
+ agooBind b = agoo_bind_port(err, port);
269
281
 
270
- if (AGOO_ERR_OK != err->code) {
271
- rb_raise(rb_eArgError, "%s", err->msg);
272
- }
273
- agoo_server_bind(b);
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
- * - *:ssl_sert* [_String_] filepath to the SSL certificate file.
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 err = AGOO_ERR_INIT;
313
- int port;
314
- const char *root;
315
- VALUE options = Qnil;
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
- rb_raise(rb_eArgError, "Wrong number of arguments to Agoo::Server.configure.");
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
- options = argv[2];
338
+ options = argv[2];
325
339
  }
326
340
  if (AGOO_ERR_OK != agoo_server_setup(&err)) {
327
- rb_raise(rb_eStandardError, "%s", err.msg);
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
- rb_raise(rb_eArgError, "%s", err.msg);
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 bad500[] = "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: ";
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 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);
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
- 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
+ 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
- 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
- }
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
- agoo_log_cat(&agoo_error_cat, "%s: %s", classname, ms);
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 req = (agooReq)(void*)x;
384
- volatile VALUE rr = request_wrap(req);
385
- volatile VALUE rres = response_new();
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
- rb_funcall((VALUE)req->hook->handler, on_request_id, 2, rr, rres);
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 *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;
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
- if (AGOO_ERR_OK != agoo_http_header_ok(&err, ks, klen, vs, vlen)) {
415
- rb_raise(rb_eArgError, "%s", err.msg);
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
- 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);
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 *tp = (agooText*)cb_arg;
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 *sizep = (int*)cb_arg;
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 *tp = (agooText*)cb_arg;
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 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;
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
- return Qfalse;
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
- agoo_queue_wakeup(&agoo_server.con_queue);
487
- return Qfalse;
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
- rb_raise(rb_eArgError, "a rack call() response must be an array of 3 members.");
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
- code = NUM2INT(hv);
509
+ code = NUM2INT(hv);
496
510
  } else {
497
- code = NUM2INT(rb_funcall(hv, to_i_id, 0));
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
- rb_raise(rb_eArgError, "invalid rack call() response status code (%d).", code);
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
- rb_raise(rb_eArgError, "invalid rack call() response headers does not respond to each.");
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
- rb_raise(rb_eArgError, "invalid rack call() response body does not respond to each.");
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
- rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
526
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
513
527
  }
514
528
  if (T_ARRAY == rb_type(bv)) {
515
- int i;
516
- int bcnt = (int)RARRAY_LEN(bv);
529
+ int i;
530
+ int bcnt = (int)RARRAY_LEN(bv);
517
531
 
518
- for (i = 0; i < bcnt; i++) {
519
- bsize += (int)RSTRING_LEN(rb_ary_entry(bv, i));
520
- }
532
+ for (i = 0; i < bcnt; i++) {
533
+ bsize += (int)RSTRING_LEN(rb_ary_entry(bv, i));
534
+ }
521
535
  } else {
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
- }
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
- // 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;
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
- // 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;
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
- 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
- }
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
- bsize = 0;
610
+ bsize = 0;
597
611
  } else {
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
- }
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
- 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
- }
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 req = (agooReq)x;
638
- volatile VALUE rr = request_wrap(req);
639
- volatile VALUE rres = response_new();
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
- rb_funcall((VALUE)req->hook->handler, on_request_id, 2, rr, rres);
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 req = (agooReq)x;
674
+ agooReq req = (agooReq)x;
661
675
 
662
676
  switch (req->method) {
663
677
  case AGOO_ON_MSG:
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;
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
- if (req->up->on_msg && NULL != req->hook) {
670
- volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
683
+ if (req->up->on_msg && NULL != req->hook) {
684
+ volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
671
685
 
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;
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
- 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;
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
- if (NULL != req->hook) {
685
- rb_funcall((VALUE)req->hook->handler, rb_intern("on_shutdown"), 1, (VALUE)req->up->wrap);
686
- }
687
- break;
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
- if (req->up->on_error && NULL != req->hook) {
690
- volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
703
+ if (req->up->on_error && NULL != req->hook) {
704
+ volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
691
705
 
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;
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
- 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;
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
- break;
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
- return;
732
+ return;
719
733
  }
720
734
  switch (req->hook->type) {
721
735
  case BASE_HOOK:
722
- if (gvi) {
723
- rb_thread_call_with_gvl(handle_base, req);
724
- } else {
725
- handle_base(req);
726
- }
727
- break;
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
- if (gvi) {
730
- rb_thread_call_with_gvl(handle_rack, req);
731
- } else {
732
- handle_rack(req);
733
- }
734
- break;
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
- if (gvi) {
737
- rb_thread_call_with_gvl(handle_wab, req);
738
- } else {
739
- handle_wab(req);
740
- }
741
- break;
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
- if (gvi) {
744
- rb_thread_call_with_gvl(handle_push, req);
745
- } else {
746
- handle_push(req);
747
- }
748
- break;
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
- req->hook->func(req);
751
- agoo_queue_wakeup(&agoo_server.con_queue);
752
- break;
764
+ req->hook->func(req);
765
+ agoo_queue_wakeup(&agoo_server.con_queue);
766
+ break;
753
767
  default: {
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;
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 req;
782
+ agooReq req;
769
783
 
770
784
  atomic_fetch_add(&agoo_server.running, 1);
771
785
  while (agoo_server.active) {
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
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 *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"));
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
- agoo_server.loop_max /= the_rserver.worker_cnt;
815
- if (agoo_server.loop_max < 1) {
816
- agoo_server.loop_max = 1;
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
- rb_raise(rb_eIOError, "%s", err.msg);
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
- 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
- }
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
- rb_raise(rb_eStandardError, "%s", err.msg);
868
+ rb_raise(rb_eStandardError, "%s", err.msg);
844
869
  }
845
870
  if (0 >= agoo_server.thread_cnt) {
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
- }
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
- 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 has
873
- // been started yet.
874
- rb_thread_schedule();
875
- if (2 + agoo_server.thread_cnt <= (long)atomic_load(&agoo_server.running)) {
876
- break;
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
- double timeout = dtime() + 2.0;
891
-
892
- while (dtime() < timeout) {
893
- if (0 >= (long)atomic_load(&agoo_server.running)) {
894
- break;
895
- }
896
- dsleep(0.02);
897
- }
898
- AGOO_FREE(the_rserver.eval_threads);
899
- the_rserver.eval_threads = NULL;
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
- agoo_server_shutdown("Agoo", stop_runners);
913
-
914
- if (1 < the_rserver.worker_cnt && getpid() == *the_rserver.worker_pids) {
915
- int i;
916
- int status;
917
- int exit_cnt = 1;
918
- int j;
919
-
920
- for (i = 1; i < the_rserver.worker_cnt; i++) {
921
- kill(the_rserver.worker_pids[i], SIGKILL);
922
- }
923
- for (j = 0; j < 20; j++) {
924
- for (i = 1; i < the_rserver.worker_cnt; i++) {
925
- if (0 == the_rserver.worker_pids[i]) {
926
- continue;
927
- }
928
- if (0 < waitpid(the_rserver.worker_pids[i], &status, WNOHANG)) {
929
- if (WIFEXITED(status)) {
930
- //printf("exited, status=%d for %d\n", agoo_server.worker_pids[i], WEXITSTATUS(status));
931
- the_rserver.worker_pids[i] = 0;
932
- exit_cnt++;
933
- } else if (WIFSIGNALED(status)) {
934
- //printf("*** killed by signal %d for %d\n", agoo_server.worker_pids[i], WTERMSIG(status));
935
- the_rserver.worker_pids[i] = 0;
936
- exit_cnt++;
937
- }
938
- }
939
- }
940
- if (the_rserver.worker_cnt <= exit_cnt) {
941
- break;
942
- }
943
- dsleep(0.2);
944
- }
945
- if (exit_cnt < the_rserver.worker_cnt) {
946
- printf("*-*-* Some workers did not exit.\n");
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 hook;
964
- agooMethod meth = AGOO_ALL;
965
- const char *pat;
966
- ID static_id = rb_intern("static?");
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
- meth = AGOO_CONNECT;
998
+ meth = AGOO_CONNECT;
973
999
  } else if (delete_sym == method) {
974
- meth = AGOO_DELETE;
1000
+ meth = AGOO_DELETE;
975
1001
  } else if (get_sym == method) {
976
- meth = AGOO_GET;
1002
+ meth = AGOO_GET;
977
1003
  } else if (head_sym == method) {
978
- meth = AGOO_HEAD;
1004
+ meth = AGOO_HEAD;
979
1005
  } else if (options_sym == method) {
980
- meth = AGOO_OPTIONS;
1006
+ meth = AGOO_OPTIONS;
981
1007
  } else if (post_sym == method) {
982
- meth = AGOO_POST;
1008
+ meth = AGOO_POST;
983
1009
  } else if (put_sym == method) {
984
- meth = AGOO_PUT;
1010
+ meth = AGOO_PUT;
985
1011
  } else if (patch_sym == method) {
986
- meth = AGOO_PATCH;
1012
+ meth = AGOO_PATCH;
987
1013
  } else if (Qnil == method) {
988
- meth = AGOO_ALL;
1014
+ meth = AGOO_ALL;
989
1015
  } else {
990
- rb_raise(rb_eArgError, "invalid method");
1016
+ rb_raise(rb_eArgError, "invalid method");
991
1017
  }
992
1018
  if (T_STRING == rb_type(handler)) {
993
- handler = resolve_classpath(StringValuePtr(handler), RSTRING_LEN(handler));
1019
+ handler = resolve_classpath(StringValuePtr(handler), RSTRING_LEN(handler));
994
1020
  }
995
1021
  if (rb_respond_to(handler, static_id)) {
996
- if (Qtrue == rb_funcall(handler, static_id, 0)) {
997
- VALUE res = rb_funcall(handler, call_id, 1, Qnil);
998
- VALUE bv;
999
-
1000
- rb_check_type(res, T_ARRAY);
1001
- if (3 != RARRAY_LEN(res)) {
1002
- rb_raise(rb_eArgError, "a rack call() response must be an array of 3 members.");
1003
- }
1004
- bv = rb_ary_entry(res, 2);
1005
- if (T_ARRAY == rb_type(bv)) {
1006
- int i;
1007
- int bcnt = (int)RARRAY_LEN(bv);
1008
- agooText t = agoo_text_allocate(1024);
1009
- struct _agooErr err = AGOO_ERR_INIT;
1010
- VALUE v;
1011
-
1012
- if (NULL == t) {
1013
- rb_raise(rb_eArgError, "failed to allocate response.");
1014
- }
1015
- for (i = 0; i < bcnt; i++) {
1016
- v = rb_ary_entry(bv, i);
1017
- t = agoo_text_append(t, StringValuePtr(v), (int)RSTRING_LEN(v));
1018
- }
1019
- if (NULL == t) {
1020
- rb_raise(rb_eNoMemError, "Failed to allocate memory for a response.");
1021
- }
1022
- if (NULL == agoo_page_immutable(&err, pat, t->text, (int)t->len)) {
1023
- rb_raise(rb_eArgError, "%s", err.msg);
1024
- }
1025
- agoo_text_release(t);
1026
-
1027
- return Qnil;
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
- RUse u;
1058
+ RUse u;
1033
1059
 
1034
- for (u = the_rserver.uses; NULL != u; u = u->next) {
1035
- u->argv[0] = handler;
1036
- handler = rb_funcall2(u->clas, rb_intern("new"), u->argc, u->argv);
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
- rb_raise(rb_eStandardError, "out of memory.");
1066
+ rb_raise(rb_eStandardError, "out of memory.");
1041
1067
  } else {
1042
- agooHook h;
1043
- agooHook prev = NULL;
1044
-
1045
- for (h = agoo_server.hooks; NULL != h; h = h->next) {
1046
- prev = h;
1047
- }
1048
- if (NULL != prev) {
1049
- prev->next = hook;
1050
- } else {
1051
- agoo_server.hooks = hook;
1052
- }
1053
- rb_gc_register_address((VALUE*)&hook->handler);
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
- rb_raise(rb_eStandardError, "out of memory.");
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 err = AGOO_ERR_INIT;
1110
+ struct _agooErr err = AGOO_ERR_INIT;
1085
1111
 
1086
1112
  if (AGOO_ERR_OK != mime_set(&err, StringValuePtr(suffix), StringValuePtr(type))) {
1087
- rb_raise(rb_eArgError, "%s", err.msg);
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 err = AGOO_ERR_INIT;
1103
- agooGroup g;
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
- int i;
1110
- int dcnt = (int)RARRAY_LEN(dirs);
1111
- VALUE entry;
1112
-
1113
- for (i = dcnt - 1; 0 <= i; i--) {
1114
- entry = rb_ary_entry(dirs, i);
1115
- if (T_STRING != rb_type(entry)) {
1116
- entry = rb_funcall(entry, rb_intern("to_s"), 0);
1117
- }
1118
- if (NULL == agoo_group_add(&err, g, StringValuePtr(entry))) {
1119
- rb_raise(rb_eStandardError, "%s", err.msg);
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 err = AGOO_ERR_INIT;
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
- rb_raise(rb_eArgError, "%s", err.msg);
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 err = AGOO_ERR_INIT;
1195
+ struct _agooErr err = AGOO_ERR_INIT;
1170
1196
 
1171
1197
  switch(rb_type(host)) {
1172
1198
  case RUBY_T_STRING:
1173
- rb_check_type(path, T_STRING);
1174
- if (AGOO_ERR_OK != agoo_domain_add(&err, rb_string_value_ptr((VALUE*)&host), rb_string_value_ptr((VALUE*)&path))) {
1175
- rb_raise(rb_eArgError, "%s", err.msg);
1176
- }
1177
- break;
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
- volatile VALUE v = rb_funcall(host, rb_intern("inspect"), 0);
1180
- char rx[1024];
1181
-
1182
- if (sizeof(rx) <= (size_t)RSTRING_LEN(v)) {
1183
- rb_raise(rb_eArgError, "host Regex limited to %ld characters", sizeof(rx));
1184
- }
1185
- strcpy(rx, rb_string_value_ptr((VALUE*)&v) + 1);
1186
- rx[RSTRING_LEN(v) - 2] = '\0';
1187
- if (AGOO_ERR_OK != agoo_domain_add_regex(&err, rx, rb_string_value_ptr((VALUE*)&path))) {
1188
- rb_raise(rb_eArgError, "%s", err.msg);
1189
- }
1190
- break;
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
- rb_raise(rb_eArgError, "host must be a String or Regex");
1194
- break;
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
- agoo_server.rack_early_hints = true;
1235
+ agoo_server.rack_early_hints = true;
1210
1236
  } else if (Qfalse == on) {
1211
- agoo_server.rack_early_hints = false;
1237
+ agoo_server.rack_early_hints = false;
1212
1238
  } else if (Qnil == on) {
1213
- on = agoo_server.rack_early_hints ? Qtrue : Qfalse;
1239
+ on = agoo_server.rack_early_hints ? Qtrue : Qfalse;
1214
1240
  } else {
1215
- rb_raise(rb_eArgError, "rack_early_hints can only be set to true or false");
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 mc;
1230
- RUse u;
1255
+ VALUE mc;
1256
+ RUse u;
1231
1257
 
1232
1258
  if (argc < 1) { // at least the middleware class must be provided.
1233
- rb_raise(rb_eArgError, "no middleware class provided");
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
- rb_raise(rb_eArgError, "the first argument to use must be a class");
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
- rb_raise(rb_eNoMemError, "Failed to allocate memory for a middleware use.");
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
- rb_raise(rb_eNoMemError, "Failed to allocate memory for a middleware use.");
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")); rb_gc_register_address(&connect_sym);
1287
- delete_sym = ID2SYM(rb_intern("DELETE")); rb_gc_register_address(&delete_sym);
1288
- get_sym = ID2SYM(rb_intern("GET")); rb_gc_register_address(&get_sym);
1289
- head_sym = ID2SYM(rb_intern("HEAD")); rb_gc_register_address(&head_sym);
1290
- options_sym = ID2SYM(rb_intern("OPTIONS")); rb_gc_register_address(&options_sym);
1291
- post_sym = ID2SYM(rb_intern("POST")); rb_gc_register_address(&post_sym);
1292
- put_sym = ID2SYM(rb_intern("PUT")); rb_gc_register_address(&put_sym);
1293
- patch_sym = ID2SYM(rb_intern("PATCH")); rb_gc_register_address(&patch_sym);
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"); rb_gc_register_address(&push_env_key);
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);