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.
- checksums.yaml +4 -4
- data/example/factorial.rb +19 -0
- data/ext/accept.c +2 -2
- data/ext/event.c +48 -23
- data/ext/extconf.rb +2 -0
- data/ext/hashes.c +28 -3
- data/ext/http-parser/http_parser.h +1 -0
- data/ext/nyara.c +20 -3
- data/ext/nyara.h +13 -2
- data/ext/request.c +90 -13
- data/ext/request.h +8 -2
- data/ext/request_parse.c +135 -6
- data/ext/route.cc +7 -10
- data/ext/test_response.c +155 -0
- data/ext/url_encoded.c +0 -5
- data/lib/nyara/config.rb +5 -0
- data/lib/nyara/controller.rb +91 -28
- data/lib/nyara/cookie.rb +7 -0
- data/lib/nyara/flash.rb +23 -0
- data/lib/nyara/hashes/header_hash.rb +2 -0
- data/lib/nyara/nyara.rb +14 -2
- data/lib/nyara/part.rb +156 -0
- data/lib/nyara/patches/array.rb +5 -0
- data/lib/nyara/patches/blank.rb +128 -0
- data/lib/nyara/patches/json.rb +15 -0
- data/lib/nyara/patches/mini_support.rb +6 -0
- data/lib/nyara/patches/string.rb +21 -0
- data/lib/nyara/patches/to_query.rb +113 -0
- data/lib/nyara/request.rb +13 -15
- data/lib/nyara/route.rb +15 -80
- data/lib/nyara/route_entry.rb +69 -2
- data/lib/nyara/session.rb +66 -21
- data/lib/nyara/test.rb +170 -0
- data/lib/nyara/view.rb +5 -6
- data/lib/nyara.rb +7 -6
- data/nyara.gemspec +2 -2
- data/rakefile +34 -4
- data/readme.md +8 -1
- data/spec/config_spec.rb +28 -0
- data/spec/cpu_counter_spec.rb +9 -0
- data/spec/evented_io_spec.rb +1 -0
- data/spec/flash_spec.rb +29 -0
- data/spec/hashes_spec.rb +8 -0
- data/spec/mini_support_spec.rb +54 -0
- data/spec/part_spec.rb +52 -0
- data/spec/path_helper_spec.rb +22 -14
- data/spec/request_delegate_spec.rb +19 -11
- data/spec/route_entry_spec.rb +55 -0
- data/spec/session_spec.rb +69 -7
- data/spec/spec_helper.rb +3 -0
- data/spec/test_spec.rb +58 -0
- data/tools/hello.rb +11 -3
- data/tools/memcheck.rb +33 -0
- data/tools/s.rb +11 -0
- metadata +23 -7
- data/example/design.rb +0 -62
- data/example/fib.rb +0 -15
- data/spec/route_spec.rb +0 -84
- /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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4923242f45af2bfc9d06879f83c200d10379f89b
|
4
|
+
data.tar.gz: 7a03f851beecfb9e5846bd17adf3b15efe91968b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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,
|
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
|
106
|
+
nyara_request_term_close(request);
|
117
107
|
} else if (state == sym_term_close) {
|
118
|
-
nyara_request_term_close(request
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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,
|
315
|
-
rb_define_singleton_method(ext, "request_wakeup", ext_request_wakeup,
|
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 =
|
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);
|
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"),
|
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 =
|
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 =
|
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.
|
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
|
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
|
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
|
-
|
91
|
-
|
92
|
-
if (
|
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
|
-
|
96
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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;
|