mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2025-02-02 15:07:36 -05:00
Fix: Report correct listen URL to client.
The URL is constructed considering Protocol, TLS Mode, Host, and Port. This considers: - The Host:-header as provided by the client, - The effective listensocket of the client, - Global configuration. This works for: - Playlist generation, - Admin authed playlist generation, - Stats based XSLT. It also unifies code: - Default stats values. Not yet included: - YP requests.
This commit is contained in:
parent
33588fc9cf
commit
7742bf0a21
15
src/admin.c
15
src/admin.c
@ -747,7 +747,6 @@ static void command_buildm3u(client_t *client, source_t *source, admin_format_t
|
|||||||
const char *mount = source->mount;
|
const char *mount = source->mount;
|
||||||
const char *username = NULL;
|
const char *username = NULL;
|
||||||
const char *password = NULL;
|
const char *password = NULL;
|
||||||
ice_config_t *config;
|
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
COMMAND_REQUIRE(client, "username", username);
|
COMMAND_REQUIRE(client, "username", username);
|
||||||
@ -766,17 +765,7 @@ static void command_buildm3u(client_t *client, source_t *source, admin_format_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
config = config_get_config();
|
client_get_baseurl(client, NULL, client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret, username, password, "Content-Disposition: attachment; filename=listen.m3u\r\n\r\n", mount, "\r\n");
|
||||||
snprintf(client->refbuf->data + ret, PER_CLIENT_REFBUF_SIZE - ret,
|
|
||||||
"Content-Disposition: attachment; filename=listen.m3u\r\n\r\n"
|
|
||||||
"http://%s:%s@%s:%d%s\r\n",
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
config->hostname,
|
|
||||||
config->port,
|
|
||||||
mount
|
|
||||||
);
|
|
||||||
config_release_config();
|
|
||||||
|
|
||||||
client->respcode = 200;
|
client->respcode = 200;
|
||||||
client->refbuf->len = strlen (client->refbuf->data);
|
client->refbuf->len = strlen (client->refbuf->data);
|
||||||
@ -1131,7 +1120,7 @@ static void command_stats(client_t *client, source_t *source, admin_format_t res
|
|||||||
|
|
||||||
ICECAST_LOG_DEBUG("Stats request, sending xml stats");
|
ICECAST_LOG_DEBUG("Stats request, sending xml stats");
|
||||||
|
|
||||||
doc = stats_get_xml(1, mount, client->mode);
|
doc = stats_get_xml(1, mount, client);
|
||||||
admin_send_response(doc, client, response, STATS_HTML_REQUEST);
|
admin_send_response(doc, client, response, STATS_HTML_REQUEST);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
return;
|
return;
|
||||||
|
89
src/client.c
89
src/client.c
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "acl.h"
|
#include "acl.h"
|
||||||
|
#include "listensocket.h"
|
||||||
|
|
||||||
/* for ADMIN_COMMAND_ERROR */
|
/* for ADMIN_COMMAND_ERROR */
|
||||||
#include "admin.h"
|
#include "admin.h"
|
||||||
@ -766,3 +767,91 @@ client_slurp_result_t client_body_skip(client_t *client)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t client_get_baseurl(client_t *client, listensocket_t *listensocket, char *buf, size_t len, const char *user, const char *pw, const char *prefix, const char *suffix0, const char *suffix1)
|
||||||
|
{
|
||||||
|
const listener_t *listener = NULL;
|
||||||
|
const ice_config_t *config = NULL;
|
||||||
|
const char *host = NULL;
|
||||||
|
const char *proto = "http";
|
||||||
|
int port = 0;
|
||||||
|
ssize_t ret;
|
||||||
|
tlsmode_t tlsmode = ICECAST_TLSMODE_AUTO;
|
||||||
|
protocol_t protocol = ICECAST_PROTOCOL_HTTP;
|
||||||
|
|
||||||
|
if (!buf || !len)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!prefix)
|
||||||
|
prefix = "";
|
||||||
|
|
||||||
|
if (!suffix0)
|
||||||
|
suffix0 = "";
|
||||||
|
|
||||||
|
if (!suffix1)
|
||||||
|
suffix1 = "";
|
||||||
|
|
||||||
|
if (client) {
|
||||||
|
host = httpp_getvar(client->parser, "host");
|
||||||
|
|
||||||
|
/* at least a couple of players (fb2k/winamp) are reported to send a
|
||||||
|
* host header but without the port number. So if we are missing the
|
||||||
|
* port then lets treat it as if no host line was sent */
|
||||||
|
if (host && strchr(host, ':') == NULL)
|
||||||
|
host = NULL;
|
||||||
|
|
||||||
|
listensocket = client->con->listensocket_effective;
|
||||||
|
tlsmode = client->con->tlsmode;
|
||||||
|
protocol = client->protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host && listensocket) {
|
||||||
|
listener = listensocket_get_listener(listensocket);
|
||||||
|
if (listener) {
|
||||||
|
host = listener->bind_address;
|
||||||
|
port = listener->port;
|
||||||
|
if (!client)
|
||||||
|
tlsmode = listener->tls;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host) {
|
||||||
|
config = config_get_config();
|
||||||
|
host = config->hostname;
|
||||||
|
if (!port)
|
||||||
|
port = config->port;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tlsmode) {
|
||||||
|
case ICECAST_TLSMODE_DISABLED:
|
||||||
|
case ICECAST_TLSMODE_AUTO:
|
||||||
|
switch (protocol) {
|
||||||
|
case ICECAST_PROTOCOL_HTTP: proto = "http"; break;
|
||||||
|
case ICECAST_PROTOCOL_SHOUTCAST: proto = "icy"; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ICECAST_TLSMODE_AUTO_NO_PLAIN:
|
||||||
|
case ICECAST_TLSMODE_RFC2817:
|
||||||
|
case ICECAST_TLSMODE_RFC2818:
|
||||||
|
switch (protocol) {
|
||||||
|
case ICECAST_PROTOCOL_HTTP: proto = "https"; break;
|
||||||
|
case ICECAST_PROTOCOL_SHOUTCAST: proto = "icys"; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host && port) {
|
||||||
|
ret = snprintf(buf, len, "%s%s://%s%s%s%s%s:%i%s%s", prefix, proto, user ? user : "", pw ? ":" : "", pw ? pw : "", (user || pw) ? "@" : "", host, port, suffix0, suffix1);
|
||||||
|
} else if (host) {
|
||||||
|
ret = snprintf(buf, len, "%s%s://%s%s%s%s%s%s%s", prefix, proto, user ? user : "", pw ? ":" : "", pw ? pw : "", (user || pw) ? "@" : "", host, suffix0, suffix1);
|
||||||
|
} else {
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config)
|
||||||
|
config_release_config();
|
||||||
|
if (listener)
|
||||||
|
listensocket_release_listener(listensocket);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -151,5 +151,6 @@ ssize_t client_body_read(client_t *client, void *buf, size_t len);
|
|||||||
int client_body_eof(client_t *client);
|
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_slurp(client_t *client, void *buf, size_t *len);
|
||||||
client_slurp_result_t client_body_skip(client_t *client);
|
client_slurp_result_t client_body_skip(client_t *client);
|
||||||
|
ssize_t client_get_baseurl(client_t *client, listensocket_t *listensocket, char *buf, size_t len, const char *user, const char *pw, const char *prefix, const char *suffix0, const char *suffix1);
|
||||||
|
|
||||||
#endif /* __CLIENT_H__ */
|
#endif /* __CLIENT_H__ */
|
||||||
|
28
src/fserve.c
28
src/fserve.c
@ -452,16 +452,9 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
|
|
||||||
if (m3u_requested && m3u_file_available == 0)
|
if (m3u_requested && m3u_file_available == 0)
|
||||||
{
|
{
|
||||||
const char *host = httpp_getvar (httpclient->parser, "host");
|
|
||||||
char *sourceuri = strdup (path);
|
char *sourceuri = strdup (path);
|
||||||
char *dot = strrchr(sourceuri, '.');
|
char *dot = strrchr(sourceuri, '.');
|
||||||
|
|
||||||
/* at least a couple of players (fb2k/winamp) are reported to send a
|
|
||||||
* host header but without the port number. So if we are missing the
|
|
||||||
* port then lets treat it as if no host line was sent */
|
|
||||||
if (host && strchr (host, ':') == NULL)
|
|
||||||
host = NULL;
|
|
||||||
|
|
||||||
*dot = 0;
|
*dot = 0;
|
||||||
httpclient->respcode = 200;
|
httpclient->respcode = 200;
|
||||||
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0,
|
||||||
@ -473,24 +466,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
free(sourceuri);
|
free(sourceuri);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (host == NULL)
|
client_get_baseurl(httpclient, NULL, httpclient->refbuf->data + ret, BUFSIZE - ret, NULL, NULL, NULL, sourceuri, "\r\n");
|
||||||
{
|
|
||||||
config = config_get_config();
|
|
||||||
snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret,
|
|
||||||
"http://%s:%d%s\r\n",
|
|
||||||
config->hostname, config->port,
|
|
||||||
sourceuri
|
|
||||||
);
|
|
||||||
config_release_config();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
snprintf (httpclient->refbuf->data + ret, BUFSIZE - ret,
|
|
||||||
"http://%s%s\r\n",
|
|
||||||
host,
|
|
||||||
sourceuri
|
|
||||||
);
|
|
||||||
}
|
|
||||||
httpclient->refbuf->len = strlen (httpclient->refbuf->data);
|
httpclient->refbuf->len = strlen (httpclient->refbuf->data);
|
||||||
fserve_add_client (httpclient, NULL);
|
fserve_add_client (httpclient, NULL);
|
||||||
free (sourceuri);
|
free (sourceuri);
|
||||||
@ -504,7 +480,7 @@ int fserve_client_create (client_t *httpclient, const char *path)
|
|||||||
char *eol = strrchr (reference, '.');
|
char *eol = strrchr (reference, '.');
|
||||||
if (eol)
|
if (eol)
|
||||||
*eol = '\0';
|
*eol = '\0';
|
||||||
doc = stats_get_xml (0, reference, httpclient->mode);
|
doc = stats_get_xml (0, reference, httpclient);
|
||||||
free (reference);
|
free (reference);
|
||||||
admin_send_response (doc, httpclient, ADMIN_FORMAT_HTML, xslt_playlist_requested);
|
admin_send_response (doc, httpclient, ADMIN_FORMAT_HTML, xslt_playlist_requested);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
16
src/source.c
16
src/source.c
@ -616,19 +616,8 @@ static FILE * source_open_dumpfile(const char * filename) {
|
|||||||
*/
|
*/
|
||||||
static void source_init (source_t *source)
|
static void source_init (source_t *source)
|
||||||
{
|
{
|
||||||
ice_config_t *config = config_get_config();
|
char listenurl[512];
|
||||||
char *listenurl;
|
|
||||||
const char *str;
|
const char *str;
|
||||||
int listen_url_size;
|
|
||||||
|
|
||||||
/* 6 for max size of port */
|
|
||||||
listen_url_size = strlen("http://") + strlen(config->hostname) +
|
|
||||||
strlen(":") + 6 + strlen(source->mount) + 1;
|
|
||||||
|
|
||||||
listenurl = malloc (listen_url_size);
|
|
||||||
snprintf (listenurl, listen_url_size, "http://%s:%d%s",
|
|
||||||
config->hostname, config->port, source->mount);
|
|
||||||
config_release_config();
|
|
||||||
|
|
||||||
str = httpp_getvar(source->parser, "ice-audio-info");
|
str = httpp_getvar(source->parser, "ice-audio-info");
|
||||||
source->audio_info = util_dict_new();
|
source->audio_info = util_dict_new();
|
||||||
@ -638,10 +627,9 @@ static void source_init (source_t *source)
|
|||||||
stats_event (source->mount, "audio_info", str);
|
stats_event (source->mount, "audio_info", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_get_baseurl(NULL, NULL, listenurl, sizeof(listenurl), NULL, NULL, NULL, NULL, NULL);
|
||||||
stats_event (source->mount, "listenurl", listenurl);
|
stats_event (source->mount, "listenurl", listenurl);
|
||||||
|
|
||||||
free(listenurl);
|
|
||||||
|
|
||||||
if (source->dumpfilename != NULL)
|
if (source->dumpfilename != NULL)
|
||||||
{
|
{
|
||||||
source->dumpfile = source_open_dumpfile (source->dumpfilename);
|
source->dumpfile = source_open_dumpfile (source->dumpfilename);
|
||||||
|
18
src/stats.c
18
src/stats.c
@ -829,7 +829,7 @@ static inline void __add_authstack (auth_stack_t *stack, xmlNodePtr parent) {
|
|||||||
auth_stack_next(&stack);
|
auth_stack_next(&stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden) {
|
static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, int hidden, client_t *client) {
|
||||||
avl_node *avlnode;
|
avl_node *avlnode;
|
||||||
xmlNodePtr ret = NULL;
|
xmlNodePtr ret = NULL;
|
||||||
ice_config_t *config;
|
ice_config_t *config;
|
||||||
@ -870,7 +870,13 @@ static xmlNodePtr _dump_stats_to_doc (xmlNodePtr root, const char *show_mount, i
|
|||||||
while (avlnode2)
|
while (avlnode2)
|
||||||
{
|
{
|
||||||
stats_node_t *stat = avlnode2->key;
|
stats_node_t *stat = avlnode2->key;
|
||||||
xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
|
if (client && strcmp(stat->name, "listenurl") == 0) {
|
||||||
|
char buf[512];
|
||||||
|
client_get_baseurl(client, NULL, buf, sizeof(buf), NULL, NULL, NULL, source->source, NULL);
|
||||||
|
xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(buf));
|
||||||
|
} else {
|
||||||
|
xmlNewTextChild (xmlnode, NULL, XMLSTR(stat->name), XMLSTR(stat->value));
|
||||||
|
}
|
||||||
avlnode2 = avl_get_next (avlnode2);
|
avlnode2 = avl_get_next (avlnode2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1022,7 +1028,7 @@ void stats_transform_xslt(client_t *client, const char *uri)
|
|||||||
char *xslpath = util_get_path_from_normalised_uri(uri);
|
char *xslpath = util_get_path_from_normalised_uri(uri);
|
||||||
const char *mount = httpp_get_param(client->parser, "mount");
|
const char *mount = httpp_get_param(client->parser, "mount");
|
||||||
|
|
||||||
doc = stats_get_xml(0, mount, client->mode);
|
doc = stats_get_xml(0, mount, client);
|
||||||
|
|
||||||
xslt_transform(doc, xslpath, client, 200);
|
xslt_transform(doc, xslpath, client, 200);
|
||||||
|
|
||||||
@ -1053,7 +1059,7 @@ static void __add_metadata(xmlNodePtr node, const char *tag) {
|
|||||||
free(name);
|
free(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode mode)
|
xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, client_t *client)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc;
|
xmlDocPtr doc;
|
||||||
xmlNodePtr node;
|
xmlNodePtr node;
|
||||||
@ -1063,12 +1069,12 @@ xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode
|
|||||||
node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL);
|
node = xmlNewDocNode (doc, NULL, XMLSTR("icestats"), NULL);
|
||||||
xmlDocSetRootElement(doc, node);
|
xmlDocSetRootElement(doc, node);
|
||||||
|
|
||||||
node = _dump_stats_to_doc (node, show_mount, show_hidden);
|
node = _dump_stats_to_doc(node, show_mount, show_hidden, client);
|
||||||
|
|
||||||
if (show_mount && node) {
|
if (show_mount && node) {
|
||||||
avl_tree_rlock(global.source_tree);
|
avl_tree_rlock(global.source_tree);
|
||||||
source = source_find_mount_raw(show_mount);
|
source = source_find_mount_raw(show_mount);
|
||||||
admin_add_listeners_to_mount(source, node, mode);
|
admin_add_listeners_to_mount(source, node, client->mode);
|
||||||
avl_tree_unlock(global.source_tree);
|
avl_tree_unlock(global.source_tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@
|
|||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
|
||||||
#include "icecasttypes.h"
|
#include "icecasttypes.h"
|
||||||
#include "cfgfile.h"
|
|
||||||
#include "refbuf.h"
|
#include "refbuf.h"
|
||||||
|
|
||||||
typedef struct _stats_node_tag
|
typedef struct _stats_node_tag
|
||||||
@ -95,7 +94,7 @@ void stats_callback (client_t *client, void *notused);
|
|||||||
|
|
||||||
void stats_transform_xslt(client_t *client, const char *uri);
|
void stats_transform_xslt(client_t *client, const char *uri);
|
||||||
void stats_sendxml(client_t *client);
|
void stats_sendxml(client_t *client);
|
||||||
xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, operation_mode mode);
|
xmlDocPtr stats_get_xml(int show_hidden, const char *show_mount, client_t *client);
|
||||||
char *stats_get_value(const char *source, const char *name);
|
char *stats_get_value(const char *source, const char *name);
|
||||||
|
|
||||||
#endif /* __STATS_H__ */
|
#endif /* __STATS_H__ */
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
#include "fserve.h"
|
#include "fserve.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "cfgfile.h"
|
||||||
|
|
||||||
#define CATMODULE "xslt"
|
#define CATMODULE "xslt"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user