diff --git a/src/chunk.c b/src/chunk.c index fe1eb14..bb512ec 100644 --- a/src/chunk.c +++ b/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; diff --git a/src/config_parser.h b/src/config_parser.h index 7f33a01..e055e22 100644 --- a/src/config_parser.h +++ b/src/config_parser.h @@ -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; diff --git a/src/config_parser.rl b/src/config_parser.rl index 134ead8..6a6220b 100644 --- a/src/config_parser.rl +++ b/src/config_parser.rl @@ -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); + action function_noparam { + option *name; + action *a, *al; - a = action_new_setting(srv, name->value.opt_string->str, val); + name = g_queue_pop_head(ctx->option_stack); - if (a == NULL) - return FALSE; + 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->actions, a); -*/ -UNUSED(a); UNUSED(al); + g_array_append_val(al->value.list, a); + } + } } - action function { + 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; diff --git a/src/lighttpd.c b/src/lighttpd.c index 745c8f7..aefec68 100644 --- a/src/lighttpd.c +++ b/src/lighttpd.c @@ -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 diff --git a/src/log.c b/src/log.c index 32de73f..aa8b972 100644 --- a/src/log.c +++ b/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); diff --git a/src/log.h b/src/log.h index 3d68cad..8403d88 100644 --- a/src/log.h +++ b/src/log.h @@ -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); diff --git a/src/plugin.c b/src/plugin.c index cb92433..f5a88f3 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -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; } diff --git a/src/plugin_core.c b/src/plugin_core.c index 8597c2b..9b7e2ff 100644 --- a/src/plugin_core.c +++ b/src/plugin_core.c @@ -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 },