1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-12-04 14:46:30 -05:00

push HTTP header writing for file download into file serving thread to prevent

stalls in connection thread.  perform most file checking in fserve but allow
for m3u file override and using the Host header if available.

svn path=/icecast/trunk/icecast/; revision=9462
This commit is contained in:
Karl Heyes 2005-06-17 22:55:59 +00:00
parent 7446328d1d
commit 4f4e7be98f
3 changed files with 137 additions and 84 deletions

View File

@ -765,7 +765,6 @@ static void _handle_get_request (client_t *client, char *passed_uri)
struct stat statbuf; struct stat statbuf;
source_t *source; source_t *source;
int fileserve; int fileserve;
char *host = NULL;
int port; int port;
int i; int i;
char *serverhost = NULL; char *serverhost = NULL;
@ -777,8 +776,6 @@ static void _handle_get_request (client_t *client, char *passed_uri)
config = config_get_config(); config = config_get_config();
fileserve = config->fileserve; fileserve = config->fileserve;
if (config->hostname)
host = strdup (config->hostname);
port = config->port; port = config->port;
for(i = 0; i < global.server_sockets; i++) { for(i = 0; i < global.server_sockets; i++) {
if(global.serversock[i] == client->con->serversock) { if(global.serversock[i] == client->con->serversock) {
@ -817,7 +814,6 @@ static void _handle_get_request (client_t *client, char *passed_uri)
(strncmp(uri, "/admin/", 7) == 0)) { (strncmp(uri, "/admin/", 7) == 0)) {
admin_handle_request(client, uri); admin_handle_request(client, uri);
if (uri != passed_uri) free (uri); if (uri != passed_uri) free (uri);
free (host);
return; return;
} }
@ -842,46 +838,17 @@ static void _handle_get_request (client_t *client, char *passed_uri)
} }
free(fullpath); free(fullpath);
if (uri != passed_uri) free (uri); if (uri != passed_uri) free (uri);
free (host);
return; return;
} }
else if(fileserve && stat(fullpath, &statbuf) == 0 &&
#ifdef _WIN32 if (fserve_client_create (client, uri))
((statbuf.st_mode) & _S_IFREG))
#else
S_ISREG(statbuf.st_mode))
#endif
{ {
fserve_client_create(client, fullpath);
free(fullpath); free(fullpath);
if (uri != passed_uri) free (uri); if (uri != passed_uri) free (uri);
free (host);
return; return;
} }
free(fullpath); free(fullpath);
if(strcmp(util_get_extension(uri), "m3u") == 0) {
char *sourceuri = strdup(uri);
char *dot = strrchr(sourceuri, '.');
*dot = 0;
client->respcode = 200;
bytes = sock_write(client->con->sock,
"HTTP/1.0 200 OK\r\n"
"Content-Type: audio/x-mpegurl\r\n\r\n"
"http://%s:%d%s\r\n",
host,
port,
sourceuri
);
if(bytes > 0) client->con->sent_bytes = bytes;
client_destroy(client);
free(sourceuri);
if (uri != passed_uri) free (uri);
free (host);
return;
}
free (host);
avl_tree_rlock(global.source_tree); avl_tree_rlock(global.source_tree);
source = source_find_mount(uri); source = source_find_mount(uri);
if (source) { if (source) {

View File

@ -32,6 +32,7 @@
#include <winsock2.h> #include <winsock2.h>
#include <windows.h> #include <windows.h>
#define snprintf _snprintf #define snprintf _snprintf
#define S_ISREG(mode) ((mode) & _S_IFREG)
#endif #endif
#include "thread/thread.h" #include "thread/thread.h"
@ -93,14 +94,6 @@ static void create_mime_mappings(const char *fn);
void fserve_initialize(void) void fserve_initialize(void)
{ {
ice_config_t *config = config_get_config();
int serve = config->fileserve;
config_release_config();
if(!serve)
return;
create_mime_mappings(MIMETYPESFILE); create_mime_mappings(MIMETYPESFILE);
thread_mutex_create (&pending_lock); thread_mutex_create (&pending_lock);
@ -230,7 +223,7 @@ static void wait_for_fds() {
pending_list = NULL; pending_list = NULL;
thread_mutex_unlock (&pending_lock); thread_mutex_unlock (&pending_lock);
} }
/* drop out of here is someone is ready */ /* drop out of here if someone is ready */
if (fserve_client_waiting()) if (fserve_client_waiting())
break; break;
} }
@ -259,7 +252,10 @@ static void *fserv_thread_function(void *arg)
if (client->pos == refbuf->len) if (client->pos == refbuf->len)
{ {
/* Grab a new chunk */ /* Grab a new chunk */
bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file); if (fclient->file)
bytes = fread (refbuf->data, 1, BUFSIZE, fclient->file);
else
bytes = 0;
if (bytes == 0) if (bytes == 0)
{ {
fserve_t *to_go = fclient; fserve_t *to_go = fclient;
@ -341,6 +337,8 @@ char *fserve_content_type (const char *path)
return "image/jpeg"; return "image/jpeg";
else if(!strcmp(ext, "png")) else if(!strcmp(ext, "png"))
return "image/png"; return "image/png";
else if(!strcmp(ext, "m3u"))
return "audio/x-mpegurl";
else else
return "application/octet-stream"; return "application/octet-stream";
} }
@ -362,42 +360,106 @@ static void fserve_client_destroy(fserve_t *fclient)
int fserve_client_create(client_t *httpclient, const char *path) int fserve_client_create(client_t *httpclient, const char *path)
{ {
fserve_t *client;
int bytes; int bytes;
struct stat file_buf; struct stat file_buf;
char *range = NULL; char *range = NULL;
int64_t new_content_len = 0; int64_t new_content_len = 0;
int64_t rangenumber = 0; int64_t rangenumber = 0, content_length;
int rangeproblem = 0; int rangeproblem = 0;
int ret = 0; int ret = 0;
char *fullpath;
int m3u_requested = 0, m3u_file_available = 1;
ice_config_t *config;
FILE *file;
if (stat (path, &file_buf) != 0) fullpath = util_get_path_from_normalised_uri (path);
INFO2 ("checking for file %s (%s)", path, fullpath);
if (strcmp (util_get_extension (fullpath), "m3u") == 0)
m3u_requested = 1;
/* check for the actual file */
if (stat (fullpath, &file_buf) != 0)
{ {
client_send_404 (httpclient, "The file you requested could not be found"); /* the m3u can be generated, but send an m3u file if available */
return 0; if (m3u_requested == 0)
{
free (fullpath);
return 0;
}
m3u_file_available = 0;
} }
client = calloc (1, sizeof(fserve_t));
if (client == NULL)
{
client_send_404 (httpclient, "memory exhausted");
return 0;
}
client->file = fopen (path, "rb");
if (client->file == NULL)
{
client_send_404 (httpclient, "File not readable");
fserve_client_destroy (client);
return 0;
}
client->client = httpclient;
client->ready = 0;
client_set_queue (httpclient, NULL); client_set_queue (httpclient, NULL);
httpclient->refbuf = refbuf_new (BUFSIZE); httpclient->refbuf = refbuf_new (BUFSIZE);
client->content_length = (int64_t)file_buf.st_size;
range = httpp_getvar (client->client->parser, "range"); if (m3u_requested && m3u_file_available == 0)
{
char *host = httpp_getvar (httpclient->parser, "host");
char *sourceuri = strdup (path);
char *dot = strrchr(sourceuri, '.');
*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 1;
}
/* on demand file serving check */
config = config_get_config();
if (config->fileserve == 0)
{
DEBUG1 ("on demand file \"%s\" refused", fullpath);
client_send_404 (httpclient, "The file you requested could not be found");
config_release_config();
free (fullpath);
return 0;
}
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: %s", fullpath);
free (fullpath);
return 1;
}
file = fopen (fullpath, "rb");
free (fullpath);
if (file == NULL)
{
WARN1 ("Problem accessing file \"%s\"", fullpath);
client_send_404 (httpclient, "File not readable");
return 1;
}
content_length = (int64_t)file_buf.st_size;
range = httpp_getvar (httpclient->parser, "range");
if (range != NULL) { if (range != NULL) {
ret = sscanf(range, "bytes=" FORMAT_INT64 "-", &rangenumber); ret = sscanf(range, "bytes=" FORMAT_INT64 "-", &rangenumber);
@ -410,9 +472,9 @@ int fserve_client_create(client_t *httpclient, const char *path)
rangeproblem = 1; rangeproblem = 1;
} }
if (!rangeproblem) { if (!rangeproblem) {
ret = fseek(client->file, rangenumber, SEEK_SET); ret = fseek (file, rangenumber, SEEK_SET);
if (ret != -1) { if (ret != -1) {
new_content_len = client->content_length - rangenumber; new_content_len = content_length - rangenumber;
if (new_content_len < 0) { if (new_content_len < 0) {
rangeproblem = 1; rangeproblem = 1;
} }
@ -445,25 +507,25 @@ int fserve_client_create(client_t *httpclient, const char *path)
new_content_len, new_content_len,
rangenumber, rangenumber,
endpos, endpos,
client->content_length, content_length,
fserve_content_type(path)); fserve_content_type(path));
} }
else { else {
httpclient->respcode = 416; httpclient->respcode = 416;
bytes = snprintf (httpclient->refbuf->data, BUFSIZE, sock_write (httpclient->con->sock,
"HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n"); "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
fserve_client_destroy(client); client_destroy (httpclient);
return -1; return 1;
} }
} }
else { else {
/* If we run into any issues with the ranges /* If we run into any issues with the ranges
we fallback to a normal/non-range request */ we fallback to a normal/non-range request */
httpclient->respcode = 416; httpclient->respcode = 416;
bytes = snprintf (httpclient->refbuf->data, BUFSIZE, sock_write (httpclient->con->sock,
"HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n"); "HTTP/1.0 416 Request Range Not Satisfiable\r\n\r\n");
fserve_client_destroy(client); client_destroy (httpclient);
return -1; return 1;
} }
} }
else { else {
@ -473,17 +535,42 @@ int fserve_client_create(client_t *httpclient, const char *path)
"HTTP/1.0 200 OK\r\n" "HTTP/1.0 200 OK\r\n"
"Content-Length: " FORMAT_INT64 "\r\n" "Content-Length: " FORMAT_INT64 "\r\n"
"Content-Type: %s\r\n\r\n", "Content-Type: %s\r\n\r\n",
client->content_length, content_length,
fserve_content_type(path)); fserve_content_type(path));
} }
httpclient->refbuf->len = bytes; httpclient->refbuf->len = bytes;
httpclient->pos = 0;
stats_event_inc (NULL, "file_connections"); stats_event_inc (NULL, "file_connections");
sock_set_blocking(client->client->con->sock, SOCK_NONBLOCK); fserve_add_client (httpclient, file);
sock_set_nodelay(client->client->con->sock);
return 1;
}
/* Add client to fserve thread, client needs to have refbuf set and filled
* but may provide a NULL file if no data needs to be read
*/
int fserve_add_client (client_t *client, FILE *file)
{
fserve_t *fclient = calloc (1, sizeof(fserve_t));
DEBUG0 ("Adding client to file serving engine");
if (fclient == NULL)
{
client_send_404 (client, "memory exhausted");
return -1;
}
fclient->file = file;
fclient->client = client;
fclient->ready = 0;
sock_set_blocking (client->con->sock, SOCK_NONBLOCK);
sock_set_nodelay (client->con->sock);
thread_mutex_lock (&pending_lock); thread_mutex_lock (&pending_lock);
client->next = (fserve_t *)pending_list; fclient->next = (fserve_t *)pending_list;
pending_list = client; pending_list = fclient;
thread_mutex_unlock (&pending_lock); thread_mutex_unlock (&pending_lock);
return 0; return 0;

View File

@ -14,14 +14,12 @@
#define __FSERVE_H__ #define __FSERVE_H__
#include <stdio.h> #include <stdio.h>
#include "compat.h"
typedef struct _fserve_t typedef struct _fserve_t
{ {
client_t *client; client_t *client;
FILE *file; FILE *file;
int64_t content_length;
int ready; int ready;
struct _fserve_t *next; struct _fserve_t *next;
} fserve_t; } fserve_t;
@ -29,6 +27,7 @@ typedef struct _fserve_t
void fserve_initialize(void); void fserve_initialize(void);
void fserve_shutdown(void); void fserve_shutdown(void);
int fserve_client_create(client_t *httpclient, const char *path); int fserve_client_create(client_t *httpclient, const char *path);
int fserve_add_client (client_t *client, FILE *file);
char *fserve_content_type (const char *path); char *fserve_content_type (const char *path);