mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Merge branch 'ph3-corpse'
Thanks to Julien CROUZET <contact@juliencrouzet.fr> for all the input!
This commit is contained in:
commit
eb2735e0f0
@ -93,7 +93,7 @@
|
|||||||
If you don't want this, comment out the following line or read up on CORS.
|
If you don't want this, comment out the following line or read up on CORS.
|
||||||
-->
|
-->
|
||||||
<http-headers>
|
<http-headers>
|
||||||
<header name="Access-Control-Allow-Origin" value="*" />
|
<header type="cors" name="Access-Control-Allow-Origin" />
|
||||||
</http-headers>
|
</http-headers>
|
||||||
|
|
||||||
|
|
||||||
@ -202,7 +202,7 @@
|
|||||||
<role type="anonymous" deny-all="*" />
|
<role type="anonymous" deny-all="*" />
|
||||||
</authentication>
|
</authentication>
|
||||||
<http-headers>
|
<http-headers>
|
||||||
<header name="Access-Control-Allow-Origin" value="http://webplayer.example.org" />
|
<header type="cors" name="Access-Control-Allow-Origin" value="http://webplayer.example.org" />
|
||||||
<header name="baz" value="quux" />
|
<header name="baz" value="quux" />
|
||||||
</http-headers>
|
</http-headers>
|
||||||
|
|
||||||
|
@ -34,6 +34,6 @@
|
|||||||
<loglevel>information</loglevel> <!-- "debug", "information", "warning", or "error" -->
|
<loglevel>information</loglevel> <!-- "debug", "information", "warning", or "error" -->
|
||||||
</logging>
|
</logging>
|
||||||
<http-headers>
|
<http-headers>
|
||||||
<header name="Access-Control-Allow-Origin" value="*" />
|
<header type="cors" name="Access-Control-Allow-Origin" />
|
||||||
</http-headers>
|
</http-headers>
|
||||||
</icecast>
|
</icecast>
|
||||||
|
@ -47,6 +47,6 @@
|
|||||||
<chroot>false</chroot>
|
<chroot>false</chroot>
|
||||||
</security>
|
</security>
|
||||||
<http-headers>
|
<http-headers>
|
||||||
<header name="Access-Control-Allow-Origin" value="*" />
|
<header type="cors" name="Access-Control-Allow-Origin" />
|
||||||
</http-headers>
|
</http-headers>
|
||||||
</icecast>
|
</icecast>
|
||||||
|
27
src/acl.c
27
src/acl.c
@ -44,6 +44,9 @@ struct acl_tag {
|
|||||||
/* mount specific functons */
|
/* mount specific functons */
|
||||||
time_t max_connection_duration;
|
time_t max_connection_duration;
|
||||||
size_t max_connections_per_user;
|
size_t max_connections_per_user;
|
||||||
|
|
||||||
|
/* HTTP headers to send to clients using this role */
|
||||||
|
ice_config_http_header_t *http_headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* some string util functions */
|
/* some string util functions */
|
||||||
@ -195,6 +198,20 @@ acl_t *acl_new_from_xml_node(xmlNodePtr node)
|
|||||||
prop = prop->next;
|
prop = prop->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* if we're new style configured try to read child nodes */
|
||||||
|
if (xmlStrcmp(node->name, XMLSTR("acl")) == 0) {
|
||||||
|
xmlNodePtr child = node->xmlChildrenNode;
|
||||||
|
do {
|
||||||
|
if (child == NULL)
|
||||||
|
break;
|
||||||
|
if (xmlIsBlankNode(child))
|
||||||
|
continue;
|
||||||
|
if (xmlStrcmp(child->name, XMLSTR("http-headers")) == 0) {
|
||||||
|
config_parse_http_headers(child->xmlChildrenNode, &(ret->http_headers));
|
||||||
|
}
|
||||||
|
} while ((child = child->next));
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +232,8 @@ void acl_release(acl_t * acl)
|
|||||||
if (acl->refcount)
|
if (acl->refcount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
config_clear_http_header(acl->http_headers);
|
||||||
|
|
||||||
free(acl);
|
free(acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,3 +368,11 @@ ssize_t acl_get_max_connections_per_user(acl_t *acl)
|
|||||||
|
|
||||||
return acl->max_connections_per_user;
|
return acl->max_connections_per_user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ice_config_http_header_t *acl_get_http_headers(acl_t * acl)
|
||||||
|
{
|
||||||
|
if (!acl)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return acl->http_headers;
|
||||||
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "common/httpp/httpp.h"
|
#include "common/httpp/httpp.h"
|
||||||
|
|
||||||
#include "icecasttypes.h"
|
#include "icecasttypes.h"
|
||||||
|
#include "cfgfile.h"
|
||||||
|
|
||||||
typedef enum acl_policy_tag {
|
typedef enum acl_policy_tag {
|
||||||
/* Error on function call */
|
/* Error on function call */
|
||||||
@ -60,4 +61,7 @@ time_t acl_get_max_connection_duration(acl_t * acl);
|
|||||||
int acl_set_max_connections_per_user(acl_t * acl, size_t limit);
|
int acl_set_max_connections_per_user(acl_t * acl, size_t limit);
|
||||||
ssize_t acl_get_max_connections_per_user(acl_t * acl);
|
ssize_t acl_get_max_connections_per_user(acl_t * acl);
|
||||||
|
|
||||||
|
/* HTTP specific functions */
|
||||||
|
const ice_config_http_header_t *acl_get_http_headers(acl_t * acl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
132
src/auth.c
132
src/auth.c
@ -182,6 +182,8 @@ static void queue_auth_client (auth_client *auth_user)
|
|||||||
* refcounted and only actual freed after the last use
|
* refcounted and only actual freed after the last use
|
||||||
*/
|
*/
|
||||||
void auth_release (auth_t *authenticator) {
|
void auth_release (auth_t *authenticator) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (authenticator == NULL)
|
if (authenticator == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -215,6 +217,13 @@ void auth_release (auth_t *authenticator) {
|
|||||||
if (authenticator->mount)
|
if (authenticator->mount)
|
||||||
free(authenticator->mount);
|
free(authenticator->mount);
|
||||||
acl_release(authenticator->acl);
|
acl_release(authenticator->acl);
|
||||||
|
config_clear_http_header(authenticator->http_headers);
|
||||||
|
|
||||||
|
for (i = 0; i < authenticator->filter_origin_len; i++) {
|
||||||
|
free(authenticator->filter_origin[i].origin);
|
||||||
|
}
|
||||||
|
free(authenticator->filter_origin);
|
||||||
|
|
||||||
free(authenticator);
|
free(authenticator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,6 +444,8 @@ static void *auth_run_thread (void *arg)
|
|||||||
static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)(client_t *client, void (*on_result)(client_t *client, void *userdata, auth_result result), void *userdata), void (*on_result)(client_t *client, void *userdata, auth_result result), void *userdata) {
|
static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)(client_t *client, void (*on_result)(client_t *client, void *userdata, auth_result result), void *userdata), void (*on_result)(client_t *client, void *userdata, auth_result result), void *userdata) {
|
||||||
auth_client *auth_user;
|
auth_client *auth_user;
|
||||||
auth_matchtype_t matchtype;
|
auth_matchtype_t matchtype;
|
||||||
|
const char *origin;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
ICECAST_LOG_DEBUG("Trying to add client %p to auth %p's (role %s) queue.", client, auth, auth->role);
|
ICECAST_LOG_DEBUG("Trying to add client %p to auth %p's (role %s) queue.", client, auth, auth->role);
|
||||||
|
|
||||||
@ -454,6 +465,31 @@ static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter for CORS "Origin".
|
||||||
|
*
|
||||||
|
* CORS actually knows about non-CORS requests and assigned the "null"
|
||||||
|
* location to them.
|
||||||
|
*/
|
||||||
|
origin = httpp_getvar(client->parser, "origin");
|
||||||
|
if (!origin)
|
||||||
|
origin = "null";
|
||||||
|
|
||||||
|
matchtype = auth->filter_origin_policy;
|
||||||
|
for (i = 0; i < auth->filter_origin_len; i++) {
|
||||||
|
if (strcmp(auth->filter_origin[i].origin, origin) == 0) {
|
||||||
|
matchtype = auth->filter_origin[i].type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matchtype == AUTH_MATCHTYPE_NOMATCH) {
|
||||||
|
if (on_no_match) {
|
||||||
|
on_no_match(client, on_result, userdata);
|
||||||
|
} else if (on_result) {
|
||||||
|
on_result(client, userdata, AUTH_NOMATCH);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (client->admin_command == ADMIN_COMMAND_ERROR) {
|
if (client->admin_command == ADMIN_COMMAND_ERROR) {
|
||||||
/* this is a web/ client */
|
/* this is a web/ client */
|
||||||
matchtype = auth->filter_web_policy;
|
matchtype = auth->filter_web_policy;
|
||||||
@ -611,6 +647,49 @@ static inline void auth_get_authenticator__filter_admin(auth_t *auth, xmlNodePtr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void auth_get_authenticator__filter_origin(auth_t *auth, xmlNodePtr node, const char *name, auth_matchtype_t matchtype)
|
||||||
|
{
|
||||||
|
char * tmp = (char*)xmlGetProp(node, XMLSTR(name));
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
|
char *cur = tmp;
|
||||||
|
char *next;
|
||||||
|
|
||||||
|
while (cur) {
|
||||||
|
next = strstr(cur, ",");
|
||||||
|
if (next) {
|
||||||
|
*next = 0;
|
||||||
|
next++;
|
||||||
|
for (; *next == ' '; next++);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(cur, "*") == 0) {
|
||||||
|
auth->filter_origin_policy = matchtype;
|
||||||
|
} else {
|
||||||
|
void *n = realloc(auth->filter_origin, (auth->filter_origin_len + 1)*sizeof(*auth->filter_origin));
|
||||||
|
if (!n) {
|
||||||
|
ICECAST_LOG_ERROR("Can not allocate memory. BAD.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auth->filter_origin = n;
|
||||||
|
auth->filter_origin[auth->filter_origin_len].type = matchtype;
|
||||||
|
auth->filter_origin[auth->filter_origin_len].origin = strdup(cur);
|
||||||
|
if (auth->filter_origin[auth->filter_origin_len].origin) {
|
||||||
|
auth->filter_origin_len++;
|
||||||
|
} else {
|
||||||
|
ICECAST_LOG_ERROR("Can not allocate memory. BAD.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline void auth_get_authenticator__init_method(auth_t *auth, int *method_inited, auth_matchtype_t init_with)
|
static inline void auth_get_authenticator__init_method(auth_t *auth, int *method_inited, auth_matchtype_t init_with)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -716,7 +795,7 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
|||||||
{
|
{
|
||||||
auth_t *auth = calloc(1, sizeof(auth_t));
|
auth_t *auth = calloc(1, sizeof(auth_t));
|
||||||
config_options_t *options = NULL, **next_option = &options;
|
config_options_t *options = NULL, **next_option = &options;
|
||||||
xmlNodePtr option;
|
xmlNodePtr child;
|
||||||
char *method;
|
char *method;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
size_t i;
|
size_t i;
|
||||||
@ -814,39 +893,54 @@ auth_t *auth_get_authenticator(xmlNodePtr node)
|
|||||||
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "match-admin", AUTH_MATCHTYPE_MATCH);
|
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "match-admin", AUTH_MATCHTYPE_MATCH);
|
||||||
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "nomatch-admin", AUTH_MATCHTYPE_NOMATCH);
|
auth_get_authenticator__filter_admin(auth, node, &filter_admin_index, "nomatch-admin", AUTH_MATCHTYPE_NOMATCH);
|
||||||
|
|
||||||
|
auth->filter_origin_policy = AUTH_MATCHTYPE_MATCH;
|
||||||
|
auth_get_authenticator__filter_origin(auth, node, "match-origin", AUTH_MATCHTYPE_MATCH);
|
||||||
|
auth_get_authenticator__filter_origin(auth, node, "nomatch-origin", AUTH_MATCHTYPE_NOMATCH);
|
||||||
|
|
||||||
auth_get_authenticator__permission_alter(auth, node, "may-alter", AUTH_MATCHTYPE_MATCH);
|
auth_get_authenticator__permission_alter(auth, node, "may-alter", AUTH_MATCHTYPE_MATCH);
|
||||||
auth_get_authenticator__permission_alter(auth, node, "may-not-alter", AUTH_MATCHTYPE_NOMATCH);
|
auth_get_authenticator__permission_alter(auth, node, "may-not-alter", AUTH_MATCHTYPE_NOMATCH);
|
||||||
|
|
||||||
/* BEFORE RELEASE 2.5.0 TODO: Migrate this to config_parse_options(). */
|
/* sub node parsing */
|
||||||
option = node->xmlChildrenNode;
|
child = node->xmlChildrenNode;
|
||||||
while (option)
|
do {
|
||||||
{
|
if (child == NULL)
|
||||||
xmlNodePtr current = option;
|
break;
|
||||||
option = option->next;
|
|
||||||
if (xmlStrcmp (current->name, XMLSTR("option")) == 0)
|
if (xmlIsBlankNode(child))
|
||||||
{
|
continue;
|
||||||
|
|
||||||
|
if (xmlStrcmp (child->name, XMLSTR("option")) == 0) {
|
||||||
config_options_t *opt = calloc(1, sizeof (config_options_t));
|
config_options_t *opt = calloc(1, sizeof (config_options_t));
|
||||||
opt->name = (char *)xmlGetProp(current, XMLSTR("name"));
|
opt->name = (char *)xmlGetProp(child, XMLSTR("name"));
|
||||||
if (opt->name == NULL)
|
if (opt->name == NULL) {
|
||||||
{
|
|
||||||
free(opt);
|
free(opt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
opt->value = (char *)xmlGetProp(current, XMLSTR("value"));
|
opt->value = (char *)xmlGetProp(child, XMLSTR("value"));
|
||||||
if (opt->value == NULL)
|
if (opt->value == NULL) {
|
||||||
{
|
|
||||||
xmlFree(opt->name);
|
xmlFree(opt->name);
|
||||||
free(opt);
|
free(opt);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
*next_option = opt;
|
*next_option = opt;
|
||||||
next_option = &opt->next;
|
next_option = &opt->next;
|
||||||
|
} else if (xmlStrcmp (child->name, XMLSTR("http-headers")) == 0) {
|
||||||
|
config_parse_http_headers(child->xmlChildrenNode, &(auth->http_headers));
|
||||||
|
} else if (xmlStrcmp (child->name, XMLSTR("acl")) == 0) {
|
||||||
|
if (!auth->acl) {
|
||||||
|
auth->acl = acl_new_from_xml_node(child);
|
||||||
|
} else {
|
||||||
|
ICECAST_LOG_ERROR("More than one ACL defined in role! Not supported (yet).");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ICECAST_LOG_WARN("unknown auth setting (%H)", child->name);
|
||||||
}
|
}
|
||||||
else
|
} while ((child = child->next));
|
||||||
if (xmlStrcmp (current->name, XMLSTR("text")) != 0)
|
|
||||||
ICECAST_LOG_WARN("unknown auth setting (%s)", current->name);
|
if (!auth->acl) {
|
||||||
|
/* If we did not get a <acl> try ACL as part of <role> (old style). */
|
||||||
|
auth->acl = acl_new_from_xml_node(node);
|
||||||
}
|
}
|
||||||
auth->acl = acl_new_from_xml_node(node);
|
|
||||||
if (!auth->acl) {
|
if (!auth->acl) {
|
||||||
auth_release(auth);
|
auth_release(auth);
|
||||||
auth = NULL;
|
auth = NULL;
|
||||||
|
11
src/auth.h
11
src/auth.h
@ -26,6 +26,7 @@
|
|||||||
#include "common/httpp/httpp.h"
|
#include "common/httpp/httpp.h"
|
||||||
|
|
||||||
#include "icecasttypes.h"
|
#include "icecasttypes.h"
|
||||||
|
#include "cfgfile.h"
|
||||||
|
|
||||||
/* implemented */
|
/* implemented */
|
||||||
#define AUTH_TYPE_ANONYMOUS "anonymous"
|
#define AUTH_TYPE_ANONYMOUS "anonymous"
|
||||||
@ -115,6 +116,13 @@ struct auth_tag
|
|||||||
admin_command_id_t command;
|
admin_command_id_t command;
|
||||||
} filter_admin[MAX_ADMIN_COMMANDS];
|
} filter_admin[MAX_ADMIN_COMMANDS];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
auth_matchtype_t type;
|
||||||
|
char *origin;
|
||||||
|
} *filter_origin;
|
||||||
|
size_t filter_origin_len;
|
||||||
|
auth_matchtype_t filter_origin_policy;
|
||||||
|
|
||||||
/* permissions */
|
/* permissions */
|
||||||
auth_matchtype_t permission_alter[AUTH_ALTER_SEND_ERROR+1];
|
auth_matchtype_t permission_alter[AUTH_ALTER_SEND_ERROR+1];
|
||||||
|
|
||||||
@ -152,6 +160,9 @@ struct auth_tag
|
|||||||
acl_t *acl;
|
acl_t *acl;
|
||||||
/* role name for later matching, may be NULL if no role name was given in config */
|
/* role name for later matching, may be NULL if no role name was given in config */
|
||||||
char *role;
|
char *role;
|
||||||
|
|
||||||
|
/* HTTP headers to send to clients using this role */
|
||||||
|
ice_config_http_header_t *http_headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* prototypes for auths that do not need own header file */
|
/* prototypes for auths that do not need own header file */
|
||||||
|
@ -141,10 +141,6 @@ static void _parse_authentication(xmlDocPtr doc,
|
|||||||
ice_config_t *c,
|
ice_config_t *c,
|
||||||
char **source_password);
|
char **source_password);
|
||||||
|
|
||||||
static void _parse_http_headers(xmlDocPtr doc,
|
|
||||||
xmlNodePtr node,
|
|
||||||
ice_config_http_header_t **http_headers);
|
|
||||||
|
|
||||||
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c, const char *mount);
|
static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c, const char *mount);
|
||||||
static void _parse_mount(xmlDocPtr doc, xmlNodePtr parentnode, ice_config_t *c);
|
static void _parse_mount(xmlDocPtr doc, xmlNodePtr parentnode, ice_config_t *c);
|
||||||
|
|
||||||
@ -512,13 +508,14 @@ static void __append_old_style_url_event(event_registration_t **list,
|
|||||||
xmlFreeNode(exec);
|
xmlFreeNode(exec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void config_clear_http_header(ice_config_http_header_t *header)
|
void config_clear_http_header(ice_config_http_header_t *header)
|
||||||
{
|
{
|
||||||
ice_config_http_header_t *old;
|
ice_config_http_header_t *old;
|
||||||
|
|
||||||
while (header) {
|
while (header) {
|
||||||
xmlFree(header->name);
|
xmlFree(header->name);
|
||||||
xmlFree(header->value);
|
if (header->value)
|
||||||
|
xmlFree(header->value);
|
||||||
old = header;
|
old = header;
|
||||||
header = header->next;
|
header = header->next;
|
||||||
free(old);
|
free(old);
|
||||||
@ -1061,7 +1058,7 @@ static void _parse_root(xmlDocPtr doc,
|
|||||||
} else if (xmlStrcmp(node->name, XMLSTR("limits")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("limits")) == 0) {
|
||||||
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
_parse_limits(doc, node->xmlChildrenNode, configuration);
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) {
|
||||||
_parse_http_headers(doc, node->xmlChildrenNode, &(configuration->http_headers));
|
config_parse_http_headers(node->xmlChildrenNode, &(configuration->http_headers));
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("relay")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("relay")) == 0) {
|
||||||
_parse_relay(doc, node->xmlChildrenNode, configuration, NULL);
|
_parse_relay(doc, node->xmlChildrenNode, configuration, NULL);
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("mount")) == 0) {
|
||||||
@ -1555,7 +1552,7 @@ static void _parse_mount(xmlDocPtr doc,
|
|||||||
mount->subtype = (char *)xmlNodeListGetString(doc,
|
mount->subtype = (char *)xmlNodeListGetString(doc,
|
||||||
node->xmlChildrenNode, 1);
|
node->xmlChildrenNode, 1);
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("http-headers")) == 0) {
|
||||||
_parse_http_headers(doc, node->xmlChildrenNode,
|
config_parse_http_headers(node->xmlChildrenNode,
|
||||||
&(mount->http_headers));
|
&(mount->http_headers));
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("event-bindings")) == 0 ||
|
} else if (xmlStrcmp(node->name, XMLSTR("event-bindings")) == 0 ||
|
||||||
xmlStrcmp(node->name, XMLSTR("kartoffelsalat")) == 0) {
|
xmlStrcmp(node->name, XMLSTR("kartoffelsalat")) == 0) {
|
||||||
@ -1643,9 +1640,8 @@ static void _parse_mount(xmlDocPtr doc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _parse_http_headers(xmlDocPtr doc,
|
void config_parse_http_headers(xmlNodePtr node,
|
||||||
xmlNodePtr node,
|
ice_config_http_header_t **http_headers)
|
||||||
ice_config_http_header_t **http_headers)
|
|
||||||
{
|
{
|
||||||
ice_config_http_header_t *header;
|
ice_config_http_header_t *header;
|
||||||
ice_config_http_header_t *next;
|
ice_config_http_header_t *next;
|
||||||
@ -1664,13 +1660,15 @@ static void _parse_http_headers(xmlDocPtr doc,
|
|||||||
continue;
|
continue;
|
||||||
if (!(name = (char *)xmlGetProp(node, XMLSTR("name"))))
|
if (!(name = (char *)xmlGetProp(node, XMLSTR("name"))))
|
||||||
break;
|
break;
|
||||||
if (!(value = (char *)xmlGetProp(node, XMLSTR("value"))))
|
|
||||||
break;
|
value = (char *)xmlGetProp(node, XMLSTR("value"));
|
||||||
|
|
||||||
type = HTTP_HEADER_TYPE_STATIC; /* default */
|
type = HTTP_HEADER_TYPE_STATIC; /* default */
|
||||||
if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
|
if ((tmp = (char *)xmlGetProp(node, XMLSTR("type")))) {
|
||||||
if (strcmp(tmp, "static") == 0) {
|
if (strcmp(tmp, "static") == 0) {
|
||||||
type = HTTP_HEADER_TYPE_STATIC;
|
type = HTTP_HEADER_TYPE_STATIC;
|
||||||
|
} else if (strcmp(tmp, "cors") == 0 || strcmp(tmp, "corpse") == 0) {
|
||||||
|
type = HTTP_HEADER_TYPE_CORS;
|
||||||
} else {
|
} else {
|
||||||
ICECAST_LOG_WARN("Unknown type %s for "
|
ICECAST_LOG_WARN("Unknown type %s for "
|
||||||
"HTTP Header %s", tmp, name);
|
"HTTP Header %s", tmp, name);
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
|
|
||||||
typedef enum _http_header_type {
|
typedef enum _http_header_type {
|
||||||
/* static: headers are passed as is to the client. */
|
/* static: headers are passed as is to the client. */
|
||||||
HTTP_HEADER_TYPE_STATIC
|
HTTP_HEADER_TYPE_STATIC,
|
||||||
|
/* CORS: headers are only sent to the client if it's a CORS request. */
|
||||||
|
HTTP_HEADER_TYPE_CORS
|
||||||
} http_header_type;
|
} http_header_type;
|
||||||
|
|
||||||
typedef struct ice_config_http_header_tag {
|
typedef struct ice_config_http_header_tag {
|
||||||
@ -299,6 +301,10 @@ listener_t *config_copy_listener_one(const listener_t *listener);
|
|||||||
config_options_t *config_parse_options(xmlNodePtr node);
|
config_options_t *config_parse_options(xmlNodePtr node);
|
||||||
void config_clear_options(config_options_t *options);
|
void config_clear_options(config_options_t *options);
|
||||||
|
|
||||||
|
void config_parse_http_headers(xmlNodePtr node,
|
||||||
|
ice_config_http_header_t **http_headers);
|
||||||
|
void config_clear_http_header(ice_config_http_header_t *header);
|
||||||
|
|
||||||
int config_rehash(void);
|
int config_rehash(void);
|
||||||
|
|
||||||
ice_config_locks *config_locks(void);
|
ice_config_locks *config_locks(void);
|
||||||
|
51
src/util.c
51
src/util.c
@ -50,6 +50,8 @@
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "source.h"
|
#include "source.h"
|
||||||
#include "admin.h"
|
#include "admin.h"
|
||||||
|
#include "auth.h"
|
||||||
|
#include "acl.h"
|
||||||
|
|
||||||
#define CATMODULE "util"
|
#define CATMODULE "util"
|
||||||
|
|
||||||
@ -598,7 +600,7 @@ unsigned int util_str_to_unsigned_int(const char *str, const unsigned int defaul
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TODO, FIXME: handle memory allocation errors better. */
|
/* TODO, FIXME: handle memory allocation errors better. */
|
||||||
static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header, int status) {
|
static inline void _build_headers_loop(char **ret, size_t *len, const ice_config_http_header_t *header, int status, const char *allow, client_t *client) {
|
||||||
size_t headerlen;
|
size_t headerlen;
|
||||||
const char *name;
|
const char *name;
|
||||||
const char *value;
|
const char *value;
|
||||||
@ -620,7 +622,39 @@ static inline void _build_headers_loop(char **ret, size_t *len, ice_config_htt
|
|||||||
switch (header->type) {
|
switch (header->type) {
|
||||||
case HTTP_HEADER_TYPE_STATIC:
|
case HTTP_HEADER_TYPE_STATIC:
|
||||||
value = header->value;
|
value = header->value;
|
||||||
break;
|
break;
|
||||||
|
case HTTP_HEADER_TYPE_CORS:
|
||||||
|
if (name && client && client->parser) {
|
||||||
|
const char *origin = httpp_getvar(client->parser, "origin");
|
||||||
|
if (origin) {
|
||||||
|
value = header->value;
|
||||||
|
if (!value) {
|
||||||
|
if (strcasecmp(name, "Access-Control-Allow-Origin") == 0) {
|
||||||
|
if (status >= 200 && status <= 299) {
|
||||||
|
value = origin;
|
||||||
|
} else if (status >= 400 && status <= 599) {
|
||||||
|
value = "null";
|
||||||
|
} else {
|
||||||
|
/* do not set as we do not have a default for that. */
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(name, "Access-Control-Allow-Methods") == 0) {
|
||||||
|
if (status >= 200 && status <= 299) {
|
||||||
|
/* only use the default if we are posive reply. */
|
||||||
|
value = allow;
|
||||||
|
}
|
||||||
|
} else if (strcasecmp(name, "Access-Control-Expose-Headers") == 0) {
|
||||||
|
value = "icy-br, icy-description, icy-genre, icy-name, icy-pub, icy-url";
|
||||||
|
} else if (strcasecmp(name, "Access-Control-Max-Age") == 0) {
|
||||||
|
value = "300"; /* 300s = 5 minutes */
|
||||||
|
/* No default (yet)
|
||||||
|
* } else if (strcasecmp(name, "Access-Control-Allow-Credentials") == 0) {
|
||||||
|
* } else if (strcasecmp(name, "Access-Control-Allow-Headers") == 0) {
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check data */
|
/* check data */
|
||||||
@ -644,7 +678,8 @@ static inline void _build_headers_loop(char **ret, size_t *len, ice_config_htt
|
|||||||
} while ((header = header->next));
|
} while ((header = header->next));
|
||||||
*ret = r;
|
*ret = r;
|
||||||
}
|
}
|
||||||
static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
|
static inline char * _build_headers(int status, const char *allow, ice_config_t *config, source_t *source, client_t *client) {
|
||||||
|
const ice_config_http_header_t *header;
|
||||||
mount_proxy *mountproxy = NULL;
|
mount_proxy *mountproxy = NULL;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
size_t len = 1;
|
size_t len = 1;
|
||||||
@ -655,9 +690,13 @@ static inline char * _build_headers(int status, ice_config_t *config, source_t *
|
|||||||
ret = calloc(1, 1);
|
ret = calloc(1, 1);
|
||||||
*ret = 0;
|
*ret = 0;
|
||||||
|
|
||||||
_build_headers_loop(&ret, &len, config->http_headers, status);
|
_build_headers_loop(&ret, &len, config->http_headers, status, allow, client);
|
||||||
if (mountproxy && mountproxy->http_headers)
|
if (mountproxy && mountproxy->http_headers)
|
||||||
_build_headers_loop(&ret, &len, mountproxy->http_headers, status);
|
_build_headers_loop(&ret, &len, mountproxy->http_headers, status, allow, client);
|
||||||
|
if (client && client->auth && (header = client->auth->http_headers))
|
||||||
|
_build_headers_loop(&ret, &len, header, status, allow, client);
|
||||||
|
if (client && client->acl && (header = acl_get_http_headers(client->acl)))
|
||||||
|
_build_headers_loop(&ret, &len, header, status, allow, client);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -785,7 +824,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
config = config_get_config();
|
config = config_get_config();
|
||||||
extra_headers = _build_headers(status, config, source);
|
extra_headers = _build_headers(status, allow_header, config, source, client);
|
||||||
ret = snprintf (out, len, "%sServer: %s\r\nConnection: %s\r\nAccept-Encoding: identity\r\nAllow: %s\r\n%s%s%s%s%s%s%s%s",
|
ret = snprintf (out, len, "%sServer: %s\r\nConnection: %s\r\nAccept-Encoding: identity\r\nAllow: %s\r\n%s%s%s%s%s%s%s%s",
|
||||||
status_buffer,
|
status_buffer,
|
||||||
config->server_id,
|
config->server_id,
|
||||||
|
Loading…
Reference in New Issue
Block a user