Browse Source

added nested conditionals (merged [298])

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@519 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.2
Jan Kneschke 17 years ago
parent
commit
8073d5fe9f
  1. 4
      src/Makefile.am
  2. 12
      src/array.c
  3. 21
      src/array.h
  4. 2
      src/base.h
  5. 190
      src/configfile-glue.c
  6. 116
      src/configfile.c
  7. 6
      src/configfile.h
  8. 105
      src/configparser.y
  9. 1
      src/connections.c
  10. 9
      src/data_config.c
  11. 2
      src/network.c
  12. 11
      tests/LightyTest.pm
  13. 2
      tests/Makefile.am
  14. 59
      tests/condition.conf
  15. 53
      tests/core-condition.t

4
src/Makefile.am

@ -24,7 +24,7 @@ mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
$(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
endif
config.c: configparser.h
configfile.c: configparser.h
mod_ssi_expr.c: mod_ssi_exprparser.h
common_src=buffer.c log.c \
@ -47,7 +47,7 @@ src = server.c response.c connections.c network.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
config.c request.c
configfile.c request.c
spawn_fcgi_SOURCES=spawn-fcgi.c

12
src/array.c

@ -45,6 +45,18 @@ void array_reset(array *a) {
a->used = 0;
}
data_unset *array_pop(array *a) {
data_unset *du;
assert(a->used != 0);
a->used --;
du = a->data[a->used];
a->data[a->used] = NULL;
return du;
}
static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
int ndx = -1;
int i, pos = 0;

21
src/array.h

@ -62,12 +62,14 @@ typedef struct {
data_array *data_array_init(void);
typedef enum { CONFIG_COND_UNSET, CONFIG_COND_EQ, CONFIG_COND_MATCH, CONFIG_COND_NE, CONFIG_COND_NOMATCH } config_cond_t;
typedef enum { COND_RESULT_FALSE, COND_RESULT_TRUE, COND_RESULT_UNSET } cond_result_t;
/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
* comp_key cond string/regex
*/
typedef struct {
typedef struct _data_config data_config;
struct _data_config {
DATA_UNSET;
array *value;
@ -75,14 +77,20 @@ typedef struct {
buffer *comp_key;
config_cond_t cond;
int context_ndx; /* more or less like an id */
array *childs;
/* nested */
data_config *parent;
/* for chaining only */
data_config *prev;
data_config *next;
union {
buffer *string;
buffer *string;
#ifdef HAVE_PCRE_H
pcre *regex;
pcre *regex;
pcre_extra *regex_study;
#endif
} match;
} data_config;
};
data_config *data_config_init(void);
@ -115,6 +123,7 @@ array *array_init(void);
void array_free(array *a);
void array_reset(array *a);
int array_insert_unique(array *a, data_unset *str);
data_unset *array_pop(array *a);
int array_print(array *a, int depth);
data_unset *array_get_unused_element(array *a, data_type_t t);
data_unset *array_get_element(array *a, const char *key);

2
src/base.h

@ -251,6 +251,7 @@ typedef struct {
unsigned short log_request_header;
unsigned short log_request_handling;
unsigned short log_response_header;
unsigned short log_condition_handling;
/* server wide */
@ -360,6 +361,7 @@ typedef struct {
void **plugin_ctx; /* plugin connection specific config */
specific_config conf; /* global connection specific config */
cond_result_t *cond_results_cache;
buffer *server_name;

190
src/configfile-glue.c

@ -3,6 +3,7 @@
#include "buffer.h"
#include "array.h"
#include "log.h"
#include "plugin.h"
/**
* like all glue code this file contains functions which
@ -146,15 +147,149 @@ int config_insert_values_global(server *srv, array *ca, const config_values_t cv
return config_insert_values_internal(srv, ca, cv);
}
int config_check_cond(server *srv, connection *con, data_config *dc) {
static int config_check_cond_cached(server *srv, connection *con, data_config *dc);
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
buffer *l;
server_socket *srv_sock = con->srv_socket;
/* check parent first */
if (dc->parent) {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->string);
}
if (!config_check_cond_cached(srv, con, dc->parent)) {
return COND_RESULT_FALSE;
}
}
if (dc->prev) {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->string);
}
/* make sure prev is checked first */
config_check_cond_cached(srv, con, dc->prev);
/* one of prev set me to FALSE */
if (con->cond_results_cache[dc->context_ndx] == COND_RESULT_FALSE) {
return COND_RESULT_FALSE;
}
}
/*
* OPTIMIZE
*
* - replace all is_equal be simple == to an enum
*
*/
/* pass the rules */
l = srv->empty_string;
if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPhost"))) {
l = con->uri.authority;
#if 0
/* FIXME: get this working again */
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->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_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;
if (*(nm_slash+1) == '\0') {
log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
return COND_RESULT_FALSE;
}
nm_bits = strtol(nm_slash + 1, &err, 10);
if (*err) {
log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
return COND_RESULT_FALSE;
}
/* take IP convert to the native */
buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
#ifdef __WIN32
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);
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);
return COND_RESULT_FALSE;
}
#endif
/* build netmask */
nm = htonl(~((1 << (32 - nm_bits)) - 1));
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 {
const char *s;
#ifdef HAVE_IPV6
char b2[INET6_ADDRSTRLEN + 1];
s = inet_ntop(con->dst_addr.plain.sa_family,
con->dst_addr.plain.sa_family == AF_INET6 ?
(const void *) &(con->dst_addr.ipv6.sin6_addr) :
(const void *) &(con->dst_addr.ipv4.sin_addr),
b2, sizeof(b2)-1);
#else
s = inet_ntoa(con->dst_addr.ipv4.sin_addr);
#endif
buffer_copy_string(srv->cond_check_buf, s);
}
#endif
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPurl"))) {
l = con->uri.path;
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("SERVERsocket"))) {
@ -176,16 +311,19 @@ int config_check_cond(server *srv, connection *con, data_config *dc) {
l = ds->value;
}
} else {
return 0;
return COND_RESULT_FALSE;
}
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key, "(", l, ") compare to ", dc->string);
}
switch(dc->cond) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
if (buffer_is_equal(l, dc->match.string)) {
return (dc->cond == CONFIG_COND_EQ) ? 1 : 0;
if (buffer_is_equal(l, dc->string)) {
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
return (dc->cond == CONFIG_COND_EQ) ? 0 : 1;
return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
}
break;
#ifdef HAVE_PCRE_H
@ -195,14 +333,13 @@ int config_check_cond(server *srv, connection *con, data_config *dc) {
int ovec[N * 3];
int n;
n = pcre_exec(dc->match.regex, NULL, l->ptr, l->used - 1, 0, 0, ovec, N * 3);
n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0, ovec, N * 3);
if (n > 0) {
return (dc->cond == CONFIG_COND_MATCH) ? 1 : 0;
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
return (dc->cond == CONFIG_COND_MATCH) ? 0 : 1;
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
}
break;
}
#endif
@ -211,6 +348,39 @@ int config_check_cond(server *srv, connection *con, data_config *dc) {
break;
}
return 0;
return COND_RESULT_FALSE;
}
static int config_check_cond_cached(server *srv, connection *con, data_config *dc) {
cond_result_t *cache = con->cond_results_cache;
if (cache[dc->context_ndx] == COND_RESULT_UNSET) {
if (COND_RESULT_TRUE == (cache[dc->context_ndx] = config_check_cond_nocache(srv, con, dc))) {
if (dc->next) {
data_config *c;
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "setting remains of chaining to FALSE");
}
for (c = dc->next; c; c = c->next) {
cache[c->context_ndx] = COND_RESULT_FALSE;
}
}
}
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dsd", dc->context_ndx, "(uncached) result:", cache[dc->context_ndx]);
}
}
else {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dsd", dc->context_ndx, "(cached) result:", cache[dc->context_ndx]);
}
}
return cache[dc->context_ndx];
}
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 ===");
}
return config_check_cond_cached(srv, con, dc);
}

116
src/config.c → src/configfile.c

@ -70,7 +70,6 @@ static int config_insert(server *srv) {
{ "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
{ "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
{ "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
{ "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
{ "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 39 */
@ -81,6 +80,8 @@ static int config_insert(server *srv) {
{ "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
{ "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
{ "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 45 */
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@ -191,6 +192,8 @@ static int config_insert(server *srv) {
cv[41].destination = s->dirlist_encoding;
cv[43].destination = &(s->range_requests);
cv[45].destination = &(s->log_condition_handling);
srv->config_storage[i] = s;
if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
@ -222,6 +225,11 @@ static int config_insert(server *srv) {
#define PATCH(x) con->conf.x = s->x
int config_setup_connection(server *srv, connection *con) {
specific_config *s = srv->config_storage[0];
int i;
for (i = srv->config_context->used - 1; i >= 0; i --) {
con->cond_results_cache[i] = COND_RESULT_UNSET;
}
PATCH(allow_http11);
PATCH(mimetypes);
@ -250,6 +258,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(log_request_header);
PATCH(log_response_header);
PATCH(log_request_handling);
PATCH(log_condition_handling);
PATCH(log_file_not_found);
PATCH(range_requests);
@ -325,6 +334,8 @@ int config_patch_connection(server *srv, connection *con, const char *stage, siz
PATCH(log_request_header);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-response-header"))) {
PATCH(log_response_header);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
PATCH(log_condition_handling);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
PATCH(log_file_not_found);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
@ -356,6 +367,27 @@ typedef struct {
int in_cond;
} tokenizer_t;
static int config_skip_newline(tokenizer_t *t) {
int skipped = 1;
assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
if (t->input[t->offset] == '\r' && t->input[t->offset + 1] == '\n') {
skipped ++;
t->offset ++;
}
t->offset ++;
return skipped;
}
static int config_skip_comment(tokenizer_t *t) {
int i;
assert(t->input[t->offset] == '#');
for (i = 1; t->input[t->offset + i] &&
(t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
i++);
t->offset += i;
return i;
}
static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
int tid = 0;
size_t i;
@ -447,39 +479,41 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
t->offset++;
t->line_pos++;
break;
case '\n':
case '\r':
if (t->in_brace == 0) {
if (t->input[t->offset + 1] == '\n') {
t->in_key = 1;
t->offset += 2;
tid = TK_EOL;
t->line++;
t->line_pos = 1;
buffer_copy_string(token, "(EOL)");
} else {
log_error_write(srv, __FILE__, __LINE__, "sdsds",
"line:", t->line, "pos:", t->line_pos,
"CR without LF");
return 0;
int done = 0;
while (!done) {
switch (t->input[t->offset]) {
case '\r':
case '\n':
config_skip_newline(t);
t->line_pos = 1;
t->line++;
break;
case '#':
t->line_pos += config_skip_comment(t);
break;
case '\t':
case ' ':
t->offset++;
t->line_pos++;
break;
default:
done = 1;
}
}
} else {
t->offset++;
t->line_pos++;
}
break;
case '\n':
if (t->in_brace == 0) {
t->in_key = 1;
tid = TK_EOL;
buffer_copy_string(token, "(EOL)");
} else {
config_skip_newline(t);
t->line_pos = 1;
t->line++;
}
t->line++;
t->line_pos = 1;
t->offset++;
break;
case ',':
if (t->in_brace > 0) {
@ -559,6 +593,12 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
buffer_copy_string(token, "$");
break;
case '|':
t->offset++;
tid = TK_OR;
buffer_copy_string(token, "|");
break;
case '{':
t->offset++;
@ -578,6 +618,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
buffer_copy_string(token, "}");
break;
case '[':
t->offset++;
@ -596,11 +637,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
break;
case '#':
for (i = 1; t->input[t->offset + i] &&
(t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
i++);
t->offset += i;
t->line_pos += config_skip_comment(t);
break;
default:
@ -721,14 +758,16 @@ int config_read(server *srv, const char *fn) {
t.in_cond = 0;
context.ok = 1;
context.config = srv->config_context;
context.all_configs = srv->config_context;
context.configs_stack = array_init();
dc = data_config_init();
buffer_copy_string(dc->key, "global");
array_insert_unique(srv->config_context, (data_unset *)dc);
context.ctx_name = dc->key;
context.ctx_config = dc->value;
assert(context.all_configs->used == 0);
dc->context_ndx = context.all_configs->used;
array_insert_unique(context.all_configs, (data_unset *)dc);
context.current = dc;
/* default context */
srv->config = dc->value;
@ -760,6 +799,9 @@ int config_read(server *srv, const char *fn) {
return -1;
}
assert(context.configs_stack->used == 0);
array_free(context.configs_stack);
if (0 != config_insert(srv)) {
return -1;
}

6
src/configfile.h

@ -6,9 +6,9 @@
typedef struct {
int ok;
array *config;
buffer *ctx_name;
array *ctx_config;
array *all_configs;
array *configs_stack; /* to parse nested block */
data_config *current; /* current started with { */
} config_t;
void *configparserAlloc(void *(*mallocProc)(size_t));

105
src/configparser.y

@ -10,6 +10,22 @@
#include "configfile.h"
#include "buffer.h"
#include "array.h"
static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
if (isnew) {
dc->context_ndx = ctx->all_configs->used;
array_insert_unique(ctx->all_configs, (data_unset *)dc);
}
array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
ctx->current = dc;
}
static data_config *configparser_pop(config_t *ctx) {
data_config *old = ctx->current;
ctx->current = (data_config *) array_pop(ctx->configs_stack);
return old;
}
}
%parse_failure {
@ -20,23 +36,25 @@ input ::= metalines.
metalines ::= metalines metaline.
metalines ::= .
metaline ::= varline.
metaline ::= condline.
metaline ::= condlines EOL.
metaline ::= EOL.
%type value {data_unset *}
%type aelement {data_unset *}
%type aelements {array *}
%type array {array *}
%type condline {data_config *}
%type condlines {data_config *}
%type cond {config_cond_t }
%token_destructor { buffer_free($$); }
varline ::= key(A) ASSIGN value(B). {
buffer_copy_string_buffer(B->key, A);
if (NULL == array_get_element(ctx->ctx_config, B->key->ptr)) {
array_insert_unique(ctx->ctx_config, B);
if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
array_insert_unique(ctx->current->value, B);
} else {
fprintf(stderr, "Duplicate config variable in conditional %s: %s\n",
ctx->ctx_name->ptr, B->key->ptr);
fprintf(stderr, "Duplicate config variable in conditional 1 %s: %s\n",
ctx->current->key->ptr, B->key->ptr);
ctx->ok = 0;
B->free(B);
}
@ -103,13 +121,38 @@ aelement(A) ::= STRING(B) ARRAY_ASSIGN value(C). {
A = C;
C = NULL;
}
condline ::= context LCURLY metalines RCURLY EOL. {
data_config *dc;
eols ::= EOL.
eols ::= .
condlines(A) ::= condlines(B) eols OR condline(C). {
assert(B->context_ndx < C->context_ndx);
C->prev = B;
B->next = C;
A = C;
B = NULL;
C = NULL;
}
condlines(A) ::= condline(B). {
A = B;
B = NULL;
}
condline(A) ::= context LCURLY metalines RCURLY. {
data_config *parent, *cur;
dc = (data_config *)array_get_element(ctx->config, "global");
assert(dc);
ctx->ctx_name = dc->key;
ctx->ctx_config = dc->value;
cur = ctx->current;
configparser_pop(ctx);
parent = ctx->current;
assert(cur && parent);
if (0 != parent->context_ndx) { /* not global */
assert(cur->context_ndx > parent->context_ndx);
cur->parent = parent;
}
A = cur;
}
context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D). {
@ -117,14 +160,15 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D).
buffer *b;
b = buffer_init();
buffer_copy_string_buffer(b, B);
buffer_copy_string_buffer(b, ctx->current->key);
buffer_append_string(b, "/");
buffer_append_string_buffer(b, B);
buffer_append_string_buffer(b, C);
buffer_append_string_buffer(b, D);
buffer_append_long(b, E);
if (NULL != (dc = (data_config *)array_get_element(ctx->config, b->ptr))) {
ctx->ctx_name = dc->key;
ctx->ctx_config = dc->value;
if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
configparser_push(ctx, dc, 0);
} else {
dc = data_config_init();
@ -136,30 +180,43 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D).
switch(E) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
dc->match.string = buffer_init_string(D->ptr);
dc->string = buffer_init_string(D->ptr);
break;
#ifdef HAVE_PCRE_H
case CONFIG_COND_NOMATCH:
case CONFIG_COND_MATCH: {
#ifdef HAVE_PCRE_H
const char *errptr;
int erroff;
if (NULL == (dc->match.regex =
if (NULL == (dc->regex =
pcre_compile(D->ptr, 0, &errptr, &erroff, NULL))) {
dc->match.string = buffer_init_string(errptr);
dc->string = buffer_init_string(errptr);
dc->cond = CONFIG_COND_UNSET;
ctx->ok = 0;
} else if (NULL == (dc->regex_study = pcre_study(dc->regex, 0, &errptr)) &&
errptr != NULL) {
fprintf(stderr, "studying regex failed: %s -> %s\n",
D->ptr, errptr);
ctx->ok = 0;
}
#else
fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
"is missing: $%s[%s]\n",
B->ptr, C->ptr);
ctx->ok = 0;
#endif
break;
}
#endif
default:
fprintf(stderr, "unknown condition for $%s[%s]\n",
B->ptr, C->ptr);
ctx->ok = 0;
break;
}
array_insert_unique(ctx->config, (data_unset *)dc);
ctx->ctx_name = dc->key;
ctx->ctx_config = dc->value;
configparser_push(ctx, dc, 1);
}
buffer_free(b);
buffer_free(B);

1
src/connections.c

@ -603,6 +603,7 @@ connection *connection_init(server *srv) {
con->plugin_ctx = calloc(srv->plugins.used + 1, sizeof(void *));
con->cond_results_cache = calloc(srv->config_context->used, sizeof(cond_result_t));
config_setup_connection(srv, con);
return con;

9
src/data_config.c

@ -12,14 +12,11 @@ static void data_config_free(data_unset *d) {
array_free(ds->value);
switch(ds->cond) {
case CONFIG_COND_EQ: buffer_free(ds->match.string); break;
if (ds->string) buffer_free(ds->string);
#ifdef HAVE_PCRE_H
case CONFIG_COND_MATCH: pcre_free(ds->match.regex); break;
if (ds->regex) pcre_free(ds->regex);
if (ds->regex_study) pcre_free(ds->regex_study);
#endif
default:
break;
}
free(d);
}

2
src/network.c

@ -394,7 +394,7 @@ int network_init(server *srv) {
return -1;
}
if (0 != network_server_init(srv, dc->match.string, s)) {
if (0 != network_server_init(srv, dc->string, s)) {
return -1;
}
}

11
tests/LightyTest.pm

@ -69,11 +69,14 @@ sub start_proc {
system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$pwd.'/'.$self->{BASEDIR}.'/tests/#" > /tmp/cfg.file');
unlink($self->{LIGHTTPD_PIDFILE});
system($self->{LIGHTTPD_PATH}." -f /tmp/cfg.file");
# system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$lighttpd_path." -D -f /tmp/cfg.file &");
#
if (1) {
system($self->{LIGHTTPD_PATH}." -f /tmp/cfg.file");
select(undef, undef, undef, 0.1);
} else {
system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f /tmp/cfg.file &");
select(undef, undef, undef, 1);
}
select(undef, undef, undef, 0.1);
# sleep(1);

2
tests/Makefile.am

@ -22,6 +22,8 @@ CONFS=fastcgi-10.conf \
fastcgi-13.conf \
bug-06.conf \
bug-12.conf \
condition.conf \
core-condition.t \
core-request.t \
core-response.t \
core.t \

59
tests/condition.conf

@ -0,0 +1,59 @@
debug.log-request-handling = "enable"
debug.log-condition-handling = "enable"
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
server.pid-file = "/tmp/lighttpd/lighttpd.pid"
## bind to port (default: 80)
server.port = 2048
## bind to localhost (default: all interfaces)
server.bind = "localhost"
server.errorlog = "/tmp/lighttpd/logs/lighttpd.error.log"
server.name = "www.example.org"
server.tag = "Apache 1.3.29"
server.modules = (
"mod_access",
"mod_accesslog" )
######################## MODULE CONFIG ############################
accesslog.filename = "/tmp/lighttpd/logs/lighttpd.access.log"
mimetype.assign = ( ".html" => "text/html" )
# ban first, unban later
url.access-deny = ( "index.html" )
$HTTP["host"] == "www.example.org" {
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
server.name = "www.example.org"
}
| $HTTP["host"] == "test1.example.org" {
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
server.name = "test1.example.org"
url.access-deny = ( "nothing" )
}
# comments
| $HTTP["host"] == "test2.example.org" {
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
server.name = "test2.example.org"
url.access-deny = ( "nothing" )
}
# comments
| $HTTP["host"] == "test3.example.org" {
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
server.name = "test3.example.org"
# comments
url.access-deny = ( "nothing" )
$HTTP["url"] == "/index.html" {
url.access-deny = ( "index.html" )
}
}

53
tests/core-condition.t

@ -0,0 +1,53 @@
#! /usr/bin/perl -w
BEGIN {
# add current source dir to the include-path
# we need this for make distcheck
(my $srcdir = $0) =~ s#/[^/]+$#/#;
unshift @INC, $srcdir;
}
use strict;
use IO::Socket;
use Test::More tests => 6;
use LightyTest;
my $tf = LightyTest->new();
my $t;
$tf->{CONFIGFILE} = 'condition.conf';
ok($tf->start_proc == 0, "Starting lighttpd") or die();
$t->{REQUEST} = ( <<EOF
GET /index.html HTTP/1.0
Host: www.example.org
EOF
);
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } );
ok($tf->handle_http($t) == 0, 'config deny');
$t->{REQUEST} = ( <<EOF
GET /index.html HTTP/1.0
Host: test1.example.org
EOF
);
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } );
ok($tf->handle_http($t) == 0, '2nd child of chaining');
$t->{REQUEST} = ( <<EOF
GET /index.html HTTP/1.0
Host: test2.example.org
EOF
);
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } );
ok($tf->handle_http($t) == 0, '3rd child of chaining');
$t->{REQUEST} = ( <<EOF
GET /index.html HTTP/1.0
Host: test3.example.org
EOF
);
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } );
ok($tf->handle_http($t) == 0, 'nesting');
ok($tf->stop_proc == 0, "Stopping lighttpd");
Loading…
Cancel
Save