mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Fix: allow Keep-Alive connections on normal error pages
This commit is contained in:
parent
78213fe30a
commit
c806e47a4a
49
src/client.c
49
src/client.c
@ -92,12 +92,35 @@ int client_create(client_t **c_ptr, connection_t *con, http_parser_t *parser)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void client_reuseconnection(client_t *client) {
|
||||
connection_t *con;
|
||||
reuse_t reuse;
|
||||
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
con = client->con;
|
||||
con = connection_create(con->sock, con->serversock, strdup(con->ip));
|
||||
reuse = client->reuse;
|
||||
client->con->sock = -1; /* TODO: do not use magic */
|
||||
client->reuse = ICECAST_REUSE_CLOSE;
|
||||
|
||||
client_destroy(client);
|
||||
|
||||
connection_queue(con);
|
||||
}
|
||||
|
||||
void client_destroy(client_t *client)
|
||||
{
|
||||
ICECAST_LOG_DEBUG("Called to destory client %p", client);
|
||||
if (client == NULL)
|
||||
return;
|
||||
|
||||
if (client->reuse != ICECAST_REUSE_CLOSE) {
|
||||
client_reuseconnection(client);
|
||||
return;
|
||||
}
|
||||
|
||||
/* release the buffer now, as the buffer could be on the source queue
|
||||
* and may of disappeared after auth completes */
|
||||
if (client->refbuf) {
|
||||
@ -163,16 +186,23 @@ int client_read_bytes(client_t *client, void *buf, unsigned len)
|
||||
void client_send_error(client_t *client, int status, int plain, const char *message)
|
||||
{
|
||||
ssize_t ret;
|
||||
refbuf_t *data;
|
||||
|
||||
if (status == 500) {
|
||||
client_send_500(client, message);
|
||||
return;
|
||||
}
|
||||
|
||||
data = refbuf_new(PER_CLIENT_REFBUF_SIZE);
|
||||
if (!data) {
|
||||
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",
|
||||
plain ? message : "", NULL, client);
|
||||
NULL, NULL, client);
|
||||
|
||||
if (ret == -1 || ret >= PER_CLIENT_REFBUF_SIZE) {
|
||||
ICECAST_LOG_ERROR("Dropping client as we can not build response headers.");
|
||||
@ -180,13 +210,26 @@ void client_send_error(client_t *client, int status, int plain, const char *mess
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plain)
|
||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
||||
if (plain) {
|
||||
strncpy(data->data, message, data->len);
|
||||
data->data[data->len-1] = 0;
|
||||
} else {
|
||||
snprintf(data->data, data->len,
|
||||
"<html><head><title>Error %i</title></head><body><b>%i - %s</b></body></html>\r\n",
|
||||
status, status, message);
|
||||
}
|
||||
data->len = strlen(data->data);
|
||||
|
||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
||||
"Content-Length: %llu\r\nConnection: Keep-Alive\r\n\r\n",
|
||||
(long long unsigned int)data->len);
|
||||
|
||||
client->respcode = status;
|
||||
client->refbuf->len = strlen (client->refbuf->data);
|
||||
client->refbuf->next = data;
|
||||
|
||||
client->reuse = ICECAST_REUSE_KEEPALIVE;
|
||||
|
||||
fserve_add_client (client, NULL);
|
||||
}
|
||||
|
||||
|
11
src/client.h
11
src/client.h
@ -30,6 +30,13 @@ typedef enum _protocol_tag {
|
||||
ICECAST_PROTOCOL_SHOUTCAST
|
||||
} protocol_t;
|
||||
|
||||
typedef enum _reuse_tag {
|
||||
/* do not reuse */
|
||||
ICECAST_REUSE_CLOSE = 0,
|
||||
/* reuse */
|
||||
ICECAST_REUSE_KEEPALIVE
|
||||
} reuse_t;
|
||||
|
||||
typedef struct _client_tag
|
||||
{
|
||||
/* mode of operation for this client */
|
||||
@ -37,6 +44,10 @@ typedef struct _client_tag
|
||||
|
||||
/* the client's connection */
|
||||
connection_t *con;
|
||||
|
||||
/* Reuse this connection ... */
|
||||
reuse_t reuse;
|
||||
|
||||
/* the client's http headers */
|
||||
http_parser_t *parser;
|
||||
|
||||
|
@ -685,6 +685,41 @@ static client_queue_t *create_client_node(client_t *client)
|
||||
return node;
|
||||
}
|
||||
|
||||
void connection_queue(connection_t *con)
|
||||
{
|
||||
client_queue_t *node;
|
||||
client_t *client = NULL;
|
||||
|
||||
global_lock();
|
||||
if (client_create(&client, con, NULL) < 0) {
|
||||
global_unlock();
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
/* setup client for reading incoming http */
|
||||
client->refbuf->data[PER_CLIENT_REFBUF_SIZE-1] = '\000';
|
||||
|
||||
if (sock_set_blocking(client->con->sock, 0) || sock_set_nodelay(client->con->sock)) {
|
||||
global_unlock();
|
||||
ICECAST_LOG_WARN("failed to set tcp options on client connection, dropping");
|
||||
client_destroy(client);
|
||||
return;
|
||||
}
|
||||
node = create_client_node(client);
|
||||
global_unlock();
|
||||
|
||||
if (node == NULL) {
|
||||
client_destroy(client);
|
||||
return;
|
||||
}
|
||||
|
||||
_add_request_queue(node);
|
||||
stats_event_inc(NULL, "connections");
|
||||
}
|
||||
|
||||
void connection_accept_loop(void)
|
||||
{
|
||||
connection_t *con;
|
||||
@ -699,38 +734,7 @@ void connection_accept_loop(void)
|
||||
con = _accept_connection (duration);
|
||||
|
||||
if (con) {
|
||||
client_queue_t *node;
|
||||
client_t *client = NULL;
|
||||
|
||||
global_lock();
|
||||
if (client_create (&client, con, NULL) < 0) {
|
||||
global_unlock();
|
||||
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;
|
||||
}
|
||||
|
||||
/* setup client for reading incoming http */
|
||||
client->refbuf->data [PER_CLIENT_REFBUF_SIZE-1] = '\000';
|
||||
|
||||
if (sock_set_blocking (client->con->sock, 0) || sock_set_nodelay (client->con->sock)) {
|
||||
global_unlock();
|
||||
ICECAST_LOG_WARN("failed to set tcp options on client connection, dropping");
|
||||
client_destroy(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
node = create_client_node(client);
|
||||
global_unlock();
|
||||
|
||||
if (node == NULL) {
|
||||
client_destroy(client);
|
||||
continue;
|
||||
}
|
||||
|
||||
_add_request_queue(node);
|
||||
stats_event_inc(NULL, "connections");
|
||||
connection_queue(con);
|
||||
duration = 5;
|
||||
} else {
|
||||
if (_req_queue == NULL)
|
||||
@ -1569,6 +1573,9 @@ int connection_setup_sockets (ice_config_t *config)
|
||||
|
||||
void connection_close(connection_t *con)
|
||||
{
|
||||
if (!con)
|
||||
return;
|
||||
|
||||
sock_close(con->sock);
|
||||
if (con->ip)
|
||||
free(con->ip);
|
||||
|
@ -60,6 +60,7 @@ int connection_setup_sockets(struct ice_config_tag *config);
|
||||
void connection_close(connection_t *con);
|
||||
connection_t *connection_create(sock_t sock, sock_t serversock, char *ip);
|
||||
int connection_complete_source(struct source_tag *source, int response);
|
||||
void connection_queue(connection_t *con);
|
||||
|
||||
extern rwlock_t _source_shutdown_rwlock;
|
||||
|
||||
|
@ -696,7 +696,7 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
||||
|
||||
config = config_get_config();
|
||||
extra_headers = _build_headers(status, config, source);
|
||||
ret = snprintf (out, len, "%sServer: %s\r\nAccept-Encoding: identity\r\nConnection: close\r\nAllow: %s\r\n%s%s%s%s%s%s%s",
|
||||
ret = snprintf (out, len, "%sServer: %s\r\nAccept-Encoding: identity\r\nAllow: %s\r\n%s%s%s%s%s%s%s",
|
||||
status_buffer,
|
||||
config->server_id,
|
||||
(client->admin_command == ADMIN_COMMAND_ERROR ?
|
||||
|
Loading…
Reference in New Issue
Block a user