agoo 2.0.5 → 2.1.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/CHANGELOG.md +8 -0
- data/README.md +5 -2
- data/ext/agoo/agoo.c +35 -2
- data/ext/agoo/con.c +184 -86
- data/ext/agoo/con.h +4 -2
- data/ext/agoo/debug.c +2 -0
- data/ext/agoo/debug.h +2 -0
- data/ext/agoo/page.c +1 -0
- data/ext/agoo/pub.c +31 -27
- data/ext/agoo/pub.h +10 -11
- data/ext/agoo/request.c +5 -4
- data/ext/agoo/request.h +2 -1
- data/ext/agoo/res.c +3 -1
- data/ext/agoo/res.h +4 -1
- data/ext/agoo/server.c +55 -26
- data/ext/agoo/server.h +5 -3
- data/ext/agoo/subject.c +51 -0
- data/ext/agoo/subject.h +17 -0
- data/ext/agoo/text.c +18 -1
- data/ext/agoo/text.h +1 -0
- data/ext/agoo/upgraded.c +264 -57
- data/ext/agoo/upgraded.h +27 -1
- data/ext/agoo/websocket.c +10 -9
- data/lib/agoo/version.rb +1 -1
- metadata +4 -6
- data/ext/agoo/ccache.c +0 -301
- data/ext/agoo/ccache.h +0 -53
- data/ext/agoo/subscription.c +0 -54
- data/ext/agoo/subscription.h +0 -18
data/ext/agoo/con.h
CHANGED
@@ -15,9 +15,10 @@
|
|
15
15
|
|
16
16
|
#define MAX_HEADER_SIZE 8192
|
17
17
|
|
18
|
-
struct
|
18
|
+
struct _Upgraded;
|
19
19
|
|
20
20
|
typedef struct _Con {
|
21
|
+
struct _Con *next;
|
21
22
|
int sock;
|
22
23
|
ConKind kind;
|
23
24
|
struct pollfd *pp;
|
@@ -30,11 +31,12 @@ typedef struct _Con {
|
|
30
31
|
|
31
32
|
double timeout;
|
32
33
|
bool closing;
|
34
|
+
bool dead;
|
33
35
|
Req req;
|
34
36
|
Res res_head;
|
35
37
|
Res res_tail;
|
36
38
|
|
37
|
-
struct
|
39
|
+
struct _Upgraded *up; // only set for push connections
|
38
40
|
} *Con;
|
39
41
|
|
40
42
|
extern Con con_create(Err err, int sock, uint64_t id);
|
data/ext/agoo/debug.c
CHANGED
@@ -44,8 +44,10 @@ atomic_int mem_req = 0;
|
|
44
44
|
atomic_int mem_res = 0;
|
45
45
|
atomic_int mem_res_body = 0;
|
46
46
|
atomic_int mem_response = 0;
|
47
|
+
atomic_int mem_subject = 0;
|
47
48
|
atomic_int mem_text = 0;
|
48
49
|
atomic_int mem_to_s = 0;
|
50
|
+
atomic_int mem_upgraded = 0;
|
49
51
|
|
50
52
|
#ifdef MEM_DEBUG
|
51
53
|
static void
|
data/ext/agoo/debug.h
CHANGED
@@ -39,8 +39,10 @@ extern atomic_int mem_req;
|
|
39
39
|
extern atomic_int mem_res;
|
40
40
|
extern atomic_int mem_res_body;
|
41
41
|
extern atomic_int mem_response;
|
42
|
+
extern atomic_int mem_subject;
|
42
43
|
extern atomic_int mem_text;
|
43
44
|
extern atomic_int mem_to_s;
|
45
|
+
extern atomic_int mem_upgraded;
|
44
46
|
|
45
47
|
extern void debug_add(void *ptr, const char *type, const char *file, int line);
|
46
48
|
extern void debug_update(void *orig, void *ptr, const char *type, const char *file, int line);
|
data/ext/agoo/page.c
CHANGED
data/ext/agoo/pub.c
CHANGED
@@ -6,74 +6,79 @@
|
|
6
6
|
|
7
7
|
#include "debug.h"
|
8
8
|
#include "pub.h"
|
9
|
+
#include "subject.h"
|
9
10
|
#include "text.h"
|
11
|
+
#include "upgraded.h"
|
10
12
|
|
11
13
|
Pub
|
12
|
-
pub_close(
|
14
|
+
pub_close(Upgraded up) {
|
13
15
|
Pub p = (Pub)malloc(sizeof(struct _Pub));
|
14
16
|
|
15
17
|
if (NULL != p) {
|
16
18
|
DEBUG_ALLOC(mem_pub, p);
|
17
19
|
p->next = NULL;
|
18
20
|
p->kind = PUB_CLOSE;
|
19
|
-
p->
|
20
|
-
p->sid = 0;
|
21
|
+
p->up = up;
|
21
22
|
p->subject = NULL;
|
23
|
+
p->msg = NULL;
|
22
24
|
}
|
23
25
|
return p;
|
24
26
|
}
|
25
27
|
|
26
28
|
Pub
|
27
|
-
pub_subscribe(
|
29
|
+
pub_subscribe(Upgraded up, const char *subject, int slen) {
|
28
30
|
Pub p = (Pub)malloc(sizeof(struct _Pub));
|
29
31
|
|
30
32
|
if (NULL != p) {
|
31
33
|
DEBUG_ALLOC(mem_pub, p);
|
32
34
|
p->next = NULL;
|
33
35
|
p->kind = PUB_SUB;
|
34
|
-
p->
|
35
|
-
p->
|
36
|
-
p->
|
36
|
+
p->up = up;
|
37
|
+
p->subject = subject_create(subject, slen);
|
38
|
+
p->msg = NULL;
|
37
39
|
}
|
38
40
|
return p;
|
39
41
|
}
|
40
42
|
|
41
43
|
Pub
|
42
|
-
pub_unsubscribe(
|
44
|
+
pub_unsubscribe(Upgraded up, const char *subject, int slen) {
|
43
45
|
Pub p = (Pub)malloc(sizeof(struct _Pub));
|
44
46
|
|
45
47
|
if (NULL != p) {
|
46
48
|
DEBUG_ALLOC(mem_pub, p);
|
47
49
|
p->next = NULL;
|
48
50
|
p->kind = PUB_UN;
|
49
|
-
p->
|
50
|
-
|
51
|
-
|
51
|
+
p->up = up;
|
52
|
+
if (NULL != subject) {
|
53
|
+
p->subject = subject_create(subject, slen);
|
54
|
+
} else {
|
55
|
+
p->subject = NULL;
|
56
|
+
}
|
57
|
+
p->msg = NULL;
|
52
58
|
}
|
53
59
|
return p;
|
54
60
|
}
|
55
61
|
|
56
62
|
Pub
|
57
|
-
pub_publish(char *subject, const char *message, size_t mlen
|
63
|
+
pub_publish(char *subject, int slen, const char *message, size_t mlen) {
|
58
64
|
Pub p = (Pub)malloc(sizeof(struct _Pub));
|
59
65
|
|
60
66
|
if (NULL != p) {
|
61
67
|
DEBUG_ALLOC(mem_pub, p);
|
62
68
|
p->next = NULL;
|
63
69
|
p->kind = PUB_MSG;
|
64
|
-
p->
|
65
|
-
p->subject =
|
70
|
+
p->up = NULL;
|
71
|
+
p->subject = subject_create(subject, slen);
|
66
72
|
// Allocate an extra 24 bytes so the message can be expanded in place
|
67
73
|
// if a WebSocket or SSE write.
|
68
|
-
p->msg = text_allocate((int)mlen + 24);
|
69
|
-
p->msg = text_append(text_allocate((int)mlen + 16), message, (int)mlen);
|
74
|
+
p->msg = text_append(text_allocate((int)mlen + 24), message, (int)mlen);
|
70
75
|
text_ref(p->msg);
|
71
76
|
}
|
72
77
|
return p;
|
73
78
|
}
|
74
79
|
|
75
80
|
Pub
|
76
|
-
pub_write(
|
81
|
+
pub_write(Upgraded up, const char *message, size_t mlen, bool bin) {
|
77
82
|
// Allocate an extra 16 bytes so the message can be expanded in place if a
|
78
83
|
// WebSocket write.
|
79
84
|
Pub p = (Pub)malloc(sizeof(struct _Pub));
|
@@ -82,7 +87,7 @@ pub_write(uint64_t cid, const char *message, size_t mlen, bool bin) {
|
|
82
87
|
DEBUG_ALLOC(mem_pub, p);
|
83
88
|
p->next = NULL;
|
84
89
|
p->kind = PUB_WRITE;
|
85
|
-
p->
|
90
|
+
p->up = up;
|
86
91
|
p->subject = NULL;
|
87
92
|
// Allocate an extra 16 bytes so the message can be expanded in place
|
88
93
|
// if a WebSocket write.
|
@@ -95,15 +100,14 @@ pub_write(uint64_t cid, const char *message, size_t mlen, bool bin) {
|
|
95
100
|
|
96
101
|
void
|
97
102
|
pub_destroy(Pub pub) {
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
break;
|
103
|
+
if (NULL != pub->msg) {
|
104
|
+
text_release(pub->msg);
|
105
|
+
}
|
106
|
+
if (NULL != pub->subject) {
|
107
|
+
subject_destroy(pub->subject);
|
108
|
+
}
|
109
|
+
if (NULL != pub->up) {
|
110
|
+
upgraded_release(pub->up);
|
107
111
|
}
|
108
112
|
DEBUG_FREE(mem_pub, pub);
|
109
113
|
free(pub);
|
data/ext/agoo/pub.h
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
#include <stdlib.h>
|
9
9
|
|
10
10
|
struct _Text;
|
11
|
+
struct _Upgraded;
|
12
|
+
struct _Subject;
|
11
13
|
|
12
14
|
typedef enum {
|
13
15
|
PUB_SUB = 'S',
|
@@ -22,19 +24,16 @@ typedef enum {
|
|
22
24
|
typedef struct _Pub {
|
23
25
|
struct _Pub *next;
|
24
26
|
PubKind kind;
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
uint64_t sid;
|
29
|
-
struct _Text *msg;
|
30
|
-
};
|
27
|
+
struct _Upgraded *up;
|
28
|
+
struct _Subject *subject;
|
29
|
+
struct _Text *msg;
|
31
30
|
} *Pub;
|
32
31
|
|
33
|
-
extern Pub pub_close(
|
34
|
-
extern Pub pub_subscribe(
|
35
|
-
extern Pub pub_unsubscribe(
|
36
|
-
extern Pub pub_publish(char *subject, const char *message, size_t mlen
|
37
|
-
extern Pub pub_write(
|
32
|
+
extern Pub pub_close(struct _Upgraded *up);
|
33
|
+
extern Pub pub_subscribe(struct _Upgraded *up, const char *subject, int slen);
|
34
|
+
extern Pub pub_unsubscribe(struct _Upgraded *up, const char *subject, int slen);
|
35
|
+
extern Pub pub_publish(char *subject, int slen, const char *message, size_t mlen);
|
36
|
+
extern Pub pub_write(struct _Upgraded *up, const char *message, size_t mlen, bool bin);
|
38
37
|
extern void pub_destroy(Pub pub);
|
39
38
|
|
40
39
|
#endif // __AGOO_PUB_H__
|
data/ext/agoo/request.c
CHANGED
@@ -383,8 +383,9 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
|
|
383
383
|
} else if (sizeof(content_length) - 1 == klen && 0 == strncasecmp(key, content_length, sizeof(content_length) - 1)) {
|
384
384
|
rb_hash_aset(hh, content_length_val, rb_str_new(val, vlen));
|
385
385
|
} else {
|
386
|
-
char
|
387
|
-
char
|
386
|
+
char hkey[1024];
|
387
|
+
char *k = hkey;
|
388
|
+
volatile VALUE sval = rb_str_new(val, vlen);
|
388
389
|
|
389
390
|
strcpy(hkey, "HTTP_");
|
390
391
|
k = hkey + 5;
|
@@ -394,12 +395,12 @@ add_header_value(VALUE hh, const char *key, int klen, const char *val, int vlen)
|
|
394
395
|
strncpy(k, key, klen);
|
395
396
|
hkey[klen + 5] = '\0';
|
396
397
|
|
397
|
-
rb_hash_aset(hh, rb_str_new(hkey, klen + 5),
|
398
|
+
rb_hash_aset(hh, rb_str_new(hkey, klen + 5), sval);
|
398
399
|
// Contrary to the Rack spec, Rails expects all upper case keys so add those as well.
|
399
400
|
for (k = hkey + 5; '\0' != *k; k++) {
|
400
401
|
*k = toupper(*k);
|
401
402
|
}
|
402
|
-
rb_hash_aset(hh, rb_str_new(hkey, klen + 5),
|
403
|
+
rb_hash_aset(hh, rb_str_new(hkey, klen + 5), sval);
|
403
404
|
}
|
404
405
|
}
|
405
406
|
|
data/ext/agoo/request.h
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
#include "types.h"
|
13
13
|
|
14
14
|
struct _Server;
|
15
|
+
struct _Upgraded;
|
15
16
|
|
16
17
|
typedef enum {
|
17
18
|
UP_NONE = '\0',
|
@@ -27,7 +28,7 @@ typedef struct _Str {
|
|
27
28
|
typedef struct _Req {
|
28
29
|
Method method;
|
29
30
|
Upgrade upgrade;
|
30
|
-
|
31
|
+
struct _Upgraded *up;
|
31
32
|
struct _Str path;
|
32
33
|
struct _Str query;
|
33
34
|
struct _Str header;
|
data/ext/agoo/res.c
CHANGED
@@ -2,17 +2,19 @@
|
|
2
2
|
|
3
3
|
#include <stdlib.h>
|
4
4
|
|
5
|
+
#include "con.h"
|
5
6
|
#include "debug.h"
|
6
7
|
#include "res.h"
|
7
8
|
|
8
9
|
Res
|
9
|
-
res_create() {
|
10
|
+
res_create(Con con) {
|
10
11
|
Res res = (Res)malloc(sizeof(struct _Res));
|
11
12
|
|
12
13
|
if (NULL != res) {
|
13
14
|
DEBUG_ALLOC(mem_res, res)
|
14
15
|
res->next = NULL;
|
15
16
|
atomic_init(&res->message, NULL);
|
17
|
+
res->con = con;
|
16
18
|
res->con_kind = CON_HTTP;
|
17
19
|
res->close = false;
|
18
20
|
res->ping = false;
|
data/ext/agoo/res.h
CHANGED
@@ -11,8 +11,11 @@
|
|
11
11
|
#include "text.h"
|
12
12
|
#include "types.h"
|
13
13
|
|
14
|
+
struct _Con;
|
15
|
+
|
14
16
|
typedef struct _Res {
|
15
17
|
struct _Res *next;
|
18
|
+
struct _Con *con;
|
16
19
|
_Atomic(Text) message;
|
17
20
|
ConKind con_kind;
|
18
21
|
bool close;
|
@@ -20,7 +23,7 @@ typedef struct _Res {
|
|
20
23
|
bool pong;
|
21
24
|
} *Res;
|
22
25
|
|
23
|
-
extern Res res_create();
|
26
|
+
extern Res res_create(struct _Con *con);
|
24
27
|
extern void res_destroy(Res res);
|
25
28
|
extern void res_set_message(Res res, Text t);
|
26
29
|
|
data/ext/agoo/server.c
CHANGED
@@ -25,6 +25,7 @@
|
|
25
25
|
#include "dtime.h"
|
26
26
|
#include "err.h"
|
27
27
|
#include "http.h"
|
28
|
+
#include "pub.h"
|
28
29
|
#include "response.h"
|
29
30
|
#include "request.h"
|
30
31
|
#include "server.h"
|
@@ -46,6 +47,8 @@ static VALUE post_sym;
|
|
46
47
|
static VALUE push_env_key;
|
47
48
|
static VALUE put_sym;
|
48
49
|
|
50
|
+
static VALUE rserver;
|
51
|
+
|
49
52
|
static ID call_id;
|
50
53
|
static ID each_id;
|
51
54
|
static ID on_close_id;
|
@@ -58,6 +61,23 @@ static const char err500[] = "HTTP/1.1 500 Internal Server Error\r\n";
|
|
58
61
|
|
59
62
|
struct _Server the_server = {false};
|
60
63
|
|
64
|
+
static void
|
65
|
+
server_mark(void *ptr) {
|
66
|
+
Upgraded up;
|
67
|
+
|
68
|
+
rb_gc_mark(rserver);
|
69
|
+
pthread_mutex_lock(&the_server.up_lock);
|
70
|
+
for (up = the_server.up_list; NULL != up; up = up->next) {
|
71
|
+
if (Qnil != up->handler) {
|
72
|
+
rb_gc_mark(up->handler);
|
73
|
+
}
|
74
|
+
if (Qnil != up->wrap) {
|
75
|
+
rb_gc_mark(up->wrap);
|
76
|
+
}
|
77
|
+
}
|
78
|
+
pthread_mutex_unlock(&the_server.up_lock);
|
79
|
+
}
|
80
|
+
|
61
81
|
void
|
62
82
|
server_shutdown() {
|
63
83
|
if (the_server.inited) {
|
@@ -74,7 +94,6 @@ server_shutdown() {
|
|
74
94
|
the_server.con_thread = 0;
|
75
95
|
}
|
76
96
|
sub_cleanup(&the_server.sub_cache);
|
77
|
-
cc_cleanup(&the_server.con_cache);
|
78
97
|
// The preferred method to of waiting for the ruby threads would
|
79
98
|
// be either a join or even a kill but since we may not have the
|
80
99
|
// gvl here that would cause a segfault. Instead we set a timeout
|
@@ -89,7 +108,7 @@ server_shutdown() {
|
|
89
108
|
dsleep(0.02);
|
90
109
|
}
|
91
110
|
DEBUG_FREE(mem_eval_threads, the_server.eval_threads);
|
92
|
-
free(the_server.eval_threads);
|
111
|
+
free(the_server.eval_threads);
|
93
112
|
the_server.eval_threads = NULL;
|
94
113
|
}
|
95
114
|
while (NULL != the_server.hooks) {
|
@@ -217,8 +236,10 @@ rserver_init(int argc, VALUE *argv, VALUE self) {
|
|
217
236
|
queue_multi_init(&the_server.eval_queue, 1024, false, true);
|
218
237
|
|
219
238
|
cache_init(&the_server.pages);
|
220
|
-
cc_init(&the_server.con_cache);
|
221
239
|
sub_init(&the_server.sub_cache);
|
240
|
+
|
241
|
+
pthread_mutex_init(&the_server.up_lock, 0);
|
242
|
+
the_server.up_list = NULL;
|
222
243
|
|
223
244
|
the_server.inited = true;
|
224
245
|
|
@@ -320,21 +341,25 @@ rescue_error(VALUE x) {
|
|
320
341
|
volatile VALUE msg = rb_funcall(info, rb_intern("message"), 0);
|
321
342
|
const char *classname = rb_obj_classname(info);
|
322
343
|
const char *ms = rb_string_value_ptr(&msg);
|
323
|
-
char buf[1024];
|
324
|
-
int len = (int)(strlen(classname) + 2 + strlen(ms));
|
325
|
-
int cnt;
|
326
|
-
Text message;
|
327
344
|
|
328
|
-
if (
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
345
|
+
if (NULL == req->up) {
|
346
|
+
char buf[1024];
|
347
|
+
int len = (int)(strlen(classname) + 2 + strlen(ms));
|
348
|
+
int cnt;
|
349
|
+
Text message;
|
333
350
|
|
334
|
-
|
335
|
-
|
336
|
-
|
351
|
+
if ((int)(sizeof(buf) - sizeof(bad500) + 7) <= len) {
|
352
|
+
len = sizeof(buf) - sizeof(bad500) + 7;
|
353
|
+
}
|
354
|
+
cnt = snprintf(buf, sizeof(buf), "%s%d\r\n\r\n%s: %s", bad500, len, classname, ms);
|
355
|
+
message = text_create(buf, cnt);
|
337
356
|
|
357
|
+
req->res->close = true;
|
358
|
+
res_set_message(req->res, message);
|
359
|
+
queue_wakeup(&the_server.con_queue);
|
360
|
+
} else {
|
361
|
+
log_cat(&error_cat, "%s: %s", classname, ms);
|
362
|
+
}
|
338
363
|
return Qfalse;
|
339
364
|
}
|
340
365
|
|
@@ -495,7 +520,7 @@ handle_rack_inner(void *x) {
|
|
495
520
|
break;
|
496
521
|
}
|
497
522
|
req->handler_type = PUSH_HOOK;
|
498
|
-
|
523
|
+
upgraded_create(req->res->con, req->handler);
|
499
524
|
t->len = snprintf(t->text, 1024, "HTTP/1.1 101 %s\r\n", status_msg);
|
500
525
|
t = ws_add_headers(req, t);
|
501
526
|
break;
|
@@ -507,7 +532,7 @@ handle_rack_inner(void *x) {
|
|
507
532
|
break;
|
508
533
|
}
|
509
534
|
req->handler_type = PUSH_HOOK;
|
510
|
-
|
535
|
+
upgraded_create(req->res->con, req->handler);
|
511
536
|
t = sse_upgrade(req, t);
|
512
537
|
res_set_message(req->res, t);
|
513
538
|
queue_wakeup(&the_server.con_queue);
|
@@ -548,9 +573,6 @@ handle_rack_inner(void *x) {
|
|
548
573
|
|
549
574
|
static void*
|
550
575
|
handle_rack(void *x) {
|
551
|
-
// Disable GC. The handle_rack function or rather the env seems to get
|
552
|
-
// collected even though it is volatile so for now turn off GC
|
553
|
-
// temporarily.
|
554
576
|
//rb_gc_disable();
|
555
577
|
rb_rescue2(handle_rack_inner, (VALUE)x, rescue_error, (VALUE)x, rb_eException, 0);
|
556
578
|
//rb_gc_enable();
|
@@ -587,27 +609,31 @@ handle_push_inner(void *x) {
|
|
587
609
|
|
588
610
|
switch (req->method) {
|
589
611
|
case ON_MSG:
|
590
|
-
rb_funcall(req->handler, on_message_id,
|
612
|
+
rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rb_str_new(req->msg, req->mlen));
|
591
613
|
break;
|
592
614
|
case ON_BIN: {
|
593
615
|
volatile VALUE rstr = rb_str_new(req->msg, req->mlen);
|
594
616
|
|
595
617
|
rb_enc_associate(rstr, rb_ascii8bit_encoding());
|
596
|
-
rb_funcall(req->handler, on_message_id,
|
618
|
+
rb_funcall(req->handler, on_message_id, 2, req->up->wrap, rstr);
|
597
619
|
break;
|
598
620
|
}
|
599
621
|
case ON_CLOSE:
|
600
|
-
|
622
|
+
upgraded_ref(req->up);
|
623
|
+
queue_push(&the_server.pub_queue, pub_close(req->up));
|
624
|
+
rb_funcall(req->handler, on_close_id, 1, req->up->wrap);
|
601
625
|
break;
|
602
626
|
case ON_SHUTDOWN:
|
603
|
-
rb_funcall(req->handler, rb_intern("on_shutdown"),
|
627
|
+
rb_funcall(req->handler, rb_intern("on_shutdown"), 1, req->up->wrap);
|
604
628
|
break;
|
605
629
|
case ON_EMPTY:
|
606
|
-
rb_funcall(req->handler, on_drained_id,
|
630
|
+
rb_funcall(req->handler, on_drained_id, 1, req->up->wrap);
|
607
631
|
break;
|
608
632
|
default:
|
609
633
|
break;
|
610
634
|
}
|
635
|
+
upgraded_release(req->up);
|
636
|
+
|
611
637
|
return Qfalse;
|
612
638
|
}
|
613
639
|
|
@@ -652,7 +678,7 @@ handle_protected(Req req, bool gvi) {
|
|
652
678
|
char buf[256];
|
653
679
|
int cnt = snprintf(buf, sizeof(buf), "HTTP/1.1 500 Internal Error\r\nConnection: Close\r\nContent-Length: 0\r\n\r\n");
|
654
680
|
Text message = text_create(buf, cnt);
|
655
|
-
|
681
|
+
|
656
682
|
req->res->close = true;
|
657
683
|
res_set_message(req->res, message);
|
658
684
|
queue_wakeup(&the_server.con_queue);
|
@@ -881,5 +907,8 @@ server_init(VALUE mod) {
|
|
881
907
|
|
882
908
|
push_env_key = rb_str_new_cstr("rack.upgrade"); rb_gc_register_address(&push_env_key);
|
883
909
|
|
910
|
+
rserver = Data_Wrap_Struct(rb_cObject, server_mark, NULL, strdup("dummy"));
|
911
|
+
rb_gc_register_address(&rserver);
|
912
|
+
|
884
913
|
http_init();
|
885
914
|
}
|