iodine 0.7.11 → 0.7.12

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

@@ -8,12 +8,30 @@
8
8
  /**
9
9
  * Loads a mustache template, converting it into an opaque instruction array.
10
10
  *
11
- * Returns a pointer to the instruction array.
11
+ * Returns a pointer to the instruction array or NULL (on error).
12
12
  *
13
13
  * The `filename` argument should contain the template's file name.
14
14
  */
15
15
  mustache_s *fiobj_mustache_load(fio_str_info_s filename);
16
16
 
17
+ /**
18
+ * Loads a mustache template, either from memory of a file, converting it into
19
+ * an opaque instruction array.
20
+ *
21
+ * Returns a pointer to the instruction array or NULL (on error).
22
+ *
23
+ * Accepts any of the following named arguments:
24
+ * * `char const *filename` - The root template's file name.
25
+ * * `size_t filename_len` - The file name's length.
26
+ * * `char const *data` - If set, will be used as the file's contents.
27
+ * * `size_t data_len` - If set, `data` will be used as the file's contents.
28
+ * * `mustache_error_en *err` - A container for any template load errors (see
29
+ * mustache_parser.h).
30
+ */
31
+ mustache_s *fiobj_mustache_new(mustache_load_args_s args);
32
+ #define fiobj_mustache_new(...) \
33
+ fiobj_mustache_new((mustache_load_args_s){__VA_ARGS__})
34
+
17
35
  /** Free the mustache template */
18
36
  void fiobj_mustache_free(mustache_s *mustache);
19
37
 
@@ -21,7 +39,7 @@ void fiobj_mustache_free(mustache_s *mustache);
21
39
  * Creates a FIOBJ String containing the rendered template using the information
22
40
  * in the `data` object.
23
41
  *
24
- * Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
42
+ * Returns FIOBJ_INVALID if an error occurred and a FIOBJ String on success.
25
43
  */
26
44
  FIOBJ fiobj_mustache_build(mustache_s *mustache, FIOBJ data);
27
45
 
@@ -29,7 +47,7 @@ FIOBJ fiobj_mustache_build(mustache_s *mustache, FIOBJ data);
29
47
  * Renders a template into an existing FIOBJ String (`dest`'s end), using the
30
48
  * information in the `data` object.
31
49
  *
32
- * Returns FIOBJ_INVALID if an error occured and a FIOBJ String on success.
50
+ * Returns FIOBJ_INVALID if an error occurred and a FIOBJ String on success.
33
51
  */
34
52
  FIOBJ fiobj_mustache_build2(FIOBJ dest, mustache_s *mustache, FIOBJ data);
35
53
 
@@ -2665,6 +2665,25 @@ parse_path:
2665
2665
  ++url;
2666
2666
  result.target.data = (char *)url;
2667
2667
  result.target.len = end - result.target.data;
2668
+
2669
+ /* set any empty values to NULL */
2670
+ if (!result.scheme.len)
2671
+ result.scheme.data = NULL;
2672
+ if (!result.user.len)
2673
+ result.user.data = NULL;
2674
+ if (!result.password.len)
2675
+ result.password.data = NULL;
2676
+ if (!result.host.len)
2677
+ result.host.data = NULL;
2678
+ if (!result.port.len)
2679
+ result.port.data = NULL;
2680
+ if (!result.path.len)
2681
+ result.path.data = NULL;
2682
+ if (!result.query.len)
2683
+ result.query.data = NULL;
2684
+ if (!result.target.len)
2685
+ result.target.data = NULL;
2686
+
2668
2687
  return result;
2669
2688
  }
2670
2689
 
@@ -978,8 +978,12 @@ typedef struct {
978
978
  * i.e.:
979
979
  * example.com
980
980
  * example.com/index.html
981
- * user:1234@example.com:8080
982
981
  * example.com:8080/index.html
982
+ * example.com:8080/index.html?key=val#target
983
+ *
984
+ * * `user:password@host:port/path?query#target`
985
+ *
986
+ * i.e.: user:1234@example.com:8080/index.html
983
987
  *
984
988
  * * `schema://user:password@host:port/path?query#target`
985
989
  *
@@ -12,8 +12,6 @@ Feel free to copy, use and enjoy according to the license provided.
12
12
 
13
13
  #include <http.h>
14
14
 
15
- #include <fiobj4sock.h>
16
-
17
15
  #include <arpa/inet.h>
18
16
  #include <errno.h>
19
17
 
@@ -4,7 +4,7 @@
4
4
  #define FIO_INCLUDE_STR
5
5
  #include "fio.h"
6
6
 
7
- #include "fiobj4sock.h"
7
+ #include "fiobj4fio.h"
8
8
  #include "websockets.h"
9
9
 
10
10
  #include <ruby/io.h>
@@ -938,7 +938,14 @@ static VALUE iodine_http_listen(VALUE self, VALUE opt) {
938
938
  IodineStore.add(port);
939
939
  } else if (port == Qfalse)
940
940
  port = 0;
941
- else {
941
+ else if (address &&
942
+ (StringValueCStr(address)[0] > '9' ||
943
+ StringValueCStr(address)[0] < '0') &&
944
+ StringValueCStr(address)[0] != ':' &&
945
+ (RSTRING_LEN(address) < 3 || StringValueCStr(address)[2] != ':')) {
946
+ /* address is likely a Unix domain socket address, not an IP address... */
947
+ port = Qnil;
948
+ } else {
942
949
  port = rb_str_new("3000", 4);
943
950
  IodineStore.add(port);
944
951
  }
@@ -948,14 +955,15 @@ static VALUE iodine_http_listen(VALUE self, VALUE opt) {
948
955
  else
949
956
  app = 0;
950
957
 
951
- if (http_listen(
952
- StringValueCStr(port), (address ? StringValueCStr(address) : NULL),
953
- .on_request = on_rack_request, .on_upgrade = on_rack_upgrade,
954
- .udata = (void *)app, .timeout = (tout ? FIX2INT(tout) : tout),
955
- .ws_timeout = ping, .ws_max_msg_size = max_msg,
956
- .max_header_size = max_headers, .on_finish = free_iodine_http,
957
- .log = log_http, .max_body_size = max_body,
958
- .public_folder = (www ? StringValueCStr(www) : NULL)) == -1) {
958
+ if (http_listen((port ? StringValueCStr(port) : NULL),
959
+ (address ? StringValueCStr(address) : NULL),
960
+ .on_request = on_rack_request, .on_upgrade = on_rack_upgrade,
961
+ .udata = (void *)app,
962
+ .timeout = (tout ? FIX2INT(tout) : tout), .ws_timeout = ping,
963
+ .ws_max_msg_size = max_msg, .max_header_size = max_headers,
964
+ .on_finish = free_iodine_http, .log = log_http,
965
+ .max_body_size = max_body,
966
+ .public_folder = (www ? StringValueCStr(www) : NULL)) == -1) {
959
967
  FIO_LOG_ERROR("Failed to initialize a listening HTTP socket for port %s",
960
968
  port ? StringValueCStr(port) : "3000");
961
969
  rb_raise(rb_eRuntimeError, "Listening socket initialization failed");
@@ -51,8 +51,10 @@ Parser Callbacks
51
51
  ***************************************************************************** */
52
52
 
53
53
  /** HTML ecape table, created using the following Ruby Script:
54
- a = []
55
- 256.times {|i| a[i] = "&\#x#{ i < 16 ? "0#{i.to_s(16)}" : i.to_s(16)};"}
54
+
55
+ a = (0..255).to_a.map {|i| i.chr }
56
+ # 100.times {|i| a[i] = "&\#x#{ i < 16 ? "0#{i.to_s(16)}" : i.to_s(16)};"}
57
+ 100.times {|i| a[i] = "&\##{i.to_s(10)};"}
56
58
  ('a'.ord..'z'.ord).each {|i| a[i] = i.chr }
57
59
  ('A'.ord..'Z'.ord).each {|i| a[i] = i.chr }
58
60
  ('0'.ord..'9'.ord).each {|i| a[i] = i.chr }
@@ -60,94 +62,127 @@ a['<'.ord] = "&lt;"
60
62
  a['>'.ord] = "&gt;"
61
63
  a['&'.ord] = "&amp;"
62
64
  a['"'.ord] = "&quot;"
65
+ a["\'".ord] = "&apos;"
66
+ a['|'.ord] = "&\##{'|'.ord.to_s(10)};"
63
67
 
64
68
  b = a.map {|s| s.length }
65
69
  puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
66
70
  "static uint8_t html_escape_len[] = {", b.to_s.slice(1..-2),"};"
67
71
  */
68
- static const char *html_escape_strs[] = {
69
- "&#x00;", "&#x01;", "&#x02;", "&#x03;", "&#x04;", "&#x05;", "&#x06;",
70
- "&#x07;", "&#x08;", "&#x09;", "&#x0a;", "&#x0b;", "&#x0c;", "&#x0d;",
71
- "&#x0e;", "&#x0f;", "&#x10;", "&#x11;", "&#x12;", "&#x13;", "&#x14;",
72
- "&#x15;", "&#x16;", "&#x17;", "&#x18;", "&#x19;", "&#x1a;", "&#x1b;",
73
- "&#x1c;", "&#x1d;", "&#x1e;", "&#x1f;", "&#x20;", "&#x21;", "&quot;",
74
- "&#x23;", "&#x24;", "&#x25;", "&amp;", "&#x27;", "&#x28;", "&#x29;",
75
- "&#x2a;", "&#x2b;", "&#x2c;", "&#x2d;", "&#x2e;", "&#x2f;", "0",
76
- "1", "2", "3", "4", "5", "6", "7",
77
- "8", "9", "&#x3a;", "&#x3b;", "&lt;", "&#x3d;", "&gt;",
78
- "&#x3f;", "&#x40;", "A", "B", "C", "D", "E",
79
- "F", "G", "H", "I", "J", "K", "L",
80
- "M", "N", "O", "P", "Q", "R", "S",
81
- "T", "U", "V", "W", "X", "Y", "Z",
82
- "&#x5b;", "&#x5c;", "&#x5d;", "&#x5e;", "&#x5f;", "&#x60;", "a",
83
- "b", "c", "d", "e", "f", "g", "h",
84
- "i", "j", "k", "l", "m", "n", "o",
85
- "p", "q", "r", "s", "t", "u", "v",
86
- "w", "x", "y", "z", "&#x7b;", "&#x7c;", "&#x7d;",
87
- "&#x7e;", "&#x7f;", "&#x80;", "&#x81;", "&#x82;", "&#x83;", "&#x84;",
88
- "&#x85;", "&#x86;", "&#x87;", "&#x88;", "&#x89;", "&#x8a;", "&#x8b;",
89
- "&#x8c;", "&#x8d;", "&#x8e;", "&#x8f;", "&#x90;", "&#x91;", "&#x92;",
90
- "&#x93;", "&#x94;", "&#x95;", "&#x96;", "&#x97;", "&#x98;", "&#x99;",
91
- "&#x9a;", "&#x9b;", "&#x9c;", "&#x9d;", "&#x9e;", "&#x9f;", "&#xa0;",
92
- "&#xa1;", "&#xa2;", "&#xa3;", "&#xa4;", "&#xa5;", "&#xa6;", "&#xa7;",
93
- "&#xa8;", "&#xa9;", "&#xaa;", "&#xab;", "&#xac;", "&#xad;", "&#xae;",
94
- "&#xaf;", "&#xb0;", "&#xb1;", "&#xb2;", "&#xb3;", "&#xb4;", "&#xb5;",
95
- "&#xb6;", "&#xb7;", "&#xb8;", "&#xb9;", "&#xba;", "&#xbb;", "&#xbc;",
96
- "&#xbd;", "&#xbe;", "&#xbf;", "&#xc0;", "&#xc1;", "&#xc2;", "&#xc3;",
97
- "&#xc4;", "&#xc5;", "&#xc6;", "&#xc7;", "&#xc8;", "&#xc9;", "&#xca;",
98
- "&#xcb;", "&#xcc;", "&#xcd;", "&#xce;", "&#xcf;", "&#xd0;", "&#xd1;",
99
- "&#xd2;", "&#xd3;", "&#xd4;", "&#xd5;", "&#xd6;", "&#xd7;", "&#xd8;",
100
- "&#xd9;", "&#xda;", "&#xdb;", "&#xdc;", "&#xdd;", "&#xde;", "&#xdf;",
101
- "&#xe0;", "&#xe1;", "&#xe2;", "&#xe3;", "&#xe4;", "&#xe5;", "&#xe6;",
102
- "&#xe7;", "&#xe8;", "&#xe9;", "&#xea;", "&#xeb;", "&#xec;", "&#xed;",
103
- "&#xee;", "&#xef;", "&#xf0;", "&#xf1;", "&#xf2;", "&#xf3;", "&#xf4;",
104
- "&#xf5;", "&#xf6;", "&#xf7;", "&#xf8;", "&#xf9;", "&#xfa;", "&#xfb;",
105
- "&#xfc;", "&#xfd;", "&#xfe;", "&#xff;"};
72
+ static char *html_escape_strs[] = {
73
+ "&#0;", "&#1;", "&#2;", "&#3;", "&#4;", "&#5;", "&#6;", "&#7;",
74
+ "&#8;", "&#9;", "&#10;", "&#11;", "&#12;", "&#13;", "&#14;", "&#15;",
75
+ "&#16;", "&#17;", "&#18;", "&#19;", "&#20;", "&#21;", "&#22;", "&#23;",
76
+ "&#24;", "&#25;", "&#26;", "&#27;", "&#28;", "&#29;", "&#30;", "&#31;",
77
+ "&#32;", "&#33;", "&quot;", "&#35;", "&#36;", "&#37;", "&amp;", "&apos;",
78
+ "&#40;", "&#41;", "&#42;", "&#43;", "&#44;", "&#45;", "&#46;", "&#47;",
79
+ "0", "1", "2", "3", "4", "5", "6", "7",
80
+ "8", "9", "&#58;", "&#59;", "&lt;", "&#61;", "&gt;", "&#63;",
81
+ "&#64;", "A", "B", "C", "D", "E", "F", "G",
82
+ "H", "I", "J", "K", "L", "M", "N", "O",
83
+ "P", "Q", "R", "S", "T", "U", "V", "W",
84
+ "X", "Y", "Z", "&#91;", "&#92;", "&#93;", "&#94;", "&#95;",
85
+ "&#96;", "a", "b", "c", "d", "e", "f", "g",
86
+ "h", "i", "j", "k", "l", "m", "n", "o",
87
+ "p", "q", "r", "s", "t", "u", "v", "w",
88
+ "x", "y", "z", "{", "&#124;", "}", "~", "\x7F",
89
+ "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87",
90
+ "\x88", "\x89", "\x8A", "\x8B", "\x8C", "\x8D", "\x8E", "\x8F",
91
+ "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97",
92
+ "\x98", "\x99", "\x9A", "\x9B", "\x9C", "\x9D", "\x9E", "\x9F",
93
+ "\xA0", "\xA1", "\xA2", "\xA3", "\xA4", "\xA5", "\xA6", "\xA7",
94
+ "\xA8", "\xA9", "\xAA", "\xAB", "\xAC", "\xAD", "\xAE", "\xAF",
95
+ "\xB0", "\xB1", "\xB2", "\xB3", "\xB4", "\xB5", "\xB6", "\xB7",
96
+ "\xB8", "\xB9", "\xBA", "\xBB", "\xBC", "\xBD", "\xBE", "\xBF",
97
+ "\xC0", "\xC1", "\xC2", "\xC3", "\xC4", "\xC5", "\xC6", "\xC7",
98
+ "\xC8", "\xC9", "\xCA", "\xCB", "\xCC", "\xCD", "\xCE", "\xCF",
99
+ "\xD0", "\xD1", "\xD2", "\xD3", "\xD4", "\xD5", "\xD6", "\xD7",
100
+ "\xD8", "\xD9", "\xDA", "\xDB", "\xDC", "\xDD", "\xDE", "\xDF",
101
+ "\xE0", "\xE1", "\xE2", "\xE3", "\xE4", "\xE5", "\xE6", "\xE7",
102
+ "\xE8", "\xE9", "\xEA", "\xEB", "\xEC", "\xED", "\xEE", "\xEF",
103
+ "\xF0", "\xF1", "\xF2", "\xF3", "\xF4", "\xF5", "\xF6", "\xF7",
104
+ "\xF8", "\xF9", "\xFA", "\xFB", "\xFC", "\xFD", "\xFE", "\xFF"};
106
105
  static uint8_t html_escape_len[] = {
107
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
108
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
109
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 4, 6, 4, 6, 6, 1, 1, 1, 1, 1, 1, 1,
110
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6,
111
- 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
112
- 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
113
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
114
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
115
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
116
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
117
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
106
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
107
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5,
108
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 4, 5, 4, 5, 5, 1, 1, 1, 1, 1, 1, 1,
109
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, 5, 5,
110
+ 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
111
+ 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
112
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
113
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
114
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
115
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
116
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
117
+
118
+ static inline VALUE fiobj_mustache_find_obj_absolute(VALUE udata,
119
+ const char *name,
120
+ uint32_t name_len) {
121
+ VALUE tmp;
122
+ if (!RB_TYPE_P(udata, T_HASH)) {
123
+ if (name_len == 1 && name[0] == '.')
124
+ return udata;
125
+ return Qnil;
126
+ }
127
+ /* search by String */
128
+ VALUE key = rb_str_new(name, name_len);
129
+ tmp = rb_hash_aref(udata, key);
130
+ if (tmp != Qnil)
131
+ return tmp;
132
+ /* search by Symbol */
133
+ key = rb_id2sym(rb_intern2(name, name_len));
134
+ tmp = rb_hash_aref(udata, key);
135
+ return tmp;
136
+ }
118
137
 
119
- static inline VALUE fiobj_mustache_find_obj(mustache_section_s *section,
120
- const char *name,
121
- uint32_t name_len) {
138
+ static inline VALUE fiobj_mustache_find_obj_tree(mustache_section_s *section,
139
+ const char *name,
140
+ uint32_t name_len) {
122
141
  do {
123
- VALUE tmp;
124
- #if 0
125
- /* test for Array indexing */
126
- if (name[0] >= '0' && name[0] <= '9' &&
127
- RB_TYPE_P((VALUE)section->udata2, T_ARRAY)) {
128
- char **pos = (char **)&name;
129
- tmp = rb_ary_entry((VALUE)section->udata2, fio_atol(pos));
130
- if (tmp)
131
- return tmp;
132
- }
133
- #endif
134
- if (!RB_TYPE_P((VALUE)section->udata2, T_HASH)) {
135
- continue;
136
- }
137
- /* search by String */
138
- VALUE key = rb_str_new(name, name_len);
139
- tmp = rb_hash_aref((VALUE)section->udata2, key);
140
- if (tmp != Qnil)
142
+ VALUE tmp = fiobj_mustache_find_obj_absolute((VALUE)section->udata2, name,
143
+ name_len);
144
+ if (tmp != Qnil) {
141
145
  return tmp;
142
- /* search by Symbol */
143
- key = rb_id2sym(rb_intern2(name, name_len));
144
- tmp = rb_hash_aref((VALUE)section->udata2, key);
145
- if (tmp != Qnil)
146
- return tmp;
147
- section = section->parent;
148
- } while (section);
146
+ }
147
+ } while ((section = mustache_section_parent(section)));
149
148
  return Qnil;
150
149
  }
150
+
151
+ static inline VALUE fiobj_mustache_find_obj(mustache_section_s *section,
152
+ const char *name,
153
+ uint32_t name_len) {
154
+ VALUE tmp = fiobj_mustache_find_obj_tree(section, name, name_len);
155
+ if (tmp != Qnil)
156
+ return tmp;
157
+ /* interpolate sections... */
158
+ uint32_t dot = 0;
159
+ while (dot < name_len && name[dot] != '.')
160
+ ++dot;
161
+ if (dot == name_len)
162
+ return Qnil;
163
+ tmp = fiobj_mustache_find_obj_tree(section, name, dot);
164
+ if (!tmp) {
165
+ return Qnil;
166
+ }
167
+ ++dot;
168
+ for (;;) {
169
+ VALUE obj =
170
+ fiobj_mustache_find_obj_absolute(tmp, name + dot, name_len - dot);
171
+ if (obj != Qnil)
172
+ return obj;
173
+ name += dot;
174
+ name_len -= dot;
175
+ dot = 0;
176
+ while (dot < name_len && name[dot] != '.')
177
+ ++dot;
178
+ if (dot == name_len)
179
+ return Qnil;
180
+ tmp = fiobj_mustache_find_obj_absolute(tmp, name, dot);
181
+ if (tmp == Qnil || !RB_TYPE_P(tmp, T_HASH))
182
+ return Qnil;
183
+ ++dot;
184
+ }
185
+ }
151
186
  /**
152
187
  * Called when an argument name was detected in the current section.
153
188
  *
@@ -163,13 +198,19 @@ static inline VALUE fiobj_mustache_find_obj(mustache_section_s *section,
163
198
  static int mustache_on_arg(mustache_section_s *section, const char *name,
164
199
  uint32_t name_len, unsigned char escape) {
165
200
  VALUE o = fiobj_mustache_find_obj(section, name, name_len);
166
- if (!o)
201
+ switch (o) {
202
+ case Qnil:
203
+ case Qfalse:
167
204
  return 0;
205
+ case Qtrue:
206
+ fio_str_write(section->udata1, "true", 4);
207
+ break;
208
+ }
168
209
  if (rb_respond_to(o, call_func_id))
169
210
  goto callable;
170
211
  if (!RB_TYPE_P(o, T_STRING))
171
212
  o = IodineCaller.call(o, to_s_func_id);
172
- if (!RB_TYPE_P(o, T_STRING) || !RSTRUCT_LEN(o))
213
+ if (!RB_TYPE_P(o, T_STRING) || !RSTRING_LEN(o))
173
214
  return 0;
174
215
  if (!escape) {
175
216
  fio_str_write(section->udata1, RSTRING_PTR(o), RSTRING_LEN(o));
@@ -193,9 +234,10 @@ static int mustache_on_arg(mustache_section_s *section, const char *name,
193
234
  (void)escape;
194
235
  return 0;
195
236
  callable:
196
- o = rb_funcall2(o, call_func_id, 0, NULL);
197
- o = rb_any_to_s(o);
198
- fio_str_write(section->udata1, RSTRING_PTR(o), RSTRUCT_LEN(o));
237
+ o = IodineCaller.call(o, call_func_id);
238
+ if (RB_TYPE_P(o, T_STRING))
239
+ o = rb_funcall2(o, to_s_func_id, 0, NULL);
240
+ fio_str_write(section->udata1, RSTRING_PTR(o), RSTRING_LEN(o));
199
241
  return 0;
200
242
  }
201
243
 
@@ -225,14 +267,29 @@ static int mustache_on_text(mustache_section_s *section, const char *data,
225
267
  * Please note, this will handle both normal and inverted sections.
226
268
  */
227
269
  static int32_t mustache_on_section_test(mustache_section_s *section,
228
- const char *name, uint32_t name_len) {
270
+ const char *name, uint32_t name_len,
271
+ uint8_t callable) {
229
272
  VALUE o = fiobj_mustache_find_obj(section, name, name_len);
230
- if (o == Qnil) {
273
+ if (o == Qnil || o == Qfalse) {
231
274
  return 0;
232
275
  }
233
276
  if (RB_TYPE_P(o, T_ARRAY)) {
234
277
  return RARRAY_LEN(o);
235
278
  }
279
+ if (callable && rb_respond_to(o, call_func_id)) {
280
+ size_t len;
281
+ const char *txt = mustache_section_text(section, &len);
282
+ VALUE str = Qnil;
283
+ if (txt && len) {
284
+ str = rb_str_new(txt, len);
285
+ }
286
+ o = IodineCaller.call2(o, call_func_id, 1, &str);
287
+ if (!RB_TYPE_P(o, T_STRING))
288
+ o = rb_funcall2(o, to_s_func_id, 0, NULL);
289
+ if (RB_TYPE_P(o, T_STRING) && RSTRING_LEN(o))
290
+ fio_str_write(section->udata1, RSTRING_PTR(o), RSTRING_LEN(o));
291
+ return 0;
292
+ }
236
293
  return 1;
237
294
  }
238
295
 
@@ -252,11 +309,9 @@ static int mustache_on_section_start(mustache_section_s *section,
252
309
  char const *name, uint32_t name_len,
253
310
  uint32_t index) {
254
311
  VALUE o = fiobj_mustache_find_obj(section, name, name_len);
255
- if (o == Qnil)
256
- return 0;
257
312
  if (RB_TYPE_P(o, T_ARRAY))
258
313
  section->udata2 = (void *)rb_ary_entry(o, index);
259
- else
314
+ else if (RB_TYPE_P(o, T_HASH))
260
315
  section->udata2 = (void *)o;
261
316
  return 0;
262
317
  }
@@ -321,6 +376,19 @@ error:
321
376
  case MUSTACHE_ERR_USER_ERROR:
322
377
  rb_raise(rb_eRuntimeError, "Iodine::Mustache internal error.");
323
378
  break;
379
+ case MUSTACHE_ERR_FILE_NAME_TOO_SHORT:
380
+ rb_raise(rb_eRuntimeError, "Iodine::Mustache template file name too long.");
381
+
382
+ break;
383
+ case MUSTACHE_ERR_DELIMITER_TOO_LONG:
384
+ rb_raise(rb_eRuntimeError, "Iodine::Mustache new delimiter is too long.");
385
+
386
+ break;
387
+ case MUSTACHE_ERR_NAME_TOO_LONG:
388
+ rb_raise(rb_eRuntimeError,
389
+ "Iodine::Mustache section name in template is too long.");
390
+ default:
391
+ break;
324
392
  }
325
393
  return self;
326
394
  }
@@ -438,7 +506,6 @@ static VALUE iodine_mustache_render_klass(int argc, VALUE *argv, VALUE self) {
438
506
  .err = &err);
439
507
  if (!m)
440
508
  goto error;
441
-
442
509
  int e = mustache_build(m, .udata1 = &str, .udata2 = (void *)data);
443
510
  mustache_free(m);
444
511
  if (e)
@@ -476,7 +543,23 @@ error:
476
543
  rb_raise(rb_eRuntimeError, "Iodine::Mustache unknown error.");
477
544
  break;
478
545
  case MUSTACHE_ERR_USER_ERROR:
479
- rb_raise(rb_eRuntimeError, "Iodine::Mustache internal error.");
546
+ rb_raise(rb_eRuntimeError,
547
+ "Iodine::Mustache internal error or unexpected data structure.");
548
+ break;
549
+ case MUSTACHE_ERR_FILE_NAME_TOO_SHORT:
550
+ rb_raise(rb_eRuntimeError, "Iodine::Mustache template file name too long.");
551
+
552
+ break;
553
+ case MUSTACHE_ERR_DELIMITER_TOO_LONG:
554
+ rb_raise(rb_eRuntimeError, "Iodine::Mustache new delimiter is too long.");
555
+
556
+ break;
557
+ case MUSTACHE_ERR_NAME_TOO_LONG:
558
+ rb_raise(rb_eRuntimeError,
559
+ "Iodine::Mustache section name in template is too long.");
560
+
561
+ break;
562
+ default:
480
563
  break;
481
564
  }
482
565
  return Qnil;