fixed segfault in chunkqueue with filename NULL; changed log_un/ref to use mutex; made core_handle_test more verbose; initial working version of config parser
commit
6bbda1a08b
14
src/chunk.c
14
src/chunk.c
|
@ -132,11 +132,11 @@ handler_t chunkiter_read(server *srv, connection *con, chunkiter iter, off_t sta
|
|||
/* prefer the error of the first syscall */
|
||||
if (0 != mmap_errno) {
|
||||
CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
c->file.file->name ? c->file.file->name->str : "(null)", c->file.file->fd,
|
||||
strerror(mmap_errno), mmap_errno);
|
||||
} else {
|
||||
CON_ERROR(srv, con, "lseek failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
c->file.file->name ? c->file.file->name->str : "(null)", c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
g_string_free(c->mem, TRUE);
|
||||
|
@ -149,11 +149,11 @@ read_chunk:
|
|||
/* prefer the error of the first syscall */
|
||||
if (0 != mmap_errno) {
|
||||
CON_ERROR(srv, con, "mmap failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
c->file.file->name ? c->file.file->name->str : "(null)", c->file.file->fd,
|
||||
strerror(mmap_errno), mmap_errno);
|
||||
} else {
|
||||
CON_ERROR(srv, con, "read failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
c->file.file->name ? c->file.file->name->str : "(null)", c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
g_string_free(c->mem, TRUE);
|
||||
|
@ -170,10 +170,10 @@ read_chunk:
|
|||
} else {
|
||||
#ifdef HAVE_MADVISE
|
||||
/* don't advise files < 64Kb */
|
||||
if (c->file.mmap.length > (64*1024) &&
|
||||
if (c->file.mmap.length > (64*1024) &&
|
||||
0 != madvise(c->file.mmap.data, c->file.mmap.length, MADV_WILLNEED)) {
|
||||
CON_ERROR(srv, con, "madvise failed for '%s' (fd = %i): %s (%i)",
|
||||
c->file.file->name->str, c->file.file->fd,
|
||||
c->file.file->name ? c->file.file->name->str : "(null)", c->file.file->fd,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
#endif
|
||||
|
@ -288,7 +288,7 @@ static void __chunkqueue_append_file(chunkqueue *cq, GString *filename, off_t st
|
|||
c->file.file = chunkfile_new(filename, fd, is_temp);
|
||||
c->file.start = start;
|
||||
c->file.length = length;
|
||||
|
||||
|
||||
g_queue_push_tail(cq->queue, c);
|
||||
cq->length += length;
|
||||
cq->bytes_in += length;
|
||||
|
|
|
@ -32,15 +32,18 @@ struct config_parser_context_t {
|
|||
|
||||
gchar *mark;
|
||||
gboolean in_setup_block;
|
||||
gboolean condition_with_key;
|
||||
|
||||
comp_operator_t op;
|
||||
gchar value_op;
|
||||
|
||||
|
||||
GHashTable *action_blocks; /* foo { } */
|
||||
GHashTable *uservars; /* var.foo */
|
||||
|
||||
GQueue *action_list_stack; /* first entry is current action list */
|
||||
GQueue *option_stack; /* stack of option* */
|
||||
GQueue *condition_stack; /* stack of condition* */
|
||||
|
||||
/* information about currenty parsed file */
|
||||
gchar *filename;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "condition.h"
|
||||
#include "config_parser.h"
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
#define _printf(fmt, ...) g_print(fmt, __VA_ARGS__)
|
||||
#else
|
||||
#define _printf(fmt, ...) /* */
|
||||
|
@ -380,7 +380,7 @@
|
|||
|
||||
if (ctx->in_setup_block) {
|
||||
/* in setup { } block => set default values for options */
|
||||
option_free(name);
|
||||
/* todo name */
|
||||
}
|
||||
else if (g_str_has_prefix(name->value.opt_string->str, "var.")) {
|
||||
/* assignment vor user defined variable, insert into hashtable */
|
||||
|
@ -388,23 +388,51 @@
|
|||
}
|
||||
else {
|
||||
/* normal assignment */
|
||||
a = option_action(srv, name->value.opt_string->str, val);
|
||||
|
||||
if (a == NULL)
|
||||
return FALSE;
|
||||
|
||||
al = g_queue_peek_head(ctx->action_list_stack);
|
||||
g_array_append_val(al->value.list, a);
|
||||
option_free(name);
|
||||
}
|
||||
|
||||
/*
|
||||
al = g_queue_peek_head(ctx->action_list_stack);
|
||||
|
||||
a = action_new_setting(srv, name->value.opt_string->str, val);
|
||||
|
||||
if (a == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_array_append_val(al->actions, a);
|
||||
*/
|
||||
UNUSED(a); UNUSED(al);
|
||||
}
|
||||
|
||||
action function {
|
||||
action function_noparam {
|
||||
option *name;
|
||||
action *a, *al;
|
||||
|
||||
name = g_queue_pop_head(ctx->option_stack);
|
||||
|
||||
assert(name->type == OPTION_STRING);
|
||||
|
||||
_printf("got function: %s; in line %zd\n", name->value.opt_string->str, ctx->line);
|
||||
|
||||
if (g_str_equal(name->value.opt_string->str, "break")) {
|
||||
}
|
||||
else if (g_str_equal(name->value.opt_string->str, "__halt")) {
|
||||
}
|
||||
else {
|
||||
if (ctx->in_setup_block) {
|
||||
/* we are in the setup { } block, call setups and don't append to action list */
|
||||
if (!call_setup(srv, name->value.opt_string->str, NULL)) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
al = g_queue_peek_head(ctx->action_list_stack);
|
||||
a = create_action(srv, name->value.opt_string->str, NULL);
|
||||
|
||||
if (a == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_array_append_val(al->value.list, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action function_param {
|
||||
/* similar to assignment */
|
||||
option *val, *name;
|
||||
action *a, *al;
|
||||
|
@ -453,6 +481,8 @@ UNUSED(a); UNUSED(al);
|
|||
|
||||
if (a == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_array_append_val(al->value.list, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -460,17 +490,68 @@ UNUSED(a); UNUSED(al);
|
|||
}
|
||||
|
||||
action condition_start {
|
||||
/* stack: value, varname */
|
||||
option *v, *n;
|
||||
/* stack: value, varname OR value, key, varname */
|
||||
option *v, *n, *k;
|
||||
gchar *str;
|
||||
condition *cond;
|
||||
condition_lvalue *lvalue;
|
||||
|
||||
v = g_queue_pop_head(ctx->option_stack);
|
||||
if (ctx->condition_with_key)
|
||||
k = g_queue_pop_head(ctx->option_stack);
|
||||
else
|
||||
k = NULL;
|
||||
n = g_queue_pop_head(ctx->option_stack);
|
||||
|
||||
assert(n->type == OPTION_STRING);
|
||||
|
||||
_printf("got condition: %s %s %s in line %zd\n", n->value.opt_string->str, comp_op_to_string(ctx->op), option_type_string(v->type), ctx->line);
|
||||
_printf("got condition: %s:%s %s %s in line %zd\n", n->value.opt_string->str, ctx->condition_with_key ? k->value.opt_string->str : "", comp_op_to_string(ctx->op), option_type_string(v->type), ctx->line);
|
||||
|
||||
/* create condition lvalue */
|
||||
str = n->value.opt_string->str;
|
||||
if (g_str_equal(str, "req.path") || g_str_equal(str, "request.path"))
|
||||
lvalue = condition_lvalue_new(COMP_REQUEST_PATH, NULL);
|
||||
else {
|
||||
log_warning(srv, NULL, "unkown lvalue for condition: %s", str);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (v->type == OPTION_STRING) {
|
||||
cond = condition_new_string(srv, ctx->op, lvalue, v->value.opt_string);
|
||||
}
|
||||
else if (v->type == OPTION_INT)
|
||||
cond = condition_new_int(srv, ctx->op, lvalue, (gint64) v->value.opt_int);
|
||||
else {
|
||||
cond = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (cond == NULL) {
|
||||
log_warning(srv, NULL, "could not create condition", "");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_queue_push_head(ctx->condition_stack, cond);
|
||||
|
||||
g_queue_push_head(ctx->action_list_stack, action_new_list());
|
||||
|
||||
/* TODO: free stuff */
|
||||
ctx->condition_with_key = FALSE;
|
||||
}
|
||||
|
||||
action condition_end {
|
||||
condition *cond;
|
||||
action *a, *al;
|
||||
|
||||
cond = g_queue_pop_head(ctx->condition_stack);
|
||||
al = g_queue_pop_head(ctx->action_list_stack);
|
||||
a = action_new_condition(cond, al);
|
||||
al = g_queue_peek_head(ctx->action_list_stack);
|
||||
g_array_append_val(al->value.list, a);
|
||||
}
|
||||
|
||||
action condition_key {
|
||||
ctx->condition_with_key = TRUE;
|
||||
}
|
||||
|
||||
action action_block_start {
|
||||
|
@ -553,9 +634,11 @@ UNUSED(a); UNUSED(al);
|
|||
|
||||
# statements
|
||||
assignment = ( varname ws* '=' ws* value_statement ';' ) %assignment;
|
||||
function = ( varname ws+ value ';' ) %function;
|
||||
condition = ( varname ws* operator ws* value noise* block >condition_start ) %condition_end;
|
||||
action_block = ( varname ws* block >action_block_start ) %action_block_end;
|
||||
function_noparam = ( varname ';' ) %function_noparam;
|
||||
function_param = ( varname ws+ value_statement ';') %function_param;
|
||||
function = ( function_noparam | function_param );
|
||||
condition = ( varname ('[' string >mark ']' %condition_key)? ws* operator ws* value_statement noise* block >condition_start ) %condition_end;
|
||||
action_block = ( varname noise* block >action_block_start ) %action_block_end;
|
||||
|
||||
statement = ( assignment | function | condition | action_block );
|
||||
|
||||
|
@ -638,6 +721,7 @@ config_parser_context_t *config_parser_context_new(server *srv, GList *ctx_stack
|
|||
/* 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;
|
||||
ctx->condition_stack = ((config_parser_context_t*) ctx_stack->data)->condition_stack;
|
||||
|
||||
ctx->action_blocks = ((config_parser_context_t*) ctx_stack->data)->action_blocks;
|
||||
ctx->uservars = ((config_parser_context_t*) ctx_stack->data)->uservars;
|
||||
|
@ -648,6 +732,7 @@ config_parser_context_t *config_parser_context_new(server *srv, GList *ctx_stack
|
|||
|
||||
ctx->action_list_stack = g_queue_new();
|
||||
ctx->option_stack = g_queue_new();
|
||||
ctx->condition_stack = g_queue_new();
|
||||
}
|
||||
|
||||
return ctx;
|
||||
|
|
|
@ -75,7 +75,6 @@ int main(int argc, char *argv[]) {
|
|||
log_thread_start(srv);
|
||||
g_atomic_int_set(&srv->exiting, TRUE);
|
||||
log_thread_wakeup(srv);
|
||||
g_thread_join(srv->log_thread);
|
||||
server_free(srv);
|
||||
return 1;
|
||||
}
|
||||
|
@ -87,10 +86,10 @@ int main(int argc, char *argv[]) {
|
|||
s = d / 1000000;
|
||||
millis = (d - s) / 1000;
|
||||
micros = (d - s - millis) %1000;
|
||||
g_print("parsed config file in %zd seconds, %zd milliseconds, %zd microseconds\n", s, millis, micros);
|
||||
g_print("parsed config file in %lu seconds, %lu milliseconds, %lu microseconds\n", s, millis, micros);
|
||||
g_print("option_stack: %u action_list_stack: %u (should be 0:1)\n", g_queue_get_length(ctx->option_stack), g_queue_get_length(ctx->action_list_stack));
|
||||
|
||||
config_parser_finish(srv, ctx_stack);
|
||||
/* TODO config_parser_finish(srv, ctx_stack); */
|
||||
}
|
||||
else {
|
||||
#ifdef HAVE_LUA_H
|
||||
|
|
26
src/log.c
26
src/log.c
|
@ -51,7 +51,7 @@ gboolean log_write_(server *srv, connection *con, log_level_t log_level, const g
|
|||
if (log_level < log_level_want)
|
||||
return TRUE;
|
||||
|
||||
log_ref(log);
|
||||
log_ref(srv, log);
|
||||
|
||||
log_line = g_string_sized_new(0);
|
||||
va_start(ap, fmt);
|
||||
|
@ -62,6 +62,7 @@ gboolean log_write_(server *srv, connection *con, log_level_t log_level, const g
|
|||
if (g_string_equal(log->lastmsg, log_line)) {
|
||||
log->lastmsg_count++;
|
||||
log_unref(srv, log);
|
||||
g_string_free(log_line, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
|
@ -186,13 +187,19 @@ void log_rotate_logs(server *srv) {
|
|||
}
|
||||
|
||||
|
||||
void log_ref(log_t *log) {
|
||||
g_atomic_int_inc(&log->refcount);
|
||||
void log_ref(server *srv, log_t *log) {
|
||||
g_mutex_lock(srv->log_mutex);
|
||||
log->refcount++;
|
||||
g_mutex_unlock(srv->log_mutex);
|
||||
}
|
||||
|
||||
void log_unref(server *srv, log_t *log) {
|
||||
g_mutex_lock(srv->log_mutex);
|
||||
|
||||
if (g_atomic_int_dec_and_test(&log->refcount))
|
||||
log_free(srv, log);
|
||||
log_free_unlocked(srv, log);
|
||||
|
||||
g_mutex_unlock(srv->log_mutex);
|
||||
}
|
||||
|
||||
log_t *log_new(server *srv, log_type_t type, GString *path) {
|
||||
|
@ -205,7 +212,7 @@ log_t *log_new(server *srv, log_type_t type, GString *path) {
|
|||
/* log already open, inc refcount */
|
||||
if (log != NULL)
|
||||
{
|
||||
g_atomic_int_inc(&log->refcount);
|
||||
log->refcount++;
|
||||
g_mutex_unlock(srv->log_mutex);
|
||||
return log;
|
||||
}
|
||||
|
@ -220,6 +227,7 @@ log_t *log_new(server *srv, log_type_t type, GString *path) {
|
|||
case LOG_TYPE_PIPE:
|
||||
case LOG_TYPE_SYSLOG:
|
||||
/* TODO */
|
||||
fd = -1;
|
||||
assert(NULL);
|
||||
}
|
||||
|
||||
|
@ -239,8 +247,16 @@ log_t *log_new(server *srv, log_type_t type, GString *path) {
|
|||
return log;
|
||||
}
|
||||
|
||||
/* only call this if srv->log_mutex is NOT locked */
|
||||
void log_free(server *srv, log_t *log) {
|
||||
g_mutex_lock(srv->log_mutex);
|
||||
log_free_unlocked(srv, log);
|
||||
g_mutex_unlock(srv->log_mutex);
|
||||
}
|
||||
|
||||
/* only call this if srv->log_mutex IS locked */
|
||||
void log_free_unlocked(server *srv, log_t *log) {
|
||||
g_mutex_lock(srv->log_mutex);
|
||||
|
||||
if (log->type == LOG_TYPE_FILE || log->type == LOG_TYPE_PIPE)
|
||||
close(log->fd);
|
||||
|
|
|
@ -110,12 +110,14 @@ struct log_entry_t {
|
|||
log_t *log_new(server *srv, log_type_t type, GString *path);
|
||||
/* avoid calling log_free directly. instead use log_unref which calls log_free if refcount has reached zero */
|
||||
void log_free(server *srv, log_t *log);
|
||||
void log_free_unlocked(server *srv, log_t *log);
|
||||
|
||||
void log_ref(log_t *log);
|
||||
void log_ref(server *srv, log_t *log);
|
||||
void log_unref(server *srv, log_t *log);
|
||||
|
||||
/* do not call directly, use log_rotate_logs instead */
|
||||
void log_rotate(gchar *path, log_t *log, server *srv);
|
||||
|
||||
void log_rotate_logs(server *srv);
|
||||
|
||||
gpointer log_thread(server *srv);
|
||||
|
|
|
@ -174,8 +174,8 @@ gboolean parse_option(server *srv, const char *name, option *opt, option_set *ma
|
|||
}
|
||||
|
||||
if (sopt->type != opt->type) {
|
||||
ERROR(srv, "Unexpected option type '%s', expected '%s'",
|
||||
option_type_string(opt->type), option_type_string(sopt->type));
|
||||
ERROR(srv, "Unexpected option type '%s', expected '%s' for option %s",
|
||||
option_type_string(opt->type), option_type_string(sopt->type), name);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -173,12 +173,30 @@ static action* core_static(server *srv, plugin* p, option *opt) {
|
|||
}
|
||||
|
||||
static action_result core_handle_test(server *srv, connection *con, gpointer param) {
|
||||
GHashTableIter iter;
|
||||
gpointer k, v;
|
||||
GList *hv;
|
||||
UNUSED(param);
|
||||
|
||||
if (con->state != CON_STATE_HANDLE_REQUEST_HEADER) return ACTION_GO_ON;
|
||||
|
||||
con->response.http_status = 200;
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN("path: "));
|
||||
chunkqueue_append_mem(con->out, GSTR_LEN(con->request.uri.path));
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\nquery: "));
|
||||
chunkqueue_append_mem(con->out, GSTR_LEN(con->request.uri.query));
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\n\r\n--- Headers ---\r\n"));
|
||||
g_hash_table_iter_init(&iter, con->request.headers->table);
|
||||
while (g_hash_table_iter_next(&iter, &k, &v)) {
|
||||
hv = g_queue_peek_head_link(&((http_header*)v)->values);
|
||||
while (hv != NULL) {
|
||||
chunkqueue_append_mem(con->out, GSTR_LEN(((http_header*)v)->key));
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN(": "));
|
||||
chunkqueue_append_mem(con->out, GSTR_LEN((GString*)hv->data));
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\n"));
|
||||
hv = hv->next;
|
||||
}
|
||||
}
|
||||
chunkqueue_append_mem(con->out, CONST_STR_LEN("\r\n"));
|
||||
connection_handle_direct(srv, con);
|
||||
|
||||
|
@ -251,7 +269,7 @@ static gboolean core_listen(server *srv, plugin* p, option *opt) {
|
|||
}
|
||||
|
||||
static const plugin_option options[] = {
|
||||
{ "debug.log-request-handling", OPTION_BOOLEAN, NULL, NULL},
|
||||
{ "debug.log_request_handling", OPTION_BOOLEAN, NULL, NULL},
|
||||
{ "log.level", OPTION_STRING, NULL, NULL },
|
||||
|
||||
{ "static-file.exclude", OPTION_LIST, NULL, NULL },
|
||||
|
|
Loading…
Reference in New Issue