2005-09-01 10:33:48 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
#include "base.h"
|
|
|
|
#include "buffer.h"
|
|
|
|
#include "array.h"
|
|
|
|
#include "log.h"
|
2005-08-08 13:48:33 +00:00
|
|
|
#include "plugin.h"
|
2005-02-28 08:42:47 +00:00
|
|
|
|
2007-08-18 09:27:11 +00:00
|
|
|
#include "configfile.h"
|
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2006-10-04 13:26:23 +00:00
|
|
|
* The main-goal is to have a small library in the end
|
|
|
|
* which is linked against both and which will define
|
2005-02-28 08:42:47 +00:00
|
|
|
* the interface itself in the end.
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-02-28 08:42:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
for (i = 0; cv[i].key; i++) {
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
if (NULL == (du = array_get_element(ca, cv[i].key))) {
|
|
|
|
/* no found */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
switch (cv[i].type) {
|
|
|
|
case T_CONFIG_ARRAY:
|
|
|
|
if (du->type == TYPE_ARRAY) {
|
|
|
|
size_t j;
|
|
|
|
data_array *da = (data_array *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
for (j = 0; j < da->value->used; j++) {
|
|
|
|
if (da->value->data[j]->type == TYPE_STRING) {
|
|
|
|
data_string *ds = data_string_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
|
2005-08-23 14:35:01 +00:00
|
|
|
if (!da->is_index_key) {
|
2005-08-17 09:56:33 +00:00
|
|
|
/* the id's were generated automaticly, as we copy now we might have to renumber them
|
2006-10-04 13:26:23 +00:00
|
|
|
* this is used to prepend server.modules by mod_indexfiles as it has to be loaded
|
2005-08-17 09:56:33 +00:00
|
|
|
* before mod_fastcgi and friends */
|
|
|
|
buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
array_insert_unique(cv[i].destination, (data_unset *)ds);
|
|
|
|
} else {
|
2006-10-04 13:26:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sssd",
|
|
|
|
"the key of an array can only be a string or a integer, variable:",
|
|
|
|
cv[i].key, "type:", da->value->data[j]->type);
|
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2006-09-23 11:19:02 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_CONFIG_STRING:
|
|
|
|
if (du->type == TYPE_STRING) {
|
|
|
|
data_string *ds = (data_string *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
buffer_copy_string_buffer(cv[i].destination, ds->value);
|
|
|
|
} else {
|
2006-09-23 11:19:02 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_CONFIG_SHORT:
|
|
|
|
switch(du->type) {
|
|
|
|
case TYPE_INTEGER: {
|
|
|
|
data_integer *di = (data_integer *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
*((unsigned short *)(cv[i].destination)) = di->value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TYPE_STRING: {
|
|
|
|
data_string *ds = (data_string *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2006-09-23 11:19:02 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
default:
|
2005-07-28 20:56:28 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssds", "unexpected type for key:", cv[i].key, du->type, "expected a integer, range 0 ... 65535");
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_CONFIG_BOOLEAN:
|
|
|
|
if (du->type == TYPE_STRING) {
|
|
|
|
data_string *ds = (data_string *)du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
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)");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case T_CONFIG_LOCAL:
|
|
|
|
case T_CONFIG_UNSET:
|
2006-09-07 11:00:02 +00:00
|
|
|
break;
|
|
|
|
case T_CONFIG_UNSUPPORTED:
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2006-09-07 11:00:02 +00:00
|
|
|
srv->config_unsupported = 1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
break;
|
|
|
|
case T_CONFIG_DEPRECATED:
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
srv->config_deprecated = 1;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-08-18 09:27:11 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
|
|
|
|
size_t i;
|
|
|
|
data_unset *du;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
for (i = 0; cv[i].key; i++) {
|
|
|
|
data_string *touched;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
if (NULL == (du = array_get_element(ca, cv[i].key))) {
|
|
|
|
/* no found */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
continue;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
/* touched */
|
|
|
|
touched = data_string_init();
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
buffer_copy_string(touched->value, "");
|
|
|
|
buffer_copy_string_buffer(touched->key, du->key);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
array_insert_unique(srv->config_touched, (data_unset *)touched);
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
return config_insert_values_internal(srv, ca, cv);
|
|
|
|
}
|
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc);
|
2005-08-08 13:48:33 +00:00
|
|
|
|
|
|
|
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
|
2005-02-28 08:42:47 +00:00
|
|
|
buffer *l;
|
|
|
|
server_socket *srv_sock = con->srv_socket;
|
2007-08-18 09:27:11 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
/* check parent first */
|
2005-08-08 14:40:47 +00:00
|
|
|
if (dc->parent && dc->parent->context_ndx) {
|
2007-08-18 09:27:11 +00:00
|
|
|
/**
|
|
|
|
* a nested conditional
|
|
|
|
*
|
|
|
|
* if the parent is not decided yet or false, we can't be true either
|
|
|
|
*/
|
2005-08-08 13:48:33 +00:00
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-09 06:42:33 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2007-08-18 09:27:11 +00:00
|
|
|
|
|
|
|
switch (config_check_cond_cached(srv, con, dc->parent)) {
|
|
|
|
case COND_RESULT_FALSE:
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
2007-08-18 09:27:11 +00:00
|
|
|
case COND_RESULT_UNSET:
|
|
|
|
return COND_RESULT_UNSET;
|
|
|
|
default:
|
|
|
|
break;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dc->prev) {
|
2007-08-18 09:27:11 +00:00
|
|
|
/**
|
|
|
|
* a else branch
|
|
|
|
*
|
|
|
|
* we can only be executed, if all of our previous brothers
|
|
|
|
* are false
|
|
|
|
*/
|
2005-08-08 13:48:33 +00:00
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-09 06:42:33 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2007-08-18 09:27:11 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
/* make sure prev is checked first */
|
|
|
|
config_check_cond_cached(srv, con, dc->prev);
|
2007-08-18 09:27:11 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
/* one of prev set me to FALSE */
|
2007-08-18 09:27:11 +00:00
|
|
|
switch (con->cond_cache[dc->context_ndx].result) {
|
|
|
|
case COND_RESULT_FALSE:
|
|
|
|
return con->cond_cache[dc->context_ndx].result;
|
|
|
|
default:
|
|
|
|
break;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-18 09:27:11 +00:00
|
|
|
if (!con->conditional_is_valid[dc->comp]) {
|
|
|
|
if (con->conf.log_condition_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "dss",
|
|
|
|
dc->comp,
|
|
|
|
dc->key->ptr,
|
|
|
|
con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
|
|
|
|
}
|
|
|
|
|
|
|
|
return COND_RESULT_UNSET;
|
|
|
|
}
|
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
/* pass the rules */
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
switch (dc->comp) {
|
|
|
|
case COMP_HTTP_HOST: {
|
2005-08-08 13:48:33 +00:00
|
|
|
char *ck_colon = NULL, *val_colon = NULL;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if (!buffer_is_empty(con->uri.authority)) {
|
2006-10-04 13:26:23 +00:00
|
|
|
|
|
|
|
/*
|
2005-08-08 13:48:33 +00:00
|
|
|
* append server-port to the HTTP_POST if necessary
|
|
|
|
*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
l = con->uri.authority;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
switch(dc->cond) {
|
|
|
|
case CONFIG_COND_NE:
|
|
|
|
case CONFIG_COND_EQ:
|
|
|
|
ck_colon = strchr(dc->string->ptr, ':');
|
2005-08-15 09:55:23 +00:00
|
|
|
val_colon = strchr(l->ptr, ':');
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
if (ck_colon == val_colon) {
|
|
|
|
/* nothing to do with it */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ck_colon) {
|
|
|
|
/* condition "host:port" but client send "host" */
|
|
|
|
buffer_copy_string_buffer(srv->cond_check_buf, l);
|
2005-08-08 13:48:33 +00:00
|
|
|
BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
|
|
|
|
buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
|
2005-08-15 09:55:23 +00:00
|
|
|
l = srv->cond_check_buf;
|
|
|
|
} else if (!ck_colon) {
|
|
|
|
/* condition "host" but client send "host:port" */
|
|
|
|
buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
|
|
|
|
l = srv->cond_check_buf;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2006-09-07 10:19:29 +00:00
|
|
|
l = srv->empty_string;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case COMP_HTTP_REMOTEIP: {
|
2005-08-08 13:48:33 +00:00
|
|
|
char *nm_slash;
|
2006-10-04 13:26:23 +00:00
|
|
|
/* handle remoteip limitations
|
|
|
|
*
|
2005-08-08 13:48:33 +00:00
|
|
|
* "10.0.0.1" is provided for all comparisions
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-08-08 13:48:33 +00:00
|
|
|
* only for == and != we support
|
2006-10-04 13:26:23 +00:00
|
|
|
*
|
2005-08-08 13:48:33 +00:00
|
|
|
* "10.0.0.1/24"
|
|
|
|
*/
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if ((dc->cond == CONFIG_COND_EQ ||
|
|
|
|
dc->cond == CONFIG_COND_NE) &&
|
|
|
|
(con->dst_addr.plain.sa_family == AF_INET) &&
|
|
|
|
(NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
|
|
|
|
int nm_bits;
|
|
|
|
long nm;
|
|
|
|
char *err;
|
|
|
|
struct in_addr val_inp;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if (*(nm_slash+1) == '\0') {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
nm_bits = strtol(nm_slash + 1, &err, 10);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if (*err) {
|
2006-09-20 19:04:36 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
/* take IP convert to the native */
|
|
|
|
buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
|
2006-10-04 13:26:23 +00:00
|
|
|
#ifdef __WIN32
|
2005-08-08 13:48:33 +00:00
|
|
|
if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
|
|
|
}
|
|
|
|
#endif
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
/* build netmask */
|
|
|
|
nm = htonl(~((1 << (32 - nm_bits)) - 1));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
|
|
|
|
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
|
|
|
|
} else {
|
|
|
|
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
|
|
|
|
}
|
|
|
|
} else {
|
2005-08-15 09:55:23 +00:00
|
|
|
l = con->dst_addr_buf;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-11-04 16:53:17 +00:00
|
|
|
case COMP_HTTP_SCHEME:
|
|
|
|
l = con->uri.scheme;
|
|
|
|
break;
|
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
case COMP_HTTP_URL:
|
2005-02-28 08:42:47 +00:00
|
|
|
l = con->uri.path;
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
|
2006-09-07 11:05:41 +00:00
|
|
|
case COMP_HTTP_QUERYSTRING:
|
|
|
|
l = con->uri.query;
|
|
|
|
break;
|
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
case COMP_SERVER_SOCKET:
|
2005-02-28 08:42:47 +00:00
|
|
|
l = srv_sock->srv_token;
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case COMP_HTTP_REFERER: {
|
2005-02-28 08:42:47 +00:00
|
|
|
data_string *ds;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-02-28 08:42:47 +00:00
|
|
|
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
|
|
|
|
l = ds->value;
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2005-09-30 11:06:43 +00:00
|
|
|
l = srv->empty_string;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case COMP_HTTP_COOKIE: {
|
2005-02-28 08:42:47 +00:00
|
|
|
data_string *ds;
|
|
|
|
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
|
|
|
|
l = ds->value;
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2005-09-30 11:06:43 +00:00
|
|
|
l = srv->empty_string;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case COMP_HTTP_USERAGENT: {
|
2005-02-28 08:42:47 +00:00
|
|
|
data_string *ds;
|
|
|
|
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
|
|
|
|
l = ds->value;
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2005-09-30 11:06:43 +00:00
|
|
|
l = srv->empty_string;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-15 09:55:23 +00:00
|
|
|
if (NULL == l) {
|
|
|
|
if (con->conf.log_condition_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
|
|
|
|
"(", l, ") compare to NULL");
|
|
|
|
}
|
|
|
|
return COND_RESULT_FALSE;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-15 09:55:23 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
|
|
|
|
"(", l, ") compare to ", dc->string);
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2005-02-28 08:42:47 +00:00
|
|
|
switch(dc->cond) {
|
|
|
|
case CONFIG_COND_NE:
|
|
|
|
case CONFIG_COND_EQ:
|
2005-08-08 13:48:33 +00:00
|
|
|
if (buffer_is_equal(l, dc->string)) {
|
|
|
|
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
|
2005-02-28 08:42:47 +00:00
|
|
|
} else {
|
2005-08-08 13:48:33 +00:00
|
|
|
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
#ifdef HAVE_PCRE_H
|
|
|
|
case CONFIG_COND_NOMATCH:
|
|
|
|
case CONFIG_COND_MATCH: {
|
2005-08-09 06:42:33 +00:00
|
|
|
cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
|
2005-02-28 08:42:47 +00:00
|
|
|
int n;
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
#ifndef elementsof
|
|
|
|
#define elementsof(x) (sizeof(x) / sizeof(x[0]))
|
|
|
|
#endif
|
|
|
|
n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
|
|
|
|
cache->matches, elementsof(cache->matches));
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2006-03-03 09:37:06 +00:00
|
|
|
cache->patterncount = n;
|
2005-02-28 08:42:47 +00:00
|
|
|
if (n > 0) {
|
2005-08-09 06:42:33 +00:00
|
|
|
cache->comp_value = l;
|
2007-08-18 09:27:11 +00:00
|
|
|
cache->comp_type = dc->comp;
|
2005-08-08 13:48:33 +00:00
|
|
|
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
|
2005-02-28 08:42:47 +00:00
|
|
|
} else {
|
2005-08-09 06:42:33 +00:00
|
|
|
/* cache is already cleared */
|
2005-08-08 13:48:33 +00:00
|
|
|
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
/* no way */
|
|
|
|
break;
|
|
|
|
}
|
2006-10-04 13:26:23 +00:00
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
return COND_RESULT_FALSE;
|
2005-02-28 08:42:47 +00:00
|
|
|
}
|
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
static cond_result_t config_check_cond_cached(server *srv, connection *con, data_config *dc) {
|
|
|
|
cond_cache_t *caches = con->cond_cache;
|
2005-08-08 13:48:33 +00:00
|
|
|
|
2005-08-09 06:42:33 +00:00
|
|
|
if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
|
|
|
|
if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
|
2005-08-08 13:48:33 +00:00
|
|
|
if (dc->next) {
|
|
|
|
data_config *c;
|
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-09 06:42:33 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s",
|
|
|
|
"setting remains of chaining to false");
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
for (c = dc->next; c; c = c->next) {
|
2005-08-09 06:42:33 +00:00
|
|
|
caches[c->context_ndx].result = COND_RESULT_FALSE;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-08-18 09:27:11 +00:00
|
|
|
caches[dc->context_ndx].comp_type = dc->comp;
|
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-09 06:42:33 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
|
|
|
|
"(uncached) result:",
|
2007-08-18 09:27:11 +00:00
|
|
|
caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
|
|
|
|
(caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2005-08-15 09:55:23 +00:00
|
|
|
} else {
|
2005-08-08 13:48:33 +00:00
|
|
|
if (con->conf.log_condition_handling) {
|
2005-08-09 06:42:33 +00:00
|
|
|
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
|
|
|
|
"(cached) result:",
|
2007-08-18 09:27:11 +00:00
|
|
|
caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
|
|
|
|
(caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
return caches[dc->context_ndx].result;
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
|
|
|
|
2007-08-18 09:27:11 +00:00
|
|
|
/**
|
|
|
|
* reset the config-cache for a named item
|
|
|
|
*
|
|
|
|
* if the item is COND_LAST_ELEMENT we reset all items
|
|
|
|
*/
|
|
|
|
void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < srv->config_context->used; i++) {
|
|
|
|
if (item == COMP_LAST_ELEMENT ||
|
|
|
|
con->cond_cache[i].comp_type == item) {
|
|
|
|
con->cond_cache[i].result = COND_RESULT_UNSET;
|
|
|
|
con->cond_cache[i].patterncount = 0;
|
|
|
|
con->cond_cache[i].comp_value = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* reset the config cache to its initial state at connection start
|
|
|
|
*/
|
2006-09-07 11:05:41 +00:00
|
|
|
void config_cond_cache_reset(server *srv, connection *con) {
|
|
|
|
size_t i;
|
|
|
|
|
2007-08-18 09:27:11 +00:00
|
|
|
config_cond_cache_reset_all_items(srv, con);
|
|
|
|
|
|
|
|
for (i = 0; i < COMP_LAST_ELEMENT; i++) {
|
|
|
|
con->conditional_is_valid[i] = 0;
|
2006-09-07 11:05:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-08 13:48:33 +00:00
|
|
|
int config_check_cond(server *srv, connection *con, data_config *dc) {
|
|
|
|
if (con->conf.log_condition_handling) {
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
|
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
|
2005-08-08 13:48:33 +00:00
|
|
|
}
|
2005-08-09 06:42:33 +00:00
|
|
|
|
|
|
|
int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n)
|
|
|
|
{
|
|
|
|
cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
|
|
|
|
if (n > cache->patterncount) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n <<= 1; /* n *= 2 */
|
|
|
|
buffer_append_string_len(buf,
|
|
|
|
cache->comp_value->ptr + cache->matches[n],
|
|
|
|
cache->matches[n + 1] - cache->matches[n]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|