agoo 2.15.7 → 2.15.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);