mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Merge branch 'ph3-reportxml'
This commit is contained in:
commit
c7910fb8bf
20
admin/error-html.xsl
Normal file
20
admin/error-html.xsl
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0" xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<xsl:output omit-xml-declaration="no" method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" encoding="UTF-8" />
|
||||||
|
<xsl:include href="includes/web-page.xsl"/>
|
||||||
|
<xsl:variable name="title">Error</xsl:variable>
|
||||||
|
|
||||||
|
<xsl:template name="content">
|
||||||
|
<div class="roundbox">
|
||||||
|
<xsl:for-each select="/report/incident">
|
||||||
|
<div class="article">
|
||||||
|
<h3>Response</h3>
|
||||||
|
<h4>Message</h4>
|
||||||
|
<p><xsl:value-of select="state/text" /></p>
|
||||||
|
<xsl:if test="state/@definition">
|
||||||
|
<p>Error code: <xsl:value-of select="state/@definition" /></p>
|
||||||
|
</xsl:if>
|
||||||
|
</div>
|
||||||
|
</xsl:for-each>
|
||||||
|
</div>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
15
admin/error-plaintext.xsl
Normal file
15
admin/error-plaintext.xsl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" version = "1.0">
|
||||||
|
<xsl:output omit-xml-declaration="yes" media-type="text/plain" method="text" indent="no" encoding="UTF-8" />
|
||||||
|
<xsl:template name="content" match="/report">
|
||||||
|
<xsl:for-each select="/report/incident">
|
||||||
|
<xsl:text>Report:
</xsl:text>
|
||||||
|
<xsl:value-of select="state/text" />
|
||||||
|
<xsl:text>
</xsl:text>
|
||||||
|
<xsl:if test="state/@definition">
|
||||||
|
<xsl:text>Error code: </xsl:text>
|
||||||
|
<xsl:value-of select="state/@definition" />
|
||||||
|
<xsl:text>
</xsl:text>
|
||||||
|
</xsl:if>
|
||||||
|
</xsl:for-each>
|
||||||
|
</xsl:template>
|
||||||
|
</xsl:stylesheet>
|
@ -31,6 +31,7 @@ noinst_HEADERS = \
|
|||||||
tls.h \
|
tls.h \
|
||||||
refobject.h \
|
refobject.h \
|
||||||
module.h \
|
module.h \
|
||||||
|
reportxml.h \
|
||||||
event.h \
|
event.h \
|
||||||
event_log.h \
|
event_log.h \
|
||||||
event_exec.h \
|
event_exec.h \
|
||||||
@ -72,6 +73,7 @@ icecast_SOURCES = \
|
|||||||
tls.c \
|
tls.c \
|
||||||
refobject.c \
|
refobject.c \
|
||||||
module.c \
|
module.c \
|
||||||
|
reportxml.c \
|
||||||
format.c \
|
format.c \
|
||||||
format_ogg.c \
|
format_ogg.c \
|
||||||
format_mp3.c \
|
format_mp3.c \
|
||||||
|
@ -463,7 +463,7 @@ void admin_send_response(xmlDocPtr doc,
|
|||||||
config_release_config();
|
config_release_config();
|
||||||
|
|
||||||
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
|
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
|
||||||
xslt_transform(doc, fullpath_xslt_template, client);
|
xslt_transform(doc, fullpath_xslt_template, client, 200);
|
||||||
free(fullpath_xslt_template);
|
free(fullpath_xslt_template);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
|
#include "refobject.h"
|
||||||
|
#include "reportxml.h"
|
||||||
|
|
||||||
/* for config_reread_config() */
|
/* for config_reread_config() */
|
||||||
#include "yp.h"
|
#include "yp.h"
|
||||||
@ -199,6 +201,7 @@ void config_init_configuration(ice_config_t *configuration)
|
|||||||
{
|
{
|
||||||
memset(configuration, 0, sizeof(ice_config_t));
|
memset(configuration, 0, sizeof(ice_config_t));
|
||||||
_set_defaults(configuration);
|
_set_defaults(configuration);
|
||||||
|
configuration->reportxml_db = reportxml_database_new();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning)
|
static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning)
|
||||||
@ -668,6 +671,9 @@ void config_clear(ice_config_t *c)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
config_clear_http_header(c->http_headers);
|
config_clear_http_header(c->http_headers);
|
||||||
|
|
||||||
|
refobject_unref(c->reportxml_db);
|
||||||
|
|
||||||
memset(c, 0, sizeof(ice_config_t));
|
memset(c, 0, sizeof(ice_config_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2076,6 +2082,28 @@ static void _parse_paths(xmlDocPtr doc,
|
|||||||
configuration->adminroot_dir = (char *)temp;
|
configuration->adminroot_dir = (char *)temp;
|
||||||
if (configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
|
if (configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
|
||||||
configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
|
configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] = 0;
|
||||||
|
} else if (xmlStrcmp(node->name, XMLSTR("reportxmldb")) == 0) {
|
||||||
|
reportxml_t *report;
|
||||||
|
xmlDocPtr dbdoc;
|
||||||
|
|
||||||
|
if (!(temp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1))) {
|
||||||
|
ICECAST_LOG_WARN("<reportxmldb> setting must not be empty.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dbdoc = xmlParseFile(temp);
|
||||||
|
if (!doc) {
|
||||||
|
ICECAST_LOG_ERROR("Can not read report xml database \"%H\" as XML", temp);
|
||||||
|
} else {
|
||||||
|
report = reportxml_parse_xmldoc(dbdoc);
|
||||||
|
xmlFreeDoc(dbdoc);
|
||||||
|
if (!report) {
|
||||||
|
ICECAST_LOG_ERROR("Can not parse report xml database \"%H\"", temp);
|
||||||
|
} else {
|
||||||
|
reportxml_database_add_report(configuration->reportxml_db, report);
|
||||||
|
ICECAST_LOG_INFO("File \"%H\" added to report xml database", temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlFree(temp);
|
||||||
} else if (xmlStrcmp(node->name, XMLSTR("resource")) == 0 || xmlStrcmp(node->name, XMLSTR("alias")) == 0) {
|
} else if (xmlStrcmp(node->name, XMLSTR("resource")) == 0 || xmlStrcmp(node->name, XMLSTR("alias")) == 0) {
|
||||||
_parse_resource(doc, node, configuration);
|
_parse_resource(doc, node, configuration);
|
||||||
}
|
}
|
||||||
|
@ -223,6 +223,7 @@ struct ice_config_tag {
|
|||||||
char *webroot_dir;
|
char *webroot_dir;
|
||||||
char *adminroot_dir;
|
char *adminroot_dir;
|
||||||
resource_t *resources;
|
resource_t *resources;
|
||||||
|
reportxml_database_t *reportxml_db;
|
||||||
|
|
||||||
char *access_log;
|
char *access_log;
|
||||||
char *error_log;
|
char *error_log;
|
||||||
|
248
src/client.c
248
src/client.c
@ -38,6 +38,9 @@
|
|||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
#include "fserve.h"
|
#include "fserve.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
|
#include "reportxml.h"
|
||||||
|
#include "refobject.h"
|
||||||
|
#include "xslt.h"
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
@ -236,79 +239,73 @@ int client_read_bytes(client_t *client, void *buf, unsigned len)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _client_send_error(client_t *client, int plain, const icecast_error_t *error)
|
static inline void _client_send_error(client_t *client, const icecast_error_t *error)
|
||||||
{
|
{
|
||||||
ssize_t ret;
|
ice_config_t *config;
|
||||||
refbuf_t *data;
|
reportxml_t *report;
|
||||||
|
admin_format_t admin_format;
|
||||||
|
const char *xslt = NULL;
|
||||||
|
|
||||||
if (error->http_status == 500) {
|
admin_format = client_get_admin_format_by_content_negotiation(client);
|
||||||
client_send_500(client, error->message);
|
|
||||||
return;
|
switch (admin_format) {
|
||||||
|
case ADMIN_FORMAT_RAW:
|
||||||
|
xslt = NULL;
|
||||||
|
break;
|
||||||
|
case ADMIN_FORMAT_TRANSFORMED:
|
||||||
|
xslt = CLIENT_DEFAULT_ERROR_XSL_TRANSFORMED;
|
||||||
|
break;
|
||||||
|
case ADMIN_FORMAT_PLAINTEXT:
|
||||||
|
xslt = CLIENT_DEFAULT_ERROR_XSL_PLAINTEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
client_send_500(client, "Invalid Admin Type");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = refbuf_new(PER_CLIENT_REFBUF_SIZE);
|
|
||||||
if (!data) {
|
config = config_get_config();
|
||||||
client_send_500(client, error->message);
|
report = reportxml_database_build_report(config->reportxml_db, error->uuid, -1);
|
||||||
return;
|
config_release_config();
|
||||||
|
|
||||||
|
if (!report) {
|
||||||
|
reportxml_node_t *root, *incident, *state, *text;
|
||||||
|
|
||||||
|
report = reportxml_new();
|
||||||
|
root = reportxml_get_root_node(report);
|
||||||
|
incident = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL);
|
||||||
|
state = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, error->uuid, NULL);
|
||||||
|
text = reportxml_node_new(REPORTXML_NODE_TYPE_TEXT, NULL, NULL, NULL);
|
||||||
|
reportxml_node_set_content(text, error->message);
|
||||||
|
reportxml_node_add_child(state, text);
|
||||||
|
reportxml_node_add_child(incident, state);
|
||||||
|
reportxml_node_add_child(root, incident);
|
||||||
|
refobject_unref(text);
|
||||||
|
refobject_unref(state);
|
||||||
|
refobject_unref(incident);
|
||||||
|
refobject_unref(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
client->reuse = ICECAST_REUSE_KEEPALIVE;
|
client_send_reportxml(client, report, DOCUMENT_DOMAIN_ADMIN, xslt, admin_format, error->http_status);
|
||||||
|
|
||||||
ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0,
|
refobject_unref(report);
|
||||||
0, error->http_status, NULL,
|
|
||||||
plain ? "text/plain" : "text/html", "utf-8",
|
|
||||||
NULL, NULL, client);
|
|
||||||
|
|
||||||
if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) {
|
|
||||||
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
|
||||||
client_send_500(client, "Header generation failed.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (plain) {
|
|
||||||
snprintf(data->data, data->len, "Error %i\r\n---------\r\n\r\nMessage: %s\r\n\r\nError code: %s\r\n",
|
|
||||||
error->http_status, error->message, error->uuid
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
snprintf(data->data, data->len,
|
|
||||||
"<html><head><title>Error %i</title></head><body><h1>Error %i</h1><hr><p><b>%s</b></p><p>Error code: %s</p></body></html>\r\n",
|
|
||||||
error->http_status, error->http_status, error->message, error->uuid);
|
|
||||||
}
|
|
||||||
data->len = strlen(data->data);
|
|
||||||
|
|
||||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
|
||||||
"Content-Length: %llu\r\n\r\n",
|
|
||||||
(long long unsigned int)data->len);
|
|
||||||
|
|
||||||
client->respcode = error->http_status;
|
|
||||||
client->refbuf->len = strlen (client->refbuf->data);
|
|
||||||
client->refbuf->next = data;
|
|
||||||
|
|
||||||
fserve_add_client (client, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_send_error_by_id(client_t *client, icecast_error_id_t id)
|
void client_send_error_by_id(client_t *client, icecast_error_id_t id)
|
||||||
{
|
{
|
||||||
const icecast_error_t *error = error_get_by_id(id);
|
const icecast_error_t *error = error_get_by_id(id);
|
||||||
const char *pref;
|
|
||||||
int plain;
|
|
||||||
|
|
||||||
if (!error) {
|
if (!error) {
|
||||||
client_send_500(client, "Unknown error ID");
|
client_send_500(client, "Unknown error ID");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pref = util_http_select_best(httpp_getvar(client->parser, "accept"), "text/plain", "text/html", (const char*)NULL);
|
if (error->http_status == 500) {
|
||||||
|
client_send_500(client, error->message);
|
||||||
if (strcmp(pref, "text/plain") == 0) {
|
return;
|
||||||
plain = 1;
|
|
||||||
} else if (strcmp(pref, "text/html") == 0) {
|
|
||||||
plain = 0;
|
|
||||||
} else {
|
|
||||||
plain = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_client_send_error(client, plain, error);
|
_client_send_error(client, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_send_101(client_t *client, reuse_t reuse)
|
void client_send_101(client_t *client, reuse_t reuse)
|
||||||
@ -409,6 +406,151 @@ static inline void client_send_500(client_t *client, const char *message)
|
|||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* this function sends a reportxml file to the client in the prefered format. */
|
||||||
|
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status)
|
||||||
|
{
|
||||||
|
admin_format_t admin_format;
|
||||||
|
xmlDocPtr doc;
|
||||||
|
|
||||||
|
if (!client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!report) {
|
||||||
|
ICECAST_LOG_ERROR("No report xml given. Sending 500 to client %p", client);
|
||||||
|
client_send_500(client, "No report.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!status)
|
||||||
|
status = 200;
|
||||||
|
|
||||||
|
if (admin_format_hint == ADMIN_FORMAT_AUTO) {
|
||||||
|
admin_format = client_get_admin_format_by_content_negotiation(client);
|
||||||
|
} else {
|
||||||
|
admin_format = admin_format_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xsl) {
|
||||||
|
switch (admin_format) {
|
||||||
|
case ADMIN_FORMAT_RAW:
|
||||||
|
/* noop, we don't need to set xsl */
|
||||||
|
break;
|
||||||
|
case ADMIN_FORMAT_TRANSFORMED:
|
||||||
|
xsl = CLIENT_DEFAULT_REPORT_XSL_TRANSFORMED;
|
||||||
|
break;
|
||||||
|
case ADMIN_FORMAT_PLAINTEXT:
|
||||||
|
xsl = CLIENT_DEFAULT_REPORT_XSL_PLAINTEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ICECAST_LOG_ERROR("Unsupported admin format and no XSLT file given. Sending 500 to client %p", client);
|
||||||
|
client_send_500(client, "Unsupported admin format.");
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (admin_format_hint == ADMIN_FORMAT_AUTO) {
|
||||||
|
ICECAST_LOG_ERROR("No explicit admin format but XSLT file given. BUG. Sending 500 to client %p", client);
|
||||||
|
client_send_500(client, "Admin type AUTO but XSLT.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
doc = reportxml_render_xmldoc(report);
|
||||||
|
if (!doc) {
|
||||||
|
ICECAST_LOG_ERROR("Can not render XML Document from report. Sending 500 to client %p", client);
|
||||||
|
client_send_500(client, "Can not render XML Document from report.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (admin_format == ADMIN_FORMAT_RAW) {
|
||||||
|
xmlChar *buff = NULL;
|
||||||
|
int len = 0;
|
||||||
|
size_t buf_len;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
xmlDocDumpMemory(doc, &buff, &len);
|
||||||
|
|
||||||
|
buf_len = len + 1024;
|
||||||
|
if (buf_len < 4096)
|
||||||
|
buf_len = 4096;
|
||||||
|
|
||||||
|
client_set_queue(client, NULL);
|
||||||
|
client->refbuf = refbuf_new(buf_len);
|
||||||
|
|
||||||
|
ret = util_http_build_header(client->refbuf->data, buf_len, 0,
|
||||||
|
0, status, NULL,
|
||||||
|
"text/xml", "utf-8",
|
||||||
|
NULL, NULL, client);
|
||||||
|
if (ret < 0) {
|
||||||
|
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||||
|
client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED);
|
||||||
|
xmlFree(buff);
|
||||||
|
return;
|
||||||
|
} else if (buf_len < (size_t)(len + ret + 64)) {
|
||||||
|
void *new_data;
|
||||||
|
buf_len = ret + len + 64;
|
||||||
|
new_data = realloc(client->refbuf->data, buf_len);
|
||||||
|
if (new_data) {
|
||||||
|
ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
|
||||||
|
client->refbuf->data = new_data;
|
||||||
|
client->refbuf->len = buf_len;
|
||||||
|
ret = util_http_build_header(client->refbuf->data, buf_len, 0,
|
||||||
|
0, status, NULL,
|
||||||
|
"text/xml", "utf-8",
|
||||||
|
NULL, NULL, client);
|
||||||
|
if (ret == -1) {
|
||||||
|
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||||
|
client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED);
|
||||||
|
xmlFree(buff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client.");
|
||||||
|
client_send_error_by_id(client, ICECAST_ERROR_GEN_BUFFER_REALLOC);
|
||||||
|
xmlFree(buff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: in this section we hope no function will ever return -1 */
|
||||||
|
ret += snprintf (client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
||||||
|
|
||||||
|
client->refbuf->len = ret;
|
||||||
|
xmlFree(buff);
|
||||||
|
client->respcode = status;
|
||||||
|
fserve_add_client (client, NULL);
|
||||||
|
} else {
|
||||||
|
char *fullpath_xslt_template;
|
||||||
|
const char *document_domain_path;
|
||||||
|
ssize_t fullpath_xslt_template_len;
|
||||||
|
ice_config_t *config;
|
||||||
|
|
||||||
|
config = config_get_config();
|
||||||
|
switch (domain) {
|
||||||
|
case DOCUMENT_DOMAIN_WEB:
|
||||||
|
document_domain_path = config->webroot_dir;
|
||||||
|
break;
|
||||||
|
case DOCUMENT_DOMAIN_ADMIN:
|
||||||
|
document_domain_path = config->adminroot_dir;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
config_release_config();
|
||||||
|
ICECAST_LOG_ERROR("Invalid document domain. Sending 500 to client %p", client);
|
||||||
|
client_send_500(client, "Invalid document domain.");
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fullpath_xslt_template_len = strlen(document_domain_path) + strlen(xsl) + strlen(PATH_SEPARATOR) + 1;
|
||||||
|
fullpath_xslt_template = malloc(fullpath_xslt_template_len);
|
||||||
|
snprintf(fullpath_xslt_template, fullpath_xslt_template_len, "%s%s%s", document_domain_path, PATH_SEPARATOR, xsl);
|
||||||
|
config_release_config();
|
||||||
|
|
||||||
|
ICECAST_LOG_DEBUG("Sending XSLT (%s)", fullpath_xslt_template);
|
||||||
|
xslt_transform(doc, fullpath_xslt_template, client, status);
|
||||||
|
free(fullpath_xslt_template);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
}
|
||||||
|
|
||||||
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client)
|
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client)
|
||||||
{
|
{
|
||||||
const char *pref;
|
const char *pref;
|
||||||
|
10
src/client.h
10
src/client.h
@ -27,8 +27,17 @@
|
|||||||
#include "refbuf.h"
|
#include "refbuf.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
|
#define CLIENT_DEFAULT_REPORT_XSL_TRANSFORMED "report-html.xsl"
|
||||||
|
#define CLIENT_DEFAULT_REPORT_XSL_PLAINTEXT "report-plaintext.xsl"
|
||||||
|
#define CLIENT_DEFAULT_ERROR_XSL_TRANSFORMED "error-html.xsl"
|
||||||
|
#define CLIENT_DEFAULT_ERROR_XSL_PLAINTEXT "error-plaintext.xsl"
|
||||||
#define CLIENT_DEFAULT_ADMIN_FORMAT ADMIN_FORMAT_TRANSFORMED
|
#define CLIENT_DEFAULT_ADMIN_FORMAT ADMIN_FORMAT_TRANSFORMED
|
||||||
|
|
||||||
|
typedef enum _document_domain_tag {
|
||||||
|
DOCUMENT_DOMAIN_WEB,
|
||||||
|
DOCUMENT_DOMAIN_ADMIN
|
||||||
|
} document_domain_t;
|
||||||
|
|
||||||
typedef enum _protocol_tag {
|
typedef enum _protocol_tag {
|
||||||
ICECAST_PROTOCOL_HTTP = 0,
|
ICECAST_PROTOCOL_HTTP = 0,
|
||||||
ICECAST_PROTOCOL_SHOUTCAST
|
ICECAST_PROTOCOL_SHOUTCAST
|
||||||
@ -133,6 +142,7 @@ void client_send_error_by_id(client_t *client, icecast_error_id_t id);
|
|||||||
void client_send_101(client_t *client, reuse_t reuse);
|
void client_send_101(client_t *client, reuse_t reuse);
|
||||||
void client_send_204(client_t *client);
|
void client_send_204(client_t *client);
|
||||||
void client_send_426(client_t *client, reuse_t reuse);
|
void client_send_426(client_t *client, reuse_t reuse);
|
||||||
|
void client_send_reportxml(client_t *client, reportxml_t *report, document_domain_t domain, const char *xsl, admin_format_t admin_format_hint, int status);
|
||||||
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client);
|
admin_format_t client_get_admin_format_by_content_negotiation(client_t *client);
|
||||||
int client_send_bytes (client_t *client, const void *buf, unsigned len);
|
int client_send_bytes (client_t *client, const void *buf, unsigned len);
|
||||||
int client_read_bytes (client_t *client, void *buf, unsigned len);
|
int client_read_bytes (client_t *client, void *buf, unsigned len);
|
||||||
|
@ -132,7 +132,10 @@ static const icecast_error_t __errors[] = {
|
|||||||
.message = "Could not parse XSLT file"},
|
.message = "Could not parse XSLT file"},
|
||||||
{.id = ICECAST_ERROR_XSLT_problem, .http_status = 500,
|
{.id = ICECAST_ERROR_XSLT_problem, .http_status = 500,
|
||||||
.uuid = "d3c6e4b3-7d6e-4191-a81b-970273067ae3",
|
.uuid = "d3c6e4b3-7d6e-4191-a81b-970273067ae3",
|
||||||
.message = "XSLT problem"}
|
.message = "XSLT problem"},
|
||||||
|
{.id = ICECAST_ERROR_RECURSIVE_ERROR, .http_status = 500,
|
||||||
|
.uuid = "13489d5c-eae6-4bf3-889e-ec1fa9a9b9ac",
|
||||||
|
.message = "Recursive error"}
|
||||||
};
|
};
|
||||||
|
|
||||||
const icecast_error_t * error_get_by_id(icecast_error_id_t id) {
|
const icecast_error_t * error_get_by_id(icecast_error_id_t id) {
|
||||||
|
@ -48,7 +48,8 @@ typedef enum {
|
|||||||
ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE,
|
ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE,
|
||||||
ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR,
|
ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR,
|
||||||
ICECAST_ERROR_XSLT_PARSE,
|
ICECAST_ERROR_XSLT_PARSE,
|
||||||
ICECAST_ERROR_XSLT_problem
|
ICECAST_ERROR_XSLT_problem,
|
||||||
|
ICECAST_ERROR_RECURSIVE_ERROR
|
||||||
} icecast_error_id_t;
|
} icecast_error_id_t;
|
||||||
|
|
||||||
struct icecast_error_tag {
|
struct icecast_error_tag {
|
||||||
|
@ -98,6 +98,12 @@ typedef struct module_tag module_t;
|
|||||||
|
|
||||||
typedef struct module_container_tag module_container_t;
|
typedef struct module_container_tag module_container_t;
|
||||||
|
|
||||||
|
/* ---[ reportxml.[ch] ]--- */
|
||||||
|
|
||||||
|
typedef struct reportxml_tag reportxml_t;
|
||||||
|
typedef struct reportxml_node_tag reportxml_node_t;
|
||||||
|
typedef struct reportxml_database_tag reportxml_database_t;
|
||||||
|
|
||||||
/* ---[ refobject.[ch] ]--- */
|
/* ---[ refobject.[ch] ]--- */
|
||||||
|
|
||||||
typedef struct refobject_base_tag refobject_base_t;
|
typedef struct refobject_base_tag refobject_base_t;
|
||||||
@ -107,6 +113,9 @@ typedef union __attribute__ ((__transparent_union__)) {
|
|||||||
refobject_base_t *refobject_base;
|
refobject_base_t *refobject_base;
|
||||||
module_t *module;
|
module_t *module;
|
||||||
module_container_t *module_container;
|
module_container_t *module_container;
|
||||||
|
reportxml_t *reportxml;
|
||||||
|
reportxml_node_t *reportxml_node;
|
||||||
|
reportxml_database_t *reportxml_database;
|
||||||
} refobject_t;
|
} refobject_t;
|
||||||
#else
|
#else
|
||||||
typedef void * refobject_t;
|
typedef void * refobject_t;
|
||||||
|
1316
src/reportxml.c
Normal file
1316
src/reportxml.c
Normal file
File diff suppressed because it is too large
Load Diff
65
src/reportxml.h
Normal file
65
src/reportxml.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* Icecast
|
||||||
|
*
|
||||||
|
* This program is distributed under the GNU General Public License, version 2.
|
||||||
|
* A copy of this license is included with this source.
|
||||||
|
*
|
||||||
|
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __REPORTXML_H__
|
||||||
|
#define __REPORTXML_H__
|
||||||
|
|
||||||
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
|
#include "icecasttypes.h"
|
||||||
|
#include "compat.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
REPORTXML_NODE_TYPE__ERROR,
|
||||||
|
REPORTXML_NODE_TYPE_REPORT,
|
||||||
|
REPORTXML_NODE_TYPE_DEFINITION,
|
||||||
|
REPORTXML_NODE_TYPE_INCIDENT,
|
||||||
|
REPORTXML_NODE_TYPE_STATE,
|
||||||
|
REPORTXML_NODE_TYPE_BACKTRACE,
|
||||||
|
REPORTXML_NODE_TYPE_POSITION,
|
||||||
|
REPORTXML_NODE_TYPE_MORE,
|
||||||
|
REPORTXML_NODE_TYPE_FIX,
|
||||||
|
REPORTXML_NODE_TYPE_ACTION,
|
||||||
|
REPORTXML_NODE_TYPE_REASON,
|
||||||
|
REPORTXML_NODE_TYPE_TEXT,
|
||||||
|
REPORTXML_NODE_TYPE_TIMESTAMP,
|
||||||
|
REPORTXML_NODE_TYPE_RESOURCE,
|
||||||
|
REPORTXML_NODE_TYPE_VALUE,
|
||||||
|
REPORTXML_NODE_TYPE_REFERENCE,
|
||||||
|
REPORTXML_NODE_TYPE_EXTENSION
|
||||||
|
} reportxml_node_type_t;
|
||||||
|
|
||||||
|
reportxml_t * reportxml_new(void);
|
||||||
|
reportxml_node_t * reportxml_get_root_node(reportxml_t *report);
|
||||||
|
reportxml_node_t * reportxml_get_node_by_attribute(reportxml_t *report, const char *key, const char *value, int include_definitions);
|
||||||
|
reportxml_t * reportxml_parse_xmldoc(xmlDocPtr doc);
|
||||||
|
xmlDocPtr reportxml_render_xmldoc(reportxml_t *report);
|
||||||
|
|
||||||
|
reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const char *id, const char *definition, const char *akindof);
|
||||||
|
reportxml_node_t * reportxml_node_parse_xmlnode(xmlNodePtr xmlnode);
|
||||||
|
reportxml_node_t * reportxml_node_copy(reportxml_node_t *node);
|
||||||
|
xmlNodePtr reportxml_node_render_xmlnode(reportxml_node_t *node);
|
||||||
|
reportxml_node_type_t reportxml_node_get_type(reportxml_node_t *node);
|
||||||
|
int reportxml_node_set_attribute(reportxml_node_t *node, const char *key, const char *value);
|
||||||
|
char * reportxml_node_get_attribute(reportxml_node_t *node, const char *key);
|
||||||
|
int reportxml_node_add_child(reportxml_node_t *node, reportxml_node_t *child);
|
||||||
|
ssize_t reportxml_node_count_child(reportxml_node_t *node);
|
||||||
|
reportxml_node_t * reportxml_node_get_child(reportxml_node_t *node, size_t idx);
|
||||||
|
reportxml_node_t * reportxml_node_get_child_by_attribute(reportxml_node_t *node, const char *key, const char *value, int include_definitions);
|
||||||
|
int reportxml_node_set_content(reportxml_node_t *node, const char *value);
|
||||||
|
char * reportxml_node_get_content(reportxml_node_t *node);
|
||||||
|
int reportxml_node_add_xml_child(reportxml_node_t *node, xmlNodePtr child);
|
||||||
|
ssize_t reportxml_node_count_xml_child(reportxml_node_t *node);
|
||||||
|
xmlNodePtr reportxml_node_get_xml_child(reportxml_node_t *node, size_t idx);
|
||||||
|
|
||||||
|
reportxml_database_t * reportxml_database_new(void);
|
||||||
|
int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report);
|
||||||
|
reportxml_node_t * reportxml_database_build_node(reportxml_database_t *db, const char *id, ssize_t depth);
|
||||||
|
reportxml_t * reportxml_database_build_report(reportxml_database_t *db, const char *id, ssize_t depth);
|
||||||
|
|
||||||
|
#endif
|
@ -1024,7 +1024,7 @@ void stats_transform_xslt(client_t *client, const char *uri)
|
|||||||
|
|
||||||
doc = stats_get_xml(0, mount, client->mode);
|
doc = stats_get_xml(0, mount, client->mode);
|
||||||
|
|
||||||
xslt_transform(doc, xslpath, client);
|
xslt_transform(doc, xslpath, client, 200);
|
||||||
|
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
free(xslpath);
|
free(xslpath);
|
||||||
|
27
src/xslt.c
27
src/xslt.c
@ -285,7 +285,16 @@ static xmlDocPtr custom_loader(const xmlChar *URI,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
static inline void _send_error(client_t *client, icecast_error_id_t id, int old_status) {
|
||||||
|
if (old_status >= 400) {
|
||||||
|
client_send_error_by_id(client, ICECAST_ERROR_RECURSIVE_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
client_send_error_by_id(client, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status)
|
||||||
{
|
{
|
||||||
xmlDocPtr res;
|
xmlDocPtr res;
|
||||||
xsltStylesheetPtr cur;
|
xsltStylesheetPtr cur;
|
||||||
@ -305,7 +314,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
|||||||
{
|
{
|
||||||
thread_mutex_unlock(&xsltlock);
|
thread_mutex_unlock(&xsltlock);
|
||||||
ICECAST_LOG_ERROR("problem reading stylesheet \"%s\"", xslfilename);
|
ICECAST_LOG_ERROR("problem reading stylesheet \"%s\"", xslfilename);
|
||||||
client_send_error_by_id(client, ICECAST_ERROR_XSLT_PARSE);
|
_send_error(client, ICECAST_ERROR_XSLT_PARSE, status);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,10 +355,10 @@ 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, NULL, client);
|
ret = util_http_build_header(refbuf->data, full_len, 0, 0, status, NULL, mediatype, charset, NULL, NULL, client);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED);
|
_send_error(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED, status);
|
||||||
} else {
|
} else {
|
||||||
if ( full_len < (ret + (ssize_t)len + (ssize_t)64) ) {
|
if ( full_len < (ret + (ssize_t)len + (ssize_t)64) ) {
|
||||||
void *new_data;
|
void *new_data;
|
||||||
@ -359,15 +368,15 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
|||||||
ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
|
ICECAST_LOG_DEBUG("Client buffer reallocation succeeded.");
|
||||||
refbuf->data = new_data;
|
refbuf->data = new_data;
|
||||||
refbuf->len = full_len;
|
refbuf->len = full_len;
|
||||||
ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL, client);
|
ret = util_http_build_header(refbuf->data, full_len, 0, 0, status, NULL, mediatype, charset, NULL, NULL, client);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED);
|
_send_error(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED, status);
|
||||||
failed = 1;
|
failed = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client.");
|
ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client.");
|
||||||
client_send_error_by_id(client, ICECAST_ERROR_GEN_BUFFER_REALLOC);
|
_send_error(client, ICECAST_ERROR_GEN_BUFFER_REALLOC, status);
|
||||||
failed = 1;
|
failed = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,7 +384,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
|||||||
if (!failed) {
|
if (!failed) {
|
||||||
snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
||||||
|
|
||||||
client->respcode = 200;
|
client->respcode = status;
|
||||||
client_set_queue (client, NULL);
|
client_set_queue (client, NULL);
|
||||||
client->refbuf = refbuf;
|
client->refbuf = refbuf;
|
||||||
refbuf->len = strlen (refbuf->data);
|
refbuf->len = strlen (refbuf->data);
|
||||||
@ -387,7 +396,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename);
|
ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename);
|
||||||
client_send_error_by_id(client, ICECAST_ERROR_XSLT_problem);
|
_send_error(client, ICECAST_ERROR_XSLT_problem, status);
|
||||||
}
|
}
|
||||||
thread_mutex_unlock (&xsltlock);
|
thread_mutex_unlock (&xsltlock);
|
||||||
xmlFreeDoc(res);
|
xmlFreeDoc(res);
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#include "icecasttypes.h"
|
#include "icecasttypes.h"
|
||||||
|
|
||||||
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client);
|
void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, int status);
|
||||||
void xslt_initialize(void);
|
void xslt_initialize(void);
|
||||||
void xslt_shutdown(void);
|
void xslt_shutdown(void);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user