nyara 0.0.1.pre.9 → 0.1.pre.0

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/bin/nyara +3 -3
  3. data/changes +1 -0
  4. data/ext/event.c +16 -22
  5. data/ext/hashes.c +222 -4
  6. data/ext/inc/rdtsc.h +56 -0
  7. data/ext/inc/status_codes.inc +64 -0
  8. data/ext/inc/version.inc +1 -1
  9. data/ext/nyara.c +12 -10
  10. data/ext/nyara.h +5 -5
  11. data/ext/request.c +18 -24
  12. data/ext/request_parse.c +1 -1
  13. data/ext/route.cc +2 -4
  14. data/ext/url_encoded.c +51 -193
  15. data/lib/nyara/command.rb +39 -12
  16. data/lib/nyara/config.rb +10 -10
  17. data/lib/nyara/controller.rb +60 -14
  18. data/lib/nyara/cookie.rb +1 -1
  19. data/lib/nyara/hashes/config_hash.rb +2 -24
  20. data/lib/nyara/nyara.rb +33 -19
  21. data/lib/nyara/part.rb +7 -3
  22. data/lib/nyara/reload.rb +85 -0
  23. data/lib/nyara/request.rb +1 -1
  24. data/lib/nyara/route.rb +55 -19
  25. data/lib/nyara/templates/Gemfile +10 -1
  26. data/lib/nyara/templates/Rakefile +6 -1
  27. data/lib/nyara/templates/app/controllers/application_controller.rb +3 -0
  28. data/lib/nyara/templates/app/controllers/welcome_controller.rb +5 -0
  29. data/lib/nyara/templates/app/views/layouts/application.erb +12 -0
  30. data/lib/nyara/templates/app/views/welcome/index.erb +1 -0
  31. data/lib/nyara/templates/config/application.rb +34 -0
  32. data/lib/nyara/templates/config/boot.rb +4 -0
  33. data/lib/nyara/templates/config/development.rb +5 -0
  34. data/lib/nyara/templates/config/production.rb +8 -0
  35. data/lib/nyara/templates/config/test.rb +2 -0
  36. data/lib/nyara/templates/public/css/app.css +1 -0
  37. data/lib/nyara/templates/public/js/app.js +1 -0
  38. data/lib/nyara/templates/spec/spec_helper.rb +9 -0
  39. data/lib/nyara/test.rb +10 -2
  40. data/lib/nyara/view.rb +116 -67
  41. data/nyara.gemspec +3 -1
  42. data/rakefile +1 -1
  43. data/readme.md +1 -1
  44. data/spec/command_spec.rb +28 -24
  45. data/spec/config_spec.rb +24 -1
  46. data/spec/dummy/app/controllers/dummy_controller.rb +2 -0
  47. data/spec/dummy/app/models/dmmy_model.rb +2 -0
  48. data/spec/evented_io_spec.rb +2 -1
  49. data/spec/ext_route_spec.rb +2 -2
  50. data/spec/flash_spec.rb +8 -0
  51. data/spec/hashes_spec.rb +127 -0
  52. data/spec/integration_spec.rb +15 -0
  53. data/spec/path_helper_spec.rb +17 -5
  54. data/spec/performance/escape.rb +15 -4
  55. data/spec/performance/layout_render.rb +15 -10
  56. data/spec/performance/parse_accept_value.rb +24 -8
  57. data/spec/performance/parse_param.rb +14 -8
  58. data/spec/performance/performance_helper.rb +8 -21
  59. data/spec/performance_spec.rb +5 -4
  60. data/spec/route_spec.rb +7 -2
  61. data/spec/url_encoded_spec.rb +18 -74
  62. data/spec/view_spec.rb +1 -3
  63. data/spec/views/_partial.slim +1 -0
  64. data/spec/views/_partial_with_yield.erb +1 -0
  65. metadata +73 -43
  66. data/example/factorial.rb +0 -19
  67. data/example/hello.rb +0 -5
  68. data/example/project.rb +0 -11
  69. data/example/stream.rb +0 -14
  70. data/lib/nyara/controllers/public_controller.rb +0 -14
  71. data/lib/nyara/templates/config/session.key +0 -1
  72. data/tools/bench-cookie.rb +0 -22
  73. data/tools/foo.rb +0 -9
  74. data/tools/hello.rb +0 -46
  75. data/tools/memcheck.rb +0 -33
  76. data/tools/s.rb +0 -11
data/ext/inc/version.inc CHANGED
@@ -1 +1 @@
1
- #define NYARA_VERSION "0.0.1"
1
+ #define NYARA_VERSION "0.1.pre.0"
data/ext/nyara.c CHANGED
@@ -5,6 +5,7 @@
5
5
  #include <sys/socket.h>
6
6
  #include <sys/resource.h>
7
7
  #include <sys/fcntl.h>
8
+ #include "inc/rdtsc.h"
8
9
 
9
10
  rb_encoding* u8_encoding;
10
11
  static VALUE nyara;
@@ -31,17 +32,16 @@ static void set_fd_limit(int nofiles) {
31
32
  }
32
33
  }
33
34
 
34
- static bool summary_request = false;
35
- void nyara_summary_request(int method, VALUE path, VALUE controller) {
36
- if (summary_request) {
37
- rb_funcall(nyara, rb_intern("summary_request"), 3, INT2NUM(method), path, controller);
38
- }
35
+ static unsigned long long last_rdtsc = 0;
36
+
37
+ static VALUE ext_rdtsc_start(VALUE _) {
38
+ last_rdtsc = rdtsc();
39
+ return Qnil;
39
40
  }
40
41
 
41
- // set whether should log summary of request
42
- static VALUE ext_summary_request(VALUE _, VALUE toggle) {
43
- summary_request = RTEST(toggle);
44
- return toggle;
42
+ static VALUE ext_rdtsc(VALUE _) {
43
+ unsigned long long diff = rdtsc() - last_rdtsc;
44
+ return ULL2NUM(diff);
45
45
  }
46
46
 
47
47
  void Init_nyara() {
@@ -80,7 +80,9 @@ void Init_nyara() {
80
80
  OBJ_FREEZE(status_map);
81
81
 
82
82
  VALUE ext = rb_define_module_under(nyara, "Ext");
83
- rb_define_singleton_method(ext, "summary_request", ext_summary_request, 1);
83
+ rb_define_singleton_method(ext, "rdtsc_start", ext_rdtsc_start, 0);
84
+ rb_define_singleton_method(ext, "rdtsc", ext_rdtsc, 0);
85
+
84
86
  Init_accept(ext);
85
87
  Init_mime(ext);
86
88
  Init_request(nyara, ext);
data/ext/nyara.h CHANGED
@@ -14,6 +14,7 @@
14
14
  printf("%s: %.*s\n", __func__, (int)RSTRING_LEN(_xx), RSTRING_PTR(_xx));\
15
15
  } while(0)
16
16
 
17
+
17
18
  /* event.c */
18
19
  void Init_event(VALUE ext);
19
20
  void nyara_detach_rid(VALUE rid);
@@ -25,7 +26,6 @@ void Init_request_parse(VALUE nyara, VALUE ext);
25
26
 
26
27
  /* request.c */
27
28
  void Init_request(VALUE nyara, VALUE ext);
28
- void nyara_request_init_env(VALUE request);
29
29
  void nyara_request_term_close(VALUE request);
30
30
  bool nyara_send_data(int fd, const char* s, long len);
31
31
 
@@ -37,8 +37,7 @@ void Init_test_response(VALUE nyara);
37
37
  /* url_encoded.c */
38
38
  void Init_url_encoded(VALUE ext);
39
39
  long nyara_parse_path(VALUE path, const char*s, long len);
40
- void nyara_parse_param(VALUE output, const char* s, long len);
41
- VALUE ext_parse_cookie(VALUE self, VALUE output, VALUE str);
40
+ void nyara_decode_uri_kv(volatile VALUE key, volatile VALUE value, const char* kv_s, long kv_len);
42
41
 
43
42
 
44
43
  /* accept.c */
@@ -53,11 +52,13 @@ VALUE ext_mime_match(VALUE _, VALUE request_accept, VALUE accept_mimes);
53
52
 
54
53
  /* hashes.c */
55
54
  void Init_hashes(VALUE nyara);
55
+ void nyara_parse_query(VALUE output, const char* s, long len);
56
+
56
57
 
57
58
  // "ab-cd" => "Ab-Cd"
58
59
  // note str must be string created by nyara code
59
60
  void nyara_headerlize(VALUE str);
60
- int nyara_rb_hash_has_key(VALUE hash, VALUE key);
61
+ // int nyara_rb_hash_has_key(VALUE hash, VALUE key);
61
62
 
62
63
  extern VALUE nyara_param_hash_class;
63
64
  extern VALUE nyara_header_hash_class;
@@ -78,5 +79,4 @@ extern RouteResult nyara_lookup_route(enum http_method method_num, VALUE vpath,
78
79
 
79
80
  /* nyara.c */
80
81
  void nyara_set_nonblock(int fd);
81
- void nyara_summary_request(int method, VALUE path, VALUE controller);
82
82
  extern rb_encoding* u8_encoding;
data/ext/request.c CHANGED
@@ -109,30 +109,6 @@ Request* nyara_request_new(int fd) {
109
109
  return p;
110
110
  }
111
111
 
112
- void nyara_request_init_env(VALUE self) {
113
- static VALUE session_mod = Qnil;
114
- static VALUE flash_class = Qnil;
115
- static VALUE str_cookie = Qnil;
116
- static ID id_decode = 0;
117
- if (session_mod == Qnil) {
118
- VALUE nyara = rb_const_get(rb_cModule, rb_intern("Nyara"));
119
- session_mod = rb_const_get(nyara, rb_intern("Session"));
120
- flash_class = rb_const_get(nyara, rb_intern("Flash"));
121
- str_cookie = rb_enc_str_new("Cookie", strlen("Cookie"), u8_encoding);
122
- rb_gc_register_mark_object(str_cookie);
123
- id_decode = rb_intern("decode");
124
- }
125
-
126
- P;
127
- p->cookie = rb_class_new_instance(0, NULL, nyara_param_hash_class);
128
- VALUE cookie = rb_hash_aref(p->header, str_cookie);
129
- if (cookie != Qnil) {
130
- ext_parse_cookie(Qnil, p->cookie, cookie);
131
- }
132
- p->session = rb_funcall(session_mod, id_decode, 1, p->cookie);
133
- p->flash = rb_class_new_instance(1, &p->session, flash_class);
134
- }
135
-
136
112
  void nyara_request_term_close(VALUE self) {
137
113
  P;
138
114
  VALUE transfer_enc = rb_hash_aref(p->response_header, str_transfer_encoding);
@@ -202,11 +178,27 @@ static VALUE request_session(VALUE self) {
202
178
  return p->session;
203
179
  }
204
180
 
181
+ static VALUE request_session_eq(VALUE self, VALUE session) {
182
+ P;
183
+ if (p->session != Qnil) {
184
+ rb_raise(rb_eRuntimeError, "request.session already initialized");
185
+ }
186
+ return p->session = session;
187
+ }
188
+
205
189
  static VALUE request_flash(VALUE self) {
206
190
  P;
207
191
  return p->flash;
208
192
  }
209
193
 
194
+ static VALUE request_flash_eq(VALUE self, VALUE flash) {
195
+ P;
196
+ if (p->flash != Qnil) {
197
+ rb_raise(rb_eRuntimeError, "request.flash already initialized");
198
+ }
199
+ return p->flash = flash;
200
+ }
201
+
210
202
  static VALUE request_body(VALUE self) {
211
203
  P;
212
204
  while (p->parse_state != PS_MESSAGE_COMPLETE) {
@@ -388,7 +380,9 @@ void Init_request(VALUE nyara, VALUE ext) {
388
380
  rb_define_method(request_class, "format", request_format, 0);
389
381
  rb_define_method(request_class, "cookie", request_cookie, 0);
390
382
  rb_define_method(request_class, "session", request_session, 0);
383
+ rb_define_method(request_class, "session=", request_session_eq, 1);
391
384
  rb_define_method(request_class, "flash", request_flash, 0);
385
+ rb_define_method(request_class, "flash=", request_flash_eq, 1);
392
386
  rb_define_method(request_class, "body", request_body, 0);
393
387
  rb_define_method(request_class, "message_complete?", request_message_complete_p, 0);
394
388
 
data/ext/request_parse.c CHANGED
@@ -138,7 +138,7 @@ static void _parse_path_and_query(Request* p) {
138
138
  long len = RSTRING_LEN(p->path_with_query);
139
139
  long query_i = nyara_parse_path(p->path, s, len);
140
140
  if (query_i < len) {
141
- nyara_parse_param(p->query, s + query_i, len - query_i);
141
+ nyara_parse_query(p->query, s + query_i, len - query_i);
142
142
 
143
143
  // do method override with _method=xxx in query
144
144
  if (p->method == HTTP_POST) {
data/ext/route.cc CHANGED
@@ -187,8 +187,7 @@ static VALUE ext_list_route(VALUE self) {
187
187
  return route_hash;
188
188
  }
189
189
 
190
- static VALUE build_args(const char* suffix, std::vector<ID>& conv) {
191
- volatile VALUE args = rb_ary_new();
190
+ static VALUE build_args(const char* suffix, std::vector<ID>& conv, volatile VALUE args) {
192
191
  volatile VALUE str = rb_str_new2(""); // tmp for conversion, no need encoding
193
192
  long last_len = 0;
194
193
  for (size_t j = 0; j < conv.size(); j++) {
@@ -271,8 +270,7 @@ RouteResult nyara_lookup_route(enum http_method method_num, VALUE vpath, VALUE a
271
270
  break;
272
271
  }
273
272
  }
274
- r.args = build_args(suffix, i->conv);
275
- rb_ary_push(r.args, i->id);
273
+ r.args = build_args(suffix, i->conv, rb_ary_new3(1, i->id));
276
274
  r.controller = i->controller;
277
275
  break;
278
276
  }
data/ext/url_encoded.c CHANGED
@@ -74,6 +74,8 @@ static long _decode_url_seg(VALUE output, const char*s, long len, char stop_char
74
74
  // NOTE it's similar to _decode_url_seg, but:
75
75
  // - "+" is not escaped
76
76
  // - matrix uri params (segments starting with ";") are ignored
77
+ //
78
+ // returns parsed length, including matrix uri params
77
79
  long nyara_parse_path(VALUE output, const char* s, long len) {
78
80
  const char* last_s = s;
79
81
  long last_len = 0;
@@ -133,75 +135,6 @@ long nyara_parse_path(VALUE output, const char* s, long len) {
133
135
  return i;
134
136
  }
135
137
 
136
- static VALUE ext_parse_path(VALUE self, VALUE output, VALUE input) {
137
- long parsed = nyara_parse_path(output, RSTRING_PTR(input), RSTRING_LEN(input));
138
- return ULONG2NUM(parsed);
139
- }
140
-
141
- static void _error(const char* msg, const char* s, long len, long segment_i) {
142
- if (s) {
143
- rb_raise(rb_eRuntimeError,
144
- "error parsing \"%.*s\": segments[%ld] is %s",
145
- (int)len, s, segment_i, msg);
146
- } else {
147
- rb_raise(rb_eRuntimeError, "%s", msg);
148
- }
149
- }
150
-
151
- static VALUE _new_child(long hash) {
152
- return hash ? rb_class_new_instance(0, NULL, nyara_param_hash_class) : rb_ary_new();
153
- }
154
-
155
- // a, b, c = keys; h[a][b][c] = value
156
- // the last 2 args are for error report
157
- static void _aset_keys(VALUE output, volatile VALUE keys, VALUE value, const char* kv_s, long kv_len) {
158
- VALUE* arr = RARRAY_PTR(keys);
159
- long len = RARRAY_LEN(keys);
160
- if (!len) {
161
- rb_bug("bug: aset 0 length key");
162
- return;
163
- }
164
-
165
- // first key seg
166
- long is_hash_key = 1;
167
-
168
- // middle key segs
169
- for (long i = 0; i < len - 1; i++) {
170
- long next_is_hash_key = RSTRING_LEN(arr[i + 1]);
171
- if (is_hash_key) {
172
- if (nyara_rb_hash_has_key(output, arr[i])) {
173
- output = rb_hash_aref(output, arr[i]);
174
- if (next_is_hash_key) {
175
- if (TYPE(output) != T_HASH) {
176
- // note: StringValueCStr requires VALUE* as param, and can raise another error if there's nul in the string
177
- _error("not array index (expect to be empty)", kv_s, kv_len, i);
178
- }
179
- } else {
180
- if (TYPE(output) != T_ARRAY) {
181
- _error("not hash key (expect to be non-empty)", kv_s, kv_len, i);
182
- }
183
- }
184
- } else {
185
- volatile VALUE child = _new_child(next_is_hash_key);
186
- rb_hash_aset(output, arr[i], child);
187
- output = child;
188
- }
189
- } else {
190
- volatile VALUE child = _new_child(next_is_hash_key);
191
- rb_ary_push(output, child);
192
- output = child;
193
- }
194
- is_hash_key = next_is_hash_key;
195
- }
196
-
197
- // terminate key seg: add value
198
- if (is_hash_key) {
199
- rb_hash_aset(output, arr[len - 1], value);
200
- } else {
201
- rb_ary_push(output, value);
202
- }
203
- }
204
-
205
138
  static const char* _strnchr(const char* s, long len, char c) {
206
139
  for (long i = 0; i < len; i++) {
207
140
  if (s[i] == c) {
@@ -215,16 +148,16 @@ static inline VALUE _new_blank_str() {
215
148
  return rb_enc_str_new("", 0, u8_encoding);
216
149
  }
217
150
 
218
- static void _url_encoded_seg(VALUE output, const char* kv_s, long kv_len, int nested_mode) {
219
- // (note if we _decode_url_seg with '&' first, then there may be multiple '='s in one kv)
151
+ // key and value are for output
152
+ // usually should be blank string
153
+ // decode into key and value
154
+ void nyara_decode_uri_kv(volatile VALUE key, volatile VALUE value, const char* kv_s, long kv_len) {
220
155
  const char* s = kv_s;
221
156
  long len = kv_len;
222
157
  if (!len) {
223
- return;
158
+ rb_raise(rb_eArgError, "empty key=value segment");
224
159
  }
225
160
 
226
- volatile VALUE value = _new_blank_str();
227
-
228
161
  // rule out the value part
229
162
  {
230
163
  // strnstr is not available on linux :(
@@ -232,125 +165,34 @@ static void _url_encoded_seg(VALUE output, const char* kv_s, long kv_len, int ne
232
165
  if (value_s) {
233
166
  value_s++;
234
167
  long value_len = s + len - value_s;
235
- long parsed = _decode_url_seg(value, value_s, value_len, '&');
236
- if (parsed != value_len) {
168
+ long skipped = 0;
169
+ for (;skipped < value_len; skipped++) {
170
+ if (!isspace(value_s[skipped])) {
171
+ break;
172
+ }
173
+ }
174
+ long parsed = _decode_url_seg(value, value_s + skipped, value_len - skipped, '&');
175
+ if (parsed != value_len - skipped) {
237
176
  rb_raise(rb_eArgError, "separator & in param segment");
238
177
  }
239
178
  len = value_s - s - 1;
240
179
  }
241
180
  // starts with '='
242
181
  if (value_s == s) {
243
- rb_hash_aset(output, _new_blank_str(), value);
244
182
  return;
245
183
  }
246
184
  }
247
-
248
- volatile VALUE key = _new_blank_str();
249
- if (nested_mode) {
250
- // todo fault-tolerant?
251
- long parsed = _decode_url_seg(key, s, len, '[');
252
- if (parsed == len) {
253
- rb_hash_aset(output, key, value);
254
- return;
255
- }
256
- s += parsed;
257
- len -= parsed;
258
- volatile VALUE keys = rb_ary_new3(1, key);
259
- while (len) {
260
- key = _new_blank_str();
261
- parsed = _decode_url_seg(key, s, len, ']');
262
- rb_ary_push(keys, key);
263
- s += parsed;
264
- len -= parsed;
265
- if (len) {
266
- if (s[0] == '[') {
267
- s++;
268
- len--;
269
- } else {
270
- rb_raise(rb_eRuntimeError, "malformed params: remaining chars in key but not starting with '['");
271
- return;
272
- }
273
- }
274
- }
275
- _aset_keys(output, keys, value, kv_s, kv_len);
276
- } else {
277
- _decode_url_seg(key, s, len, '=');
278
- rb_hash_aset(output, key, value);
279
- }
280
-
281
- return;
282
- }
283
-
284
- // "a[%20][][b]=c" ===> output["a", "\x20", nil, "b"] = "c"
285
- static VALUE ext_parse_url_encoded_seg(VALUE self, VALUE output, VALUE kv, VALUE v_nested_mode) {
286
- _url_encoded_seg(output, RSTRING_PTR(kv), RSTRING_LEN(kv), RTEST(v_nested_mode));
287
- return output;
288
- }
289
-
290
- void nyara_parse_param(VALUE output, const char* s, long len) {
291
- // split with /[&;] */
292
- long last_i = 0;
293
- long i = 0;
294
- for (; i < len; i++) {
295
- if (s[i] == '&' || s[i] == ';') {
296
- if (i > last_i) {
297
- _url_encoded_seg(output, s + last_i, i - last_i, 1);
298
- }
299
- while(i + 1 < len && s[i + 1] == ' ') {
300
- i++;
301
- }
302
- last_i = i + 1;
303
- }
304
- }
305
- if (i > last_i) {
306
- _url_encoded_seg(output, s + last_i, i - last_i, 1);
185
+ while (len > 0 && isspace(s[len - 1])) {
186
+ len--;
307
187
  }
188
+ _decode_url_seg(key, s, len, '=');
308
189
  }
309
190
 
310
- static VALUE ext_parse_param(VALUE self, VALUE output, VALUE s) {
311
- nyara_parse_param(output, RSTRING_PTR(s), RSTRING_LEN(s));
312
- return output;
313
- }
314
-
315
- static VALUE _cookie_seg_str_new(const char* s, long len) {
316
- // trim tailing space
317
- for (; len > 0; len--) {
318
- if (s[len - 1] != ' ') {
319
- break;
320
- }
321
- }
322
- return rb_enc_str_new(s, len, u8_encoding);
323
- }
324
-
325
- VALUE ext_parse_cookie(VALUE self, VALUE output, VALUE str) {
326
- volatile VALUE arr = rb_ary_new();
327
- const char* s = RSTRING_PTR(str);
328
- long len = RSTRING_LEN(str);
329
-
330
- // split with / *[,;] */
331
- long last_i = 0;
332
- long i = 0;
333
- for (; i < len; i++) {
334
- if (s[i] == ',' || s[i] == ';') {
335
- // char* and len parse_seg
336
- if (i > last_i) {
337
- rb_ary_push(arr, _cookie_seg_str_new(s + last_i, i - last_i));
338
- }
339
- while(i + 1 < len && s[i + 1] == ' ') {
340
- i++;
341
- }
342
- last_i = i + 1;
343
- }
344
- }
345
- if (i > last_i) {
346
- rb_ary_push(arr, _cookie_seg_str_new(s + last_i, i - last_i));
347
- }
348
-
349
- VALUE* arr_p = RARRAY_PTR(arr);
350
- for (long j = RARRAY_LEN(arr) - 1; j >= 0; j--) {
351
- _url_encoded_seg(output, RSTRING_PTR(arr_p[j]), RSTRING_LEN(arr_p[j]), 0);
352
- }
353
- return output;
191
+ static VALUE ext_decode_uri_kv(VALUE _, VALUE str) {
192
+ volatile VALUE k = _new_blank_str();
193
+ volatile VALUE v = _new_blank_str();
194
+ nyara_decode_uri_kv(k, v, RSTRING_PTR(str), RSTRING_LEN(str));
195
+ return rb_ary_new3(2, k, v);
354
196
  }
355
197
 
356
198
  static bool _should_escape(char c) {
@@ -391,7 +233,8 @@ static void _concat_char(VALUE s, char c, bool ispath) {
391
233
  }
392
234
  }
393
235
 
394
- // escape for uri path ('/', '+' are not changed) or component ('/', '+' are changed)
236
+ // escape for uri path ('/', '+' are not changed)
237
+ // or component ('/', '+' are changed)
395
238
  static VALUE ext_escape(VALUE _, VALUE s, VALUE v_ispath) {
396
239
  Check_Type(s, T_STRING);
397
240
  long len = RSTRING_LEN(s);
@@ -405,20 +248,35 @@ static VALUE ext_escape(VALUE _, VALUE s, VALUE v_ispath) {
405
248
  return res;
406
249
  }
407
250
 
408
- // nil in keys will be interpreted as array key
409
- static VALUE ext_param_hash_nested_aset(VALUE _, VALUE output, VALUE keys, VALUE value) {
410
- // todo check output is ParamHash
411
- Check_Type(keys, T_ARRAY);
412
- _aset_keys(output, keys, value, NULL, 0);
413
- return Qnil;
251
+ // caveats:
252
+ // - stops at '='
253
+ // - matrix uri params and query are ignored
254
+ static VALUE ext_unescape(VALUE _, volatile VALUE s, VALUE v_is_path) {
255
+ Check_Type(s, T_STRING);
256
+ if (RTEST(v_is_path)) {
257
+ volatile VALUE output = _new_blank_str();
258
+ if (nyara_parse_path(output, RSTRING_PTR(s), RSTRING_LEN(s))) {
259
+ }
260
+ return output;
261
+ } else {
262
+ volatile VALUE output = _new_blank_str();
263
+ _decode_url_seg(output, RSTRING_PTR(s), RSTRING_LEN(s), '=');
264
+ return output;
265
+ }
266
+ }
267
+
268
+ // concats result into output<br>
269
+ // returns parsed length
270
+ static VALUE ext_parse_path(VALUE self, VALUE output, VALUE input) {
271
+ long parsed = nyara_parse_path(output, RSTRING_PTR(input), RSTRING_LEN(input));
272
+ return ULONG2NUM(parsed);
414
273
  }
415
274
 
416
275
  void Init_url_encoded(VALUE ext) {
417
- rb_define_singleton_method(ext, "parse_param", ext_parse_param, 2);
418
- rb_define_singleton_method(ext, "parse_cookie", ext_parse_cookie, 2);
419
276
  rb_define_singleton_method(ext, "escape", ext_escape, 2);
420
- rb_define_singleton_method(ext, "param_hash_nested_aset", ext_param_hash_nested_aset, 3);
421
- // for test
422
- rb_define_singleton_method(ext, "parse_url_encoded_seg", ext_parse_url_encoded_seg, 3);
277
+ rb_define_singleton_method(ext, "unescape", ext_unescape, 2);
278
+
279
+ // test only
280
+ rb_define_singleton_method(ext, "decode_uri_kv", ext_decode_uri_kv, 1);
423
281
  rb_define_singleton_method(ext, "parse_path", ext_parse_path, 2);
424
282
  }