drain backend socket/pipe bufs upon FDEVENT_HUP
[lighttpd.git] / src / configfile-glue.c
blob2c0d6192b61bda0025a2dbfcfc133751e9d7cf28
1 #include "first.h"
3 #include "base.h"
4 #include "buffer.h"
5 #include "array.h"
6 #include "log.h"
7 #include "plugin.h"
9 #include "configfile.h"
11 #include <string.h>
12 #include <stdlib.h>
13 #ifndef _WIN32
14 #include <arpa/inet.h>
15 #endif
17 /**
18 * like all glue code this file contains functions which
19 * are the external interface of lighttpd. The functions
20 * are used by the server itself and the plugins.
22 * The main-goal is to have a small library in the end
23 * which is linked against both and which will define
24 * the interface itself in the end.
29 /* handle global options */
31 /* parse config array */
32 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
33 size_t i;
34 data_unset *du;
36 for (i = 0; cv[i].key; i++) {
38 if (NULL == (du = array_get_element(ca, cv[i].key))) {
39 /* no found */
41 continue;
44 if ((T_CONFIG_SCOPE_SERVER == cv[i].scope)
45 && (T_CONFIG_SCOPE_SERVER != scope)) {
46 /* server scope options should only be set in server scope, not in conditionals */
47 log_error_write(srv, __FILE__, __LINE__, "ss",
48 "DEPRECATED: don't set server options in conditionals, variable:",
49 cv[i].key);
52 switch (cv[i].type) {
53 case T_CONFIG_ARRAY:
54 if (du->type == TYPE_ARRAY) {
55 size_t j;
56 data_array *da = (data_array *)du;
58 for (j = 0; j < da->value->used; j++) {
59 data_unset *ds = da->value->data[j];
60 if (ds->type == TYPE_STRING) {
61 array_insert_unique(cv[i].destination, ds->copy(ds));
62 } else {
63 log_error_write(srv, __FILE__, __LINE__, "sssbsd",
64 "the value of an array can only be a string, variable:",
65 cv[i].key, "[", ds->key, "], type:", ds->type);
67 return -1;
70 } else {
71 log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
73 return -1;
75 break;
76 case T_CONFIG_STRING:
77 if (du->type == TYPE_STRING) {
78 data_string *ds = (data_string *)du;
80 buffer_copy_buffer(cv[i].destination, ds->value);
81 } else {
82 log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
84 return -1;
86 break;
87 case T_CONFIG_SHORT:
88 switch(du->type) {
89 case TYPE_INTEGER: {
90 data_integer *di = (data_integer *)du;
92 *((unsigned short *)(cv[i].destination)) = di->value;
93 break;
95 case TYPE_STRING: {
96 data_string *ds = (data_string *)du;
98 /* If the value came from an environment variable, then it is a
99 * data_string, although it may contain a number in ASCII
100 * decimal format. We try to interpret the string as a decimal
101 * short before giving up, in order to support setting numeric
102 * values with environment variables (eg, port number).
104 if (ds->value->ptr && *ds->value->ptr) {
105 char *e;
106 long l = strtol(ds->value->ptr, &e, 10);
107 if (e != ds->value->ptr && !*e && l >=0 && l <= 65535) {
108 *((unsigned short *)(cv[i].destination)) = l;
109 break;
113 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
115 return -1;
117 default:
118 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a short integer, range 0 ... 65535");
119 return -1;
121 break;
122 case T_CONFIG_INT:
123 switch(du->type) {
124 case TYPE_INTEGER: {
125 data_integer *di = (data_integer *)du;
127 *((unsigned int *)(cv[i].destination)) = di->value;
128 break;
130 case TYPE_STRING: {
131 data_string *ds = (data_string *)du;
133 if (ds->value->ptr && *ds->value->ptr) {
134 char *e;
135 long l = strtol(ds->value->ptr, &e, 10);
136 if (e != ds->value->ptr && !*e && l >= 0) {
137 *((unsigned int *)(cv[i].destination)) = l;
138 break;
142 log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected an integer:", cv[i].key, ds->value);
144 return -1;
146 default:
147 log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected an integer, range 0 ... 4294967295");
148 return -1;
150 break;
151 case T_CONFIG_BOOLEAN:
152 if (du->type == TYPE_STRING) {
153 data_string *ds = (data_string *)du;
155 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
156 *((unsigned short *)(cv[i].destination)) = 1;
157 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
158 *((unsigned short *)(cv[i].destination)) = 0;
159 } else {
160 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
162 return -1;
164 } else {
165 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
167 return -1;
169 break;
170 case T_CONFIG_LOCAL:
171 case T_CONFIG_UNSET:
172 break;
173 case T_CONFIG_UNSUPPORTED:
174 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
176 srv->config_unsupported = 1;
178 break;
179 case T_CONFIG_DEPRECATED:
180 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
182 srv->config_deprecated = 1;
184 break;
188 return 0;
191 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[], config_scope_type_t scope) {
192 size_t i;
193 data_unset *du;
195 for (i = 0; cv[i].key; i++) {
196 data_string *touched;
198 if (NULL == (du = array_get_element(ca, cv[i].key))) {
199 /* no found */
201 continue;
204 /* touched */
205 touched = data_string_init();
207 buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
208 buffer_copy_buffer(touched->key, du->key);
210 array_insert_unique(srv->config_touched, (data_unset *)touched);
213 return config_insert_values_internal(srv, ca, cv, scope);
216 static unsigned short sock_addr_get_port(sock_addr *addr) {
217 #ifdef HAVE_IPV6
218 return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
219 #else
220 return ntohs(addr->ipv4.sin_port);
221 #endif
224 static const char* cond_result_to_string(cond_result_t cond_result) {
225 switch (cond_result) {
226 case COND_RESULT_UNSET: return "unset";
227 case COND_RESULT_SKIP: return "skipped";
228 case COND_RESULT_FALSE: return "false";
229 case COND_RESULT_TRUE: return "true";
230 default: return "invalid cond_result_t";
234 static int config_addrstr_eq_remote_ip_mask(server *srv, const char *addrstr, int nm_bits, sock_addr *rmt) {
235 /* special-case 0 == nm_bits to mean "all bits of the address" in addrstr */
236 sock_addr val;
237 #ifdef HAVE_INET_PTON
238 if (1 == inet_pton(AF_INET, addrstr, &val.ipv4.sin_addr))
239 #else
240 if (INADDR_NONE != (val.ipv4.sin_addr = inet_addr(addrstr)))
241 #endif
243 /* build netmask */
244 uint32_t nm;
245 if (nm_bits > 32) {
246 log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv4 netmask too large:", nm_bits);
247 return -1;
249 nm = htonl(~((1u << (32 - (0 != nm_bits ? nm_bits : 32))) - 1));
251 if (rmt->plain.sa_family == AF_INET) {
252 return ((val.ipv4.sin_addr.s_addr & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
253 #ifdef HAVE_IPV6
254 } else if (rmt->plain.sa_family == AF_INET6
255 && IN6_IS_ADDR_V4MAPPED(&rmt->ipv6.sin6_addr)) {
256 in_addr_t x = *(in_addr_t *)(rmt->ipv6.sin6_addr.s6_addr+12);
257 return ((val.ipv4.sin_addr.s_addr & nm) == (x & nm));
258 #endif
259 } else {
260 return 0;
262 #if defined(HAVE_INET_PTON) && defined(HAVE_IPV6)
263 } else if (1 == inet_pton(AF_INET6, addrstr, &val.ipv6.sin6_addr)) {
264 if (nm_bits > 128) {
265 log_error_write(srv, __FILE__, __LINE__, "sd", "ERROR: ipv6 netmask too large:", nm_bits);
266 return -1;
268 if (rmt->plain.sa_family == AF_INET6) {
269 uint8_t *a = (uint8_t *)&val.ipv6.sin6_addr.s6_addr[0];
270 uint8_t *b = (uint8_t *)&rmt->ipv6.sin6_addr.s6_addr[0];
271 int match;
272 do {
273 match = (nm_bits >= 8)
274 ? *a++ == *b++
275 : (*a >> (8 - nm_bits)) == (*b >> (8 - nm_bits));
276 } while (match && (nm_bits -= 8) > 0);
277 return match;
278 } else if (rmt->plain.sa_family == AF_INET
279 && IN6_IS_ADDR_V4MAPPED(&val.ipv6.sin6_addr)) {
280 in_addr_t x = *(in_addr_t *)(val.ipv6.sin6_addr.s6_addr+12);
281 uint32_t nm =
282 htonl(~((1u << (32 - (0 != nm_bits ? (nm_bits > 96 ? nm_bits - 96 : 0) : 32))) - 1));
283 return ((x & nm) == (rmt->ipv4.sin_addr.s_addr & nm));
284 } else {
285 return 0;
287 #endif
288 } else {
289 log_error_write(srv, __FILE__, __LINE__, "ss", "ERROR: ip addr is invalid:", addrstr);
290 return -1;
294 static int config_addrbuf_eq_remote_ip_mask(server *srv, buffer *string, char *nm_slash, sock_addr *rmt) {
295 char *err;
296 int nm_bits = strtol(nm_slash + 1, &err, 10);
297 size_t addrstrlen = (size_t)(nm_slash - string->ptr);
298 char addrstr[64]; /*(larger than INET_ADDRSTRLEN and INET6_ADDRSTRLEN)*/
300 if (*err) {
301 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", string, err);
302 return -1;
305 if (nm_bits <= 0) {
306 if (*(nm_slash+1) == '\0') {
307 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", string);
308 } else {
309 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: invalid netmask <= 0:", string, err);
311 return -1;
314 if (addrstrlen >= sizeof(addrstr)) {
315 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: address string too long:", string);
316 return -1;
319 memcpy(addrstr, string->ptr, addrstrlen);
320 addrstr[addrstrlen] = '\0';
322 return config_addrstr_eq_remote_ip_mask(srv, addrstr, nm_bits, rmt);
325 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
327 static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
328 buffer *l;
329 server_socket *srv_sock = con->srv_socket;
330 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
332 /* check parent first */
333 if (dc->parent && dc->parent->context_ndx) {
335 * a nested conditional
337 * if the parent is not decided yet or false, we can't be true either
339 if (con->conf.log_condition_handling) {
340 log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
343 switch (config_check_cond_cached(srv, con, dc->parent)) {
344 case COND_RESULT_UNSET:
345 /* decide later */
346 return COND_RESULT_UNSET;
347 case COND_RESULT_SKIP:
348 case COND_RESULT_FALSE:
349 /* failed precondition */
350 return COND_RESULT_SKIP;
351 case COND_RESULT_TRUE:
352 /* proceed */
353 break;
357 if (dc->prev) {
359 * a else branch; can only be executed if the previous branch
360 * was evaluated as "false" (not unset/skipped/true)
362 if (con->conf.log_condition_handling) {
363 log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
366 /* make sure prev is checked first */
367 switch (config_check_cond_cached(srv, con, dc->prev)) {
368 case COND_RESULT_UNSET:
369 /* decide later */
370 return COND_RESULT_UNSET;
371 case COND_RESULT_SKIP:
372 case COND_RESULT_TRUE:
373 /* failed precondition */
374 return COND_RESULT_SKIP;
375 case COND_RESULT_FALSE:
376 /* proceed */
377 break;
381 if (!con->conditional_is_valid[dc->comp]) {
382 if (con->conf.log_condition_handling) {
383 log_error_write(srv, __FILE__, __LINE__, "dss",
384 dc->comp,
385 dc->key->ptr,
386 "not available yet");
389 return COND_RESULT_UNSET;
392 /* if we had a real result before and weren't cleared just return it */
393 switch (cache->local_result) {
394 case COND_RESULT_TRUE:
395 case COND_RESULT_FALSE:
396 return cache->local_result;
397 default:
398 break;
401 /* pass the rules */
403 switch (dc->comp) {
404 case COMP_HTTP_HOST: {
405 char *ck_colon = NULL, *val_colon = NULL;
407 if (!buffer_string_is_empty(con->uri.authority)) {
410 * append server-port to the HTTP_POST if necessary
413 l = con->uri.authority;
415 switch(dc->cond) {
416 case CONFIG_COND_NE:
417 case CONFIG_COND_EQ:
418 ck_colon = strchr(dc->string->ptr, ':');
419 val_colon = strchr(l->ptr, ':');
421 if (NULL != ck_colon && NULL == val_colon) {
422 /* condition "host:port" but client send "host" */
423 buffer_copy_buffer(srv->cond_check_buf, l);
424 buffer_append_string_len(srv->cond_check_buf, CONST_STR_LEN(":"));
425 buffer_append_int(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
426 l = srv->cond_check_buf;
427 } else if (NULL != val_colon && NULL == ck_colon) {
428 /* condition "host" but client send "host:port" */
429 buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
430 l = srv->cond_check_buf;
432 break;
433 default:
434 break;
436 #if defined USE_OPENSSL && ! defined OPENSSL_NO_TLSEXT
437 } else if (!buffer_string_is_empty(con->tlsext_server_name)) {
438 l = con->tlsext_server_name;
439 #endif
440 } else {
441 l = srv->empty_string;
443 break;
445 case COMP_HTTP_REMOTE_IP: {
446 char *nm_slash;
447 /* handle remoteip limitations
449 * "10.0.0.1" is provided for all comparisions
451 * only for == and != we support
453 * "10.0.0.1/24"
456 if ((dc->cond == CONFIG_COND_EQ ||
457 dc->cond == CONFIG_COND_NE) &&
458 (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
459 switch (config_addrbuf_eq_remote_ip_mask(srv, dc->string, nm_slash, &con->dst_addr)) {
460 case 1: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
461 case 0: return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
462 case -1: return COND_RESULT_FALSE; /*(error parsing configfile entry)*/
465 l = con->dst_addr_buf;
466 break;
468 case COMP_HTTP_SCHEME:
469 l = con->uri.scheme;
470 break;
472 case COMP_HTTP_URL:
473 l = con->uri.path;
474 break;
476 case COMP_HTTP_QUERY_STRING:
477 l = con->uri.query;
478 break;
480 case COMP_SERVER_SOCKET:
481 l = srv_sock->srv_token;
482 break;
484 case COMP_HTTP_REFERER: {
485 data_string *ds;
487 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
488 l = ds->value;
489 } else {
490 l = srv->empty_string;
492 break;
494 case COMP_HTTP_COOKIE: {
495 data_string *ds;
496 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
497 l = ds->value;
498 } else {
499 l = srv->empty_string;
501 break;
503 case COMP_HTTP_USER_AGENT: {
504 data_string *ds;
505 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
506 l = ds->value;
507 } else {
508 l = srv->empty_string;
510 break;
512 case COMP_HTTP_REQUEST_METHOD: {
513 const char *method = get_http_method_name(con->request.http_method);
515 /* we only have the request method as const char but we need a buffer for comparing */
517 buffer_copy_string(srv->tmp_buf, method);
519 l = srv->tmp_buf;
521 break;
523 case COMP_HTTP_LANGUAGE: {
524 data_string *ds;
525 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Language"))) {
526 l = ds->value;
527 } else {
528 l = srv->empty_string;
530 break;
532 default:
533 return COND_RESULT_FALSE;
536 if (NULL == l) {
537 if (con->conf.log_condition_handling) {
538 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
539 "(", l, ") compare to NULL");
541 return COND_RESULT_FALSE;
544 if (con->conf.log_condition_handling) {
545 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
546 "(", l, ") compare to ", dc->string);
548 switch(dc->cond) {
549 case CONFIG_COND_NE:
550 case CONFIG_COND_EQ:
551 if (buffer_is_equal(l, dc->string)) {
552 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
553 } else {
554 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
556 break;
557 #ifdef HAVE_PCRE_H
558 case CONFIG_COND_NOMATCH:
559 case CONFIG_COND_MATCH: {
560 int n;
562 #ifndef elementsof
563 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
564 #endif
565 n = pcre_exec(dc->regex, dc->regex_study, CONST_BUF_LEN(l), 0, 0,
566 cache->matches, elementsof(cache->matches));
568 cache->patterncount = n;
569 if (n > 0) {
570 cache->comp_value = l;
571 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
572 } else {
573 /* cache is already cleared */
574 return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
576 break;
578 #endif
579 default:
580 /* no way */
581 break;
584 return COND_RESULT_FALSE;
587 static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
588 cond_cache_t *caches = con->cond_cache;
590 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
591 caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc);
592 switch (caches[dc->context_ndx].result) {
593 case COND_RESULT_FALSE:
594 case COND_RESULT_TRUE:
595 /* remember result of local condition for a partial reset */
596 caches[dc->context_ndx].local_result = caches[dc->context_ndx].result;
597 break;
598 default:
599 break;
602 if (con->conf.log_condition_handling) {
603 log_error_write(srv, __FILE__, __LINE__, "dss",
604 dc->context_ndx,
605 "(uncached) result:",
606 cond_result_to_string(caches[dc->context_ndx].result));
608 } else {
609 if (con->conf.log_condition_handling) {
610 log_error_write(srv, __FILE__, __LINE__, "dss",
611 dc->context_ndx,
612 "(cached) result:",
613 cond_result_to_string(caches[dc->context_ndx].result));
616 return caches[dc->context_ndx].result;
619 /* if we reset the cache result for a node, we also need to clear all
620 * child nodes and else-branches*/
621 static void config_cond_clear_node(server *srv, connection *con, data_config *dc) {
622 /* if a node is "unset" all children are unset too */
623 if (con->cond_cache[dc->context_ndx].result != COND_RESULT_UNSET) {
624 size_t i;
626 con->cond_cache[dc->context_ndx].patterncount = 0;
627 con->cond_cache[dc->context_ndx].comp_value = NULL;
628 con->cond_cache[dc->context_ndx].result = COND_RESULT_UNSET;
630 for (i = 0; i < dc->children.used; ++i) {
631 data_config *dc_child = dc->children.data[i];
632 if (NULL == dc_child->prev) {
633 /* only call for first node in if-else chain */
634 config_cond_clear_node(srv, con, dc_child);
637 if (NULL != dc->next) config_cond_clear_node(srv, con, dc->next);
642 * reset the config-cache for a named item
644 * if the item is COND_LAST_ELEMENT we reset all items
646 void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
647 size_t i;
649 for (i = 0; i < srv->config_context->used; i++) {
650 data_config *dc = (data_config *)srv->config_context->data[i];
652 if (item == dc->comp) {
653 /* clear local_result */
654 con->cond_cache[i].local_result = COND_RESULT_UNSET;
655 /* clear result in subtree (including the node itself) */
656 config_cond_clear_node(srv, con, dc);
662 * reset the config cache to its initial state at connection start
664 void config_cond_cache_reset(server *srv, connection *con) {
665 size_t i;
667 /* resetting all entries; no need to follow children as in config_cond_cache_reset_item */
668 for (i = 0; i < srv->config_context->used; i++) {
669 con->cond_cache[i].result = COND_RESULT_UNSET;
670 con->cond_cache[i].local_result = COND_RESULT_UNSET;
671 con->cond_cache[i].patterncount = 0;
672 con->cond_cache[i].comp_value = NULL;
675 for (i = 0; i < COMP_LAST_ELEMENT; i++) {
676 con->conditional_is_valid[i] = 0;
680 int config_check_cond(server *srv, connection *con, data_config *dc) {
681 if (con->conf.log_condition_handling) {
682 log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
684 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
687 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
689 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
690 if (n >= cache->patterncount) {
691 return 0;
694 n <<= 1; /* n *= 2 */
695 buffer_append_string_len(buf,
696 cache->comp_value->ptr + cache->matches[n],
697 cache->matches[n + 1] - cache->matches[n]);
698 return 1;