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

patch to fix regression on header size with large headers introduced by...

patch to fix regression on header size with large headers introduced by support of <server-id> and <http-headers>. This should ensure we have at least space for 2kB of extra headers. Depending on function and call we may have much more space.

Please test this very carefully.
Some pointers what should be in the tests (NOT complet list):
- request to 'static' web/ and admin/ pages.
- requests to playlist generation.
- requests to streams.
- requests to admin/ manipulation functions.
- test everything with at least 8kB of extra headers, then reduce in 1kB (or 512B) steps.
- see if response is correct OR 500 is returned.
- run under valgrind or similar to see no buffer overflow or similiar will happen.
- take a cookie!

svn path=/icecast/trunk/icecast/; revision=19300
parent ad1f7bca
......@@ -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;
}
}
/* 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 = len;
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,
"<html><head><title>Admin request successful</title></head>"
"<body><p>%s</p></body></html>", 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;
......
......@@ -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,
"<html><head><title>Error %i</title></head><body><b>%i - %s</b></body></html>\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)
......
......@@ -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);
......
......@@ -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;
......
......@@ -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",
......
......@@ -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);
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment