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 10typedef 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 22ssi_val_t *ssi_val_init(void) { 23 ssi_val_t *s; 24 25 s = calloc(1, sizeof(*s)); 26 27 return s; 28} 29 30void ssi_val_free(ssi_val_t *s) { 31 if (s->str) buffer_free(s->str); 32 33 free(s); 34} 35 36int ssi_val_tobool(ssi_val_t *B) { 37 if (B->type == SSI_TYPE_STRING) { 38 return !buffer_string_is_empty(B->str); 39 } else { 40 return B->bo; 41 } 42} 43 44static 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_buffer(token, ds->value); 219 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) { 220 buffer_copy_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 271int 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 force_assert(pParser); 295 token = buffer_init(); 296 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) { 297 ssiexprparser(pParser, token_id, token, &context); 298 299 token = buffer_init(); 300 } 301 ssiexprparser(pParser, 0, token, &context); 302 ssiexprparserFree(pParser, free ); 303 304 buffer_free(token); 305 306 if (ret == -1) { 307 log_error_write(srv, __FILE__, __LINE__, "s", 308 "expr parser failed"); 309 return -1; 310 } 311 312 if (context.ok == 0) { 313 log_error_write(srv, __FILE__, __LINE__, "sds", 314 "pos:", t.line_pos, 315 "parser failed somehow near here"); 316 return -1; 317 } 318#if 0 319 log_error_write(srv, __FILE__, __LINE__, "ssd", 320 "expr: ", 321 expr, 322 context.val.bo); 323#endif 324 return context.val.bo; 325} 326