1 #include "buffer.h"
2 #include "log.h"
3 #include "mod_ssi.h"
4 #include "mod_ssi_expr.h"
5 #include "mod_ssi_exprparser.h"
6
7 #include <ctype.h>
8 #include <string.h>
9
10 typedef struct {
11 const char *input;
12 size_t offset;
13 size_t size;
14
15 int line_pos;
16
17 int in_key;
18 int in_brace;
19 int in_cond;
20 } ssi_tokenizer_t;
21
ssi_val_init(void)22 ssi_val_t *ssi_val_init(void) {
23 ssi_val_t *s;
24
25 s = calloc(1, sizeof(*s));
26
27 return s;
28 }
29
ssi_val_free(ssi_val_t * s)30 void ssi_val_free(ssi_val_t *s) {
31 if (s->str) buffer_free(s->str);
32
33 free(s);
34 }
35
ssi_val_tobool(ssi_val_t * B)36 int ssi_val_tobool(ssi_val_t *B) {
37 if (B->type == SSI_TYPE_STRING) {
38 return B->str->used > 1 ? 1 : 0;
39 } else {
40 return B->bo;
41 }
42 }
43
ssi_expr_tokenizer(server * srv,connection * con,plugin_data * p,ssi_tokenizer_t * t,int * token_id,buffer * token)44 static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p,
45 ssi_tokenizer_t *t, int *token_id, buffer *token) {
46 int tid = 0;
47 size_t i;
48
49 UNUSED(con);
50
51 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
52 char c = t->input[t->offset];
53 data_string *ds;
54
55 switch (c) {
56 case '=':
57 tid = TK_EQ;
58
59 t->offset++;
60 t->line_pos++;
61
62 buffer_copy_string_len(token, CONST_STR_LEN("(=)"));
63
64 break;
65 case '>':
66 if (t->input[t->offset + 1] == '=') {
67 t->offset += 2;
68 t->line_pos += 2;
69
70 tid = TK_GE;
71
72 buffer_copy_string_len(token, CONST_STR_LEN("(>=)"));
73 } else {
74 t->offset += 1;
75 t->line_pos += 1;
76
77 tid = TK_GT;
78
79 buffer_copy_string_len(token, CONST_STR_LEN("(>)"));
80 }
81
82 break;
83 case '<':
84 if (t->input[t->offset + 1] == '=') {
85 t->offset += 2;
86 t->line_pos += 2;
87
88 tid = TK_LE;
89
90 buffer_copy_string_len(token, CONST_STR_LEN("(<=)"));
91 } else {
92 t->offset += 1;
93 t->line_pos += 1;
94
95 tid = TK_LT;
96
97 buffer_copy_string_len(token, CONST_STR_LEN("(<)"));
98 }
99
100 break;
101
102 case '!':
103 if (t->input[t->offset + 1] == '=') {
104 t->offset += 2;
105 t->line_pos += 2;
106
107 tid = TK_NE;
108
109 buffer_copy_string_len(token, CONST_STR_LEN("(!=)"));
110 } else {
111 t->offset += 1;
112 t->line_pos += 1;
113
114 tid = TK_NOT;
115
116 buffer_copy_string_len(token, CONST_STR_LEN("(!)"));
117 }
118
119 break;
120 case '&':
121 if (t->input[t->offset + 1] == '&') {
122 t->offset += 2;
123 t->line_pos += 2;
124
125 tid = TK_AND;
126
127 buffer_copy_string_len(token, CONST_STR_LEN("(&&)"));
128 } else {
129 log_error_write(srv, __FILE__, __LINE__, "sds",
130 "pos:", t->line_pos,
131 "missing second &");
132 return -1;
133 }
134
135 break;
136 case '|':
137 if (t->input[t->offset + 1] == '|') {
138 t->offset += 2;
139 t->line_pos += 2;
140
141 tid = TK_OR;
142
143 buffer_copy_string_len(token, CONST_STR_LEN("(||)"));
144 } else {
145 log_error_write(srv, __FILE__, __LINE__, "sds",
146 "pos:", t->line_pos,
147 "missing second |");
148 return -1;
149 }
150
151 break;
152 case '\t':
153 case ' ':
154 t->offset++;
155 t->line_pos++;
156 break;
157
158 case '\'':
159 /* search for the terminating " */
160 for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
161
162 if (t->input[t->offset + i]) {
163 tid = TK_VALUE;
164
165 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
166
167 t->offset += i + 1;
168 t->line_pos += i + 1;
169 } else {
170 /* ERROR */
171
172 log_error_write(srv, __FILE__, __LINE__, "sds",
173 "pos:", t->line_pos,
174 "missing closing quote");
175
176 return -1;
177 }
178
179 break;
180 case '(':
181 t->offset++;
182 t->in_brace++;
183
184 tid = TK_LPARAN;
185
186 buffer_copy_string_len(token, CONST_STR_LEN("("));
187 break;
188 case ')':
189 t->offset++;
190 t->in_brace--;
191
192 tid = TK_RPARAN;
193
194 buffer_copy_string_len(token, CONST_STR_LEN(")"));
195 break;
196 case '$':
197 if (t->input[t->offset + 1] == '{') {
198 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
199
200 if (t->input[t->offset + i] != '}') {
201 log_error_write(srv, __FILE__, __LINE__, "sds",
202 "pos:", t->line_pos,
203 "missing closing quote");
204
205 return -1;
206 }
207
208 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
209 } else {
210 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
211
212 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
213 }
214
215 tid = TK_VALUE;
216
217 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
218 buffer_copy_string_buffer(token, ds->value);
219 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
220 buffer_copy_string_buffer(token, ds->value);
221 } else {
222 buffer_copy_string_len(token, CONST_STR_LEN(""));
223 }
224
225 t->offset += i;
226 t->line_pos += i;
227
228 break;
229 default:
230 for (i = 0; isgraph(t->input[t->offset + i]); i++) {
231 char d = t->input[t->offset + i];
232 switch(d) {
233 case ' ':
234 case '\t':
235 case ')':
236 case '(':
237 case '\'':
238 case '=':
239 case '!':
240 case '<':
241 case '>':
242 case '&':
243 case '|':
244 break;
245 }
246 }
247
248 tid = TK_VALUE;
249
250 buffer_copy_string_len(token, t->input + t->offset, i);
251
252 t->offset += i;
253 t->line_pos += i;
254
255 break;
256 }
257 }
258
259 if (tid) {
260 *token_id = tid;
261
262 return 1;
263 } else if (t->offset < t->size) {
264 log_error_write(srv, __FILE__, __LINE__, "sds",
265 "pos:", t->line_pos,
266 "foobar");
267 }
268 return 0;
269 }
270
ssi_eval_expr(server * srv,connection * con,plugin_data * p,const char * expr)271 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr) {
272 ssi_tokenizer_t t;
273 void *pParser;
274 int token_id;
275 buffer *token;
276 ssi_ctx_t context;
277 int ret;
278
279 t.input = expr;
280 t.offset = 0;
281 t.size = strlen(expr);
282 t.line_pos = 1;
283
284 t.in_key = 1;
285 t.in_brace = 0;
286 t.in_cond = 0;
287
288 context.ok = 1;
289 context.srv = srv;
290
291 /* default context */
292
293 pParser = ssiexprparserAlloc( malloc );
294 token = buffer_init();
295 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
296 ssiexprparser(pParser, token_id, token, &context);
297
298 token = buffer_init();
299 }
300 ssiexprparser(pParser, 0, token, &context);
301 ssiexprparserFree(pParser, free );
302
303 buffer_free(token);
304
305 if (ret == -1) {
306 log_error_write(srv, __FILE__, __LINE__, "s",
307 "expr parser failed");
308 return -1;
309 }
310
311 if (context.ok == 0) {
312 log_error_write(srv, __FILE__, __LINE__, "sds",
313 "pos:", t.line_pos,
314 "parser failed somehow near here");
315 return -1;
316 }
317 #if 0
318 log_error_write(srv, __FILE__, __LINE__, "ssd",
319 "expr: ",
320 expr,
321 context.val.bo);
322 #endif
323 return context.val.bo;
324 }
325