diff --git a/src/Makefile.am b/src/Makefile.am index 0f677d26..e7ea542e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ SUBDIRS = common/avl common/net common/thread common/httpp common/log common/tim bin_PROGRAMS = icecast noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ - global.h util.h curl.h slave.h source.h stats.h refbuf.h client.h playlist.h \ + global.h util.h errors.h curl.h slave.h source.h stats.h refbuf.h client.h playlist.h \ compat.h fserve.h xslt.h yp.h md5.h matchfile.h tls.h \ event.h event_log.h event_exec.h event_url.h \ acl.h auth.h \ @@ -15,7 +15,7 @@ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ format_vorbis.h format_theora.h format_flac.h format_speex.h format_midi.h \ format_kate.h format_skeleton.h format_opus.h icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \ - util.c slave.c source.c stats.c refbuf.c client.c playlist.c \ + util.c errors.c slave.c source.c stats.c refbuf.c client.c playlist.c \ xslt.c fserve.c admin.c md5.c matchfile.c tls.c \ format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \ format_kate.c format_skeleton.c format_opus.c \ diff --git a/src/admin.c b/src/admin.c index a1ea26cd..135a39ea 100644 --- a/src/admin.c +++ b/src/admin.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2012-2018, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H @@ -34,6 +34,7 @@ #include "xslt.h" #include "fserve.h" #include "admin.h" +#include "errors.h" #include "format.h" @@ -50,7 +51,7 @@ do { \ (var) = httpp_get_query_param((client)->parser, (name)); \ if((var) == NULL) { \ - client_send_error((client), 400, 0, "Missing parameter"); \ + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_MISSING_PARAMETER); \ return; \ } \ } while(0); @@ -283,7 +284,7 @@ void admin_send_response(xmlDocPtr doc, NULL, NULL, client); if (ret < 0) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); xmlFree(buff); return; } else if (buf_len < (size_t)(len + ret + 64)) { @@ -300,13 +301,13 @@ void admin_send_response(xmlDocPtr doc, NULL, NULL, client); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + 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(client, 500, 0, "Buffer reallocation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_BUFFER_REALLOC); xmlFree(buff); return; } @@ -352,7 +353,7 @@ void admin_handle_request(client_t *client, const char *uri) if (handler == NULL) { ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %H", uri); - client_send_error(client, 400, 0, "Unrecognised command"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND); return; } @@ -366,7 +367,7 @@ void admin_handle_request(client_t *client, const char *uri) ICECAST_LOG_DEBUG("Granted right to call COMMAND_RAW_METADATA_UPDATE to " "client because it is allowed to do SOURCE or PUT."); } else { - client_send_error(client, 401, 1, "You need to authenticate\r\n"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); return; } } @@ -385,14 +386,14 @@ void admin_handle_request(client_t *client, const char *uri) avl_tree_unlock(global.source_tree); ICECAST_LOG_WARN("Admin command \"%H\" on non-existent source \"%H\"", uri, mount); - client_send_error(client, 400, 0, "Source does not exist"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_SOURCE_DOES_NOT_EXIST); return; } /* No Source running */ else if (source->running == 0 && source->on_demand == 0) { avl_tree_unlock(global.source_tree); ICECAST_LOG_INFO("Received admin command \"%H\" on unavailable mount \"%H\"", uri, mount); - client_send_error(client, 400, 0, "Source is not available"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_SOURCE_IS_NOT_AVAILABLE); return; } ICECAST_LOG_INFO("Received admin command %H on mount '%s'", @@ -400,7 +401,7 @@ void admin_handle_request(client_t *client, const char *uri) } if (handler->type == ADMINTYPE_MOUNT && !source) { - client_send_error(client, 400, 0, "Mount parameter mandatory"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_MISSING_PARAMETER); return; } @@ -422,7 +423,7 @@ static void html_success(client_t *client, char *message) if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); return; } @@ -463,17 +464,17 @@ static void command_move_clients(client_t *client, dest = source_find_mount(dest_source); if (dest == NULL) { - client_send_error(client, 400, 0, "No such destination"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_NO_SUCH_DESTINATION); return; } if (strcmp(dest->mount, source->mount) == 0) { - client_send_error(client, 400, 0, "supplied mountpoints are identical"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_SUPPLIED_MOUNTPOINTS_ARE_IDENTICAL); return; } if (dest->running == 0 && dest->on_demand == 0) { - client_send_error(client, 400, 0, "Destination not running"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_DEST_NOT_RUNNING); return; } @@ -611,7 +612,7 @@ static void command_buildm3u(client_t *client, source_t *source, int format) if (ret == -1 || ret >= (PER_CLIENT_REFBUF_SIZE - 512)) { /* we want at least 512 Byte left for data */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); return; } @@ -664,8 +665,7 @@ static void command_manageauth(client_t *client, source_t *source, int response) const char *idstring = NULL; char *message = NULL; int ret = AUTH_OK; - int error_code = 400; - const char *error_message = "missing parameter"; + int error_id = ICECAST_ERROR_ADMIN_missing_parameter; long unsigned int id; ice_config_t *config = config_get_config(); auth_t *auth; @@ -692,8 +692,7 @@ static void command_manageauth(client_t *client, source_t *source, int response) /* check if we found one */ if (auth == NULL) { ICECAST_LOG_WARN("Client requested mangement for unknown role %lu", id); - error_code = 404; - error_message = "Role not found"; + error_id = ICECAST_ERROR_ADMIN_ROLEMGN_ROLE_NOT_FOUND; break; } @@ -713,7 +712,7 @@ static void command_manageauth(client_t *client, source_t *source, int response) } if (!auth->adduser) { - error_message = "Adding users to role not supported by role"; + error_id = ICECAST_ERROR_ADMIN_ROLEMGN_ADD_NOSYS; break; } @@ -733,7 +732,7 @@ static void command_manageauth(client_t *client, source_t *source, int response) } if (!auth->deleteuser) { - error_message = "Deleting users from role not supported by role"; + error_id = ICECAST_ERROR_ADMIN_ROLEMGN_DELETE_NOSYS; break; } @@ -774,7 +773,7 @@ static void command_manageauth(client_t *client, source_t *source, int response) config_release_config(); auth_release(auth); - client_send_error(client, error_code, 0, error_message); + client_send_error_by_id(client, error_id); } static void command_kill_source(client_t *client, @@ -944,7 +943,7 @@ static void command_shoutcast_metadata(client_t *client, if (source->shoutcast_compat == 0) { ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast " "compatible stream"); - client_send_error(client, 400, 0, "illegal metadata call"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_METADAT_BADCALL); return; } @@ -957,7 +956,7 @@ static void command_shoutcast_metadata(client_t *client, COMMAND_REQUIRE(client, "song", value); if (strcmp (action, "updinfo") != 0) { - client_send_error(client, 400, 0, "No such action"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_METADAT_NO_SUCH_ACTION); return; } if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) @@ -972,7 +971,7 @@ static void command_shoutcast_metadata(client_t *client, source->mount, value); html_success(client, "Metadata update successful"); } else { - client_send_error(client, 400, 0, "mountpoint will not accept URL updates"); + client_send_error_by_id(client, ICECAST_ERROR_ADMIN_MOUNT_NOT_ACCEPT_URL_UPDATES); } } @@ -1022,7 +1021,7 @@ static void command_list_mounts(client_t *client, source_t *source, int response if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); return; } diff --git a/src/auth.c b/src/auth.c index 47427560..fbff604a 100644 --- a/src/auth.c +++ b/src/auth.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2013-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2013-2018, Philipp "ph3-der-loewe" Schafft , */ /** @@ -27,6 +27,7 @@ #include "auth.h" #include "source.h" #include "client.h" +#include "errors.h" #include "cfgfile.h" #include "stats.h" #include "common/httpp/httpp.h" @@ -373,7 +374,7 @@ static void auth_add_client(auth_t *auth, client_t *client, void (*on_no_match)( /* TODO: replace that magic number */ if (auth->pending_count > 100) { ICECAST_LOG_WARN("too many clients awaiting authentication on auth %p", auth); - client_send_error(client, 403, 1, "busy, please try again later"); + client_send_error_by_id(client, ICECAST_ERROR_AUTH_BUSY); return; } diff --git a/src/client.c b/src/client.c index da95c589..18e8deb1 100644 --- a/src/client.c +++ b/src/client.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , */ /* client.c @@ -34,6 +34,7 @@ #include "format.h" #include "stats.h" #include "fserve.h" +#include "errors.h" #include "client.h" #include "auth.h" @@ -214,7 +215,7 @@ int client_read_bytes(client_t *client, void *buf, unsigned len) return bytes; } -void client_send_error(client_t *client, int status, int plain, const char *message) +static inline void _client_send_error(client_t *client, int status, int plain, const char *message) { ssize_t ret; refbuf_t *data; @@ -264,6 +265,30 @@ void client_send_error(client_t *client, int status, int plain, const char *mess fserve_add_client (client, NULL); } +void client_send_error_by_id(client_t *client, int id) +{ + const icecast_error_t *error = error_get_by_id(id); + const char *pref; + int plain; + + if (!error) { + client_send_500(client, "Unknown error ID"); + return; + } + + pref = util_http_select_best(httpp_getvar(client->parser, "accept"), "text/plain", "text/html", (const char*)NULL); + + if (strcmp(pref, "text/plain") == 0) { + plain = 1; + } else if (strcmp(pref, "text/html") == 0) { + plain = 0; + } else { + plain = 1; + } + + _client_send_error(client, error->http_status, plain, error->message); +} + void client_send_101(client_t *client, reuse_t reuse) { ssize_t ret; diff --git a/src/client.h b/src/client.h index 2f2a3259..2cdc67f9 100644 --- a/src/client.h +++ b/src/client.h @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , */ /* client.h @@ -109,7 +109,7 @@ typedef struct _client_tag int client_create (client_t **c_ptr, connection_t *con, http_parser_t *parser); void client_destroy(client_t *client); -void client_send_error(client_t *client, int status, int plain, const char *message); +void client_send_error_by_id(client_t *client, int id); void client_send_101(client_t *client, reuse_t reuse); void client_send_426(client_t *client, reuse_t reuse); int client_send_bytes (client_t *client, const void *buf, unsigned len); diff --git a/src/connection.c b/src/connection.c index 98a96b72..8568cc26 100644 --- a/src/connection.c +++ b/src/connection.c @@ -9,7 +9,7 @@ * Karl Heyes * and others (see AUTHORS for details). * Copyright 2011, Dave 'justdave' Miller , - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ @@ -46,6 +46,7 @@ #include "connection.h" #include "refbuf.h" #include "client.h" +#include "errors.h" #include "stats.h" #include "logging.h" #include "xslt.h" @@ -575,7 +576,7 @@ void connection_queue(connection_t *con) global_lock(); if (client_create(&client, con, NULL) < 0) { global_unlock(); - client_send_error(client, 403, 1, "Icecast connection limit reached"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_LIMIT); /* don't be too eager as this is an imposed hard limit */ thread_sleep(400000); return; @@ -659,7 +660,7 @@ int connection_complete_source(source_t *source, int response) config_release_config(); global_unlock(); if (response) { - client_send_error(source->client, 403, 1, "Content-type not supported"); + client_send_error_by_id(source->client, ICECAST_ERROR_CON_CONTENT_TYPE_NOSYS); source->client = NULL; } ICECAST_LOG_WARN("Content-type \"%s\" not supported, dropping source", contenttype); @@ -669,7 +670,7 @@ int connection_complete_source(source_t *source, int response) config_release_config(); global_unlock(); if (response) { - client_send_error(source->client, 403, 1, "No Content-type given"); + client_send_error_by_id(source->client, ICECAST_ERROR_CON_NO_CONTENT_TYPE_GIVEN); source->client = NULL; } ICECAST_LOG_ERROR("Content-type not given in PUT request, dropping source"); @@ -685,7 +686,7 @@ int connection_complete_source(source_t *source, int response) global_unlock(); config_release_config(); if (response) { - client_send_error(source->client, 403, 1, "internal format allocation problem"); + client_send_error_by_id(source->client, ICECAST_ERROR_CON_INTERNAL_FORMAT_ALLOC_ERROR); source->client = NULL; } ICECAST_LOG_WARN("plugin format failed for \"%s\"", source->mount); @@ -714,7 +715,7 @@ int connection_complete_source(source_t *source, int response) config_release_config(); if (response) { - client_send_error(source->client, 403, 1, "too many sources connected"); + client_send_error_by_id(source->client, ICECAST_ERROR_CON_SOURCE_CLIENT_LIMIT); source->client = NULL; } @@ -754,7 +755,7 @@ static inline void source_startup(client_t *client, const char *uri) if (transfer_encoding && strcasecmp(transfer_encoding, HTTPP_ENCODING_IDENTITY) != 0) { client->encoding = httpp_encoding_new(transfer_encoding); if (!client->encoding) { - client_send_error(client, 501, 1, "Unimplemented"); + client_send_error_by_id(client, ICECAST_ERROR_CON_UNIMPLEMENTED); return; } } @@ -784,7 +785,7 @@ static inline void source_startup(client_t *client, const char *uri) fserve_add_client_callback(client, source_client_callback, source); } } else { - client_send_error(client, 403, 1, "Mountpoint in use"); + client_send_error_by_id(client, ICECAST_ERROR_CON_MOUNT_IN_USE); ICECAST_LOG_WARN("Mountpoint %s in use", uri); } } @@ -797,7 +798,7 @@ static void _handle_source_request(client_t *client, const char *uri) if (uri[0] != '/') { ICECAST_LOG_WARN("source mountpoint not starting with /"); - client_send_error(client, 400, 1, "source mountpoint not starting with /"); + client_send_error_by_id(client, ICECAST_ERROR_CON_MOUNTPOINT_NOT_STARTING_WITH_SLASH); return; } @@ -932,7 +933,7 @@ static void _handle_get_request(client_t *client, char *uri) { if (client->protocol == ICECAST_PROTOCOL_SHOUTCAST) { client_destroy(client); } else { - client_send_error(client, 401, 1, "You need to authenticate\r\n"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); } return; } @@ -954,8 +955,7 @@ static void _handle_get_request(client_t *client, char *uri) { /* check for duplicate_logins */ if (max_connections_per_user > 0) { /* -1 = not set (-> default=unlimited), 0 = unlimited */ if (max_connections_per_user <= __count_user_role_on_mount(source, client)) { - client_send_error(client, 403, 1, "Reached limit of concurrent " - "connections on those credentials"); + client_send_error_by_id(client, ICECAST_ERROR_CON_PER_CRED_CLIENT_LIMIT); in_error = 1; } } @@ -976,7 +976,7 @@ static void _handle_get_request(client_t *client, char *uri) { client->con->discon_time = connection_duration + time(NULL); } if (!in_error && __add_listener_to_source(source, client) == -1) { - client_send_error(client, 403, 1, "Rejecting client for whatever reason"); + client_send_error_by_id(client, ICECAST_ERROR_CON_rejecting_client_for_whatever_reason); } avl_tree_unlock(global.source_tree); } else { @@ -1143,14 +1143,14 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul client->authstack = NULL; if (result != AUTH_OK) { - client_send_error(client, 401, 1, "You need to authenticate\r\n"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); free(uri); return; } if (acl_test_method(client->acl, client->parser->req_type) != ACL_POLICY_ALLOW) { ICECAST_LOG_ERROR("Client (role=%s, username=%s) not allowed to use this request method on %H", client->role, client->username, uri); - client_send_error(client, 401, 1, "You need to authenticate\r\n"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE); free(uri); return; } @@ -1168,7 +1168,7 @@ static void _handle_authed_client(client_t *client, void *uri, auth_result resul break; default: ICECAST_LOG_ERROR("Wrong request type from client"); - client_send_error(client, 400, 0, "unknown request"); + client_send_error_by_id(client, ICECAST_ERROR_CON_UNKNOWN_REQUEST); break; } @@ -1357,7 +1357,7 @@ static void _handle_connection(void) connection = httpp_getvar(parser, "connection"); if (upgrade && connection && strcasecmp(connection, "upgrade") == 0) { if (client->con->tlsmode == ICECAST_TLSMODE_DISABLED || strstr(upgrade, "TLS/1.0") == NULL) { - client_send_error(client, 400, 1, "Can not upgrade protocol"); + client_send_error_by_id(client, ICECAST_ERROR_CON_UPGRADE_ERROR); continue; } else { client_send_101(client, ICECAST_REUSE_UPGRADETLS); @@ -1386,7 +1386,7 @@ static void _handle_connection(void) client->admin_command = admin_get_command(uri + 1); __prepare_shoutcast_admin_cgi_request(client); if (!client->password) { - client_send_error(client, 400, 0, "missing pass parameter"); + client_send_error_by_id(client, ICECAST_ERROR_CON_MISSING_PASS_PARAMETER); continue; } } else if (strncmp("/admin/", uri, 7) == 0) { diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 00000000..1a86973e --- /dev/null +++ b/src/errors.c @@ -0,0 +1,110 @@ +/* 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 + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "errors.h" +#include "logging.h" +#define CATMODULE "errors" + +// cut -d' ' -f2 x | while read x; do printf " {.id = %-60s .http_status = xxx,\n .message = \"\"},\n" "$x",; done +const icecast_error_t __errors[] = { + {.id = ICECAST_ERROR_ADMIN_DEST_NOT_RUNNING, .http_status = 400, + .message = "Destination not running"}, + {.id = ICECAST_ERROR_ADMIN_METADAT_BADCALL, .http_status = 400, + .message = "illegal metadata call"}, + {.id = ICECAST_ERROR_ADMIN_METADAT_NO_SUCH_ACTION, .http_status = 501, + .message = "No such action"}, + {.id = ICECAST_ERROR_ADMIN_MISSING_PARAMETER, .http_status = 400, + .message = "Missing parameter"}, + {.id = ICECAST_ERROR_ADMIN_missing_parameter, .http_status = 400, + .message = "missing parameter"}, + {.id = ICECAST_ERROR_ADMIN_MOUNT_NOT_ACCEPT_URL_UPDATES, .http_status = 501, + .message = "mountpoint will not accept URL updates"}, + {.id = ICECAST_ERROR_ADMIN_NO_SUCH_DESTINATION, .http_status = 404, + .message = "No such destination"}, + {.id = ICECAST_ERROR_ADMIN_ROLEMGN_ADD_NOSYS, .http_status = 501, + .message = "Adding users to role not supported by role"}, + {.id = ICECAST_ERROR_ADMIN_ROLEMGN_DELETE_NOSYS, .http_status = 501, + .message = "Deleting users from role not supported by role"}, + {.id = ICECAST_ERROR_ADMIN_ROLEMGN_ROLE_NOT_FOUND, .http_status = 404, + .message = "Role not found"}, + {.id = ICECAST_ERROR_ADMIN_SOURCE_DOES_NOT_EXIST, .http_status = 404, + .message = "Source does not exist"}, + {.id = ICECAST_ERROR_ADMIN_SOURCE_IS_NOT_AVAILABLE, .http_status = 400, + .message = "Source is not available"}, + {.id = ICECAST_ERROR_ADMIN_SUPPLIED_MOUNTPOINTS_ARE_IDENTICAL, .http_status = 400, + .message = "supplied mountpoints are identical"}, + {.id = ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND, .http_status = 400, + .message = "unrecognised command"}, + {.id = ICECAST_ERROR_AUTH_BUSY, .http_status = 503, + .message = "busy, please try again later"}, + {.id = ICECAST_ERROR_CON_CONTENT_TYPE_NOSYS, .http_status = 415, + .message = "Content-type not supported"}, + {.id = ICECAST_ERROR_CON_INTERNAL_FORMAT_ALLOC_ERROR, .http_status = 500, + .message = "internal format allocation problem"}, + {.id = ICECAST_ERROR_CON_MISSING_PASS_PARAMETER, .http_status = 400 /* XXX */, + .message = "missing pass parameter"}, + {.id = ICECAST_ERROR_CON_MOUNT_IN_USE, .http_status = 409, + .message = "Mountpoint in use"}, + {.id = ICECAST_ERROR_CON_MOUNTPOINT_NOT_STARTING_WITH_SLASH, .http_status = 400, + .message = "source mountpoint not starting with /"}, + {.id = ICECAST_ERROR_CON_NO_CONTENT_TYPE_GIVEN, .http_status = 400, + .message = "No Content-type given"}, + {.id = ICECAST_ERROR_CON_PER_CRED_CLIENT_LIMIT, .http_status = 429, + .message = "Reached limit of concurrent connections on those credentials"}, + {.id = ICECAST_ERROR_CON_rejecting_client_for_whatever_reason, .http_status = 403 /* XXX */, + .message = "Rejecting client for whatever reason"}, + {.id = ICECAST_ERROR_CON_SOURCE_CLIENT_LIMIT, .http_status = 503, + .message = "too many sources connected"}, + {.id = ICECAST_ERROR_CON_UNIMPLEMENTED, .http_status = 501, + .message = "Unimplemented"}, + {.id = ICECAST_ERROR_CON_UNKNOWN_REQUEST, .http_status = 405, + .message = "unknown request"}, + {.id = ICECAST_ERROR_CON_UPGRADE_ERROR, .http_status = 400 /* XXX */, + .message = "Can not upgrade protocol"}, + {.id = ICECAST_ERROR_FSERV_FILE_NOT_FOUND, .http_status = 404, + .message = "The file you requested could not be found"}, + {.id = ICECAST_ERROR_FSERV_FILE_NOT_READABLE, .http_status = 404 /* XXX */, + .message = "File not readable"}, + {.id = ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE, .http_status = 416, + .message = "Request Range Not Satisfiable"}, + {.id = ICECAST_ERROR_GEN_BUFFER_REALLOC, .http_status = 500, + .message = "Buffer reallocation failed."}, + {.id = ICECAST_ERROR_GEN_CLIENT_LIMIT, .http_status = 503, + .message = "Icecast connection limit reached"}, + {.id = ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE, .http_status = 401, + .message = "You need to authenticate"}, + {.id = ICECAST_ERROR_GEN_HEADER_GEN_FAILED, .http_status = 500, + .message = "Header generation failed."}, + {.id = ICECAST_ERROR_GEN_MEMORY_EXHAUSTED, .http_status = 503, + .message = "memory exhausted"}, + {.id = ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE, .http_status = 404 /* XXX */, + .message = "Mount unavailable"}, + {.id = ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR, .http_status = 500 /* XXX */, + .message = "Stream preparation error"}, + {.id = ICECAST_ERROR_XSLT_PARSE, .http_status = 404 /* XXX */, + .message = "Could not parse XSLT file"}, + {.id = ICECAST_ERROR_XSLT_problem, .http_status = 500, + .message = "XSLT problem"} +}; + +const icecast_error_t * error_get_by_id(int id) { + size_t i; + + for (i = 0; i < (sizeof(__errors)/sizeof(*__errors)); i++) { + if (__errors[i].id == id) { + return &(__errors[i]); + } + } + + return NULL; +} + diff --git a/src/errors.h b/src/errors.h new file mode 100644 index 00000000..472f5950 --- /dev/null +++ b/src/errors.h @@ -0,0 +1,62 @@ +/* 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 + */ + +#ifndef __ERRORS_H__ +#define __ERRORS_H__ + +#define ICECAST_ERROR_ADMIN_DEST_NOT_RUNNING 1 +#define ICECAST_ERROR_ADMIN_METADAT_BADCALL 2 +#define ICECAST_ERROR_ADMIN_METADAT_NO_SUCH_ACTION 3 +#define ICECAST_ERROR_ADMIN_MISSING_PARAMETER 4 +#define ICECAST_ERROR_ADMIN_missing_parameter 5 /* what is this? */ +#define ICECAST_ERROR_ADMIN_MOUNT_NOT_ACCEPT_URL_UPDATES 6 +#define ICECAST_ERROR_ADMIN_NO_SUCH_DESTINATION 7 +#define ICECAST_ERROR_ADMIN_ROLEMGN_ADD_NOSYS 8 +#define ICECAST_ERROR_ADMIN_ROLEMGN_DELETE_NOSYS 9 +#define ICECAST_ERROR_ADMIN_ROLEMGN_ROLE_NOT_FOUND 10 +#define ICECAST_ERROR_ADMIN_SOURCE_DOES_NOT_EXIST 11 +#define ICECAST_ERROR_ADMIN_SOURCE_IS_NOT_AVAILABLE 12 +#define ICECAST_ERROR_ADMIN_SUPPLIED_MOUNTPOINTS_ARE_IDENTICAL 13 +#define ICECAST_ERROR_ADMIN_UNRECOGNISED_COMMAND 14 +#define ICECAST_ERROR_AUTH_BUSY 15 +#define ICECAST_ERROR_CON_CONTENT_TYPE_NOSYS 16 +#define ICECAST_ERROR_CON_INTERNAL_FORMAT_ALLOC_ERROR 17 +#define ICECAST_ERROR_CON_MISSING_PASS_PARAMETER 18 +#define ICECAST_ERROR_CON_MOUNT_IN_USE 19 +#define ICECAST_ERROR_CON_MOUNTPOINT_NOT_STARTING_WITH_SLASH 20 +#define ICECAST_ERROR_CON_NO_CONTENT_TYPE_GIVEN 21 +#define ICECAST_ERROR_CON_PER_CRED_CLIENT_LIMIT 22 +#define ICECAST_ERROR_CON_rejecting_client_for_whatever_reason 23 /* ??? */ +#define ICECAST_ERROR_CON_SOURCE_CLIENT_LIMIT 24 +#define ICECAST_ERROR_CON_UNIMPLEMENTED 25 +#define ICECAST_ERROR_CON_UNKNOWN_REQUEST 26 +#define ICECAST_ERROR_CON_UPGRADE_ERROR 27 +#define ICECAST_ERROR_FSERV_FILE_NOT_FOUND 28 +#define ICECAST_ERROR_FSERV_FILE_NOT_READABLE 29 +#define ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE 30 +#define ICECAST_ERROR_GEN_BUFFER_REALLOC 31 +#define ICECAST_ERROR_GEN_CLIENT_LIMIT 32 +#define ICECAST_ERROR_GEN_CLIENT_NEEDS_TO_AUTHENTICATE 33 +#define ICECAST_ERROR_GEN_HEADER_GEN_FAILED 34 +#define ICECAST_ERROR_GEN_MEMORY_EXHAUSTED 35 +#define ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE 36 +#define ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR 37 +#define ICECAST_ERROR_XSLT_PARSE 38 +#define ICECAST_ERROR_XSLT_problem 39 + +struct icecast_error_tag { + const int id; + const int http_status; + const char *message; +}; + +typedef struct icecast_error_tag icecast_error_t; + +const icecast_error_t * error_get_by_id(int id); + +#endif /* __ERRORS_H__ */ diff --git a/src/fserve.c b/src/fserve.c index 94a6e961..02a1bc25 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2011, Philipp "ph3-der-loewe" Schafft . + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft . */ #ifdef HAVE_CONFIG_H @@ -51,6 +51,7 @@ #include "global.h" #include "refbuf.h" #include "client.h" +#include "errors.h" #include "stats.h" #include "format.h" #include "logging.h" @@ -440,7 +441,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (m3u_requested == 0 && xslt_playlist_requested == NULL) { ICECAST_LOG_WARN("req for file \"%H\" %s", fullpath, strerror (errno)); - client_send_error(httpclient, 404, 0, "The file you requested could not be found"); + client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); free (fullpath); return -1; } @@ -469,7 +470,7 @@ int fserve_client_create (client_t *httpclient, const char *path) "audio/x-mpegurl", NULL, "", NULL, httpclient); if (ret == -1 || ret >= (BUFSIZE - 512)) { /* we want at least 512 bytes left for the content of the playlist */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(httpclient, 500, 0, "Header generation failed."); + client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); free(sourceuri); return -1; } @@ -517,7 +518,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (config->fileserve == 0) { ICECAST_LOG_DEBUG("on demand file \"%H\" refused. Serving static files has been disabled in the config", fullpath); - client_send_error(httpclient, 404, 0, "The file you requested could not be found"); + client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); config_release_config(); free(fullpath); return -1; @@ -526,7 +527,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (S_ISREG (file_buf.st_mode) == 0) { - client_send_error(httpclient, 404, 0, "The file you requested could not be found"); + client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); ICECAST_LOG_WARN("found requested file but there is no handler for it: %H", fullpath); free (fullpath); return -1; @@ -536,7 +537,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (file == NULL) { ICECAST_LOG_WARN("Problem accessing file \"%H\"", fullpath); - client_send_error(httpclient, 404, 0, "File not readable"); + client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_READABLE); free (fullpath); return -1; } @@ -585,7 +586,7 @@ int fserve_client_create (client_t *httpclient, const char *path) NULL, NULL, httpclient); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(httpclient, 500, 0, "Header generation failed."); + client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, @@ -616,7 +617,7 @@ int fserve_client_create (client_t *httpclient, const char *path) NULL, NULL, httpclient); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(httpclient, 500, 0, "Header generation failed."); + client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); fclose(file); return -1; } @@ -636,7 +637,7 @@ int fserve_client_create (client_t *httpclient, const char *path) fail: fclose (file); - client_send_error(httpclient, 416, 1, "Request Range Not Satisfiable\r\n"); + client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE); return -1; } @@ -669,7 +670,7 @@ int fserve_add_client (client_t *client, FILE *file) ICECAST_LOG_DEBUG("Adding client %p to file serving engine", client); if (fclient == NULL) { - client_send_error(client, 404, 0, "memory exhausted"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_MEMORY_EXHAUSTED); return -1; } fclient->file = file; @@ -691,7 +692,7 @@ void fserve_add_client_callback (client_t *client, fserve_callback_t callback, v ICECAST_LOG_DEBUG("Adding client to file serving engine"); if (fclient == NULL) { - client_send_error(client, 404, 0, "memory exhausted"); + client_send_error_by_id(client, ICECAST_ERROR_GEN_MEMORY_EXHAUSTED); return; } fclient->file = NULL; diff --git a/src/main.c b/src/main.c index 27b688f3..7ee01a5a 100644 --- a/src/main.c +++ b/src/main.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes , * and others (see AUTHORS for details). - * Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft , * Copyright 2014, Thomas B. Ruecker . */ diff --git a/src/source.c b/src/source.c index b4a6f265..b7ace96a 100644 --- a/src/source.c +++ b/src/source.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft , + * Copyright 2012-2018, Philipp "ph3-der-loewe" Schafft , */ /* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */ @@ -48,6 +48,7 @@ #include "global.h" #include "refbuf.h" #include "client.h" +#include "errors.h" #include "stats.h" #include "logging.h" #include "cfgfile.h" @@ -961,10 +962,10 @@ static int _free_client(void *key) switch (client->respcode) { case 0: /* if no response has been sent then send a 404 */ - client_send_error(client, 404, 0, "Mount unavailable"); + client_send_error_by_id(client, ICECAST_ERROR_SOURCE_MOUNT_UNAVAILABLE); break; case 500: - client_send_error(client, 500, 0, "Stream preparation error"); + client_send_error_by_id(client, ICECAST_ERROR_SOURCE_STREAM_PREPARATION_ERROR); break; default: client_destroy(client); diff --git a/src/util.c b/src/util.c index d815edf5..a8c6e7a2 100644 --- a/src/util.c +++ b/src/util.c @@ -5,7 +5,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2012-2015 Philipp "ph3-der-loewe" Schafft + * Copyright 2012-2018 Philipp "ph3-der-loewe" Schafft * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. @@ -819,13 +819,10 @@ static inline void __free_args(struct __args *arg, size_t len) size_t i; for (i = 0; i < len; i++) { - free(arg->group); + free(arg[i].group); } } - // Accept: text/html, application/xhtml+xml, */* - // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - static inline int __parse_q(const char *str) { int ret = 0; diff --git a/src/util.h b/src/util.h index 469aca72..cdc30fbe 100644 --- a/src/util.h +++ b/src/util.h @@ -5,7 +5,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2012-2015 Philipp "ph3-der-loewe" Schafft + * Copyright 2012-2018 Philipp "ph3-der-loewe" Schafft * * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. diff --git a/src/xslt.c b/src/xslt.c index 2e6797a5..09af35b4 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -8,6 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). + * Copyright 2012-2018, Philipp "ph3-der-loewe" Schafft , */ #ifdef HAVE_CONFIG_H @@ -50,6 +51,7 @@ #include "global.h" #include "refbuf.h" #include "client.h" +#include "errors.h" #include "config.h" #include "stats.h" #include "fserve.h" @@ -306,7 +308,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(client, 404, 0, "Could not parse XSLT file"); + client_send_error_by_id(client, ICECAST_ERROR_XSLT_PARSE); return; } @@ -350,7 +352,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL, client); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); } else { if ( full_len < (ret + (ssize_t)len + (ssize_t)64) ) { void *new_data; @@ -363,12 +365,12 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL, client); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_error(client, 500, 0, "Header generation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); failed = 1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); - client_send_error(client, 500, 0, "Buffer reallocation failed."); + client_send_error_by_id(client, ICECAST_ERROR_GEN_BUFFER_REALLOC); failed = 1; } } @@ -388,7 +390,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) else { ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename); - client_send_error(client, 404, 0, "XSLT problem"); + client_send_error_by_id(client, ICECAST_ERROR_XSLT_problem); } thread_mutex_unlock (&xsltlock); xmlFreeDoc(res);