diff --git a/src/cfgfile.c b/src/cfgfile.c index 1c7a0e55..23112337 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -61,11 +61,13 @@ #define CONFIG_DEFAULT_LOG_DIR "/usr/local/icecast/logs" #define CONFIG_DEFAULT_WEBROOT_DIR "/usr/local/icecast/webroot" #define CONFIG_DEFAULT_ADMINROOT_DIR "/usr/local/icecast/admin" +#define MIMETYPESFILE "/etc/mime.types" #else #define CONFIG_DEFAULT_BASE_DIR ".\\" #define CONFIG_DEFAULT_LOG_DIR ".\\logs" #define CONFIG_DEFAULT_WEBROOT_DIR ".\\webroot" #define CONFIG_DEFAULT_ADMINROOT_DIR ".\\admin" +#define MIMETYPESFILE ".\\mime.types" #endif static ice_config_t _current_configuration; @@ -201,6 +203,7 @@ void config_clear(ice_config_t *c) if (c->master_password) xmlFree(c->master_password); if (c->user) xmlFree(c->user); if (c->group) xmlFree(c->group); + xmlFree (c->mimetypes_fn); thread_mutex_lock(&(_locks.relay_lock)); relay = c->relay; @@ -349,6 +352,7 @@ static void _set_defaults(ice_config_t *configuration) configuration->on_demand = 0; configuration->dir_list = NULL; configuration->hostname = CONFIG_DEFAULT_HOSTNAME; + configuration->mimetypes_fn = xmlCharStrdup (MIMETYPESFILE); configuration->port = 0; configuration->listeners[0].port = 0; configuration->listeners[0].bind_address = NULL; @@ -420,6 +424,9 @@ static void _parse_root(xmlDocPtr doc, xmlNodePtr node, } else if (strcmp(node->name, "hostname") == 0) { if (configuration->hostname && configuration->hostname != CONFIG_DEFAULT_HOSTNAME) xmlFree(configuration->hostname); configuration->hostname = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); + } else if (strcmp(node->name, "mime-types") == 0) { + if (configuration->mimetypes_fn) xmlFree(configuration->mimetypes_fn); + configuration->mimetypes_fn = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1); } else if (strcmp(node->name, "listen-socket") == 0) { _parse_listen_socket(doc, node->xmlChildrenNode, configuration); } else if (strcmp(node->name, "port") == 0) { diff --git a/src/cfgfile.h b/src/cfgfile.h index a32c9f35..6b7a414b 100644 --- a/src/cfgfile.h +++ b/src/cfgfile.h @@ -131,6 +131,7 @@ typedef struct ice_config_tag char *hostname; int port; + char *mimetypes_fn; listener_t listeners[MAX_LISTEN_SOCKETS]; diff --git a/src/event.c b/src/event.c index b1218844..b357540c 100644 --- a/src/event.c +++ b/src/event.c @@ -23,6 +23,7 @@ #include "client.h" #include "logging.h" #include "slave.h" +#include "fserve.h" #define CATMODULE "event" @@ -61,6 +62,7 @@ void event_config_read(void *arg) config_set_config(&new_config); restart_logging (config_get_config_unlocked()); yp_recheck_config (config_get_config_unlocked()); + fserve_recheck_mime_types (config_get_config_unlocked()); config_release_config(); slave_recheck_all(); diff --git a/src/fserve.c b/src/fserve.c index ba9ad34a..fbaf374f 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -60,12 +60,6 @@ #define BUFSIZE 4096 -#ifdef _WIN32 -#define MIMETYPESFILE ".\\mime.types" -#else -#define MIMETYPESFILE "/etc/mime.types" -#endif - static fserve_t *active_list = NULL; static volatile fserve_t *pending_list = NULL; @@ -92,14 +86,17 @@ typedef struct { static void fserve_client_destroy(fserve_t *fclient); static int _delete_mapping(void *mapping); static void *fserv_thread_function(void *arg); -static void create_mime_mappings(const char *fn); void fserve_initialize(void) { - create_mime_mappings(MIMETYPESFILE); + ice_config_t *config = config_get_config(); + mimetypes = NULL; thread_mutex_create (&pending_lock); + fserve_recheck_mime_types (config); + config_release_config(); + run_fserv = 1; stats_event (NULL, "file_connections", "0"); @@ -115,7 +112,8 @@ void fserve_shutdown(void) run_fserv = 0; thread_join(fserv_thread); INFO0("file serving thread stopped"); - avl_tree_free(mimetypes, _delete_mapping); + if (mimetypes) + avl_tree_free (mimetypes, _delete_mapping); } #ifdef HAVE_POLL @@ -312,38 +310,45 @@ static void *fserv_thread_function(void *arg) return NULL; } +/* string returned needs to be free'd */ char *fserve_content_type (const char *path) { char *ext = util_get_extension(path); mime_type exttype = {ext, NULL}; void *result; + char *type; - if (!avl_get_by_key (mimetypes, &exttype, &result)) + thread_mutex_lock (&pending_lock); + if (mimetypes && !avl_get_by_key (mimetypes, &exttype, &result)) { mime_type *mime = result; - return mime->type; + type = strdup (mime->type); } else { /* Fallbacks for a few basic ones */ if(!strcmp(ext, "ogg")) - return "application/ogg"; + type = strdup ("application/ogg"); else if(!strcmp(ext, "mp3")) - return "audio/mpeg"; + type = strdup ("audio/mpeg"); else if(!strcmp(ext, "html")) - return "text/html"; + type = strdup ("text/html"); else if(!strcmp(ext, "css")) - return "text/css"; + type = strdup ("text/css"); else if(!strcmp(ext, "txt")) - return "text/plain"; + type = strdup ("text/plain"); else if(!strcmp(ext, "jpg")) - return "image/jpeg"; + type = strdup ("image/jpeg"); else if(!strcmp(ext, "png")) - return "image/png"; + type = strdup ("image/png"); else if(!strcmp(ext, "m3u")) - return "audio/x-mpegurl"; + type = strdup ("audio/x-mpegurl"); + else if(!strcmp(ext, "aac")) + type = strdup ("audio/aac"); else - return "application/octet-stream"; + type = strdup ("application/octet-stream"); } + thread_mutex_unlock (&pending_lock); + return type; } static void fserve_client_destroy(fserve_t *fclient) @@ -524,6 +529,8 @@ int fserve_client_create (client_t *httpclient, const char *path) int strflen; struct tm result; int64_t endpos = rangenumber+new_content_len-1; + char *type; + if (endpos < 0) { endpos = 0; } @@ -531,6 +538,7 @@ int fserve_client_create (client_t *httpclient, const char *path) strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT", gmtime_r(&now, &result)); httpclient->respcode = 206; + type = fserve_content_type (path); bytes = snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.1 206 Partial Content\r\n" "Date: %s\r\n" @@ -543,7 +551,8 @@ int fserve_client_create (client_t *httpclient, const char *path) rangenumber, endpos, content_length, - fserve_content_type(path)); + type); + free (type); } else { goto fail; @@ -554,14 +563,15 @@ int fserve_client_create (client_t *httpclient, const char *path) } } else { - + char *type = fserve_content_type(path); httpclient->respcode = 200; bytes = snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.0 200 OK\r\n" "Content-Length: " FORMAT_INT64 "\r\n" "Content-Type: %s\r\n\r\n", content_length, - fserve_content_type(path)); + type); + free (type); } httpclient->refbuf->len = bytes; httpclient->pos = 0; @@ -649,20 +659,25 @@ static int _compare_mappings(void *arg, void *a, void *b) ((mime_type *)b)->ext); } -static void create_mime_mappings(const char *fn) { - FILE *mimefile = fopen(fn, "r"); +void fserve_recheck_mime_types (ice_config_t *config) +{ + FILE *mimefile; char line[4096]; char *type, *ext, *cur; mime_type *mapping; + avl_tree *new_mimetypes; - mimetypes = avl_tree_new(_compare_mappings, NULL); - + if (config->mimetypes_fn == NULL) + return; + mimefile = fopen (config->mimetypes_fn, "r"); if (mimefile == NULL) { - WARN1 ("Cannot open mime type file %s", fn); + WARN1 ("Cannot open mime types file %s", config->mimetypes_fn); return; } + new_mimetypes = avl_tree_new(_compare_mappings, NULL); + while(fgets(line, 4096, mimefile)) { line[4095] = 0; @@ -698,13 +713,18 @@ static void create_mime_mappings(const char *fn) { mapping = malloc(sizeof(mime_type)); mapping->ext = strdup(ext); mapping->type = strdup(type); - if(!avl_get_by_key(mimetypes, mapping, &tmp)) - avl_delete(mimetypes, mapping, _delete_mapping); - avl_insert(mimetypes, mapping); + if (!avl_get_by_key (new_mimetypes, mapping, &tmp)) + avl_delete (new_mimetypes, mapping, _delete_mapping); + avl_insert (new_mimetypes, mapping); } } } - fclose(mimefile); + + thread_mutex_lock (&pending_lock); + if (mimetypes) + avl_tree_free (mimetypes, _delete_mapping); + mimetypes = new_mimetypes; + thread_mutex_unlock (&pending_lock); } diff --git a/src/fserve.h b/src/fserve.h index 1b000915..a5035100 100644 --- a/src/fserve.h +++ b/src/fserve.h @@ -14,6 +14,7 @@ #define __FSERVE_H__ #include +#include "cfgfile.h" typedef void (*fserve_callback_t)(client_t *, void *); @@ -34,6 +35,7 @@ int fserve_client_create(client_t *httpclient, const char *path); int fserve_add_client (client_t *client, FILE *file); void fserve_add_client_callback (client_t *client, fserve_callback_t callback, void *arg); char *fserve_content_type (const char *path); +void fserve_recheck_mime_types (ice_config_t *config); #endif diff --git a/src/source.c b/src/source.c index ee29c27f..622546f3 100644 --- a/src/source.c +++ b/src/source.c @@ -1320,6 +1320,7 @@ static void *source_fallback_file (void *arg) parser = httpp_create_parser(); httpp_initialize (parser, NULL); httpp_setvar (parser, "content-type", type); + free (type); source->hidden = 1; source->yp_public = 0;