mirror of
https://gitlab.xiph.org/xiph/icecast-common.git
synced 2025-01-03 14:56:36 -05:00
Merge branch 'update-httpp'
This commit is contained in:
commit
ad5fc10061
332
httpp/httpp.c
332
httpp/httpp.c
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user