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

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.
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;