nyara 0.0.1.pre.2 → 0.0.1.pre.3

Sign up to get free protection for your applications and to get access to all the features.
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;