diff --git a/conf/icecast.xml b/conf/icecast.xml index e28435fa..71b790c2 100644 --- a/conf/icecast.xml +++ b/conf/icecast.xml @@ -32,6 +32,7 @@ /usr/local/icecast /tmp + /usr/local/icecast/webroot diff --git a/src/Makefile.am b/src/Makefile.am index d89e1fb2..29a64718 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,23 +11,20 @@ noinst_HEADERS = config.h os.h logging.h sighandler.h connection.h global.h\ compat.h format_mp3.h icecast_SOURCES = config.c main.c logging.c sighandler.c connection.c global.c\ util.c slave.c source.c stats.c refbuf.c client.c format.c format_vorbis.c\ - format_mp3.c + format_mp3.c xslt.c icecast_LDADD = net/libicenet.la thread/libicethread.la httpp/libicehttpp.la\ log/libicelog.la avl/libiceavl.la timing/libicetiming.la -LIBS = @LIBS@ -lpthread @SOCKET_LIBS@ @XML_LIBS@ @OGG_LIBS@ @VORBIS_LIBS@ -CFLAGS = @CFLAGS@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ +LIBS = @LIBS@ -lxslt -lpthread @SOCKET_LIBS@ @XML_LIBS@ @OGG_LIBS@ @VORBIS_LIBS@ +CFLAGS = -g @CFLAGS@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@ INCLUDES = -I$(srcdir)/net -I$(srcdir)/thread -I$(srcdir)/avl -I$(srcdir)/httpp \ -I$(srcdir)/log -I$(srcdir)/timing -# SCCS stuff (for BitKeeper) -GET = true - debug: - $(MAKE) all CFLAGS="@DEBUG@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@" + $(MAKE) all CFLAGS="@DEBUG@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@" profile: - $(MAKE) all CFLAGS="@PROFILE@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@" + $(MAKE) all CFLAGS="@PROFILE@ @XML_CFLAGS@ @OGG_CFLAGS@ @VORBIS_CFLAGS@" diff --git a/src/config.c b/src/config.c index 8f403024..ff659be0 100644 --- a/src/config.c +++ b/src/config.c @@ -28,9 +28,11 @@ #ifndef _WIN32 #define CONFIG_DEFAULT_BASE_DIR "/usr/local/icecast" #define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs" +#define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot" #else #define CONFIG_DEFAULT_BASE_DIR ".\\" #define CONFIG_DEFAULT_LOG_DIR ".\\logs" +#define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot" #endif ice_config_t _configuration; @@ -278,6 +280,9 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node) } else if (strcmp(node->name, "logdir") == 0) { if (_configuration.log_dir) free(_configuration.log_dir); _configuration.log_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + } else if (strcmp(node->name, "webroot") == 0) { + if (_configuration.webroot_dir) free(_configuration.webroot_dir); + _configuration.webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } } while ((node = node->next)); } diff --git a/src/config.h b/src/config.h index 37fd87f3..4534d1a7 100644 --- a/src/config.h +++ b/src/config.h @@ -39,6 +39,7 @@ typedef struct ice_config_tag char *base_dir; char *log_dir; + char *webroot_dir; char *access_log; char *error_log; diff --git a/src/connection.c b/src/connection.c index 42aeb59d..51d7a721 100644 --- a/src/connection.c +++ b/src/connection.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -32,6 +33,7 @@ #include "stats.h" #include "format.h" #include "logging.h" +#include "xslt.h" #include "source.h" @@ -333,6 +335,8 @@ static void *_handle_connection(void *arg) http_var_t *var; client_t *client; int bytes; + struct stat statbuf; + char fullPath[4096]; while (global.running == ICE_RUNNING) { memset(header, 0, 4096); @@ -437,6 +441,27 @@ static void *_handle_connection(void *arg) if (strcmp(httpp_getvar(parser, HTTPP_VAR_URI), "/stats.xml") == 0) { printf("sending stats.xml\n"); stats_sendxml(client); + client_destroy(client); + continue; + } + + /* Here we are parsing the URI request to see + ** if the extension is .xsl, if so, then process + ** this request as an XSLT request + */ + if (util_check_valid_extension(httpp_getvar(parser, HTTPP_VAR_URI)) == XSLT_CONTENT) { + util_get_full_path(httpp_getvar(parser, HTTPP_VAR_URI), fullPath, sizeof(fullPath)); + + /* If the file exists, then transform it, otherwise, write a 404 error */ + if (stat(fullPath, &statbuf) == 0) { + sock_write(client->con->sock, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"); + stats_transform_xslt(client, fullPath); + } + else { + sock_write(client->con->sock, "HTTP/1.0 404 File Not Found\r\nContent-Type: text/html\r\n\r\n"\ + "The file you requested could not be found.\r\n"); + } + client_destroy(client); continue; } diff --git a/src/stats.c b/src/stats.c index 8d04f807..8e336a2b 100644 --- a/src/stats.c +++ b/src/stats.c @@ -18,6 +18,7 @@ #include "refbuf.h" #include "client.h" #include "stats.h" +#include "xslt.h" #ifdef _WIN32 #define vsnprintf _vsnprintf @@ -728,6 +729,45 @@ static xmlNodePtr _find_xml_node(char *mount, source_xml_t **list, xmlNodePtr ro return node->node; } +void stats_transform_xslt(client_t *client, char *xslpath) +{ + xmlDocPtr doc; + + stats_get_xml(&doc); + + transformXSLT(doc, xslpath, client); + + xmlFreeDoc(doc); +} + +void stats_get_xml(xmlDocPtr *doc) +{ + stats_event_t *event; + stats_event_t *queue; + xmlNodePtr node, srcnode; + source_xml_t *src_nodes = NULL; + + queue = NULL; + _dump_stats_to_queue(&queue); + + *doc = xmlNewDoc("1.0"); + node = xmlNewDocNode(*doc, NULL, "icestats", NULL); + xmlDocSetRootElement(*doc, node); + + + event = _get_event_from_queue(&queue); + while (event) { + if (event->source == NULL) { + xmlNewChild(node, NULL, event->name, event->value); + } else { + srcnode = _find_xml_node(event->source, &src_nodes, node); + xmlNewChild(srcnode, NULL, event->name, event->value); + } + + _free_event(event); + event = _get_event_from_queue(&queue); + } +} void stats_sendxml(client_t *client) { int bytes; diff --git a/src/stats.h b/src/stats.h index 2cffa71e..91855124 100644 --- a/src/stats.h +++ b/src/stats.h @@ -4,6 +4,10 @@ #include "connection.h" #include "httpp.h" #include "client.h" +#include +#include +#include + typedef struct _stats_connection_tag { @@ -70,7 +74,9 @@ void stats_event_dec(char *source, char *name); void *stats_connection(void *arg); void *stats_callback(void *arg); +void stats_transform_xslt(client_t *client, char *xslpath); void stats_sendxml(client_t *client); +void stats_get_xml(xmlDocPtr *doc); #endif /* __STATS_H__ */ diff --git a/src/thread/thread.c b/src/thread/thread.c index e312e3fb..d4e56724 100644 --- a/src/thread/thread.c +++ b/src/thread/thread.c @@ -115,11 +115,6 @@ void thread_initialize(void) { thread_t *thread; - /* this must be called to init pthreads-win32 */ -#ifdef _WIN32 - ptw32_processInitialize(); -#endif - /* set up logging */ log_initialize(); @@ -129,7 +124,7 @@ void thread_initialize(void) log_set_level(_logid, THREAD_DEBUG); #endif - /* create all the interal mutexes, and initialize the mutex tree */ + /* create all the internal mutexes, and initialize the mutex tree */ _mutextree = avl_tree_new(_compare_mutexes, NULL); diff --git a/src/util.c b/src/util.c index 980bbe70..76687b85 100644 --- a/src/util.c +++ b/src/util.c @@ -1,4 +1,6 @@ #include +#include +#include #ifndef _WIN32 #include @@ -10,12 +12,17 @@ #else #include #include +#include +#define snprintf _snprintf +#define strcasecmp stricmp +#define strncasecmp strnicmp #endif #include "sock.h" #include "config.h" #include "util.h" +#include "os.h" /* Abstract out an interface to use either poll or select depending on which * is available (poll is preferred) to watch a single fd. @@ -85,6 +92,46 @@ int util_read_header(int sock, char *buff, unsigned long len) return ret; } - +int util_get_full_path(char *uri, char *fullPath, int fullPathLen) { + int ret = 0; + if (uri) { + memset(fullPath, '\000', fullPathLen); + snprintf(fullPath, fullPathLen-1, "%s%s%s", config_get_config()->webroot_dir, PATH_SEPARATOR, uri); + ret = 1; + } + return ret; +} + +int util_check_valid_extension(char *uri) { + int ret = 0; + char *p2; + + if (uri) { + p2 = strrchr(uri, '.'); + if (p2) { + p2++; + if (strncmp(p2, "xsl", strlen("xsl")) == 0) { + /* Build the full path for the request, concatenating the webroot from the config. + ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. + */ + ret = XSLT_CONTENT; + } + if (strncmp(p2, "htm", strlen("htm")) == 0) { + /* Build the full path for the request, concatenating the webroot from the config. + ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. + */ + ret = HTML_CONTENT; + } + if (strncmp(p2, "html", strlen("html")) == 0) { + /* Build the full path for the request, concatenating the webroot from the config. + ** Here would be also a good time to prevent accesses like '../../../../etc/passwd' or somesuch. + */ + ret = HTML_CONTENT; + } + + } + } + return ret; +} diff --git a/src/util.h b/src/util.h index d3da771f..f034794b 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,12 @@ #ifndef __UTIL_H__ #define __UTIL_H__ +#define XSLT_CONTENT 1 +#define HTML_CONTENT 2 + int util_timed_wait_for_fd(int fd, int timeout); int util_read_header(int sock, char *buff, unsigned long len); +int util_get_full_path(char *uri, char *fullPath, int fullPathLen); +int util_check_valid_extension(char *uri); #endif /* __UTIL_H__ */