diff --git a/src/admin.c b/src/admin.c index 1785d3b9cbcdf06b65d2680f3dfae7b5fb64e1c4..d8b9b5ba5adc2a1940ef1e0c55f10d56f9331c92 100644 --- a/src/admin.c +++ b/src/admin.c @@ -279,7 +279,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client, len = util_http_build_header(client->refbuf->data, buf_len, 0, 0, 200, NULL, "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); client->refbuf->len = len; @@ -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, 0, 200, NULL, "text/html", "utf-8", - ""); + "", NULL); snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Admin request successful" "

%s

", message); @@ -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, 0, 200, NULL, "audio/x-mpegurl", NULL, - NULL); + NULL, NULL); config = config_get_config(); snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, @@ -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, 0, 200, NULL, "text/plain", "utf-8", - ""); + "", NULL); client->refbuf->len = strlen (client->refbuf->data); client->respcode = 200; diff --git a/src/cfgfile.c b/src/cfgfile.c index 748078562377281e6ae89ea4f26e8b7d7b1e77c3..c9be993fb9cf0b0fe4ec89d1ee75fe3ae1ead660 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.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_authentication(xmlDocPtr doc, xmlNodePtr node, 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_mount(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c); 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) { } } +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) { config_options_t *option; @@ -168,6 +208,7 @@ static void config_clear_mount (mount_proxy *mount) option = nextopt; } auth_release (mount->auth); + config_clear_http_header(mount->http_headers); free (mount); } @@ -491,7 +532,7 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node, } else if (xmlStrcmp (node->name, XMLSTR("limits")) == 0) { _parse_limits(doc, node->xmlChildrenNode, configuration); } 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) { _parse_relay(doc, node->xmlChildrenNode, configuration); } else if (xmlStrcmp (node->name, XMLSTR("mount")) == 0) { @@ -728,6 +769,8 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, } else if (xmlStrcmp (node->name, XMLSTR("subtype")) == 0) { mount->subtype = (char *)xmlNodeListGetString( 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)); @@ -762,7 +805,7 @@ static void _parse_mount(xmlDocPtr doc, xmlNodePtr node, 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 *next; char *name = NULL; @@ -783,11 +826,11 @@ static void _parse_http_headers(xmlDocPtr doc, xmlNodePtr node, ice_config_t *c) name = NULL; value = NULL; - if (!c->http_headers) { - c->http_headers = header; + if (!*http_headers) { + *http_headers = header; continue; } - next = c->http_headers; + next = *http_headers; while (next->next) next = next->next; next->next = header; } while ((node = node->next)); @@ -1244,6 +1287,9 @@ static void _add_server(xmlDocPtr doc, xmlNodePtr node, } 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) return; @@ -1305,6 +1351,15 @@ static void merge_mounts(mount_proxy * dst, mount_proxy * src) { dst->subtype = (char*)xmlStrdup((xmlChar*)src->subtype); if (dst->yp_public == -1) 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) { diff --git a/src/cfgfile.h b/src/cfgfile.h index f1eaaee2d5f3561464a83804191ec9ab52481c93..54458fc423bab5c2067baa8c585cf920298d7880 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -88,6 +88,8 @@ typedef struct _mount_proxy { char *charset; /* character set if not utf8 */ int mp3_meta_interval; /* outgoing per-stream metadata interval */ + ice_config_http_header_t *http_headers; /* additional HTTP headers */ + char *auth_type; /* Authentication type */ struct auth_tag *auth; char *cluster_password; diff --git a/src/client.c b/src/client.c index ec52a872c0c14d9eca20752abed56c55307f0d13..22906ba2e385824a4642b52ae8863e049f8adaad 100644 --- a/src/client.c +++ b/src/client.c @@ -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, 0, status, NULL, plain ? "text/plain" : "text/html", "utf-8", - plain ? message : ""); + plain ? message : "", NULL); if (!plain) snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, diff --git a/src/format.c b/src/format.c index c5790eeada5cfcb3ddf581c4e43e4dc825fb32bc..d87b04963695e90c35789ae03b2b09fb964ec633 100644 --- a/src/format.c +++ b/src/format.c @@ -299,7 +299,7 @@ static int format_prepare_headers (source_t *source, client_t *client) ptr = client->refbuf->data; 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; ptr += bytes; diff --git a/src/fserve.c b/src/fserve.c index a4bf8e166b28fc0ef3e8386cdf716a216d34968d..90ecac0012f1b680b5df47f97c3d8b9f26578a68 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -458,7 +458,7 @@ int fserve_client_create (client_t *httpclient, const char *path) httpclient->respcode = 200; ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, - "audio/x-mpegurl", NULL, ""); + "audio/x-mpegurl", NULL, "", NULL); if (host == NULL) { config = config_get_config(); @@ -567,7 +567,7 @@ int fserve_client_create (client_t *httpclient, const char *path) bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 206, NULL, type, NULL, - NULL); + NULL, NULL); bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" @@ -593,7 +593,7 @@ int fserve_client_create (client_t *httpclient, const char *path) bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, type, NULL, - NULL); + NULL, NULL); bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n\r\n", diff --git a/src/util.c b/src/util.c index 1457896d7c14444ae527f37d7fada3450e64da7b..99ca078c4002f5d96561211ff07af0df806ecfb7 100644 --- a/src/util.c +++ b/src/util.c @@ -45,6 +45,7 @@ #include "refbuf.h" #include "connection.h" #include "client.h" +#include "source.h" #define CATMODULE "util" @@ -487,20 +488,12 @@ char *util_base64_decode(const char *data) } /* TODO, FIXME: handle memory allocation errors better. */ -static inline char * _build_headers(ice_config_t *config) { - char *ret = NULL; - size_t len = 1; +static inline void _build_headers_loop(char **ret, size_t *len, ice_config_http_header_t *header) { size_t headerlen; const char *name; const char *value; - ice_config_http_header_t *header = config->http_headers; - - if (!header) { - return strdup(""); - } + char * r = *ret; - ret = calloc(1, 1); - *ret = 0; while (header) { name = header->name; switch (header->type) { @@ -509,14 +502,31 @@ static inline char * _build_headers(ice_config_t *config) { break; } headerlen = strlen(name) + strlen(value) + 4; - len += headerlen; - ret = realloc(ret, len); - strcat(ret, name); - strcat(ret, ": "); - strcat(ret, value); - strcat(ret, "\r\n"); + *len += headerlen; + r = realloc(r, *len); + strcat(r, name); + strcat(r, ": "); + strcat(r, value); + strcat(r, "\r\n"); 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; } @@ -524,7 +534,8 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, int cache, int status, const char * statusmsg, const char * contenttype, const char * charset, - const char * datablock) { + const char * datablock, + struct source_tag * source) { const char * http_version = "1.0"; ice_config_t *config; time_t now; @@ -598,7 +609,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, currenttime_buffer[0] = '\0'; 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", status_buffer, config->server_id, diff --git a/src/util.h b/src/util.h index 3e73356b2a90dfa154c227e058c846d25b5307e2..c57633a75a8d7c25598a3fbdf8a58a79490b5b00 100644 --- a/src/util.h +++ b/src/util.h @@ -56,11 +56,14 @@ char *util_url_escape(const char *src); * If datablock is NULL no end-of-header nor any data is appended. * Returns the number of bytes written or -1 on error. */ +struct source_tag; /* use forward decleration so we do not need to + * include that would cause other conflicts. */ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset, int cache, int status, const char * statusmsg, 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 * instances of the same key */ diff --git a/src/xslt.c b/src/xslt.c index 608677c6a9dfb26acb04abf552af0c4b8ae097e6..080c7102f1917b2afb320f64ba21e9726b1fa0c9 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -238,7 +238,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) if (string == NULL) 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, "Content-Length: %d\r\n\r\n%s", len, string);