Commit 937268e2 authored by Philipp Schafft's avatar Philipp Schafft 🦁

Feature: Added support to parse POST data

parent fca416b1
...@@ -52,6 +52,12 @@ static char *_lowercase(char *str); ...@@ -52,6 +52,12 @@ static char *_lowercase(char *str);
static int _compare_vars(void *compare_arg, void *a, void *b); static int _compare_vars(void *compare_arg, void *a, void *b);
static int _free_vars(void *key); static int _free_vars(void *key);
/* For avl tree manipulation */
static void parse_query(avl_tree *tree, const char *query, size_t len);
static const char *_httpp_get_param(avl_tree *tree, const char *name);
static void _httpp_set_param_nocopy(avl_tree *tree, char *name, char *value);
static void _httpp_set_param(avl_tree *tree, const char *name, const char *value);
http_parser_t *httpp_create_parser(void) http_parser_t *httpp_create_parser(void)
{ {
return (http_parser_t *)malloc(sizeof(http_parser_t)); return (http_parser_t *)malloc(sizeof(http_parser_t));
...@@ -65,6 +71,7 @@ void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults) ...@@ -65,6 +71,7 @@ void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
parser->uri = NULL; parser->uri = NULL;
parser->vars = avl_tree_new(_compare_vars, NULL); parser->vars = avl_tree_new(_compare_vars, NULL);
parser->queryvars = avl_tree_new(_compare_vars, NULL); parser->queryvars = avl_tree_new(_compare_vars, NULL);
parser->postvars = avl_tree_new(_compare_vars, NULL);
/* now insert the default variables */ /* now insert the default variables */
list = defaults; list = defaults;
...@@ -203,6 +210,19 @@ int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned ...@@ -203,6 +210,19 @@ int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned
return 1; return 1;
} }
int httpp_parse_postdata(http_parser_t *parser, const char *body_data, size_t len)
{
const char *header = httpp_getvar(parser, "content-type");
if (strcasecmp(header, "application/x-www-form-urlencoded") != 0) {
return -1;
}
parse_query(parser->postvars, body_data, len);
return 0;
}
static int hex(char c) static int hex(char c)
{ {
if(c >= '0' && c <= '9') if(c >= '0' && c <= '9')
...@@ -215,11 +235,10 @@ static int hex(char c) ...@@ -215,11 +235,10 @@ static int hex(char c)
return -1; return -1;
} }
static char *url_escape(const char *src) static char *url_unescape(const char *src, size_t len)
{ {
int len = strlen(src);
unsigned char *decoded; unsigned char *decoded;
int i; size_t i;
char *dst; char *dst;
int done = 0; int done = 0;
...@@ -265,38 +284,58 @@ static char *url_escape(const char *src) ...@@ -265,38 +284,58 @@ static char *url_escape(const char *src)
return (char *)decoded; return (char *)decoded;
} }
/** TODO: This is almost certainly buggy in some cases */ static void parse_query_element(avl_tree *tree, const char *start, const char *mid, const char *end)
static void parse_query(http_parser_t *parser, char *query)
{ {
int len; size_t keylen;
int i=0; char *key;
char *key = query; size_t valuelen;
char *val=NULL; char *value;
if (start >= end)
return;
if(!query || !*query) if (!mid)
return; return;
len = strlen(query); keylen = mid - start;
valuelen = end - mid - 1;
while(i<len) { /* REVIEW: We ignore keys with empty values. */
switch(query[i]) { if (!keylen || !valuelen)
case '&': return;
query[i] = 0;
if(val && key) key = malloc(keylen + 1);
httpp_set_query_param(parser, key, val); memcpy(key, start, keylen);
key = query+i+1; key[keylen] = 0;
value = url_unescape(mid + 1, valuelen);
_httpp_set_param_nocopy(tree, key, value);
}
static void parse_query(avl_tree *tree, const char *query, size_t len)
{
const char *start = query;
const char *mid = NULL;
size_t i;
if (!query || !*query)
return;
for (i = 0; i < len; i++) {
switch (query[i]) {
case '&':
parse_query_element(tree, start, mid, &(query[i]));
start = &(query[i + 1]);
mid = NULL;
break; break;
case '=': case '=':
query[i] = 0; mid = &(query[i]);
val = query+i+1;
break; break;
} }
i++;
} }
if(val && key) { parse_query_element(tree, start, mid, &(query[i]));
httpp_set_query_param(parser, key, val);
}
} }
int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len) int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len)
...@@ -361,7 +400,7 @@ int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len) ...@@ -361,7 +400,7 @@ int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len)
httpp_setvar(parser, HTTPP_VAR_QUERYARGS, query); httpp_setvar(parser, HTTPP_VAR_QUERYARGS, query);
*query = 0; *query = 0;
query++; query++;
parse_query(parser, query); parse_query(parser->queryvars, query, strlen(query));
} }
parser->uri = strdup(uri); parser->uri = strdup(uri);
...@@ -492,7 +531,7 @@ const char *httpp_getvar(http_parser_t *parser, const char *name) ...@@ -492,7 +531,7 @@ const char *httpp_getvar(http_parser_t *parser, const char *name)
return NULL; return NULL;
} }
void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value) static void _httpp_set_param_nocopy(avl_tree *tree, char *name, char *value)
{ {
http_var_t *var; http_var_t *var;
...@@ -502,18 +541,26 @@ void httpp_set_query_param(http_parser_t *parser, const char *name, const char * ...@@ -502,18 +541,26 @@ void httpp_set_query_param(http_parser_t *parser, const char *name, const char *
var = (http_var_t *)malloc(sizeof(http_var_t)); var = (http_var_t *)malloc(sizeof(http_var_t));
if (var == NULL) return; if (var == NULL) return;
var->name = strdup(name); var->name = name;
var->value = url_escape(value); var->value = value;
if (httpp_get_query_param(parser, name) == NULL) { if (_httpp_get_param(tree, name) == NULL) {
avl_insert(parser->queryvars, (void *)var); avl_insert(tree, (void *)var);
} else { } else {
avl_delete(parser->queryvars, (void *)var, _free_vars); avl_delete(tree, (void *)var, _free_vars);
avl_insert(parser->queryvars, (void *)var); avl_insert(tree, (void *)var);
} }
} }
const char *httpp_get_query_param(http_parser_t *parser, const char *name) static void _httpp_set_param(avl_tree *tree, const char *name, const char *value)
{
if (name == NULL || value == NULL)
return;
_httpp_set_param_nocopy(tree, strdup(name), url_unescape(value, strlen(value)));
}
static const char *_httpp_get_param(avl_tree *tree, const char *name)
{ {
http_var_t var; http_var_t var;
http_var_t *found; http_var_t *found;
...@@ -523,12 +570,32 @@ const char *httpp_get_query_param(http_parser_t *parser, const char *name) ...@@ -523,12 +570,32 @@ const char *httpp_get_query_param(http_parser_t *parser, const char *name)
var.name = (char *)name; var.name = (char *)name;
var.value = NULL; var.value = NULL;
if (avl_get_by_key(parser->queryvars, (void *)&var, fp) == 0) if (avl_get_by_key(tree, (void *)&var, fp) == 0)
return found->value; return found->value;
else else
return NULL; return NULL;
} }
void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value)
{
return _httpp_set_param(parser->queryvars, name, value);
}
const char *httpp_get_query_param(http_parser_t *parser, const char *name)
{
return _httpp_get_param(parser->queryvars, name);
}
void httpp_set_post_param(http_parser_t *parser, const char *name, const char *value)
{
return _httpp_set_param(parser->postvars, name, value);
}
const char *httpp_get_post_param(http_parser_t *parser, const char *name)
{
return _httpp_get_param(parser->postvars, name);
}
void httpp_clear(http_parser_t *parser) void httpp_clear(http_parser_t *parser)
{ {
parser->req_type = httpp_req_none; parser->req_type = httpp_req_none;
...@@ -537,6 +604,7 @@ void httpp_clear(http_parser_t *parser) ...@@ -537,6 +604,7 @@ void httpp_clear(http_parser_t *parser)
parser->uri = NULL; parser->uri = NULL;
avl_tree_free(parser->vars, _free_vars); avl_tree_free(parser->vars, _free_vars);
avl_tree_free(parser->queryvars, _free_vars); avl_tree_free(parser->queryvars, _free_vars);
avl_tree_free(parser->postvars, _free_vars);
parser->vars = NULL; parser->vars = NULL;
} }
......
...@@ -76,6 +76,7 @@ typedef struct http_parser_tag { ...@@ -76,6 +76,7 @@ typedef struct http_parser_tag {
char *uri; char *uri;
avl_tree *vars; avl_tree *vars;
avl_tree *queryvars; avl_tree *queryvars;
avl_tree *postvars;
} http_parser_t; } http_parser_t;
#ifdef _mangle #ifdef _mangle
...@@ -97,11 +98,14 @@ void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults); ...@@ -97,11 +98,14 @@ void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults);
int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len); int httpp_parse(http_parser_t *parser, const char *http_data, unsigned long len);
int httpp_parse_icy(http_parser_t *parser, const char *http_data, unsigned long len); int httpp_parse_icy(http_parser_t *parser, const char *http_data, unsigned long len);
int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned long len, const char *uri); int httpp_parse_response(http_parser_t *parser, const char *http_data, unsigned long len, const char *uri);
int httpp_parse_postdata(http_parser_t *parser, const char *body_data, size_t len);
void httpp_setvar(http_parser_t *parser, const char *name, const char *value); void httpp_setvar(http_parser_t *parser, const char *name, const char *value);
void httpp_deletevar(http_parser_t *parser, const char *name); void httpp_deletevar(http_parser_t *parser, const char *name);
const char *httpp_getvar(http_parser_t *parser, const char *name); const char *httpp_getvar(http_parser_t *parser, const char *name);
void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value); void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value);
const char *httpp_get_query_param(http_parser_t *parser, const char *name); const char *httpp_get_query_param(http_parser_t *parser, const char *name);
void httpp_set_post_param(http_parser_t *parser, const char *name, const char *value);
const char *httpp_get_post_param(http_parser_t *parser, const char *name);
void httpp_destroy(http_parser_t *parser); void httpp_destroy(http_parser_t *parser);
void httpp_clear(http_parser_t *parser); void httpp_clear(http_parser_t *parser);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment