Request/condition
This commit is contained in:
parent
777232ab5d
commit
c612995cfe
264
src/actions.c
264
src/actions.c
|
@ -1,158 +1,140 @@
|
|||
void action_stack_init(action_stack* as)
|
||||
{
|
||||
// preallocate a stack of 15 elements
|
||||
as->stack = g_array_sized_new(FALSE, TRUE, sizeof(action_stack_elem), 15);
|
||||
as->index = 0;
|
||||
}
|
||||
|
||||
void action_stack_push(action_stack* as, action_stack_elem ase)
|
||||
{
|
||||
// stack needs to grow
|
||||
if (as->index == (as->stack->len -1)) // we are at the end of the stack
|
||||
g_array_append_val(as, ase);
|
||||
else
|
||||
g_array_insert_val(as, as->index, ase);
|
||||
#include "actions.h"
|
||||
#include "condition.h"
|
||||
|
||||
as->index++;
|
||||
}
|
||||
struct action_stack_element;
|
||||
typedef struct action_stack_element action_stack_element;
|
||||
|
||||
// pops the last entry of the action stack
|
||||
action_stack_elem action_stack_pop(action_stack* as)
|
||||
{
|
||||
as->index--;
|
||||
return g_array_index(as, action_stack_elem, as->index);
|
||||
}
|
||||
struct action_stack_element {
|
||||
action_list *list;
|
||||
guint pos;
|
||||
};
|
||||
|
||||
action_result action_list_exec(action_list* al, action_stack* as, guint index)
|
||||
{
|
||||
action_stack_elem ase;
|
||||
guint i;
|
||||
action* act;
|
||||
action_result ar;
|
||||
|
||||
// iterate over list
|
||||
for (i = index; i < al->list->len; i++)
|
||||
{
|
||||
act = g_array_index(al->list, action*, i);
|
||||
|
||||
switch (act->type)
|
||||
{
|
||||
case ACTION_CONDITION:
|
||||
if (TRUE == condition_check(&(act->value.cond)))
|
||||
{
|
||||
// save current
|
||||
ase.al = al;
|
||||
ase.index = i;
|
||||
action_stack_push(as, ase);
|
||||
|
||||
ar = action_list_exec(act->target, as);
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
case ACTION_SETTING:
|
||||
ar = ACTION_RESULT_GO_ON;
|
||||
break;
|
||||
case ACTION_FUNCTION:
|
||||
ar = ACTION_RESULT_GO_ON;
|
||||
break;
|
||||
default:
|
||||
ar = ACTION_RESULT_GO_ON;
|
||||
// TODO: print error and exit
|
||||
}
|
||||
|
||||
if (ar == ACTION_RESULT_BREAK)
|
||||
void action_release(action *a) {
|
||||
assert(a->refcount > 0);
|
||||
if (!(--a->refcount)) {
|
||||
switch (a->type) {
|
||||
case ACTION_TSETTING:
|
||||
/* TODO */
|
||||
break;
|
||||
else if (ar == ACTION_RESULT_WAIT_FOR_EVENT)
|
||||
return ACTION_RESULT_WAIT_FOR_EVENT;
|
||||
}
|
||||
|
||||
// executed all actions in the list
|
||||
// if the action stack index is > 0, we need to jump back to the previous list
|
||||
if (as->index > 0)
|
||||
{
|
||||
ase = action_stack_pop(as);
|
||||
return action_list_exec(ase->al, ase->index);
|
||||
}
|
||||
|
||||
return ACTION_RESULT_GO_ON;
|
||||
}
|
||||
|
||||
// checks if a condition is fulfilled. returns the next action to jump to if fulfilled, otherwise NULL
|
||||
gboolean condition_check(condition* cond)
|
||||
{
|
||||
switch (cond->type)
|
||||
{
|
||||
case CONDITION_STRING:
|
||||
return condition_check_string(cond);
|
||||
case CONDITION_INT:
|
||||
return condition_check_int(cond);
|
||||
case CONDITION_BOOL:
|
||||
return condition_check_bool(cond);
|
||||
case CONDITION_IP:
|
||||
// todo
|
||||
default:
|
||||
// TODO: print error and exit
|
||||
return FALSE;
|
||||
case ACTION_TFUNCTION:
|
||||
/* TODO */
|
||||
break;
|
||||
case ACTION_TCONDITION:
|
||||
condition_release(a->value.condition.cond);
|
||||
action_list_release(a->value.condition.target);
|
||||
break;
|
||||
}
|
||||
g_slice_free(action, a);
|
||||
}
|
||||
}
|
||||
|
||||
void action_acquire(action *a) {
|
||||
assert(a->refcount > 0);
|
||||
a->refcount++;
|
||||
}
|
||||
|
||||
// string condition, operators: ==, !=, =~, !~
|
||||
gboolean condition_check_string(condition* cond)
|
||||
{
|
||||
switch (cond->op)
|
||||
{
|
||||
case CONDITION_EQUAL:
|
||||
if (cond->lvalue.val_string->len != cond->rvalue.val_string->len)
|
||||
return FALSE;
|
||||
return g_string_equal(cond->lvalue.val_string, cond->rvalue.val_string);
|
||||
case CONDITION_UNEQUAL:
|
||||
return (FALSE == g_string_equal(cond->lvalue.val_string, cond->rvalue.val_string)) ? TRUE : FALSE;
|
||||
case CONDITION_REGEX_MATCH:
|
||||
// todo
|
||||
case CONDITION_REGEX_NOMATCH:
|
||||
// todo
|
||||
default:
|
||||
// TODO: print error and exit
|
||||
return FALSE;
|
||||
void action_list_release(action_list *al) {
|
||||
assert(al->refcount > 0);
|
||||
if (!(--al->refcount)) {
|
||||
guint i;
|
||||
for (i = al->actions->len; i-- > 0; ) {
|
||||
action_release(g_array_index(al->actions, action*, i));
|
||||
}
|
||||
g_array_free(al->actions, TRUE);
|
||||
g_slice_free(action_list, al);
|
||||
}
|
||||
}
|
||||
|
||||
// integer condition, operators: ==, !=, <, <=, >, >=
|
||||
gboolean condition_check_int(condition* cond)
|
||||
{
|
||||
switch (cond->op)
|
||||
{
|
||||
case CONDITION_EQUAL:
|
||||
return (cond->lvalue.val_int == cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
case CONDITION_UNEQUAL:
|
||||
return (cond->lvalue.val_int != cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
case CONDITION_LESS:
|
||||
return (cond->lvalue.val_int < cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
case CONDITION_LESS_EQUAL:
|
||||
return (cond->lvalue.val_int <= cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
case CONDITION_GREATER:
|
||||
return (cond->lvalue.val_int > cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
case CONDITION_GREATER_EQUAL:
|
||||
return (cond->lvalue.val_int >= cond->rvalue.val_int) ? TRUE : FALSE;
|
||||
default:
|
||||
// TODO: print error and exit
|
||||
return FALSE;
|
||||
}
|
||||
void action_list_acquire(action_list *al) {
|
||||
assert(al->refcount > 0);
|
||||
al->refcount++;
|
||||
}
|
||||
|
||||
// bool condition, operators: ==, !=
|
||||
gboolean condition_check_bool(condition* cond)
|
||||
{
|
||||
switch (cond->op)
|
||||
{
|
||||
case CONDITION_EQUAL:
|
||||
return (cond->lvalue.val_bool == cond->rvalue.val_bool) ? TRUE : FALSE;
|
||||
case CONDITION_UNEQUAL:
|
||||
return (cond->lvalue.val_bool != cond->rvalue.val_bool) ? TRUE : FALSE;
|
||||
default:
|
||||
// TODO: print error and exit
|
||||
return FALSE;
|
||||
}
|
||||
void action_stack_element_release(action_stack_element *ase) {
|
||||
if (!ase || !ase->list) return;
|
||||
action_list_release(ase->list);
|
||||
ase->list = NULL;
|
||||
}
|
||||
|
||||
void action_stack_init(action_stack *as) {
|
||||
as->stack = g_array_sized_new(FALSE, TRUE, sizeof(action_stack_element), 15);
|
||||
}
|
||||
|
||||
void action_stack_reset(action_stack *as) {
|
||||
guint i;
|
||||
for (i = as->stack->len; i-- > 0; ) {
|
||||
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
|
||||
}
|
||||
g_array_set_size(as->stack, 0);
|
||||
}
|
||||
|
||||
void action_stack_clear(action_stack *as) {
|
||||
guint i;
|
||||
for (i = as->stack->len; i-- > 0; ) {
|
||||
action_stack_element_release(&g_array_index(as->stack, action_stack_element, i));
|
||||
}
|
||||
g_array_free(as->stack, TRUE);
|
||||
}
|
||||
|
||||
/** handle sublist now, remember current position (stack) */
|
||||
void action_enter(connection *con, action_list *al) {
|
||||
action_list_acquire(al);
|
||||
action_stack_element ase = { al, 0 };
|
||||
g_array_append_val(con->action_stack.stack, ase);
|
||||
}
|
||||
|
||||
static action_stack_element *action_stack_top(action_stack* as) {
|
||||
return as->stack->len > 0 ? &g_array_index(as->stack, action_stack_element, as->stack->len - 1) : NULL;
|
||||
}
|
||||
|
||||
static void action_stack_pop(action_stack *as) {
|
||||
action_stack_element_release(&g_array_index(as->stack, action_stack_element, as->stack->len - 1));
|
||||
g_array_set_size(as->stack, as->stack->len - 1);
|
||||
}
|
||||
|
||||
static action* action_stack_element_next(action_stack_element *ase) {
|
||||
action_list *al = ase->list;
|
||||
return ase->pos < al->actions->len ? g_array_index(al->actions, action*, ase->pos++) : NULL;
|
||||
}
|
||||
|
||||
action_result action_execute(server *srv, connection *con) {
|
||||
action *a;
|
||||
action_stack *as = &con->action_stack;
|
||||
action_stack_element *ase;
|
||||
action_result res;
|
||||
|
||||
while (NULL != (ase = action_stack_top(as))) {
|
||||
a = action_stack_element_next(ase);
|
||||
if (!a) {
|
||||
action_stack_pop(as);
|
||||
continue;
|
||||
}
|
||||
switch (a->type) {
|
||||
case ACTION_TSETTING:
|
||||
/* TODO */
|
||||
break;
|
||||
case ACTION_TFUNCTION:
|
||||
res = a->value.function.func(srv, con, a->value.function.param);
|
||||
switch (res) {
|
||||
case ACTION_GO_ON:
|
||||
break;
|
||||
case ACTION_FINISHED:
|
||||
case ACTION_ERROR:
|
||||
action_stack_clear(as);
|
||||
return res;
|
||||
case ACTION_WAIT_FOR_EVENT:
|
||||
return ACTION_WAIT_FOR_EVENT;
|
||||
}
|
||||
break;
|
||||
case ACTION_TCONDITION:
|
||||
if (condition_check(srv, con, a->value.condition.cond)) {
|
||||
action_enter(con, a->value.condition.target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ACTION_GO_ON;
|
||||
}
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
#ifndef _LIGHTTPD_ACTIONS_H_
|
||||
#define _LIGHTTPD_ACTIONS_H_
|
||||
|
||||
typedef enum { ACTION_RESULT_GO_ON, ACTION_RESULT_BREAK, ACTION_RESULT_WAIT_FOR_EVENT } action_result;
|
||||
#include "settings.h"
|
||||
|
||||
typedef enum {
|
||||
ACTION_GO_ON,
|
||||
ACTION_FINISHED,
|
||||
ACTION_ERROR,
|
||||
ACTION_WAIT_FOR_EVENT
|
||||
} action_result;
|
||||
|
||||
// action type
|
||||
typedef enum { ACTION_SETTING, ACTION_FUNCTION, ACTION_CONDITION } action_type;
|
||||
typedef enum {
|
||||
ACTION_TSETTING,
|
||||
ACTION_TFUNCTION,
|
||||
ACTION_TCONDITION
|
||||
} action_type;
|
||||
|
||||
struct action;
|
||||
typedef struct action action;
|
||||
|
@ -15,61 +26,51 @@ typedef struct action_list action_list;
|
|||
struct action_stack;
|
||||
typedef struct action_stack action_stack;
|
||||
|
||||
|
||||
|
||||
|
||||
struct action_list {
|
||||
GArray* actions;
|
||||
guint refcount;
|
||||
};
|
||||
|
||||
struct action_stack {
|
||||
GArray* stack;
|
||||
guint index;
|
||||
};
|
||||
|
||||
struct action_stack_elem {
|
||||
action_list* al;
|
||||
guint index;
|
||||
struct server; struct connection;
|
||||
typedef action_result (*action_func)(struct server *srv, struct connection *con, void* param);
|
||||
|
||||
#include "condition.h"
|
||||
|
||||
struct action_list {
|
||||
gint refcount;
|
||||
|
||||
GArray* actions; /** array of (action*) */
|
||||
};
|
||||
typedef struct action_stack_elem action_stack_elem;
|
||||
|
||||
struct action {
|
||||
gint refcount;
|
||||
action_type type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
option_mark opt;
|
||||
option newvalue;
|
||||
GArray *options; /** array of option_mark */
|
||||
} setting;
|
||||
|
||||
condition cond;
|
||||
struct {
|
||||
condition *cond;
|
||||
action_list* target; /** action target to jump to if condition is fulfilled */
|
||||
} condition;
|
||||
|
||||
struct {
|
||||
action_func* func;
|
||||
action_func func;
|
||||
gpointer param;
|
||||
} actionfunc;
|
||||
} function;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct condition {
|
||||
condition_type type;
|
||||
condition_op op;
|
||||
action_list* target; // action target to jump to if condition is fulfilled
|
||||
LI_API void action_list_release(action_list *al);
|
||||
|
||||
// left value of condition
|
||||
union {
|
||||
guint val_int;
|
||||
gboolean val_bool;
|
||||
GString* val_string;
|
||||
} lvalue;
|
||||
/* no new/free function, so just use the struct direct (i.e. not a pointer) */
|
||||
LI_API void action_stack_init(action_stack *as);
|
||||
LI_API void action_stack_reset(action_stack *as);
|
||||
LI_API void action_stack_clear(action_stack *as);
|
||||
|
||||
// right value of condition
|
||||
union {
|
||||
guint val_int;
|
||||
gboolean val_bool;
|
||||
GString* val_string;
|
||||
} rvalue;
|
||||
};
|
||||
/** handle sublist now, remember current position (stack) */
|
||||
LI_API void action_enter(connection *con, action_list *al);
|
||||
LI_API action_result action_execute(server *srv, connection *con);
|
||||
|
||||
#endif
|
||||
|
|
12
src/base.h
12
src/base.h
|
@ -12,6 +12,8 @@ struct connection;
|
|||
typedef struct connection connection;
|
||||
|
||||
#include "plugin.h"
|
||||
#include "actions.h"
|
||||
#include "request.h"
|
||||
|
||||
struct server {
|
||||
GHashTable *plugins;
|
||||
|
@ -21,4 +23,14 @@ struct server {
|
|||
gpointer *option_def_values;
|
||||
};
|
||||
|
||||
struct connection {
|
||||
|
||||
sock_addr dst_addr, src_addr;
|
||||
GString *dst_addr_str, *src_addr_str;
|
||||
|
||||
action_stack action_stack;
|
||||
|
||||
request request;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
200
src/condition.c
200
src/condition.c
|
@ -5,10 +5,13 @@
|
|||
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 condition* cond_new_string(config_cond_t cond, comp_key_t comp, GString *str);
|
||||
static condition* cond_new_socket(config_cond_t cond, comp_key_t comp, GString *str);
|
||||
static condition* condition_new_from_string(config_cond_t cond, comp_key_t comp, GString *str);
|
||||
static void condition_free(condition *c);
|
||||
|
||||
static gboolean condition_check_eval(server *srv, connection *con, condition *cond);
|
||||
|
||||
static condition* condition_find_cached(server *srv, GString *key) {
|
||||
UNUSED(srv);
|
||||
UNUSED(key);
|
||||
|
@ -32,7 +35,7 @@ static condition* condition_new(config_cond_t cond, comp_key_t comp) {
|
|||
return c;
|
||||
}
|
||||
|
||||
static condition* condition_new_with_string(config_cond_t cond, comp_key_t comp, GString *str) {
|
||||
static condition* cond_new_string(config_cond_t cond, comp_key_t comp, GString *str) {
|
||||
condition *c = condition_new(cond, comp);
|
||||
switch (c->cond) {
|
||||
case CONFIG_COND_EQ: /** == */
|
||||
|
@ -66,29 +69,33 @@ static condition* condition_new_with_string(config_cond_t cond, comp_key_t comp,
|
|||
condition_free(c);
|
||||
return NULL;
|
||||
}
|
||||
c->value_type = COND_VALUE_STRING;
|
||||
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;
|
||||
static condition* cond_new_socket(config_cond_t cond, comp_key_t comp, GString *str) {
|
||||
return cond_new_string(cond, comp, str);
|
||||
/* TODO: parse str as socket addr */
|
||||
}
|
||||
|
||||
static condition* condition_new_from_string(config_cond_t cond, comp_key_t comp, GString *str) {
|
||||
switch (comp) {
|
||||
case COMP_SERVER_SOCKET:
|
||||
case COMP_HTTP_REMOTE_IP:
|
||||
return cond_new_socket(cond, comp, str);
|
||||
case COMP_HTTP_PATH:
|
||||
case COMP_HTTP_HOST:
|
||||
case COMP_HTTP_REFERER:
|
||||
case COMP_HTTP_USER_AGENT:
|
||||
case COMP_HTTP_COOKIE:
|
||||
case COMP_HTTP_SCHEME:
|
||||
case COMP_HTTP_QUERY_STRING:
|
||||
case COMP_HTTP_REQUEST_METHOD:
|
||||
case COMP_PHYSICAL_PATH:
|
||||
case COMP_PHYSICAL_PATH_EXISTS:
|
||||
return cond_new_string(cond, comp, str);
|
||||
}
|
||||
return c;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
condition* condition_new_string(server *srv, config_cond_t cond, comp_key_t comp, GString *str) {
|
||||
|
@ -101,22 +108,7 @@ condition* condition_new_string(server *srv, config_cond_t cond, comp_key_t comp
|
|||
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);
|
||||
c = condition_new_from_string(cond, comp, str);
|
||||
condition_cache_insert(srv, key, c);
|
||||
return c;
|
||||
}
|
||||
|
@ -130,38 +122,25 @@ condition* condition_new_string_uncached(server *srv, config_cond_t cond, comp_k
|
|||
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);
|
||||
return condition_new_from_string(cond, comp, str);
|
||||
}
|
||||
|
||||
static void condition_free(condition *c) {
|
||||
switch (c->cond) {
|
||||
case CONFIG_COND_EQ: /** == */
|
||||
case CONFIG_COND_NE: /** != */
|
||||
g_string_free(c->value.string, TRUE);
|
||||
switch (c->value_type) {
|
||||
case COND_VALUE_INT:
|
||||
case COND_VALUE_SOCKET_IPV4:
|
||||
case COND_VALUE_SOCKET_IPV6:
|
||||
/* nothing to free */
|
||||
break;
|
||||
case CONFIG_COND_MATCH: /** =~ */
|
||||
case CONFIG_COND_NOMATCH: /** !~ */
|
||||
case COND_VALUE_STRING:
|
||||
if (c->cond == CONFIG_COND_MATCH || c->cond == 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);
|
||||
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: /** <= */
|
||||
} else {
|
||||
g_string_free(c->value.string, TRUE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
g_slice_free(condition, c);
|
||||
|
@ -187,3 +166,96 @@ const char* comp_key_to_string(comp_key_t comp) {
|
|||
/* TODO */
|
||||
return "";
|
||||
}
|
||||
|
||||
gboolean condition_check(server *srv, connection *con, condition *cond) {
|
||||
/* TODO: implement cache */
|
||||
return condition_check_eval(srv, con, cond);
|
||||
}
|
||||
|
||||
static gboolean condition_check_eval_string(server *srv, connection *con, condition *cond) {
|
||||
const char *value = NULL;
|
||||
GString *tmp = NULL;
|
||||
gboolean result = FALSE;
|
||||
UNUSED(srv);
|
||||
UNUSED(con);
|
||||
|
||||
switch (cond->comp) {
|
||||
/* TODO: get values */
|
||||
case COMP_SERVER_SOCKET:
|
||||
break;
|
||||
case COMP_HTTP_PATH:
|
||||
value = con->request.uri.path->str;
|
||||
break;
|
||||
case COMP_HTTP_HOST:
|
||||
value = con->request.host->str;
|
||||
break;
|
||||
case COMP_HTTP_REFERER:
|
||||
break;
|
||||
case COMP_HTTP_USER_AGENT:
|
||||
break;
|
||||
case COMP_HTTP_COOKIE:
|
||||
break;
|
||||
case COMP_HTTP_SCHEME:
|
||||
/* TODO: check for ssl */
|
||||
value = "http"; /* ssl ? "https" : "http" */
|
||||
break;
|
||||
case COMP_HTTP_REMOTE_IP:
|
||||
value = con->dst_addr_str->str;
|
||||
break;
|
||||
case COMP_HTTP_QUERY_STRING:
|
||||
value = con->request.uri.query->str;
|
||||
break;
|
||||
case COMP_HTTP_REQUEST_METHOD:
|
||||
value = con->request.http_method_str->str;
|
||||
break;
|
||||
case COMP_PHYSICAL_PATH:
|
||||
case COMP_PHYSICAL_PATH_EXISTS:
|
||||
break;
|
||||
}
|
||||
if (value) switch (cond->cond) {
|
||||
case CONFIG_COND_EQ: /** == */
|
||||
result = 0 == strcmp(value, cond->value.string->str);
|
||||
break;
|
||||
case CONFIG_COND_NE: /** != */
|
||||
result = 0 != strcmp(value, cond->value.string->str);
|
||||
break;
|
||||
case CONFIG_COND_MATCH: /** =~ */
|
||||
case CONFIG_COND_NOMATCH: /** !~ */
|
||||
/* TODO: pcre */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (tmp) g_string_free(tmp, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean ipv4_in_ipv4_net(guint32 target, guint32 match, guint32 networkmask) {
|
||||
return (target & networkmask) == (match & networkmask);
|
||||
}
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
static gboolean ipv6_in_ipv6_net(const unsigned char *target, const guint8 *match, guint network) {
|
||||
guint8 mask = network % 8;
|
||||
if (0 != memcmp(target, match, network / 8)) return FALSE;
|
||||
if (!mask) return TRUE;
|
||||
mask = ~(((guint) 1 << (8-mask)) - 1);
|
||||
return (target[network / 8] & mask) == (match[network / 8] & mask);
|
||||
}
|
||||
|
||||
static gboolean ipv6_in_ipv4_net(const unsigned char *target, guint32 match, guint32 networkmask) {
|
||||
static const guint8 ipv6match[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
|
||||
if (!ipv6_in_ipv6_net(target, ipv6match, 96)) return FALSE;
|
||||
return ipv4_in_ipv4_net(*(guint32*)(target+12), match, networkmask);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean condition_check_eval(server *srv, connection *con, condition *cond) {
|
||||
switch (cond->value_type) {
|
||||
case COND_VALUE_STRING:
|
||||
return condition_check_eval_string(srv, con, cond);
|
||||
/* TODO: implement checks */
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,15 @@
|
|||
* possible compare ops in the configfile parser
|
||||
*/
|
||||
typedef enum {
|
||||
/* everything */
|
||||
CONFIG_COND_EQ, /** == */
|
||||
CONFIG_COND_MATCH, /** =~ */
|
||||
CONFIG_COND_NE, /** != */
|
||||
|
||||
/* only with strings (including socket name) */
|
||||
CONFIG_COND_MATCH, /** =~ */
|
||||
CONFIG_COND_NOMATCH, /** !~ */
|
||||
|
||||
/* only with int */
|
||||
CONFIG_COND_GT, /** > */
|
||||
CONFIG_COND_GE, /** >= */
|
||||
CONFIG_COND_LT, /** < */
|
||||
|
@ -19,7 +24,6 @@ typedef enum {
|
|||
* possible fields to match against
|
||||
*/
|
||||
typedef enum {
|
||||
COMP_UNSET,
|
||||
COMP_SERVER_SOCKET,
|
||||
COMP_HTTP_PATH,
|
||||
COMP_HTTP_HOST,
|
||||
|
@ -31,11 +35,16 @@ typedef enum {
|
|||
COMP_HTTP_QUERY_STRING,
|
||||
COMP_HTTP_REQUEST_METHOD,
|
||||
COMP_PHYSICAL_PATH,
|
||||
COMP_PHYSICAL_PATH_EXISTS,
|
||||
|
||||
COMP_LAST_ELEMENT
|
||||
COMP_PHYSICAL_PATH_EXISTS
|
||||
} comp_key_t;
|
||||
|
||||
typedef enum {
|
||||
COND_VALUE_INT,
|
||||
COND_VALUE_STRING,
|
||||
COND_VALUE_SOCKET_IPV4, /** only match ip/netmask */
|
||||
COND_VALUE_SOCKET_IPV6 /** only match ip/netmask */
|
||||
} cond_value_t;
|
||||
|
||||
struct condition;
|
||||
typedef struct condition condition;
|
||||
|
||||
|
@ -50,6 +59,7 @@ struct condition {
|
|||
/* index into connection conditional caching table, -1 if uncached */
|
||||
int cache_index;
|
||||
|
||||
cond_value_t value_type;
|
||||
union {
|
||||
GString *string;
|
||||
#ifdef HAVE_PCRE_H
|
||||
|
@ -59,6 +69,17 @@ struct condition {
|
|||
};
|
||||
#endif
|
||||
gint i;
|
||||
struct {
|
||||
guint32 addr;
|
||||
guint32 networkmask;
|
||||
} ipv4;
|
||||
#ifdef HAVE_IPV6
|
||||
struct {
|
||||
guint8 addr[16];
|
||||
guint network;
|
||||
} ipv6;
|
||||
#endif
|
||||
sock_addr addr;
|
||||
} value;
|
||||
};
|
||||
|
||||
|
@ -73,4 +94,7 @@ 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);
|
||||
|
||||
|
||||
LI_API gboolean condition_check(server *srv, connection *con, condition *cond);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef _LIGHTTPD_REQUEST_H_
|
||||
#define _LIGHTTPD_REQUEST_H_
|
||||
|
||||
|
||||
typedef enum {
|
||||
HTTP_METHOD_UNSET = -1,
|
||||
HTTP_METHOD_GET,
|
||||
HTTP_METHOD_POST,
|
||||
HTTP_METHOD_HEAD,
|
||||
HTTP_METHOD_OPTIONS,
|
||||
HTTP_METHOD_PROPFIND, /* WebDAV */
|
||||
HTTP_METHOD_MKCOL,
|
||||
HTTP_METHOD_PUT,
|
||||
HTTP_METHOD_DELETE,
|
||||
HTTP_METHOD_COPY,
|
||||
HTTP_METHOD_MOVE,
|
||||
HTTP_METHOD_PROPPATCH,
|
||||
HTTP_METHOD_REPORT, /* DeltaV */
|
||||
HTTP_METHOD_CHECKOUT,
|
||||
HTTP_METHOD_CHECKIN,
|
||||
HTTP_METHOD_VERSION_CONTROL,
|
||||
HTTP_METHOD_UNCHECKOUT,
|
||||
HTTP_METHOD_MKACTIVITY,
|
||||
HTTP_METHOD_MERGE,
|
||||
HTTP_METHOD_LOCK,
|
||||
HTTP_METHOD_UNLOCK,
|
||||
HTTP_METHOD_LABEL,
|
||||
HTTP_METHOD_CONNECT
|
||||
} http_method_t;
|
||||
|
||||
typedef enum {
|
||||
HTTP_VERSION_UNSET = -1,
|
||||
HTTP_VERSION_1_0,
|
||||
HTTP_VERSION_1_1
|
||||
} http_version_t;
|
||||
|
||||
struct request;
|
||||
typedef struct request request;
|
||||
|
||||
struct request_uri;
|
||||
typedef struct request_uri request_uri;
|
||||
|
||||
struct request_uri {
|
||||
GString *uri, *orig_uri;
|
||||
|
||||
GString *scheme;
|
||||
GString *path;
|
||||
GString *query;
|
||||
};
|
||||
|
||||
struct pyhsical {
|
||||
GString *path;
|
||||
GString *basedir;
|
||||
|
||||
GString *doc_root;
|
||||
GString *rel_path;
|
||||
|
||||
GString *pathinfo;
|
||||
};
|
||||
|
||||
struct request {
|
||||
http_method_t http_method;
|
||||
GString *http_method_str;
|
||||
http_version_t http_version;
|
||||
|
||||
request_uri uri;
|
||||
|
||||
GArray *headers;
|
||||
/* Parsed headers: */
|
||||
GString *host;
|
||||
goffset content_length;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -5,8 +5,15 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
|
||||
# define USE_OPENSSL
|
||||
# include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@ import Params
|
|||
common_uselib = 'glib '
|
||||
|
||||
common_source='''
|
||||
actions.c
|
||||
base.c
|
||||
chunks.c
|
||||
condition.c
|
||||
|
|
Loading…
Reference in New Issue