mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Feature: Implemented Gopher support.
Gopher clients are automagically detected based on the selector. All selectors must start with / and map directly to the HTTP paths.
This commit is contained in:
parent
d56189eca9
commit
0c099de57e
33
src/client.c
33
src/client.c
@ -272,7 +272,7 @@ void client_destroy(client_t *client)
|
|||||||
|
|
||||||
fastevent_emit(FASTEVENT_TYPE_CLIENT_DESTROY, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
fastevent_emit(FASTEVENT_TYPE_CLIENT_DESTROY, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
||||||
|
|
||||||
if (client->reuse != ICECAST_REUSE_CLOSE) {
|
if (client->protocol != ICECAST_PROTOCOL_GOPHER && client->reuse != ICECAST_REUSE_CLOSE) {
|
||||||
/* only reuse the client if we reached the body's EOF. */
|
/* only reuse the client if we reached the body's EOF. */
|
||||||
if (client_body_eof(client) == 1) {
|
if (client_body_eof(client) == 1) {
|
||||||
client_reuseconnection(client);
|
client_reuseconnection(client);
|
||||||
@ -287,6 +287,10 @@ void client_destroy(client_t *client)
|
|||||||
if (auth_release_client(client))
|
if (auth_release_client(client))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (client->protocol == ICECAST_PROTOCOL_GOPHER && client->respcode != 0) {
|
||||||
|
client_send_bytes(client, "\r\n.\r\n", 5);
|
||||||
|
}
|
||||||
|
|
||||||
/* write log entry if ip is set (some things don't set it, like outgoing
|
/* write log entry if ip is set (some things don't set it, like outgoing
|
||||||
* slave requests
|
* slave requests
|
||||||
*/
|
*/
|
||||||
@ -511,19 +515,26 @@ void client_send_426(client_t *client, reuse_t reuse)
|
|||||||
/* this function is designed to work even if client is in bad state */
|
/* this function is designed to work even if client is in bad state */
|
||||||
static inline void client_send_500(client_t *client, const char *message)
|
static inline 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"
|
const char header_http[] = "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";
|
"500 - Internal Server Error\n---------------------------\n";
|
||||||
const ssize_t header_len = sizeof(header) - 1;
|
const char header_gopher[] = "Internal Server Error\n---------------------------\n";
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
client->respcode = 500;
|
client->respcode = 500;
|
||||||
client->refbuf->len = 0;
|
client->refbuf->len = 0;
|
||||||
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
fastevent_emit(FASTEVENT_TYPE_CLIENT_SEND_RESPONSE, FASTEVENT_FLAG_MODIFICATION_ALLOWED, FASTEVENT_DATATYPE_CLIENT, client);
|
||||||
|
|
||||||
ret = client_send_bytes(client, header, header_len);
|
if (client->protocol == ICECAST_PROTOCOL_GOPHER) {
|
||||||
|
len = sizeof(header_gopher) - 1;
|
||||||
|
ret = client_send_bytes(client, header_gopher, len);
|
||||||
|
} else {
|
||||||
|
len = sizeof(header_http) - 1;
|
||||||
|
ret = client_send_bytes(client, header_http, len);
|
||||||
|
}
|
||||||
|
|
||||||
/* only send message if we have one AND if header could have transmitted completly */
|
/* only send message if we have one AND if header could have transmitted completly */
|
||||||
if (message && ret == header_len)
|
if (message && ret == len)
|
||||||
client_send_bytes(client, message, strlen(message));
|
client_send_bytes(client, message, strlen(message));
|
||||||
|
|
||||||
client_destroy(client);
|
client_destroy(client);
|
||||||
@ -656,10 +667,14 @@ void client_send_reportxml(client_t *client, reportxml_t *report, document_domai
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: in this section we hope no function will ever return -1 */
|
/* FIXME: in this section we hope no function will ever return -1 */
|
||||||
if (location) {
|
if (client->protocol == ICECAST_PROTOCOL_GOPHER) {
|
||||||
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Location: %s\r\n", location);
|
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "%s", buff);
|
||||||
|
} else {
|
||||||
|
if (location) {
|
||||||
|
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Location: %s\r\n", location);
|
||||||
|
}
|
||||||
|
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
||||||
}
|
}
|
||||||
ret += snprintf(client->refbuf->data + ret, buf_len - ret, "Content-Length: %d\r\n\r\n%s", xmlStrlen(buff), buff);
|
|
||||||
|
|
||||||
client->refbuf->len = ret;
|
client->refbuf->len = ret;
|
||||||
xmlFree(buff);
|
xmlFree(buff);
|
||||||
|
@ -503,6 +503,8 @@ static void process_request_queue (void)
|
|||||||
stream_offset = (ptr+2) - client->refbuf->data;
|
stream_offset = (ptr+2) - client->refbuf->data;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (client->refbuf->data[0] == '/' && strstr(client->refbuf->data, "\n") != NULL)
|
||||||
|
break;
|
||||||
pass_it = 0;
|
pass_it = 0;
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
@ -1198,6 +1200,49 @@ static void _handle_shoutcast_compatible(client_queue_t *node)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _handle_gopher_compatible(client_queue_t *node)
|
||||||
|
{
|
||||||
|
size_t n_len;
|
||||||
|
char *n;
|
||||||
|
char *ptr;
|
||||||
|
http_parser_t *parser;
|
||||||
|
client_t *client = node->client;
|
||||||
|
|
||||||
|
ptr = strstr(client->refbuf->data, "\r\n");
|
||||||
|
if (!ptr)
|
||||||
|
ptr = strstr(client->refbuf->data, "\n");
|
||||||
|
if (!ptr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
n_len = strlen(client->refbuf->data) + 80;
|
||||||
|
n = calloc(1, n_len);
|
||||||
|
if (!n) {
|
||||||
|
client_destroy(client);
|
||||||
|
free(node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(n, n_len, "GET %s HTTP/1.0\r\n\r\n", client->refbuf->data);
|
||||||
|
|
||||||
|
parser = httpp_create_parser();
|
||||||
|
httpp_initialize(parser, NULL);
|
||||||
|
if (httpp_parse(parser, n, strlen(n))) {
|
||||||
|
client->refbuf->len = 0;
|
||||||
|
client->parser = parser;
|
||||||
|
client->protocol = ICECAST_PROTOCOL_GOPHER;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
httpp_destroy(parser);
|
||||||
|
client_destroy(client);
|
||||||
|
}
|
||||||
|
free(n);
|
||||||
|
free(node);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Handle <resource> lookups here.
|
/* Handle <resource> lookups here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1610,6 +1655,13 @@ static void _handle_connection(void)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for gopher clients */
|
||||||
|
if (client->refbuf->data[0] == '/') {
|
||||||
|
if (_handle_gopher_compatible(node) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* process normal HTTP headers */
|
/* process normal HTTP headers */
|
||||||
if (client->parser) {
|
if (client->parser) {
|
||||||
already_parsed = 1;
|
already_parsed = 1;
|
||||||
|
10
src/fserve.c
10
src/fserve.c
@ -596,10 +596,12 @@ int fserve_client_create (client_t *httpclient)
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
if (httpclient->protocol != ICECAST_PROTOCOL_GOPHER) {
|
||||||
"Accept-Ranges: bytes\r\n"
|
bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes,
|
||||||
"Content-Length: %" PRI_OFF_T "\r\n\r\n",
|
"Accept-Ranges: bytes\r\n"
|
||||||
content_length);
|
"Content-Length: %" PRI_OFF_T "\r\n\r\n",
|
||||||
|
content_length);
|
||||||
|
}
|
||||||
free (type);
|
free (type);
|
||||||
}
|
}
|
||||||
httpclient->refbuf->len = bytes;
|
httpclient->refbuf->len = bytes;
|
||||||
|
@ -740,6 +740,10 @@ ssize_t util_http_build_header(char * out, size_t len, ssize_t offset,
|
|||||||
out += offset;
|
out += offset;
|
||||||
len -= offset;
|
len -= offset;
|
||||||
|
|
||||||
|
if (client && client->protocol == ICECAST_PROTOCOL_GOPHER) {
|
||||||
|
return snprintf(out, len, "%s", (datablock) ? datablock : "");
|
||||||
|
}
|
||||||
|
|
||||||
if (status == -1)
|
if (status == -1)
|
||||||
{
|
{
|
||||||
status_buffer[0] = '\0';
|
status_buffer[0] = '\0';
|
||||||
|
10
src/xslt.c
10
src/xslt.c
@ -417,10 +417,14 @@ void xslt_transform(xmlDocPtr doc, const char *xslfilename, client_t *client, in
|
|||||||
|
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
/* FIXME: in this section we hope no function will ever return -1 */
|
/* FIXME: in this section we hope no function will ever return -1 */
|
||||||
if (location) {
|
if (client->protocol == ICECAST_PROTOCOL_GOPHER) {
|
||||||
ret += snprintf(refbuf->data + ret, full_len - ret, "Location: %s\r\n", location);
|
snprintf(refbuf->data + ret, full_len - ret, "%s", string);
|
||||||
|
} else {
|
||||||
|
if (location) {
|
||||||
|
ret += snprintf(refbuf->data + ret, full_len - ret, "Location: %s\r\n", location);
|
||||||
|
}
|
||||||
|
ret += snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
||||||
}
|
}
|
||||||
ret += snprintf(refbuf->data + ret, full_len - ret, "Content-Length: %d\r\n\r\n%s", len, string);
|
|
||||||
|
|
||||||
client->respcode = status;
|
client->respcode = status;
|
||||||
client_set_queue (client, NULL);
|
client_set_queue (client, NULL);
|
||||||
|
Loading…
Reference in New Issue
Block a user