2 %extra_argument
{config_t
*ctx
}
7 #include "configfile.h"
10 #include "request.h" /* http_request_host_normalize() */
18 static void configparser_push
(config_t
*ctx
, data_config
*dc
, int isnew
) {
20 dc
->context_ndx
= ctx
->all_configs
->used
;
21 force_assert
(dc
->context_ndx
> ctx
->current
->context_ndx
);
22 array_insert_unique
(ctx
->all_configs
, (data_unset
*)dc
);
23 dc
->parent
= ctx
->current
;
24 vector_config_weak_push
(&dc
->parent
->children
, dc
);
26 if
(ctx
->configs_stack.used
> 0 && ctx
->current
->context_ndx
== 0) {
27 fprintf
(stderr
, "Cannot use conditionals inside a global { ... } block\n");
30 vector_config_weak_push
(&ctx
->configs_stack
, ctx
->current
);
34 static data_config
*configparser_pop
(config_t
*ctx
) {
35 data_config
*old
= ctx
->current
;
36 ctx
->current
= vector_config_weak_pop
(&ctx
->configs_stack
);
40 /* return a copied variable */
41 static data_unset
*configparser_get_variable
(config_t
*ctx
, const buffer
*key
) {
46 fprintf
(stderr
, "get var %s\n", key
->ptr
);
48 for
(dc
= ctx
->current
; dc
; dc
= dc
->parent
) {
50 fprintf
(stderr
, "get var on block: %s\n", dc
->key
->ptr
);
51 array_print
(dc
->value
, 0);
53 if
(NULL
!= (du
= array_get_element
(dc
->value
, key
->ptr
))) {
60 /* op1 is to be eat/return by this function if success, op1->key is not cared
61 op2 is left untouch, unreferenced
63 data_unset
*configparser_merge_data
(data_unset
*op1
, const data_unset
*op2
) {
65 if
(op1
->type
!= op2
->type
) {
66 if
(op1
->type
== TYPE_STRING
&& op2
->type
== TYPE_INTEGER
) {
67 data_string
*ds
= (data_string
*)op1
;
68 buffer_append_int
(ds
->value
, ((data_integer
*)op2
)->value
);
70 } else if
(op1
->type
== TYPE_INTEGER
&& op2
->type
== TYPE_STRING
) {
71 data_string
*ds
= data_string_init
();
72 buffer_append_int
(ds
->value
, ((data_integer
*)op1
)->value
);
73 buffer_append_string_buffer
(ds
->value
, ((data_string
*)op2
)->value
);
75 return
(data_unset
*)ds
;
77 fprintf
(stderr
, "data type mismatch, cannot merge\n");
85 buffer_append_string_buffer
(((data_string
*)op1
)->value
, ((data_string
*)op2
)->value
);
88 ((data_integer
*)op1
)->value
+= ((data_integer
*)op2
)->value
;
91 array
*dst
= ((data_array
*)op1
)->value
;
92 array
*src
= ((data_array
*)op2
)->value
;
96 for
(i
= 0; i
< src
->used
; i
++) {
97 du
= (data_unset
*)src
->data
[i
];
99 if
(du
->is_index_key || buffer_is_empty
(du
->key
) ||
!array_get_element
(dst
, du
->key
->ptr
)) {
100 array_insert_unique
(dst
, du
->copy
(du
));
102 fprintf
(stderr
, "Duplicate array-key '%s'\n", du
->key
->ptr
);
124 metalines
::= metalines metaline.
126 metaline
::= varline.
128 metaline
::= condlines
(A
) EOL.
{ A
= NULL
; }
129 metaline
::= include.
130 metaline
::= include_shell.
133 %type value
{data_unset
*}
134 %type expression
{data_unset
*}
135 %type aelement
{data_unset
*}
136 %type condline
{data_config
*}
137 %type condlines
{data_config
*}
138 %type aelements
{array
*}
139 %type array
{array
*}
141 %type stringop
{buffer
*}
143 %type cond
{config_cond_t
}
145 %destructor value
{ if
($$
) $$
->free
($$
); }
146 %destructor expression
{ if
($$
) $$
->free
($$
); }
147 %destructor aelement
{ if
($$
) $$
->free
($$
); }
148 %destructor aelements
{ array_free
($$
); }
149 %destructor array
{ array_free
($$
); }
150 %destructor key
{ buffer_free
($$
); }
151 %destructor stringop
{ buffer_free
($$
); }
153 %token_type
{buffer
*}
154 %token_destructor
{ buffer_free
($$
); }
156 varline
::= key
(A
) ASSIGN expression
(B
).
{
158 buffer_copy_buffer
(B
->key
, A
);
159 if
(strncmp
(A
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
160 fprintf
(stderr
, "Setting env variable is not supported in conditional %d %s: %s\n",
161 ctx
->current
->context_ndx
,
162 ctx
->current
->key
->ptr
, A
->ptr
);
164 } else if
(NULL
== array_get_element
(ctx
->current
->value
, B
->key
->ptr
)) {
165 array_insert_unique
(ctx
->current
->value
, B
);
168 fprintf
(stderr
, "Duplicate config variable in conditional %d %s: %s\n",
169 ctx
->current
->context_ndx
,
170 ctx
->current
->key
->ptr
, B
->key
->ptr
);
180 varline
::= key
(A
) APPEND expression
(B
).
{
182 array
*vars
= ctx
->current
->value
;
185 if
(strncmp
(A
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
186 fprintf
(stderr
, "Appending env variable is not supported in conditional %d %s: %s\n",
187 ctx
->current
->context_ndx
,
188 ctx
->current
->key
->ptr
, A
->ptr
);
190 } else if
(NULL
!= (du
= array_extract_element
(vars
, A
->ptr
)) || NULL
!= (du
= configparser_get_variable
(ctx
, A
))) {
191 du
= configparser_merge_data
(du
, B
);
196 buffer_copy_buffer
(du
->key
, A
);
197 array_insert_unique
(ctx
->current
->value
, du
);
201 buffer_copy_buffer
(B
->key
, A
);
202 array_insert_unique
(ctx
->current
->value
, B
);
210 key
(A
) ::= LKEY
(B
).
{
211 if
(strchr
(B
->ptr
, '.') == NULL
) {
212 A
= buffer_init_string
("var.");
213 buffer_append_string_buffer
(A
, B
);
222 expression
(A
) ::= expression
(B
) PLUS value
(C
).
{
225 A
= configparser_merge_data
(B
, C
);
235 expression
(A
) ::= value
(B
).
{
240 value
(A
) ::= key
(B
).
{
243 if
(strncmp
(B
->ptr
, "env.", sizeof
("env.") - 1) == 0) {
246 if
(NULL
!= (env
= getenv
(B
->ptr
+ 4))) {
248 ds
= data_string_init
();
249 buffer_append_string
(ds
->value
, env
);
250 A
= (data_unset
*)ds
;
253 fprintf
(stderr
, "Undefined env variable: %s\n", B
->ptr
+ 4);
256 } else if
(NULL
== (A
= configparser_get_variable
(ctx
, B
))) {
257 fprintf
(stderr
, "Undefined config variable: %s\n", B
->ptr
);
265 value
(A
) ::= STRING
(B
).
{
266 A
= (data_unset
*)data_string_init
();
267 buffer_copy_buffer
(((data_string
*)(A
))->value
, B
);
272 value
(A
) ::= INTEGER
(B
).
{
274 A
= (data_unset
*)data_integer_init
();
276 ((data_integer
*)(A
))->value
= strtol
(B
->ptr
, &endptr
, 10);
277 /* skip trailing whitespace */
278 if
(endptr
!= B
->ptr
) while
(isspace
(*endptr
)) endptr
++;
279 if
(0 != errno ||
*endptr
!= '\0') {
280 fprintf
(stderr
, "error parsing number: '%s'\n", B
->ptr
);
286 value
(A
) ::= array
(B
).
{
287 A
= (data_unset
*)data_array_init
();
288 array_free
(((data_array
*)(A
))->value
);
289 ((data_array
*)(A
))->value
= B
;
292 array
(A
) ::= LPARAN RPARAN.
{
295 array
(A
) ::= LPARAN aelements
(B
) RPARAN.
{
300 aelements
(A
) ::= aelements
(C
) COMMA aelement
(B
).
{
303 if
(buffer_is_empty
(B
->key
) ||
304 NULL
== array_get_element
(C
, B
->key
->ptr
)) {
305 array_insert_unique
(C
, B
);
308 fprintf
(stderr
, "Error: duplicate array-key: %s. Please get rid of the duplicate entry.\n",
320 aelements
(A
) ::= aelements
(C
) COMMA.
{
325 aelements
(A
) ::= aelement
(B
).
{
329 array_insert_unique
(A
, B
);
334 aelement
(A
) ::= expression
(B
).
{
338 aelement
(A
) ::= stringop
(B
) ARRAY_ASSIGN expression
(C
).
{
341 buffer_copy_buffer
(C
->key
, B
);
353 globalstart
::= GLOBAL.
{
355 dc
= (data_config
*)array_get_element
(ctx
->srv
->config_context
, "global");
357 configparser_push
(ctx
, dc
, 0);
360 global
::= globalstart LCURLY metalines RCURLY.
{
361 force_assert
(ctx
->current
);
362 configparser_pop
(ctx
);
363 force_assert
(ctx
->current
);
366 condlines
(A
) ::= condlines
(B
) eols ELSE condline
(C
).
{
369 if
(B
->context_ndx
>= C
->context_ndx
) {
370 fprintf
(stderr
, "unreachable else condition\n");
381 condlines
(A
) ::= condline
(B
).
{
386 condline
(A
) ::= context LCURLY metalines RCURLY.
{
392 configparser_pop
(ctx
);
394 force_assert
(cur
&& ctx
->current
);
400 context
::= DOLLAR SRVVARNAME
(B
) LBRACKET stringop
(C
) RBRACKET cond
(E
) expression
(D
).
{
402 buffer
*b
, *rvalue
, *op
;
404 if
(ctx
->ok
&& D
->type
!= TYPE_STRING
) {
405 fprintf
(stderr
, "rvalue must be string");
412 op
= buffer_init_string
("!=");
415 op
= buffer_init_string
("==");
417 case CONFIG_COND_NOMATCH
:
418 op
= buffer_init_string
("!~");
420 case CONFIG_COND_MATCH
:
421 op
= buffer_init_string
("=~");
425 return
; /* unreachable */
429 buffer_copy_buffer
(b
, ctx
->current
->key
);
430 buffer_append_string
(b
, "/");
431 buffer_append_string_buffer
(b
, B
);
432 buffer_append_string_buffer
(b
, C
);
433 buffer_append_string_buffer
(b
, op
);
434 rvalue
= ((data_string
*)D
)->value
;
435 buffer_append_string_buffer
(b
, rvalue
);
437 if
(NULL
!= (dc
= (data_config
*)array_get_element
(ctx
->all_configs
, b
->ptr
))) {
438 configparser_push
(ctx
, dc
, 0);
440 static const struct {
445 { COMP_SERVER_SOCKET
, CONST_STR_LEN
("SERVER[\"socket\"]" ) },
446 { COMP_HTTP_URL
, CONST_STR_LEN
("HTTP[\"url\"]" ) },
447 { COMP_HTTP_HOST
, CONST_STR_LEN
("HTTP[\"host\"]" ) },
448 { COMP_HTTP_REFERER
, CONST_STR_LEN
("HTTP[\"referer\"]" ) },
449 { COMP_HTTP_USER_AGENT
, CONST_STR_LEN
("HTTP[\"useragent\"]" ) },
450 { COMP_HTTP_USER_AGENT
, CONST_STR_LEN
("HTTP[\"user-agent\"]" ) },
451 { COMP_HTTP_LANGUAGE
, CONST_STR_LEN
("HTTP[\"language\"]" ) },
452 { COMP_HTTP_COOKIE
, CONST_STR_LEN
("HTTP[\"cookie\"]" ) },
453 { COMP_HTTP_REMOTE_IP
, CONST_STR_LEN
("HTTP[\"remoteip\"]" ) },
454 { COMP_HTTP_REMOTE_IP
, CONST_STR_LEN
("HTTP[\"remote-ip\"]" ) },
455 { COMP_HTTP_QUERY_STRING
, CONST_STR_LEN
("HTTP[\"querystring\"]") },
456 { COMP_HTTP_QUERY_STRING
, CONST_STR_LEN
("HTTP[\"query-string\"]") },
457 { COMP_HTTP_REQUEST_METHOD
, CONST_STR_LEN
("HTTP[\"request-method\"]") },
458 { COMP_HTTP_SCHEME
, CONST_STR_LEN
("HTTP[\"scheme\"]" ) },
459 { COMP_UNSET
, NULL
, 0 },
463 dc
= data_config_init
();
465 buffer_copy_buffer
(dc
->key
, b
);
466 buffer_copy_buffer
(dc
->op
, op
);
467 buffer_copy_buffer
(dc
->comp_key
, B
);
468 buffer_append_string_len
(dc
->comp_key
, CONST_STR_LEN
("[\""));
469 buffer_append_string_buffer
(dc
->comp_key
, C
);
470 buffer_append_string_len
(dc
->comp_key
, CONST_STR_LEN
("\"]"));
473 for
(i
= 0; comps
[i
].comp_key
; i
++) {
474 if
(buffer_is_equal_string
(
475 dc
->comp_key
, comps
[i
].comp_key
, comps
[i
].len
)) {
476 dc
->comp
= comps
[i
].comp
;
480 if
(COMP_UNSET
== dc
->comp
) {
481 fprintf
(stderr
, "error comp_key %s", dc
->comp_key
->ptr
);
484 else if
(COMP_HTTP_REMOTE_IP
== dc
->comp
485 && (dc
->cond
== CONFIG_COND_EQ || dc
->cond
== CONFIG_COND_NE
)) {
486 char * const slash
= strchr
(rvalue
->ptr
, '/');
487 if
(NULL
!= slash
&& slash
!= rvalue
->ptr
){/*(skip AF_UNIX /path/file)*/
489 const unsigned long nm_bits
= strtoul
(slash
+ 1, &nptr
, 10);
490 if
(*nptr ||
0 == nm_bits
491 || nm_bits
> (rvalue
->ptr
[0] == '[' ?
128 : 32)) {
492 /*(also rejects (slash+1 == nptr) which results in nm_bits = 0)*/
493 fprintf
(stderr
, "invalid or missing netmask: %s\n", rvalue
->ptr
);
498 buffer_string_set_length
(rvalue
, (size_t)(slash
- rvalue
->ptr
)); /*(truncate)*/
499 rc
= http_request_host_normalize
(rvalue
);
500 buffer_append_string_len
(rvalue
, CONST_STR_LEN
("/"));
501 buffer_append_int
(rvalue
, (int)nm_bits
);
503 fprintf
(stderr
, "invalid IP addr: %s\n", rvalue
->ptr
);
509 if
(http_request_host_normalize
(rvalue
)) {
510 fprintf
(stderr
, "invalid IP addr: %s\n", rvalue
->ptr
);
515 else if
(COMP_SERVER_SOCKET
== dc
->comp
) {
516 /*(redundant with parsing in network.c; not actually required here)*/
517 if
(rvalue
->ptr
[0] != ':' /*(network.c special-cases ":" and "[]")*/
518 && !(rvalue
->ptr
[0] == '[' && rvalue
->ptr
[1] == ']')) {
519 if
(http_request_host_normalize
(rvalue
)) {
520 fprintf
(stderr
, "invalid IP addr: %s\n", rvalue
->ptr
);
525 else if
(COMP_HTTP_HOST
== dc
->comp
) {
526 if
(dc
->cond
== CONFIG_COND_EQ || dc
->cond
== CONFIG_COND_NE
) {
527 if
(http_request_host_normalize
(rvalue
)) {
528 fprintf
(stderr
, "invalid IP addr: %s\n", rvalue
->ptr
);
534 if
(ctx
->ok
) switch
(E
) {
537 dc
->string = buffer_init_buffer
(rvalue
);
539 case CONFIG_COND_NOMATCH
:
540 case CONFIG_COND_MATCH
: {
543 int erroff
, captures
;
545 if
(NULL
== (dc
->regex
=
546 pcre_compile
(rvalue
->ptr
, 0, &errptr
, &erroff
, NULL
))) {
547 dc
->string = buffer_init_string
(errptr
);
548 dc
->cond
= CONFIG_COND_UNSET
;
550 fprintf
(stderr
, "parsing regex failed: %s -> %s at offset %d\n",
551 rvalue
->ptr
, errptr
, erroff
);
554 } else if
(NULL
== (dc
->regex_study
=
555 pcre_study
(dc
->regex
, 0, &errptr
)) &&
557 fprintf
(stderr
, "studying regex failed: %s -> %s\n",
558 rvalue
->ptr
, errptr
);
560 } else if
(0 != (pcre_fullinfo
(dc
->regex
, dc
->regex_study
, PCRE_INFO_CAPTURECOUNT
, &captures
))) {
561 fprintf
(stderr
, "getting capture count for regex failed: %s\n",
564 } else if
(captures
> 9) {
565 fprintf
(stderr
, "Too many captures in regex, use (?:...) instead of (...): %s\n",
569 dc
->string = buffer_init_buffer
(rvalue
);
572 fprintf
(stderr
, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
573 "(perhaps just a missing pcre-devel package ?) \n",
581 fprintf
(stderr
, "unknown condition for $%s[%s]\n",
588 configparser_push
(ctx
, dc
, 1);
590 dc
->free
((data_unset
*) dc
);
608 A
= CONFIG_COND_MATCH
;
613 cond
(A
) ::= NOMATCH.
{
614 A
= CONFIG_COND_NOMATCH
;
617 stringop
(A
) ::= expression
(B
).
{
620 if
(B
->type
== TYPE_STRING
) {
621 A
= buffer_init_buffer
(((data_string
*)B
)->value
);
622 } else if
(B
->type
== TYPE_INTEGER
) {
624 buffer_copy_int
(A
, ((data_integer
*)B
)->value
);
626 fprintf
(stderr
, "operand must be string");
634 include
::= INCLUDE stringop
(A
).
{
636 if
(0 != config_parse_file
(ctx
->srv
, ctx
, A
->ptr
)) {
644 include_shell
::= INCLUDE_SHELL stringop
(A
).
{
646 if
(0 != config_parse_cmd
(ctx
->srv
, ctx
, A
->ptr
)) {