Commit c7910fb8 authored by Philipp Schafft's avatar Philipp Schafft 🦁

Merge branch 'ph3-reportxml'

parents 5df79580 bc6a9603
<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>
<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:&#xa;</xsl:text>
<xsl:value-of select="state/text" />
<xsl:text>&#xa;</xsl:text>
<xsl:if test="state/@definition">
<xsl:text>Error code: </xsl:text>
<xsl:value-of select="state/@definition" />
<xsl:text>&#xa;</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
......@@ -31,6 +31,7 @@ noinst_HEADERS = \
tls.h \
refobject.h \
module.h \
reportxml.h \
event.h \
event_log.h \
event_exec.h \
......@@ -72,6 +73,7 @@ icecast_SOURCES = \
tls.c \
refobject.c \
module.c \
reportxml.c \
format.c \
format_ogg.c \
format_mp3.c \
......
......@@ -463,7 +463,7 @@ void admin_send_response(xmlDocPtr doc,
config_release_config();
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);
}
}
......
......@@ -34,6 +34,8 @@
#include "util.h"
#include "auth.h"
#include "event.h"
#include "refobject.h"
#include "reportxml.h"
/* for config_reread_config() */
#include "yp.h"
......@@ -199,6 +201,7 @@ void config_init_configuration(ice_config_t *configuration)
{
memset(configuration, 0, sizeof(ice_config_t));
_set_defaults(configuration);
configuration->reportxml_db = reportxml_database_new();
}
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
config_clear_http_header(c->http_headers);
refobject_unref(c->reportxml_db);
memset(c, 0, sizeof(ice_config_t));
}
......@@ -2076,6 +2082,28 @@ static void _parse_paths(xmlDocPtr doc,
configuration->adminroot_dir = (char *)temp;
if (configuration->adminroot_dir[strlen(configuration->adminroot_dir)-1] == '/')
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) {
_parse_resource(doc, node, configuration);
}
......
......@@ -223,6 +223,7 @@ struct ice_config_tag {
char *webroot_dir;
char *adminroot_dir;
resource_t *resources;
reportxml_database_t *reportxml_db;
char *access_log;
char *error_log;
......
This diff is collapsed.
......@@ -27,8 +27,17 @@
#include "refbuf.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
typedef enum _document_domain_tag {
DOCUMENT_DOMAIN_WEB,
DOCUMENT_DOMAIN_ADMIN
} document_domain_t;
typedef enum _protocol_tag {
ICECAST_PROTOCOL_HTTP = 0,
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_204(client_t *client);
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);
int client_send_bytes (client_t *client, const 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"},
{.id = ICECAST_ERROR_XSLT_problem, .http_status = 500,
.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) {
......
......@@ -48,7 +48,8 @@ typedef enum {
ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE,
ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR,
ICECAST_ERROR_XSLT_PARSE,
ICECAST_ERROR_XSLT_problem
ICECAST_ERROR_XSLT_problem,
ICECAST_ERROR_RECURSIVE_ERROR
} icecast_error_id_t;
struct icecast_error_tag {
......
......@@ -98,6 +98,12 @@ typedef struct module_tag module_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] ]--- */
typedef struct refobject_base_tag refobject_base_t;
......@@ -107,6 +113,9 @@ typedef union __attribute__ ((__transparent_union__)) {
refobject_base_t *refobject_base;
module_t *module;
module_container_t *module_container;
reportxml_t *reportxml;
reportxml_node_t *reportxml_node;
reportxml_database_t *reportxml_database;
} refobject_t;
#else
typedef void * refobject_t;
......
This diff is collapsed.
/* 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);
xslt_transform(doc, xslpath, client);
xslt_transform(doc, xslpath, client, 200);
xmlFreeDoc(doc);
free(xslpath);
......
......@@ -285,7 +285,16 @@ static xmlDocPtr custom_loader(const xmlChar *URI,
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;
xsltStylesheetPtr cur;
......@@ -305,7 +314,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
{
thread_mutex_unlock(&xsltlock);
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;
}
......@@ -346,10 +355,10 @@ 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, NULL, client);
ret = util_http_build_header(refbuf->data, full_len, 0, 0, status, NULL, mediatype, charset, 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);
_send_error(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED, status);
} else {
if ( full_len < (ret + (ssize_t)len + (ssize_t)64) ) {
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.");
refbuf->data = new_data;
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) {
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;
}
} else {
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;
}
}
......@@ -375,7 +384,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
if (!failed) {
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->refbuf = refbuf;
refbuf->len = strlen (refbuf->data);
......@@ -387,7 +396,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client)
else
{
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);
xmlFreeDoc(res);
......
......@@ -16,7 +16,7 @@
#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_shutdown(void);
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