1
0
mirror of https://gitlab.xiph.org/xiph/icecast-common.git synced 2024-07-21 03:04:15 -04:00

Merge branch 'update-httpp'

This commit is contained in:
Philipp Schafft 2018-09-20 09:58:39 +00:00
commit ad5fc10061
2 changed files with 327 additions and 43 deletions

View File

@ -55,28 +55,94 @@ 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_nocopy(avl_tree *tree, char *name, char *value, int replace);
static void _httpp_set_param(avl_tree *tree, const char *name, const char *value);
static http_var_t *_httpp_get_param_var(avl_tree *tree, const char *name);
httpp_request_info_t httpp_request_info(httpp_request_type_e req)
{
#if 0
#define HTTPP_REQUEST_IS_SAFE ((httpp_request_info_t)0x0001U)
#define HTTPP_REQUEST_IS_IDEMPOTENT ((httpp_request_info_t)0x0002U)
#define HTTPP_REQUEST_IS_CACHEABLE ((httpp_request_info_t)0x0004U)
#define HTTPP_REQUEST_HAS_RESPONSE_BODY ((httpp_request_info_t)0x0010U)
#define HTTPP_REQUEST_HAS_REQUEST_BODY ((httpp_request_info_t)0x0100U)
#define HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY ((httpp_request_info_t)0x0200U)
#endif
switch (req) {
/* offical methods */
case httpp_req_get:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_IS_CACHEABLE|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY;
break;
case httpp_req_post:
return HTTPP_REQUEST_IS_CACHEABLE|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_REQUEST_BODY;
break;
case httpp_req_put:
return HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_REQUEST_BODY;
break;
case httpp_req_head:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_IS_CACHEABLE;
break;
case httpp_req_options:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY;
break;
case httpp_req_delete:
return HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_HAS_RESPONSE_BODY;
break;
case httpp_req_trace:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_IS_IDEMPOTENT|HTTPP_REQUEST_HAS_RESPONSE_BODY;
break;
case httpp_req_connect:
return HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_REQUEST_BODY;
break;
/* Icecast specific methods */
case httpp_req_source:
return HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_REQUEST_BODY;
break;
case httpp_req_play:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY;
break;
case httpp_req_stats:
return HTTPP_REQUEST_IS_SAFE|HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY;
break;
/* Virtual and other methods */
case httpp_req_none:
case httpp_req_unknown:
default:
return HTTPP_REQUEST_HAS_RESPONSE_BODY|HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY;
break;
}
}
http_parser_t *httpp_create_parser(void)
{
return (http_parser_t *)malloc(sizeof(http_parser_t));
}
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
{
http_varlist_t *list;
http_parser_t *parser = calloc(1, sizeof(http_parser_t));
parser->refc = 1;
parser->req_type = httpp_req_none;
parser->uri = NULL;
parser->vars = avl_tree_new(_compare_vars, NULL);
parser->queryvars = avl_tree_new(_compare_vars, NULL);
parser->postvars = avl_tree_new(_compare_vars, NULL);
return parser;
}
void httpp_initialize(http_parser_t *parser, http_varlist_t *defaults)
{
http_varlist_t *list;
/* now insert the default variables */
list = defaults;
while (list != NULL) {
httpp_setvar(parser, list->var.name, list->var.value);
size_t i;
for (i = 0; i < list->var.values; i++) {
httpp_setvar(parser, list->var.name, list->var.value[i]);
}
list = list->next;
}
}
@ -310,7 +376,7 @@ static void parse_query_element(avl_tree *tree, const char *start, const char *m
value = url_unescape(mid + 1, valuelen);
_httpp_set_param_nocopy(tree, key, value);
_httpp_set_param_nocopy(tree, key, value, 0);
}
static void parse_query(avl_tree *tree, const char *query, size_t len)
@ -491,8 +557,10 @@ void httpp_deletevar(http_parser_t *parser, const char *name)
if (parser == NULL || name == NULL)
return;
memset(&var, 0, sizeof(var));
var.name = (char*)name;
var.value = NULL;
avl_delete(parser->vars, (void *)&var, _free_vars);
}
@ -503,11 +571,18 @@ void httpp_setvar(http_parser_t *parser, const char *name, const char *value)
if (name == NULL || value == NULL)
return;
var = (http_var_t *)malloc(sizeof(http_var_t));
var = (http_var_t *)calloc(1, sizeof(http_var_t));
if (var == NULL) return;
var->value = calloc(1, sizeof(*var->value));
if (!var->value) {
free(var);
return;
}
var->name = strdup(name);
var->value = strdup(value);
var->values = 1;
var->value[0] = strdup(value);
if (httpp_getvar(parser, name) == NULL) {
avl_insert(parser->vars, (void *)var);
@ -527,32 +602,59 @@ const char *httpp_getvar(http_parser_t *parser, const char *name)
return NULL;
fp = &found;
memset(&var, 0, sizeof(var));
var.name = (char*)name;
var.value = NULL;
if (avl_get_by_key(parser->vars, &var, fp) == 0)
return found->value;
else
if (avl_get_by_key(parser->vars, &var, fp) == 0) {
if (!found->values)
return NULL;
return found->value[0];
} else {
return NULL;
}
}
static void _httpp_set_param_nocopy(avl_tree *tree, char *name, char *value)
static void _httpp_set_param_nocopy(avl_tree *tree, char *name, char *value, int replace)
{
http_var_t *var;
http_var_t *var, *found;
char **n;
if (name == NULL || value == NULL)
return;
var = (http_var_t *)malloc(sizeof(http_var_t));
if (var == NULL) return;
found = _httpp_get_param_var(tree, name);
var->name = name;
var->value = value;
if (replace || !found) {
var = (http_var_t *)calloc(1, sizeof(http_var_t));
if (var == NULL) {
free(name);
free(value);
return;
}
if (_httpp_get_param(tree, name) == NULL) {
avl_insert(tree, (void *)var);
var->name = name;
} else {
avl_delete(tree, (void *)var, _free_vars);
free(name);
var = found;
}
n = realloc(var->value, sizeof(*n)*(var->values + 1));
if (!n) {
if (replace || !found) {
free(name);
free(var);
}
free(value);
return;
}
var->value = n;
var->value[var->values++] = value;
if (replace && found) {
avl_delete(tree, (void *)found, _free_vars);
avl_insert(tree, (void *)var);
} else if (!found) {
avl_insert(tree, (void *)var);
}
}
@ -562,24 +664,36 @@ 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)));
_httpp_set_param_nocopy(tree, strdup(name), url_unescape(value, strlen(value)), 1);
}
static const char *_httpp_get_param(avl_tree *tree, const char *name)
static http_var_t *_httpp_get_param_var(avl_tree *tree, const char *name)
{
http_var_t var;
http_var_t *found;
void *fp;
fp = &found;
memset(&var, 0, sizeof(var));
var.name = (char *)name;
var.value = NULL;
if (avl_get_by_key(tree, (void *)&var, fp) == 0)
return found->value;
return found;
else
return NULL;
}
static const char *_httpp_get_param(avl_tree *tree, const char *name)
{
http_var_t *res = _httpp_get_param_var(tree, name);
if (!res)
return NULL;
if (!res->values)
return NULL;
return res->value[0];
}
void httpp_set_query_param(http_parser_t *parser, const char *name, const char *value)
{
@ -601,6 +715,130 @@ const char *httpp_get_post_param(http_parser_t *parser, const char *name)
return _httpp_get_param(parser->postvars, name);
}
const http_var_t *httpp_get_param_var(http_parser_t *parser, const char *name)
{
http_var_t *ret = _httpp_get_param_var(parser->postvars, name);
if (ret)
return ret;
return _httpp_get_param_var(parser->queryvars, name);
}
const http_var_t *httpp_get_any_var(http_parser_t *parser, httpp_ns_t ns, const char *name)
{
avl_tree *tree = NULL;
if (!parser || !name)
return NULL;
switch (ns) {
case HTTPP_NS_VAR:
if (name[0] != '_' || name[1] != '_')
return NULL;
tree = parser->vars;
break;
case HTTPP_NS_HEADER:
if (name[0] == '_' && name[1] == '_')
return NULL;
tree = parser->vars;
break;
case HTTPP_NS_QUERY_STRING:
tree = parser->queryvars;
break;
case HTTPP_NS_POST_BODY:
tree = parser->postvars;
break;
}
if (!tree)
return NULL;
return _httpp_get_param_var(tree, name);
}
char ** httpp_get_any_key(http_parser_t *parser, httpp_ns_t ns)
{
avl_tree *tree = NULL;
avl_node *avlnode;
char **ret;
size_t len;
size_t pos = 0;
if (!parser)
return NULL;
switch (ns) {
case HTTPP_NS_VAR:
case HTTPP_NS_HEADER:
tree = parser->vars;
break;
case HTTPP_NS_QUERY_STRING:
tree = parser->queryvars;
break;
case HTTPP_NS_POST_BODY:
tree = parser->postvars;
break;
}
if (!tree)
return NULL;
ret = calloc(8, sizeof(*ret));
if (!ret)
return NULL;
len = 8;
for (avlnode = avl_get_first(tree); avlnode; avlnode = avl_get_next(avlnode)) {
http_var_t *var = avlnode->key;
if (ns == HTTPP_NS_VAR) {
if (var->name[0] != '_' || var->name[1] != '_') {
continue;
}
} else if (ns == HTTPP_NS_HEADER) {
if (var->name[0] == '_' && var->name[1] == '_') {
continue;
}
}
if (pos == (len-1)) {
char **n = realloc(ret, sizeof(*ret)*(len + 8));
if (!n) {
httpp_free_any_key(ret);
return NULL;
}
memset(n + len, 0, sizeof(*n)*8);
ret = n;
len += 8;
}
ret[pos] = strdup(var->name);
if (!ret[pos]) {
httpp_free_any_key(ret);
return NULL;
}
pos++;
}
return ret;
}
void httpp_free_any_key(char **keys)
{
char **p;
if (!keys)
return;
for (p = keys; *p; p++) {
free(*p);
}
free(keys);
}
const char *httpp_get_param(http_parser_t *parser, const char *name)
{
const char *ret = _httpp_get_param(parser->postvars, name);
@ -611,7 +849,7 @@ const char *httpp_get_param(http_parser_t *parser, const char *name)
return _httpp_get_param(parser->queryvars, name);
}
void httpp_clear(http_parser_t *parser)
static void httpp_clear(http_parser_t *parser)
{
parser->req_type = httpp_req_none;
if (parser->uri)
@ -623,10 +861,29 @@ void httpp_clear(http_parser_t *parser)
parser->vars = NULL;
}
void httpp_destroy(http_parser_t *parser)
int httpp_addref(http_parser_t *parser)
{
if (!parser)
return -1;
parser->refc++;
return 0;
}
int httpp_release(http_parser_t *parser)
{
if (!parser)
return -1;
parser->refc--;
if (parser->refc)
return 0;
httpp_clear(parser);
free(parser);
return 0;
}
static char *_lowercase(char *str)
@ -650,14 +907,15 @@ static int _compare_vars(void *compare_arg, void *a, void *b)
static int _free_vars(void *key)
{
http_var_t *var;
http_var_t *var = (http_var_t *)key;
size_t i;
var = (http_var_t *)key;
free(var->name);
if (var->name)
free(var->name);
if (var->value)
free(var->value);
for (i = 0; i < var->values; i++) {
free(var->value[i]);
}
free(var->value);
free(var);
return 1;

View File

@ -33,12 +33,19 @@
#define HTTPP_VAR_VERSION "__version"
#define HTTPP_VAR_URI "__uri"
#define HTTPP_VAR_RAWURI "__rawuri"
#define HTTPP_VAR_QUERYARGS " __queryargs"
#define HTTPP_VAR_QUERYARGS "__queryargs"
#define HTTPP_VAR_REQ_TYPE "__req_type"
#define HTTPP_VAR_ERROR_MESSAGE "__errormessage"
#define HTTPP_VAR_ERROR_CODE "__errorcode"
#define HTTPP_VAR_ICYPASSWORD "__icy_password"
typedef enum {
HTTPP_NS_VAR,
HTTPP_NS_HEADER,
HTTPP_NS_QUERY_STRING,
HTTPP_NS_POST_BODY
} httpp_ns_t;
typedef enum httpp_request_type_tag {
/* Initial and internally used state of the engine */
httpp_req_none = 0,
@ -61,10 +68,20 @@ typedef enum httpp_request_type_tag {
httpp_req_unknown
} httpp_request_type_e;
typedef struct http_var_tag {
typedef unsigned int httpp_request_info_t;
#define HTTPP_REQUEST_IS_SAFE ((httpp_request_info_t)0x0001U)
#define HTTPP_REQUEST_IS_IDEMPOTENT ((httpp_request_info_t)0x0002U)
#define HTTPP_REQUEST_IS_CACHEABLE ((httpp_request_info_t)0x0004U)
#define HTTPP_REQUEST_HAS_RESPONSE_BODY ((httpp_request_info_t)0x0010U)
#define HTTPP_REQUEST_HAS_REQUEST_BODY ((httpp_request_info_t)0x0100U)
#define HTTPP_REQUEST_HAS_OPTIONAL_REQUEST_BODY ((httpp_request_info_t)0x0200U)
typedef struct http_var_tag http_var_t;
struct http_var_tag {
char *name;
char *value;
} http_var_t;
size_t values;
char **value;
};
typedef struct http_varlist_tag {
http_var_t var;
@ -72,6 +89,7 @@ typedef struct http_varlist_tag {
} http_varlist_t;
typedef struct http_parser_tag {
size_t refc;
httpp_request_type_e req_type;
char *uri;
avl_tree *vars;
@ -80,6 +98,7 @@ typedef struct http_parser_tag {
} http_parser_t;
#ifdef _mangle
# define httpp_request_info _mangle(httpp_request_info)
# define httpp_create_parser _mangle(httpp_create_parser)
# define httpp_initialize _mangle(httpp_initialize)
# define httpp_parse _mangle(httpp_parse)
@ -97,6 +116,8 @@ typedef struct http_parser_tag {
# define httpp_clear _mangle(httpp_clear)
#endif
httpp_request_info_t httpp_request_info(httpp_request_type_e req);
http_parser_t *httpp_create_parser(void);
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);
@ -111,8 +132,13 @@ 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);
const char *httpp_get_param(http_parser_t *parser, const char *name);
void httpp_destroy(http_parser_t *parser);
void httpp_clear(http_parser_t *parser);
const http_var_t *httpp_get_param_var(http_parser_t *parser, const char *name);
const http_var_t *httpp_get_any_var(http_parser_t *parser, httpp_ns_t ns, const char *name);
char ** httpp_get_any_key(http_parser_t *parser, httpp_ns_t ns);
void httpp_free_any_key(char **keys);
int httpp_addref(http_parser_t *parser);
int httpp_release(http_parser_t *parser);
#define httpp_destroy(x) httpp_release((x))
/* util functions */
httpp_request_type_e httpp_str_to_method(const char * method);