Browse Source

allow _ in env. and var. and optimized matching of conditions

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@529 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.2
Jan Kneschke 17 years ago
parent
commit
360aba360f
  1. 21
      src/configfile-glue.c
  2. 16
      src/configfile.c
  3. 112
      src/configparser.y
  4. 1
      src/connections.c
  5. 2
      src/mod_rewrite.c
  6. 2
      src/network.c
  7. 2
      src/plugin.h
  8. 13
      src/response.c
  9. 8
      tests/core-var-include.t
  10. 4
      tests/var-include-sub.conf

21
src/configfile-glue.c

@ -174,18 +174,11 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
}
}
/*
* 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"))) {
if (COMP_HTTP_HOST == dc->comp) {
l = con->uri.authority;
#if 0
/* FIXME: get this working again */
@ -215,7 +208,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
break;
}
}
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPremoteip"))) {
} else if (COMP_HTTP_REMOTEIP == dc->comp) {
char *nm_slash;
/* handle remoteip limitations
*
@ -290,22 +283,22 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
buffer_copy_string(srv->cond_check_buf, s);
}
#endif
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPurl"))) {
} else if (COMP_HTTP_URL == dc->comp) {
l = con->uri.path;
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("SERVERsocket"))) {
} else if (COMP_SERVER_SOCKET == dc->comp) {
l = srv_sock->srv_token;
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPreferer"))) {
} else if (COMP_HTTP_REFERER == dc->comp) {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
l = ds->value;
}
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPcookie"))) {
} else if (COMP_HTTP_COOKIE == dc->comp) {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
l = ds->value;
}
} else if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPuseragent"))) {
} else if (COMP_HTTP_USERAGENT == dc->comp) {
data_string *ds;
if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
l = ds->value;

16
src/configfile.c

@ -266,7 +266,7 @@ int config_setup_connection(server *srv, connection *con) {
return 0;
}
int config_patch_connection(server *srv, connection *con, const char *stage, size_t stage_len) {
int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
size_t i, j;
/* skip the first, the global context */
@ -275,7 +275,7 @@ int config_patch_connection(server *srv, connection *con, const char *stage, siz
specific_config *s = srv->config_storage[i];
/* not our stage */
if (!buffer_is_equal_string(dc->comp_key, stage, stage_len)) continue;
if (comp != dc->comp) continue;
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;
@ -739,6 +739,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
for (i = 0; t->input[t->offset + i] &&
(isalnum((unsigned char)t->input[t->offset + i]) ||
t->input[t->offset + i] == '.' ||
t->input[t->offset + i] == '_' || /* for env.* */
t->input[t->offset + i] == '-'
); i++);
@ -838,19 +839,12 @@ static void context_init(server *srv, config_t *context) {
context->srv = srv;
context->ok = 1;
context->configs_stack = array_init();
context->configs_stack->is_weakref = 1;
context->basedir = buffer_init();
}
static void context_free(config_t *context) {
size_t i;
array *a = context->configs_stack;
/* don't free elements */
for (i = 0; i < a->size; i++) {
a->data[i] = NULL;
}
array_free(a);
array_free(context->configs_stack);
buffer_free(context->basedir);
}

112
src/configparser.y

@ -17,6 +17,7 @@ static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
assert(dc->context_ndx > ctx->current->context_ndx);
array_insert_unique(ctx->all_configs, (data_unset *)dc);
dc->parent = ctx->current;
array_insert_unique(dc->parent->childs, (data_unset *)dc);
}
array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
ctx->current = dc;
@ -28,30 +29,42 @@ static data_config *configparser_pop(config_t *ctx) {
return old;
}
static const data_unset *configparser_get_variable(config_t *ctx, buffer *key) {
data_unset *ds, *result;
data_config *dc;
/* return a copied variable */
static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
char *env;
if (NULL != (env = getenv(key->ptr + 4))) {
data_string *ds;
ds = data_string_init();
buffer_append_string(ds->value, env);
return (data_unset *)ds;
}
fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
ctx->ok = 0;
return NULL;
} else {
data_unset *du;
data_config *dc;
result = NULL;
#if 0
fprintf(stderr, "get var %s\n", key->ptr);
fprintf(stderr, "get var %s\n", key->ptr);
#endif
for (dc = ctx->current; dc && !result; dc = dc->parent) {
for (dc = ctx->current; dc; dc = dc->parent) {
#if 0
fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
array_print(dc->value, 0);
fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
array_print(dc->value, 0);
#endif
ds = array_get_element(dc->value, key->ptr);
if (NULL != ds) {
result = ds;
break;
if (NULL != (du = array_get_element(dc->value, key->ptr))) {
return du->copy(du);
}
}
}
if (NULL == result) {
fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
ctx->ok = 0;
return NULL;
}
return result;
}
/* op1 is to be eat/return by this function, op1->key is not cared
@ -161,7 +174,6 @@ varline ::= key(A) ASSIGN expression(B). {
varline ::= key(A) APPEND expression(B). {
array *vars = ctx->current->value;
const data_unset *var;
data_unset *du;
if (NULL != (du = array_get_element(vars, A->ptr))) {
@ -169,9 +181,8 @@ varline ::= key(A) APPEND expression(B). {
du = configparser_merge_data(ctx, du, B);
buffer_copy_string_buffer(du->key, A);
array_replace(vars, du);
} else if (NULL != (var = configparser_get_variable(ctx, A))) {
du = var->copy(var);
du = configparser_merge_data(ctx, du->copy(du), B);
} else if (NULL != (du = configparser_get_variable(ctx, A))) {
du = configparser_merge_data(ctx, du, B);
buffer_copy_string_buffer(du->key, A);
array_insert_unique(ctx->current->value, du);
} else {
@ -210,11 +221,8 @@ expression(A) ::= value(B). {
}
value(A) ::= key(B). {
const data_unset *var = configparser_get_variable(ctx, B);
if (var) {
A = var->copy(var);
}
else {
A = configparser_get_variable(ctx, B);
if (!A) {
/* make a dummy so it won't crash */
A = (data_unset *)data_string_init();
}
@ -317,48 +325,81 @@ condline(A) ::= context LCURLY metalines RCURLY. {
context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) expression(D). {
data_config *dc;
buffer *b, *rvalue;
buffer *b, *rvalue, *op;
if (ctx->ok && D->type != TYPE_STRING) {
fprintf(stderr, "rvalue must be string");
ctx->ok = 0;
}
b = buffer_init();
buffer_copy_string_buffer(b, ctx->current->key);
buffer_append_string(b, "/");
buffer_append_string_buffer(b, B);
buffer_append_string_buffer(b, C);
switch(E) {
case CONFIG_COND_NE:
buffer_append_string_len(b, CONST_STR_LEN("!="));
op = buffer_init_string("!=");
break;
case CONFIG_COND_EQ:
buffer_append_string_len(b, CONST_STR_LEN("=="));
op = buffer_init_string("==");
break;
case CONFIG_COND_NOMATCH:
buffer_append_string_len(b, CONST_STR_LEN("!~"));
op = buffer_init_string("!~");
break;
case CONFIG_COND_MATCH:
buffer_append_string_len(b, CONST_STR_LEN("=~"));
op = buffer_init_string("=~");
break;
default:
buffer_append_string_len(b, CONST_STR_LEN("??"));
assert(0);
break;
}
b = buffer_init();
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, op);
rvalue = ((data_string*)D)->value;
buffer_append_string_buffer(b, rvalue);
if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
configparser_push(ctx, dc, 0);
} else {
struct {
comp_key_t comp;
char *comp_key;
size_t len;
} comps[] = {
{ COMP_SERVER_SOCKET, CONST_STR_LEN("SERVER[\"socket\"]" ) },
{ COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) },
{ COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) },
{ COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) },
{ COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) },
{ COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) },
{ COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) },
{ COMP_UNSET, NULL, 0 },
};
size_t i;
dc = data_config_init();
buffer_copy_string_buffer(dc->key, b);
buffer_copy_string_buffer(dc->op, op);
buffer_copy_string_buffer(dc->comp_key, B);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
buffer_append_string_buffer(dc->comp_key, C);
buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
dc->cond = E;
for (i = 0; comps[i].comp_key; i ++) {
if (buffer_is_equal_string(
dc->comp_key, comps[i].comp_key, comps[i].len)) {
dc->comp = comps[i].comp;
break;
}
}
if (COMP_UNSET == dc->comp) {
fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
ctx->ok = 0;
}
switch(E) {
case CONFIG_COND_NE:
case CONFIG_COND_EQ:
@ -408,6 +449,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) expression(
}
buffer_free(b);
buffer_free(op);
buffer_free(B);
B = NULL;
buffer_free(C);

1
src/connections.c

@ -653,6 +653,7 @@ void connections_free(server *srv) {
CLEAN(error_handler);
#undef CLEAN
free(con->plugin_ctx);
free(con->cond_results_cache);
free(con);
}

2
src/mod_rewrite.c

@ -276,7 +276,7 @@ static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_dat
data_config *dc = (data_config *)srv->config_context->data[i];
s = p->config_storage[i];
if (buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("HTTPurl"))) continue;
if (COMP_HTTP_URL == dc->comp) continue;
/* condition didn't match */
if (!config_check_cond(srv, con, dc)) continue;

2
src/network.c

@ -386,7 +386,7 @@ int network_init(server *srv) {
specific_config *s = srv->config_storage[i];
/* not our stage */
if (!buffer_is_equal_string(dc->comp_key, CONST_STR_LEN("SERVERsocket"))) continue;
if (COMP_SERVER_SOCKET != dc->comp) continue;
if (dc->cond != CONFIG_COND_EQ) {
log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");

2
src/plugin.h

@ -87,7 +87,7 @@ handler_t plugins_call_cleanup(server *srv);
int config_insert_values_global(server *srv, array *ca, const config_values_t *cv);
int config_insert_values_internal(server *srv, array *ca, const config_values_t *cv);
int config_setup_connection(server *srv, connection *con);
int config_patch_connection(server *srv, connection *con, const char *stage, size_t stage_len);
int config_patch_connection(server *srv, connection *con, comp_key_t comp);
int config_check_cond(server *srv, connection *con, data_config *dc);
#endif

13
src/response.c

@ -974,7 +974,8 @@ handler_t http_response_prepare(server *srv, connection *con) {
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
config_patch_connection(srv, con, CONST_STR_LEN("SERVERsocket")); /* SERVERsocket */
config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
/**
* prepare strings
@ -1001,10 +1002,10 @@ handler_t http_response_prepare(server *srv, connection *con) {
buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
config_patch_connection(srv, con, CONST_STR_LEN("HTTPhost")); /* Host: */
config_patch_connection(srv, con, CONST_STR_LEN("HTTPreferer")); /* Referer: */
config_patch_connection(srv, con, CONST_STR_LEN("HTTPuseragent")); /* User-Agent: */
config_patch_connection(srv, con, CONST_STR_LEN("HTTPcookie")); /* Cookie: */
config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
/** extract query string from request.uri */
if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
@ -1077,7 +1078,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
*
*/
config_patch_connection(srv, con, CONST_STR_LEN("HTTPurl")); /* HTTPurl */
config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
switch(r = plugins_call_handle_uri_clean(srv, con)) {
case HANDLER_GO_ON:

8
tests/core-var-include.t

@ -8,12 +8,14 @@ BEGIN {
use strict;
use IO::Socket;
use Test::More tests => 15;
use Test::More tests => 16;
use LightyTest;
my $tf = LightyTest->new();
my $t;
$ENV{"env_test"} = "good_env";
$tf->{CONFIGFILE} = 'var-include.conf';
ok($tf->start_proc == 0, "Starting lighttpd") or die();
@ -34,12 +36,15 @@ my $tests = {
"servername3" => "/good_" . $server_name . "/",
"var.myvar" => "/good_var_myvar" . $myvar,
"myvar" => "/good_myvar" . $myvar,
"env" => "/" . $ENV{"env_test"},
"number1" => "/good_number" . "1",
"number2" => "1" . "/good_number",
"array_append" => "/good_array_append",
"string_append" => "/good_" . $mystr,
"number_append" => "/good_" . "2"
};
foreach my $test (keys %{ $tests }) {
my $expect = $tests->{$test};
$t->{REQUEST} = ( <<EOF
@ -52,3 +57,4 @@ EOF
}
ok($tf->stop_proc == 0, "Stopping lighttpd");

4
tests/var-include-sub.conf

@ -10,7 +10,11 @@ $HTTP["host"] =~ "^" + server.name + "$" {
"^/myvar$" => "/good_myvar" + myvar,
"^/number1$" => "/good_number" + one,
"^/number2$" => one + "/good_number",
"^/env$" => "/" + env.env_test,
)
num = 1
num2 = 2
num2 += 1
# without var prefix
mystr = "string"
mystr += "_append"

Loading…
Cancel
Save