<commit_before>
#include "base.h"
#include "buffer.h"
#include "array.h"
#include "log.h"

/**
 * like all glue code this file contains functions which
 * are the external interface of lighttpd. The functions
 * are used by the server itself and the plugins.
 *
 * The main-goal is to have a small library in the end 
 * which is linked against both and which will define 
 * the interface itself in the end.
 * 
 */


/* handle global options */

/* parse config array */
int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	
	for (i = 0; cv[i].key; i++) {
		
		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			
			continue;
		}
		
		switch (cv[i].type) {
		case T_CONFIG_ARRAY:
			if (du->type == TYPE_ARRAY) {
				size_t j;
				data_array *da = (data_array *)du;
				
				for (j = 0; j < da->value->used; j++) {
					if (da->value->data[j]->type == TYPE_STRING) {
						data_string *ds = data_string_init();
						
						buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
						buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
						
						array_insert_unique(cv[i].destination, (data_unset *)ds);
					} else {
						log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", cv[i].key, "[", da->value->data[i]->key, "](string)");
						
						return -1;
					}
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
				
				return -1;
			}
			break;
		case T_CONFIG_STRING:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;
				
				buffer_copy_string_buffer(cv[i].destination, ds->value);
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
				
				return -1;
			}
			break;
		case T_CONFIG_SHORT:
			switch(du->type) {
			case TYPE_INTEGER: {
				data_integer *di = (data_integer *)du;
				
				*((unsigned short *)(cv[i].destination)) = di->value;
				break;
			}
			case TYPE_STRING: {
				data_string *ds = (data_string *)du;
					
				log_error_write(srv, __FILE__, __LINE__, "ssbss", "unexpected type for key: ", cv[i].key, ds->value, "(short)", "0 ... 65535");
				
				return -1;
			}
			default:
				log_error_write(srv, __FILE__, __LINE__, "ssdss", "unexpected type for key: ", cv[i].key, du->type, "(short)", "0 ... 65535");
				return -1;
			}
			break;
		case T_CONFIG_BOOLEAN:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;
				
				if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
					*((unsigned short *)(cv[i].destination)) = 1;
				} else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
					*((unsigned short *)(cv[i].destination)) = 0;
				} else {
					log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
						
					return -1;
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
				
				return -1;
			}
			break;
		case T_CONFIG_LOCAL:
		case T_CONFIG_UNSET:
			break;
		case T_CONFIG_DEPRECATED:
			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
			
			srv->config_deprecated = 1;
			
			break;
		}
	}
	return 0;
}

int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	
	for (i = 0; cv[i].key; i++) {
		data_string *touched;
		
		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			
			continue;
		}
		
		/* touched */
		touched = data_string_init();
		
		buffer_copy_string(touched->value, "");
		buffer_copy_string_buffer(touched->key, du->key);
		
		array_insert_unique(srv->config_touched, (data_unset *)touched);
	}
	
	return config_insert_values_internal(srv, ca, cv);
}

unsigned short sock_addr_get_port(sock_addr *addr) {
#ifdef HAVE_IPV6
	return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
#else
	return ntohs(addr->ipv4.sin_port);
#endif
}

int config_check_cond(server *srv, connection *con, data_config *dc) {
	server_socket *srv_sock = con->srv_socket;
	buffer *l;
	
	/* pass the rules */
	
	/* 
	 * OPTIMIZE
	 * 
	 * - replace all is_equal be simple == to an enum
	 * - only check each condition once at the start of the request
	 *   afterwards they will always evaluate in the same way 
	 *   as they have the same input data
	 * 
	 */
	
	buffer_copy_string(srv->cond_check_buf, "");
	
	if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPhost"))) {
		char *ck_colon = NULL, *val_colon = NULL;
		/* 
		 * append server-port to the HTTP_POST if necessary
		 */
		
		buffer_copy_string_buffer(srv->cond_check_buf, con->uri.authority);
		
		switch(dc->cond) {
		case CONFIG_COND_NE:
		case CONFIG_COND_EQ:
			ck_colon = strchr(dc->match.string->ptr, ':');
			val_colon = strchr(con->uri.authority->ptr, ':');
		
			if (ck_colon && !val_colon) {
				/* colon found */
				BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
				buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
			}
			break;
		default:
			break;
		}
	} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPremoteip"))) {
		char *nm_slash;
		/* handle remoteip limitations 
		 * 
		 * "10.0.0.1" is provided for all comparisions
		 * 
		 * only for == and != we support
		 * 
		 * "10.0.0.1/24"
		 */
		
		if ((dc->cond == CONFIG_COND_EQ ||
		     dc->cond == CONFIG_COND_EQ) &&<commit_msg>only check HTTPhost condition if we really have a Host: set<commit_after>
#include "base.h"
#include "buffer.h"
#include "array.h"
#include "log.h"

/**
 * like all glue code this file contains functions which
 * are the external interface of lighttpd. The functions
 * are used by the server itself and the plugins.
 *
 * The main-goal is to have a small library in the end 
 * which is linked against both and which will define 
 * the interface itself in the end.
 * 
 */


/* handle global options */

/* parse config array */
int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	
	for (i = 0; cv[i].key; i++) {
		
		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			
			continue;
		}
		
		switch (cv[i].type) {
		case T_CONFIG_ARRAY:
			if (du->type == TYPE_ARRAY) {
				size_t j;
				data_array *da = (data_array *)du;
				
				for (j = 0; j < da->value->used; j++) {
					if (da->value->data[j]->type == TYPE_STRING) {
						data_string *ds = data_string_init();
						
						buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
						buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
						
						array_insert_unique(cv[i].destination, (data_unset *)ds);
					} else {
						log_error_write(srv, __FILE__, __LINE__, "sssbs", "unexpected type for key: ", cv[i].key, "[", da->value->data[i]->key, "](string)");
						
						return -1;
					}
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
				
				return -1;
			}
			break;
		case T_CONFIG_STRING:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;
				
				buffer_copy_string_buffer(cv[i].destination, ds->value);
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
				
				return -1;
			}
			break;
		case T_CONFIG_SHORT:
			switch(du->type) {
			case TYPE_INTEGER: {
				data_integer *di = (data_integer *)du;
				
				*((unsigned short *)(cv[i].destination)) = di->value;
				break;
			}
			case TYPE_STRING: {
				data_string *ds = (data_string *)du;
					
				log_error_write(srv, __FILE__, __LINE__, "ssbss", "unexpected type for key: ", cv[i].key, ds->value, "(short)", "0 ... 65535");
				
				return -1;
			}
			default:
				log_error_write(srv, __FILE__, __LINE__, "ssdss", "unexpected type for key: ", cv[i].key, du->type, "(short)", "0 ... 65535");
				return -1;
			}
			break;
		case T_CONFIG_BOOLEAN:
			if (du->type == TYPE_STRING) {
				data_string *ds = (data_string *)du;
				
				if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
					*((unsigned short *)(cv[i].destination)) = 1;
				} else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
					*((unsigned short *)(cv[i].destination)) = 0;
				} else {
					log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
						
					return -1;
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
				
				return -1;
			}
			break;
		case T_CONFIG_LOCAL:
		case T_CONFIG_UNSET:
			break;
		case T_CONFIG_DEPRECATED:
			log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
			
			srv->config_deprecated = 1;
			
			break;
		}
	}
	return 0;
}

int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	
	for (i = 0; cv[i].key; i++) {
		data_string *touched;
		
		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			
			continue;
		}
		
		/* touched */
		touched = data_string_init();
		
		buffer_copy_string(touched->value, "");
		buffer_copy_string_buffer(touched->key, du->key);
		
		array_insert_unique(srv->config_touched, (data_unset *)touched);
	}
	
	return config_insert_values_internal(srv, ca, cv);
}

unsigned short sock_addr_get_port(sock_addr *addr) {
#ifdef HAVE_IPV6
	return ntohs(addr->plain.sa_family ? addr->ipv6.sin6_port : addr->ipv4.sin_port);
#else
	return ntohs(addr->ipv4.sin_port);
#endif
}

int config_check_cond(server *srv, connection *con, data_config *dc) {
	server_socket *srv_sock = con->srv_socket;
	buffer *l;
	
	/* pass the rules */
	
	/* 
	 * OPTIMIZE
	 * 
	 * - replace all is_equal be simple == to an enum
	 * - only check each condition once at the start of the request
	 *   afterwards they will always evaluate in the same way 
	 *   as they have the same input data
	 * 
	 */
	
	buffer_copy_string(srv->cond_check_buf, "");
	
	if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPhost"))) {
		char *ck_colon = NULL, *val_colon = NULL;
		
		if (!buffer_is_empty(con->uri.authority)) {
		
			/* 
			 * append server-port to the HTTP_POST if necessary
			 */
			
			buffer_copy_string_buffer(srv->cond_check_buf, con->uri.authority);
			
			switch(dc->cond) {
			case CONFIG_COND_NE:
			case CONFIG_COND_EQ:
				ck_colon = strchr(dc->match.string->ptr, ':');
				val_colon = strchr(con->uri.authority->ptr, ':');
				
				if (ck_colon && !val_colon) {
					/* colon found */
					BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
					buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
				}
				break;
			default:
				break;
			}
		}
	} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPremoteip"))) {
		char *nm_slash;
		/* handle remoteip limitations 
		 * 
		 * "10.0.0.1" is provided for all comparisions
		 * 
		 * only for == and != we support
		 * 
		 * "10.0.0.1/24"
		 */
		
		if ((dc->cond == CONFIG_COND_EQ ||
		     dc->cond == CONFIG_COND_EQ) &&
{'fraction_non_alphanumeric': 0.15828886211051815, 'fraction_numerical': 0.00740230676536409, 'mean_word_length': 3.223555070883315, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 108, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 4, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3475724', 'n_tokens_mistral': 5048, 'n_tokens_neox': 4192, 'n_words': 972}