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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8eb89d789f199a49118e1f707db07aeaa8525421
4
- data.tar.gz: 9e65ab8d0899ddad7baa96c78aff44fc26f9dd32
3
+ metadata.gz: 52583810c7afb74e920b0da7336e82441471ab82
4
+ data.tar.gz: 6fbd035f24bbd10ad1ade4ffdfce186e3a0d779f
5
5
  SHA512:
6
- metadata.gz: 1ffc6507a00a079041e7c19eb7e44f37a29bc9f185a9c659cfb2a8449367567ffa87f82e90ce45cb63994b000a68214e86827714449d5e13d5b4d8b40415fa59
7
- data.tar.gz: 7dd05d852cd406899a87eabbfb77b9a670981c783e3c4e5aa30850b03c415e1b0cbb17f77bbb4873e0d0b8c16c84db90d6f0d713bd63da415891061bd17bd093
6
+ metadata.gz: 7a3abf537a5027658497d171a5a593153316e60214b81c80f4f93c1e0557478f7473136b5cec6fc0daa76eedbb7650b01a284c72098a3069fa95bffd18ec468a
7
+ data.tar.gz: 8c5031033482180d9e0c1b3a4e541274abb562de5b1d04e81855c7ca556c7fcc44415abcf06a694b001f1c6a8dbd273509490a8ba45f3c58a0cf595921d92731
data/ext/accept.c CHANGED
@@ -1,4 +1,4 @@
1
- /* efficient Accpet-* value parser in C */
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 QArray qarray_new() {
22
- QArray qa = {ALLOC_N(double, 10), 0, 10};
23
- return qa;
24
- }
18
+ static double qarray[ACCEPT_MAX];
19
+ static long qarray_len = 0;
25
20
 
26
21
  // return inserted pos
27
- static long qarray_insert(QArray* qa, double v) {
28
- if (qa->len == qa->cap) {
29
- qa->cap *= 2;
30
- REALLOC_N(qa->qs, double, qa->cap);
31
- }
32
- long i = 0;
33
- for (; i < qa->len; i++) {
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
- qa->qs[i] = v;
40
- qa->len++;
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
- static void qarray_delete(QArray* qa) {
45
- xfree(qa->qs);
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 +out[value] = q+
84
- static void parse_seg(const char* s, long len, VALUE out, QArray* qa) {
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(qa, qval);
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 = trim_space(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
- QArray qa = qarray_new();
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, &qa);
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
- #define ETYPE_ACCEPT 0
9
- #define ETYPE_REQUEST 1
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 void set_nonblock(int fd) {
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
- rb_raise(rb_eRuntimeError, "fcntl(F_GETFL): %s", strerror(errno));
45
+ rb_sys_fail("fcntl(F_GETFL)");
26
46
  }
27
47
  if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
28
- rb_raise(rb_eRuntimeError, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
48
+ rb_sys_fail("fcntl(F_SETFL,O_NONBLOCK)");
29
49
  }
30
50
  }
31
51
 
32
- static VALUE ext_add(VALUE _, VALUE vfd) {
33
- int fd = FIX2INT(vfd);
34
- ADD_E(fd, ETYPE_CONNECT);
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 ETYPE_ACCEPT: {
126
+ case ETYPE_CAN_ACCEPT: {
42
127
  int cfd = accept(fd, NULL, NULL);
43
128
  if (cfd > 0) {
44
- set_nonblock(cfd);
45
- ADD_E(cfd, ETYPE_REQUEST);
129
+ _set_nonblock(cfd);
130
+ ADD_E(cfd, ETYPE_HANDLE_REQUEST);
46
131
  }
47
132
  break;
48
133
  }
49
- case ETYPE_REQUEST: {
50
- nyara_handle_request(fd);
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
- // todo
55
- // NOTE
56
- // fd and connection are 1:1, there can more more than 1 fds on a same file / address
57
- // so it's streight forward to using fd as query index
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
- set_nonblock(fd);
70
- ADD_E(fd, ETYPE_ACCEPT);
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
- set_nonblock(fd);
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
- // rb_define_singleton_method(c, "add", add_q, 2);
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
- // for test
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++11. this can not be installed on $CPPFLAGS, wtf??
16
- mf_conf['CXXFLAGS'] << ' -stdlib=libc++ -std=c++11'
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++11'
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
@@ -1,4 +1,5 @@
1
- // provide handy hash variants
1
+ /* handy hash variants */
2
+
2
3
  #include "nyara.h"
3
4
  #include <ruby/st.h>
4
5
 
data/ext/http_parser.c CHANGED
@@ -1 +1,7 @@
1
+ /* to make mkmf happy */
2
+
3
+ #ifndef HTTP_PARSER_STRICT
4
+ #define HTTP_PARSER_STRICT 0
5
+ #endif
6
+
1
7
  #include "http-parser/http_parser.c"
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
- switch (qevents[i].events) {
49
- case EPOLLIN: {
50
- int fd = (int)(qevents[i].data.u64 & 0xFFFFFFFF);
51
- int etype = (int)(qevents[i].data.u64 >> 32);
52
- loop_body(fd, etype);
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, EVFILT_READ, EV_DELETE, 0, 0, NULL);
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
- switch (qevents[i].filter) {
61
- case EVFILT_READ: {
62
- int fd = (int)qevents[i].ident;
63
- // EV_EOF is set if the read side of the socket is shutdown
64
- // the event can keep flipping back to consume cpu if we don't remove it
65
- if ((qevents[i].flags & EV_EOF)) {
66
- DEL_E(fd);
67
- } else {
68
- loop_body(fd, (int)qevents[i].udata);
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
@@ -1,6 +1,6 @@
1
- #pragma once
1
+ /* string internals, from ruby source code string.c */
2
2
 
3
- // from string.c
3
+ #pragma once
4
4
 
5
5
  #define RUBY_MAX_CHAR_LEN 16
6
6
  #define STR_TMPLOCK FL_USER7
data/ext/mime.c CHANGED
@@ -1,3 +1,5 @@
1
+ /* content-type matching */
2
+
1
3
  #include "nyara.h"
2
4
  #include <string.h>
3
5
  #include <ctype.h>
@@ -1 +1,3 @@
1
+ /* to make mkmf happy */
2
+
1
3
  #include "multipart-parser-c/multipart_parser.c"
data/ext/nyara.c CHANGED
@@ -1,3 +1,5 @@
1
+ /* ext entrance */
2
+
1
3
  #include "nyara.h"
2
4
  #include <ruby/io.h>
3
5
  #include <sys/socket.h>
data/ext/nyara.h CHANGED
@@ -9,35 +9,41 @@
9
9
  #endif
10
10
 
11
11
 
12
- /* -- event -- */
12
+ /* event.c */
13
13
  void Init_event(VALUE ext);
14
+ void nyara_detach_fd(int fd);
14
15
 
15
16
 
16
- /* -- request & response class -- */
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
- void nyara_handle_request(int fd);
23
+ VALUE nyara_request_new(int fd);
24
+ void nyara_request_term_close(VALUE request, bool write_last_chunk);
19
25
 
20
26
 
21
- /* -- url encoded parse -- */
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
- /* -- accept parse -- */
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
- /* -- mime parse and match -- */
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
- /* -- hashes -- */
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
- /* -- route -- */
56
+ /* route.c */
51
57
  typedef struct {
52
58
  VALUE controller;
53
59
  VALUE args;