diff --git a/src/admin.c b/src/admin.c index e36dc4e3..56f6e64f 100644 --- a/src/admin.c +++ b/src/admin.c @@ -295,7 +295,7 @@ void admin_send_response (xmlDocPtr doc, client_t *client, NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); xmlFree(buff); return; } else if (buf_len < (len + ret + 64)) { @@ -312,13 +312,13 @@ void admin_send_response (xmlDocPtr doc, client_t *client, NULL, NULL); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); xmlFree(buff); return; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); - client_send_500(client, "Buffer reallocation failed."); + client_send_error(client, 500, 0, "Buffer reallocation failed."); xmlFree(buff); return; } @@ -361,7 +361,7 @@ void admin_handle_request(client_t *client, const char *uri) if (!((strcmp(uri, "/admin.cgi") == 0) || (strncmp("/admin/", uri, 7) == 0))) { ICECAST_LOG_ERROR("Internal error: admin request isn't"); - client_send_401(client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); return; } @@ -378,7 +378,7 @@ void admin_handle_request(client_t *client, const char *uri) if(command < 0) { ICECAST_LOG_ERROR("Error parsing command string or unrecognised command: %s", command_string); - client_send_400(client, "Unrecognised command"); + client_send_error(client, 400, 0, "Unrecognised command"); return; } @@ -391,7 +391,7 @@ void admin_handle_request(client_t *client, const char *uri) if (pass == NULL) { - client_send_400 (client, "missing pass parameter"); + client_send_error(client, 400, 0, "missing pass parameter"); return; } global_lock(); @@ -430,7 +430,7 @@ void admin_handle_request(client_t *client, const char *uri) default: ICECAST_LOG_INFO("Bad or missing password on mount modification admin " "request (command: %s)", command_string); - client_send_401(client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); /* fall through */ case 1: return; @@ -445,7 +445,7 @@ void admin_handle_request(client_t *client, const char *uri) ICECAST_LOG_WARN("Admin command %s on non-existent source %s", command_string, mount); avl_tree_unlock(global.source_tree); - client_send_400(client, "Source does not exist"); + client_send_error(client, 400, 0, "Source does not exist"); } else { @@ -454,7 +454,7 @@ void admin_handle_request(client_t *client, const char *uri) avl_tree_unlock (global.source_tree); ICECAST_LOG_INFO("Received admin command %s on unavailable mount \"%s\"", command_string, mount); - client_send_400 (client, "Source is not available"); + client_send_error(client, 400, 0, "Source is not available"); return; } if (command == COMMAND_SHOUTCAST_METADATA_UPDATE && @@ -463,7 +463,7 @@ void admin_handle_request(client_t *client, const char *uri) avl_tree_unlock (global.source_tree); ICECAST_LOG_ERROR("illegal change of metadata on non-shoutcast " "compatible stream"); - client_send_400 (client, "illegal metadata call"); + client_send_error(client, 400, 0, "illegal metadata call"); return; } ICECAST_LOG_INFO("Received admin command %s on mount \"%s\"", @@ -481,7 +481,7 @@ void admin_handle_request(client_t *client, const char *uri) if(!connection_check_relay_pass(client->parser)) { ICECAST_LOG_INFO("Bad or missing password on admin command " "request (command: %s)", command_string); - client_send_401(client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); return; } } @@ -489,7 +489,7 @@ void admin_handle_request(client_t *client, const char *uri) if(!connection_check_admin_pass(client->parser)) { ICECAST_LOG_INFO("Bad or missing password on admin command " "request (command: %s)", command_string); - client_send_401(client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); return; } } @@ -533,7 +533,7 @@ static void admin_handle_general_request(client_t *client, int command) break; default: ICECAST_LOG_WARN("General admin request not recognised"); - client_send_400(client, "Unknown admin request"); + client_send_error(client, 400, 0, "Unknown admin request"); return; } } @@ -601,7 +601,7 @@ static void admin_handle_mount_request(client_t *client, source_t *source, break; default: ICECAST_LOG_WARN("Mount request not recognised"); - client_send_400(client, "Mount request unknown"); + client_send_error(client, 400, 0, "Mount request unknown"); break; } } @@ -610,7 +610,7 @@ static void admin_handle_mount_request(client_t *client, source_t *source, do { \ (var) = httpp_get_query_param((client)->parser, (name)); \ if((var) == NULL) { \ - client_send_400((client), "Missing parameter"); \ + client_send_error((client), 400, 0, "Missing parameter"); \ return; \ } \ } while(0); @@ -628,7 +628,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_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); return; } @@ -669,19 +669,19 @@ static void command_move_clients(client_t *client, source_t *source, if (dest == NULL) { - client_send_400 (client, "No such destination"); + client_send_error(client, 400, 0, "No such destination"); return; } if (strcmp (dest->mount, source->mount) == 0) { - client_send_400 (client, "supplied mountpoints are identical"); + client_send_error(client, 400, 0, "supplied mountpoints are identical"); return; } if (dest->running == 0 && dest->on_demand == 0) { - client_send_400 (client, "Destination not running"); + client_send_error(client, 400, 0, "Destination not running"); return; } @@ -798,7 +798,7 @@ static void command_buildm3u(client_t *client, const char *mount) 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_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); return; } @@ -908,7 +908,7 @@ static void command_manageauth(client_t *client, source_t *source, } while (0); config_release_config (); - client_send_400 (client, "missing parameter"); + client_send_error(client, 400, 0, "missing parameter"); } static void command_kill_source(client_t *client, source_t *source, @@ -1079,7 +1079,7 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) if (strcmp (action, "updinfo") != 0) { - client_send_400 (client, "No such action"); + client_send_error(client, 400, 0, "No such action"); return; } if (source->client && strcmp (client->con->ip, source->client->con->ip) != 0) @@ -1097,7 +1097,7 @@ static void command_shoutcast_metadata(client_t *client, source_t *source) } else { - client_send_400 (client, "mountpoint will not accept URL updates"); + client_send_error(client, 400, 0, "mountpoint will not accept URL updates"); } } @@ -1144,7 +1144,7 @@ static void command_list_mounts(client_t *client, int response) if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); return; } diff --git a/src/auth.c b/src/auth.c index fdf80fbb..dc9fc108 100644 --- a/src/auth.c +++ b/src/auth.c @@ -167,7 +167,7 @@ static void auth_client_free (auth_client *auth_user) if (client->respcode) client_destroy (client); else - client_send_401 (client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); auth_user->client = NULL; } free (auth_user->mount); @@ -492,7 +492,7 @@ int auth_postprocess_listener (auth_client *auth_user) config_release_config(); if (ret < 0) - client_send_401 (auth_user->client); + client_send_error(auth_user->client, 401, 1, "You need to authenticate\r\n"); auth_user->client = NULL; return ret; @@ -535,7 +535,7 @@ void auth_add_listener (const char *mount, client_t *client) if (mountinfo && mountinfo->no_mount) { config_release_config (); - client_send_403 (client, "mountpoint unavailable"); + client_send_error(client, 403, 1, "mountpoint unavailable"); return; } if (mountinfo && mountinfo->auth) @@ -546,7 +546,7 @@ void auth_add_listener (const char *mount, client_t *client) { config_release_config (); ICECAST_LOG_WARN("too many clients awaiting authentication"); - client_send_403 (client, "busy, please try again later"); + client_send_error(client, 403, 1, "busy, please try again later"); return; } auth_user = auth_client_setup (mount, client); @@ -560,7 +560,7 @@ void auth_add_listener (const char *mount, client_t *client) int ret = add_authenticated_listener (mount, mountinfo, client); config_release_config (); if (ret < 0) - client_send_403 (client, "max listeners reached"); + client_send_error(client, 403, 1, "max listeners reached"); } } diff --git a/src/client.c b/src/client.c index c302cf48..70cb2892 100644 --- a/src/client.c +++ b/src/client.c @@ -47,6 +47,8 @@ #undef CATMODULE #define CATMODULE "client" +static inline void client_send_500(client_t *client, const char *message); + /* create a client_t with the provided connection and parser details. Return * 0 on success, -1 if server limit has been reached. In either case a * client_t is returned just in case a message needs to be returned. Should @@ -183,10 +185,15 @@ int client_read_bytes (client_t *client, void *buf, unsigned len) return bytes; } -static void client_send_error(client_t *client, int status, int plain, const char *message) +void client_send_error(client_t *client, int status, int plain, const char *message) { ssize_t ret; + if (status == 500) { + client_send_500(client, message); + return; + } + ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, status, NULL, plain ? "text/plain" : "text/html", "utf-8", @@ -214,28 +221,8 @@ void client_send_100(client_t *client) sock_write (client->con->sock, "HTTP/1.1 100 Continue\r\n\r\n"); } -void client_send_400(client_t *client, const char *message) -{ - client_send_error(client, 400, 0, message); -} - -void client_send_404(client_t *client, const char *message) -{ - client_send_error(client, 404, 0, message); -} - -void client_send_401(client_t *client) -{ - client_send_error(client, 401, 1, "You need to authenticate\r\n"); -} - -void client_send_403(client_t *client, const char *message) -{ - client_send_error(client, 403, 1, message); -} - /* this function is designed to work even if client is in bad state */ -void client_send_500(client_t *client, const char *message) { +static inline void client_send_500(client_t *client, const char *message) { const char header[] = "HTTP/1.0 500 Internal Server Error\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n" "500 - Internal Server Error\n---------------------------\n"; const size_t header_len = sizeof(header) - 1; diff --git a/src/client.h b/src/client.h index c89e1025..943763ee 100644 --- a/src/client.h +++ b/src/client.h @@ -70,12 +70,8 @@ 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_100(client_t *client); -void client_send_404(client_t *client, const char *message); -void client_send_401(client_t *client); -void client_send_403(client_t *client, const char *message); -void client_send_400(client_t *client, const char *message); -void client_send_500(client_t *client, const char *message); int client_send_bytes (client_t *client, const void *buf, unsigned len); int client_read_bytes (client_t *client, void *buf, unsigned len); void client_set_queue (client_t *client, refbuf_t *refbuf); diff --git a/src/connection.c b/src/connection.c index 5ffc0a6c..b40a2ec3 100644 --- a/src/connection.c +++ b/src/connection.c @@ -732,7 +732,7 @@ void connection_accept_loop (void) if (client_create (&client, con, NULL) < 0) { global_unlock(); - client_send_403 (client, "Icecast connection limit reached"); + client_send_error(client, 403, 1, "Icecast connection limit reached"); /* don't be too eager as this is an imposed hard limit */ thread_sleep (400000); continue; @@ -823,7 +823,7 @@ int connection_complete_source (source_t *source, int response) config_release_config(); global_unlock(); if (response) { - client_send_403 (source->client, "Content-type not supported"); + client_send_error(source->client, 403, 1, "Content-type not supported"); source->client = NULL; } ICECAST_LOG_WARN("Content-type \"%s\" not supported, dropping source", contenttype); @@ -833,7 +833,7 @@ int connection_complete_source (source_t *source, int response) config_release_config(); global_unlock(); if (response) { - client_send_403 (source->client, "No Content-type given"); + client_send_error(source->client, 403, 1, "No Content-type given"); source->client = NULL; } ICECAST_LOG_ERROR("Content-type not given in PUT request, dropping source"); @@ -851,7 +851,7 @@ int connection_complete_source (source_t *source, int response) config_release_config(); if (response) { - client_send_403 (source->client, "internal format allocation problem"); + client_send_error(source->client, 403, 1, "internal format allocation problem"); source->client = NULL; } ICECAST_LOG_WARN("plugin format failed for \"%s\"", source->mount); @@ -896,7 +896,7 @@ int connection_complete_source (source_t *source, int response) if (response) { - client_send_403 (source->client, "too many sources connected"); + client_send_error(source->client, 403, 1, "too many sources connected"); source->client = NULL; } @@ -1053,7 +1053,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_401 (client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); return; } switch (client_check_source_auth (client, uri)) @@ -1067,7 +1067,7 @@ static void _handle_source_request (client_t *client, const char *uri) default: /* failed */ ICECAST_LOG_INFO("Source (%s) attempted to login with invalid or missing password", uri); - client_send_401(client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); break; } } @@ -1110,7 +1110,7 @@ void source_startup (client_t *client, const char *uri, int auth_style) } else { - client_send_403 (client, "Mountpoint in use"); + client_send_error(client, 403, 1, "Mountpoint in use"); ICECAST_LOG_WARN("Mountpoint %s in use", uri); } } @@ -1122,7 +1122,7 @@ static void _handle_stats_request (client_t *client, char *uri) if (connection_check_admin_pass (client->parser) == 0) { - client_send_401 (client); + client_send_error(client, 401, 1, "You need to authenticate\r\n"); ICECAST_LOG_ERROR("Bad password for stats connection"); return; } @@ -1397,7 +1397,7 @@ static void _handle_connection(void) } else { ICECAST_LOG_ERROR("Wrong request type from client"); - client_send_400 (client, "unknown request"); + client_send_error(client, 400, 0, "unknown request"); } free(uri); diff --git a/src/format.c b/src/format.c index 74fc055a..d0a579d3 100644 --- a/src/format.c +++ b/src/format.c @@ -302,7 +302,7 @@ static int format_prepare_headers (source_t *source, client_t *client) bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); if (bytes == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); return -1; } else if ((bytes + 1024) >= remaining) { /* we don't know yet how much to follow but want at least 1kB free space */ void *new_ptr = realloc(ptr, bytes + 1024); @@ -313,12 +313,12 @@ static int format_prepare_headers (source_t *source, client_t *client) bytes = util_http_build_header(ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); if (bytes == -1 ) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); return -1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); - client_send_500(client, "Buffer reallocation failed."); + client_send_error(client, 500, 0, "Buffer reallocation failed."); return -1; } } diff --git a/src/fserve.c b/src/fserve.c index fd8d4961..de4b5fe5 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -432,7 +432,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_404 (httpclient, "The file you requested could not be found"); + client_send_error(httpclient, 404, 0, "The file you requested could not be found"); free (fullpath); return -1; } @@ -461,7 +461,7 @@ int fserve_client_create (client_t *httpclient, const char *path) "audio/x-mpegurl", NULL, "", NULL); 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_500(httpclient, "Header generation failed."); + client_send_error(httpclient, 500, 0, "Header generation failed."); return -1; } if (host == NULL) @@ -507,7 +507,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_404 (httpclient, "The file you requested could not be found"); + client_send_error(httpclient, 404, 0, "The file you requested could not be found"); config_release_config(); free (fullpath); return -1; @@ -516,7 +516,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (S_ISREG (file_buf.st_mode) == 0) { - client_send_404 (httpclient, "The file you requested could not be found"); + client_send_error(httpclient, 404, 0, "The file you requested could not be found"); ICECAST_LOG_WARN("found requested file but there is no handler for it: %H", fullpath); free (fullpath); return -1; @@ -526,7 +526,7 @@ int fserve_client_create (client_t *httpclient, const char *path) if (file == NULL) { ICECAST_LOG_WARN("Problem accessing file \"%H\"", fullpath); - client_send_404 (httpclient, "File not readable"); + client_send_error(httpclient, 404, 0, "File not readable"); free (fullpath); return -1; } @@ -575,7 +575,7 @@ int fserve_client_create (client_t *httpclient, const char *path) NULL, NULL); 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_500(httpclient, "Header generation failed."); + client_send_error(httpclient, 500, 0, "Header generation failed."); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, @@ -606,7 +606,7 @@ int fserve_client_create (client_t *httpclient, const char *path) NULL, NULL); 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_500(httpclient, "Header generation failed."); + client_send_error(httpclient, 500, 0, "Header generation failed."); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, @@ -661,7 +661,7 @@ int fserve_add_client (client_t *client, FILE *file) ICECAST_LOG_DEBUG("Adding client to file serving engine"); if (fclient == NULL) { - client_send_404 (client, "memory exhausted"); + client_send_error(client, 404, 0, "memory exhausted"); return -1; } fclient->file = file; @@ -683,7 +683,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_404 (client, "memory exhausted"); + client_send_error(client, 404, 0, "memory exhausted"); return; } fclient->file = NULL; diff --git a/src/source.c b/src/source.c index abc51cdc..4e62ecc5 100644 --- a/src/source.c +++ b/src/source.c @@ -947,7 +947,7 @@ static int _free_client(void *key) /* if no response has been sent then send a 404 */ if (client->respcode == 0) - client_send_404 (client, "Mount unavailable"); + client_send_error(client, 404, 0, "Mount unavailable"); else client_destroy(client); diff --git a/src/xslt.c b/src/xslt.c index a7f037c6..b6d48f80 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -203,7 +203,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_404 (client, "Could not parse XSLT file"); + client_send_error(client, 404, 0, "Could not parse XSLT file"); return; } @@ -244,7 +244,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); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); } else { if ( full_len < (ret + len + 64) ) { void *new_data; @@ -257,12 +257,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); if (ret == -1) { ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); - client_send_500(client, "Header generation failed."); + client_send_error(client, 500, 0, "Header generation failed."); failed = 1; } } else { ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); - client_send_500(client, "Buffer reallocation failed."); + client_send_error(client, 500, 0, "Buffer reallocation failed."); failed = 1; } } @@ -282,7 +282,7 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) else { ICECAST_LOG_WARN("problem applying stylesheet \"%s\"", xslfilename); - client_send_404 (client, "XSLT problem"); + client_send_error(client, 404, 0, "XSLT problem"); } thread_mutex_unlock (&xsltlock); xmlFreeDoc(res);