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