agoo 1.2.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of agoo might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +11 -9
- data/ext/agoo/agoo.c +45 -0
- data/ext/agoo/base64.c +107 -0
- data/ext/agoo/base64.h +15 -0
- data/ext/agoo/ccache.c +301 -0
- data/ext/agoo/ccache.h +53 -0
- data/ext/agoo/con.c +522 -82
- data/ext/agoo/con.h +7 -5
- data/ext/agoo/debug.c +121 -7
- data/ext/agoo/debug.h +11 -6
- data/ext/agoo/error_stream.c +5 -6
- data/ext/agoo/error_stream.h +1 -1
- data/ext/agoo/extconf.rb +2 -1
- data/ext/agoo/hook.c +4 -4
- data/ext/agoo/hook.h +1 -0
- data/ext/agoo/http.c +2 -2
- data/ext/agoo/http.h +2 -0
- data/ext/agoo/log.c +604 -219
- data/ext/agoo/log.h +20 -7
- data/ext/agoo/page.c +20 -23
- data/ext/agoo/page.h +2 -0
- data/ext/agoo/pub.c +111 -0
- data/ext/agoo/pub.h +40 -0
- data/ext/agoo/queue.c +2 -2
- data/ext/agoo/rack_logger.c +15 -71
- data/ext/agoo/rack_logger.h +1 -1
- data/ext/agoo/request.c +96 -21
- data/ext/agoo/request.h +23 -12
- data/ext/agoo/res.c +5 -2
- data/ext/agoo/res.h +4 -0
- data/ext/agoo/response.c +13 -12
- data/ext/agoo/response.h +1 -2
- data/ext/agoo/server.c +290 -428
- data/ext/agoo/server.h +10 -10
- data/ext/agoo/sha1.c +148 -0
- data/ext/agoo/sha1.h +10 -0
- data/ext/agoo/sse.c +26 -0
- data/ext/agoo/sse.h +12 -0
- data/ext/agoo/sub.c +111 -0
- data/ext/agoo/sub.h +36 -0
- data/ext/agoo/subscription.c +54 -0
- data/ext/agoo/subscription.h +18 -0
- data/ext/agoo/text.c +26 -4
- data/ext/agoo/text.h +2 -0
- data/ext/agoo/types.h +13 -0
- data/ext/agoo/upgraded.c +148 -0
- data/ext/agoo/upgraded.h +13 -0
- data/ext/agoo/websocket.c +248 -0
- data/ext/agoo/websocket.h +27 -0
- data/lib/agoo/version.rb +1 -1
- data/lib/rack/handler/agoo.rb +13 -6
- data/test/base_handler_test.rb +24 -22
- data/test/log_test.rb +146 -199
- data/test/rack_handler_test.rb +19 -20
- data/test/static_test.rb +30 -28
- metadata +23 -7
- data/test/rrr/test.rb +0 -26
- data/test/tests.rb +0 -8
data/ext/agoo/rack_logger.h
CHANGED
data/ext/agoo/request.c
CHANGED
@@ -19,6 +19,7 @@ static VALUE get_val = Qundef;
|
|
19
19
|
static VALUE head_val = Qundef;
|
20
20
|
static VALUE http_val = Qundef;
|
21
21
|
static VALUE options_val = Qundef;
|
22
|
+
static VALUE patch_val = Qundef;
|
22
23
|
static VALUE path_info_val = Qundef;
|
23
24
|
static VALUE post_val = Qundef;
|
24
25
|
static VALUE put_val = Qundef;
|
@@ -29,6 +30,7 @@ static VALUE rack_logger_val = Qundef;
|
|
29
30
|
static VALUE rack_multiprocess_val = Qundef;
|
30
31
|
static VALUE rack_multithread_val = Qundef;
|
31
32
|
static VALUE rack_run_once_val = Qundef;
|
33
|
+
static VALUE rack_upgrade_val = Qundef;
|
32
34
|
static VALUE rack_url_scheme_val = Qundef;
|
33
35
|
static VALUE rack_version_val = Qundef;
|
34
36
|
static VALUE rack_version_val_val = Qundef;
|
@@ -38,12 +40,33 @@ static VALUE server_name_val = Qundef;
|
|
38
40
|
static VALUE server_port_val = Qundef;
|
39
41
|
static VALUE slash_val = Qundef;
|
40
42
|
|
43
|
+
static VALUE sse_sym;
|
44
|
+
static VALUE websocket_sym;
|
45
|
+
|
41
46
|
static VALUE stringio_class = Qundef;
|
42
47
|
|
43
48
|
static ID new_id;
|
44
49
|
|
45
50
|
static const char content_type[] = "Content-Type";
|
46
51
|
static const char content_length[] = "Content-Length";
|
52
|
+
static const char connection_key[] = "Connection";
|
53
|
+
static const char upgrade_key[] = "Upgrade";
|
54
|
+
static const char websocket_val[] = "websocket";
|
55
|
+
static const char accept_key[] = "Accept";
|
56
|
+
static const char event_stream_val[] = "text/event-stream";
|
57
|
+
|
58
|
+
Req
|
59
|
+
request_create(size_t mlen) {
|
60
|
+
size_t size = mlen + sizeof(struct _Req) - 7;
|
61
|
+
Req req = (Req)malloc(size);
|
62
|
+
|
63
|
+
if (NULL != req) {
|
64
|
+
DEBUG_ALLOC(mem_req, req);
|
65
|
+
memset(req, 0, size);
|
66
|
+
req->mlen = mlen;
|
67
|
+
}
|
68
|
+
return req;
|
69
|
+
}
|
47
70
|
|
48
71
|
static VALUE
|
49
72
|
req_method(Req r) {
|
@@ -60,6 +83,7 @@ req_method(Req r) {
|
|
60
83
|
case OPTIONS: m = options_val; break;
|
61
84
|
case POST: m = post_val; break;
|
62
85
|
case PUT: m = put_val; break;
|
86
|
+
case PATCH: m = patch_val; break;
|
63
87
|
default: m = Qnil; break;
|
64
88
|
}
|
65
89
|
return m;
|
@@ -218,6 +242,26 @@ server_port(VALUE self) {
|
|
218
242
|
return req_server_port((Req)DATA_PTR(self));
|
219
243
|
}
|
220
244
|
|
245
|
+
static VALUE
|
246
|
+
req_rack_upgrade(Req r) {
|
247
|
+
switch (r->upgrade) {
|
248
|
+
case UP_WS: return websocket_sym;
|
249
|
+
case UP_SSE: return sse_sym;
|
250
|
+
default: return Qnil;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
/* Document-method: rack_upgrade?
|
255
|
+
*
|
256
|
+
* call-seq: rack_upgrade?()
|
257
|
+
*
|
258
|
+
* Returns the URL scheme or either _http_ or _https_ as a string.
|
259
|
+
*/
|
260
|
+
static VALUE
|
261
|
+
rack_upgrade(VALUE self) {
|
262
|
+
return req_rack_upgrade((Req)DATA_PTR(self));
|
263
|
+
}
|
264
|
+
|
221
265
|
/* Document-method: rack_version
|
222
266
|
*
|
223
267
|
* call-seq: rack_version()
|
@@ -271,7 +315,7 @@ rack_input(VALUE self) {
|
|
271
315
|
|
272
316
|
static VALUE
|
273
317
|
req_rack_errors(Req r) {
|
274
|
-
return error_stream_new(
|
318
|
+
return error_stream_new();
|
275
319
|
}
|
276
320
|
|
277
321
|
/* Document-method: rack_errors
|
@@ -291,7 +335,7 @@ req_rack_multithread(Req r) {
|
|
291
335
|
if (NULL == r) {
|
292
336
|
rb_raise(rb_eArgError, "Request is no longer valid.");
|
293
337
|
}
|
294
|
-
if (
|
338
|
+
if (1 < the_server.thread_cnt) {
|
295
339
|
return Qtrue;
|
296
340
|
}
|
297
341
|
return Qfalse;
|
@@ -354,13 +398,16 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
|
|
354
398
|
|
355
399
|
static void
|
356
400
|
fill_headers(Req r, VALUE hash) {
|
357
|
-
char
|
358
|
-
char
|
359
|
-
char
|
360
|
-
char
|
361
|
-
char
|
362
|
-
char
|
363
|
-
|
401
|
+
char *h = r->header.start;
|
402
|
+
char *end = h + r->header.len + 1; // +1 for last \r
|
403
|
+
char *key = h;
|
404
|
+
char *kend = key;
|
405
|
+
char *val = NULL;
|
406
|
+
char *vend;
|
407
|
+
int klen;
|
408
|
+
bool upgrade = false;
|
409
|
+
bool ws = false;
|
410
|
+
|
364
411
|
if (NULL == r) {
|
365
412
|
rb_raise(rb_eArgError, "Request is no longer valid.");
|
366
413
|
}
|
@@ -370,22 +417,40 @@ fill_headers(Req r, VALUE hash) {
|
|
370
417
|
kend = h;
|
371
418
|
val = h + 1;
|
372
419
|
break;
|
373
|
-
case ' ':
|
374
|
-
if (NULL != val) {
|
375
|
-
val++;
|
376
|
-
} else {
|
377
|
-
// TBD handle trailing spaces as well
|
378
|
-
key++;
|
379
|
-
}
|
380
|
-
break;
|
381
420
|
case '\r':
|
382
421
|
if (NULL != val) {
|
422
|
+
for (; ' ' == *val; val++) {
|
423
|
+
}
|
383
424
|
vend = h;
|
384
425
|
}
|
426
|
+
if (NULL != key) {
|
427
|
+
for (; ' ' == *key; key++) {
|
428
|
+
}
|
429
|
+
}
|
385
430
|
if ('\n' == *(h + 1)) {
|
386
431
|
h++;
|
387
432
|
}
|
388
|
-
|
433
|
+
klen = (int)(kend - key);
|
434
|
+
add_header_value(hash, key, klen, val, (int)(vend - val));
|
435
|
+
if (sizeof(upgrade_key) - 1 == klen && 0 == strncasecmp(key, upgrade_key, sizeof(upgrade_key) - 1)) {
|
436
|
+
if (sizeof(websocket_val) - 1 == vend - val &&
|
437
|
+
0 == strncasecmp(val, websocket_val, sizeof(websocket_val) - 1)) {
|
438
|
+
ws = true;
|
439
|
+
}
|
440
|
+
} else if (sizeof(connection_key) - 1 == klen && 0 == strncasecmp(key, connection_key, sizeof(connection_key) - 1)) {
|
441
|
+
char buf[1024];
|
442
|
+
|
443
|
+
strncpy(buf, val, vend - val);
|
444
|
+
buf[sizeof(buf)-1] = '\0';
|
445
|
+
if (NULL != strstr(buf, upgrade_key)) {
|
446
|
+
upgrade = true;
|
447
|
+
}
|
448
|
+
} else if (sizeof(accept_key) - 1 == klen && 0 == strncasecmp(key, accept_key, sizeof(accept_key) - 1)) {
|
449
|
+
if (sizeof(event_stream_val) - 1 == vend - val &&
|
450
|
+
0 == strncasecmp(val, event_stream_val, sizeof(event_stream_val) - 1)) {
|
451
|
+
r->upgrade = UP_SSE;
|
452
|
+
}
|
453
|
+
}
|
389
454
|
key = h + 1;
|
390
455
|
kend = NULL;
|
391
456
|
val = NULL;
|
@@ -395,6 +460,9 @@ fill_headers(Req r, VALUE hash) {
|
|
395
460
|
break;
|
396
461
|
}
|
397
462
|
}
|
463
|
+
if (upgrade && ws) {
|
464
|
+
r->upgrade = UP_WS;
|
465
|
+
}
|
398
466
|
}
|
399
467
|
|
400
468
|
/* Document-method: headers
|
@@ -439,7 +507,7 @@ body(VALUE self) {
|
|
439
507
|
|
440
508
|
static VALUE
|
441
509
|
req_rack_logger(Req req) {
|
442
|
-
return rack_logger_new(
|
510
|
+
return rack_logger_new();
|
443
511
|
}
|
444
512
|
|
445
513
|
/* Document-method: rack_logger
|
@@ -484,6 +552,7 @@ request_env(Req req) {
|
|
484
552
|
rb_hash_aset(env, rack_multiprocess_val, Qfalse);
|
485
553
|
rb_hash_aset(env, rack_run_once_val, Qfalse);
|
486
554
|
rb_hash_aset(env, rack_logger_val, req_rack_logger(req));
|
555
|
+
rb_hash_aset(env, rack_upgrade_val, req_rack_upgrade(req));
|
487
556
|
|
488
557
|
return env;
|
489
558
|
}
|
@@ -520,7 +589,7 @@ to_s(VALUE self) {
|
|
520
589
|
|
521
590
|
void
|
522
591
|
request_destroy(Req req) {
|
523
|
-
DEBUG_FREE(mem_req)
|
592
|
+
DEBUG_FREE(mem_req, req)
|
524
593
|
free(req);
|
525
594
|
}
|
526
595
|
|
@@ -557,6 +626,7 @@ request_init(VALUE mod) {
|
|
557
626
|
rb_define_method(req_class, "rack_multithread", rack_multithread, 0);
|
558
627
|
rb_define_method(req_class, "rack_multiprocess", rack_multiprocess, 0);
|
559
628
|
rb_define_method(req_class, "rack_run_once", rack_run_once, 0);
|
629
|
+
rb_define_method(req_class, "rack_upgrade?", rack_upgrade, 0);
|
560
630
|
rb_define_method(req_class, "headers", headers, 0);
|
561
631
|
rb_define_method(req_class, "body", body, 0);
|
562
632
|
rb_define_method(req_class, "rack_logger", rack_logger, 0);
|
@@ -579,6 +649,7 @@ request_init(VALUE mod) {
|
|
579
649
|
head_val = rb_str_new_cstr("HEAD"); rb_gc_register_address(&head_val);
|
580
650
|
http_val = rb_str_new_cstr("http"); rb_gc_register_address(&http_val);
|
581
651
|
options_val = rb_str_new_cstr("OPTIONS"); rb_gc_register_address(&options_val);
|
652
|
+
patch_val = rb_str_new_cstr("PATCH"); rb_gc_register_address(&patch_val);
|
582
653
|
path_info_val = rb_str_new_cstr("PATH_INFO"); rb_gc_register_address(&path_info_val);
|
583
654
|
post_val = rb_str_new_cstr("POST"); rb_gc_register_address(&post_val);
|
584
655
|
put_val = rb_str_new_cstr("PUT"); rb_gc_register_address(&put_val);
|
@@ -587,8 +658,9 @@ request_init(VALUE mod) {
|
|
587
658
|
rack_input_val = rb_str_new_cstr("rack.input"); rb_gc_register_address(&rack_input_val);
|
588
659
|
rack_logger_val = rb_str_new_cstr("rack.logger"); rb_gc_register_address(&rack_logger_val);
|
589
660
|
rack_multiprocess_val = rb_str_new_cstr("rack.multiprocess");rb_gc_register_address(&rack_multiprocess_val);
|
590
|
-
rack_multithread_val = rb_str_new_cstr("rack.multithread");rb_gc_register_address(&rack_multithread_val);
|
661
|
+
rack_multithread_val = rb_str_new_cstr("rack.multithread"); rb_gc_register_address(&rack_multithread_val);
|
591
662
|
rack_run_once_val = rb_str_new_cstr("rack.run_once"); rb_gc_register_address(&rack_run_once_val);
|
663
|
+
rack_upgrade_val = rb_str_new_cstr("rack.upgrade?"); rb_gc_register_address(&rack_upgrade_val);
|
592
664
|
rack_url_scheme_val = rb_str_new_cstr("rack.url_scheme"); rb_gc_register_address(&rack_url_scheme_val);
|
593
665
|
rack_version_val = rb_str_new_cstr("rack.version"); rb_gc_register_address(&rack_version_val);
|
594
666
|
request_method_val = rb_str_new_cstr("REQUEST_METHOD"); rb_gc_register_address(&request_method_val);
|
@@ -596,4 +668,7 @@ request_init(VALUE mod) {
|
|
596
668
|
server_name_val = rb_str_new_cstr("SERVER_NAME"); rb_gc_register_address(&server_name_val);
|
597
669
|
server_port_val = rb_str_new_cstr("SERVER_PORT"); rb_gc_register_address(&server_port_val);
|
598
670
|
slash_val = rb_str_new_cstr("/"); rb_gc_register_address(&slash_val);
|
671
|
+
|
672
|
+
sse_sym = ID2SYM(rb_intern("sse")); rb_gc_register_address(&sse_sym);
|
673
|
+
websocket_sym = ID2SYM(rb_intern("websocket")); rb_gc_register_address(&websocket_sym);
|
599
674
|
}
|
data/ext/agoo/request.h
CHANGED
@@ -3,32 +3,43 @@
|
|
3
3
|
#ifndef __AGOO_REQUEST_H__
|
4
4
|
#define __AGOO_REQUEST_H__
|
5
5
|
|
6
|
+
#include <stdint.h>
|
7
|
+
|
6
8
|
#include <ruby.h>
|
7
9
|
|
8
10
|
#include "hook.h"
|
9
11
|
#include "res.h"
|
10
|
-
#include "server.h"
|
11
12
|
#include "types.h"
|
12
13
|
|
14
|
+
struct _Server;
|
15
|
+
|
16
|
+
typedef enum {
|
17
|
+
UP_NONE = '\0',
|
18
|
+
UP_WS = 'W',
|
19
|
+
UP_SSE = 'S',
|
20
|
+
} Upgrade;
|
21
|
+
|
13
22
|
typedef struct _Str {
|
14
23
|
char *start;
|
15
24
|
unsigned int len;
|
16
25
|
} *Str;
|
17
26
|
|
18
27
|
typedef struct _Req {
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
struct _Str
|
23
|
-
struct _Str
|
24
|
-
struct _Str
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
Method method;
|
29
|
+
Upgrade upgrade;
|
30
|
+
uint64_t cid;
|
31
|
+
struct _Str path;
|
32
|
+
struct _Str query;
|
33
|
+
struct _Str header;
|
34
|
+
struct _Str body;
|
35
|
+
VALUE handler;
|
36
|
+
HookType handler_type;
|
37
|
+
Res res;
|
38
|
+
size_t mlen; // allocated msg length
|
39
|
+
char msg[8]; // expanded to be full message
|
30
40
|
} *Req;
|
31
41
|
|
42
|
+
extern Req request_create(size_t mlen);
|
32
43
|
extern void request_init(VALUE mod);
|
33
44
|
extern VALUE request_wrap(Req req);
|
34
45
|
extern VALUE request_env(Req req);
|
data/ext/agoo/res.c
CHANGED
@@ -10,10 +10,13 @@ res_create() {
|
|
10
10
|
Res res = (Res)malloc(sizeof(struct _Res));
|
11
11
|
|
12
12
|
if (NULL != res) {
|
13
|
-
DEBUG_ALLOC(mem_res)
|
13
|
+
DEBUG_ALLOC(mem_res, res)
|
14
14
|
res->next = NULL;
|
15
15
|
atomic_init(&res->message, NULL);
|
16
|
+
res->con_kind = CON_HTTP;
|
16
17
|
res->close = false;
|
18
|
+
res->ping = false;
|
19
|
+
res->pong = false;
|
17
20
|
}
|
18
21
|
return res;
|
19
22
|
}
|
@@ -26,7 +29,7 @@ res_destroy(Res res) {
|
|
26
29
|
if (NULL != message) {
|
27
30
|
text_release(message);
|
28
31
|
}
|
29
|
-
DEBUG_FREE(mem_res)
|
32
|
+
DEBUG_FREE(mem_res, res)
|
30
33
|
free(res);
|
31
34
|
}
|
32
35
|
}
|
data/ext/agoo/res.h
CHANGED
@@ -9,11 +9,15 @@
|
|
9
9
|
#include <ruby.h>
|
10
10
|
|
11
11
|
#include "text.h"
|
12
|
+
#include "types.h"
|
12
13
|
|
13
14
|
typedef struct _Res {
|
14
15
|
struct _Res *next;
|
15
16
|
_Atomic(Text) message;
|
17
|
+
ConKind con_kind;
|
16
18
|
bool close;
|
19
|
+
bool ping;
|
20
|
+
bool pong;
|
17
21
|
} *Res;
|
18
22
|
|
19
23
|
extern Res res_create();
|
data/ext/agoo/response.c
CHANGED
@@ -52,23 +52,23 @@ response_free(void *ptr) {
|
|
52
52
|
|
53
53
|
while (NULL != (h = res->headers)) {
|
54
54
|
res->headers = h->next;
|
55
|
-
DEBUG_FREE(mem_header)
|
55
|
+
DEBUG_FREE(mem_header, h);
|
56
|
+
// TBD
|
56
57
|
xfree(h);
|
57
58
|
}
|
58
|
-
DEBUG_FREE(mem_res_body);
|
59
|
-
DEBUG_FREE(mem_response);
|
59
|
+
DEBUG_FREE(mem_res_body, res->body);
|
60
|
+
DEBUG_FREE(mem_response, ptr);
|
60
61
|
free(res->body); // allocated with strdup
|
61
62
|
xfree(ptr);
|
62
63
|
}
|
63
64
|
|
64
65
|
VALUE
|
65
|
-
response_new(
|
66
|
+
response_new( ) {
|
66
67
|
Response res = ALLOC(struct _Response);
|
67
68
|
|
68
|
-
DEBUG_ALLOC(mem_response)
|
69
|
+
DEBUG_ALLOC(mem_response, res)
|
69
70
|
memset(res, 0, sizeof(struct _Response));
|
70
71
|
res->code = 200;
|
71
|
-
res->server = server;
|
72
72
|
|
73
73
|
return Data_Wrap_Struct(res_class, NULL, response_free, res);
|
74
74
|
}
|
@@ -85,7 +85,7 @@ to_s(VALUE self) {
|
|
85
85
|
int len = response_len(res);
|
86
86
|
char *s = ALLOC_N(char, len + 1);
|
87
87
|
|
88
|
-
DEBUG_ALLOC(mem_to_s)
|
88
|
+
DEBUG_ALLOC(mem_to_s, s)
|
89
89
|
response_fill(res, s);
|
90
90
|
|
91
91
|
return rb_str_new(s, len);
|
@@ -133,10 +133,11 @@ body_set(VALUE self, VALUE val) {
|
|
133
133
|
|
134
134
|
if (T_STRING == rb_type(val)) {
|
135
135
|
res->body = strdup(StringValuePtr(val));
|
136
|
-
DEBUG_ALLOC(mem_res_body)
|
136
|
+
DEBUG_ALLOC(mem_res_body, res->body)
|
137
137
|
res->blen = (int)RSTRING_LEN(val);
|
138
138
|
} else {
|
139
|
-
|
139
|
+
rb_raise(rb_eArgError, "Expected a string");
|
140
|
+
// TBD use Oj to encode val
|
140
141
|
}
|
141
142
|
return Qnil;
|
142
143
|
}
|
@@ -215,7 +216,7 @@ head_set(VALUE self, VALUE key, VALUE val) {
|
|
215
216
|
} else {
|
216
217
|
prev->next = h->next;
|
217
218
|
}
|
218
|
-
DEBUG_FREE(mem_header)
|
219
|
+
DEBUG_FREE(mem_header, h);
|
219
220
|
xfree(h);
|
220
221
|
break;
|
221
222
|
}
|
@@ -227,12 +228,12 @@ head_set(VALUE self, VALUE key, VALUE val) {
|
|
227
228
|
vs = StringValuePtr(val);
|
228
229
|
vlen = (int)RSTRING_LEN(val);
|
229
230
|
|
230
|
-
if (
|
231
|
+
if (the_server.pedantic) {
|
231
232
|
http_header_ok(ks, klen, vs, vlen);
|
232
233
|
}
|
233
234
|
hlen = klen + vlen + 4;
|
234
235
|
h = (Header)ALLOC_N(char, sizeof(struct _Header) - 8 + hlen + 1);
|
235
|
-
DEBUG_ALLOC(mem_header)
|
236
|
+
DEBUG_ALLOC(mem_header, h)
|
236
237
|
|
237
238
|
h->next = NULL;
|
238
239
|
h->len = hlen;
|
data/ext/agoo/response.h
CHANGED
@@ -22,12 +22,11 @@ typedef struct _Response {
|
|
22
22
|
Header headers;
|
23
23
|
int blen;
|
24
24
|
char *body;
|
25
|
-
Server server;
|
26
25
|
} *Response;
|
27
26
|
|
28
27
|
extern void response_init(VALUE mod);
|
29
28
|
|
30
|
-
extern VALUE response_new(
|
29
|
+
extern VALUE response_new();
|
31
30
|
extern Text response_text(VALUE self);
|
32
31
|
|
33
32
|
#endif // __AGOO_RESPONSE_H__
|
data/ext/agoo/server.c
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
#include <netdb.h>
|
7
7
|
#include <netinet/tcp.h>
|
8
8
|
#include <poll.h>
|
9
|
-
#include <signal.h>
|
10
9
|
#include <stdarg.h>
|
11
10
|
#include <stdio.h>
|
12
11
|
#include <stdlib.h>
|
@@ -19,6 +18,7 @@
|
|
19
18
|
|
20
19
|
#include <ruby.h>
|
21
20
|
#include <ruby/thread.h>
|
21
|
+
#include <ruby/encoding.h>
|
22
22
|
|
23
23
|
#include "con.h"
|
24
24
|
#include "debug.h"
|
@@ -28,8 +28,14 @@
|
|
28
28
|
#include "response.h"
|
29
29
|
#include "request.h"
|
30
30
|
#include "server.h"
|
31
|
+
#include "sse.h"
|
32
|
+
#include "sub.h"
|
33
|
+
#include "upgraded.h"
|
34
|
+
#include "websocket.h"
|
31
35
|
|
32
|
-
|
36
|
+
extern void agoo_shutdown();
|
37
|
+
|
38
|
+
static VALUE server_mod = Qundef;
|
33
39
|
|
34
40
|
static VALUE connect_sym;
|
35
41
|
static VALUE delete_sym;
|
@@ -37,102 +43,79 @@ static VALUE get_sym;
|
|
37
43
|
static VALUE head_sym;
|
38
44
|
static VALUE options_sym;
|
39
45
|
static VALUE post_sym;
|
46
|
+
static VALUE push_env_key;
|
40
47
|
static VALUE put_sym;
|
41
48
|
|
42
49
|
static ID call_id;
|
43
50
|
static ID each_id;
|
51
|
+
static ID on_close_id;
|
52
|
+
static ID on_drained_id;
|
53
|
+
static ID on_message_id;
|
44
54
|
static ID on_request_id;
|
45
55
|
static ID to_i_id;
|
46
56
|
|
47
|
-
static
|
57
|
+
static const char err500[] = "HTTP/1.1 500 Internal Server Error\r\n";
|
48
58
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
log_cat(&
|
55
|
-
|
56
|
-
if (
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
59
|
+
struct _Server the_server = {false};
|
60
|
+
|
61
|
+
void
|
62
|
+
server_shutdown() {
|
63
|
+
if (the_server.inited) {
|
64
|
+
log_cat(&info_cat, "Agoo shutting down.");
|
65
|
+
the_server.inited = false;
|
66
|
+
if (the_server.active) {
|
67
|
+
the_server.active = false;
|
68
|
+
if (0 != the_server.listen_thread) {
|
69
|
+
pthread_join(the_server.listen_thread, NULL);
|
70
|
+
the_server.listen_thread = 0;
|
71
|
+
}
|
72
|
+
if (0 != the_server.con_thread) {
|
73
|
+
pthread_join(the_server.con_thread, NULL);
|
74
|
+
the_server.con_thread = 0;
|
75
|
+
}
|
76
|
+
sub_cleanup(&the_server.sub_cache);
|
77
|
+
cc_cleanup(&the_server.con_cache);
|
78
|
+
// The preferred method to of waiting for the ruby threads would
|
79
|
+
// be either a join or even a kill but since we may not have the
|
80
|
+
// gvl here that would cause a segfault. Instead we set a timeout
|
81
|
+
// and wait for the running counter to drop to zero.
|
82
|
+
if (NULL != the_server.eval_threads) {
|
83
|
+
double timeout = dtime() + 2.0;
|
84
|
+
|
85
|
+
while (dtime() < timeout) {
|
86
|
+
if (0 >= atomic_load(&the_server.running)) {
|
87
|
+
break;
|
88
|
+
}
|
89
|
+
dsleep(0.02);
|
75
90
|
}
|
76
|
-
|
91
|
+
DEBUG_FREE(mem_eval_threads, the_server.eval_threads);
|
92
|
+
free(the_server.eval_threads); // TBD use regular malloc and free
|
93
|
+
the_server.eval_threads = NULL;
|
77
94
|
}
|
78
|
-
|
79
|
-
|
80
|
-
server->eval_threads = NULL;
|
81
|
-
}
|
82
|
-
while (NULL != server->hooks) {
|
83
|
-
Hook h = server->hooks;
|
95
|
+
while (NULL != the_server.hooks) {
|
96
|
+
Hook h = the_server.hooks;
|
84
97
|
|
85
|
-
|
86
|
-
|
98
|
+
the_server.hooks = h->next;
|
99
|
+
hook_destroy(h);
|
100
|
+
}
|
87
101
|
}
|
88
|
-
queue_cleanup(&
|
89
|
-
|
90
|
-
|
102
|
+
queue_cleanup(&the_server.con_queue);
|
103
|
+
queue_cleanup(&the_server.pub_queue);
|
104
|
+
queue_cleanup(&the_server.eval_queue);
|
105
|
+
cache_cleanup(&the_server.pages);
|
106
|
+
http_cleanup();
|
91
107
|
}
|
92
108
|
}
|
93
109
|
|
94
|
-
static void
|
95
|
-
sig_handler(int sig) {
|
96
|
-
if (NULL != the_server) {
|
97
|
-
shutdown_server(the_server);
|
98
|
-
}
|
99
|
-
// Use exit instead of rb_exit as rb_exit segfaults most of the time.
|
100
|
-
//rb_exit(0);
|
101
|
-
exit(0);
|
102
|
-
}
|
103
|
-
|
104
|
-
static void
|
105
|
-
server_free(void *ptr) {
|
106
|
-
shutdown_server((Server)ptr);
|
107
|
-
// Commented out for now as it causes a segfault later. Some thread seems
|
108
|
-
//to be pointing at it even though they have exited so live with a memory
|
109
|
-
//leak that only shows up when the program exits.
|
110
|
-
//xfree(ptr);
|
111
|
-
DEBUG_FREE(mem_server)
|
112
|
-
the_server = NULL;
|
113
|
-
}
|
114
|
-
|
115
110
|
static int
|
116
|
-
configure(Err err,
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
log_cat_reg(&s->log, &s->error_cat, "ERROR", ERROR, RED, true);
|
125
|
-
log_cat_reg(&s->log, &s->warn_cat, "WARN", WARN, YELLOW, true);
|
126
|
-
log_cat_reg(&s->log, &s->info_cat, "INFO", INFO, GREEN, true);
|
127
|
-
log_cat_reg(&s->log, &s->debug_cat, "DEBUG", DEBUG, GRAY, false);
|
128
|
-
log_cat_reg(&s->log, &s->con_cat, "connect", INFO, GREEN, false);
|
129
|
-
log_cat_reg(&s->log, &s->req_cat, "request", INFO, CYAN, false);
|
130
|
-
log_cat_reg(&s->log, &s->resp_cat, "response", INFO, DARK_CYAN, false);
|
131
|
-
log_cat_reg(&s->log, &s->eval_cat, "eval", INFO, BLUE, false);
|
132
|
-
|
133
|
-
if (ERR_OK != log_init(err, &s->log, options)) {
|
134
|
-
return err->code;
|
135
|
-
}
|
111
|
+
configure(Err err, int port, const char *root, VALUE options) {
|
112
|
+
the_server.port = port;
|
113
|
+
the_server.root = strdup(root);
|
114
|
+
the_server.thread_cnt = 0;
|
115
|
+
the_server.running = 0;
|
116
|
+
the_server.listen_thread = 0;
|
117
|
+
the_server.con_thread = 0;
|
118
|
+
the_server.max_push_pending = 32;
|
136
119
|
if (Qnil != options) {
|
137
120
|
VALUE v;
|
138
121
|
|
@@ -140,24 +123,33 @@ configure(Err err, Server s, int port, const char *root, VALUE options) {
|
|
140
123
|
int tc = FIX2INT(v);
|
141
124
|
|
142
125
|
if (1 <= tc || tc < 1000) {
|
143
|
-
|
126
|
+
the_server.thread_cnt = tc;
|
144
127
|
} else {
|
145
128
|
rb_raise(rb_eArgError, "thread_count must be between 1 and 1000.");
|
146
129
|
}
|
147
130
|
}
|
131
|
+
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("max_push_pending"))))) {
|
132
|
+
int tc = FIX2INT(v);
|
133
|
+
|
134
|
+
if (0 <= tc || tc < 1000) {
|
135
|
+
the_server.thread_cnt = tc;
|
136
|
+
} else {
|
137
|
+
rb_raise(rb_eArgError, "thread_count must be between 0 and 1000.");
|
138
|
+
}
|
139
|
+
}
|
148
140
|
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("pedantic"))))) {
|
149
|
-
|
141
|
+
the_server.pedantic = (Qtrue == v);
|
150
142
|
}
|
151
143
|
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("Port"))))) {
|
152
144
|
if (rb_cInteger == rb_obj_class(v)) {
|
153
|
-
|
145
|
+
the_server.port = NUM2INT(v);
|
154
146
|
} else {
|
155
147
|
switch (rb_type(v)) {
|
156
148
|
case T_STRING:
|
157
|
-
|
149
|
+
the_server.port = atoi(StringValuePtr(v));
|
158
150
|
break;
|
159
151
|
case T_FIXNUM:
|
160
|
-
|
152
|
+
the_server.port = NUM2INT(v);
|
161
153
|
break;
|
162
154
|
default:
|
163
155
|
break;
|
@@ -166,30 +158,31 @@ configure(Err err, Server s, int port, const char *root, VALUE options) {
|
|
166
158
|
}
|
167
159
|
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("quiet"))))) {
|
168
160
|
if (Qtrue == v) {
|
169
|
-
|
161
|
+
info_cat.on = false;
|
170
162
|
}
|
171
163
|
}
|
172
164
|
if (Qnil != (v = rb_hash_lookup(options, ID2SYM(rb_intern("debug"))))) {
|
173
165
|
if (Qtrue == v) {
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
166
|
+
error_cat.on = true;
|
167
|
+
warn_cat.on = true;
|
168
|
+
info_cat.on = true;
|
169
|
+
debug_cat.on = true;
|
170
|
+
con_cat.on = true;
|
171
|
+
req_cat.on = true;
|
172
|
+
resp_cat.on = true;
|
173
|
+
eval_cat.on = true;
|
174
|
+
push_cat.on = true;
|
182
175
|
}
|
183
176
|
}
|
184
177
|
}
|
185
178
|
return ERR_OK;
|
186
179
|
}
|
187
180
|
|
188
|
-
/* Document-method:
|
181
|
+
/* Document-method: init
|
189
182
|
*
|
190
|
-
* call-seq:
|
183
|
+
* call-seq: init(port, root, options)
|
191
184
|
*
|
192
|
-
*
|
185
|
+
* Configures the server that will listen on the designated _port_ and using
|
193
186
|
* the _root_ as the root of the static resources. Logging is feature based
|
194
187
|
* and not level based and the options reflect that approach.
|
195
188
|
*
|
@@ -198,35 +191,16 @@ configure(Err err, Server s, int port, const char *root, VALUE options) {
|
|
198
191
|
* - *:pedantic* [_true_|_false_] if true response header and status codes are check and an exception raised if they violate the rack spec at https://github.com/rack/rack/blob/master/SPEC, https://tools.ietf.org/html/rfc3875#section-4.1.18, or https://tools.ietf.org/html/rfc7230.
|
199
192
|
*
|
200
193
|
* - *:thread_count* [_Integer_] number of ruby worker threads. Defaults to one. If zero then the _start_ function will not return but instead will proess using the thread that called _start_. Usually the default is best unless the workers are making IO calls.
|
201
|
-
*
|
202
|
-
* - *:log_dir* [_String_] directory to place log files in. If nil or empty then no log files are written.
|
203
|
-
*
|
204
|
-
* - *:log_console* [_true_|_false_] if true log entry are display on the console.
|
205
|
-
*
|
206
|
-
* - *:log_classic* [_true_|_false_] if true log entry follow a classic format. If false log entries are JSON.
|
207
|
-
*
|
208
|
-
* - *:log_colorize* [_true_|_false_] if true log entries are colorized.
|
209
|
-
*
|
210
|
-
* - *:log_states* [_Hash_] a map of logging categories and whether they should be on or off. Categories are:
|
211
|
-
* - *:ERROR* errors
|
212
|
-
* - *:WARN* warnings
|
213
|
-
* - *:INFO* infomational
|
214
|
-
* - *:DEBUG* debugging
|
215
|
-
* - *:connect* openning and closing of connections
|
216
|
-
* - *:request* requests
|
217
|
-
* - *:response* responses
|
218
|
-
* - *:eval* handler evaluationss
|
219
194
|
*/
|
220
195
|
static VALUE
|
221
|
-
|
222
|
-
Server s;
|
196
|
+
rserver_init(int argc, VALUE *argv, VALUE self) {
|
223
197
|
struct _Err err = ERR_INIT;
|
224
198
|
int port;
|
225
199
|
const char *root;
|
226
200
|
VALUE options = Qnil;
|
227
|
-
|
201
|
+
|
228
202
|
if (argc < 2 || 3 < argc) {
|
229
|
-
rb_raise(rb_eArgError, "Wrong number of arguments to Agoo::Server.
|
203
|
+
rb_raise(rb_eArgError, "Wrong number of arguments to Agoo::Server.configure.");
|
230
204
|
}
|
231
205
|
port = FIX2INT(argv[0]);
|
232
206
|
rb_check_type(argv[1], T_STRING);
|
@@ -234,27 +208,25 @@ server_new(int argc, VALUE *argv, VALUE self) {
|
|
234
208
|
if (3 <= argc) {
|
235
209
|
options = argv[2];
|
236
210
|
}
|
237
|
-
|
238
|
-
|
239
|
-
memset(s, 0, sizeof(struct _Server));
|
240
|
-
if (ERR_OK != configure(&err, s, port, root, options)) {
|
241
|
-
xfree(s);
|
242
|
-
DEBUG_FREE(mem_server)
|
243
|
-
// TBD raise Agoo specific exception
|
211
|
+
memset(&the_server, 0, sizeof(struct _Server));
|
212
|
+
if (ERR_OK != configure(&err, port, root, options)) {
|
244
213
|
rb_raise(rb_eArgError, "%s", err.msg);
|
245
214
|
}
|
246
|
-
queue_multi_init(&
|
247
|
-
queue_multi_init(&
|
215
|
+
queue_multi_init(&the_server.con_queue, 256, false, false);
|
216
|
+
queue_multi_init(&the_server.pub_queue, 256, true, false);
|
217
|
+
queue_multi_init(&the_server.eval_queue, 1024, false, true);
|
248
218
|
|
249
|
-
cache_init(&
|
250
|
-
the_server
|
219
|
+
cache_init(&the_server.pages);
|
220
|
+
cc_init(&the_server.con_cache);
|
221
|
+
sub_init(&the_server.sub_cache);
|
251
222
|
|
252
|
-
|
223
|
+
the_server.inited = true;
|
224
|
+
|
225
|
+
return Qnil;
|
253
226
|
}
|
254
227
|
|
255
228
|
static void*
|
256
229
|
listen_loop(void *x) {
|
257
|
-
Server server = (Server)x;
|
258
230
|
struct sockaddr_in addr;
|
259
231
|
int optval = 1;
|
260
232
|
struct pollfd pa[1];
|
@@ -267,10 +239,9 @@ listen_loop(void *x) {
|
|
267
239
|
int i;
|
268
240
|
uint64_t cnt = 0;
|
269
241
|
|
270
|
-
atomic_fetch_add(&server->running, 1);
|
271
242
|
if (0 >= (pa->fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
|
272
|
-
log_cat(&
|
273
|
-
atomic_fetch_sub(&
|
243
|
+
log_cat(&error_cat, "Server failed to open server socket. %s.", strerror(errno));
|
244
|
+
atomic_fetch_sub(&the_server.running, 1);
|
274
245
|
return NULL;
|
275
246
|
}
|
276
247
|
#ifdef OSX_OS
|
@@ -279,26 +250,26 @@ listen_loop(void *x) {
|
|
279
250
|
memset(&addr, 0, sizeof(addr));
|
280
251
|
addr.sin_family = AF_INET;
|
281
252
|
addr.sin_addr.s_addr = INADDR_ANY;
|
282
|
-
addr.sin_port = htons(
|
253
|
+
addr.sin_port = htons(the_server.port);
|
283
254
|
setsockopt(pa->fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
284
255
|
setsockopt(pa->fd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
285
256
|
if (0 > bind(fp->fd, (struct sockaddr*)&addr, sizeof(addr))) {
|
286
|
-
log_cat(&
|
287
|
-
atomic_fetch_sub(&
|
257
|
+
log_cat(&error_cat, "Server failed to bind server socket. %s.", strerror(errno));
|
258
|
+
atomic_fetch_sub(&the_server.running, 1);
|
288
259
|
return NULL;
|
289
260
|
}
|
290
261
|
listen(pa->fd, 1000);
|
291
|
-
server->ready = true;
|
292
262
|
pa->events = POLLIN;
|
293
263
|
pa->revents = 0;
|
294
264
|
|
295
265
|
memset(&client_addr, 0, sizeof(client_addr));
|
296
|
-
|
266
|
+
atomic_fetch_add(&the_server.running, 1);
|
267
|
+
while (the_server.active) {
|
297
268
|
if (0 > (i = poll(pa, 1, 100))) {
|
298
269
|
if (EAGAIN == errno) {
|
299
270
|
continue;
|
300
271
|
}
|
301
|
-
log_cat(&
|
272
|
+
log_cat(&error_cat, "Server polling error. %s.", strerror(errno));
|
302
273
|
// Either a signal or something bad like out of memory. Might as well exit.
|
303
274
|
break;
|
304
275
|
}
|
@@ -307,9 +278,9 @@ listen_loop(void *x) {
|
|
307
278
|
}
|
308
279
|
if (0 != (pa->revents & POLLIN)) {
|
309
280
|
if (0 > (client_sock = accept(pa->fd, (struct sockaddr*)&client_addr, &alen))) {
|
310
|
-
log_cat(&
|
311
|
-
} else if (NULL == (con = con_create(&err,
|
312
|
-
log_cat(&
|
281
|
+
log_cat(&error_cat, "Server accept connection failed. %s.", strerror(errno));
|
282
|
+
} else if (NULL == (con = con_create(&err, client_sock, ++cnt))) {
|
283
|
+
log_cat(&error_cat, "Server accept connection failed. %s.", err.msg);
|
313
284
|
close(client_sock);
|
314
285
|
cnt--;
|
315
286
|
err_clear(&err);
|
@@ -320,22 +291,22 @@ listen_loop(void *x) {
|
|
320
291
|
fcntl(client_sock, F_SETFL, O_NONBLOCK);
|
321
292
|
setsockopt(client_sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
|
322
293
|
setsockopt(client_sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
|
323
|
-
log_cat(&
|
324
|
-
queue_push(&
|
294
|
+
log_cat(&con_cat, "Server accepted connection %llu on port %d [%d]", (unsigned long long)cnt, the_server.port, con->sock);
|
295
|
+
queue_push(&the_server.con_queue, (void*)con);
|
325
296
|
}
|
326
297
|
}
|
327
298
|
if (0 != (pa->revents & (POLLERR | POLLHUP | POLLNVAL))) {
|
328
299
|
if (0 != (pa->revents & (POLLHUP | POLLNVAL))) {
|
329
|
-
log_cat(&
|
300
|
+
log_cat(&error_cat, "Agoo server socket on port %d closed.", the_server.port);
|
330
301
|
} else {
|
331
|
-
log_cat(&
|
302
|
+
log_cat(&error_cat, "Agoo server socket on port %d error.", the_server.port);
|
332
303
|
}
|
333
|
-
|
304
|
+
the_server.active = false;
|
334
305
|
}
|
335
306
|
pa->revents = 0;
|
336
307
|
}
|
337
308
|
close(pa->fd);
|
338
|
-
atomic_fetch_sub(&
|
309
|
+
atomic_fetch_sub(&the_server.running, 1);
|
339
310
|
|
340
311
|
return NULL;
|
341
312
|
}
|
@@ -362,7 +333,7 @@ rescue_error(VALUE x) {
|
|
362
333
|
|
363
334
|
req->res->close = true;
|
364
335
|
res_set_message(req->res, message);
|
365
|
-
queue_wakeup(&
|
336
|
+
queue_wakeup(&the_server.con_queue);
|
366
337
|
|
367
338
|
return Qfalse;
|
368
339
|
}
|
@@ -371,13 +342,13 @@ static VALUE
|
|
371
342
|
handle_base_inner(void *x) {
|
372
343
|
Req req = (Req)x;
|
373
344
|
volatile VALUE rr = request_wrap(req);
|
374
|
-
volatile VALUE rres = response_new(
|
345
|
+
volatile VALUE rres = response_new();
|
375
346
|
|
376
347
|
rb_funcall(req->handler, on_request_id, 2, rr, rres);
|
377
348
|
DATA_PTR(rr) = NULL;
|
378
349
|
|
379
350
|
res_set_message(req->res, response_text(rres));
|
380
|
-
queue_wakeup(&
|
351
|
+
queue_wakeup(&the_server.con_queue);
|
381
352
|
|
382
353
|
return Qfalse;
|
383
354
|
}
|
@@ -512,13 +483,44 @@ handle_rack_inner(void *x) {
|
|
512
483
|
t->len = snprintf(t->text, 1024, "HTTP/1.1 %d %s\r\nContent-Length: %d\r\n", code, status_msg, bsize);
|
513
484
|
break;
|
514
485
|
}
|
486
|
+
if (code < 300) {
|
487
|
+
switch (req->upgrade) {
|
488
|
+
case UP_WS:
|
489
|
+
if (CON_WS != req->res->con_kind ||
|
490
|
+
Qnil == (req->handler = rb_hash_lookup(env, push_env_key))) {
|
491
|
+
strcpy(t->text, err500);
|
492
|
+
t->len = sizeof(err500) - 1;
|
493
|
+
break;
|
494
|
+
}
|
495
|
+
req->handler_type = PUSH_HOOK;
|
496
|
+
upgraded_extend(req->cid, req->handler);
|
497
|
+
t->len = snprintf(t->text, 1024, "HTTP/1.1 101 %s\r\n", status_msg);
|
498
|
+
t = ws_add_headers(req, t);
|
499
|
+
break;
|
500
|
+
case UP_SSE:
|
501
|
+
if (CON_SSE != req->res->con_kind ||
|
502
|
+
Qnil == (req->handler = rb_hash_lookup(env, push_env_key))) {
|
503
|
+
strcpy(t->text, err500);
|
504
|
+
t->len = sizeof(err500) - 1;
|
505
|
+
break;
|
506
|
+
}
|
507
|
+
req->handler_type = PUSH_HOOK;
|
508
|
+
upgraded_extend(req->cid, req->handler);
|
509
|
+
t = sse_upgrade(req, t);
|
510
|
+
res_set_message(req->res, t);
|
511
|
+
queue_wakeup(&the_server.con_queue);
|
512
|
+
return Qfalse;
|
513
|
+
default:
|
514
|
+
break;
|
515
|
+
}
|
516
|
+
}
|
515
517
|
if (HEAD == req->method) {
|
516
518
|
bsize = 0;
|
517
519
|
} else {
|
518
520
|
if (T_HASH == rb_type(hv)) {
|
519
521
|
rb_hash_foreach(hv, header_cb, (VALUE)&t);
|
520
522
|
} else {
|
521
|
-
rb_iterate
|
523
|
+
rb_iterate(rb_each, hv, header_each_cb, (VALUE)&t);
|
522
524
|
}
|
523
525
|
}
|
524
526
|
t = text_append(t, "\r\n", 2);
|
@@ -537,7 +539,7 @@ handle_rack_inner(void *x) {
|
|
537
539
|
}
|
538
540
|
}
|
539
541
|
res_set_message(req->res, t);
|
540
|
-
queue_wakeup(&
|
542
|
+
queue_wakeup(&the_server.con_queue);
|
541
543
|
|
542
544
|
return Qfalse;
|
543
545
|
}
|
@@ -559,13 +561,13 @@ static VALUE
|
|
559
561
|
handle_wab_inner(void *x) {
|
560
562
|
Req req = (Req)x;
|
561
563
|
volatile VALUE rr = request_wrap(req);
|
562
|
-
volatile VALUE rres = response_new(
|
564
|
+
volatile VALUE rres = response_new();
|
563
565
|
|
564
566
|
rb_funcall(req->handler, on_request_id, 2, rr, rres);
|
565
567
|
DATA_PTR(rr) = NULL;
|
566
568
|
|
567
569
|
res_set_message(req->res, response_text(rres));
|
568
|
-
queue_wakeup(&
|
570
|
+
queue_wakeup(&the_server.con_queue);
|
569
571
|
|
570
572
|
return Qfalse;
|
571
573
|
}
|
@@ -576,17 +578,73 @@ handle_wab(void *x) {
|
|
576
578
|
|
577
579
|
return NULL;
|
578
580
|
}
|
581
|
+
|
582
|
+
static VALUE
|
583
|
+
handle_push_inner(void *x) {
|
584
|
+
Req req = (Req)x;
|
585
|
+
|
586
|
+
switch (req->method) {
|
587
|
+
case ON_MSG:
|
588
|
+
rb_funcall(req->handler, on_message_id, 1, rb_str_new(req->msg, req->mlen));
|
589
|
+
break;
|
590
|
+
case ON_BIN: {
|
591
|
+
volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
|
592
|
+
|
593
|
+
rb_enc_associate(rstr, rb_ascii8bit_encoding());
|
594
|
+
rb_funcall(req->handler, on_message_id, 1, rstr);
|
595
|
+
break;
|
596
|
+
}
|
597
|
+
case ON_CLOSE:
|
598
|
+
rb_funcall(req->handler, on_close_id, 0);
|
599
|
+
break;
|
600
|
+
case ON_SHUTDOWN:
|
601
|
+
rb_funcall(req->handler, rb_intern("on_shutdown"), 0);
|
602
|
+
break;
|
603
|
+
case ON_EMPTY:
|
604
|
+
rb_funcall(req->handler, on_drained_id, 0);
|
605
|
+
break;
|
606
|
+
default:
|
607
|
+
break;
|
608
|
+
}
|
609
|
+
return Qfalse;
|
610
|
+
}
|
611
|
+
|
612
|
+
static void*
|
613
|
+
handle_push(void *x) {
|
614
|
+
rb_rescue2(handle_push_inner, (VALUE)x, rescue_error, (VALUE)x, rb_eException, 0);
|
615
|
+
return NULL;
|
616
|
+
}
|
617
|
+
|
579
618
|
static void
|
580
|
-
handle_protected(Req req) {
|
619
|
+
handle_protected(Req req, bool gvi) {
|
581
620
|
switch (req->handler_type) {
|
582
621
|
case BASE_HOOK:
|
583
|
-
|
622
|
+
if (gvi) {
|
623
|
+
rb_thread_call_with_gvl(handle_base, req);
|
624
|
+
} else {
|
625
|
+
handle_base(req);
|
626
|
+
}
|
584
627
|
break;
|
585
628
|
case RACK_HOOK:
|
586
|
-
|
629
|
+
if (gvi) {
|
630
|
+
rb_thread_call_with_gvl(handle_rack, req);
|
631
|
+
} else {
|
632
|
+
handle_rack(req);
|
633
|
+
}
|
587
634
|
break;
|
588
635
|
case WAB_HOOK:
|
589
|
-
|
636
|
+
if (gvi) {
|
637
|
+
rb_thread_call_with_gvl(handle_wab, req);
|
638
|
+
} else {
|
639
|
+
handle_wab(req);
|
640
|
+
}
|
641
|
+
break;
|
642
|
+
case PUSH_HOOK:
|
643
|
+
if (gvi) {
|
644
|
+
rb_thread_call_with_gvl(handle_push, req);
|
645
|
+
} else {
|
646
|
+
handle_push(req);
|
647
|
+
}
|
590
648
|
break;
|
591
649
|
default: {
|
592
650
|
char buf[256];
|
@@ -595,7 +653,7 @@ handle_protected(Req req) {
|
|
595
653
|
|
596
654
|
req->res->close = true;
|
597
655
|
res_set_message(req->res, message);
|
598
|
-
queue_wakeup(&
|
656
|
+
queue_wakeup(&the_server.con_queue);
|
599
657
|
break;
|
600
658
|
}
|
601
659
|
}
|
@@ -603,25 +661,23 @@ handle_protected(Req req) {
|
|
603
661
|
|
604
662
|
static void*
|
605
663
|
process_loop(void *ptr) {
|
606
|
-
|
607
|
-
Req req;
|
664
|
+
Req req;
|
608
665
|
|
609
|
-
atomic_fetch_add(&
|
610
|
-
while (
|
611
|
-
if (NULL != (req = (Req)queue_pop(&
|
612
|
-
handle_protected(req);
|
613
|
-
|
614
|
-
DEBUG_FREE(mem_req)
|
666
|
+
atomic_fetch_add(&the_server.running, 1);
|
667
|
+
while (the_server.active) {
|
668
|
+
if (NULL != (req = (Req)queue_pop(&the_server.eval_queue, 0.1))) {
|
669
|
+
handle_protected(req, true);
|
670
|
+
request_destroy(req);
|
615
671
|
}
|
616
672
|
}
|
617
|
-
atomic_fetch_sub(&
|
618
|
-
|
673
|
+
atomic_fetch_sub(&the_server.running, 1);
|
674
|
+
|
619
675
|
return NULL;
|
620
676
|
}
|
621
677
|
|
622
678
|
static VALUE
|
623
679
|
wrap_process_loop(void *ptr) {
|
624
|
-
rb_thread_call_without_gvl(process_loop,
|
680
|
+
rb_thread_call_without_gvl(process_loop, NULL, RUBY_UBF_IO, NULL);
|
625
681
|
return Qnil;
|
626
682
|
}
|
627
683
|
|
@@ -632,73 +688,60 @@ wrap_process_loop(void *ptr) {
|
|
632
688
|
* Start the server.
|
633
689
|
*/
|
634
690
|
static VALUE
|
635
|
-
|
636
|
-
Server server = (Server)DATA_PTR(self);
|
691
|
+
server_start(VALUE self) {
|
637
692
|
VALUE *vp;
|
638
693
|
int i;
|
639
694
|
double giveup;
|
640
695
|
|
641
|
-
|
642
|
-
server->ready = false;
|
696
|
+
the_server.active = true;
|
643
697
|
|
644
|
-
pthread_create(&
|
645
|
-
pthread_create(&
|
698
|
+
pthread_create(&the_server.listen_thread, NULL, listen_loop, NULL);
|
699
|
+
pthread_create(&the_server.con_thread, NULL, con_loop, NULL);
|
646
700
|
|
647
701
|
giveup = dtime() + 1.0;
|
648
702
|
while (dtime() < giveup) {
|
649
|
-
if (
|
703
|
+
if (2 <= atomic_load(&the_server.running)) {
|
650
704
|
break;
|
651
705
|
}
|
652
|
-
dsleep(0.
|
706
|
+
dsleep(0.01);
|
653
707
|
}
|
654
|
-
|
655
|
-
signal(SIGTERM, sig_handler);
|
656
|
-
signal(SIGPIPE, SIG_IGN);
|
657
|
-
|
658
|
-
if (server->info_cat.on) {
|
708
|
+
if (info_cat.on) {
|
659
709
|
VALUE agoo = rb_const_get_at(rb_cObject, rb_intern("Agoo"));
|
660
710
|
VALUE v = rb_const_get_at(agoo, rb_intern("VERSION"));
|
661
711
|
|
662
|
-
log_cat(&
|
712
|
+
log_cat(&info_cat, "Agoo %s listening on port %d.", StringValuePtr(v), the_server.port);
|
663
713
|
}
|
664
|
-
if (0 >=
|
714
|
+
if (0 >= the_server.thread_cnt) {
|
665
715
|
Req req;
|
666
716
|
|
667
|
-
while (
|
668
|
-
if (NULL != (req = (Req)queue_pop(&
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
case RACK_HOOK:
|
674
|
-
handle_rack(req);
|
675
|
-
break;
|
676
|
-
case WAB_HOOK:
|
677
|
-
handle_wab(req);
|
678
|
-
break;
|
679
|
-
default: {
|
680
|
-
char buf[256];
|
681
|
-
int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
|
682
|
-
Text message = text_create(buf, cnt);
|
683
|
-
|
684
|
-
req->res->close = true;
|
685
|
-
res_set_message(req->res, message);
|
686
|
-
queue_wakeup(&req->server->con_queue);
|
687
|
-
break;
|
688
|
-
}
|
689
|
-
}
|
690
|
-
free(req);
|
691
|
-
DEBUG_FREE(mem_req)
|
717
|
+
while (the_server.active) {
|
718
|
+
if (NULL != (req = (Req)queue_pop(&the_server.eval_queue, 0.1))) {
|
719
|
+
handle_protected(req, false);
|
720
|
+
request_destroy(req);
|
721
|
+
} else {
|
722
|
+
rb_thread_schedule();
|
692
723
|
}
|
724
|
+
|
693
725
|
}
|
694
726
|
} else {
|
695
|
-
|
696
|
-
DEBUG_ALLOC(mem_eval_threads)
|
727
|
+
the_server.eval_threads = (VALUE*)malloc(sizeof(VALUE) * (the_server.thread_cnt + 1));
|
728
|
+
DEBUG_ALLOC(mem_eval_threads, the_server.eval_threads);
|
697
729
|
|
698
|
-
for (i =
|
699
|
-
*vp = rb_thread_create(wrap_process_loop,
|
730
|
+
for (i = the_server.thread_cnt, vp = the_server.eval_threads; 0 < i; i--, vp++) {
|
731
|
+
*vp = rb_thread_create(wrap_process_loop, NULL);
|
700
732
|
}
|
701
733
|
*vp = Qnil;
|
734
|
+
|
735
|
+
giveup = dtime() + 1.0;
|
736
|
+
while (dtime() < giveup) {
|
737
|
+
// The processing threads will not start until this thread
|
738
|
+
// releases ownership so do that and then see if the threads has
|
739
|
+
// been started yet.
|
740
|
+
rb_thread_schedule();
|
741
|
+
if (2 + the_server.thread_cnt <= atomic_load(&the_server.running)) {
|
742
|
+
break;
|
743
|
+
}
|
744
|
+
}
|
702
745
|
}
|
703
746
|
return Qnil;
|
704
747
|
}
|
@@ -710,176 +753,8 @@ start(VALUE self) {
|
|
710
753
|
* Shutdown the server. Logs and queues are flushed before shutting down.
|
711
754
|
*/
|
712
755
|
static VALUE
|
713
|
-
|
714
|
-
|
715
|
-
return Qnil;
|
716
|
-
}
|
717
|
-
|
718
|
-
/* Document-method: error?
|
719
|
-
*
|
720
|
-
* call-seq: error?()
|
721
|
-
*
|
722
|
-
* Returns true is errors are being logged.
|
723
|
-
*/
|
724
|
-
static VALUE
|
725
|
-
log_errorp(VALUE self) {
|
726
|
-
return ((Server)DATA_PTR(self))->error_cat.on ? Qtrue : Qfalse;
|
727
|
-
}
|
728
|
-
|
729
|
-
/* Document-method: warn?
|
730
|
-
*
|
731
|
-
* call-seq: warn?()
|
732
|
-
*
|
733
|
-
* Returns true is warnings are being logged.
|
734
|
-
*/
|
735
|
-
static VALUE
|
736
|
-
log_warnp(VALUE self) {
|
737
|
-
return ((Server)DATA_PTR(self))->warn_cat.on ? Qtrue : Qfalse;
|
738
|
-
}
|
739
|
-
|
740
|
-
/* Document-method: info?
|
741
|
-
*
|
742
|
-
* call-seq: info?()
|
743
|
-
*
|
744
|
-
* Returns true is info entries are being logged.
|
745
|
-
*/
|
746
|
-
static VALUE
|
747
|
-
log_infop(VALUE self) {
|
748
|
-
return ((Server)DATA_PTR(self))->info_cat.on ? Qtrue : Qfalse;
|
749
|
-
}
|
750
|
-
|
751
|
-
/* Document-method: debug?
|
752
|
-
*
|
753
|
-
* call-seq: debug?()
|
754
|
-
*
|
755
|
-
* Returns true is debug entries are being logged.
|
756
|
-
*/
|
757
|
-
static VALUE
|
758
|
-
log_debugp(VALUE self) {
|
759
|
-
return ((Server)DATA_PTR(self))->debug_cat.on ? Qtrue : Qfalse;
|
760
|
-
}
|
761
|
-
|
762
|
-
/* Document-method: eval?
|
763
|
-
*
|
764
|
-
* call-seq: eval?()
|
765
|
-
*
|
766
|
-
* Returns true is handler evaluation entries are being logged.
|
767
|
-
*/
|
768
|
-
static VALUE
|
769
|
-
log_evalp(VALUE self) {
|
770
|
-
return ((Server)DATA_PTR(self))->eval_cat.on ? Qtrue : Qfalse;
|
771
|
-
}
|
772
|
-
|
773
|
-
/* Document-method: error
|
774
|
-
*
|
775
|
-
* call-seq: error(msg)
|
776
|
-
*
|
777
|
-
* Log an error message.
|
778
|
-
*/
|
779
|
-
static VALUE
|
780
|
-
log_error(VALUE self, VALUE msg) {
|
781
|
-
log_cat(&((Server)DATA_PTR(self))->error_cat, "%s", StringValuePtr(msg));
|
782
|
-
return Qnil;
|
783
|
-
}
|
784
|
-
|
785
|
-
/* Document-method: warn
|
786
|
-
*
|
787
|
-
* call-seq: warn(msg)
|
788
|
-
*
|
789
|
-
* Log a warn message.
|
790
|
-
*/
|
791
|
-
static VALUE
|
792
|
-
log_warn(VALUE self, VALUE msg) {
|
793
|
-
log_cat(&((Server)DATA_PTR(self))->warn_cat, "%s", StringValuePtr(msg));
|
794
|
-
return Qnil;
|
795
|
-
}
|
796
|
-
|
797
|
-
/* Document-method: info
|
798
|
-
*
|
799
|
-
* call-seq: info(msg)
|
800
|
-
*
|
801
|
-
* Log an info message.
|
802
|
-
*/
|
803
|
-
static VALUE
|
804
|
-
log_info(VALUE self, VALUE msg) {
|
805
|
-
log_cat(&((Server)DATA_PTR(self))->info_cat, "%s", StringValuePtr(msg));
|
806
|
-
return Qnil;
|
807
|
-
}
|
808
|
-
|
809
|
-
/* Document-method: debug
|
810
|
-
*
|
811
|
-
* call-seq: debug(msg)
|
812
|
-
*
|
813
|
-
* Log a debug message.
|
814
|
-
*/
|
815
|
-
static VALUE
|
816
|
-
log_debug(VALUE self, VALUE msg) {
|
817
|
-
log_cat(&((Server)DATA_PTR(self))->debug_cat, "%s", StringValuePtr(msg));
|
818
|
-
return Qnil;
|
819
|
-
}
|
820
|
-
|
821
|
-
/* Document-method: log_eval
|
822
|
-
*
|
823
|
-
* call-seq: log_eval(msg)
|
824
|
-
*
|
825
|
-
* Log an eval message.
|
826
|
-
*/
|
827
|
-
static VALUE
|
828
|
-
log_eval(VALUE self, VALUE msg) {
|
829
|
-
log_cat(&((Server)DATA_PTR(self))->eval_cat, "%s", StringValuePtr(msg));
|
830
|
-
return Qnil;
|
831
|
-
}
|
832
|
-
|
833
|
-
/* Document-method: log_state
|
834
|
-
*
|
835
|
-
* call-seq: log_state(label)
|
836
|
-
*
|
837
|
-
* Return the logging state of the category identified by the _label_.
|
838
|
-
*/
|
839
|
-
static VALUE
|
840
|
-
log_state(VALUE self, VALUE label) {
|
841
|
-
Server server = (Server)DATA_PTR(self);
|
842
|
-
LogCat cat = log_cat_find(&server->log, StringValuePtr(label));
|
843
|
-
|
844
|
-
if (NULL == cat) {
|
845
|
-
rb_raise(rb_eArgError, "%s is not a valid log category.", StringValuePtr(label));
|
846
|
-
}
|
847
|
-
return cat->on ? Qtrue : Qfalse;
|
848
|
-
}
|
849
|
-
|
850
|
-
/* Document-method: set_log_state
|
851
|
-
*
|
852
|
-
* call-seq: set_log_state(label, state)
|
853
|
-
*
|
854
|
-
* Set the logging state of the category identified by the _label_.
|
855
|
-
*/
|
856
|
-
static VALUE
|
857
|
-
set_log_state(VALUE self, VALUE label, VALUE on) {
|
858
|
-
Server server = (Server)DATA_PTR(self);
|
859
|
-
LogCat cat = log_cat_find(&server->log, StringValuePtr(label));
|
860
|
-
|
861
|
-
if (NULL == cat) {
|
862
|
-
rb_raise(rb_eArgError, "%s is not a valid log category.", StringValuePtr(label));
|
863
|
-
}
|
864
|
-
cat->on = (Qtrue == on);
|
865
|
-
|
866
|
-
return Qnil;
|
867
|
-
}
|
868
|
-
|
869
|
-
/* Document-method: log_flush
|
870
|
-
*
|
871
|
-
* call-seq: log_flush()
|
872
|
-
*
|
873
|
-
* Flush the log queue and write all entries to disk or the console. The call
|
874
|
-
* waits for the flush to complete.
|
875
|
-
*/
|
876
|
-
static VALUE
|
877
|
-
server_log_flush(VALUE self, VALUE to) {
|
878
|
-
double timeout = NUM2DBL(to);
|
879
|
-
|
880
|
-
if (!log_flush(&((Server)DATA_PTR(self))->log, timeout)) {
|
881
|
-
rb_raise(rb_eStandardError, "timed out waiting for log flush.");
|
882
|
-
}
|
756
|
+
rserver_shutdown(VALUE self) {
|
757
|
+
server_shutdown();
|
883
758
|
return Qnil;
|
884
759
|
}
|
885
760
|
|
@@ -893,7 +768,6 @@ server_log_flush(VALUE self, VALUE to) {
|
|
893
768
|
*/
|
894
769
|
static VALUE
|
895
770
|
handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
896
|
-
Server server = (Server)DATA_PTR(self);
|
897
771
|
Hook hook;
|
898
772
|
Method meth = ALL;
|
899
773
|
const char *pat;
|
@@ -926,13 +800,13 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
|
926
800
|
Hook h;
|
927
801
|
Hook prev = NULL;
|
928
802
|
|
929
|
-
for (h =
|
803
|
+
for (h = the_server.hooks; NULL != h; h = h->next) {
|
930
804
|
prev = h;
|
931
805
|
}
|
932
806
|
if (NULL != prev) {
|
933
807
|
prev->next = hook;
|
934
808
|
} else {
|
935
|
-
|
809
|
+
the_server.hooks = hook;
|
936
810
|
}
|
937
811
|
rb_gc_register_address(&hook->handler);
|
938
812
|
}
|
@@ -948,12 +822,10 @@ handle(VALUE self, VALUE method, VALUE pattern, VALUE handler) {
|
|
948
822
|
*/
|
949
823
|
static VALUE
|
950
824
|
handle_not_found(VALUE self, VALUE handler) {
|
951
|
-
|
952
|
-
|
953
|
-
if (NULL == (server->hook404 = hook_create(GET, "/", handler))) {
|
825
|
+
if (NULL == (the_server.hook404 = hook_create(GET, "/", handler))) {
|
954
826
|
rb_raise(rb_eStandardError, "out of memory.");
|
955
827
|
}
|
956
|
-
rb_gc_register_address(&
|
828
|
+
rb_gc_register_address(&the_server.hook404->handler);
|
957
829
|
|
958
830
|
return Qnil;
|
959
831
|
}
|
@@ -967,7 +839,7 @@ handle_not_found(VALUE self, VALUE handler) {
|
|
967
839
|
*/
|
968
840
|
static VALUE
|
969
841
|
add_mime(VALUE self, VALUE suffix, VALUE type) {
|
970
|
-
mime_set(&
|
842
|
+
mime_set(&the_server.pages, StringValuePtr(suffix), StringValuePtr(type));
|
971
843
|
|
972
844
|
return Qnil;
|
973
845
|
}
|
@@ -979,43 +851,33 @@ add_mime(VALUE self, VALUE suffix, VALUE type) {
|
|
979
851
|
*/
|
980
852
|
void
|
981
853
|
server_init(VALUE mod) {
|
982
|
-
|
983
|
-
|
984
|
-
rb_define_module_function(
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
rb_define_method(server_class, "debug?", log_debugp, 0);
|
992
|
-
rb_define_method(server_class, "log_eval?", log_evalp, 0);
|
993
|
-
rb_define_method(server_class, "error", log_error, 1);
|
994
|
-
rb_define_method(server_class, "warn", log_warn, 1);
|
995
|
-
rb_define_method(server_class, "info", log_info, 1);
|
996
|
-
rb_define_method(server_class, "debug", log_debug, 1);
|
997
|
-
rb_define_method(server_class, "log_eval", log_eval, 1);
|
998
|
-
|
999
|
-
rb_define_method(server_class, "log_state", log_state, 1);
|
1000
|
-
rb_define_method(server_class, "set_log_state", set_log_state, 2);
|
1001
|
-
rb_define_method(server_class, "log_flush", server_log_flush, 1);
|
1002
|
-
|
1003
|
-
rb_define_method(server_class, "handle", handle, 3);
|
1004
|
-
rb_define_method(server_class, "handle_not_found", handle_not_found, 1);
|
1005
|
-
rb_define_method(server_class, "add_mime", add_mime, 2);
|
854
|
+
server_mod = rb_define_module_under(mod, "Server");
|
855
|
+
|
856
|
+
rb_define_module_function(server_mod, "init", rserver_init, -1);
|
857
|
+
rb_define_module_function(server_mod, "start", server_start, 0);
|
858
|
+
rb_define_module_function(server_mod, "shutdown", rserver_shutdown, 0);
|
859
|
+
|
860
|
+
rb_define_module_function(server_mod, "handle", handle, 3);
|
861
|
+
rb_define_module_function(server_mod, "handle_not_found", handle_not_found, 1);
|
862
|
+
rb_define_module_function(server_mod, "add_mime", add_mime, 2);
|
1006
863
|
|
1007
864
|
call_id = rb_intern("call");
|
1008
865
|
each_id = rb_intern("each");
|
866
|
+
on_close_id = rb_intern("on_close");
|
867
|
+
on_drained_id = rb_intern("on_drained");
|
868
|
+
on_message_id = rb_intern("on_message");
|
1009
869
|
on_request_id = rb_intern("on_request");
|
1010
870
|
to_i_id = rb_intern("to_i");
|
1011
871
|
|
1012
|
-
connect_sym = ID2SYM(rb_intern("CONNECT"));
|
1013
|
-
delete_sym = ID2SYM(rb_intern("DELETE"));
|
1014
|
-
get_sym = ID2SYM(rb_intern("GET"));
|
1015
|
-
head_sym = ID2SYM(rb_intern("HEAD"));
|
1016
|
-
options_sym = ID2SYM(rb_intern("OPTIONS"));
|
1017
|
-
post_sym = ID2SYM(rb_intern("POST"));
|
1018
|
-
put_sym = ID2SYM(rb_intern("PUT"));
|
872
|
+
connect_sym = ID2SYM(rb_intern("CONNECT")); rb_gc_register_address(&connect_sym);
|
873
|
+
delete_sym = ID2SYM(rb_intern("DELETE")); rb_gc_register_address(&delete_sym);
|
874
|
+
get_sym = ID2SYM(rb_intern("GET")); rb_gc_register_address(&get_sym);
|
875
|
+
head_sym = ID2SYM(rb_intern("HEAD")); rb_gc_register_address(&head_sym);
|
876
|
+
options_sym = ID2SYM(rb_intern("OPTIONS")); rb_gc_register_address(&options_sym);
|
877
|
+
post_sym = ID2SYM(rb_intern("POST")); rb_gc_register_address(&post_sym);
|
878
|
+
put_sym = ID2SYM(rb_intern("PUT")); rb_gc_register_address(&put_sym);
|
879
|
+
|
880
|
+
push_env_key = rb_str_new_cstr("rack.upgrade"); rb_gc_register_address(&push_env_key);
|
1019
881
|
|
1020
882
|
http_init();
|
1021
883
|
}
|