Commit 01c35e2c authored by Philipp Schafft's avatar Philipp Schafft 🦁

Feature: Check if we know client's body length. If so do not allow reading more than it.

parent f370e883
......@@ -87,6 +87,8 @@ int client_create(client_t **c_ptr, connection_t *con, http_parser_t *parser)
client->con = con;
client->parser = parser;
client->protocol = ICECAST_PROTOCOL_HTTP;
client->request_body_length = 0;
client->request_body_read = 0;
client->admin_command = ADMIN_COMMAND_ERROR;
client->refbuf = refbuf_new (PER_CLIENT_REFBUF_SIZE);
client->refbuf->len = 0; /* force reader code to ignore buffer contents */
......@@ -439,8 +441,25 @@ void client_set_queue(client_t *client, refbuf_t *refbuf)
ssize_t client_body_read(client_t *client, void *buf, size_t len)
{
ssize_t ret;
ICECAST_LOG_DEBUG("Reading from body (client=%p)", client);
return client_read_bytes(client, buf, len);
if (client->request_body_length != -1) {
size_t left = (size_t)client->request_body_length - client->request_body_read;
if (len > left) {
ICECAST_LOG_DEBUG("Limiting read request to left over body size: left %zu byte, requested %zu byte", left, len);
len = left;
}
}
ret = client_read_bytes(client, buf, len);
if (ret > 0) {
client->request_body_read += ret;
}
return ret;
}
/* we might un-static this if needed at some time in distant future. -- ph3-der-loewe, 2018-04-17 */
......@@ -468,7 +487,10 @@ int client_body_eof(client_t *client)
if (!client)
return -1;
if (client->encoding) {
if (client->request_body_length != -1 && client->request_body_read == (size_t)client->request_body_length) {
ICECAST_LOG_DEBUG("Reached given body length (client=%p)", client);
ret = 1;
} else if (client->encoding) {
ICECAST_LOG_DEBUG("Looking for body EOF with encoding (client=%p)", client);
ret = httpp_encoding_eof(client->encoding, (int(*)(void*))client_eof, client);
} else {
......
......@@ -62,6 +62,14 @@ struct _client_tag {
/* protocol client uses */
protocol_t protocol;
/* http request body length
* -1 for streaming (e.g. chunked), 0 for no body, >0 for NNN bytes
*/
ssize_t request_body_length;
/* http request body length read so far */
size_t request_body_read;
/* http response code for this client */
int respcode;
......
......@@ -1431,6 +1431,50 @@ static void __prepare_shoutcast_admin_cgi_request(client_t *client)
global_unlock();
}
static void _update_client_request_body_length(client_t *client)
{
const char *header;
long long unsigned int scannumber;
int have = 0;
if (!have) {
if (client->parser->req_type == httpp_req_source) {
client->request_body_length = -1; /* streaming */
have = 1;
}
}
if (!have) {
header = httpp_getvar(client->parser, "transfer-encoding");
if (header) {
if (strcasecmp(header, "identity") != 0) {
client->request_body_length = -1; /* streaming */
have = 1;
}
}
}
if (!have) {
header = httpp_getvar(client->parser, "content-length");
if (header) {
if (sscanf(header, "%llu", &scannumber) == 1) {
client->request_body_length = scannumber;
have = 1;
}
}
}
if (!have) {
if (client->parser->req_type == httpp_req_put) {
/* As we don't know yet, we asume this PUT is in streaming mode */
client->request_body_length = -1; /* streaming */
have = 1;
}
}
ICECAST_LOG_DEBUG("Client %p has request_body_length=%zi", client, client->request_body_length);
}
/* Connection thread. Here we take clients off the connection queue and check
* the contents provided. We set up the parser then hand off to the specific
* request handler.
......@@ -1489,6 +1533,8 @@ static void _handle_connection(void)
continue;
}
_update_client_request_body_length(client);
upgrade = httpp_getvar(parser, "upgrade");
connection = httpp_getvar(parser, "connection");
if (upgrade && connection && strcasecmp(connection, "upgrade") == 0) {
......
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