config parser rewritten

personal/stbuehler/wip
Thomas Porzelt 14 years ago
parent b3767c0190
commit a9cbec1046
  1. 65
      src/config_parser.h
  2. 527
      src/config_parser.rl
  3. 36
      src/lighttpd.c
  4. 10
      src/log.c
  5. 1
      src/plugin_core.c
  6. 3
      src/server.c

@ -1,67 +1,44 @@
#ifndef _LIGHTTPD_CONFIGPARSER_H_
#define _LIGHTTPD_CONFIGPARSER_H_
#include "condition.h"
struct config_parser_context_t;
typedef struct config_parser_context_t config_parser_context_t;
struct config_parser_data_t;
typedef struct config_parser_data_t config_parser_data_t;
struct config_parser_filestack_entry_t;
typedef struct config_parser_filestack_entry_t config_parser_filestack_entry_t;
/* initializes the config parser */
config_parser_context_t *config_parser_init();
/* loads a file into memory and parses it */
gboolean config_parser_file(server *srv, config_parser_context_t *ctx, const gchar *path);
gboolean config_parser_file(server *srv, GList *ctx_stack, const gchar *path);
/* launched a command through the shell and parses the stdout it returns */
gboolean config_parser_shell(server *srv, config_parser_context_t *ctx, const gchar *command);
gboolean config_parser_shell(server *srv,GList *ctx_stack, const gchar *command);
/* parses a buffer pointed to by the previously allocated config_parser_data struct */
gboolean config_parser_buffer(server *srv, config_parser_context_t *ctx);
gboolean config_parser_buffer(server *srv, GList *ctx_stack);
config_parser_data_t *config_parser_data_new();
void config_parser_data_free(config_parser_data_t *cpd);
config_parser_context_t *config_parser_context_new();
void config_parser_context_free(config_parser_context_t *ctx, gboolean free_queues);
struct config_parser_context_t {
GList *action_list_stack;
GList *stack;
};
struct config_parser_data_t {
/* information of currently parsed file */
gchar *filename;
gchar *ptr;
gsize len;
gsize line;
int stacksize;
/* ragel vars */
int cs;
int *stack;
int top;
int stacksize; /* not really used by ragel but need to remember it */
char *p, *pe, *eof;
/* markers to start of current data */
gchar *mark;
gchar *mark_var;
/* action list stack */
GList *action_list_stack;
/* current value */
enum { CONFP_BOOL, CONFP_INT, CONFP_STR, CONFP_LIST, CONFP_HASH } val_type, val_type_last;
GString *val_str;
gint64 val_int;
gboolean val_bool;
GArray *val_list;
GHashTable *val_hash;
option *opt;
gboolean in_setup_block;
comp_operator_t op;
/* operator */
comp_operator_t operator;
GQueue *action_list_stack; /* first entry is current action list */
GQueue *option_stack; /* stack for options */
/* name of current variable */
GString *varname;
/* information about currenty parsed file */
gchar *filename;
gchar *ptr; /* pointer to the data */
gsize len;
gsize line; /* holds current line */
};
#endif

@ -1,4 +1,5 @@
#include "base.h"
#include "condition.h"
#include "config_parser.h"
#if 1
@ -10,407 +11,431 @@
/** config parser state machine **/
%%{
## ragel stuff
machine config_parser;
variable p cpd->p;
variable pe cpd->pe;
variable eof cpd->eof;
access cpd->;
variable p ctx->p;
variable pe ctx->pe;
variable eof ctx->eof;
# actions
action mark { cpd->mark = fpc; }
action mark_var { cpd->mark_var = fpc; }
access ctx->;
prepush {
_printf("current stacksize: %d, top: %d\n", cpd->stacksize, cpd->top);
//_printf("current stacksize: %d, top: %d\n", ctx->stacksize, ctx->top);
/* increase stacksize if necessary */
if (cpd->stacksize == cpd->top)
if (ctx->stacksize == ctx->top)
{
cpd->stack = g_realloc(cpd->stack, sizeof(int) * (cpd->stacksize + 8));
cpd->stacksize += 8;
/* increase stacksize by 8 */
ctx->stack = g_realloc(ctx->stack, sizeof(int) * (ctx->stacksize + 8));
ctx->stacksize += 8;
}
}
## actions
action mark { ctx->mark = fpc; }
# basic types
action boolean {
cpd->val_type = CONFP_BOOL;
if (*cpd->mark == 't')
cpd->val_bool = TRUE;
else
cpd->val_bool = FALSE;
_printf("got boolean %s in line %zd of %s\n", cpd->val_bool ? "true" : "false", cpd->line, cpd->filename);
}
option *o;
action string {
g_string_truncate(cpd->val_str, 0);
g_string_append_len(cpd->val_str, cpd->mark + 1, fpc - cpd->mark - 2);
cpd->val_type = CONFP_STR;
_printf("got string: \"%s\" in line %zd of %s\n", cpd->val_str->str, cpd->line, cpd->filename);
o = option_new_bool(*ctx->mark == 't' ? TRUE : FALSE);
g_queue_push_head(ctx->option_stack, o);
_printf("got boolean %s in line %zd\n", *ctx->mark == 't' ? "true" : "false", ctx->line);
}
action integer
{
gchar *c;
cpd->val_int = 0;
for (c=cpd->mark; c<fpc; c++)
cpd->val_int = cpd->val_int * 10 + *c - 48;
cpd->val_type = CONFP_INT;
//_printf("got integer: %d in line %zd of %s\n", cpd->val_int, cpd->line, cpd->filename);
action integer {
option *o;
guint i = 0;
for (gchar *c = ctx->mark; c < fpc; c++)
i = i * 10 + *c - 48;
o = option_new_int(i);
/* push option onto stack */
g_queue_push_head(ctx->option_stack, o);
_printf("got integer %d in line %zd\n", i, ctx->line);
}
action integer_suffix {
switch (*cpd->mark) {
case 'k': cpd->val_int *= (guint64) 1024; break;
case 'm': cpd->val_int *= (guint64) 1024 * 1024; break;
case 'g': cpd->val_int *= (guint64) 1024 * 1024 * 1024; break;
case 't': cpd->val_int *= (guint64) 1024 * 1024 * 1024 * 1024; break;
case 'p': cpd->val_int *= (guint64) 1024 * 1024 * 1024 * 1024 * 1024; break;
}
}
action comment { _printf("got comment in line %zd of %s\n", cpd->line-1, cpd->filename); }
action value { }
action valuepair { _printf("got valuepair in line %zd of %s\n", cpd->line, cpd->filename); }
action line { cpd->line++; }
action lineWin { cpd->line--; }
action string {
option *o;
GString *str;
action varname {
g_string_truncate(cpd->varname, 0);
g_string_append_len(cpd->varname, cpd->mark_var, fpc - cpd->mark_var);
_printf("got varname: \"%s\" in line %zd of %s\n", cpd->varname->str, cpd->line, cpd->filename);
str = g_string_new_len(ctx->mark+1, fpc - ctx->mark - 2);
o = option_new_string(str);
g_queue_push_head(ctx->option_stack, o);
_printf("got string %s", "");
for (gchar *c = ctx->mark + 1; c < fpc - 1; c++) _printf("%c", *c);
_printf(" in line %zd\n", ctx->line);
}
action operator {
if ((fpc - cpd->mark) == 1) {
/* 1 char operator: < or > */
cpd->operator = (*fpc == '<') ? CONFIG_COND_LT : CONFIG_COND_GT;
}
else {
/* 2 char operator */
char frst = *cpd->mark, scnd = *(fpc-1);
_printf(" [%c %c] ", frst, scnd);
if (frst == '<' && scnd == '=') {
cpd->operator = CONFIG_COND_LE;
}
else if (frst == '>' && scnd == '=') {
cpd->operator = CONFIG_COND_GE;
}
else if (frst == '!' && scnd == '=') {
cpd->operator = CONFIG_COND_NE;
}
else if (frst == '=' && scnd == '=') {
cpd->operator = CONFIG_COND_EQ;
}
else if (frst == '=' && scnd == '~') {
cpd->operator = CONFIG_COND_MATCH;
}
else if (frst == '!' && scnd == '~') {
cpd->operator = CONFIG_COND_NOMATCH;
}
}
# advanced types
action list_start {
option *o;
_printf("got operator: %s", "");
for (char* c=cpd->mark; c < fpc; c++)
_printf("%c", (int)*c);
_printf(" (%d) in line %zd of %s\n", cpd->operator, cpd->line, cpd->filename);
/* create new list option and put it on stack, list entries are put in it by getting the previous option from the stack */
o = option_new_list();
g_queue_push_head(ctx->option_stack, o);
fcall list_scanner;
}
action list_push {
option *o, *l;
action assignment {
action *a;
option *o;
action_list *al;
switch (cpd->val_type) {
case CONFP_BOOL:
o = option_new_bool(cpd->val_bool);
break;
case CONFP_INT:
o = option_new_int(cpd->val_int);
break;
case CONFP_STR:
o = option_new_string(cpd->val_str);
break;
case CONFP_LIST:
o = option_new_list();
g_array_free(o->value.opt_list, TRUE);
o->value.opt_list = cpd->val_list;
break;
case CONFP_HASH:
o = option_new_hash();
g_hash_table_destroy(o->value.opt_hash);
o->value.opt_hash = cpd->val_hash;
break;
}
/* pop current option form stack and append it to the new top of the stack option (the list) */
o = g_queue_pop_head(ctx->option_stack);
a = action_new_setting(srv, cpd->varname->str, o);
l = g_queue_peek_head(ctx->option_stack);
assert(l->type == OPTION_LIST);
if (a == NULL) {
option_free(o);
return FALSE;
}
g_array_append_val(l->value.opt_list, o);
al = ctx->action_list_stack->data;
g_array_append_val(al->actions, a);
_printf("list_push%s\n", "");
}
_printf("got assignment for var %s in line %zd of %s\n", cpd->varname->str, cpd->line, cpd->filename);
action list_end {
fret;
}
action function {
if (g_str_equal(cpd->varname->str, "include") || g_str_equal(cpd->varname->str, "include_shell"))
break;
_printf("got function call to %s in line %zd of %s\n", cpd->varname->str, cpd->line, cpd->filename);
action hash_start {
option *o;
/* create new hash option and put it on stack, if a key-value pair is encountered, get it by walking 2 steps back the stack */
o = option_new_hash();
g_queue_push_head(ctx->option_stack, o);
fcall hash_scanner;
}
action condition { _printf("got condition for var %s in line %zd of %s\n", cpd->varname->str, cpd->line, cpd->filename); }
action fooblock { _printf("got fooblock in line %zd of %s\n", cpd->line, cpd->filename); }
action hash_push {
option *k, *v, *h; /* key value hashtable */
GString *str;
action list { _printf("list\n"); }
action list_start { /*_printf("list start in line %d\n", line);*/ fcall listscanner; }
action list_end {
/*_printf("list end in line %d\n", line);*/
cpd->val_type = CONFP_LIST;
fret;
v = g_queue_pop_head(ctx->option_stack);
k = g_queue_pop_head(ctx->option_stack);
h = g_queue_peek_head(ctx->option_stack);
/* duplicate key so option can be free'd */
str = g_string_new_len(k->value.opt_string->str, k->value.opt_string->len);
g_hash_table_insert(h->value.opt_hash, str, v);
option_free(k);
_printf("%s\n", "hash_push");
}
action hash_start { fcall hashscanner; }
action hash_end {
_printf("hash ended in line %zd of %s\n", cpd->line, cpd->filename);
fret;
}
action block_start { /*_printf("block start in line %d\n", line);*/ fcall blockscanner; }
action block_end { /*_printf("block end in line %d\n", line);*/ fret; }
action block_start {
fcall block_scanner;
}
action incl {
_printf("including file %s in line %zd of %s\n", cpd->val_str->str, cpd->line, cpd->filename);
if (!config_parser_file(srv, ctx, cpd->val_str->str))
return FALSE;
action block_end {
fret;
}
action incl_shell {
if (!config_parser_shell(srv, ctx, cpd->val_str->str))
return FALSE;
action keyvalue_start {
fcall keyvalue_scanner;
}
action done { _printf("done\n"); }
action keyvalue_end {
option *k, *v, *l;
/* we have a key and a value on the stack; convert them to a list with 2 elements */
# tokens
boolean = ( 'true' | 'false' ) >mark %boolean;
integer_suffix = ( 'mb' | 'kb' | 'gb' | 'tb' | 'pb' ) >mark %integer_suffix;
integer = ( 0 | ( [1-9] [0-9]* ) ) >mark %integer;
string = ( '"' (any-'"')* '"' ) >mark %string;
v = g_queue_pop_head(ctx->option_stack);
k = g_queue_pop_head(ctx->option_stack);
ipv4_part = ( [0-9] | ([1-9] [0-9]) | ('1' [0-9] [0-9]) | ('2' [0-4] [0-9]) | ('25' [0-5]) );
ipv4 = ( ipv4_part '.' ipv4_part '.' ipv4_part '.' ipv4_part );
assert(k->type == OPTION_STRING);
# we dont need to specify ipv6 here correctly, just look if something looks like it could be an ipv6
ipv6_part = ( xdigit{1,4} );
ipv6 = ( (ipv6_part | ':')+ ipv4? );
l = option_new_list();
cidr = ( (ipv4|ipv6) '/' ( ([0-2]? [0-9]) | ('3' [0-2]) ) );
g_array_append_val(l->value.opt_list, k);
g_array_append_val(l->value.opt_list, v);
ws = ( ' ' | '\t' );
/* push list on the stack */
g_queue_push_head(ctx->option_stack, l);
lineUnix = ( '\n' ) %line;
lineMac = ( '\r' ) %line;
lineWin = ( '\r\n' ) %lineWin;
line = ( lineUnix | lineMac | lineWin );
fret;
}
noise = ( ws | line );
action value {
/*
_printf("got value %s", "");
for (gchar *c = ctx->mark; c < fpc; c++) _printf("%c", *c);
_printf(" in line %zd\n", ctx->line);
*/
}
comment = ( '#' (any - line)* line ) %comment;
action varname {
/* varname, push it as string option onto the stack */
option *o;
GString *str;
value = ( boolean | (integer integer_suffix?) | string ) %value;
valuepair = ( string ws* '=>' ws* value ) %valuepair;
str = g_string_new_len(ctx->mark, fpc - ctx->mark);
o = option_new_string(str);
g_queue_push_head(ctx->option_stack, o);
}
list = ( '(' ) >list_start;
listscanner := ( noise* ((value|valuepair|list) (noise* ',' noise* (value|valuepair|list))*)? noise* ')' >list_end );
# statements
action assignment {
option *val, *name;
hash = ( '[' ) >hash_start;
hashelem = ( string >mark %{_printf("hash key \"%s\" ", cpd->val_str->str);} noise* '=>' noise* (value|list|hash) %{_printf("value %s on line %zd of %s\n",
cpd->val_type == CONFP_BOOL ? "bool" : (cpd->val_type == CONFP_INT ? "int" : (cpd->val_type == CONFP_STR ? "str" : "list or hash")),
cpd->line, cpd->filename);} );
hashscanner := ( noise* (hashelem (noise* ',' noise* hashelem)*)? noise* ']' >hash_end );
/* top of the stack is the value, then the varname as string option */
val = g_queue_pop_head(ctx->option_stack);
name = g_queue_pop_head(ctx->option_stack);
varname = ( alpha ( alnum | [_.\-] )* ) >mark_var %varname;
assert(name->type == OPTION_STRING);
operator = ( '==' | '!=' | '=~' | '!~' | '<' | '<=' | '>' | '>=' ) >mark %operator;
g_print("got assignment: %s = %s; in line %zd\n", name->value.opt_string->str, option_type_string(val->type), ctx->line);
}
#assignment_bool = ( varname ws* '=' ws* boolean ';' ) %assignment_bool;
assignment = ( varname ws* '=' ws* ( value | list | hash) ';' ) %assignment;
#assignment = ( assignment_bool ) %assignment;
action function {
/* similar to assignment */
option *val, *name;
function = ( varname (ws+ (value|valuepair|list|hash))? ';' ) %function;
/* top of the stack is the value, then the varname as string option */
val = g_queue_pop_head(ctx->option_stack);
name = g_queue_pop_head(ctx->option_stack);
statement = ( assignment | function );
assert(name->type == OPTION_STRING);
incl = ( 'include' ws+ string ';' ) %incl;
incl_shell = ( 'include_shell' ws+ string ';' ) %incl_shell;
if (g_str_equal(name->value.opt_string->str, "include")) {
if (val->type != OPTION_STRING) {
/* TODO */
}
}
else if (g_str_equal(name->value.opt_string->str, "include_shell")) {
if (val->type != OPTION_STRING) {
/* TODO */
}
}
else {
/* TODO */
}
block = ( '{' >block_start );
g_print("got function: %s %s; in line %zd\n", name->value.opt_string->str, option_type_string(val->type), ctx->line);
}
condition_var = (
'con.ip' | 'req.host' | 'req.path' | 'req.agent' | 'req.scheme' | 'serv.socket' |
'req.cookie' | 'req.query' | 'req.method' | 'req.length' | 'req.referer' |
'phys.path' | 'phys.exists' | 'phys.size' | 'resp.size' | 'resp.status'
) >mark_var;
action condition {
/* stack: value, varname */
option *v, *n;
condition = ( condition_var %varname ws* operator ws* value >condition noise* block );
v = g_queue_pop_head(ctx->option_stack);
n = g_queue_pop_head(ctx->option_stack);
assert(n->type == OPTION_STRING);
blockscanner := ( (noise | comment | statement | condition | incl | incl_shell )* '}' >block_end );
g_print("got condition: %s %s %s in line %zd\n", n->value.opt_string->str, option_type_string(v->type), comp_op_to_string(ctx->op), ctx->line);
}
fooblock = ( varname ws+ varname ws* block ) %fooblock;
action action_block {
option *o;
main := ( noise | comment | statement | condition | fooblock | incl | incl_shell )* '\00';
}%%
o = g_queue_pop_head(ctx->option_stack);
assert(o->type == OPTION_STRING);
%% write data;
g_print("action block %s in line %zd\n", o->value.opt_string->str, ctx->line);
}
config_parser_context_t *config_parser_init() {
config_parser_context_t *ctx;
action_list *al;
ctx = g_slice_new(config_parser_context_t);
ctx->stack = NULL;
## definitions
al = action_list_new();
ctx->action_list_stack = g_list_prepend(NULL, al);
# basic types
boolean = ( 'true' | 'false' ) %boolean;
integer = ( 0 | ( [1-9] [0-9]* ) ) %integer;
integer_suffix_bytes = ( 'b' | 'kb' | 'mb' | 'gb' | 'tb' | 'pb' );
integer_suffix_seconds = ( 's' | 'm' | 'h' | 'd' );
string = ( '"' (any-'"')* '"' ) %string;
return ctx;
}
# misc stuff
line_sane = ( '\n' ) >{ ctx->line++; };
line_weird = ( '\r' ) >{ ctx->line++; };
line_insane = ( '\r\n' ) >{ ctx->line--; };
line = ( line_sane | line_weird | line_insane );
void config_parser_finish(config_parser_context_t *ctx) {
assert(ctx->stack == NULL);
ws = ( '\t' | ' ' );
noise = ( ws | line );
g_slice_free(config_parser_context_t, ctx);
}
comment = ( '#' (any - line)* line );
block = ( '{' >block_start );
config_parser_data_t *config_parser_data_new() {
config_parser_data_t *cpd;
# advanced types
varname = ( alpha ( alnum | [._\-] )* ) >mark %varname;
actionref = ( varname );
list = ( '(' >list_start );
hash = ( '[' >hash_start );
keyvalue = ( string ws* '=>' ws* >keyvalue_start );
value = ( boolean | integer | string | list | hash | keyvalue | actionref ) >mark %value;
hash_elem = ( string >mark noise* ':' noise* value );
cpd = g_slice_new0(config_parser_data_t);
operator = ( '==' | '!=' | '<' | '<=' | '>' | '>=' | '=~' | '!~' );
cpd->line = 1;
# statements
assignment = ( varname ws* '=' ws* value ';' ) %assignment;
function = ( varname ws+ value ';' ) %function;
condition = ( varname ws* operator ws* value noise* block ) %condition;
action_block = ( varname ws* block ) %action_block;
/* allocate stack of 8 items. sufficient for most configs, will grow when needed */
cpd->stack = (int*) g_malloc(sizeof(int) * 8);
cpd->stacksize = 8;
statement = ( assignment | function | condition | action_block );
# scanner
keyvalue_scanner := ( value any >{fpc--;} >keyvalue_end );
block_scanner := ( (noise | comment | statement)* '}' >block_end );
list_scanner := ( noise* (value %list_push (noise* ',' noise* value %list_push)*)? noise* ')' >list_end );
hash_scanner := ( noise* (hash_elem %hash_push (noise* ',' noise* hash_elem %hash_push)*)? noise* ']' >hash_end );
main := (noise | comment | statement)* '\00';
}%%
%% write data;
config_parser_context_t *config_parser_context_new(GList *ctx_stack) {
config_parser_context_t *ctx;
ctx = g_slice_new0(config_parser_context_t);
ctx->line = 1;
/* allocate stack of 8 items. sufficient for most configs, will grow when needed */
ctx->stack = (int*) g_malloc(sizeof(int) * 8);
ctx->stacksize = 8;
cpd->val_str = g_string_sized_new(0);
cpd->varname = g_string_sized_new(0);
if (ctx_stack != NULL) {
/* inherit old stacks */
ctx->action_list_stack = ((config_parser_context_t*) ctx_stack->data)->action_list_stack;
ctx->option_stack = ((config_parser_context_t*) ctx_stack->data)->option_stack;
}
else {
ctx->action_list_stack = g_queue_new();
ctx->option_stack = g_queue_new();
}
return cpd;
return ctx;
}
void config_parser_data_free(config_parser_data_t *cpd)
void config_parser_context_free(config_parser_context_t *ctx, gboolean free_queues)
{
g_string_free(cpd->val_str, TRUE);
g_string_free(cpd->varname, TRUE);
g_free(ctx->stack);
g_free(cpd->stack);
if (free_queues) {
g_assert_cmpuint(ctx->action_list_stack->length, ==, 0);
g_assert_cmpuint(ctx->option_stack->length, ==, 0);
g_queue_free(ctx->action_list_stack);
g_queue_free(ctx->option_stack);
}
g_slice_free(config_parser_data_t, cpd);
g_slice_free(config_parser_context_t, ctx);
}
gboolean config_parser_file(server *srv, config_parser_context_t *ctx, const gchar *path) {
gboolean config_parser_file(server *srv, GList *ctx_stack, const gchar *path) {
config_parser_context_t *ctx;
gboolean res;
config_parser_data_t *cpd;
GError *err = NULL;
cpd = config_parser_data_new();
cpd->filename = (gchar*) path;
ctx = config_parser_context_new(ctx_stack);
ctx->filename = (gchar*) path;
if (!g_file_get_contents(path, &cpd->ptr, &cpd->len, &err))
if (!g_file_get_contents(path, &ctx->ptr, &ctx->len, &err))
{
/* could not read file */
/* TODO: die("could not read config file. reason: \"%s\" (%d)\n", err->message, err->code); */
_printf("could not read config file \"%s\". reason: \"%s\" (%d)\n", path, err->message, err->code);
config_parser_data_free(cpd);
log_warning(srv, NULL, "could not read config file \"%s\". reason: \"%s\" (%d)", path, err->message, err->code);
config_parser_context_free(ctx, FALSE);
g_error_free(err);
return FALSE;
}
/* push on stack */
ctx->stack = g_list_prepend(ctx->stack, cpd);
ctx_stack = g_list_prepend(ctx_stack, ctx);
res = config_parser_buffer(srv, ctx_stack);
res = config_parser_buffer(srv, ctx);
if (!res)
log_warning(srv, NULL, "config parsing failed in line %zd of %s", ctx->line, ctx->filename);
/* pop from stack */
ctx->stack = g_list_delete_link(ctx->stack, ctx->stack);
ctx_stack = g_list_delete_link(ctx_stack, ctx_stack);
/* have to free the buffer on our own */
g_free(cpd->ptr);
config_parser_data_free(cpd);
g_free(ctx->ptr);
config_parser_context_free(ctx, FALSE);
return res;
}
gboolean config_parser_shell(server *srv, config_parser_context_t *ctx, const gchar *command)
gboolean config_parser_shell(server *srv, GList *ctx_stack, const gchar *command)
{
gboolean res;
gchar* _stdout;
gchar* _stderr;
gint status;
config_parser_data_t *cpd;
config_parser_context_t *ctx;
GError *err = NULL;
cpd = config_parser_data_new();
cpd->filename = (gchar*) command;
ctx = config_parser_context_new(ctx_stack);
ctx->filename = (gchar*) command;
if (!g_spawn_command_line_sync(command, &_stdout, &_stderr, &status, &err))
{
_printf("error launching shell command \"%s\": %s (%d)\n", command, err->message, err->code);
config_parser_data_free(cpd);
log_warning(srv, NULL, "error launching shell command \"%s\": %s (%d)", command, err->message, err->code);
config_parser_context_free(ctx, FALSE);
g_error_free(err);
return FALSE;
}
if (status != 0)
{
_printf("shell command \"%s\" exited with status %d\n", command, status);
_printf("%s\n----\n%s\n", _stdout, _stderr);
log_warning(srv, NULL, "shell command \"%s\" exited with status %d", command, status);
log_debug(srv, NULL, "stdout:\n-----\n%s\n-----\nstderr:\n-----\n%s\n-----", _stdout, _stderr);
g_free(_stdout);
g_free(_stderr);
config_parser_data_free(cpd);
config_parser_context_free(ctx, FALSE);
return FALSE;
}
cpd->len = strlen(_stdout);
cpd->ptr = _stdout;
ctx->len = strlen(_stdout);
ctx->ptr = _stdout;
_printf("included shell output from \"%s\" (%zu bytes):\n%s\n", command, cpd->len, _stdout);
log_debug(srv, NULL, "included shell output from \"%s\" (%zu bytes)", command, ctx->len, _stdout);
ctx->stack = g_list_prepend(ctx->stack, cpd);
res = config_parser_buffer(srv, ctx);
ctx->stack = g_list_delete_link(ctx->stack, ctx->stack);
/* push on stack */
ctx_stack = g_list_prepend(ctx_stack, ctx);
/* parse buffer */
res = config_parser_buffer(srv, ctx_stack);
/* pop from stack */
ctx_stack = g_list_delete_link(ctx_stack, ctx_stack);
g_free(_stdout);
g_free(_stderr);
config_parser_data_free(cpd);
config_parser_context_free(ctx, FALSE);
return res;
}
gboolean config_parser_buffer(server *srv, config_parser_context_t *ctx)
gboolean config_parser_buffer(server *srv, GList *ctx_stack)
{
config_parser_data_t *cpd;
config_parser_context_t *ctx;
/* get top of stack */
cpd = ctx->stack->data;
ctx = (config_parser_context_t*) ctx_stack->data;
cpd->p = cpd->ptr;
cpd->pe = cpd->ptr + cpd->len + 1; /* marks the end of the data to scan (+1 because of trailing \0 char) */
ctx->p = ctx->ptr;
ctx->pe = ctx->ptr + ctx->len + 1; /* marks the end of the data to scan (+1 because of trailing \0 char) */
%% write init;
%% write exec;
if (cpd->cs == config_parser_error || cpd->cs == config_parser_first_final)
if (ctx->cs == config_parser_error || ctx->cs == config_parser_first_final)
{
/* parse error */
g_printerr("parse error in line %zd of \"%s\" at character %c (0x%.2x)\n", cpd->line, cpd->filename, *cpd->p, *cpd->p);
log_warning(srv, NULL, "parse error in line %zd of \"%s\" at character %c (0x%.2x)", ctx->line, ctx->filename, *ctx->p, *ctx->p);
return FALSE;
}

@ -1,6 +1,5 @@
#include "base.h"
#include "log.h"
#include "config_parser.h"
#ifdef HAVE_LUA_H
@ -13,6 +12,7 @@ int main(int argc, char *argv[]) {
GError *error;
GOptionContext *context;
server *srv;
gboolean res;
gchar *config_path = NULL;
gboolean luaconfig = FALSE;
@ -32,7 +32,11 @@ int main(int argc, char *argv[]) {
context = g_option_context_new("- fast and lightweight webserver");
g_option_context_add_main_entries(context, entries, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
res = g_option_context_parse(context, &argc, &argv, &error);
g_option_context_free(context);
if (!res) {
g_printerr("failed to parse command line arguments: %s\n", error->message);
return 1;
}
@ -57,14 +61,34 @@ int main(int argc, char *argv[]) {
if (config_path == NULL)
config_path = "lighttpd.conf";
g_print("config path: %s\n", config_path);
log_debug(srv, NULL, "config path: %s", config_path);
if (!luaconfig) {
GTimeVal start, end;
gulong s, millis, micros;
g_get_current_time(&start);
/* standard config frontend */
config_parser_context_t *cp_ctx = config_parser_init();
if (!config_parser_file(srv, cp_ctx, config_path)) {
config_parser_context_t *ctx = config_parser_context_new(NULL);
GList *ctx_stack = g_list_append(NULL, ctx);
if (!config_parser_file(srv, ctx_stack, config_path)) {
for (guint i = 0; i < g_queue_get_length(ctx->action_list_stack); i++) { /* TODO */ }
for (guint i = 0; i < g_queue_get_length(ctx->option_stack); i++) { option_free(g_queue_peek_nth(ctx->option_stack, i)); }
config_parser_context_free(ctx, TRUE);
log_thread_start(srv);
g_atomic_int_set(&srv->exiting, TRUE);
log_thread_wakeup(srv);
g_thread_join(srv->log_thread);
return 1;
}
g_get_current_time(&end);
start.tv_usec = end.tv_usec - start.tv_usec;
s = start.tv_sec = end.tv_sec - start.tv_sec;
millis = start.tv_usec / 1000;
micros = start.tv_usec % 1000;
g_print("parsed config file in %zd seconds, %zd milliseconds, %zd microseconds\n", start.tv_sec, millis, micros);
g_print("option_stack: %u action_list_stack: %u\n", g_queue_get_length(ctx->option_stack), g_queue_get_length(ctx->action_list_stack));
}
else {
#ifdef HAVE_LUA_H
@ -98,5 +122,7 @@ int main(int argc, char *argv[]) {
log_thread_wakeup(srv);
g_thread_join(srv->log_thread);
server_free(srv);
return 0;
}

@ -105,10 +105,7 @@ gpointer log_thread(server *srv) {
queue = srv->log_queue;
while (TRUE) {
/* lighty is exiting, end logging thread */
if (g_atomic_int_get(&srv->exiting) && g_async_queue_length(srv->log_queue) == 0)
break;
/* do we need to rotate logs? */
if (g_atomic_int_get(&srv->rotate_logs)) {
g_atomic_int_set(&srv->rotate_logs, FALSE);
g_mutex_lock(srv->log_mutex);
@ -120,6 +117,11 @@ gpointer log_thread(server *srv) {
if (log_entry->log == NULL) {
g_slice_free(log_entry_t, log_entry);
/* lighty is exiting, end logging thread */
if (g_atomic_int_get(&srv->exiting) && g_async_queue_length(srv->log_queue) == 0)
break;
continue;
}

@ -85,6 +85,7 @@ static gboolean core_listen(server *srv, plugin* p, option *opt) {
static const plugin_option options[] = {
{ "static-file.exclude", OPTION_LIST, NULL, NULL },
{ "log.level", OPTION_STRING, NULL, NULL },
{ NULL, 0, NULL, NULL }
};

@ -21,7 +21,6 @@ server* server_new() {
srv->actions = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_action_free);
srv->setups = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, server_setup_free);
srv->mutex = g_mutex_new();
srv->actions = action_list_new();
return srv;
}
@ -38,7 +37,7 @@ void server_free(server* srv) {
/* free logs */
g_hash_table_destroy(srv->logs);
g_mutex_free(srv->log_mutex);
g_async_queue_unref(srv->log_queue);
g_slice_free(server, srv);

Loading…
Cancel
Save