2010-06-06 21:54:55 +00:00
|
|
|
#include <lighttpd/base.h>
|
2010-09-23 16:28:31 +00:00
|
|
|
#include <lighttpd/encoding.h>
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-09-25 23:04:50 +00:00
|
|
|
typedef struct {
|
|
|
|
enum {
|
|
|
|
PATTERN_STRING, /* literal */
|
|
|
|
PATTERN_NTH, /* $n */
|
|
|
|
PATTERN_NTH_PREV, /* %n */
|
|
|
|
PATTERN_VAR, /* %{req.foo} */
|
|
|
|
PATTERN_VAR_ENCODED /* %{enc:req.foo} */
|
|
|
|
} type;
|
|
|
|
|
|
|
|
union {
|
|
|
|
GString *str; /* PATTERN_STRING */
|
|
|
|
guint8 ndx; /* PATTERN_NTH and PATTERN_NTH_PREV */
|
|
|
|
liConditionLValue *lvalue; /* PATTERN_VAR and PATTERN_VAR_ENCODED */
|
|
|
|
} data;
|
|
|
|
} liPatternPart;
|
|
|
|
|
2010-07-24 12:51:44 +00:00
|
|
|
liPattern *li_pattern_new(liServer *srv, const gchar* str) {
|
2010-06-06 21:54:55 +00:00
|
|
|
GArray *pattern;
|
|
|
|
liPatternPart part;
|
|
|
|
gchar *c;
|
|
|
|
gboolean encoded;
|
|
|
|
|
|
|
|
pattern = g_array_new(FALSE, TRUE, sizeof(liPatternPart));
|
|
|
|
|
|
|
|
for (c = (gchar*)str; *c;) {
|
|
|
|
if (*c == '$') {
|
|
|
|
/* $n, PATTERN_NTH */
|
|
|
|
c++;
|
|
|
|
if (*c >= '0' && *c <= '9') {
|
|
|
|
part.type = PATTERN_NTH;
|
|
|
|
part.data.ndx = *c - '0';
|
|
|
|
g_array_append_val(pattern, part);
|
|
|
|
c++;
|
|
|
|
} else {
|
|
|
|
/* parse error */
|
2010-07-24 12:51:44 +00:00
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
2010-06-06 21:54:55 +00:00
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else if (*c == '%') {
|
|
|
|
c++;
|
|
|
|
if (*c >= '0' && *c <= '9') {
|
|
|
|
/* %n, PATTERN_NTH_PREV */
|
|
|
|
part.type = PATTERN_NTH_PREV;
|
|
|
|
part.data.ndx = *c - '0';
|
|
|
|
g_array_append_val(pattern, part);
|
|
|
|
c++;
|
|
|
|
} else if (*c == '{') {
|
|
|
|
/* %{var}, PATTERN_VAR */
|
2010-09-18 12:47:11 +00:00
|
|
|
gchar *lval_c, *lval_start;
|
|
|
|
guint lval_len = 0;
|
|
|
|
GString *key = NULL;
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-09-18 12:47:11 +00:00
|
|
|
lval_c = c+1;
|
2010-06-06 21:54:55 +00:00
|
|
|
encoded = FALSE;
|
|
|
|
|
2010-09-18 12:47:11 +00:00
|
|
|
if (g_str_has_prefix(lval_c, "enc:")) {
|
2010-06-06 21:54:55 +00:00
|
|
|
/* %{enc:var}, PATTERN_VAR_ENCODED */
|
2010-09-18 12:47:11 +00:00
|
|
|
lval_c += sizeof("enc:")-1;
|
2010-06-06 21:54:55 +00:00
|
|
|
encoded = TRUE;
|
|
|
|
}
|
|
|
|
|
2010-09-18 12:47:11 +00:00
|
|
|
/* search for closing '}' */
|
|
|
|
for (lval_start = lval_c; *lval_c != '\0' && *lval_c != '}'; lval_c++) {
|
|
|
|
/* got a key */
|
|
|
|
if (*lval_c == '[') {
|
|
|
|
gchar *key_c, *key_start;
|
|
|
|
guint key_len = 0;
|
|
|
|
|
2010-09-25 23:04:50 +00:00
|
|
|
/* search for closing ']' */
|
2010-09-18 12:47:11 +00:00
|
|
|
for (key_start = key_c = lval_c+1; *key_c != '\0' && *key_c != ']'; key_c++) {
|
|
|
|
key_len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (key_len == 0 || *key_c != ']' || *(key_c+1) != '}') {
|
|
|
|
/* parse error */
|
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
key = g_string_new_len(key_start, key_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
lval_len++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adjust c */
|
|
|
|
c = lval_start + lval_len + (key ? (key->len+2) : 0);
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-09-18 12:47:11 +00:00
|
|
|
if (*c != '}') {
|
2010-06-06 21:54:55 +00:00
|
|
|
/* parse error */
|
2010-07-24 12:51:44 +00:00
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
2010-09-25 21:43:54 +00:00
|
|
|
if (key)
|
|
|
|
g_string_free(key, TRUE);
|
2010-06-06 21:54:55 +00:00
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-18 12:47:11 +00:00
|
|
|
part.data.lvalue = li_condition_lvalue_new(li_cond_lvalue_from_string(lval_start, lval_len), key);
|
2010-07-24 12:51:44 +00:00
|
|
|
part.type = encoded ? PATTERN_VAR_ENCODED : PATTERN_VAR;
|
|
|
|
g_array_append_val(pattern, part);
|
2010-09-18 12:47:11 +00:00
|
|
|
c++;
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-07-24 12:51:44 +00:00
|
|
|
if (part.data.lvalue->type == LI_COMP_UNKNOWN) {
|
2010-06-06 21:54:55 +00:00
|
|
|
/* parse error */
|
2010-07-24 12:51:44 +00:00
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
2010-06-06 21:54:55 +00:00
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* parse error */
|
2010-07-24 12:51:44 +00:00
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
2010-06-06 21:54:55 +00:00
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* string */
|
|
|
|
gchar *first = c;
|
|
|
|
c++;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (*c == '\0' || *c == '?' || *c == '$' || *c == '%') {
|
|
|
|
break;
|
|
|
|
} else if (*c == '\\') {
|
|
|
|
c++;
|
|
|
|
if (*c == '\\' || *c == '?' || *c == '$' || *c == '%') {
|
|
|
|
c++;
|
|
|
|
} else {
|
|
|
|
/* parse error */
|
2010-07-24 12:51:44 +00:00
|
|
|
ERROR(srv, "could not parse pattern: \"%s\"", str);
|
2010-06-06 21:54:55 +00:00
|
|
|
li_pattern_free((liPattern*)pattern);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
part.type = PATTERN_STRING;
|
|
|
|
part.data.str= g_string_new_len(first, c - first);
|
|
|
|
g_array_append_val(pattern, part);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (liPattern*) pattern;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void li_pattern_free(liPattern *pattern) {
|
|
|
|
guint i;
|
2010-07-17 13:23:42 +00:00
|
|
|
GArray *arr;
|
2010-07-24 12:51:44 +00:00
|
|
|
liPatternPart *part;
|
2010-07-17 13:23:42 +00:00
|
|
|
|
|
|
|
if (!pattern) return;
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-07-17 13:23:42 +00:00
|
|
|
arr = (GArray*) pattern;
|
2010-06-06 21:54:55 +00:00
|
|
|
for (i = 0; i < arr->len; i++) {
|
2010-07-24 12:51:44 +00:00
|
|
|
part = &g_array_index(arr, liPatternPart, i);
|
|
|
|
switch (part->type) {
|
|
|
|
case PATTERN_STRING: g_string_free(part->data.str, TRUE); break;
|
|
|
|
case PATTERN_VAR_ENCODED: /* fall through */
|
|
|
|
case PATTERN_VAR: li_condition_lvalue_release(part->data.lvalue); break;
|
|
|
|
default: break;
|
|
|
|
}
|
2010-06-06 21:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
g_array_free(arr, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void li_pattern_eval(liVRequest *vr, GString *dest, liPattern *pattern, liPatternCB nth_callback, gpointer nth_data, liPatternCB nth_prev_callback, gpointer nth_prev_data) {
|
|
|
|
guint i;
|
|
|
|
gboolean encoded;
|
2010-07-24 12:51:44 +00:00
|
|
|
liHandlerResult res;
|
|
|
|
liConditionValue cond_val;
|
2010-06-06 21:54:55 +00:00
|
|
|
GArray *arr = (GArray*) pattern;
|
|
|
|
|
|
|
|
for (i = 0; i < arr->len; i++) {
|
|
|
|
liPatternPart *part = &g_array_index(arr, liPatternPart, i);
|
|
|
|
encoded = FALSE;
|
|
|
|
|
|
|
|
switch (part->type) {
|
|
|
|
case PATTERN_STRING:
|
|
|
|
g_string_append_len(dest, GSTR_LEN(part->data.str));
|
|
|
|
break;
|
|
|
|
case PATTERN_NTH:
|
2010-06-12 10:37:59 +00:00
|
|
|
if (nth_callback)
|
|
|
|
nth_callback(dest, part->data.ndx, nth_data);
|
2010-06-06 21:54:55 +00:00
|
|
|
break;
|
|
|
|
case PATTERN_NTH_PREV:
|
2010-06-12 10:37:59 +00:00
|
|
|
if (nth_prev_callback)
|
|
|
|
nth_prev_callback(dest, part->data.ndx, nth_prev_data);
|
2010-06-06 21:54:55 +00:00
|
|
|
break;
|
|
|
|
case PATTERN_VAR_ENCODED:
|
|
|
|
encoded = TRUE;
|
|
|
|
/* fall through */
|
|
|
|
case PATTERN_VAR:
|
2010-07-24 12:51:44 +00:00
|
|
|
res = li_condition_get_value(vr, part->data.lvalue, &cond_val, LI_COND_VALUE_HINT_STRING);
|
|
|
|
if (res == LI_HANDLER_GO_ON) {
|
|
|
|
if (encoded)
|
|
|
|
li_string_encode_append(li_condition_value_to_string(vr, &cond_val), dest, LI_ENCODING_URI);
|
2010-06-06 21:54:55 +00:00
|
|
|
else
|
2010-07-24 12:51:44 +00:00
|
|
|
g_string_append(dest, li_condition_value_to_string(vr, &cond_val));
|
2010-06-06 21:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void li_pattern_array_cb(GString *pattern_result, guint8 nth_ndx, gpointer data) {
|
2010-09-25 23:04:50 +00:00
|
|
|
GArray *a = data;
|
2010-06-06 21:54:55 +00:00
|
|
|
|
2010-09-25 23:04:50 +00:00
|
|
|
if (nth_ndx < a->len) {
|
|
|
|
GString *str = g_array_index(a, GString*, nth_ndx);
|
|
|
|
g_string_append_len(pattern_result, GSTR_LEN(str));
|
|
|
|
}
|
2010-06-06 21:54:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void li_pattern_regex_cb(GString *pattern_result, guint8 nth_ndx, gpointer data) {
|
|
|
|
gint start_pos, end_pos;
|
|
|
|
GMatchInfo *match_info = data;
|
|
|
|
|
|
|
|
if (!match_info)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (g_match_info_fetch_pos(match_info, (gint)nth_ndx, &start_pos, &end_pos))
|
|
|
|
g_string_append_len(pattern_result, g_match_info_get_string(match_info) + start_pos, end_pos - start_pos);
|
|
|
|
}
|