void stats_transform_xslt(client_t *client, char *xslpath) { xmlDocPtr doc; stats_get_xml(&doc); xslt_transform(doc, xslpath, client); xmlFreeDoc(doc); }
static void command_stats(client_t *client, const char *mount, int response) { xmlDocPtr doc; DEBUG0("Stats request, sending xml stats"); stats_get_xml(&doc, 1, mount); admin_send_response(doc, client, response, STATS_TRANSFORMED_REQUEST); xmlFreeDoc(doc); return; }
static int command_shoutcast_metadata (client_t *client, source_t *source) { const char *action; const char *value; int same_ip = 1; if (COMMAND_REQUIRE(client, "mode", action) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, mode"); } if ((source->flags & SOURCE_SHOUTCAST_COMPAT) == 0) { thread_mutex_unlock (&source->lock); ERROR0 ("illegal request on non-shoutcast compatible stream"); return client_send_400 (client, "Not a shoutcast compatible stream"); } if (strcmp (action, "updinfo") == 0) { DEBUG0("Got shoutcast metadata update request"); if (COMMAND_REQUIRE (client, "song", value) < 0) { thread_mutex_unlock (&source->lock); return client_send_400 (client, "missing arg, song"); } if (source->client && strcmp (client->connection.ip, source->client->connection.ip) != 0) if (connection_check_admin_pass (client->parser) == 0) same_ip = 0; if (same_ip && source->format && source->format->set_tag) { httpp_set_query_param (client->parser, "mount", client->server_conn->shoutcast_mount); source->format->set_tag (source->format, "title", value, NULL); source->format->set_tag (source->format, NULL, NULL, NULL); DEBUG2("Metadata on mountpoint %s changed to \"%s\"", source->mount, value); thread_mutex_unlock (&source->lock); return html_success(client, "Metadata update successful"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "mountpoint will not accept URL updates"); } if (strcmp (action, "viewxml") == 0) { xmlDocPtr doc; DEBUG0("Got shoutcast viewxml request"); thread_mutex_unlock (&source->lock); doc = stats_get_xml (STATS_ALL, source->mount); return admin_send_response (doc, client, XSLT, "viewxml.xsl"); } thread_mutex_unlock (&source->lock); return client_send_400 (client, "No such action"); }
void stats_transform_xslt(client_t *client, const char *uri) { xmlDocPtr doc; char *xslpath = util_get_path_from_normalised_uri (uri); stats_get_xml(&doc, 0); xslt_transform(doc, xslpath, client); xmlFreeDoc(doc); free (xslpath); }
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"); doc = stats_get_xml(0, mount, client->mode); xslt_transform(doc, xslpath, client); xmlFreeDoc(doc); free(xslpath); }
/* catch all function for admin requests. If file has xsl extension then * transform it using the available stats, else send the XML tree of the * stats */ static int command_stats (client_t *client, const char *filename) { admin_response_type response = RAW; const char *show_mount = NULL; xmlDocPtr doc; if (filename) if (util_check_valid_extension (filename) == XSLT_CONTENT) response = XSLT; show_mount = httpp_get_query_param (client->parser, "mount"); doc = stats_get_xml (STATS_ALL, show_mount); return admin_send_response (doc, client, response, filename); }
int stats_transform_xslt (client_t *client, const char *uri) { xmlDocPtr doc; char *xslpath = util_get_path_from_normalised_uri (uri, 0); const char *mount = httpp_get_query_param (client->parser, "mount"); int ret; if (mount == NULL && client->server_conn->shoutcast_mount && strcmp (uri, "/7.xsl") == 0) mount = client->server_conn->shoutcast_mount; doc = stats_get_xml (STATS_PUBLIC, mount); ret = xslt_transform (doc, xslpath, client); xmlFreeDoc(doc); free (xslpath); return ret; }
/* client has requested a file, so check for it and send the file. Do not * refer to the client_t afterwards. return 0 for success, -1 on error. */ int fserve_client_create (client_t *httpclient, const char *path) { struct stat file_buf; char *fullpath; int m3u_requested = 0, m3u_file_available = 1; int xspf_requested = 0, xspf_file_available = 1; int ret = -1; ice_config_t *config; fbinfo finfo; char fsize[20]; fullpath = util_get_path_from_normalised_uri (path, 0); DEBUG2 ("checking for file %s (%s)", path, fullpath); if (strcmp (util_get_extension (fullpath), "m3u") == 0) m3u_requested = 1; if (strcmp (util_get_extension (fullpath), "xspf") == 0) xspf_requested = 1; /* check for the actual file */ if (stat (fullpath, &file_buf) != 0) { /* the m3u can be generated, but send an m3u file if available */ if (m3u_requested == 0 && xspf_requested == 0) { if (redirect_client (path, httpclient) == 0) { if ((httpclient->flags & CLIENT_SKIP_ACCESSLOG) == 0) WARN2 ("req for file \"%s\" %s", fullpath, strerror (errno)); ret = client_send_404 (httpclient, "The file you requested could not be found"); } free (fullpath); return ret; } m3u_file_available = 0; xspf_file_available = 0; } client_set_queue (httpclient, NULL); httpclient->refbuf = refbuf_new (4096); if (m3u_requested && m3u_file_available == 0) { const char *host = httpp_getvar (httpclient->parser, "host"), *args = httpp_getvar (httpclient->parser, HTTPP_VAR_QUERYARGS), *at = "", *user = "", *pass =""; char *sourceuri = strdup (path); char *dot = strrchr (sourceuri, '.'); char *protocol = "http"; const char *agent = httpp_getvar (httpclient->parser, "user-agent"); int x; char scratch[1000]; if (agent) { if (strstr (agent, "QTS") || strstr (agent, "QuickTime")) protocol = "icy"; } /* 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; if (httpclient->username && httpclient->password) { at = "@"; user = httpclient->username; pass = httpclient->password; } httpclient->respcode = 200; if (host == NULL) { config = config_get_config(); x = snprintf (scratch, sizeof scratch, "%s://%s%s%s%s%s:%d%s%s\r\n", protocol, user, at[0]?":":"", pass, at, config->hostname, config->port, sourceuri, args?args:""); config_release_config(); } else { x = snprintf (scratch, sizeof scratch, "%s://%s%s%s%s%s%s%s\r\n", protocol, user, at[0]?":":"", pass, at, host, sourceuri, args?args:""); } snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.0 200 OK\r\n" "Content-Length: %d\r\n" "%s\r\n" "Content-Type: audio/x-mpegurl\r\n\r\n%s", x, client_keepalive_header (httpclient), scratch); httpclient->refbuf->len = strlen (httpclient->refbuf->data); free (sourceuri); free (fullpath); return fserve_setup_client_fb (httpclient, NULL); } if (xspf_requested && xspf_file_available == 0) { xmlDocPtr doc; char *reference = strdup (path); char *eol = strrchr (reference, '.'); if (eol) *eol = '\0'; doc = stats_get_xml (0, reference); free (reference); free (fullpath); return admin_send_response (doc, httpclient, XSLT, "xspf.xsl"); } /* on demand file serving check */ config = config_get_config(); if (config->fileserve == 0) { config_release_config(); DEBUG1 ("on demand file \"%s\" refused", fullpath); free (fullpath); return client_send_404 (httpclient, "The file you requested could not be found"); } config_release_config(); if (S_ISREG (file_buf.st_mode) == 0) { WARN1 ("found requested file but there is no handler for it: %s", fullpath); free (fullpath); return client_send_404 (httpclient, "The file you requested could not be found"); } free (fullpath); finfo.flags = 0; finfo.mount = (char *)path; finfo.fallback = NULL; finfo.limit = 0; finfo.type = FORMAT_TYPE_UNDEFINED; snprintf (fsize, 20, "%" PRId64, (int64_t)file_buf.st_size); httpp_setvar (httpclient->parser, "__FILESIZE", fsize); stats_event_inc (NULL, "file_connections"); return fserve_setup_client_fb (httpclient, &finfo); }
/* client has requested a file, so check for it and send the file. Do not * refer to the client_t afterwards. return 0 for success, -1 on error. */ int fserve_client_create (client_t *httpclient) { int bytes; struct stat file_buf; const char *range = NULL; off_t new_content_len = 0; off_t rangenumber = 0, content_length; int rangeproblem = 0; int ret = 0; char *fullpath; int m3u_requested = 0, m3u_file_available = 1; const char * xslt_playlist_requested = NULL; int xslt_playlist_file_available = 1; ice_config_t *config; FILE *file; fullpath = util_get_path_from_normalised_uri(httpclient->uri); ICECAST_LOG_INFO("checking for file %H (%H)", httpclient->uri, fullpath); if (strcmp (util_get_extension (fullpath), "m3u") == 0) m3u_requested = 1; if (strcmp (util_get_extension (fullpath), "xspf") == 0) xslt_playlist_requested = "xspf.xsl"; if (strcmp (util_get_extension (fullpath), "vclt") == 0) xslt_playlist_requested = "vclt.xsl"; /* check for the actual file */ if (stat (fullpath, &file_buf) != 0) { /* the m3u can be generated, but send an m3u file if available */ if (m3u_requested == 0 && xslt_playlist_requested == NULL) { ICECAST_LOG_WARN("req for file \"%H\" %s", fullpath, strerror (errno)); client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); free (fullpath); return -1; } m3u_file_available = 0; xslt_playlist_file_available = 0; } httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE; if (m3u_requested && m3u_file_available == 0) { char *sourceuri = strdup(httpclient->uri); char *dot = strrchr(sourceuri, '.'); *dot = 0; httpclient->respcode = 200; ret = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, "audio/x-mpegurl", NULL, "", NULL, httpclient); if (ret == -1 || ret >= (BUFSIZE - 512)) { /* we want at least 512 bytes left for the content of the playlist */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); free(sourceuri); return -1; } client_get_baseurl(httpclient, NULL, httpclient->refbuf->data + ret, BUFSIZE - ret, NULL, NULL, NULL, sourceuri, "\r\n"); httpclient->refbuf->len = strlen (httpclient->refbuf->data); fserve_add_client (httpclient, NULL); free (sourceuri); free (fullpath); return 0; } if (xslt_playlist_requested && xslt_playlist_file_available == 0) { xmlDocPtr doc; char *reference = strdup(httpclient->uri); char *eol = strrchr (reference, '.'); if (eol) *eol = '\0'; doc = stats_get_xml (0, reference, httpclient); free (reference); admin_send_response (doc, httpclient, ADMIN_FORMAT_HTML, xslt_playlist_requested); xmlFreeDoc(doc); free (fullpath); return 0; } /* on demand file serving check */ config = config_get_config(); if (config->fileserve == 0) { ICECAST_LOG_DEBUG("on demand file \"%H\" refused. Serving static files has been disabled in the config", fullpath); client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); config_release_config(); free(fullpath); return -1; } config_release_config(); if (S_ISREG (file_buf.st_mode) == 0) { client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_FOUND); ICECAST_LOG_WARN("found requested file but there is no handler for it: %H", fullpath); free (fullpath); return -1; } file = fopen (fullpath, "rb"); if (file == NULL) { ICECAST_LOG_WARN("Problem accessing file \"%H\"", fullpath); client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_FILE_NOT_READABLE); free (fullpath); return -1; } free (fullpath); content_length = file_buf.st_size; range = httpp_getvar (httpclient->parser, "range"); /* full http range handling is currently not done but we deal with the common case */ if (range != NULL) { ret = 0; if (strncasecmp (range, "bytes=", 6) == 0) ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber); if (ret != 1) { /* format not correct, so lets just assume we start from the beginning */ rangeproblem = 1; } if (rangenumber < 0) { rangeproblem = 1; } if (!rangeproblem) { ret = fseeko (file, rangenumber, SEEK_SET); if (ret != -1) { new_content_len = content_length - rangenumber; if (new_content_len < 0) { rangeproblem = 1; } } else { rangeproblem = 1; } if (!rangeproblem) { off_t endpos = rangenumber+new_content_len-1; char *type; if (endpos < 0) { endpos = 0; } httpclient->respcode = 206; type = fserve_content_type(httpclient->uri); bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 206, NULL, type, NULL, NULL, NULL, httpclient); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" "Content-Range: bytes %" PRI_OFF_T \ "-%" PRI_OFF_T "/%" PRI_OFF_T "\r\n\r\n", new_content_len, rangenumber, endpos, content_length); free (type); } else { goto fail; } } else { goto fail; } } else { char *type = fserve_content_type(httpclient->uri); httpclient->respcode = 200; bytes = util_http_build_header (httpclient->refbuf->data, BUFSIZE, 0, 0, 200, NULL, type, NULL, NULL, NULL, httpclient); if (bytes == -1 || bytes >= (BUFSIZE - 512)) { /* we want at least 512 bytes left */ ICECAST_LOG_ERROR("Dropping client as we can not build response headers."); client_send_error_by_id(httpclient, ICECAST_ERROR_GEN_HEADER_GEN_FAILED); fclose(file); return -1; } bytes += snprintf (httpclient->refbuf->data + bytes, BUFSIZE - bytes, "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n\r\n", content_length); free (type); } httpclient->refbuf->len = bytes; httpclient->pos = 0; stats_event_inc (NULL, "file_connections"); fserve_add_client (httpclient, file); return 0; fail: fclose (file); client_send_error_by_id(httpclient, ICECAST_ERROR_FSERV_REQUEST_RANGE_NOT_SATISFIABLE); return -1; }
/* client has requested a file, so check for it and send the file. Do not * refer to the client_t afterwards. return 0 for success, -1 on error. */ int fserve_client_create (client_t *httpclient, const char *path) { int bytes; struct stat file_buf; const char *range = NULL; off_t new_content_len = 0; off_t rangenumber = 0, content_length; int rangeproblem = 0; int ret = 0; char *fullpath; int m3u_requested = 0, m3u_file_available = 1; const char * xslt_playlist_requested = NULL; int xslt_playlist_file_available = 1; ice_config_t *config; FILE *file; fullpath = util_get_path_from_normalised_uri (path); INFO2 ("checking for file %H (%H)", path, fullpath); if (strcmp (util_get_extension (fullpath), "m3u") == 0) m3u_requested = 1; if (strcmp (util_get_extension (fullpath), "xspf") == 0) xslt_playlist_requested = "xspf.xsl"; if (strcmp (util_get_extension (fullpath), "vclt") == 0) xslt_playlist_requested = "vclt.xsl"; /* check for the actual file */ if (stat (fullpath, &file_buf) != 0) { /* the m3u can be generated, but send an m3u file if available */ if (m3u_requested == 0 && xslt_playlist_requested == NULL) { WARN2 ("req for file \"%H\" %s", fullpath, strerror (errno)); client_send_404 (httpclient, "The file you requested could not be found"); free (fullpath); return -1; } m3u_file_available = 0; xslt_playlist_file_available = 0; } httpclient->refbuf->len = PER_CLIENT_REFBUF_SIZE; if (m3u_requested && m3u_file_available == 0) { const char *host = httpp_getvar (httpclient->parser, "host"); char *sourceuri = strdup (path); 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; httpclient->respcode = 200; if (host == NULL) { config = config_get_config(); snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.0 200 OK\r\n" "Content-Type: audio/x-mpegurl\r\n\r\n" "http://%s:%d%s\r\n", config->hostname, config->port, sourceuri ); config_release_config(); } else { snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.0 200 OK\r\n" "Content-Type: audio/x-mpegurl\r\n\r\n" "http://%s%s\r\n", host, sourceuri ); } httpclient->refbuf->len = strlen (httpclient->refbuf->data); fserve_add_client (httpclient, NULL); free (sourceuri); free (fullpath); return 0; } if (xslt_playlist_requested && xslt_playlist_file_available == 0) { xmlDocPtr doc; char *reference = strdup (path); char *eol = strrchr (reference, '.'); if (eol) *eol = '\0'; doc = stats_get_xml (0, reference); free (reference); admin_send_response (doc, httpclient, TRANSFORMED, xslt_playlist_requested); xmlFreeDoc(doc); return 0; } /* on demand file serving check */ config = config_get_config(); if (config->fileserve == 0) { DEBUG1 ("on demand file \"%H\" refused", fullpath); client_send_404 (httpclient, "The file you requested could not be found"); config_release_config(); free (fullpath); return -1; } config_release_config(); if (S_ISREG (file_buf.st_mode) == 0) { client_send_404 (httpclient, "The file you requested could not be found"); WARN1 ("found requested file but there is no handler for it: %H", fullpath); free (fullpath); return -1; } file = fopen (fullpath, "rb"); if (file == NULL) { WARN1 ("Problem accessing file \"%H\"", fullpath); client_send_404 (httpclient, "File not readable"); free (fullpath); return -1; } free (fullpath); content_length = file_buf.st_size; range = httpp_getvar (httpclient->parser, "range"); /* full http range handling is currently not done but we deal with the common case */ if (range != NULL) { ret = 0; if (strncasecmp (range, "bytes=", 6) == 0) ret = sscanf (range+6, "%" SCN_OFF_T "-", &rangenumber); if (ret != 1) { /* format not correct, so lets just assume we start from the beginning */ rangeproblem = 1; } if (rangenumber < 0) { rangeproblem = 1; } if (!rangeproblem) { ret = fseeko (file, rangenumber, SEEK_SET); if (ret != -1) { new_content_len = content_length - rangenumber; if (new_content_len < 0) { rangeproblem = 1; } } else { rangeproblem = 1; } if (!rangeproblem) { /* Date: is required on all HTTP1.1 responses */ char currenttime[50]; time_t now; int strflen; struct tm result; off_t endpos = rangenumber+new_content_len-1; char *type; if (endpos < 0) { endpos = 0; } time(&now); strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT", gmtime_r(&now, &result)); httpclient->respcode = 206; type = fserve_content_type (path); bytes = snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.1 206 Partial Content\r\n" "Date: %s\r\n" "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" "Content-Range: bytes %" PRI_OFF_T \ "-%" PRI_OFF_T "/%" PRI_OFF_T "\r\n" "Content-Type: %s\r\n\r\n", currenttime, new_content_len, rangenumber, endpos, content_length, type); free (type); } else { goto fail; } } else { goto fail; } } else { char *type = fserve_content_type(path); httpclient->respcode = 200; bytes = snprintf (httpclient->refbuf->data, BUFSIZE, "HTTP/1.0 200 OK\r\n" "Accept-Ranges: bytes\r\n" "Content-Length: %" PRI_OFF_T "\r\n" "Content-Type: %s\r\n\r\n", content_length, type); free (type); } httpclient->refbuf->len = bytes; httpclient->pos = 0; stats_event_inc (NULL, "file_connections"); fserve_add_client (httpclient, file); return 0; fail: fclose (file); httpclient->respcode = 416; sock_write (httpclient->con->sock, "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n"); client_destroy (httpclient); return -1; }