Commit 4a10d7e7 authored by Philipp Schafft's avatar Philipp Schafft 🦁

Merge branch 'ph3-body'

parents 2d3409af a5327006
......@@ -53,7 +53,7 @@
<!-- Form to add Users -->
<xsl:if test="@can-adduser = 'true'">
<h4>Add User</h4>
<form method="get" action="manageauth.xsl">
<form method="post" action="manageauth.xsl">
<label for="username" class="hidden">Username</label>
<input type="text" id="username" name="username" value="" placeholder="Username" required="required" />
<label for="password" class="hidden">Password</label>
......
......@@ -18,7 +18,7 @@
<xsl:choose>
<xsl:when test="source">
<p>Choose the mountpoint to which you want to move the listeners to:</p>
<form method="get" action="moveclients.xsl">
<form method="post" action="moveclients.xsl">
<label for="moveto" class="hidden">
Move from <code><xsl:value-of select="current_source" /></code> to
</label>
......
......@@ -15,7 +15,7 @@
<h3>Mountpoint <xsl:value-of select="@mount" /></h3>
<!-- Mount nav -->
<xsl:call-template name="mountnav" />
<form method="get" action="/admin/metadata.xsl">
<form method="post" action="/admin/metadata.xsl">
<label for="metadata" class="hidden">Metadata</label>
<input type="text" id="metadata" name="song" value="" placeholder="Click to edit" required="required" />
<input type="hidden" name="mount" value="{@mount}" />
......
......@@ -52,7 +52,7 @@
/* Helper macros */
#define COMMAND_REQUIRE(client,name,var) \
do { \
(var) = httpp_get_query_param((client)->parser, (name)); \
(var) = httpp_get_param((client)->parser, (name)); \
if((var) == NULL) { \
client_send_error_by_id(client, ICECAST_ERROR_ADMIN_MISSING_PARAMETER); \
return; \
......@@ -60,7 +60,7 @@
} while(0);
#define COMMAND_OPTIONAL(client,name,var) \
(var) = httpp_get_query_param((client)->parser, (name))
(var) = httpp_get_param((client)->parser, (name))
/* special commands */
#define COMMAND_ERROR ADMIN_COMMAND_ERROR
......@@ -502,7 +502,7 @@ void admin_handle_request(client_t *client, const char *uri)
}
}
mount = httpp_get_query_param(client->parser, "mount");
COMMAND_OPTIONAL(client, "mount", mount);
/* Find mountpoint source */
if(mount != NULL) {
......@@ -543,6 +543,7 @@ void admin_handle_request(client_t *client, const char *uri)
switch (client->parser->req_type) {
case httpp_req_get:
case httpp_req_post:
handler->function(client, source, format);
break;
case httpp_req_options:
......
......@@ -49,11 +49,13 @@
#define CONFIG_DEFAULT_CLIENT_LIMIT 256
#define CONFIG_DEFAULT_SOURCE_LIMIT 16
#define CONFIG_DEFAULT_QUEUE_SIZE_LIMIT (500*1024)
#define CONFIG_DEFAULT_BODY_SIZE_LIMIT (4*1024)
#define CONFIG_DEFAULT_BURST_SIZE (64*1024)
#define CONFIG_DEFAULT_THREADPOOL_SIZE 4
#define CONFIG_DEFAULT_CLIENT_TIMEOUT 30
#define CONFIG_DEFAULT_HEADER_TIMEOUT 15
#define CONFIG_DEFAULT_SOURCE_TIMEOUT 10
#define CONFIG_DEFAULT_BODY_TIMEOUT (10 + CONFIG_DEFAULT_HEADER_TIMEOUT)
#define CONFIG_DEFAULT_MASTER_USERNAME "relay"
#define CONFIG_DEFAULT_SHOUTCAST_MOUNT "/stream"
#define CONFIG_DEFAULT_SHOUTCAST_USER "source"
......@@ -801,12 +803,16 @@ static void _set_defaults(ice_config_t *configuration)
->source_limit = CONFIG_DEFAULT_SOURCE_LIMIT;
configuration
->queue_size_limit = CONFIG_DEFAULT_QUEUE_SIZE_LIMIT;
configuration
->body_size_limit = CONFIG_DEFAULT_BODY_SIZE_LIMIT;
configuration
->client_timeout = CONFIG_DEFAULT_CLIENT_TIMEOUT;
configuration
->header_timeout = CONFIG_DEFAULT_HEADER_TIMEOUT;
configuration
->source_timeout = CONFIG_DEFAULT_SOURCE_TIMEOUT;
configuration
->source_timeout = CONFIG_DEFAULT_BODY_TIMEOUT;
configuration
->shoutcast_mount = (char *) xmlCharStrdup(CONFIG_DEFAULT_SHOUTCAST_MOUNT);
configuration
......@@ -1123,6 +1129,8 @@ static void _parse_limits(xmlDocPtr doc,
__read_int(doc, node, &configuration->client_limit, "<clients> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("sources")) == 0) {
__read_int(doc, node, &configuration->source_limit, "<sources> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("bodysize")) == 0) {
__read_int(doc, node, &configuration->body_size_limit, "<bodysize> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("queue-size")) == 0) {
__read_unsigned_int(doc, node, &configuration->queue_size_limit, "<queue-size> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("threadpool")) == 0) {
......@@ -1134,6 +1142,8 @@ static void _parse_limits(xmlDocPtr doc,
__read_int(doc, node, &configuration->header_timeout, "<header-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("source-timeout")) == 0) {
__read_int(doc, node, &configuration->source_timeout, "<source-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("body-timeout")) == 0) {
__read_int(doc, node, &configuration->body_timeout, "<body-timeout> must not be empty.");
} else if (xmlStrcmp(node->name, XMLSTR("burst-on-connect")) == 0) {
ICECAST_LOG_WARN("<burst-on-connect> is deprecated, use <burst-size> instead.");
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
......
......@@ -26,6 +26,7 @@
#include "common/thread/thread.h"
#include "common/avl/avl.h"
#include "icecasttypes.h"
#include "compat.h"
#define XMLSTR(str) ((xmlChar *)(str))
......@@ -170,11 +171,13 @@ struct ice_config_tag {
int client_limit;
int source_limit;
int body_size_limit;
unsigned int queue_size_limit;
unsigned int burst_size;
int client_timeout;
int header_timeout;
int source_timeout;
int body_timeout;
int fileserve;
int on_demand; /* global setting for all relays */
......
......@@ -32,6 +32,7 @@
#include "refobject.h"
#include "cfgfile.h"
#include "connection.h"
#include "tls.h"
#include "refbuf.h"
#include "format.h"
#include "stats.h"
......@@ -86,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 */
......@@ -121,6 +124,16 @@ static inline void client_reuseconnection(client_t *client) {
client->con->send = NULL;
}
if (client->con->readbufferlen) {
/* Aend... moorre paaiin.
* stealing putback buffer.
*/
con->readbuffer = client->con->readbuffer;
con->readbufferlen = client->con->readbufferlen;
client->con->readbuffer = NULL;
client->con->readbufferlen = 0;
}
client->reuse = ICECAST_REUSE_CLOSE;
client_destroy(client);
......@@ -137,8 +150,11 @@ void client_destroy(client_t *client)
return;
if (client->reuse != ICECAST_REUSE_CLOSE) {
client_reuseconnection(client);
return;
/* only reuse the client if we reached the body's EOF. */
if (client_body_eof(client) == 1) {
client_reuseconnection(client);
return;
}
}
/* release the buffer now, as the buffer could be on the source queue
......@@ -435,3 +451,176 @@ void client_set_queue(client_t *client, refbuf_t *refbuf)
if (to_release)
refbuf_release(to_release);
}
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);
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 */
static int client_eof(client_t *client)
{
if (!client)
return -1;
if (!client->con)
return 0;
if (client->con->tls && tls_got_shutdown(client->con->tls) > 1)
client->con->error = 1;
if (client->con->error)
return 1;
return 0;
}
int client_body_eof(client_t *client)
{
int ret = -1;
if (!client)
return -1;
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 {
ICECAST_LOG_DEBUG("Looking for body EOF without encoding (client=%p)", client);
ret = client_eof(client);
}
ICECAST_LOG_DEBUG("... result is: %i (client=%p)", ret, client);
return ret;
}
client_slurp_result_t client_body_slurp(client_t *client, void *buf, size_t *len)
{
if (!client || !buf || !len)
return CLIENT_SLURP_ERROR;
if (client->request_body_length != -1) {
/* non-streaming mode */
size_t left = (size_t)client->request_body_length - client->request_body_read;
if (!left)
return CLIENT_SLURP_SUCCESS;
if (*len < (size_t)client->request_body_length)
return CLIENT_SLURP_BUFFER_TO_SMALL;
if (left > 2048)
left = 2048;
client_body_read(client, buf + client->request_body_read, left);
if ((size_t)client->request_body_length == client->request_body_read) {
*len = client->request_body_read;
return CLIENT_SLURP_SUCCESS;
} else {
return CLIENT_SLURP_NEEDS_MORE_DATA;
}
} else {
/* streaming mode */
size_t left = *len - client->request_body_read;
int ret;
if (left) {
if (left > 2048)
left = 2048;
client_body_read(client, buf + client->request_body_read, left);
}
ret = client_body_eof(client);
switch (ret) {
case 0:
if (*len == client->request_body_read) {
return CLIENT_SLURP_BUFFER_TO_SMALL;
}
return CLIENT_SLURP_NEEDS_MORE_DATA;
break;
case 1:
return CLIENT_SLURP_SUCCESS;
break;
default:
return CLIENT_SLURP_ERROR;
break;
}
}
}
client_slurp_result_t client_body_skip(client_t *client)
{
char buf[2048];
int ret;
ICECAST_LOG_DEBUG("Slurping client %p");
if (!client) {
ICECAST_LOG_DEBUG("Slurping client %p ... failed");
return CLIENT_SLURP_ERROR;
}
if (client->request_body_length != -1) {
size_t left = (size_t)client->request_body_length - client->request_body_read;
if (!left) {
ICECAST_LOG_DEBUG("Slurping client %p ... was a success");
return CLIENT_SLURP_SUCCESS;
}
if (left > sizeof(buf))
left = sizeof(buf);
client_body_read(client, buf, left);
if ((size_t)client->request_body_length == client->request_body_read) {
ICECAST_LOG_DEBUG("Slurping client %p ... was a success");
return CLIENT_SLURP_SUCCESS;
} else {
ICECAST_LOG_DEBUG("Slurping client %p ... needs more data");
return CLIENT_SLURP_NEEDS_MORE_DATA;
}
} else {
client_body_read(client, buf, sizeof(buf));
}
ret = client_body_eof(client);
switch (ret) {
case 0:
ICECAST_LOG_DEBUG("Slurping client %p ... needs more data");
return CLIENT_SLURP_NEEDS_MORE_DATA;
break;
case 1:
ICECAST_LOG_DEBUG("Slurping client %p ... was a success");
return CLIENT_SLURP_SUCCESS;
break;
default:
ICECAST_LOG_DEBUG("Slurping client %p ... failed");
return CLIENT_SLURP_ERROR;
break;
}
}
......@@ -43,6 +43,13 @@ typedef enum _reuse_tag {
ICECAST_REUSE_UPGRADETLS
} reuse_t;
typedef enum {
CLIENT_SLURP_ERROR,
CLIENT_SLURP_NEEDS_MORE_DATA,
CLIENT_SLURP_BUFFER_TO_SMALL,
CLIENT_SLURP_SUCCESS
} client_slurp_result_t;
struct _client_tag {
/* mode of operation for this client */
operation_mode mode;
......@@ -62,6 +69,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;
......@@ -122,5 +137,9 @@ admin_format_t client_get_admin_format_by_content_negotiation(client_t *client);
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);
ssize_t client_body_read(client_t *client, void *buf, size_t len);
int client_body_eof(client_t *client);
client_slurp_result_t client_body_slurp(client_t *client, void *buf, size_t *len);
client_slurp_result_t client_body_skip(client_t *client);
#endif /* __CLIENT_H__ */
Subproject commit fca416b126cb842034ac3468362c044895975b5a
Subproject commit 9bfb3a34fc41cc8e0075328d7d6527bd84eb40ba
This diff is collapsed.
......@@ -40,6 +40,9 @@ struct connection_tag {
int (*send)(connection_t *handle, const void *buf, size_t len);
int (*read)(connection_t *handle, void *buf, size_t len);
void *readbuffer;
size_t readbufferlen;
char *ip;
};
......@@ -55,6 +58,7 @@ void connection_queue(connection_t *con);
void connection_uses_tls(connection_t *con);
ssize_t connection_read_bytes(connection_t *con, void *buf, size_t len);
int connection_read_put_back(connection_t *con, const void *buf, size_t len);
extern rwlock_t _source_shutdown_rwlock;
......
......@@ -317,7 +317,7 @@ static refbuf_t *ebml_get_buffer(source_t *source)
} else if(read_bytes == 0) {
/* Feed more bytes into the parser */
write_buffer = ebml_get_write_buffer(ebml_source_state->ebml, &write_bytes);
read_bytes = client_read_bytes (source->client, write_buffer, write_bytes);
read_bytes = client_body_read(source->client, write_buffer, write_bytes);
if (read_bytes <= 0) {
ebml_wrote (ebml_source_state->ebml, 0);
return NULL;
......
......@@ -465,7 +465,7 @@ static void format_mp3_free_plugin(format_plugin_t *self)
*/
static int complete_read(source_t *source)
{
int bytes;
ssize_t bytes;
format_plugin_t *format = source->format;
mp3_state *source_mp3 = format->_state;
char *buf;
......@@ -480,10 +480,11 @@ static int complete_read(source_t *source)
}
buf = source_mp3->read_data->data + source_mp3->read_count;
bytes = client_read_bytes (source->client, buf, REFBUF_SIZE-source_mp3->read_count);
bytes = client_body_read(source->client, buf, REFBUF_SIZE-source_mp3->read_count);
if (bytes < 0)
{
if (source->client->con->error)
/* Why do we do this here (not source.c)? -- ph3-der-loewe, 2018-04-17 */
if (client_body_eof(source->client))
{
refbuf_release (source_mp3->read_data);
source_mp3->read_data = NULL;
......
......@@ -402,7 +402,7 @@ static refbuf_t *ogg_get_buffer(source_t *source)
ogg_state_t *ogg_info = source->format->_state;
format_plugin_t *format = source->format;
char *data = NULL;
int bytes = 0;
ssize_t bytes = 0;
while (1)
{
......@@ -449,7 +449,7 @@ static refbuf_t *ogg_get_buffer(source_t *source)
/* we need more data to continue getting pages */
data = ogg_sync_buffer (&ogg_info->oy, 4096);
bytes = client_read_bytes (source->client, data, 4096);
bytes = client_body_read(source->client, data, 4096);
if (bytes <= 0)
{
ogg_sync_wrote (&ogg_info->oy, 0);
......
......@@ -516,10 +516,7 @@ static refbuf_t *get_next_buffer (source_t *source)
}
source->last_read = current;
refbuf = source->format->get_buffer (source);
if (source->client->con->tls && tls_got_shutdown(source->client->con->tls) > 1)
source->client->con->error = 1;
if (source->client->con && source->client->con->error)
{
if (client_body_eof(source->client)) {
ICECAST_LOG_INFO("End of Stream %s", source->mount);
source->running = 0;
continue;
......@@ -1321,7 +1318,6 @@ void source_client_callback (client_t *client, void *arg)
{
const char *agent;
source_t *source = arg;
refbuf_t *old_data = client->refbuf;
if (client->con->error)
{
......@@ -1332,9 +1328,9 @@ void source_client_callback (client_t *client, void *arg)
source_free_source (source);
return;
}
client->refbuf = old_data->associated;
old_data->associated = NULL;
refbuf_release (old_data);
client->refbuf->len = 0;
stats_event (source->mount, "source_ip", source->client->con->ip);
agent = httpp_getvar (source->client->parser, "user-agent");
if (agent)
......
......@@ -1020,7 +1020,7 @@ void stats_transform_xslt(client_t *client, const char *uri)
{
xmlDocPtr doc;
char *xslpath = util_get_path_from_normalised_uri(uri);
const char *mount = httpp_get_query_param(client->parser, "mount");
const char *mount = httpp_get_param(client->parser, "mount");
doc = stats_get_xml(0, mount, client->mode);
......
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