Commit 9597e2ea authored by Philipp Schafft's avatar Philipp Schafft 🦁

Added support for <http-headers> within <mount>. Also support merging of...

Added support for <http-headers> within <mount>. Also support merging of headers (normal mount + default mount). See #1885

svn path=/icecast/trunk/icecast/; revision=19269
parent aa869033
...@@ -279,7 +279,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client, ...@@ -279,7 +279,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client,
len = util_http_build_header(client->refbuf->data, buf_len, 0, len = util_http_build_header(client->refbuf->data, buf_len, 0,
0, 200, NULL, 0, 200, NULL,
"text/xml", "utf-8", "text/xml", "utf-8",
NULL); NULL, NULL);
len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
client->refbuf->len = len; client->refbuf->len = len;
...@@ -573,7 +573,7 @@ static void html_success(client_t *client, char *message) ...@@ -573,7 +573,7 @@ static void html_success(client_t *client, char *message)
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL, 0, 200, NULL,
"text/html", "utf-8", "text/html", "utf-8",
""); "", NULL);
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
"<html><head><title>Admin request successful</title></head>" "<html><head><title>Admin request successful</title></head>"
"<body><p>%s</p></body></html>", message); "<body><p>%s</p></body></html>", message);
...@@ -712,7 +712,7 @@ static void command_buildm3u(client_t *client, const char *mount) ...@@ -712,7 +712,7 @@ static void command_buildm3u(client_t *client, const char *mount)
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL, 0, 200, NULL,
"audio/x-mpegurl", NULL, "audio/x-mpegurl", NULL,
NULL); NULL, NULL);
config = config_get_config(); config = config_get_config();
snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
...@@ -1032,7 +1032,7 @@ static void command_list_mounts(client_t *client, int response) ...@@ -1032,7 +1032,7 @@ static void command_list_mounts(client_t *client, int response)
util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, 200, NULL, 0, 200, NULL,
"text/plain", "utf-8", "text/plain", "utf-8",
""); "", NULL);
client->refbuf->len = strlen (client->refbuf->data); client->refbuf->len = strlen (client->refbuf->data);
client->respcode = 200; client->respcode = 200;
......
...@@ -87,7 +87,8 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); ...@@ -87,7 +87,8 @@ static void _parse_logging(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_security(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node, static void _parse_authentication(xmlDocPtr doc, xmlNodePtr node,
ice_config_t *c); ice_config_t *c);
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); 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); static void _parse_relay(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c);
static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node, static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
...@@ -136,6 +137,45 @@ static void config_clear_http_header(ice_config_http_header_t *header) { ...@@ -136,6 +137,45 @@ static void config_clear_http_header(ice_config_http_header_t *header) {
} }
} }
static ice_config_http_header_t * config_copy_http_header(ice_config_http_header_t *header) {
ice_config_http_header_t *ret = NULL;
ice_config_http_header_t *cur = NULL;
ice_config_http_header_t *old = NULL;
while (header) {
if (cur) {
cur->next = calloc(1, sizeof(ice_config_http_header_t));
old = cur;
cur = cur->next;
} else {
ret = calloc(1, sizeof(ice_config_http_header_t));
cur = ret;
}
if (!cur) return ret; /* TODO: do better error handling */
cur->type = header->type;
cur->name = (char *)xmlCharStrdup(header->name);
cur->value = (char *)xmlCharStrdup(header->value);
if (!cur->name || !cur->value) {
if (cur->name) xmlFree(cur->name);
if (cur->value) xmlFree(cur->value);
if (old) {
old->next = NULL;
} else {
ret = NULL;
}
free(cur);
return ret;
}
header = header->next;
}
return ret;
}
static void config_clear_mount (mount_proxy *mount) static void config_clear_mount (mount_proxy *mount)
{ {
config_options_t *option; config_options_t *option;
...@@ -168,6 +208,7 @@ static void config_clear_mount (mount_proxy *mount) ...@@ -168,6 +208,7 @@ static void config_clear_mount (mount_proxy *mount)
option = nextopt; option = nextopt;
} }
auth_release (mount->auth); auth_release (mount->auth);
config_clear_http_header(mount->http_headers);
free (mount); free (mount);
} }
...@@ -491,7 +532,7 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node, ...@@ -491,7 +532,7 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node,
} 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); _parse_http_headers(doc, 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); _parse_relay(doc, node->xmlChildrenNode, configuration);
} else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) { } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) {
...@@ -728,6 +769,8 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ...@@ -728,6 +769,8 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
} else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) { } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) {
mount->subtype = (char *)xmlNodeListGetString( mount->subtype = (char *)xmlNodeListGetString(
doc, node->xmlChildrenNode, 1); doc, node->xmlChildrenNode, 1);
} else if (xmlStrcmp (node->name, XMLSTR("http-headers")) == 0) {
_parse_http_headers(doc, node->xmlChildrenNode, &(mount->http_headers));
} }
} while ((node = node->next)); } while ((node = node->next));
...@@ -762,7 +805,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, ...@@ -762,7 +805,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node,
configuration->mounts = mount; configuration->mounts = mount;
} }
static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c) { static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, 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;
char *name = NULL; char *name = NULL;
...@@ -783,11 +826,11 @@ static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c) ...@@ -783,11 +826,11 @@ static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c)
name = NULL; name = NULL;
value = NULL; value = NULL;
if (!c->http_headers) { if (!*http_headers) {
c->http_headers = header; *http_headers = header;
continue; continue;
} }
next = c->http_headers; next = *http_headers;
while (next->next) next = next->next; while (next->next) next = next->next;
next->next = header; next->next = header;
} while ((node = node->next)); } while ((node = node->next));
...@@ -1244,6 +1287,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node, ...@@ -1244,6 +1287,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node,
} }
static void merge_mounts(mount_proxy * dst, mount_proxy * src) { static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
ice_config_http_header_t *http_header_next;
ice_config_http_header_t **http_header_tail;
if (!dst || !src) if (!dst || !src)
return; return;
...@@ -1305,6 +1351,15 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) { ...@@ -1305,6 +1351,15 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) {
dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype); dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype);
if (dst->yp_public == -1) if (dst->yp_public == -1)
dst->yp_public = src->yp_public; dst->yp_public = src->yp_public;
if (dst->http_headers) {
http_header_next = dst->http_headers;
while (http_header_next->next) http_header_next = http_header_next->next;
http_header_tail = &(http_header_next->next);
} else {
http_header_tail = &(dst->http_headers);
}
*http_header_tail = config_copy_http_header(src->http_headers);
} }
static inline void _merge_mounts_all(ice_config_t *c) { static inline void _merge_mounts_all(ice_config_t *c) {
......
...@@ -88,6 +88,8 @@ typedef struct _mount_proxy { ...@@ -88,6 +88,8 @@ typedef struct _mount_proxy {
char *charset; /* character set if not utf8 */ char *charset; /* character set if not utf8 */
int mp3_meta_interval; /* outgoing per-stream metadata interval */ int mp3_meta_interval; /* outgoing per-stream metadata interval */
ice_config_http_header_t *http_headers; /* additional HTTP headers */
char *auth_type; /* Authentication type */ char *auth_type; /* Authentication type */
struct auth_tag *auth; struct auth_tag *auth;
char *cluster_password; char *cluster_password;
......
...@@ -190,7 +190,7 @@ static void client_send_error(client_t *client, int status, int plain, const cha ...@@ -190,7 +190,7 @@ static void client_send_error(client_t *client, int status, int plain, const cha
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
0, status, NULL, 0, status, NULL,
plain ? "text/plain" : "text/html", "utf-8", plain ? "text/plain" : "text/html", "utf-8",
plain ? message : ""); plain ? message : "", NULL);
if (!plain) if (!plain)
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
......
...@@ -299,7 +299,7 @@ static int format_prepare_headers (source_t *source, client_t *client) ...@@ -299,7 +299,7 @@ static int format_prepare_headers (source_t *source, client_t *client)
ptr = client->refbuf->data; ptr = client->refbuf->data;
client->respcode = 200; client->respcode = 200;
bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL); bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source);
remaining -= bytes; remaining -= bytes;
ptr += bytes; ptr += bytes;
......
...@@ -458,7 +458,7 @@ int fserve_client_create (client_t *httpclient, const char *path) ...@@ -458,7 +458,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
httpclient->respcode = 200; httpclient->respcode = 200;
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 200, NULL, 0, 200, NULL,
"audio/x-mpegurl", NULL, ""); "audio/x-mpegurl", NULL, "", NULL);
if (host == NULL) if (host == NULL)
{ {
config = config_get_config(); config = config_get_config();
...@@ -567,7 +567,7 @@ int fserve_client_create (client_t *httpclient, const char *path) ...@@ -567,7 +567,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 206, NULL, 0, 206, NULL,
type, NULL, type, NULL,
NULL); NULL, NULL);
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
"Accept-Ranges: bytes\r\n" "Accept-Ranges: bytes\r\n"
"Content-Length: %" PRI_OFF_T "\r\n" "Content-Length: %" PRI_OFF_T "\r\n"
...@@ -593,7 +593,7 @@ int fserve_client_create (client_t *httpclient, const char *path) ...@@ -593,7 +593,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
0, 200, NULL, 0, 200, NULL,
type, NULL, type, NULL,
NULL); NULL, NULL);
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
"Accept-Ranges: bytes\r\n" "Accept-Ranges: bytes\r\n"
"Content-Length: %" PRI_OFF_T "\r\n\r\n", "Content-Length: %" PRI_OFF_T "\r\n\r\n",
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "refbuf.h" #include "refbuf.h"
#include "connection.h" #include "connection.h"
#include "client.h" #include "client.h"
#include "source.h"
#define CATMODULE "util" #define CATMODULE "util"
...@@ -487,20 +488,12 @@ char *util_base64_decode(const char *data) ...@@ -487,20 +488,12 @@ char *util_base64_decode(const char *data)
} }
/* TODO, FIXME: handle memory allocation errors better. */ /* TODO, FIXME: handle memory allocation errors better. */
static inline char * _build_headers(ice_config_t *config) { static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header) {
char *ret = NULL;
size_t len = 1;
size_t headerlen; size_t headerlen;
const char *name; const char *name;
const char *value; const char *value;
ice_config_http_header_t *header = config->http_headers; char * r = *ret;
if (!header) {
return strdup("");
}
ret = calloc(1, 1);
*ret = 0;
while (header) { while (header) {
name = header->name; name = header->name;
switch (header->type) { switch (header->type) {
...@@ -509,14 +502,31 @@ static inline char * _build_headers(ice_config_t *config) { ...@@ -509,14 +502,31 @@ static inline char * _build_headers(ice_config_t *config) {
break; break;
} }
headerlen = strlen(name) + strlen(value) + 4; headerlen = strlen(name) + strlen(value) + 4;
len += headerlen; *len += headerlen;
ret = realloc(ret, len); r = realloc(r, *len);
strcat(ret, name); strcat(r, name);
strcat(ret, ": "); strcat(r, ": ");
strcat(ret, value); strcat(r, value);
strcat(ret, "\r\n"); strcat(r, "\r\n");
header = header->next; header = header->next;
} }
*ret = r;
}
static inline char * _build_headers(int status, ice_config_t *config, source_t *source) {
mount_proxy *mountproxy = NULL;
char *ret = NULL;
size_t len = 1;
if (source)
mountproxy = config_find_mount(config, source->mount, MOUNT_TYPE_NORMAL);
ret = calloc(1, 1);
*ret = 0;
_build_headers_loop(&ret, &len, config->http_headers);
if (mountproxy && mountproxy->http_headers)
_build_headers_loop(&ret, &len, mountproxy->http_headers);
return ret; return ret;
} }
...@@ -524,7 +534,8 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, ...@@ -524,7 +534,8 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
int cache, int cache,
int status, const char * statusmsg, int status, const char * statusmsg,
const char * contenttype, const char * charset, const char * contenttype, const char * charset,
const char * datablock) { const char * datablock,
struct source_tag * source) {
const char * http_version = "1.0"; const char * http_version = "1.0";
ice_config_t *config; ice_config_t *config;
time_t now; time_t now;
...@@ -598,7 +609,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, ...@@ -598,7 +609,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
currenttime_buffer[0] = '\0'; currenttime_buffer[0] = '\0';
config = config_get_config(); config = config_get_config();
extra_headers = _build_headers(config); extra_headers = _build_headers(status, config, source);
ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s", ret = snprintf (out, len, "%sServer: %s\r\n%s%s%s%s%s%s%s",
status_buffer, status_buffer,
config->server_id, config->server_id,
......
...@@ -56,11 +56,14 @@ char *util_url_escape(const char *src); ...@@ -56,11 +56,14 @@ char *util_url_escape(const char *src);
* If datablock is NULL no end-of-header nor any data is appended. * If datablock is NULL no end-of-header nor any data is appended.
* Returns the number of bytes written or -1 on error. * Returns the number of bytes written or -1 on error.
*/ */
struct source_tag; /* use forward decleration so we do not need to
* include <source.h> that would cause other conflicts. */
ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
int cache, int cache,
int status, const char * statusmsg, int status, const char * statusmsg,
const char * contenttype, const char * charset, const char * contenttype, const char * charset,
const char * datablock); const char * datablock,
struct source_tag * source);
/* String dictionary type, without support for NULL keys, or multiple /* String dictionary type, without support for NULL keys, or multiple
* instances of the same key */ * instances of the same key */
......
...@@ -238,7 +238,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) ...@@ -238,7 +238,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
if (string == NULL) if (string == NULL)
string = xmlCharStrdup (""); string = xmlCharStrdup ("");
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL); ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL);
snprintf (refbuf->data + ret, full_len - ret, snprintf (refbuf->data + ret, full_len - ret,
"Content-Length: %d\r\n\r\n%s", "Content-Length: %d\r\n\r\n%s",
len, string); len, string);
......
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