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

Feature: Generate errors based on IDs.

This generates error pages based on IDs. This allows to reuse errors
and add more advanced information to them.

This patch also makes Icecast send in plain text OR HTML based
on the clients Accept:-string.
parent b6cd41ea
......@@ -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 \
......
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2012-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2012-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
#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;
}
......
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2013-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2013-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/**
......@@ -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;
}
......
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/* 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;
......
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/* 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);
......
......@@ -9,7 +9,7 @@
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011, Dave 'justdave' Miller <justdave@mozilla.com>,
* Copyright 2011-2014, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/* -*- 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) {
......
/* 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>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#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;
}
/* 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 __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__ */
......@@ -8,7 +8,7 @@
* oddsock <oddsock@xiph.org>,
* Karl Heyes <karl@xiph.org>
* and others (see AUTHORS for details).
* Copyright 2011, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>.
* Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>.
*/
#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;