• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/lighttpd-1.4.39/src/
1%token_prefix TK_
2%extra_argument {config_t *ctx}
3%name configparser
4
5%include {
6#include "configfile.h"
7#include "buffer.h"
8#include "array.h"
9
10#include <assert.h>
11#include <stdio.h>
12#include <string.h>
13
14static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
15  if (isnew) {
16    dc->context_ndx = ctx->all_configs->used;
17    force_assert(dc->context_ndx > ctx->current->context_ndx);
18    array_insert_unique(ctx->all_configs, (data_unset *)dc);
19    dc->parent = ctx->current;
20    array_insert_unique(dc->parent->childs, (data_unset *)dc);
21  }
22  if (ctx->configs_stack->used > 0 && ctx->current->context_ndx == 0) {
23    fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
24    exit(-1);
25  }
26  array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
27  ctx->current = dc;
28}
29
30static data_config *configparser_pop(config_t *ctx) {
31  data_config *old = ctx->current;
32  ctx->current = (data_config *) array_pop(ctx->configs_stack);
33  return old;
34}
35
36/* return a copied variable */
37static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
38  data_unset *du;
39  data_config *dc;
40
41#if 0
42  fprintf(stderr, "get var %s\n", key->ptr);
43#endif
44  for (dc = ctx->current; dc; dc = dc->parent) {
45#if 0
46    fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
47    array_print(dc->value, 0);
48#endif
49    if (NULL != (du = array_get_element(dc->value, key->ptr))) {
50      return du->copy(du);
51    }
52  }
53  return NULL;
54}
55
56/* op1 is to be eat/return by this function if success, op1->key is not cared
57   op2 is left untouch, unreferenced
58 */
59data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
60  /* type mismatch */
61  if (op1->type != op2->type) {
62    if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
63      data_string *ds = (data_string *)op1;
64      buffer_append_int(ds->value, ((data_integer*)op2)->value);
65      return op1;
66    } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
67      data_string *ds = data_string_init();
68      buffer_append_int(ds->value, ((data_integer*)op1)->value);
69      buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
70      op1->free(op1);
71      return (data_unset *)ds;
72    } else {
73      fprintf(stderr, "data type mismatch, cannot merge\n");
74      return NULL;
75    }
76  }
77
78  switch (op1->type) {
79    case TYPE_STRING:
80      buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
81      break;
82    case TYPE_INTEGER:
83      ((data_integer *)op1)->value += ((data_integer *)op2)->value;
84      break;
85    case TYPE_ARRAY: {
86      array *dst = ((data_array *)op1)->value;
87      array *src = ((data_array *)op2)->value;
88      data_unset *du;
89      size_t i;
90
91      for (i = 0; i < src->used; i ++) {
92        du = (data_unset *)src->data[i];
93        if (du) {
94          array_insert_unique(dst, du->copy(du));
95        }
96      }
97      break;
98    default:
99      force_assert(0);
100      break;
101    }
102  }
103  return op1;
104}
105
106}
107
108%parse_failure {
109  ctx->ok = 0;
110}
111
112input ::= metalines.
113metalines ::= metalines metaline.
114metalines ::= .
115metaline ::= varline.
116metaline ::= global.
117metaline ::= condlines(A) EOL. { A = NULL; }
118metaline ::= include.
119metaline ::= include_shell.
120metaline ::= EOL.
121
122%type       value                  {data_unset *}
123%type       expression             {data_unset *}
124%type       aelement               {data_unset *}
125%type       condline               {data_config *}
126%type       condlines              {data_config *}
127%type       global                 {data_config *}
128%type       aelements              {array *}
129%type       array                  {array *}
130%type       key                    {buffer *}
131%type       stringop               {buffer *}
132
133%type       cond                   {config_cond_t }
134
135%destructor value                  { $$->free($$); }
136%destructor expression             { $$->free($$); }
137%destructor aelement               { $$->free($$); }
138%destructor aelements              { array_free($$); }
139%destructor array                  { array_free($$); }
140%destructor key                    { buffer_free($$); }
141%destructor stringop               { buffer_free($$); }
142
143%token_type                        {buffer *}
144%token_destructor                  { buffer_free($$); }
145
146varline ::= key(A) ASSIGN expression(B). {
147  if (ctx->ok) {
148    buffer_copy_buffer(B->key, A);
149    if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
150      fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
151          ctx->current->context_ndx,
152          ctx->current->key->ptr, A->ptr);
153      ctx->ok = 0;
154    } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
155      array_insert_unique(ctx->current->value, B);
156      B = NULL;
157    } else {
158      fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
159              ctx->current->context_ndx,
160              ctx->current->key->ptr, B->key->ptr);
161      ctx->ok = 0;
162      B->free(B);
163      B = NULL;
164    }
165  }
166  buffer_free(A);
167  A = NULL;
168}
169
170varline ::= key(A) APPEND expression(B). {
171  array *vars = ctx->current->value;
172  data_unset *du;
173
174  if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
175    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
176        ctx->current->context_ndx,
177        ctx->current->key->ptr, A->ptr);
178    ctx->ok = 0;
179  } else if (NULL != (du = array_get_element(vars, A->ptr))) {
180    /* exists in current block */
181    du = configparser_merge_data(du, B);
182    if (NULL == du) {
183      ctx->ok = 0;
184    }
185    else {
186      buffer_copy_buffer(du->key, A);
187      array_replace(vars, du);
188    }
189    B->free(B);
190  } else if (NULL != (du = configparser_get_variable(ctx, A))) {
191    du = configparser_merge_data(du, B);
192    if (NULL == du) {
193      ctx->ok = 0;
194    }
195    else {
196      buffer_copy_buffer(du->key, A);
197      array_insert_unique(ctx->current->value, du);
198    }
199    B->free(B);
200  } else {
201    buffer_copy_buffer(B->key, A);
202    array_insert_unique(ctx->current->value, B);
203  }
204  buffer_free(A);
205  A = NULL;
206  B = NULL;
207}
208
209key(A) ::= LKEY(B). {
210  if (strchr(B->ptr, '.') == NULL) {
211    A = buffer_init_string("var.");
212    buffer_append_string_buffer(A, B);
213    buffer_free(B);
214    B = NULL;
215  } else {
216    A = B;
217    B = NULL;
218  }
219}
220
221expression(A) ::= expression(B) PLUS value(C). {
222  A = configparser_merge_data(B, C);
223  if (NULL == A) {
224    ctx->ok = 0;
225  }
226  B = NULL;
227  C->free(C);
228  C = NULL;
229}
230
231expression(A) ::= value(B). {
232  A = B;
233  B = NULL;
234}
235
236value(A) ::= key(B). {
237  A = NULL;
238  if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
239    char *env;
240
241    if (NULL != (env = getenv(B->ptr + 4))) {
242      data_string *ds;
243      ds = data_string_init();
244      buffer_append_string(ds->value, env);
245      A = (data_unset *)ds;
246    }
247    else {
248      fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
249      ctx->ok = 0;
250    }
251  } else if (NULL == (A = configparser_get_variable(ctx, B))) {
252    fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
253    ctx->ok = 0;
254  }
255  if (!A) {
256    /* make a dummy so it won't crash */
257    A = (data_unset *)data_string_init();
258  }
259  buffer_free(B);
260  B = NULL;
261}
262
263value(A) ::= STRING(B). {
264  A = (data_unset *)data_string_init();
265  buffer_copy_buffer(((data_string *)(A))->value, B);
266  buffer_free(B);
267  B = NULL;
268}
269
270value(A) ::= INTEGER(B). {
271  A = (data_unset *)data_integer_init();
272  ((data_integer *)(A))->value = strtol(B->ptr, NULL, 10);
273  buffer_free(B);
274  B = NULL;
275}
276value(A) ::= array(B). {
277  A = (data_unset *)data_array_init();
278  array_free(((data_array *)(A))->value);
279  ((data_array *)(A))->value = B;
280  B = NULL;
281}
282array(A) ::= LPARAN RPARAN. {
283  A = array_init();
284}
285array(A) ::= LPARAN aelements(B) RPARAN. {
286  A = B;
287  B = NULL;
288}
289
290aelements(A) ::= aelements(C) COMMA aelement(B). {
291  if (buffer_is_empty(B->key) ||
292      NULL == array_get_element(C, B->key->ptr)) {
293    array_insert_unique(C, B);
294    B = NULL;
295  } else {
296    fprintf(stderr, "Duplicate array-key: %s\n",
297            B->key->ptr);
298    ctx->ok = 0;
299    B->free(B);
300    B = NULL;
301  }
302
303  A = C;
304  C = NULL;
305}
306
307aelements(A) ::= aelements(C) COMMA. {
308  A = C;
309  C = NULL;
310}
311
312aelements(A) ::= aelement(B). {
313  A = array_init();
314  array_insert_unique(A, B);
315  B = NULL;
316}
317
318aelement(A) ::= expression(B). {
319  A = B;
320  B = NULL;
321}
322aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
323  buffer_copy_buffer(C->key, B);
324  buffer_free(B);
325  B = NULL;
326
327  A = C;
328  C = NULL;
329}
330
331eols ::= EOL.
332eols ::= .
333
334globalstart ::= GLOBAL. {
335  data_config *dc;
336  dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
337  force_assert(dc);
338  configparser_push(ctx, dc, 0);
339}
340
341global(A) ::= globalstart LCURLY metalines RCURLY. {
342  data_config *cur;
343
344  cur = ctx->current;
345  configparser_pop(ctx);
346
347  force_assert(cur && ctx->current);
348
349  A = cur;
350}
351
352condlines(A) ::= condlines(B) eols ELSE condline(C). {
353  if (B->context_ndx >= C->context_ndx) {
354    fprintf(stderr, "unreachable else condition\n");
355    ctx->ok = 0;
356  }
357  C->prev = B;
358  B->next = C;
359  A = C;
360  B = NULL;
361  C = NULL;
362}
363
364condlines(A) ::= condline(B). {
365  A = B;
366  B = NULL;
367}
368
369condline(A) ::= context LCURLY metalines RCURLY. {
370  data_config *cur;
371
372  cur = ctx->current;
373  configparser_pop(ctx);
374
375  force_assert(cur && ctx->current);
376
377  A = cur;
378}
379
380context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
381  data_config *dc;
382  buffer *b, *rvalue, *op;
383
384  if (ctx->ok && D->type != TYPE_STRING) {
385    fprintf(stderr, "rvalue must be string");
386    ctx->ok = 0;
387  }
388
389  switch(E) {
390  case CONFIG_COND_NE:
391    op = buffer_init_string("!=");
392    break;
393  case CONFIG_COND_EQ:
394    op = buffer_init_string("==");
395    break;
396  case CONFIG_COND_NOMATCH:
397    op = buffer_init_string("!~");
398    break;
399  case CONFIG_COND_MATCH:
400    op = buffer_init_string("=~");
401    break;
402  default:
403    force_assert(0);
404    return;
405  }
406
407  b = buffer_init();
408  buffer_copy_buffer(b, ctx->current->key);
409  buffer_append_string(b, "/");
410  buffer_append_string_buffer(b, B);
411  buffer_append_string_buffer(b, C);
412  buffer_append_string_buffer(b, op);
413  rvalue = ((data_string*)D)->value;
414  buffer_append_string_buffer(b, rvalue);
415
416  if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
417    configparser_push(ctx, dc, 0);
418  } else {
419    struct {
420      comp_key_t comp;
421      char *comp_key;
422      size_t len;
423    } comps[] = {
424      { COMP_SERVER_SOCKET,      CONST_STR_LEN("SERVER[\"socket\"]"   ) },
425      { COMP_HTTP_URL,           CONST_STR_LEN("HTTP[\"url\"]"        ) },
426      { COMP_HTTP_HOST,          CONST_STR_LEN("HTTP[\"host\"]"       ) },
427      { COMP_HTTP_REFERER,       CONST_STR_LEN("HTTP[\"referer\"]"    ) },
428      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
429      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"user-agent\"]"  ) },
430      { COMP_HTTP_LANGUAGE,      CONST_STR_LEN("HTTP[\"language\"]"   ) },
431      { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
432      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
433      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remote-ip\"]"   ) },
434      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"querystring\"]") },
435      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"query-string\"]") },
436      { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
437      { COMP_HTTP_SCHEME,        CONST_STR_LEN("HTTP[\"scheme\"]"     ) },
438      { COMP_UNSET, NULL, 0 },
439    };
440    size_t i;
441
442    dc = data_config_init();
443
444    buffer_copy_buffer(dc->key, b);
445    buffer_copy_buffer(dc->op, op);
446    buffer_copy_buffer(dc->comp_key, B);
447    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
448    buffer_append_string_buffer(dc->comp_key, C);
449    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
450    dc->cond = E;
451
452    for (i = 0; comps[i].comp_key; i ++) {
453      if (buffer_is_equal_string(
454            dc->comp_key, comps[i].comp_key, comps[i].len)) {
455        dc->comp = comps[i].comp;
456        break;
457      }
458    }
459    if (COMP_UNSET == dc->comp) {
460      fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
461      ctx->ok = 0;
462    }
463
464    switch(E) {
465    case CONFIG_COND_NE:
466    case CONFIG_COND_EQ:
467      dc->string = buffer_init_buffer(rvalue);
468      break;
469    case CONFIG_COND_NOMATCH:
470    case CONFIG_COND_MATCH: {
471#ifdef HAVE_PCRE_H
472      const char *errptr;
473      int erroff, captures;
474
475      if (NULL == (dc->regex =
476          pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
477        dc->string = buffer_init_string(errptr);
478        dc->cond = CONFIG_COND_UNSET;
479
480        fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
481            rvalue->ptr, errptr, erroff);
482
483        ctx->ok = 0;
484      } else if (NULL == (dc->regex_study =
485          pcre_study(dc->regex, 0, &errptr)) &&
486                 errptr != NULL) {
487        fprintf(stderr, "studying regex failed: %s -> %s\n",
488            rvalue->ptr, errptr);
489        ctx->ok = 0;
490      } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) {
491        fprintf(stderr, "getting capture count for regex failed: %s\n",
492            rvalue->ptr);
493        ctx->ok = 0;
494      } else if (captures > 9) {
495        fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
496            rvalue->ptr);
497        ctx->ok = 0;
498      } else {
499        dc->string = buffer_init_buffer(rvalue);
500      }
501#else
502      fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
503		      "(perhaps just a missing pcre-devel package ?) \n",
504                      B->ptr, C->ptr);
505      ctx->ok = 0;
506#endif
507      break;
508    }
509
510    default:
511      fprintf(stderr, "unknown condition for $%s[%s]\n",
512                      B->ptr, C->ptr);
513      ctx->ok = 0;
514      break;
515    }
516
517    configparser_push(ctx, dc, 1);
518  }
519
520  buffer_free(b);
521  buffer_free(op);
522  buffer_free(B);
523  B = NULL;
524  buffer_free(C);
525  C = NULL;
526  D->free(D);
527  D = NULL;
528}
529cond(A) ::= EQ. {
530  A = CONFIG_COND_EQ;
531}
532cond(A) ::= MATCH. {
533  A = CONFIG_COND_MATCH;
534}
535cond(A) ::= NE. {
536  A = CONFIG_COND_NE;
537}
538cond(A) ::= NOMATCH. {
539  A = CONFIG_COND_NOMATCH;
540}
541
542stringop(A) ::= expression(B). {
543  A = NULL;
544  if (ctx->ok) {
545    if (B->type == TYPE_STRING) {
546      A = buffer_init_buffer(((data_string*)B)->value);
547    } else if (B->type == TYPE_INTEGER) {
548      A = buffer_init();
549      buffer_copy_int(A, ((data_integer *)B)->value);
550    } else {
551      fprintf(stderr, "operand must be string");
552      ctx->ok = 0;
553    }
554  }
555  B->free(B);
556  B = NULL;
557}
558
559include ::= INCLUDE stringop(A). {
560  if (ctx->ok) {
561    if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
562      ctx->ok = 0;
563    }
564    buffer_free(A);
565    A = NULL;
566  }
567}
568
569include_shell ::= INCLUDE_SHELL stringop(A). {
570  if (ctx->ok) {
571    if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
572      ctx->ok = 0;
573    }
574    buffer_free(A);
575    A = NULL;
576  }
577}
578