diff --git a/src/actions.h b/src/actions.h index 560b0a1..053bbb5 100644 --- a/src/actions.h +++ b/src/actions.h @@ -9,82 +9,63 @@ typedef enum { ACTION_SETTING, ACTION_FUNCTION, ACTION_CONDITION } action_type; struct action; typedef struct action action; -// condition operator -typedef enum -{ - CONDITION_EQUAL, CONDITION_UNEQUAL, - CONDITION_LESS, CONDITION_LESS_EQUAL, - CONDITION_GREATER, CONDITION_GREATER_EQUAL, - CONDITION_REGEX_MATCH, CONDITION_REGEX_NOMATCH -} condition_op; - -// condition type -typedef enum { CONDITION_BOOL, CONDITION_INT, CONDITION_STRING, CONDITION_IP } condition_type; - -struct condition; -typedef struct condition condition; - - -struct action_list -{ - GArray* actions; - guint refcount; -} +struct action_list; typedef struct action_list action_list; -struct action_stack -{ - GArray* stack; - guint index; -} +struct action_stack; typedef struct action_stack action_stack; -struct action_stack_elem -{ + + + +struct action_list { + GArray* actions; + guint refcount; +}; + +struct action_stack { + GArray* stack; + guint index; +}; + +struct action_stack_elem { action_list* al; guint index; -} +}; typedef struct action_stack_elem action_stack_elem; -struct action -{ +struct action { action_type type; - union - { - struct - { + union { + struct { option_mark opt; option newvalue; } setting; condition cond; - struct - { + struct { action_func* func; gpointer param; } actionfunc; } value; }; -struct condition -{ +struct condition { condition_type type; condition_op op; action_list* target; // action target to jump to if condition is fulfilled // left value of condition - union - { + union { guint val_int; gboolean val_bool; GString* val_string; } lvalue; // right value of condition - union - { + union { guint val_int; gboolean val_bool; GString* val_string; diff --git a/src/condition.c b/src/condition.c new file mode 100644 index 0000000..6a0426f --- /dev/null +++ b/src/condition.c @@ -0,0 +1,189 @@ + +#include "condition.h" +#include "log.h" + +static condition* condition_find_cached(server *srv, GString *key); +static void condition_cache_insert(server *srv, GString *key, condition *c); +static condition* condition_new(config_cond_t cond, comp_key_t comp); +static condition* condition_new_with_string(config_cond_t cond, comp_key_t comp, GString *str); +static condition* condition_new_with_int(config_cond_t cond, comp_key_t comp, gint i); +static void condition_free(condition *c); + +static condition* condition_find_cached(server *srv, GString *key) { + UNUSED(srv); + UNUSED(key); + + return NULL; +} + +static void condition_cache_insert(server *srv, GString *key, condition *c) { + UNUSED(srv); + UNUSED(c); + + g_string_free(key, TRUE); +} + +static condition* condition_new(config_cond_t cond, comp_key_t comp) { + condition *c = g_slice_new0(condition); + c->refcount = 1; + c->cache_index = -1; + c->cond = cond; + c->comp = comp; + return c; +} + +static condition* condition_new_with_string(config_cond_t cond, comp_key_t comp, GString *str) { + condition *c = condition_new(cond, comp); + switch (c->cond) { + case CONFIG_COND_EQ: /** == */ + case CONFIG_COND_NE: /** != */ + c->value.string = str; + break; + case CONFIG_COND_MATCH: /** =~ */ + case CONFIG_COND_NOMATCH: /** !~ */ +#ifdef HAVE_PCRE_H + /* TODO */ + ERROR("Regular expressions not supported for now in condition: %s %s '%s'", + config_cond_to_string(cond), comp_key_to_string(comp), + str); + condition_free(c); + return NULL; + break; +#else + ERROR("Regular expressions not supported in condition: %s %s '%s'", + config_cond_to_string(cond), comp_key_to_string(comp), + str->str); + condition_free(c); + return NULL; +#endif + case CONFIG_COND_GT: /** > */ + case CONFIG_COND_GE: /** >= */ + case CONFIG_COND_LT: /** < */ + case CONFIG_COND_LE: /** <= */ + ERROR("Cannot compare with strings in condition: %s %s '%s'", + config_cond_to_string(cond), comp_key_to_string(comp), + str->str); + condition_free(c); + return NULL; + } + return c; +} + +static condition* condition_new_with_int(config_cond_t cond, comp_key_t comp, gint i) { + condition *c = condition_new(cond, comp); + switch (c->cond) { + case CONFIG_COND_EQ: /** == */ + case CONFIG_COND_NE: /** != */ + case CONFIG_COND_MATCH: /** =~ */ + case CONFIG_COND_NOMATCH: /** !~ */ + ERROR("Cannot compare with integer in condition: %s %s %i", + config_cond_to_string(cond), comp_key_to_string(comp), + i); + condition_free(c); + return NULL; + case CONFIG_COND_GT: /** > */ + case CONFIG_COND_GE: /** >= */ + case CONFIG_COND_LT: /** < */ + case CONFIG_COND_LE: /** <= */ + c->value.i = i; + break; + } + return c; +} + +condition* condition_new_string(server *srv, config_cond_t cond, comp_key_t comp, GString *str) { + condition *c; + GString *key = g_string_sized_new(0); + g_string_sprintf(key, "%i:%i:%s", (int) cond, (int) comp, str->str); + + if (NULL != (c = condition_find_cached(srv, key))) { + g_string_free(key, TRUE); + return c; + } + + c = condition_new_with_string(cond, comp, str); + condition_cache_insert(srv, key, c); + return c; +} + +condition* condition_new_int(server *srv, config_cond_t cond, comp_key_t comp, gint i) { + condition *c; + GString *key = g_string_sized_new(0); + g_string_sprintf(key, "%i:%i#%i", (int) cond, (int) comp, i); + + if (NULL != (c = condition_find_cached(srv, key))) { + g_string_free(key, TRUE); + return c; + } + + c = condition_new_with_int(cond, comp, i); + condition_cache_insert(srv, key, c); + return c; +} + +condition* condition_new_string_uncached(server *srv, config_cond_t cond, comp_key_t comp, GString *str) { + condition *c; + GString *key = g_string_sized_new(0); + g_string_sprintf(key, "%i:%i:%s", (int) cond, (int) comp, str->str); + + c = condition_find_cached(srv, key); + g_string_free(key, TRUE); + if (NULL != c) return c; + + return condition_new_with_string(cond, comp, str); +} + +condition* condition_new_int_uncached(server *srv, config_cond_t cond, comp_key_t comp, gint i) { + condition *c; + GString *key = g_string_sized_new(0); + g_string_sprintf(key, "%i:%i#%i", (int) cond, (int) comp, i); + + c = condition_find_cached(srv, key); + g_string_free(key, TRUE); + if (NULL != c) return c; + + return condition_new_with_int(cond, comp, i); +} + +static void condition_free(condition *c) { + switch (c->cond) { + case CONFIG_COND_EQ: /** == */ + case CONFIG_COND_NE: /** != */ + g_string_free(c->value.string, TRUE); + break; + case CONFIG_COND_MATCH: /** =~ */ + case CONFIG_COND_NOMATCH: /** !~ */ +#ifdef HAVE_PCRE_H + if (c->value.regex) pcre_free(c->value.regex); + if (c->value.regex_study) pcre_free(c->value.regex_study); +#endif + break; + case CONFIG_COND_GT: /** > */ + case CONFIG_COND_GE: /** >= */ + case CONFIG_COND_LT: /** < */ + case CONFIG_COND_LE: /** <= */ + break; + } + g_slice_free(condition, c); +} + +void condition_release(condition* c) { + /* assert(c->recount > 0); */ + if (!(--c->refcount)) { + condition_free(c); + } +} + +const char* config_cond_to_string(config_cond_t cond) { + UNUSED(cond); + + /* TODO */ + return ""; +} + +const char* comp_key_to_string(comp_key_t comp) { + UNUSED(comp); + + /* TODO */ + return ""; +} diff --git a/src/condition.h b/src/condition.h new file mode 100644 index 0000000..aca257d --- /dev/null +++ b/src/condition.h @@ -0,0 +1,76 @@ +#ifndef _LIGHTTPD_CONDITION_H_ +#define _LIGHTTPD_CONDITION_H_ + +/** + * possible compare ops in the configfile parser + */ +typedef enum { + CONFIG_COND_EQ, /** == */ + CONFIG_COND_MATCH, /** =~ */ + CONFIG_COND_NE, /** != */ + CONFIG_COND_NOMATCH, /** !~ */ + CONFIG_COND_GT, /** > */ + CONFIG_COND_GE, /** >= */ + CONFIG_COND_LT, /** < */ + CONFIG_COND_LE /** <= */ +} config_cond_t; + +/** + * possible fields to match against + */ +typedef enum { + COMP_UNSET, + COMP_SERVER_SOCKET, + COMP_HTTP_PATH, + COMP_HTTP_HOST, + COMP_HTTP_REFERER, + COMP_HTTP_USER_AGENT, + COMP_HTTP_COOKIE, + COMP_HTTP_SCHEME, + COMP_HTTP_REMOTE_IP, + COMP_HTTP_QUERY_STRING, + COMP_HTTP_REQUEST_METHOD, + COMP_PHYSICAL_PATH, + COMP_PHYSICAL_PATH_EXISTS, + + COMP_LAST_ELEMENT +} comp_key_t; + +struct condition; +typedef struct condition condition; + +#include "base.h" + +struct condition { + int refcount; + + config_cond_t cond; + comp_key_t comp; + + /* index into connection conditional caching table, -1 if uncached */ + int cache_index; + + union { + GString *string; +#ifdef HAVE_PCRE_H + struct { + pcre *regex; + pcre_extra *regex_study; + }; +#endif + gint i; + } value; +}; + +LI_API condition* condition_new_string(server *srv, config_cond_t cond, comp_key_t comp, GString *str); +LI_API condition* condition_new_int(server *srv, config_cond_t cond, comp_key_t comp, gint i); + +LI_API condition* condition_new_string_uncached(server *srv, config_cond_t cond, comp_key_t comp, GString *str); +LI_API condition* condition_new_int_uncached(server *srv, config_cond_t cond, comp_key_t comp, gint i); + +LI_API void condition_release(condition* c); + +LI_API const char* config_cond_to_string(config_cond_t cond); +LI_API const char* comp_key_to_string(comp_key_t comp); + +#endif diff --git a/src/settings.h b/src/settings.h index ec9182c..c1716f3 100644 --- a/src/settings.h +++ b/src/settings.h @@ -173,6 +173,8 @@ typedef enum { HANDLER_UNSET, # define UNUSED_PARAM(x) x #endif +#define UNUSED(x) ( (void)(x) ) + #if __GNUC__ #define INLINE static inline // # define INLINE extern inline diff --git a/src/wscript b/src/wscript index bf10078..d993929 100644 --- a/src/wscript +++ b/src/wscript @@ -9,13 +9,17 @@ common_uselib = 'glib ' common_source=''' base.c chunks.c + condition.c log.c options.c - options_lua.c sys-files.c sys-socket.c ''' +common_source_lua=''' + options_lua.c +''' + main_source = ''' server.c '''