nyara 0.0.1.pre.2 → 0.0.1.pre.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/accept.c +29 -33
- data/ext/event.c +218 -22
- data/ext/extconf.rb +3 -3
- data/ext/hashes.c +2 -1
- data/ext/http_parser.c +6 -0
- data/ext/inc/epoll.h +11 -9
- data/ext/inc/kqueue.h +14 -17
- data/ext/inc/str_intern.h +2 -2
- data/ext/mime.c +2 -0
- data/ext/multipart_parser.c +2 -0
- data/ext/nyara.c +2 -0
- data/ext/nyara.h +15 -9
- data/ext/request.c +88 -266
- data/ext/request.h +43 -0
- data/ext/request_parse.c +123 -0
- data/ext/route.cc +2 -0
- data/ext/url_encoded.c +66 -6
- data/hello.rb +8 -2
- data/lib/nyara/controller.rb +29 -10
- data/lib/nyara/cookie.rb +3 -2
- data/lib/nyara/nyara.rb +41 -27
- data/lib/nyara/patch_tcp_socket.rb +22 -0
- data/lib/nyara/request.rb +1 -3
- data/lib/nyara/view.rb +1 -0
- data/nyara.gemspec +1 -1
- data/rakefile +63 -42
- data/readme.md +34 -5
- data/spec/apps/connect.rb +14 -0
- data/spec/evented_io_spec.rb +23 -0
- data/spec/ext_parse_spec.rb +26 -7
- data/spec/performance/layout_render.rb +52 -0
- data/spec/performance/parse_accept_value.rb +13 -0
- data/spec/performance/parse_param.rb +18 -0
- data/spec/performance/performance_helper.rb +25 -0
- data/spec/performance_spec.rb +33 -0
- data/spec/request_delegate_spec.rb +41 -16
- data/spec/request_spec.rb +4 -7
- data/spec/spec_helper.rb +20 -10
- metadata +15 -6
- /data/lib/nyara/{config_hash.rb → hashes/config_hash.rb} +0 -0
- /data/lib/nyara/{header_hash.rb → hashes/header_hash.rb} +0 -0
- /data/lib/nyara/{param_hash.rb → hashes/param_hash.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52583810c7afb74e920b0da7336e82441471ab82
|
4
|
+
data.tar.gz: 6fbd035f24bbd10ad1ade4ffdfce186e3a0d779f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a3abf537a5027658497d171a5a593153316e60214b81c80f4f93c1e0557478f7473136b5cec6fc0daa76eedbb7650b01a284c72098a3069fa95bffd18ec468a
|
7
|
+
data.tar.gz: 8c5031033482180d9e0c1b3a4e541274abb562de5b1d04e81855c7ca556c7fcc44415abcf06a694b001f1c6a8dbd273509490a8ba45f3c58a0cf595921d92731
|
data/ext/accept.c
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
/*
|
1
|
+
/* http accpet* value parser */
|
2
2
|
|
3
3
|
#include "nyara.h"
|
4
4
|
#include <ctype.h>
|
@@ -11,42 +11,39 @@
|
|
11
11
|
// +level+ is a waste of time:
|
12
12
|
// http://stackoverflow.com/questions/13890996/http-accept-level
|
13
13
|
|
14
|
+
#define ACCEPT_MAX 1000
|
15
|
+
|
14
16
|
// sorted data structure
|
15
|
-
typedef struct {
|
16
|
-
double* qs;
|
17
|
-
long len;
|
18
|
-
long cap;
|
19
|
-
} QArray;
|
20
17
|
|
21
|
-
static
|
22
|
-
|
23
|
-
return qa;
|
24
|
-
}
|
18
|
+
static double qarray[ACCEPT_MAX];
|
19
|
+
static long qarray_len = 0;
|
25
20
|
|
26
21
|
// return inserted pos
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if (qa->qs[i] < v) {
|
35
|
-
memmove(qa->qs + i + 1, qa->qs + i, sizeof(double) * (qa->len - i));
|
22
|
+
// the sort is "stable", which doesn't swap elements with the same q
|
23
|
+
static long qarray_insert(double v) {
|
24
|
+
long i = qarray_len;
|
25
|
+
for (long j = qarray_len - 1; j >= 0; j--) {
|
26
|
+
if (qarray[j] < v) {
|
27
|
+
i = j;
|
28
|
+
} else {
|
36
29
|
break;
|
37
30
|
}
|
38
31
|
}
|
39
|
-
|
40
|
-
|
32
|
+
memmove(qarray + i + 1, qarray + i, sizeof(double) * (qarray_len - i));
|
33
|
+
qarray[i] = v;
|
34
|
+
qarray_len++;
|
41
35
|
return i;
|
42
36
|
}
|
43
37
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
static VALUE trim_space(volatile VALUE str) {
|
38
|
+
// why truncate:
|
39
|
+
// 1. normal user never send such long Aceept
|
40
|
+
// 2. qarray_insert is O(n^2) in worst case, can lead to ddos vulnerability if there are more than 50000 accept entries
|
41
|
+
static VALUE trim_space_and_truncate(volatile VALUE str) {
|
49
42
|
long olen = RSTRING_LEN(str);
|
43
|
+
if (olen > ACCEPT_MAX) {
|
44
|
+
// todo log this exception
|
45
|
+
olen = ACCEPT_MAX;
|
46
|
+
}
|
50
47
|
str = rb_str_new(RSTRING_PTR(str), olen);
|
51
48
|
char* s = RSTRING_PTR(str);
|
52
49
|
long len = 0;
|
@@ -80,8 +77,8 @@ static const char* find_q(const char* s, long len) {
|
|
80
77
|
return NULL;
|
81
78
|
}
|
82
79
|
|
83
|
-
// parse a segment, and
|
84
|
-
static void parse_seg(const char* s, long len, VALUE out
|
80
|
+
// parse a segment, and store in a sorted array, also updates qarray
|
81
|
+
static void parse_seg(const char* s, long len, VALUE out) {
|
85
82
|
double qval = 1;
|
86
83
|
const char* q = find_q(s, len);
|
87
84
|
if (q) {
|
@@ -97,7 +94,7 @@ static void parse_seg(const char* s, long len, VALUE out, QArray* qa) {
|
|
97
94
|
}
|
98
95
|
len = q - s;
|
99
96
|
}
|
100
|
-
long pos = qarray_insert(
|
97
|
+
long pos = qarray_insert(qval);
|
101
98
|
rb_ary_push(out, Qnil); // just to increase cap
|
102
99
|
VALUE* out_ptr = RARRAY_PTR(out);
|
103
100
|
long out_len = RARRAY_LEN(out); // note this len is +1
|
@@ -110,21 +107,20 @@ VALUE ext_parse_accept_value(VALUE _, volatile VALUE str) {
|
|
110
107
|
return rb_ary_new();
|
111
108
|
}
|
112
109
|
|
113
|
-
str =
|
110
|
+
str = trim_space_and_truncate(str);
|
114
111
|
const char* s = RSTRING_PTR(str);
|
115
112
|
long len = RSTRING_LEN(str);
|
116
113
|
volatile VALUE out = rb_ary_new();
|
117
|
-
|
114
|
+
qarray_len = 0;
|
118
115
|
while (len > 0) {
|
119
116
|
long seg_len = find_seg(s, len);
|
120
117
|
if (seg_len == 0) {
|
121
118
|
break;
|
122
119
|
}
|
123
|
-
parse_seg(s, seg_len, out
|
120
|
+
parse_seg(s, seg_len, out);
|
124
121
|
s += seg_len + 1;
|
125
122
|
len -= seg_len + 1;
|
126
123
|
}
|
127
|
-
qarray_delete(&qa);
|
128
124
|
return out;
|
129
125
|
}
|
130
126
|
|
data/ext/event.c
CHANGED
@@ -1,62 +1,167 @@
|
|
1
|
+
/* unify API for epoll and kqueue */
|
2
|
+
|
1
3
|
#include "nyara.h"
|
4
|
+
#include "request.h"
|
2
5
|
#include <sys/fcntl.h>
|
3
6
|
#include <sys/socket.h>
|
4
7
|
#include <errno.h>
|
5
8
|
#include <stdint.h>
|
6
9
|
#include <unistd.h>
|
7
10
|
|
8
|
-
#
|
9
|
-
|
11
|
+
#ifndef rb_obj_hide
|
12
|
+
extern VALUE rb_obj_hide(VALUE obj);
|
13
|
+
extern VALUE rb_obj_reveal(VALUE obj, VALUE klass);
|
14
|
+
#endif
|
15
|
+
|
16
|
+
#define ETYPE_CAN_ACCEPT 0
|
17
|
+
#define ETYPE_HANDLE_REQUEST 1
|
10
18
|
#define ETYPE_CONNECT 2
|
11
19
|
#define MAX_E 1024
|
12
20
|
static void loop_body(int fd, int etype);
|
13
21
|
static int qfd;
|
14
22
|
|
23
|
+
#define MAX_RECEIVE_DATA 65536
|
24
|
+
static char received_data[MAX_RECEIVE_DATA];
|
25
|
+
extern http_parser_settings nyara_request_parse_settings;
|
26
|
+
|
15
27
|
#ifdef HAVE_KQUEUE
|
16
28
|
#include "inc/kqueue.h"
|
17
29
|
#elif HAVE_EPOLL
|
18
30
|
#include "inc/epoll.h"
|
19
31
|
#endif
|
20
32
|
|
21
|
-
static
|
33
|
+
static VALUE fd_request_map;
|
34
|
+
static VALUE watch_request_map;
|
35
|
+
static ID id_not_found;
|
36
|
+
static VALUE sym_term_close;
|
37
|
+
static VALUE sym_writing;
|
38
|
+
static VALUE sym_reading;
|
39
|
+
static Request* curr_request;
|
40
|
+
|
41
|
+
static void _set_nonblock(int fd) {
|
22
42
|
int flags;
|
23
43
|
|
24
44
|
if ((flags = fcntl(fd, F_GETFL)) == -1) {
|
25
|
-
|
45
|
+
rb_sys_fail("fcntl(F_GETFL)");
|
26
46
|
}
|
27
47
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
28
|
-
|
48
|
+
rb_sys_fail("fcntl(F_SETFL,O_NONBLOCK)");
|
29
49
|
}
|
30
50
|
}
|
31
51
|
|
32
|
-
static VALUE
|
33
|
-
|
34
|
-
|
52
|
+
static VALUE _fiber_func(VALUE _, VALUE args) {
|
53
|
+
VALUE instance = rb_ary_pop(args);
|
54
|
+
VALUE meth = rb_ary_pop(args);
|
55
|
+
rb_apply(instance, SYM2ID(meth), args);
|
35
56
|
return Qnil;
|
36
57
|
}
|
37
58
|
|
59
|
+
static void _handle_request(VALUE request) {
|
60
|
+
Request* p;
|
61
|
+
Data_Get_Struct(request, Request, p);
|
62
|
+
curr_request = p;
|
63
|
+
|
64
|
+
// read and parse data
|
65
|
+
// NOTE we don't let http_parser invoke ruby code, because:
|
66
|
+
// 1. so the stack is shallower
|
67
|
+
// 2. Fiber.yield can pause http_parser, then the unparsed received_data is lost
|
68
|
+
long len = read(p->fd, received_data, MAX_RECEIVE_DATA);
|
69
|
+
if (len < 0) {
|
70
|
+
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
71
|
+
// this can happen when 2 events are fetched, and first event closes the fd, then second event fails
|
72
|
+
if (p->fd) {
|
73
|
+
nyara_detach_fd(p->fd);
|
74
|
+
p->fd = 0;
|
75
|
+
}
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
} else if (len) {
|
79
|
+
// note: for http_parser, len = 0 means eof reached
|
80
|
+
// but when in a fd-becomes-writable event it can also be 0
|
81
|
+
http_parser_execute(&(p->hparser), &nyara_request_parse_settings, received_data, len);
|
82
|
+
}
|
83
|
+
|
84
|
+
if (!p->parse_state) {
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
|
88
|
+
// ensure action
|
89
|
+
if (p->fiber == Qnil) {
|
90
|
+
volatile RouteResult result = nyara_lookup_route(p->method, p->path, p->accept);
|
91
|
+
if (RTEST(result.controller)) {
|
92
|
+
rb_ary_push(result.args, rb_class_new_instance(1, &(p->self), result.controller));
|
93
|
+
// result.args is on stack, no need to worry gc
|
94
|
+
p->fiber = rb_fiber_new(_fiber_func, result.args);
|
95
|
+
p->scope = result.scope;
|
96
|
+
p->format = result.format;
|
97
|
+
p->response_header = rb_class_new_instance(0, NULL, nyara_header_hash_class);
|
98
|
+
p->response_header_extra_lines = rb_ary_new();
|
99
|
+
} else {
|
100
|
+
rb_funcall(p->self, id_not_found, 0);
|
101
|
+
nyara_detach_fd(p->fd);
|
102
|
+
p->fd = 0;
|
103
|
+
return;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
// resume action
|
108
|
+
VALUE state = rb_fiber_resume(p->fiber, 0, NULL);
|
109
|
+
if (state == Qnil) { // _fiber_func always returns Qnil
|
110
|
+
// terminated (todo log raised error ?)
|
111
|
+
nyara_request_term_close(request, false);
|
112
|
+
} else if (state == sym_term_close) {
|
113
|
+
nyara_request_term_close(request, true);
|
114
|
+
} else if (state == sym_writing) {
|
115
|
+
// do nothing
|
116
|
+
} else if (state == sym_reading) {
|
117
|
+
// do nothing
|
118
|
+
} else {
|
119
|
+
// double value: sleep
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
38
123
|
// platform independent, invoked by LOOP_E()
|
39
124
|
static void loop_body(int fd, int etype) {
|
40
125
|
switch (etype) {
|
41
|
-
case
|
126
|
+
case ETYPE_CAN_ACCEPT: {
|
42
127
|
int cfd = accept(fd, NULL, NULL);
|
43
128
|
if (cfd > 0) {
|
44
|
-
|
45
|
-
ADD_E(cfd,
|
129
|
+
_set_nonblock(cfd);
|
130
|
+
ADD_E(cfd, ETYPE_HANDLE_REQUEST);
|
46
131
|
}
|
47
132
|
break;
|
48
133
|
}
|
49
|
-
case
|
50
|
-
|
134
|
+
case ETYPE_HANDLE_REQUEST: {
|
135
|
+
VALUE key = INT2FIX(fd);
|
136
|
+
volatile VALUE request = rb_hash_aref(fd_request_map, key);
|
137
|
+
if (request == Qnil) {
|
138
|
+
request = nyara_request_new(fd);
|
139
|
+
rb_hash_aset(fd_request_map, key, request);
|
140
|
+
}
|
141
|
+
_handle_request(request);
|
51
142
|
break;
|
52
143
|
}
|
53
144
|
case ETYPE_CONNECT: {
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
145
|
+
VALUE request = rb_hash_aref(watch_request_map, INT2FIX(fd));
|
146
|
+
if (request != Qnil) {
|
147
|
+
_handle_request(request);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
void nyara_detach_fd(int fd) {
|
154
|
+
VALUE request = rb_hash_delete(fd_request_map, INT2FIX(fd));
|
155
|
+
if (request != Qnil) {
|
156
|
+
Request* p;
|
157
|
+
Data_Get_Struct(request, Request, p);
|
158
|
+
VALUE* watched = RARRAY_PTR(p->watched_fds);
|
159
|
+
long watched_len = RARRAY_LEN(p->watched_fds);
|
160
|
+
for (long i = 0; i < watched_len; i++) {
|
161
|
+
rb_hash_delete(watch_request_map, watched[i]);
|
58
162
|
}
|
59
163
|
}
|
164
|
+
close(fd);
|
60
165
|
}
|
61
166
|
|
62
167
|
static VALUE ext_init_queue(VALUE _) {
|
@@ -66,8 +171,8 @@ static VALUE ext_init_queue(VALUE _) {
|
|
66
171
|
|
67
172
|
static VALUE ext_run_queue(VALUE _, VALUE v_fd) {
|
68
173
|
int fd = FIX2INT(v_fd);
|
69
|
-
|
70
|
-
ADD_E(fd,
|
174
|
+
_set_nonblock(fd);
|
175
|
+
ADD_E(fd, ETYPE_CAN_ACCEPT);
|
71
176
|
|
72
177
|
LOOP_E();
|
73
178
|
return Qnil;
|
@@ -75,15 +180,106 @@ static VALUE ext_run_queue(VALUE _, VALUE v_fd) {
|
|
75
180
|
|
76
181
|
static VALUE ext_set_nonblock(VALUE _, VALUE v_fd) {
|
77
182
|
int fd = FIX2INT(v_fd);
|
78
|
-
|
183
|
+
_set_nonblock(fd);
|
79
184
|
return Qnil;
|
80
185
|
}
|
81
186
|
|
187
|
+
static VALUE ext_fd_watch(VALUE _, VALUE v_fd) {
|
188
|
+
int fd = NUM2INT(v_fd);
|
189
|
+
rb_hash_aset(watch_request_map, v_fd, curr_request->self);
|
190
|
+
rb_ary_push(curr_request->watched_fds, v_fd);
|
191
|
+
ADD_E(fd, ETYPE_CONNECT);
|
192
|
+
return Qnil;
|
193
|
+
}
|
194
|
+
|
195
|
+
// override TCPSocket.send
|
196
|
+
// returns sent length
|
197
|
+
static VALUE ext_fd_send(VALUE _, VALUE v_fd, VALUE v_data, VALUE v_flags) {
|
198
|
+
int flags = NUM2INT(v_flags);
|
199
|
+
int fd = NUM2INT(v_fd);
|
200
|
+
char* buf = RSTRING_PTR(v_data);
|
201
|
+
long len = RSTRING_LEN(v_data);
|
202
|
+
|
203
|
+
// similar to _send_data in request.c
|
204
|
+
while(len) {
|
205
|
+
long written = send(fd, buf, len, flags);
|
206
|
+
if (written <= 0) {
|
207
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
208
|
+
rb_fiber_yield(1, &sym_writing);
|
209
|
+
continue;
|
210
|
+
} else {
|
211
|
+
rb_sys_fail("send(2)");
|
212
|
+
break;
|
213
|
+
}
|
214
|
+
} else {
|
215
|
+
buf += written;
|
216
|
+
len -= written;
|
217
|
+
if (len) {
|
218
|
+
rb_fiber_yield(1, &sym_writing);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
return LONG2NUM(RSTRING_LEN(v_data) - len);
|
224
|
+
}
|
225
|
+
|
226
|
+
// override TCPSocket.recv
|
227
|
+
// simulate blocking recv len or eof
|
228
|
+
static VALUE ext_fd_recv(VALUE _, VALUE v_fd, VALUE v_len, VALUE v_flags) {
|
229
|
+
int flags = NUM2INT(v_flags);
|
230
|
+
int fd = NUM2INT(v_fd);
|
231
|
+
long buf_len = NUM2INT(v_len); // int shall be large enough...
|
232
|
+
|
233
|
+
volatile VALUE str = rb_tainted_str_new(0, buf_len);
|
234
|
+
volatile VALUE klass = RBASIC(str)->klass;
|
235
|
+
rb_obj_hide(str);
|
236
|
+
|
237
|
+
char* s = RSTRING_PTR(str);
|
238
|
+
while(buf_len) {
|
239
|
+
long recved = recv(fd, s, buf_len, flags);
|
240
|
+
if (recved < 0) {
|
241
|
+
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
242
|
+
rb_fiber_yield(1, &sym_reading);
|
243
|
+
continue;
|
244
|
+
} else {
|
245
|
+
rb_sys_fail("recv(2)");
|
246
|
+
break;
|
247
|
+
}
|
248
|
+
} else if (recved == 0) { // reached EOF
|
249
|
+
break;
|
250
|
+
}
|
251
|
+
s += recved;
|
252
|
+
buf_len -= recved;
|
253
|
+
}
|
254
|
+
|
255
|
+
if (RBASIC(str)->klass || RSTRING_LEN(str) != NUM2INT(v_len)) {
|
256
|
+
rb_raise(rb_eRuntimeError, "buffer string modified");
|
257
|
+
}
|
258
|
+
rb_obj_reveal(str, klass);
|
259
|
+
if (buf_len) {
|
260
|
+
rb_str_set_len(str, RSTRING_LEN(str) - buf_len);
|
261
|
+
}
|
262
|
+
rb_obj_taint(str);
|
263
|
+
|
264
|
+
return str;
|
265
|
+
}
|
266
|
+
|
82
267
|
void Init_event(VALUE ext) {
|
83
|
-
|
268
|
+
fd_request_map = rb_hash_new();
|
269
|
+
rb_gc_register_mark_object(fd_request_map);
|
270
|
+
watch_request_map = rb_hash_new();
|
271
|
+
rb_gc_register_mark_object(watch_request_map);
|
272
|
+
id_not_found = rb_intern("not_found");
|
273
|
+
sym_term_close = ID2SYM(rb_intern("term_close"));
|
274
|
+
sym_writing = ID2SYM(rb_intern("writing"));
|
275
|
+
sym_reading = ID2SYM(rb_intern("reading"));
|
276
|
+
|
84
277
|
rb_define_singleton_method(ext, "init_queue", ext_init_queue, 0);
|
85
278
|
rb_define_singleton_method(ext, "run_queue", ext_run_queue, 1);
|
86
279
|
|
87
|
-
//
|
280
|
+
// fd operations
|
88
281
|
rb_define_singleton_method(ext, "set_nonblock", ext_set_nonblock, 1);
|
282
|
+
rb_define_singleton_method(ext, "fd_watch", ext_fd_watch, 1);
|
283
|
+
rb_define_singleton_method(ext, "fd_send", ext_fd_send, 3);
|
284
|
+
rb_define_singleton_method(ext, "fd_recv", ext_fd_recv, 3);
|
89
285
|
}
|
data/ext/extconf.rb
CHANGED
@@ -12,11 +12,11 @@ end
|
|
12
12
|
def tweak_cflags
|
13
13
|
mf_conf = RbConfig::MAKEFILE_CONFIG
|
14
14
|
if mf_conf['CC'] =~ /clang/
|
15
|
-
# enable c++
|
16
|
-
mf_conf['CXXFLAGS'] << ' -stdlib=libc++ -std=c++
|
15
|
+
# enable c++0x. this can not be installed on $CPPFLAGS, wtf??
|
16
|
+
mf_conf['CXXFLAGS'] << ' -stdlib=libc++ -std=c++0x'
|
17
17
|
$CFLAGS << ' $(xflags)'
|
18
18
|
else
|
19
|
-
mf_conf['CXXFLAGS'] << ' -std=c++
|
19
|
+
mf_conf['CXXFLAGS'] << ' -std=c++0x'
|
20
20
|
$CFLAGS << ' -std=c99 -Wno-declaration-after-statement $(xflags)'
|
21
21
|
end
|
22
22
|
|
data/ext/hashes.c
CHANGED
data/ext/http_parser.c
CHANGED
data/ext/inc/epoll.h
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
/* epoll event adapter */
|
2
|
+
|
1
3
|
#pragma once
|
2
4
|
|
3
5
|
#include <sys/epoll.h>
|
@@ -6,7 +8,7 @@ static struct epoll_event qevents[MAX_E];
|
|
6
8
|
|
7
9
|
static void ADD_E(int fd, uint64_t etype) {
|
8
10
|
struct epoll_event e;
|
9
|
-
e.events = EPOLLIN;
|
11
|
+
e.events = EPOLLIN | EPOLLOUT;
|
10
12
|
e.data.u64 = (etype << 32) | (uint64_t)fd;
|
11
13
|
|
12
14
|
// todo timeout
|
@@ -18,9 +20,11 @@ static void ADD_E(int fd, uint64_t etype) {
|
|
18
20
|
# endif
|
19
21
|
}
|
20
22
|
|
23
|
+
// either epoll or kqueue removes the event watch from queue when fd closed
|
24
|
+
// seems this is not required in epoll?
|
21
25
|
static void DEL_E(int fd) {
|
22
26
|
struct epoll_event e;
|
23
|
-
e.events = EPOLLIN;
|
27
|
+
e.events = EPOLLIN | EPOLLOUT;
|
24
28
|
e.data.ptr = NULL;
|
25
29
|
|
26
30
|
# ifdef NDEBUG
|
@@ -45,13 +49,11 @@ static void LOOP_E() {
|
|
45
49
|
int sz = epoll_wait(qfd, qevents, MAX_E, 100);
|
46
50
|
|
47
51
|
for (int i = 0; i < sz; i++) {
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
break;
|
54
|
-
}
|
52
|
+
if (qevents[i].events & (EPOLLIN | EPOLLOUT)) {
|
53
|
+
int fd = (int)(qevents[i].data.u64 & 0xFFFFFFFF);
|
54
|
+
int etype = (int)(qevents[i].data.u64 >> 32);
|
55
|
+
loop_body(fd, etype);
|
56
|
+
break;
|
55
57
|
}
|
56
58
|
}
|
57
59
|
// execute other thread / interrupts
|
data/ext/inc/kqueue.h
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
/* kqueue event adapter */
|
2
|
+
|
1
3
|
#pragma once
|
2
4
|
|
3
5
|
#include <sys/types.h>
|
@@ -8,15 +10,13 @@
|
|
8
10
|
# include <sys/queue.h>
|
9
11
|
#endif
|
10
12
|
|
11
|
-
static void loop_body(int fd, int etype);
|
12
|
-
|
13
13
|
#define MAX_E 1024
|
14
14
|
static int qfd;
|
15
15
|
static struct kevent qevents[MAX_E];
|
16
16
|
|
17
17
|
static void ADD_E(int fd, uint64_t etype) {
|
18
18
|
struct kevent e;
|
19
|
-
EV_SET(&e, fd, EVFILT_READ, EV_ADD, 0, 0, (void*)etype);
|
19
|
+
EV_SET(&e, fd, EVFILT_READ | EVFILT_WRITE, EV_ADD, 0, 0, (void*)etype);
|
20
20
|
// todo timeout
|
21
21
|
# ifdef NDEBUG
|
22
22
|
kevent(qfd, &e, 1, NULL, 0, NULL);
|
@@ -26,9 +26,9 @@ static void ADD_E(int fd, uint64_t etype) {
|
|
26
26
|
# endif
|
27
27
|
}
|
28
28
|
|
29
|
-
static void DEL_E(int fd) {
|
29
|
+
static void DEL_E(int fd, int filter) {
|
30
30
|
struct kevent e;
|
31
|
-
EV_SET(&e, fd,
|
31
|
+
EV_SET(&e, fd, filter, EV_DELETE, 0, 0, NULL);
|
32
32
|
# ifdef NDEBUG
|
33
33
|
kevent(qfd, &e, 1, NULL, 0, NULL);
|
34
34
|
# else
|
@@ -57,18 +57,15 @@ static void LOOP_E() {
|
|
57
57
|
int sz = kevent(qfd, NULL, 0, qevents, MAX_E, &ts);
|
58
58
|
|
59
59
|
for (int i = 0; i < sz; i++) {
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
}
|
70
|
-
break;
|
71
|
-
}
|
60
|
+
int fd = (int)qevents[i].ident;
|
61
|
+
if (qevents[i].flags & EV_EOF) {
|
62
|
+
// EV_EOF is set if the read side of the socket is shutdown
|
63
|
+
// the event can keep flipping back to consume cpu if we don't remove it
|
64
|
+
DEL_E(fd, qevents[i].filter);
|
65
|
+
}
|
66
|
+
if (qevents[i].filter & (EVFILT_READ | EVFILT_WRITE)) {
|
67
|
+
loop_body(fd, (int)qevents[i].udata);
|
68
|
+
break;
|
72
69
|
}
|
73
70
|
}
|
74
71
|
// execute other thread / interrupts
|
data/ext/inc/str_intern.h
CHANGED
data/ext/mime.c
CHANGED
data/ext/multipart_parser.c
CHANGED
data/ext/nyara.c
CHANGED
data/ext/nyara.h
CHANGED
@@ -9,35 +9,41 @@
|
|
9
9
|
#endif
|
10
10
|
|
11
11
|
|
12
|
-
/*
|
12
|
+
/* event.c */
|
13
13
|
void Init_event(VALUE ext);
|
14
|
+
void nyara_detach_fd(int fd);
|
14
15
|
|
15
16
|
|
16
|
-
/*
|
17
|
+
/* request_parse.c */
|
18
|
+
void Init_request_parse(VALUE nyara);
|
19
|
+
|
20
|
+
|
21
|
+
/* request.c */
|
17
22
|
void Init_request(VALUE nyara, VALUE ext);
|
18
|
-
|
23
|
+
VALUE nyara_request_new(int fd);
|
24
|
+
void nyara_request_term_close(VALUE request, bool write_last_chunk);
|
19
25
|
|
20
26
|
|
21
|
-
/*
|
27
|
+
/* url_encoded.c */
|
22
28
|
void Init_url_encoded(VALUE ext);
|
23
29
|
long nyara_parse_path(VALUE path, const char*s, long len);
|
24
30
|
void nyara_parse_param(VALUE output, const char* s, long len);
|
25
31
|
|
26
32
|
|
27
|
-
/*
|
33
|
+
/* accept.c */
|
28
34
|
void Init_accept(VALUE ext);
|
29
35
|
VALUE ext_parse_accept_value(VALUE _, VALUE str);
|
30
36
|
|
31
37
|
|
32
|
-
/*
|
38
|
+
/* mime.c */
|
33
39
|
void Init_mime(VALUE ext);
|
34
40
|
VALUE ext_mime_match(VALUE _, VALUE request_accept, VALUE accept_mimes);
|
35
41
|
|
36
42
|
|
37
|
-
/*
|
43
|
+
/* hashes.c */
|
38
44
|
void Init_hashes(VALUE nyara);
|
39
45
|
|
40
|
-
// ab-cd => Ab-Cd
|
46
|
+
// "ab-cd" => "Ab-Cd"
|
41
47
|
// note str must be string created by nyara code
|
42
48
|
void nyara_headerlize(VALUE str);
|
43
49
|
int nyara_rb_hash_has_key(VALUE hash, VALUE key);
|
@@ -47,7 +53,7 @@ extern VALUE nyara_header_hash_class;
|
|
47
53
|
extern VALUE nyara_config_hash_class;
|
48
54
|
|
49
55
|
|
50
|
-
/*
|
56
|
+
/* route.c */
|
51
57
|
typedef struct {
|
52
58
|
VALUE controller;
|
53
59
|
VALUE args;
|