nyara 0.0.1.pre.5 → 0.0.1.pre.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/example/factorial.rb +19 -0
  3. data/ext/accept.c +2 -2
  4. data/ext/event.c +48 -23
  5. data/ext/extconf.rb +2 -0
  6. data/ext/hashes.c +28 -3
  7. data/ext/http-parser/http_parser.h +1 -0
  8. data/ext/nyara.c +20 -3
  9. data/ext/nyara.h +13 -2
  10. data/ext/request.c +90 -13
  11. data/ext/request.h +8 -2
  12. data/ext/request_parse.c +135 -6
  13. data/ext/route.cc +7 -10
  14. data/ext/test_response.c +155 -0
  15. data/ext/url_encoded.c +0 -5
  16. data/lib/nyara/config.rb +5 -0
  17. data/lib/nyara/controller.rb +91 -28
  18. data/lib/nyara/cookie.rb +7 -0
  19. data/lib/nyara/flash.rb +23 -0
  20. data/lib/nyara/hashes/header_hash.rb +2 -0
  21. data/lib/nyara/nyara.rb +14 -2
  22. data/lib/nyara/part.rb +156 -0
  23. data/lib/nyara/patches/array.rb +5 -0
  24. data/lib/nyara/patches/blank.rb +128 -0
  25. data/lib/nyara/patches/json.rb +15 -0
  26. data/lib/nyara/patches/mini_support.rb +6 -0
  27. data/lib/nyara/patches/string.rb +21 -0
  28. data/lib/nyara/patches/to_query.rb +113 -0
  29. data/lib/nyara/request.rb +13 -15
  30. data/lib/nyara/route.rb +15 -80
  31. data/lib/nyara/route_entry.rb +69 -2
  32. data/lib/nyara/session.rb +66 -21
  33. data/lib/nyara/test.rb +170 -0
  34. data/lib/nyara/view.rb +5 -6
  35. data/lib/nyara.rb +7 -6
  36. data/nyara.gemspec +2 -2
  37. data/rakefile +34 -4
  38. data/readme.md +8 -1
  39. data/spec/config_spec.rb +28 -0
  40. data/spec/cpu_counter_spec.rb +9 -0
  41. data/spec/evented_io_spec.rb +1 -0
  42. data/spec/flash_spec.rb +29 -0
  43. data/spec/hashes_spec.rb +8 -0
  44. data/spec/mini_support_spec.rb +54 -0
  45. data/spec/part_spec.rb +52 -0
  46. data/spec/path_helper_spec.rb +22 -14
  47. data/spec/request_delegate_spec.rb +19 -11
  48. data/spec/route_entry_spec.rb +55 -0
  49. data/spec/session_spec.rb +69 -7
  50. data/spec/spec_helper.rb +3 -0
  51. data/spec/test_spec.rb +58 -0
  52. data/tools/hello.rb +11 -3
  53. data/tools/memcheck.rb +33 -0
  54. data/tools/s.rb +11 -0
  55. metadata +23 -7
  56. data/example/design.rb +0 -62
  57. data/example/fib.rb +0 -15
  58. data/spec/route_spec.rb +0 -84
  59. /data/ext/inc/{status_codes.inc → status_codes.h} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff97920b70aa73d175c0c11ceabd1d2117d680da
4
- data.tar.gz: 37bb1733ddfafef3a1ce806e58e1ddf145396a15
3
+ metadata.gz: 4923242f45af2bfc9d06879f83c200d10379f89b
4
+ data.tar.gz: 7a03f851beecfb9e5846bd17adf3b15efe91968b
5
5
  SHA512:
6
- metadata.gz: dabf49a57dd4c1e91693020c699e5dcb9a5726663af573a162d8c1df44d712c0ac4894b15e943010e5259488746d4da117d98c127563b7a75905813dcc2bceb5
7
- data.tar.gz: 636bbcd0ab74719cb7feb9c93891dc04287c3445eb19465c8bb232495b935964b7e4f9da582e6faed3a33f5d6be14f7410b9534096832692cbafcda8ee35ab8e
6
+ metadata.gz: 3ffe022bf0b05d95238fddcf4bf2fdb998c23e8490d31eec5154bd011034eb058fb2fd6ca99dcc37aeee1282102f6cb924e61fe20eeecc81f0ed50d903762186
7
+ data.tar.gz: cf2fe6b094478f9ed04c96e940e2075a019908abafb7fbf5eb255e66c91afa80dd5efea3b4c9d943f6d27a6a18f966b17b116e1664552c658264c7abda26fe69
@@ -0,0 +1,19 @@
1
+ require 'nyara'
2
+
3
+ get '/factorial(%u)' do |n|
4
+ redirect_to '#product', 1, n
5
+ end
6
+
7
+ meta '#product'
8
+ get '/%u*factorial(%u)' do |product, n|
9
+ if n == 0
10
+ redirect_to '#result', product
11
+ else
12
+ redirect_to '#product', product * n, n - 1
13
+ end
14
+ end
15
+
16
+ meta '#result'
17
+ get '/%u' do |result|
18
+ send_string result
19
+ end
data/ext/accept.c CHANGED
@@ -44,7 +44,7 @@ static VALUE trim_space_and_truncate(volatile VALUE str) {
44
44
  // todo log this exception
45
45
  olen = ACCEPT_MAX;
46
46
  }
47
- str = rb_str_new(RSTRING_PTR(str), olen);
47
+ str = rb_enc_str_new(RSTRING_PTR(str), olen, u8_encoding);
48
48
  char* s = RSTRING_PTR(str);
49
49
  long len = 0;
50
50
  for (long i = 0; i < olen; i++) {
@@ -99,7 +99,7 @@ static void parse_seg(const char* s, long len, VALUE out) {
99
99
  VALUE* out_ptr = RARRAY_PTR(out);
100
100
  long out_len = RARRAY_LEN(out); // note this len is +1
101
101
  memmove(out_ptr + pos + 1, out_ptr + pos, sizeof(VALUE) * (out_len - pos - 1));
102
- rb_ary_store(out, pos, rb_str_new(s, len));
102
+ rb_ary_store(out, pos, rb_enc_str_new(s, len, u8_encoding));
103
103
  }
104
104
 
105
105
  VALUE ext_parse_accept_value(VALUE _, volatile VALUE str) {
data/ext/event.c CHANGED
@@ -18,10 +18,9 @@ extern VALUE rb_obj_reveal(VALUE obj, VALUE klass);
18
18
  #define ETYPE_CONNECT 2
19
19
  #define MAX_E 1024
20
20
  static void loop_body(int fd, int etype);
21
- static int qfd;
21
+ static int qfd = 0;
22
22
 
23
- #define MAX_RECEIVE_DATA 65536
24
- // * 4
23
+ #define MAX_RECEIVE_DATA 65536 * 2
25
24
  static char received_data[MAX_RECEIVE_DATA];
26
25
  extern http_parser_settings nyara_request_parse_settings;
27
26
 
@@ -40,17 +39,6 @@ static VALUE sym_reading;
40
39
  static VALUE sym_sleep;
41
40
  static Request* curr_request;
42
41
 
43
- static void _set_nonblock(int fd) {
44
- int flags;
45
-
46
- if ((flags = fcntl(fd, F_GETFL)) == -1) {
47
- rb_sys_fail("fcntl(F_GETFL)");
48
- }
49
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
50
- rb_sys_fail("fcntl(F_SETFL,O_NONBLOCK)");
51
- }
52
- }
53
-
54
42
  static VALUE _fiber_func(VALUE _, VALUE args) {
55
43
  VALUE instance = rb_ary_pop(args);
56
44
  VALUE meth = rb_ary_pop(args);
@@ -97,10 +85,12 @@ static void _handle_request(VALUE request) {
97
85
  rb_ary_push(result.args, rb_class_new_instance(1, &(p->self), result.controller));
98
86
  // result.args is on stack, no need to worry gc
99
87
  p->fiber = rb_fiber_new(_fiber_func, result.args);
88
+ p->instance = RARRAY_PTR(result.args)[RARRAY_LEN(result.args) - 1];
100
89
  p->scope = result.scope;
101
90
  p->format = result.format;
102
91
  p->response_header = rb_class_new_instance(0, NULL, nyara_header_hash_class);
103
92
  p->response_header_extra_lines = rb_ary_new();
93
+ nyara_request_init_env(request);
104
94
  } else {
105
95
  rb_funcall(p->self, id_not_found, 0);
106
96
  nyara_detach_fd(p->fd);
@@ -113,9 +103,9 @@ static void _handle_request(VALUE request) {
113
103
  VALUE state = rb_fiber_resume(p->fiber, 0, NULL);
114
104
  if (state == Qnil) { // _fiber_func always returns Qnil
115
105
  // terminated (todo log raised error ?)
116
- nyara_request_term_close(request, false);
106
+ nyara_request_term_close(request);
117
107
  } else if (state == sym_term_close) {
118
- nyara_request_term_close(request, true);
108
+ nyara_request_term_close(request);
119
109
  } else if (state == sym_writing) {
120
110
  // do nothing
121
111
  } else if (state == sym_reading) {
@@ -131,7 +121,7 @@ static void loop_body(int fd, int etype) {
131
121
  case ETYPE_CAN_ACCEPT: {
132
122
  int cfd = accept(fd, NULL, NULL);
133
123
  if (cfd > 0) {
134
- _set_nonblock(cfd);
124
+ nyara_set_nonblock(cfd);
135
125
  ADD_E(cfd, ETYPE_HANDLE_REQUEST);
136
126
  }
137
127
  break;
@@ -176,7 +166,7 @@ static VALUE ext_init_queue(VALUE _) {
176
166
 
177
167
  static VALUE ext_run_queue(VALUE _, VALUE v_fd) {
178
168
  int fd = FIX2INT(v_fd);
179
- _set_nonblock(fd);
169
+ nyara_set_nonblock(fd);
180
170
  ADD_E(fd, ETYPE_CAN_ACCEPT);
181
171
 
182
172
  LOOP_E();
@@ -187,21 +177,32 @@ static VALUE ext_request_sleep(VALUE _, VALUE request) {
187
177
  Request* p;
188
178
  Data_Get_Struct(request, Request, p);
189
179
 
180
+ p->sleeping = true;
181
+ if (!qfd) {
182
+ // we are in a test
183
+ return Qnil;
184
+ }
185
+
190
186
  VALUE* v_fds = RARRAY_PTR(p->watched_fds);
191
187
  long v_fds_len = RARRAY_LEN(p->watched_fds);
192
188
  for (long i = 0; i < v_fds_len; i++) {
193
189
  DEL_E(FIX2INT(v_fds[i]));
194
190
  }
195
191
  DEL_E(p->fd);
196
- p->sleeping = true;
197
192
  return Qnil;
198
193
  }
199
194
 
200
195
  static VALUE ext_request_wakeup(VALUE _, VALUE request) {
201
- // NOTE should not use current_request
196
+ // NOTE should not use curr_request
202
197
  Request* p;
203
198
  Data_Get_Struct(request, Request, p);
204
199
 
200
+ p->sleeping = false;
201
+ if (!qfd) {
202
+ // we are in a test
203
+ return Qnil;
204
+ }
205
+
205
206
  VALUE* v_fds = RARRAY_PTR(p->watched_fds);
206
207
  long v_fds_len = RARRAY_LEN(p->watched_fds);
207
208
  for (long i = 0; i < v_fds_len; i++) {
@@ -213,7 +214,7 @@ static VALUE ext_request_wakeup(VALUE _, VALUE request) {
213
214
 
214
215
  static VALUE ext_set_nonblock(VALUE _, VALUE v_fd) {
215
216
  int fd = FIX2INT(v_fd);
216
- _set_nonblock(fd);
217
+ nyara_set_nonblock(fd);
217
218
  return Qnil;
218
219
  }
219
220
 
@@ -297,6 +298,27 @@ static VALUE ext_fd_recv(VALUE _, VALUE v_fd, VALUE v_len, VALUE v_flags) {
297
298
  return str;
298
299
  }
299
300
 
301
+ // (for test) run request handler, read from associated fd and write to it
302
+ static VALUE ext_handle_request(VALUE _, VALUE request) {
303
+ Request* p;
304
+ Data_Get_Struct(request, Request, p);
305
+
306
+ while (p->fiber == Qnil || rb_fiber_alive_p(p->fiber)) {
307
+ _handle_request(request);
308
+ // stop if no more to read
309
+ // NOTE this condition is sufficient to terminate handle, because
310
+ // - there's no connect yield during test
311
+ // - there's no view pause yield up to _handle_request
312
+ if (!p->sleeping) {
313
+ char buf[1];
314
+ if (recv(p->fd, buf, 1, MSG_PEEK) <= 0) {
315
+ break;
316
+ }
317
+ }
318
+ }
319
+ return p->instance;
320
+ }
321
+
300
322
  void Init_event(VALUE ext) {
301
323
  fd_request_map = rb_hash_new();
302
324
  rb_gc_register_mark_object(fd_request_map);
@@ -311,12 +333,15 @@ void Init_event(VALUE ext) {
311
333
  rb_define_singleton_method(ext, "init_queue", ext_init_queue, 0);
312
334
  rb_define_singleton_method(ext, "run_queue", ext_run_queue, 1);
313
335
 
314
- rb_define_singleton_method(ext, "request_sleep", ext_request_sleep, 0);
315
- rb_define_singleton_method(ext, "request_wakeup", ext_request_wakeup, 0);
336
+ rb_define_singleton_method(ext, "request_sleep", ext_request_sleep, 1);
337
+ rb_define_singleton_method(ext, "request_wakeup", ext_request_wakeup, 1);
316
338
 
317
339
  // fd operations
318
340
  rb_define_singleton_method(ext, "set_nonblock", ext_set_nonblock, 1);
319
341
  rb_define_singleton_method(ext, "fd_watch", ext_fd_watch, 1);
320
342
  rb_define_singleton_method(ext, "fd_send", ext_fd_send, 3);
321
343
  rb_define_singleton_method(ext, "fd_recv", ext_fd_recv, 3);
344
+
345
+ // for test
346
+ rb_define_singleton_method(ext, "handle_request", ext_handle_request, 1);
322
347
  }
data/ext/extconf.rb CHANGED
@@ -24,6 +24,8 @@ have_epoll = have_func('epoll_create', 'sys/epoll.h')
24
24
  abort('no kqueue nor epoll') if !have_kqueue and !have_epoll
25
25
  $defs << "-DNDEBUG -D#{have_epoll ? 'HAVE_EPOLL' : 'HAVE_KQUEUE'}"
26
26
 
27
+ have_func('rb_ary_new_capa', 'ruby.h')
28
+
27
29
  tweak_include
28
30
  tweak_cflags
29
31
  create_makefile 'nyara'
data/ext/hashes.c CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  #include "nyara.h"
4
4
  #include <ruby/st.h>
5
+ #include "inc/str_intern.h"
5
6
 
6
7
  VALUE nyara_param_hash_class;
7
8
  VALUE nyara_header_hash_class;
@@ -69,7 +70,7 @@ static VALUE header_hash_tidy_key(VALUE key) {
69
70
  key = rb_sym_to_s(key);
70
71
  } else {
71
72
  Check_Type(key, T_STRING);
72
- key = rb_str_new(RSTRING_PTR(key), RSTRING_LEN(key));
73
+ key = rb_enc_str_new(RSTRING_PTR(key), RSTRING_LEN(key), u8_encoding);
73
74
  }
74
75
  nyara_headerlize(key);
75
76
  return key;
@@ -83,7 +84,7 @@ static VALUE header_hash_key_p(VALUE self, VALUE key) {
83
84
  return nyara_rb_hash_has_key(self, header_hash_tidy_key(key)) ? Qtrue : Qfalse;
84
85
  }
85
86
 
86
- ID id_to_s;
87
+ static ID id_to_s;
87
88
  static VALUE header_hash_aset(VALUE self, VALUE key, VALUE value) {
88
89
  key = header_hash_tidy_key(key);
89
90
  if (TYPE(value) != T_STRING) {
@@ -93,7 +94,7 @@ static VALUE header_hash_aset(VALUE self, VALUE key, VALUE value) {
93
94
  return rb_hash_aset(self, key, value);
94
95
  }
95
96
 
96
- int header_hash_merge_func(VALUE k, VALUE v, VALUE self_st) {
97
+ static int header_hash_merge_func(VALUE k, VALUE v, VALUE self_st) {
97
98
  st_table* t = (st_table*)self_st;
98
99
  if (!st_is_member(t, k)) {
99
100
  st_insert(t, (st_data_t)k, (st_data_t)v);
@@ -110,6 +111,29 @@ static VALUE header_hash_reverse_merge_bang(VALUE self, VALUE other) {
110
111
  return self;
111
112
  }
112
113
 
114
+ static int header_hash_serialize_func(VALUE k, VALUE v, VALUE arr) {
115
+ long klen = RSTRING_LEN(k);
116
+ long vlen = RSTRING_LEN(v);
117
+ long capa = klen + vlen + 4;
118
+ volatile VALUE s = rb_str_buf_new(capa);
119
+ sprintf(RSTRING_PTR(s), "%.*s: %.*s\r\n", (int)klen, RSTRING_PTR(k), (int)vlen, RSTRING_PTR(v));
120
+ STR_SET_LEN(s, capa);
121
+ rb_enc_associate(s, u8_encoding);
122
+ rb_ary_push(arr, s);
123
+ return ST_CONTINUE;
124
+ }
125
+
126
+ static VALUE header_hash_serialize(VALUE self) {
127
+ # ifdef HAVE_RB_ARY_NEW_CAPA
128
+ long size = (!RHASH(self)->ntbl ? RHASH(self)->ntbl->num_entries : 0);
129
+ volatile VALUE arr = rb_ary_new_capa(size);
130
+ # else
131
+ volatile VALUE arr = rb_ary_new();
132
+ # endif
133
+ rb_hash_foreach(self, header_hash_serialize_func, arr);
134
+ return arr;
135
+ }
136
+
113
137
  void Init_hashes(VALUE nyara) {
114
138
  id_to_s = rb_intern("to_s");
115
139
 
@@ -125,6 +149,7 @@ void Init_hashes(VALUE nyara) {
125
149
  rb_define_method(nyara_header_hash_class, "key?", header_hash_key_p, 1);
126
150
  rb_define_method(nyara_header_hash_class, "[]=", header_hash_aset, 2);
127
151
  rb_define_method(nyara_header_hash_class, "reverse_merge!", header_hash_reverse_merge_bang, 1);
152
+ rb_define_method(nyara_header_hash_class, "serialize", header_hash_serialize, 0);
128
153
 
129
154
  // for internal use
130
155
  rb_define_method(nyara_header_hash_class, "_aset", rb_hash_aset, 2);
@@ -24,6 +24,7 @@
24
24
  extern "C" {
25
25
  #endif
26
26
 
27
+ /* Also update SONAME in the Makefile whenever you change these. */
27
28
  #define HTTP_PARSER_VERSION_MAJOR 2
28
29
  #define HTTP_PARSER_VERSION_MINOR 1
29
30
 
data/ext/nyara.c CHANGED
@@ -4,6 +4,20 @@
4
4
  #include <ruby/io.h>
5
5
  #include <sys/socket.h>
6
6
  #include <sys/resource.h>
7
+ #include <sys/fcntl.h>
8
+
9
+ rb_encoding* u8_encoding;
10
+
11
+ void nyara_set_nonblock(int fd) {
12
+ int flags;
13
+
14
+ if ((flags = fcntl(fd, F_GETFL)) == -1) {
15
+ rb_sys_fail("fcntl(F_GETFL)");
16
+ }
17
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
18
+ rb_sys_fail("fcntl(F_SETFL,O_NONBLOCK)");
19
+ }
20
+ }
7
21
 
8
22
  static void set_fd_limit(int nofiles) {
9
23
  struct rlimit rlim;
@@ -17,11 +31,12 @@ static void set_fd_limit(int nofiles) {
17
31
  }
18
32
 
19
33
  void Init_nyara() {
34
+ u8_encoding = rb_utf8_encoding();
20
35
  set_fd_limit(20000);
21
36
 
22
37
  VALUE nyara = rb_define_module("Nyara");
23
38
  # include "inc/version.inc"
24
- rb_const_set(nyara, rb_intern("VERSION"), rb_str_new2(NYARA_VERSION));
39
+ rb_const_set(nyara, rb_intern("VERSION"), rb_enc_str_new(NYARA_VERSION, strlen(NYARA_VERSION), u8_encoding));
25
40
 
26
41
  // utils: hashes
27
42
  Init_hashes(nyara);
@@ -31,7 +46,7 @@ void Init_nyara() {
31
46
  rb_const_set(nyara, rb_intern("HTTP_METHODS"), method_map);
32
47
  VALUE tmp_key = Qnil;
33
48
  # define METHOD_STR2NUM(n, name, string) \
34
- tmp_key = rb_str_new2(#string);\
49
+ tmp_key = rb_enc_str_new(#string, strlen(#string), u8_encoding);\
35
50
  OBJ_FREEZE(tmp_key);\
36
51
  rb_hash_aset(method_map, tmp_key, INT2FIX(n));
37
52
  HTTP_METHOD_MAP(METHOD_STR2NUM);
@@ -43,7 +58,7 @@ void Init_nyara() {
43
58
  rb_const_set(nyara, rb_intern("HTTP_STATUS_CODES"), status_map);
44
59
  VALUE tmp_value = Qnil;
45
60
  # define STATUS_DESC(status, desc) \
46
- tmp_value = rb_str_new2(desc);\
61
+ tmp_value = rb_enc_str_new(desc, strlen(desc), u8_encoding);\
47
62
  OBJ_FREEZE(tmp_value);\
48
63
  rb_hash_aset(status_map, INT2FIX(status), tmp_value);
49
64
  HTTP_STATUS_CODES(STATUS_DESC);
@@ -54,6 +69,8 @@ void Init_nyara() {
54
69
  Init_accept(ext);
55
70
  Init_mime(ext);
56
71
  Init_request(nyara, ext);
72
+ Init_request_parse(nyara);
73
+ Init_test_response(nyara);
57
74
  Init_event(ext);
58
75
  Init_route(nyara, ext);
59
76
  Init_url_encoded(ext);
data/ext/nyara.h CHANGED
@@ -1,8 +1,9 @@
1
1
  #pragma once
2
2
  #include <ruby.h>
3
+ #include <ruby/encoding.h>
3
4
  #include <stdbool.h>
4
5
  #include <http_parser.h>
5
- #include "inc/status_codes.inc"
6
+ #include "inc/status_codes.h"
6
7
 
7
8
  #ifdef DEBUG
8
9
  #undef NDEBUG
@@ -21,7 +22,12 @@ void Init_request_parse(VALUE nyara);
21
22
  /* request.c */
22
23
  void Init_request(VALUE nyara, VALUE ext);
23
24
  VALUE nyara_request_new(int fd);
24
- void nyara_request_term_close(VALUE request, bool write_last_chunk);
25
+ void nyara_request_init_env(VALUE request);
26
+ void nyara_request_term_close(VALUE request);
27
+
28
+
29
+ /* test_response.c */
30
+ void Init_test_response(VALUE nyara);
25
31
 
26
32
 
27
33
  /* url_encoded.c */
@@ -63,3 +69,8 @@ typedef struct {
63
69
 
64
70
  extern void Init_route(VALUE nyara, VALUE ext);
65
71
  extern RouteResult nyara_lookup_route(enum http_method method_num, VALUE vpath, VALUE accept_arr);
72
+
73
+
74
+ /* nyara.c */
75
+ void nyara_set_nonblock(int fd);
76
+ extern rb_encoding* u8_encoding;
data/ext/request.c CHANGED
@@ -1,13 +1,12 @@
1
1
  /* request parsing and request object */
2
2
 
3
3
  #include "nyara.h"
4
- #include <ruby/encoding.h>
5
4
  #include "request.h"
6
5
 
7
6
  static VALUE str_html;
8
- static rb_encoding* u8_encoding;
9
7
  static VALUE request_class;
10
8
  static VALUE sym_writing;
9
+ static VALUE str_transfer_encoding;
11
10
 
12
11
  #define P \
13
12
  Request* p;\
@@ -26,10 +25,18 @@ static void request_mark(void* pp) {
26
25
  rb_gc_mark_maybe(p->query);
27
26
  rb_gc_mark_maybe(p->last_field);
28
27
  rb_gc_mark_maybe(p->last_value);
28
+ rb_gc_mark_maybe(p->last_part);
29
+ rb_gc_mark_maybe(p->body);
30
+
31
+ rb_gc_mark_maybe(p->cookie);
32
+ rb_gc_mark_maybe(p->session);
33
+ rb_gc_mark_maybe(p->flash);
34
+
29
35
  rb_gc_mark_maybe(p->response_content_type);
30
36
  rb_gc_mark_maybe(p->response_header);
31
37
  rb_gc_mark_maybe(p->response_header_extra_lines);
32
38
  rb_gc_mark_maybe(p->watched_fds);
39
+ rb_gc_mark_maybe(p->instance);
33
40
  }
34
41
  }
35
42
 
@@ -38,6 +45,11 @@ static void request_free(void* pp) {
38
45
  if (p) {
39
46
  if (p->fd) {
40
47
  nyara_detach_fd(p->fd);
48
+ p->fd = 0;
49
+ }
50
+ if (p->mparser) {
51
+ multipart_parser_free(p->mparser);
52
+ p->mparser = NULL;
41
53
  }
42
54
  xfree(p);
43
55
  }
@@ -66,12 +78,20 @@ static Request* _request_alloc() {
66
78
  p->query = query;
67
79
  p->last_field = Qnil;
68
80
  p->last_value = Qnil;
81
+ p->last_part = Qnil;
82
+ p->body = Qnil;
83
+
84
+ p->cookie = Qnil;
85
+ p->session = Qnil;
86
+ p->flash = Qnil;
87
+
69
88
  p->response_content_type = Qnil;
70
89
  p->response_header = Qnil;
71
90
  p->response_header_extra_lines = Qnil;
72
91
 
73
92
  volatile VALUE watched_fds = rb_ary_new();
74
93
  p->watched_fds = watched_fds;
94
+ p->instance = Qnil;
75
95
 
76
96
  p->sleeping = false;
77
97
 
@@ -85,20 +105,48 @@ VALUE nyara_request_new(int fd) {
85
105
  return p->self;
86
106
  }
87
107
 
88
- void nyara_request_term_close(VALUE self, bool write_last_chunk) {
108
+ void nyara_request_init_env(VALUE self) {
109
+ static VALUE cookie_mod = Qnil;
110
+ static VALUE session_mod = Qnil;
111
+ static VALUE flash_class = Qnil;
112
+ static ID id_decode = 0;
113
+ if (cookie_mod == Qnil) {
114
+ VALUE nyara = rb_const_get(rb_cModule, rb_intern("Nyara"));
115
+ cookie_mod = rb_const_get(nyara, rb_intern("Cookie"));
116
+ session_mod = rb_const_get(nyara, rb_intern("Session"));
117
+ flash_class = rb_const_get(nyara, rb_intern("Flash"));
118
+ id_decode = rb_intern("decode");
119
+ }
120
+
121
+ P;
122
+ p->cookie = rb_funcall(cookie_mod, id_decode, 1, p->header);
123
+ p->session = rb_funcall(session_mod, id_decode, 1, p->cookie);
124
+ p->flash = rb_class_new_instance(1, &p->session, flash_class);
125
+ }
126
+
127
+ void nyara_request_term_close(VALUE self) {
89
128
  P;
90
- if (write_last_chunk || p->status == 200) {
91
- // usually this succeeds, while not, it doesn't matter cause we are closing it
92
- if (write(p->fd, "0\r\n\r\n", 5)) {
129
+ VALUE transfer_enc = rb_hash_aref(p->response_header, str_transfer_encoding);
130
+ if (TYPE(transfer_enc) == T_STRING) {
131
+ if (RSTRING_LEN(transfer_enc) == 7) {
132
+ if (strncmp(RSTRING_PTR(transfer_enc), "chunked", 7) == 0) {
133
+ // usually this succeeds, while not, it doesn't matter cause we are closing it
134
+ if (write(p->fd, "0\r\n\r\n", 5)) {
135
+ }
136
+ }
93
137
  }
94
138
  }
95
- nyara_detach_fd(p->fd);
96
- p->fd = 0;
139
+ if (p->fd) {
140
+ nyara_detach_fd(p->fd);
141
+ p->fd = 0;
142
+ }
97
143
  }
98
144
 
99
145
  static VALUE request_http_method(VALUE self) {
100
146
  P;
101
- return rb_str_new2(http_method_str(p->method));
147
+ // todo reduce allocation
148
+ const char* str = http_method_str(p->method);
149
+ return rb_enc_str_new(str, strlen(str), u8_encoding);
102
150
  }
103
151
 
104
152
  static VALUE request_header(VALUE self) {
@@ -136,6 +184,21 @@ static VALUE request_format(VALUE self) {
136
184
  return p->format == Qnil ? str_html : p->format;
137
185
  }
138
186
 
187
+ static VALUE request_cookie(VALUE self) {
188
+ P;
189
+ return p->cookie;
190
+ }
191
+
192
+ static VALUE request_session(VALUE self) {
193
+ P;
194
+ return p->session;
195
+ }
196
+
197
+ static VALUE request_flash(VALUE self) {
198
+ P;
199
+ return p->flash;
200
+ }
201
+
139
202
  static VALUE request_status(VALUE self) {
140
203
  P;
141
204
  return INT2FIX(p->status);
@@ -228,11 +291,17 @@ static VALUE ext_request_new(VALUE _) {
228
291
 
229
292
  static VALUE ext_request_set_fd(VALUE _, VALUE self, VALUE vfd) {
230
293
  P;
231
- p->fd = NUM2INT(vfd);
294
+ int fd = NUM2INT(vfd);
295
+ if (fd) {
296
+ fd = dup(fd);
297
+ nyara_set_nonblock(fd);
298
+ p->fd = fd;
299
+ }
232
300
  return Qnil;
233
301
  }
234
302
 
235
- // set internal attrs in the request object
303
+ // set internal attrs in the request object<br>
304
+ // method_num is required, others are optional
236
305
  static VALUE ext_request_set_attrs(VALUE _, VALUE self, VALUE attrs) {
237
306
  # define ATTR(key) rb_hash_delete(attrs, ID2SYM(rb_intern(key)))
238
307
  # define HEADER_HASH_NEW rb_class_new_instance(0, NULL, nyara_header_hash_class)
@@ -249,6 +318,10 @@ static VALUE ext_request_set_attrs(VALUE _, VALUE self, VALUE attrs) {
249
318
  p->scope = ATTR("scope");
250
319
  p->header = ATTR("header");
251
320
  p->format = ATTR("format");
321
+ p->body = ATTR("body");
322
+ p->cookie = ATTR("cookie");
323
+ p->session = ATTR("session");
324
+ p->flash = ATTR("flash");
252
325
  p->response_header = ATTR("response_header");
253
326
  p->response_header_extra_lines = ATTR("response_header_extra_lines");
254
327
 
@@ -266,11 +339,12 @@ static VALUE ext_request_set_attrs(VALUE _, VALUE self, VALUE attrs) {
266
339
  }
267
340
 
268
341
  void Init_request(VALUE nyara, VALUE ext) {
269
- str_html = rb_str_new2("html");
342
+ str_html = rb_enc_str_new("html", strlen("html"), u8_encoding);
270
343
  OBJ_FREEZE(str_html);
271
344
  rb_gc_register_mark_object(str_html);
272
- u8_encoding = rb_utf8_encoding();
273
345
  sym_writing = ID2SYM(rb_intern("writing"));
346
+ str_transfer_encoding = rb_enc_str_new("Transfer-Encoding", strlen("Transfer-Encoding"), u8_encoding);
347
+ rb_gc_register_mark_object(str_transfer_encoding);
274
348
 
275
349
  // request
276
350
  request_class = rb_define_class_under(nyara, "Request", rb_cObject);
@@ -282,6 +356,9 @@ void Init_request(VALUE nyara, VALUE ext) {
282
356
  rb_define_method(request_class, "path_with_query", request_path_with_query, 0);
283
357
  rb_define_method(request_class, "accept", request_accept, 0);
284
358
  rb_define_method(request_class, "format", request_format, 0);
359
+ rb_define_method(request_class, "cookie", request_cookie, 0);
360
+ rb_define_method(request_class, "session", request_session, 0);
361
+ rb_define_method(request_class, "flash", request_flash, 0);
285
362
 
286
363
  rb_define_method(request_class, "status", request_status, 0);
287
364
  rb_define_method(request_class, "response_content_type", request_response_content_type, 0);
data/ext/request.h CHANGED
@@ -3,9 +3,7 @@
3
3
  #include "nyara.h"
4
4
  #include <multipart_parser.h>
5
5
  #include <errno.h>
6
- #ifndef write
7
6
  #include <unistd.h>
8
- #endif
9
7
 
10
8
  enum ParseState {
11
9
  PS_INIT, PS_HEADERS_COMPLETE, PS_MESSAGE_COMPLETE, PS_ERROR
@@ -33,6 +31,13 @@ typedef struct {
33
31
  VALUE query;
34
32
  VALUE last_field;
35
33
  VALUE last_value;
34
+ VALUE last_part; // multipart last header or body
35
+ VALUE body; // string when single part, array when multipart
36
+
37
+ // env
38
+ VALUE cookie;
39
+ VALUE session;
40
+ VALUE flash;
36
41
 
37
42
  // response
38
43
  VALUE response_content_type;
@@ -40,6 +45,7 @@ typedef struct {
40
45
  VALUE response_header_extra_lines;
41
46
 
42
47
  VALUE watched_fds;
48
+ VALUE instance;
43
49
 
44
50
  bool sleeping;
45
51
  } Request;