diff --git a/src/admin.c b/src/admin.c index d8b9b5ba5adc2a1940ef1e0c55f10d56f9331c92..4583bce3bd20b1b89c1c86d5abffe3ace820bad0 100644 --- a/src/admin.c +++ b/src/admin.c @@ -268,21 +268,57 @@ void admin_send_response (xmlDocPtr doc, client_t *client, { xmlChar *buff = NULL; int len = 0; - unsigned int buf_len; + size_t buf_len; + ssize_t ret; + xmlDocDumpMemory(doc, &buff, &len); - buf_len = len + 256 /* just a random medium number */; + + buf_len = len + 1024; + if (buf_len < 4096) + buf_len = 4096; client_set_queue (client, NULL); client->refbuf = refbuf_new (buf_len); - /* FIXME: in this section we hope no function will ever return -1 */ - len = util_http_build_header(client->refbuf->data, buf_len, 0, + ret = util_http_build_header(client->refbuf->data, buf_len, 0, 0, 200, NULL, "text/xml", "utf-8", NULL, NULL); - len += snprintf (client->refbuf->data + len, buf_len - len, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + xmlFree(buff); + return; + } else if (buf_len < (len + ret + 64)) { + void *new_data; + buf_len = ret + len + 64; + new_data = realloc(client->refbuf->data, buf_len); + if (new_data) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + client->refbuf->data = new_data; + client->refbuf->len = buf_len; + ret = util_http_build_header(client->refbuf->data, buf_len, 0, + 0, 200, NULL, + "text/xml", "utf-8", + NULL, NULL); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + xmlFree(buff); + return; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + xmlFree(buff); + return; + } + } - client->refbuf->len = len; + /* FIXME: in this section we hope no function will ever return -1 */ + ret += snprintf (client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff); + + client->refbuf->len = ret; xmlFree(buff); client->respcode = 200; fserve_add_client (client, NULL); @@ -574,6 +610,13 @@ static void html_success(client_t *client, char *message) 0, 200, NULL, "text/html", "utf-8", "", NULL); + + 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."); + return; + } + snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Admin request successful" "

%s

", message); @@ -714,6 +757,13 @@ static void command_buildm3u(client_t *client, const char *mount) "audio/x-mpegurl", NULL, NULL, NULL); + 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."); + return; + } + + config = config_get_config(); snprintf (client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Content-Disposition = attachment; filename=listen.m3u\r\n\r\n" @@ -1029,10 +1079,17 @@ static void command_list_mounts(client_t *client, int response) if (response == PLAINTEXT) { - util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, + ssize_t ret = util_http_build_header(client->refbuf->data, PER_CLIENT_REFBUF_SIZE, 0, 0, 200, NULL, "text/plain", "utf-8", "", NULL); + + 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."); + return; + } + client->refbuf->len = strlen (client->refbuf->data); client->respcode = 200; diff --git a/src/client.c b/src/client.c index 22906ba2e385824a4642b52ae8863e049f8adaad..c302cf4894ed9afdf643a4dd7f28b5be4feff701 100644 --- a/src/client.c +++ b/src/client.c @@ -192,6 +192,12 @@ static void client_send_error(client_t *client, int status, int plain, const cha plain ? "text/plain" : "text/html", "utf-8", plain ? message : "", NULL); + 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."); + return; + } + if (!plain) snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, "Error %i%i - %s\r\n", @@ -228,6 +234,21 @@ 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) { + 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; + int ret; + + ret = client_send_bytes(client, header, header_len); + + /* only send message if we have one AND if header could have transmitted completly */ + if (message && ret == header_len) + client_send_bytes(client, message, strlen(message)); + + client_destroy(client); +} /* helper function for sending the data to a client */ int client_send_bytes (client_t *client, const void *buf, unsigned len) diff --git a/src/client.h b/src/client.h index c3429676f6d96a7023dbe8051958a0101f12f840..c89e102518cc4d1cd2a85c9cf88b479fdc976fef 100644 --- a/src/client.h +++ b/src/client.h @@ -75,6 +75,7 @@ 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/format.c b/src/format.c index d87b04963695e90c35789ae03b2b09fb964ec633..74fc055a3b9405e7cc0b6a1109671d11fca948f3 100644 --- a/src/format.c +++ b/src/format.c @@ -299,7 +299,29 @@ static int format_prepare_headers (source_t *source, client_t *client) ptr = client->refbuf->data; client->respcode = 200; - bytes = util_http_build_header (ptr, remaining, 0, 0, 200, NULL, source->format->contenttype, NULL, NULL, source); + 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."); + 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); + if (new_ptr) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + client->refbuf->data = ptr = new_ptr; + client->refbuf->len = remaining = bytes + 1024; + 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."); + return -1; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + return -1; + } + } remaining -= bytes; ptr += bytes; diff --git a/src/fserve.c b/src/fserve.c index 90ecac0012f1b680b5df47f97c3d8b9f26578a68..fd8d49618071d18bb2a07cc75a7c6dbe75391c3f 100644 --- a/src/fserve.c +++ b/src/fserve.c @@ -459,6 +459,11 @@ int fserve_client_create (client_t *httpclient, const char *path) ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, "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."); + return -1; + } if (host == NULL) { config = config_get_config(); @@ -568,6 +573,11 @@ int fserve_client_create (client_t *httpclient, const char *path) 0, 206, NULL, type, NULL, 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."); + return -1; + } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" @@ -594,6 +604,11 @@ int fserve_client_create (client_t *httpclient, const char *path) 0, 200, NULL, type, NULL, 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."); + return -1; + } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n\r\n", diff --git a/src/xslt.c b/src/xslt.c index 080c7102f1917b2afb320f64ba21e9726b1fa0c9..5db923270247373156fca491b3d0445d76121383 100644 --- a/src/xslt.c +++ b/src/xslt.c @@ -231,23 +231,52 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client) } if (problem == 0) { - /* the 100 is to allow for the hardcoded headers */ - unsigned int full_len = strlen (mediatype) + len + 256; + size_t full_len = strlen (mediatype) + len + 1024; refbuf_t *refbuf = refbuf_new (full_len); ssize_t ret; + int failed = 0; + + if (full_len < 4096) + full_len = 4096; if (string == NULL) string = xmlCharStrdup (""); ret = util_http_build_header(refbuf->data, full_len, 0, 0, 200, NULL, mediatype, charset, NULL, NULL); - snprintf (refbuf->data + ret, full_len - ret, - "Content-Length: %d\r\n\r\n%s", - len, string); - - client->respcode = 200; - client_set_queue (client, NULL); - client->refbuf = refbuf; - refbuf->len = strlen (refbuf->data); - fserve_add_client (client, NULL); + if (ret == -1) { + ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); + client_send_500(client, "Header generation failed."); + } else { + if ( full_len < (ret + len + 64) ) { + void *new_data; + full_len = ret + len + 64; + new_data = realloc(refbuf->data, full_len); + if (new_data) { + ICECAST_LOG_DEBUG("Client buffer reallocation succeeded."); + refbuf->data = new_data; + refbuf->len = full_len; + 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."); + failed = 1; + } + } else { + ICECAST_LOG_ERROR("Client buffer reallocation failed. Dropping client."); + client_send_500(client, "Buffer reallocation failed."); + failed = 1; + } + } + + if (!failed) { + snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string); + + client->respcode = 200; + client_set_queue (client, NULL); + client->refbuf = refbuf; + refbuf->len = strlen (refbuf->data); + fserve_add_client (client, NULL); + } + } xmlFree (string); } else