reset response headers, write_queue for error docs
[lighttpd.git] / src / configparser.y
blob99e20a78db879a4c6297370a98171ffaed74cc45
1 %token_prefix TK_
2 %extra_argument {config_t *ctx}
3 %name configparser
5 %include {
6 #include "first.h"
7 #include "configfile.h"
8 #include "buffer.h"
9 #include "array.h"
11 #include <assert.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <stdio.h>
15 #include <string.h>
17 static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
18 if (isnew) {
19 dc->context_ndx = ctx->all_configs->used;
20 force_assert(dc->context_ndx > ctx->current->context_ndx);
21 array_insert_unique(ctx->all_configs, (data_unset *)dc);
22 dc->parent = ctx->current;
23 vector_config_weak_push(&dc->parent->children, dc);
25 if (ctx->configs_stack.used > 0 && ctx->current->context_ndx == 0) {
26 fprintf(stderr, "Cannot use conditionals inside a global { ... } block\n");
27 exit(-1);
29 vector_config_weak_push(&ctx->configs_stack, ctx->current);
30 ctx->current = dc;
33 static data_config *configparser_pop(config_t *ctx) {
34 data_config *old = ctx->current;
35 ctx->current = vector_config_weak_pop(&ctx->configs_stack);
36 return old;
39 /* return a copied variable */
40 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
41 data_unset *du;
42 data_config *dc;
44 #if 0
45 fprintf(stderr, "get var %s\n", key->ptr);
46 #endif
47 for (dc = ctx->current; dc; dc = dc->parent) {
48 #if 0
49 fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
50 array_print(dc->value, 0);
51 #endif
52 if (NULL != (du = array_get_element(dc->value, key->ptr))) {
53 return du->copy(du);
56 return NULL;
59 /* op1 is to be eat/return by this function if success, op1->key is not cared
60 op2 is left untouch, unreferenced
62 data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) {
63 /* type mismatch */
64 if (op1->type != op2->type) {
65 if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
66 data_string *ds = (data_string *)op1;
67 buffer_append_int(ds->value, ((data_integer*)op2)->value);
68 return op1;
69 } else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
70 data_string *ds = data_string_init();
71 buffer_append_int(ds->value, ((data_integer*)op1)->value);
72 buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
73 op1->free(op1);
74 return (data_unset *)ds;
75 } else {
76 fprintf(stderr, "data type mismatch, cannot merge\n");
77 op1->free(op1);
78 return NULL;
82 switch (op1->type) {
83 case TYPE_STRING:
84 buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
85 break;
86 case TYPE_INTEGER:
87 ((data_integer *)op1)->value += ((data_integer *)op2)->value;
88 break;
89 case TYPE_ARRAY: {
90 array *dst = ((data_array *)op1)->value;
91 array *src = ((data_array *)op2)->value;
92 data_unset *du;
93 size_t i;
95 for (i = 0; i < src->used; i ++) {
96 du = (data_unset *)src->data[i];
97 if (du) {
98 if (du->is_index_key || buffer_is_empty(du->key) || !array_get_element(dst, du->key->ptr)) {
99 array_insert_unique(dst, du->copy(du));
100 } else {
101 fprintf(stderr, "Duplicate array-key '%s'\n", du->key->ptr);
102 op1->free(op1);
103 return NULL;
107 break;
108 default:
109 force_assert(0);
110 break;
113 return op1;
118 %parse_failure {
119 ctx->ok = 0;
122 input ::= metalines.
123 metalines ::= metalines metaline.
124 metalines ::= .
125 metaline ::= varline.
126 metaline ::= global.
127 metaline ::= condlines(A) EOL. { A = NULL; }
128 metaline ::= include.
129 metaline ::= include_shell.
130 metaline ::= EOL.
132 %type value {data_unset *}
133 %type expression {data_unset *}
134 %type aelement {data_unset *}
135 %type condline {data_config *}
136 %type condlines {data_config *}
137 %type aelements {array *}
138 %type array {array *}
139 %type key {buffer *}
140 %type stringop {buffer *}
142 %type cond {config_cond_t }
144 %destructor value { if ($$) $$->free($$); }
145 %destructor expression { if ($$) $$->free($$); }
146 %destructor aelement { if ($$) $$->free($$); }
147 %destructor aelements { array_free($$); }
148 %destructor array { array_free($$); }
149 %destructor key { buffer_free($$); }
150 %destructor stringop { buffer_free($$); }
152 %token_type {buffer *}
153 %token_destructor { buffer_free($$); }
155 varline ::= key(A) ASSIGN expression(B). {
156 if (ctx->ok) {
157 buffer_copy_buffer(B->key, A);
158 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
159 fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
160 ctx->current->context_ndx,
161 ctx->current->key->ptr, A->ptr);
162 ctx->ok = 0;
163 } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
164 array_insert_unique(ctx->current->value, B);
165 B = NULL;
166 } else {
167 fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
168 ctx->current->context_ndx,
169 ctx->current->key->ptr, B->key->ptr);
170 ctx->ok = 0;
171 B->free(B);
172 B = NULL;
175 buffer_free(A);
176 A = NULL;
179 varline ::= key(A) APPEND expression(B). {
180 if (ctx->ok) {
181 array *vars = ctx->current->value;
182 data_unset *du;
184 if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
185 fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
186 ctx->current->context_ndx,
187 ctx->current->key->ptr, A->ptr);
188 ctx->ok = 0;
189 } else if (NULL != (du = array_extract_element(vars, A->ptr)) || NULL != (du = configparser_get_variable(ctx, A))) {
190 du = configparser_merge_data(du, B);
191 if (NULL == du) {
192 ctx->ok = 0;
194 else {
195 buffer_copy_buffer(du->key, A);
196 array_insert_unique(ctx->current->value, du);
198 B->free(B);
199 } else {
200 buffer_copy_buffer(B->key, A);
201 array_insert_unique(ctx->current->value, B);
203 buffer_free(A);
204 A = NULL;
205 B = NULL;
209 key(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;
221 expression(A) ::= expression(B) PLUS value(C). {
222 A = NULL;
223 if (ctx->ok) {
224 A = configparser_merge_data(B, C);
225 if (NULL == A) {
226 ctx->ok = 0;
228 B = NULL;
229 C->free(C);
230 C = NULL;
234 expression(A) ::= value(B). {
235 A = B;
236 B = NULL;
239 value(A) ::= key(B). {
240 A = NULL;
241 if (ctx->ok) {
242 if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
243 char *env;
245 if (NULL != (env = getenv(B->ptr + 4))) {
246 data_string *ds;
247 ds = data_string_init();
248 buffer_append_string(ds->value, env);
249 A = (data_unset *)ds;
251 else {
252 fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
253 ctx->ok = 0;
255 } else if (NULL == (A = configparser_get_variable(ctx, B))) {
256 fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
257 ctx->ok = 0;
259 buffer_free(B);
260 B = NULL;
264 value(A) ::= STRING(B). {
265 A = (data_unset *)data_string_init();
266 buffer_copy_buffer(((data_string *)(A))->value, B);
267 buffer_free(B);
268 B = NULL;
271 value(A) ::= INTEGER(B). {
272 char *endptr;
273 A = (data_unset *)data_integer_init();
274 errno = 0;
275 ((data_integer *)(A))->value = strtol(B->ptr, &endptr, 10);
276 /* skip trailing whitespace */
277 if (endptr != B->ptr) while (isspace(*endptr)) endptr++;
278 if (0 != errno || *endptr != '\0') {
279 fprintf(stderr, "error parsing number: '%s'\n", B->ptr);
280 ctx->ok = 0;
282 buffer_free(B);
283 B = NULL;
285 value(A) ::= array(B). {
286 A = (data_unset *)data_array_init();
287 array_free(((data_array *)(A))->value);
288 ((data_array *)(A))->value = B;
289 B = NULL;
291 array(A) ::= LPARAN RPARAN. {
292 A = array_init();
294 array(A) ::= LPARAN aelements(B) RPARAN. {
295 A = B;
296 B = NULL;
299 aelements(A) ::= aelements(C) COMMA aelement(B). {
300 A = NULL;
301 if (ctx->ok) {
302 if (buffer_is_empty(B->key) ||
303 NULL == array_get_element(C, B->key->ptr)) {
304 array_insert_unique(C, B);
305 B = NULL;
306 } else {
307 fprintf(stderr, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
308 B->key->ptr);
309 ctx->ok = 0;
310 B->free(B);
311 B = NULL;
314 A = C;
315 C = NULL;
319 aelements(A) ::= aelements(C) COMMA. {
320 A = C;
321 C = NULL;
324 aelements(A) ::= aelement(B). {
325 A = NULL;
326 if (ctx->ok) {
327 A = array_init();
328 array_insert_unique(A, B);
329 B = NULL;
333 aelement(A) ::= expression(B). {
334 A = B;
335 B = NULL;
337 aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). {
338 A = NULL;
339 if (ctx->ok) {
340 buffer_copy_buffer(C->key, B);
341 buffer_free(B);
342 B = NULL;
344 A = C;
345 C = NULL;
349 eols ::= EOL.
350 eols ::= .
352 globalstart ::= GLOBAL. {
353 data_config *dc;
354 dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
355 force_assert(dc);
356 configparser_push(ctx, dc, 0);
359 global ::= globalstart LCURLY metalines RCURLY. {
360 force_assert(ctx->current);
361 configparser_pop(ctx);
362 force_assert(ctx->current);
365 condlines(A) ::= condlines(B) eols ELSE condline(C). {
366 A = NULL;
367 if (ctx->ok) {
368 if (B->context_ndx >= C->context_ndx) {
369 fprintf(stderr, "unreachable else condition\n");
370 ctx->ok = 0;
372 C->prev = B;
373 B->next = C;
374 A = C;
375 B = NULL;
376 C = NULL;
380 condlines(A) ::= condline(B). {
381 A = B;
382 B = NULL;
385 condline(A) ::= context LCURLY metalines RCURLY. {
386 A = NULL;
387 if (ctx->ok) {
388 data_config *cur;
390 cur = ctx->current;
391 configparser_pop(ctx);
393 force_assert(cur && ctx->current);
395 A = cur;
399 context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expression(D). {
400 data_config *dc;
401 buffer *b, *rvalue, *op;
403 if (ctx->ok && D->type != TYPE_STRING) {
404 fprintf(stderr, "rvalue must be string");
405 ctx->ok = 0;
408 if (ctx->ok) {
409 switch(E) {
410 case CONFIG_COND_NE:
411 op = buffer_init_string("!=");
412 break;
413 case CONFIG_COND_EQ:
414 op = buffer_init_string("==");
415 break;
416 case CONFIG_COND_NOMATCH:
417 op = buffer_init_string("!~");
418 break;
419 case CONFIG_COND_MATCH:
420 op = buffer_init_string("=~");
421 break;
422 default:
423 force_assert(0);
424 return; /* unreachable */
427 b = buffer_init();
428 buffer_copy_buffer(b, ctx->current->key);
429 buffer_append_string(b, "/");
430 buffer_append_string_buffer(b, B);
431 buffer_append_string_buffer(b, C);
432 buffer_append_string_buffer(b, op);
433 rvalue = ((data_string*)D)->value;
434 buffer_append_string_buffer(b, rvalue);
436 if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
437 configparser_push(ctx, dc, 0);
438 } else {
439 static const struct {
440 comp_key_t comp;
441 char *comp_key;
442 size_t len;
443 } comps[] = {
444 { COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
445 { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
446 { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
447 { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
448 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
449 { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) },
450 { COMP_HTTP_LANGUAGE, CONST_STR_LEN("HTTP[\"language\"]" ) },
451 { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
452 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
453 { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) },
454 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") },
455 { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") },
456 { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
457 { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) },
458 { COMP_UNSET, NULL, 0 },
460 size_t i;
462 dc = data_config_init();
464 buffer_copy_buffer(dc->key, b);
465 buffer_copy_buffer(dc->op, op);
466 buffer_copy_buffer(dc->comp_key, B);
467 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
468 buffer_append_string_buffer(dc->comp_key, C);
469 buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
470 dc->cond = E;
472 for (i = 0; comps[i].comp_key; i ++) {
473 if (buffer_is_equal_string(
474 dc->comp_key, comps[i].comp_key, comps[i].len)) {
475 dc->comp = comps[i].comp;
476 break;
479 if (COMP_UNSET == dc->comp) {
480 fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
481 ctx->ok = 0;
483 else switch(E) {
484 case CONFIG_COND_NE:
485 case CONFIG_COND_EQ:
486 dc->string = buffer_init_buffer(rvalue);
487 break;
488 case CONFIG_COND_NOMATCH:
489 case CONFIG_COND_MATCH: {
490 #ifdef HAVE_PCRE_H
491 const char *errptr;
492 int erroff, captures;
494 if (NULL == (dc->regex =
495 pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
496 dc->string = buffer_init_string(errptr);
497 dc->cond = CONFIG_COND_UNSET;
499 fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
500 rvalue->ptr, errptr, erroff);
502 ctx->ok = 0;
503 } else if (NULL == (dc->regex_study =
504 pcre_study(dc->regex, 0, &errptr)) &&
505 errptr != NULL) {
506 fprintf(stderr, "studying regex failed: %s -> %s\n",
507 rvalue->ptr, errptr);
508 ctx->ok = 0;
509 } else if (0 != (pcre_fullinfo(dc->regex, dc->regex_study, PCRE_INFO_CAPTURECOUNT, &captures))) {
510 fprintf(stderr, "getting capture count for regex failed: %s\n",
511 rvalue->ptr);
512 ctx->ok = 0;
513 } else if (captures > 9) {
514 fprintf(stderr, "Too many captures in regex, use (?:...) instead of (...): %s\n",
515 rvalue->ptr);
516 ctx->ok = 0;
517 } else {
518 dc->string = buffer_init_buffer(rvalue);
520 #else
521 fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
522 "(perhaps just a missing pcre-devel package ?) \n",
523 B->ptr, C->ptr);
524 ctx->ok = 0;
525 #endif
526 break;
529 default:
530 fprintf(stderr, "unknown condition for $%s[%s]\n",
531 B->ptr, C->ptr);
532 ctx->ok = 0;
533 break;
536 if (ctx->ok) {
537 configparser_push(ctx, dc, 1);
538 } else {
539 dc->free((data_unset*) dc);
543 buffer_free(b);
544 buffer_free(op);
545 buffer_free(B);
546 B = NULL;
547 buffer_free(C);
548 C = NULL;
549 D->free(D);
550 D = NULL;
553 cond(A) ::= EQ. {
554 A = CONFIG_COND_EQ;
556 cond(A) ::= MATCH. {
557 A = CONFIG_COND_MATCH;
559 cond(A) ::= NE. {
560 A = CONFIG_COND_NE;
562 cond(A) ::= NOMATCH. {
563 A = CONFIG_COND_NOMATCH;
566 stringop(A) ::= expression(B). {
567 A = NULL;
568 if (ctx->ok) {
569 if (B->type == TYPE_STRING) {
570 A = buffer_init_buffer(((data_string*)B)->value);
571 } else if (B->type == TYPE_INTEGER) {
572 A = buffer_init();
573 buffer_copy_int(A, ((data_integer *)B)->value);
574 } else {
575 fprintf(stderr, "operand must be string");
576 ctx->ok = 0;
579 B->free(B);
580 B = NULL;
583 include ::= INCLUDE stringop(A). {
584 if (ctx->ok) {
585 if (0 != config_parse_file(ctx->srv, ctx, A->ptr)) {
586 ctx->ok = 0;
588 buffer_free(A);
589 A = NULL;
593 include_shell ::= INCLUDE_SHELL stringop(A). {
594 if (ctx->ok) {
595 if (0 != config_parse_cmd(ctx->srv, ctx, A->ptr)) {
596 ctx->ok = 0;
598 buffer_free(A);
599 A = NULL;