user defined variable, compute on parsing: string+string, int+int, array+array, var+=expression.
"include" sub configuration file. (merged ([308], [309], [306], [305]) git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@520 152afb58-edef-0310-8abb-c4023f1b3aa9svn/tags/lighttpd-1.4.2
parent
8073d5fe9f
commit
6e78c2c8df
|
@ -96,7 +96,11 @@ AC_ARG_WITH(mysql,
|
|||
if test \! -x $withval; then
|
||||
echo "--with-mysql=path-to-mysql_config"
|
||||
fi
|
||||
MYSQL_INCLUDE="`$withval --cflags | sed s/\'//g`"
|
||||
if $withval | grep -- '--include' ; then
|
||||
MYSQL_INCLUDE="`$withval --include | sed s/\'//g`"
|
||||
else
|
||||
MYSQL_INCLUDE="`$withval --cflags | sed s/\'//g`"
|
||||
fi
|
||||
MYSQL_LIBS="`$withval --libs | sed s/\'//g`"
|
||||
|
||||
AC_MSG_RESULT(yes)
|
||||
|
|
|
@ -26,13 +26,15 @@ Basic Syntax
|
|||
|
||||
A BNF like notation: ::
|
||||
|
||||
option : NAME = VARIABLE
|
||||
option : NAME = VALUE
|
||||
merge : NAME += VALUE
|
||||
NAME : modulename.key
|
||||
VARIABLE : ( <string> | <integer> | <boolean> | <array> )
|
||||
VALUE : ( <string> | <integer> | <boolean> | <array> | VALUE [ + VALUE ]*)
|
||||
<string> : "text"
|
||||
<integer>: digit*
|
||||
<boolean>: ( "enable" | "disable" )
|
||||
<array> : "(" [ <string> "=>" ] <variable> [, [ <string> "=>" ] <variable> ]* ")"
|
||||
<array> : "(" [ <string> "=>" ] <value> [, [ <string> "=>" ] <value> ]* ")"
|
||||
INCLUDE : "include" VALUE
|
||||
|
||||
Example
|
||||
-------
|
||||
|
@ -50,7 +52,13 @@ Example
|
|||
|
||||
# enable directory listings
|
||||
server.dir-listing = "enable"
|
||||
|
||||
|
||||
# variables, computed when config is read.
|
||||
var.mymodule = "foo"
|
||||
server.modules += ( "mod_" + var.mymodule )
|
||||
|
||||
# include, relative to dirname of main config file
|
||||
include "mime.types.conf"
|
||||
|
||||
|
||||
Conditional Configuration
|
||||
|
@ -63,6 +71,12 @@ Most options can be configured conditionally by using the following syntax
|
|||
|
||||
<field> <operator> <value> {
|
||||
...
|
||||
<field> <operator> <value> {
|
||||
... nesting: match only when parent match
|
||||
}
|
||||
}
|
||||
| <field> <operator> <value> {
|
||||
... else if
|
||||
}
|
||||
|
||||
where <field> is one of one of the following:
|
||||
|
|
|
@ -283,3 +283,21 @@ $HTTP["url"] =~ "\.pdf$" {
|
|||
## don't forget to add index.cml to server.indexfiles
|
||||
# cml.extension = ".cml"
|
||||
# cml.memcache-hosts = ( "127.0.0.1:11211" )
|
||||
|
||||
#### variable usage:
|
||||
## variable name without "." is auto prefixed by "var." and becomes "var.bar"
|
||||
#bar = 1
|
||||
#var.mystring = "foo"
|
||||
|
||||
## integer add
|
||||
#bar += 1
|
||||
## string concat, with integer cast as string, result: "www.foo1.com"
|
||||
#server.name = "www." + mystring + var.bar + ".com"
|
||||
## array merge
|
||||
#index-file.names = (foo + ".php") + index-file.names
|
||||
#index-file.names += (foo + ".php")
|
||||
|
||||
#### include
|
||||
#include /etc/lighttpd/lighttpd-inc.conf
|
||||
## same as above if you run: "lighttpd -f /etc/lighttpd/lighttpd.conf"
|
||||
#include "lighttpd-inc.conf"
|
||||
|
|
34
src/array.c
34
src/array.c
|
@ -20,6 +20,26 @@ array *array_init(void) {
|
|||
return a;
|
||||
}
|
||||
|
||||
array *array_init_array(array *src) {
|
||||
size_t i;
|
||||
array *a = array_init();
|
||||
|
||||
a->used = src->used;
|
||||
a->size = src->size;
|
||||
a->next_power_of_2 = src->next_power_of_2;
|
||||
a->unique_ndx = src->unique_ndx;
|
||||
|
||||
a->data = malloc(sizeof(*src->data) * src->size);
|
||||
for (i = 0; i < src->size; i++) {
|
||||
if (src->data[i]) a->data[i] = src->data[i]->copy(src->data[i]);
|
||||
else a->data[i] = NULL;
|
||||
}
|
||||
|
||||
a->sorted = malloc(sizeof(*src->sorted) * src->size);
|
||||
memcpy(a->sorted, src->sorted, sizeof(*src->sorted) * src->size);
|
||||
return a;
|
||||
}
|
||||
|
||||
void array_free(array *a) {
|
||||
size_t i;
|
||||
if (!a) return;
|
||||
|
@ -122,6 +142,20 @@ data_unset *array_get_unused_element(array *a, data_type_t t) {
|
|||
return ds;
|
||||
}
|
||||
|
||||
/* replace or insert data, return the old one with the same key */
|
||||
data_unset *array_replace(array *a, data_unset *du) {
|
||||
int ndx;
|
||||
if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
|
||||
array_insert_unique(a, du);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
data_unset *old = a->data[ndx];
|
||||
a->data[ndx] = du;
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
int array_insert_unique(array *a, data_unset *str) {
|
||||
int ndx = -1;
|
||||
int pos = 0;
|
||||
|
|
|
@ -14,6 +14,7 @@ typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_COUNT, TYPE_ARRAY, TYPE_INTEGER, TY
|
|||
#define DATA_UNSET \
|
||||
data_type_t type; \
|
||||
buffer *key; \
|
||||
struct data_unset *(*copy)(struct data_unset *src); \
|
||||
void (* free)(struct data_unset *p); \
|
||||
void (* reset)(struct data_unset *p); \
|
||||
int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
|
||||
|
@ -120,6 +121,7 @@ typedef struct {
|
|||
data_fastcgi *data_fastcgi_init(void);
|
||||
|
||||
array *array_init(void);
|
||||
array *array_init_array(array *a);
|
||||
void array_free(array *a);
|
||||
void array_reset(array *a);
|
||||
int array_insert_unique(array *a, data_unset *str);
|
||||
|
@ -127,6 +129,7 @@ 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);
|
||||
data_unset *array_replace(array *a, data_unset *du);
|
||||
int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
|
||||
void array_print_indent(int depth);
|
||||
|
||||
|
|
|
@ -29,6 +29,12 @@ buffer* buffer_init(void) {
|
|||
return b;
|
||||
}
|
||||
|
||||
buffer *buffer_init_buffer(buffer *src) {
|
||||
buffer *b = buffer_init();
|
||||
buffer_copy_string_buffer(b, src);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* free the buffer
|
||||
*
|
||||
|
|
|
@ -39,6 +39,7 @@ void buffer_array_reset(buffer_array *b);
|
|||
buffer *buffer_array_append_get_buffer(buffer_array *b);
|
||||
|
||||
buffer* buffer_init(void);
|
||||
buffer* buffer_init_buffer(buffer *b);
|
||||
buffer* buffer_init_string(const char *str);
|
||||
void buffer_free(buffer *b);
|
||||
void buffer_reset(buffer *b);
|
||||
|
|
|
@ -153,7 +153,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
|
|||
buffer *l;
|
||||
server_socket *srv_sock = con->srv_socket;
|
||||
/* check parent first */
|
||||
if (dc->parent) {
|
||||
if (dc->parent && dc->parent->context_ndx) {
|
||||
if (con->conf.log_condition_handling) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->string);
|
||||
}
|
||||
|
|
312
src/configfile.c
312
src/configfile.c
|
@ -355,7 +355,9 @@ typedef struct {
|
|||
int foo;
|
||||
int bar;
|
||||
|
||||
char *input;
|
||||
buffer *file;
|
||||
stream s;
|
||||
const char *input;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
|
||||
|
@ -367,6 +369,42 @@ typedef struct {
|
|||
int in_cond;
|
||||
} tokenizer_t;
|
||||
|
||||
static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const char *fn) {
|
||||
if (buffer_is_empty(basedir) &&
|
||||
(fn[0] == '/' || fn[0] == '\\') &&
|
||||
(fn[0] == '.' && (fn[1] == '/' || fn[1] == '\\'))) {
|
||||
t->file = buffer_init_string(fn);
|
||||
} else {
|
||||
t->file = buffer_init_buffer(basedir);
|
||||
buffer_append_string(t->file, fn);
|
||||
}
|
||||
|
||||
if (0 != stream_open(&(t->s), t->file)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbss",
|
||||
"opening configfile ", t->file, "failed:", strerror(errno));
|
||||
buffer_free(t->file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
t->input = t->s.start;
|
||||
t->offset = 0;
|
||||
t->size = t->s.size;
|
||||
t->line = 1;
|
||||
t->line_pos = 1;
|
||||
|
||||
t->in_key = 1;
|
||||
t->in_brace = 0;
|
||||
t->in_cond = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tokenizer_close(server *srv, tokenizer_t *t) {
|
||||
UNUSED(srv);
|
||||
|
||||
buffer_free(t->file);
|
||||
return stream_close(&(t->s));
|
||||
}
|
||||
|
||||
static int config_skip_newline(tokenizer_t *t) {
|
||||
int skipped = 1;
|
||||
assert(t->input[t->offset] == '\r' || t->input[t->offset] == '\n');
|
||||
|
@ -394,7 +432,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
|
||||
char c = t->input[t->offset];
|
||||
char *start = NULL;
|
||||
const char *start = NULL;
|
||||
|
||||
switch (c) {
|
||||
case '=':
|
||||
|
@ -406,7 +444,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
tid = TK_ARRAY_ASSIGN;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"use => for assignments in arrays");
|
||||
return -1;
|
||||
|
@ -425,11 +464,14 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
tid = TK_MATCH;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"only =~ and == are allow in the condition");
|
||||
return -1;
|
||||
}
|
||||
t->in_key = 1;
|
||||
t->in_cond = 0;
|
||||
} else if (t->in_key) {
|
||||
tid = TK_ASSIGN;
|
||||
|
||||
|
@ -437,9 +479,9 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
t->offset++;
|
||||
t->line_pos++;
|
||||
t->in_key = 0;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"unexpected equal-sign: =");
|
||||
return -1;
|
||||
|
@ -461,13 +503,17 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
tid = TK_NOMATCH;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"only !~ and != are allow in the condition");
|
||||
return -1;
|
||||
}
|
||||
t->in_key = 1;
|
||||
t->in_cond = 0;
|
||||
} else {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"unexpected exclamation-marks: !");
|
||||
return -1;
|
||||
|
@ -512,7 +558,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
} else {
|
||||
config_skip_newline(t);
|
||||
t->line_pos = 1;
|
||||
t->line++;
|
||||
t->line++;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
|
@ -556,7 +602,8 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
if (t->input[t->offset + i] == '\0') {
|
||||
/* ERROR */
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"missing closing quote");
|
||||
|
||||
|
@ -593,6 +640,20 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
buffer_copy_string(token, "$");
|
||||
|
||||
break;
|
||||
|
||||
case '+':
|
||||
if (t->input[t->offset + 1] == '=') {
|
||||
t->offset += 2;
|
||||
buffer_copy_string(token, "+=");
|
||||
tid = TK_APPEND;
|
||||
}
|
||||
else {
|
||||
t->offset++;
|
||||
tid = TK_PLUS;
|
||||
buffer_copy_string(token, "+");
|
||||
}
|
||||
break;
|
||||
|
||||
case '|':
|
||||
t->offset++;
|
||||
tid = TK_OR;
|
||||
|
@ -603,8 +664,6 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
t->offset++;
|
||||
|
||||
tid = TK_LCURLY;
|
||||
t->in_key = 1;
|
||||
t->in_cond = 0;
|
||||
|
||||
buffer_copy_string(token, "{");
|
||||
|
||||
|
@ -641,28 +700,7 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
break;
|
||||
default:
|
||||
if (t->in_key) {
|
||||
/* the key might consist of [-.0-9a-z] */
|
||||
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] == '-'
|
||||
); i++);
|
||||
|
||||
if (i && t->input[t->offset + i]) {
|
||||
tid = TK_LKEY;
|
||||
buffer_copy_string_len(token, t->input + t->offset, i);
|
||||
|
||||
t->offset += i;
|
||||
t->line_pos += i;
|
||||
} else {
|
||||
/* ERROR */
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"invalid character in lvalue");
|
||||
return -1;
|
||||
}
|
||||
} else if (t->in_cond) {
|
||||
if (t->in_cond) {
|
||||
for (i = 0; t->input[t->offset + i] &&
|
||||
(isalpha((unsigned char)t->input[t->offset + i])
|
||||
); i++);
|
||||
|
@ -675,40 +713,60 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
t->line_pos += i;
|
||||
} else {
|
||||
/* ERROR */
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"invalid character in condition");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (isdigit((unsigned char)c)) {
|
||||
/* take all digits */
|
||||
for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
|
||||
} else if (isdigit((unsigned char)c)) {
|
||||
/* take all digits */
|
||||
for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
|
||||
|
||||
/* was there it least a digit ? */
|
||||
if (i && t->input[t->offset + i]) {
|
||||
tid = TK_INTEGER;
|
||||
|
||||
/* was there it least a digit ? */
|
||||
if (i && t->input[t->offset + i]) {
|
||||
tid = TK_INTEGER;
|
||||
|
||||
buffer_copy_string_len(token, t->input + t->offset, i);
|
||||
|
||||
t->offset += i;
|
||||
t->line_pos += i;
|
||||
} else {
|
||||
/* ERROR */
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"unexpected EOF");
|
||||
|
||||
return -1;
|
||||
}
|
||||
buffer_copy_string_len(token, t->input + t->offset, i);
|
||||
|
||||
t->offset += i;
|
||||
t->line_pos += i;
|
||||
} else {
|
||||
/* ERROR */
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"invalid value field");
|
||||
"unexpected EOF");
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* the key might consist of [-.0-9a-z] */
|
||||
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] == '-'
|
||||
); i++);
|
||||
|
||||
if (i && t->input[t->offset + i]) {
|
||||
buffer_copy_string_len(token, t->input + t->offset, i);
|
||||
|
||||
if (strcmp(token->ptr, "include") == 0) {
|
||||
tid = TK_INCLUDE;
|
||||
} else {
|
||||
tid = TK_LKEY;
|
||||
}
|
||||
|
||||
t->offset += i;
|
||||
t->line_pos += i;
|
||||
} else {
|
||||
/* ERROR */
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos,
|
||||
"invalid character in variable name");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -716,6 +774,11 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
|
||||
if (tid) {
|
||||
*token_id = tid;
|
||||
#if 0
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsdb",
|
||||
"file:", t->file,
|
||||
"line:", t->line, "pos:", t->line_pos, token);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
} else if (t->offset < t->size) {
|
||||
|
@ -726,40 +789,88 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *
|
|||
return 0;
|
||||
}
|
||||
|
||||
int config_read(server *srv, const char *fn) {
|
||||
stream s;
|
||||
int config_parse_file(server *srv, config_t *context, const char *fn) {
|
||||
tokenizer_t t;
|
||||
void *pParser;
|
||||
int token_id;
|
||||
buffer *token;
|
||||
config_t context;
|
||||
data_config *dc;
|
||||
buffer *token, *lasttoken;
|
||||
int ret;
|
||||
buffer *bfn = buffer_init_string(fn);
|
||||
|
||||
if (0 != stream_open(&s, bfn)) {
|
||||
buffer_free(bfn);
|
||||
|
||||
log_error_write(srv, __FILE__, __LINE__, "ssss",
|
||||
"opening configfile ", fn, "failed:", strerror(errno));
|
||||
|
||||
if (tokenizer_open(srv, &t, context->basedir, fn) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer_free(bfn);
|
||||
pParser = configparserAlloc( malloc );
|
||||
lasttoken = buffer_init();
|
||||
token = buffer_init();
|
||||
while((1 == (ret = config_tokenizer(srv, &t, &token_id, token))) && context->ok) {
|
||||
buffer_copy_string_buffer(lasttoken, token);
|
||||
configparser(pParser, token_id, token, context);
|
||||
|
||||
token = buffer_init();
|
||||
}
|
||||
if (ret != -1 && context->ok) {
|
||||
/* add an EOL at EOF, better than say sorry */
|
||||
buffer_copy_string(token, "(EOL)");
|
||||
configparser(pParser, TK_EOL, token, context);
|
||||
token = buffer_init_string("(END)");
|
||||
if (context->ok) {
|
||||
configparser(pParser, 0, token, context);
|
||||
token = buffer_init();
|
||||
}
|
||||
}
|
||||
configparserFree(pParser, free);
|
||||
buffer_free(token);
|
||||
|
||||
if (ret == -1) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sb",
|
||||
"configfile parser failed:", lasttoken);
|
||||
}
|
||||
else if (context->ok == 0) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
|
||||
"file:", t.file,
|
||||
"line:", t.line, "pos:", t.line_pos,
|
||||
"parser failed somehow near here:", lasttoken);
|
||||
ret = -1;
|
||||
}
|
||||
buffer_free(lasttoken);
|
||||
|
||||
t.input = s.start;
|
||||
t.offset = 0;
|
||||
t.size = s.size;
|
||||
t.line = 1;
|
||||
t.line_pos = 1;
|
||||
|
||||
t.in_key = 1;
|
||||
t.in_brace = 0;
|
||||
t.in_cond = 0;
|
||||
|
||||
context.ok = 1;
|
||||
tokenizer_close(srv, &t);
|
||||
return ret == -1 ? -1 : 0;
|
||||
}
|
||||
|
||||
static void context_init(server *srv, config_t *context) {
|
||||
context->srv = srv;
|
||||
context->ok = 1;
|
||||
context->configs_stack = array_init();
|
||||
context->basedir = buffer_init();
|
||||
}
|
||||
|
||||
static void context_free(config_t *context) {
|
||||
array_free(context->configs_stack);
|
||||
buffer_free(context->basedir);
|
||||
}
|
||||
|
||||
int config_read(server *srv, const char *fn) {
|
||||
config_t context;
|
||||
data_config *dc;
|
||||
int ret;
|
||||
char *pos;
|
||||
|
||||
context_init(srv, &context);
|
||||
context.all_configs = srv->config_context;
|
||||
context.configs_stack = array_init();
|
||||
|
||||
pos = strrchr(fn,
|
||||
#ifdef __WIN32
|
||||
'\\'
|
||||
#else
|
||||
'/'
|
||||
#endif
|
||||
);
|
||||
if (pos) {
|
||||
buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
|
||||
fn = pos + 1;
|
||||
}
|
||||
|
||||
dc = data_config_init();
|
||||
buffer_copy_string(dc->key, "global");
|
||||
|
@ -768,39 +879,18 @@ int config_read(server *srv, const char *fn) {
|
|||
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;
|
||||
|
||||
pParser = configparserAlloc( malloc );
|
||||
token = buffer_init();
|
||||
while((1 == (ret = config_tokenizer(srv, &t, &token_id, token))) && context.ok) {
|
||||
configparser(pParser, token_id, token, &context);
|
||||
|
||||
token = buffer_init();
|
||||
ret = config_parse_file(srv, &context, fn);
|
||||
|
||||
assert(0 != ret || context.configs_stack->used == 0);
|
||||
context_free(&context);
|
||||
|
||||
if (0 != ret) {
|
||||
return ret;
|
||||
}
|
||||
configparser(pParser, 0, token, &context);
|
||||
configparserFree(pParser, free );
|
||||
|
||||
buffer_free(token);
|
||||
|
||||
stream_close(&s);
|
||||
|
||||
if (ret == -1) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "s",
|
||||
"configfile parser failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (context.ok == 0) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sdsds",
|
||||
"line:", t.line, "pos:", t.line_pos,
|
||||
"parser failed somehow near here");
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(context.configs_stack->used == 0);
|
||||
array_free(context.configs_stack);
|
||||
|
||||
if (0 != config_insert(srv)) {
|
||||
return -1;
|
||||
|
|
|
@ -3,16 +3,20 @@
|
|||
|
||||
#include "array.h"
|
||||
#include "buffer.h"
|
||||
#include "server.h"
|
||||
|
||||
typedef struct {
|
||||
server *srv;
|
||||
int ok;
|
||||
array *all_configs;
|
||||
array *configs_stack; /* to parse nested block */
|
||||
data_config *current; /* current started with { */
|
||||
buffer *basedir;
|
||||
} config_t;
|
||||
|
||||
void *configparserAlloc(void *(*mallocProc)(size_t));
|
||||
void configparserFree(void *p, void (*freeProc)(void*));
|
||||
void configparser(void *yyp, int yymajor, buffer *yyminor, config_t *ctx);
|
||||
int config_parse_file(server *srv, config_t *context, const char *fn);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
%include {
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "config.h"
|
||||
#include "configfile.h"
|
||||
#include "buffer.h"
|
||||
|
@ -14,7 +15,9 @@
|
|||
static void configparser_push(config_t *ctx, data_config *dc, int isnew) {
|
||||
if (isnew) {
|
||||
dc->context_ndx = ctx->all_configs->used;
|
||||
assert(dc->context_ndx > ctx->current->context_ndx);
|
||||
array_insert_unique(ctx->all_configs, (data_unset *)dc);
|
||||
dc->parent = ctx->current;
|
||||
}
|
||||
array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
|
||||
ctx->current = dc;
|
||||
|
@ -26,6 +29,85 @@ static data_config *configparser_pop(config_t *ctx) {
|
|||
return old;
|
||||
}
|
||||
|
||||
data_unset *configparser_get_variable(config_t *ctx, buffer *key) {
|
||||
data_unset *ds, *result;
|
||||
data_config *dc;
|
||||
|
||||
result = NULL;
|
||||
#if 0
|
||||
fprintf(stderr, "get var %s\n", key->ptr);
|
||||
#endif
|
||||
for (dc = ctx->current; dc && !result; dc = dc->parent) {
|
||||
#if 0
|
||||
fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
|
||||
#endif
|
||||
ds = array_get_element(dc->value, key->ptr);
|
||||
if (NULL != ds) {
|
||||
result = ds;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == result) {
|
||||
fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
|
||||
ctx->ok = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* op1 is to be eat/return by this function, op1->key is not cared
|
||||
op2 is left untouch, unreferenced
|
||||
*/
|
||||
data_unset *configparser_merge_data(config_t *ctx, data_unset *op1, const data_unset *op2) {
|
||||
/* type mismatch */
|
||||
if (op1->type != op2->type) {
|
||||
if (op1->type == TYPE_STRING && op2->type == TYPE_INTEGER) {
|
||||
data_string *ds = (data_string *)op1;
|
||||
buffer_append_long(ds->value, ((data_integer*)op2)->value);
|
||||
return op1;
|
||||
}
|
||||
else if (op1->type == TYPE_INTEGER && op2->type == TYPE_STRING) {
|
||||
data_string *ds = data_string_init();
|
||||
buffer_append_long(ds->value, ((data_integer*)op1)->value);
|
||||
buffer_append_string_buffer(ds->value, ((data_string*)op2)->value);
|
||||
op1->free(op1);
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "data type mismatch, cannot be merge\n");
|
||||
ctx->ok = 0;
|
||||
op1->free(op1);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (op1->type) {
|
||||
case TYPE_STRING:
|
||||
buffer_append_string_buffer(((data_string *)op1)->value, ((data_string *)op2)->value);
|
||||
break;
|
||||
case TYPE_INTEGER:
|
||||
((data_integer *)op1)->value += ((data_integer *)op2)->value;
|
||||
break;
|
||||
case TYPE_ARRAY: {
|
||||
array *dst = ((data_array *)op1)->value;
|
||||
array *src = ((data_array *)op2)->value;
|
||||
data_unset *du;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < src->used; i ++) {
|
||||
du = (data_unset *)src->data[i];
|
||||
if (du) {
|
||||
array_insert_unique(dst, du->copy(du));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return op1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
%parse_failure {
|
||||
|
@ -37,9 +119,12 @@ metalines ::= metalines metaline.
|
|||
metalines ::= .
|
||||
metaline ::= varline.
|
||||
metaline ::= condlines EOL.
|
||||
metaline ::= include.
|
||||
metaline ::= EOL.
|
||||
|
||||
%type value {data_unset *}
|
||||
%type expression {data_unset *}
|
||||
%type context_rvalue {data_unset *}
|
||||
%type aelement {data_unset *}
|
||||
%type aelements {array *}
|
||||
%type array {array *}
|
||||
|
@ -48,7 +133,7 @@ metaline ::= EOL.
|
|||
%type cond {config_cond_t }
|
||||
%token_destructor { buffer_free($$); }
|
||||
|
||||
varline ::= key(A) ASSIGN value(B). {
|
||||
varline ::= key(A) ASSIGN expression(B). {
|
||||
buffer_copy_string_buffer(B->key, A);
|
||||
if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
|
||||
array_insert_unique(ctx->current->value, B);
|
||||
|
@ -61,11 +146,63 @@ varline ::= key(A) ASSIGN value(B). {
|
|||
buffer_free(A);
|
||||
}
|
||||
|
||||
varline ::= key(A) APPEND expression(B). {
|
||||
array *vars = ctx->current->value;
|
||||
data_unset *du;
|
||||
|
||||
if (NULL == (du = configparser_get_variable(ctx, A))) {
|
||||
fprintf(stderr, "Undefined config variable in conditional 1 %s: %s\n",
|
||||
ctx->current->key->ptr, A->ptr);
|
||||
ctx->ok = 0;
|
||||
} else if (NULL != (du = array_get_element(vars, A->ptr))) {
|
||||
/* exists in current block */
|
||||
du = configparser_merge_data(ctx, du, B);
|
||||
buffer_copy_string_buffer(du->key, A);
|
||||
array_replace(vars, du);
|
||||
} else {
|
||||
du = configparser_merge_data(ctx, du->copy(du), B);
|
||||
buffer_copy_string_buffer(du->key, A);
|
||||
array_insert_unique(ctx->current->value, du);
|
||||
}
|
||||
buffer_free(A);
|
||||
A = NULL;
|
||||
B->free(B);
|
||||
B = NULL;
|
||||
}
|
||||
|
||||
key(A) ::= LKEY(B). {
|
||||
if (strchr(B->ptr, '.') == NULL) {
|
||||
A = buffer_init_string("var.");
|
||||
buffer_append_string_buffer(A, B);
|
||||
}
|
||||
else {
|
||||
A = B;
|
||||
B = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
expression(A) ::= expression(B) PLUS value(C). {
|
||||
A = configparser_merge_data(ctx, B, C);
|
||||
B = NULL;
|
||||
C->free(C);
|
||||
C = NULL;
|
||||
}
|
||||
|
||||
expression(A) ::= value(B). {
|
||||
A = B;
|
||||
B = NULL;
|
||||
}
|
||||
|
||||
value(A) ::= key(B). {
|
||||
A = configparser_get_variable(ctx, B);
|
||||
if (!A) {
|
||||
/* make a dummy so it won't crash */
|
||||
A = (data_unset *)data_string_init();
|
||||
}
|
||||
buffer_free(B);
|
||||
B = NULL;
|
||||
}
|
||||
|
||||
value(A) ::= STRING(B). {
|
||||
A = (data_unset *)data_string_init();
|
||||
buffer_copy_string_buffer(((data_string *)(A))->value, B);
|
||||
|
@ -110,11 +247,11 @@ aelements(A) ::= aelement(B). {
|
|||
array_insert_unique(A, B);
|
||||
}
|
||||
|
||||
aelement(A) ::= value(B). {
|
||||
aelement(A) ::= expression(B). {
|
||||
A = B;
|
||||
B = NULL;
|
||||
}
|
||||
aelement(A) ::= STRING(B) ARRAY_ASSIGN value(C). {
|
||||
aelement(A) ::= STRING(B) ARRAY_ASSIGN expression(C). {
|
||||
buffer_copy_string_buffer(C->key, B);
|
||||
buffer_free(B);
|
||||
|
||||
|
@ -140,32 +277,49 @@ condlines(A) ::= condline(B). {
|
|||
}
|
||||
|
||||
condline(A) ::= context LCURLY metalines RCURLY. {
|
||||
data_config *parent, *cur;
|
||||
data_config *cur;
|
||||
|
||||
cur = ctx->current;
|
||||
configparser_pop(ctx);
|
||||
parent = ctx->current;
|
||||
|
||||
assert(cur && parent);
|
||||
assert(cur && ctx->current);
|
||||
|
||||
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). {
|
||||
context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) expression(D). {
|
||||
data_config *dc;
|
||||
buffer *b;
|
||||
|
||||
buffer *b, *rvalue;
|
||||
|
||||
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);
|
||||
buffer_append_string_buffer(b, D);
|
||||
buffer_append_long(b, E);
|
||||
switch(E) {
|
||||
case CONFIG_COND_NE:
|
||||
buffer_append_string_len(b, CONST_STR_LEN("!="));
|
||||
break;
|
||||
case CONFIG_COND_EQ:
|
||||
buffer_append_string_len(b, CONST_STR_LEN("=="));
|
||||
break;
|
||||
case CONFIG_COND_NOMATCH:
|
||||
buffer_append_string_len(b, CONST_STR_LEN("!~"));
|
||||
break;
|
||||
case CONFIG_COND_MATCH:
|
||||
buffer_append_string_len(b, CONST_STR_LEN("=~"));
|
||||
break;
|
||||
default:
|
||||
buffer_append_string_len(b, CONST_STR_LEN("??"));
|
||||
break;
|
||||
}
|
||||
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);
|
||||
|
@ -180,7 +334,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D).
|
|||
switch(E) {
|
||||
case CONFIG_COND_NE:
|
||||
case CONFIG_COND_EQ:
|
||||
dc->string = buffer_init_string(D->ptr);
|
||||
dc->string = buffer_init_buffer(rvalue);
|
||||
break;
|
||||
case CONFIG_COND_NOMATCH:
|
||||
case CONFIG_COND_MATCH: {
|
||||
|
@ -189,16 +343,22 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D).
|
|||
int erroff;
|
||||
|
||||
if (NULL == (dc->regex =
|
||||
pcre_compile(D->ptr, 0, &errptr, &erroff, NULL))) {
|
||||
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)) &&
|
||||
pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
|
||||
dc->string = buffer_init_string(errptr);
|
||||
dc->cond = CONFIG_COND_UNSET;
|
||||
|
||||
fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
|
||||
rvalue->ptr, errptr, erroff);
|
||||
|
||||
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;
|
||||
rvalue->ptr, errptr);
|
||||
ctx->ok = 0;
|
||||
} else {
|
||||
dc->string = buffer_init_buffer(rvalue);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
|
||||
|
@ -218,10 +378,10 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET STRING(C) RBRACKET cond(E) STRING(D).
|
|||
|
||||
configparser_push(ctx, dc, 1);
|
||||
}
|
||||
|
||||
buffer_free(b);
|
||||
buffer_free(B);
|
||||
buffer_free(C);
|
||||
buffer_free(D);
|
||||
D->free(D);
|
||||
D = NULL;
|
||||
}
|
||||
cond(A) ::= EQ. {
|
||||
A = CONFIG_COND_EQ;
|
||||
|
@ -235,3 +395,19 @@ cond(A) ::= NE. {
|
|||
cond(A) ::= NOMATCH. {
|
||||
A = CONFIG_COND_NOMATCH;
|
||||
}
|
||||
|
||||
include ::= INCLUDE expression(A). {
|
||||
if (ctx->ok) {
|
||||
if (A->type != TYPE_STRING) {
|
||||
fprintf(stderr, "file must be string");
|
||||
ctx->ok = 0;
|
||||
} else {
|
||||
buffer *file = ((data_string*)A)->value;
|
||||
if (0 != config_parse_file(ctx->srv, ctx, file->ptr)) {
|
||||
ctx->ok = 0;
|
||||
}
|
||||
}
|
||||
A->free(A);
|
||||
}
|
||||
A = NULL;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
|
||||
#include "array.h"
|
||||
|
||||
static data_unset *data_array_copy(data_unset *s) {
|
||||
data_array *src = (data_array *)s;
|
||||
data_array *ds = data_array_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->value = array_init_array(src->value);
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_array_free(data_unset *d) {
|
||||
data_array *ds = (data_array *)d;
|
||||
|
||||
|
@ -39,7 +48,6 @@ static void data_array_print(data_unset *d, int depth) {
|
|||
fprintf(stderr, "}");
|
||||
}
|
||||
|
||||
|
||||
data_array *data_array_init(void) {
|
||||
data_array *ds;
|
||||
|
||||
|
@ -48,6 +56,7 @@ data_array *data_array_init(void) {
|
|||
ds->key = buffer_init();
|
||||
ds->value = array_init();
|
||||
|
||||
ds->copy = data_array_copy;
|
||||
ds->free = data_array_free;
|
||||
ds->reset = data_array_reset;
|
||||
ds->insert_dup = data_array_insert_dup;
|
||||
|
|
|
@ -4,6 +4,16 @@
|
|||
|
||||
#include "array.h"
|
||||
|
||||
static data_unset *data_config_copy(data_unset *s) {
|
||||
data_config *src = (data_config *)s;
|
||||
data_config *ds = data_config_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->comp_key = buffer_init_buffer(src->comp_key);
|
||||
ds->value = array_init_array(src->value);
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_config_free(data_unset *d) {
|
||||
data_config *ds = (data_config *)d;
|
||||
|
||||
|
@ -58,6 +68,7 @@ data_config *data_config_init(void) {
|
|||
ds->comp_key = buffer_init();
|
||||
ds->value = array_init();
|
||||
|
||||
ds->copy = data_config_copy;
|
||||
ds->free = data_config_free;
|
||||
ds->reset = data_config_reset;
|
||||
ds->insert_dup = data_config_insert_dup;
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
|
||||
#include "array.h"
|
||||
|
||||
static data_unset *data_count_copy(data_unset *s) {
|
||||
data_count *src = (data_count *)s;
|
||||
data_count *ds = data_count_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->count = src->count;
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_count_free(data_unset *d) {
|
||||
data_count *ds = (data_count *)d;
|
||||
|
||||
|
@ -47,6 +56,8 @@ data_count *data_count_init(void) {
|
|||
ds->key = buffer_init();
|
||||
ds->count = 1;
|
||||
|
||||
ds->copy = data_count_copy;
|
||||
ds->copy = data_count_copy;
|
||||
ds->free = data_count_free;
|
||||
ds->reset = data_count_reset;
|
||||
ds->insert_dup = data_count_insert_dup;
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
#include "array.h"
|
||||
#include "fastcgi.h"
|
||||
|
||||
static data_unset *data_fastcgi_copy(data_unset *s) {
|
||||
data_fastcgi *src = (data_fastcgi *)s;
|
||||
data_fastcgi *ds = data_fastcgi_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->host = buffer_init_buffer(src->host);
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_fastcgi_free(data_unset *d) {
|
||||
data_fastcgi *ds = (data_fastcgi *)d;
|
||||
|
||||
|
@ -48,6 +57,7 @@ data_fastcgi *data_fastcgi_init(void) {
|
|||
ds->port = 0;
|
||||
ds->is_disabled = 0;
|
||||
|
||||
ds->copy = data_fastcgi_copy;
|
||||
ds->free = data_fastcgi_free;
|
||||
ds->reset = data_fastcgi_reset;
|
||||
ds->insert_dup = data_fastcgi_insert_dup;
|
||||
|
|
|
@ -4,6 +4,15 @@
|
|||
|
||||
#include "array.h"
|
||||
|
||||
static data_unset *data_integer_copy(data_unset *s) {
|
||||
data_integer *src = (data_integer *)s;
|
||||
data_integer *ds = data_integer_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->value = src->value;
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_integer_free(data_unset *d) {
|
||||
data_integer *ds = (data_integer *)d;
|
||||
|
||||
|
@ -44,6 +53,7 @@ data_integer *data_integer_init(void) {
|
|||
ds->key = buffer_init();
|
||||
ds->value = 0;
|
||||
|
||||
ds->copy = data_integer_copy;
|
||||
ds->free = data_integer_free;
|
||||
ds->reset = data_integer_reset;
|
||||
ds->insert_dup = data_integer_insert_dup;
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
|
||||
#include "array.h"
|
||||
|
||||
static data_unset *data_string_copy(data_unset *s) {
|
||||
data_string *src = (data_string *)s;
|
||||
data_string *ds = data_string_init();
|
||||
|
||||
ds->key = buffer_init_buffer(src->key);
|
||||
ds->value = buffer_init_buffer(src->value);
|
||||
return (data_unset *)ds;
|
||||
}
|
||||
|
||||
static void data_string_free(data_unset *d) {
|
||||
data_string *ds = (data_string *)d;
|
||||
|
||||
|
@ -74,6 +83,7 @@ data_string *data_string_init(void) {
|
|||
ds->key = buffer_init();
|
||||
ds->value = buffer_init();
|
||||
|
||||
ds->copy = data_string_copy;
|
||||
ds->free = data_string_free;
|
||||
ds->reset = data_string_reset;
|
||||
ds->insert_dup = data_string_insert_dup;
|
||||
|
|
|
@ -629,6 +629,11 @@ int main (int argc, char **argv) {
|
|||
for (i = 0; srv->config && i < srv->config->used; i++) {
|
||||
data_unset *du = srv->config->data[i];
|
||||
|
||||
/* all var.* is known as user defined variable */
|
||||
if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
|
||||
log_error_write(srv, __FILE__, __LINE__, "sbs",
|
||||
"WARNING: unknown config-key:",
|
||||
|
|
|
@ -22,6 +22,9 @@ CONFS=fastcgi-10.conf \
|
|||
fastcgi-13.conf \
|
||||
bug-06.conf \
|
||||
bug-12.conf \
|
||||
core-var-include.t \
|
||||
var-include.conf \
|
||||
var-include-sub.conf \
|
||||
condition.conf \
|
||||
core-condition.t \
|
||||
core-request.t \
|
||||
|
|
|
@ -16,7 +16,7 @@ server.tag = "Apache 1.3.29"
|
|||
|
||||
|
||||
server.modules = (
|
||||
"mod_access",
|
||||
"mod_redirect",
|
||||
"mod_accesslog" )
|
||||
|
||||
######################## MODULE CONFIG ############################
|
||||
|
@ -26,23 +26,23 @@ accesslog.filename = "/tmp/lighttpd/logs/lighttpd.access.log"
|
|||
|
||||
mimetype.assign = ( ".html" => "text/html" )
|
||||
|
||||
# ban first, unban later
|
||||
url.access-deny = ( "index.html" )
|
||||
url.redirect = ("^" => "/default")
|
||||
|
||||
$HTTP["host"] == "www.example.org" {
|
||||
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
|
||||
server.name = "www.example.org"
|
||||
url.redirect = ("^" => "/match_1")
|
||||
}
|
||||
| $HTTP["host"] == "test1.example.org" {
|
||||
server.document-root = "/tmp/lighttpd/servers/www.example.org/pages/"
|
||||
server.name = "test1.example.org"
|
||||
url.access-deny = ( "nothing" )
|
||||
url.redirect = ("^" => "/match_2")
|
||||
}
|
||||
# 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" )
|
||||
url.redirect = ("^" => "/match_3")
|
||||
}
|
||||
|
||||
# comments
|
||||
|
@ -50,10 +50,10 @@ $HTTP["host"] == "www.example.org" {
|
|||
| $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" )
|
||||
url.redirect = ("^" => "/match_4")
|
||||
|
||||
# comments
|
||||
$HTTP["url"] == "/index.html" {
|
||||
url.access-deny = ( "index.html" )
|
||||
url.redirect = ("^" => "/match_5")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ GET /index.html HTTP/1.0
|
|||
Host: www.example.org
|
||||
EOF
|
||||
);
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => "/match_1" } );
|
||||
ok($tf->handle_http($t) == 0, 'config deny');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
|
@ -30,7 +30,7 @@ GET /index.html HTTP/1.0
|
|||
Host: test1.example.org
|
||||
EOF
|
||||
);
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => "/match_2" } );
|
||||
ok($tf->handle_http($t) == 0, '2nd child of chaining');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
|
@ -38,7 +38,7 @@ GET /index.html HTTP/1.0
|
|||
Host: test2.example.org
|
||||
EOF
|
||||
);
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => "/match_3" } );
|
||||
ok($tf->handle_http($t) == 0, '3rd child of chaining');
|
||||
|
||||
$t->{REQUEST} = ( <<EOF
|
||||
|
@ -46,7 +46,7 @@ GET /index.html HTTP/1.0
|
|||
Host: test3.example.org
|
||||
EOF
|
||||
);
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => "/match_5" } );
|
||||
ok($tf->handle_http($t) == 0, 'nesting');
|
||||
|
||||
ok($tf->stop_proc == 0, "Stopping lighttpd");
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#! /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 => 16;
|
||||
use LightyTest;
|
||||
|
||||
my $tf = LightyTest->new();
|
||||
my $t;
|
||||
|
||||
$tf->{CONFIGFILE} = 'var-include.conf';
|
||||
|
||||
ok($tf->start_proc == 0, "Starting lighttpd") or die();
|
||||
|
||||
$t->{REQUEST} = ( "GET /index.html HTTP/1.0\r\nHost: www.example.org\r\n" );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => "/redirect" } );
|
||||
ok($tf->handle_http($t) == 0, 'basic test');
|
||||
|
||||
my $myvar = "good";
|
||||
my $server_name = "test.example.org";
|
||||
my $mystr = "string";
|
||||
$mystr .= "_append";
|
||||
my $tests = {
|
||||
"include" => "/good_include",
|
||||
"concat" => "/good_" . "concat",
|
||||
"servername1" => "/good_" . $server_name,
|
||||
"servername2" => $server_name . "/good_",
|
||||
"servername3" => "/good_" . $server_name . "/",
|
||||
"var.myvar" => "/good_var_myvar" . $myvar,
|
||||
"myvar" => "/good_myvar" . $myvar,
|
||||
"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} = ( "GET /$test HTTP/1.0\r\nHost: $server_name\r\n" );
|
||||
$t->{RESPONSE} = ( { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 301, 'Location' => $expect } );
|
||||
ok($tf->handle_http == 0, $test) |