Commit d6f8f329 authored by Rafaël Carré's avatar Rafaël Carré

httpd: cosmetics

parent 85724e8f
......@@ -50,21 +50,21 @@
# include <poll.h>
#endif
#if defined( _WIN32 )
#if defined(_WIN32)
# include <winsock2.h>
#else
# include <sys/socket.h>
#endif
#if defined( _WIN32 )
#if defined(_WIN32)
/* We need HUGE buffer otherwise TCP throughput is very limited */
#define HTTPD_CL_BUFSIZE 1000000
#else
#define HTTPD_CL_BUFSIZE 10000
#endif
static void httpd_ClientClean( httpd_client_t *cl );
static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_data );
static void httpd_ClientClean(httpd_client_t *cl);
static void httpd_AppendData(httpd_stream_t *stream, uint8_t *p_data, int i_data);
/* each host run in his own thread */
struct httpd_host_t
......@@ -177,7 +177,7 @@ struct httpd_client_t
/*****************************************************************************
* Various functions
*****************************************************************************/
static const char *httpd_ReasonFromCode( unsigned i_code )
static const char *httpd_ReasonFromCode(unsigned i_code)
{
typedef struct
{
......@@ -248,7 +248,7 @@ static const char *httpd_ReasonFromCode( unsigned i_code )
"Continue", "OK", "Found", "Client error", "Server error"
};
assert( ( i_code >= 100 ) && ( i_code <= 599 ) );
assert((i_code >= 100) && (i_code <= 599));
const http_status_info *p = http_reason;
while (i_code < p->i_code)
......@@ -263,7 +263,7 @@ static const char *httpd_ReasonFromCode( unsigned i_code )
static size_t httpd_HtmlError (char **body, int code, const char *url)
{
const char *errname = httpd_ReasonFromCode (code);
assert (errname != NULL);
assert (errname);
char *url_Encoded = convert_xml_special_chars (url ? url : "");
......@@ -285,8 +285,7 @@ static size_t httpd_HtmlError (char **body, int code, const char *url)
free (url_Encoded);
if (res == -1)
{
if (res == -1) {
*body = NULL;
return 0;
}
......@@ -311,34 +310,29 @@ struct httpd_file_t
};
static int
httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
httpd_message_t *answer, const httpd_message_t *query )
httpd_FileCallBack(httpd_callback_sys_t *p_sys, httpd_client_t *cl,
httpd_message_t *answer, const httpd_message_t *query)
{
httpd_file_t *file = (httpd_file_t*)p_sys;
uint8_t **pp_body, *p_body;
const char *psz_connection;
uint8_t **pp_body, *p_body; const char *psz_connection;
int *pi_body, i_body;
if( answer == NULL || query == NULL )
{
if (!answer || !query )
return VLC_SUCCESS;
}
answer->i_proto = HTTPD_PROTO_HTTP;
answer->i_version= 1;
answer->i_type = HTTPD_MSG_ANSWER;
answer->i_status = 200;
httpd_MsgAdd( answer, "Content-type", "%s", file->psz_mime );
httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
httpd_MsgAdd(answer, "Content-type", "%s", file->psz_mime);
httpd_MsgAdd(answer, "Cache-Control", "%s", "no-cache");
if( query->i_type != HTTPD_MSG_HEAD )
{
if (query->i_type != HTTPD_MSG_HEAD) {
pp_body = &answer->p_body;
pi_body = &answer->i_body;
}
else
{
} else {
/* The file still needs to be executed. */
p_body = NULL;
i_body = 0;
......@@ -346,79 +340,71 @@ httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
pi_body = &i_body;
}
if( query->i_type == HTTPD_MSG_POST )
{
if (query->i_type == HTTPD_MSG_POST) {
/* msg_Warn not supported */
}
uint8_t *psz_args = query->psz_args;
file->pf_fill( file->p_sys, file, psz_args, pp_body, pi_body );
file->pf_fill(file->p_sys, file, psz_args, pp_body, pi_body);
if( query->i_type == HTTPD_MSG_HEAD && p_body != NULL )
{
free( p_body );
}
if (query->i_type == HTTPD_MSG_HEAD)
free(p_body);
/* We respect client request */
psz_connection = httpd_MsgGet( &cl->query, "Connection" );
if( psz_connection != NULL )
{
httpd_MsgAdd( answer, "Connection", "%s", psz_connection );
}
psz_connection = httpd_MsgGet(&cl->query, "Connection");
if (!psz_connection)
httpd_MsgAdd(answer, "Connection", "%s", psz_connection);
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
httpd_MsgAdd(answer, "Content-Length", "%d", answer->i_body);
return VLC_SUCCESS;
}
httpd_file_t *httpd_FileNew( httpd_host_t *host,
httpd_file_t *httpd_FileNew(httpd_host_t *host,
const char *psz_url, const char *psz_mime,
const char *psz_user, const char *psz_password,
httpd_file_callback_t pf_fill,
httpd_file_sys_t *p_sys )
httpd_file_sys_t *p_sys)
{
httpd_file_t *file = xmalloc( sizeof( httpd_file_t ) );
httpd_file_t *file = malloc(sizeof(*file));
if (!file)
return NULL;
file->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
if( file->url == NULL )
{
free( file );
file->url = httpd_UrlNew(host, psz_url, psz_user, psz_password);
if (!file->url) {
free(file);
return NULL;
}
file->psz_url = strdup( psz_url );
if( psz_mime && *psz_mime )
{
file->psz_mime = strdup( psz_mime );
}
file->psz_url = strdup(psz_url);
if (psz_mime && *psz_mime)
file->psz_mime = strdup(psz_mime);
else
{
file->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
}
file->psz_mime = strdup(vlc_mime_Ext2Mime(psz_url));
file->pf_fill = pf_fill;
file->p_sys = p_sys;
httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack,
(httpd_callback_sys_t*)file );
httpd_UrlCatch( file->url, HTTPD_MSG_GET, httpd_FileCallBack,
(httpd_callback_sys_t*)file );
httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack,
(httpd_callback_sys_t*)file );
httpd_UrlCatch(file->url, HTTPD_MSG_HEAD, httpd_FileCallBack,
(httpd_callback_sys_t*)file);
httpd_UrlCatch(file->url, HTTPD_MSG_GET, httpd_FileCallBack,
(httpd_callback_sys_t*)file);
httpd_UrlCatch(file->url, HTTPD_MSG_POST, httpd_FileCallBack,
(httpd_callback_sys_t*)file);
return file;
}
httpd_file_sys_t *httpd_FileDelete( httpd_file_t *file )
httpd_file_sys_t *httpd_FileDelete(httpd_file_t *file)
{
httpd_file_sys_t *p_sys = file->p_sys;
httpd_UrlDelete( file->url );
httpd_UrlDelete(file->url);
free( file->psz_url );
free( file->psz_mime );
free(file->psz_url);
free(file->psz_mime);
free( file );
free(file);
return p_sys;
}
......@@ -436,120 +422,109 @@ struct httpd_handler_t
};
static int
httpd_HandlerCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl,
httpd_message_t *answer, const httpd_message_t *query )
httpd_HandlerCallBack(httpd_callback_sys_t *p_sys, httpd_client_t *cl,
httpd_message_t *answer, const httpd_message_t *query)
{
httpd_handler_t *handler = (httpd_handler_t*)p_sys;
char psz_remote_addr[NI_MAXNUMERICHOST];
if( answer == NULL || query == NULL )
{
if (!answer || !query)
return VLC_SUCCESS;
}
answer->i_proto = HTTPD_PROTO_NONE;
answer->i_type = HTTPD_MSG_ANSWER;
/* We do it ourselves, thanks */
answer->i_status = 0;
if( httpd_ClientIP( cl, psz_remote_addr, NULL ) == NULL )
if (!httpd_ClientIP(cl, psz_remote_addr, NULL))
*psz_remote_addr = '\0';
uint8_t *psz_args = query->psz_args;
handler->pf_fill( handler->p_sys, handler, query->psz_url, psz_args,
handler->pf_fill(handler->p_sys, handler, query->psz_url, psz_args,
query->i_type, query->p_body, query->i_body,
psz_remote_addr, NULL,
&answer->p_body, &answer->i_body );
&answer->p_body, &answer->i_body);
if( query->i_type == HTTPD_MSG_HEAD )
{
if (query->i_type == HTTPD_MSG_HEAD) {
char *p = (char *)answer->p_body;
/* Looks for end of header (i.e. one empty line) */
while ( (p = strchr( p, '\r' )) != NULL )
{
if( p[1] && p[1] == '\n' && p[2] && p[2] == '\r'
&& p[3] && p[3] == '\n' )
{
while ((p = strchr(p, '\r')))
if (p[1] == '\n' && p[2] == '\r' && p[3] == '\n')
break;
}
}
if( p != NULL )
{
if (p) {
p[4] = '\0';
answer->i_body = strlen((char*)answer->p_body) + 1;
answer->p_body = xrealloc( answer->p_body, answer->i_body );
answer->p_body = xrealloc(answer->p_body, answer->i_body);
}
}
if( strncmp( (char *)answer->p_body, "HTTP/1.", 7 ) )
{
if (strncmp((char *)answer->p_body, "HTTP/1.", 7)) {
int i_status, i_headers;
char *psz_headers, *psz_new;
const char *psz_status;
if( !strncmp( (char *)answer->p_body, "Status: ", 8 ) )
{
if (!strncmp((char *)answer->p_body, "Status: ", 8)) {
/* Apache-style */
i_status = strtol( (char *)&answer->p_body[8], &psz_headers, 0 );
if( *psz_headers == '\r' || *psz_headers == '\n' ) psz_headers++;
if( *psz_headers == '\n' ) psz_headers++;
i_status = strtol((char *)&answer->p_body[8], &psz_headers, 0);
if (*psz_headers == '\r' || *psz_headers == '\n') psz_headers++;
if (*psz_headers == '\n') psz_headers++;
i_headers = answer->i_body - (psz_headers - (char *)answer->p_body);
}
else
{
} else {
i_status = 200;
psz_headers = (char *)answer->p_body;
i_headers = answer->i_body;
}
psz_status = httpd_ReasonFromCode( i_status );
psz_status = httpd_ReasonFromCode(i_status);
answer->i_body = sizeof("HTTP/1.0 xxx \r\n")
+ strlen(psz_status) + i_headers - 1;
psz_new = (char *)xmalloc( answer->i_body + 1);
sprintf( psz_new, "HTTP/1.0 %03d %s\r\n", i_status, psz_status );
memcpy( &psz_new[strlen(psz_new)], psz_headers, i_headers );
free( answer->p_body );
psz_new = (char *)xmalloc(answer->i_body + 1);
sprintf(psz_new, "HTTP/1.0 %03d %s\r\n", i_status, psz_status);
memcpy(&psz_new[strlen(psz_new)], psz_headers, i_headers);
free(answer->p_body);
answer->p_body = (uint8_t *)psz_new;
}
return VLC_SUCCESS;
}
httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
httpd_handler_t *httpd_HandlerNew(httpd_host_t *host, const char *psz_url,
const char *psz_user,
const char *psz_password,
httpd_handler_callback_t pf_fill,
httpd_handler_sys_t *p_sys )
httpd_handler_sys_t *p_sys)
{
httpd_handler_t *handler = xmalloc( sizeof( httpd_handler_t ) );
httpd_handler_t *handler = malloc(sizeof(*handler));
if (!handler)
return NULL;
handler->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
if( handler->url == NULL )
{
free( handler );
handler->url = httpd_UrlNew(host, psz_url, psz_user, psz_password);
if (!handler->url) {
free(handler);
return NULL;
}
handler->pf_fill = pf_fill;
handler->p_sys = p_sys;
httpd_UrlCatch( handler->url, HTTPD_MSG_HEAD, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler );
httpd_UrlCatch( handler->url, HTTPD_MSG_GET, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler );
httpd_UrlCatch( handler->url, HTTPD_MSG_POST, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler );
httpd_UrlCatch(handler->url, HTTPD_MSG_HEAD, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler);
httpd_UrlCatch(handler->url, HTTPD_MSG_GET, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler);
httpd_UrlCatch(handler->url, HTTPD_MSG_POST, httpd_HandlerCallBack,
(httpd_callback_sys_t*)handler);
return handler;
}
httpd_handler_sys_t *httpd_HandlerDelete( httpd_handler_t *handler )
httpd_handler_sys_t *httpd_HandlerDelete(httpd_handler_t *handler)
{
httpd_handler_sys_t *p_sys = handler->p_sys;
httpd_UrlDelete( handler->url );
free( handler );
httpd_UrlDelete(handler->url);
free(handler);
return p_sys;
}
......@@ -562,18 +537,17 @@ struct httpd_redirect_t
char *psz_dst;
};
static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
static int httpd_RedirectCallBack(httpd_callback_sys_t *p_sys,
httpd_client_t *cl, httpd_message_t *answer,
const httpd_message_t *query )
const httpd_message_t *query)
{
httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys;
char *p_body;
(void)cl;
if( answer == NULL || query == NULL )
{
if (!answer || !query)
return VLC_SUCCESS;
}
answer->i_proto = HTTPD_PROTO_HTTP;
answer->i_version= 1;
answer->i_type = HTTPD_MSG_ANSWER;
......@@ -583,43 +557,44 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
answer->p_body = (unsigned char *)p_body;
/* XXX check if it's ok or we need to set an absolute url */
httpd_MsgAdd( answer, "Location", "%s", rdir->psz_dst );
httpd_MsgAdd(answer, "Location", "%s", rdir->psz_dst);
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
httpd_MsgAdd(answer, "Content-Length", "%d", answer->i_body);
return VLC_SUCCESS;
}
httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst,
const char *psz_url_src )
httpd_redirect_t *httpd_RedirectNew(httpd_host_t *host, const char *psz_url_dst,
const char *psz_url_src)
{
httpd_redirect_t *rdir = xmalloc( sizeof( httpd_redirect_t ) );
httpd_redirect_t *rdir = malloc(sizeof(*rdir));
if (!rdir)
return NULL;
rdir->url = httpd_UrlNew( host, psz_url_src, NULL, NULL );
if( rdir->url == NULL )
{
free( rdir );
rdir->url = httpd_UrlNew(host, psz_url_src, NULL, NULL);
if (!rdir->url) {
free(rdir);
return NULL;
}
rdir->psz_dst = strdup( psz_url_dst );
rdir->psz_dst = strdup(psz_url_dst);
/* Redirect apply for all HTTP request and RTSP DESCRIBE resquest */
httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir );
httpd_UrlCatch( rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir );
httpd_UrlCatch( rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir );
httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir );
httpd_UrlCatch(rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir);
httpd_UrlCatch(rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir);
httpd_UrlCatch(rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir);
httpd_UrlCatch(rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack,
(httpd_callback_sys_t*)rdir);
return rdir;
}
void httpd_RedirectDelete( httpd_redirect_t *rdir )
void httpd_RedirectDelete(httpd_redirect_t *rdir)
{
httpd_UrlDelete( rdir->url );
free( rdir->psz_dst );
free( rdir );
httpd_UrlDelete(rdir->url);
free(rdir->psz_dst);
free(rdir);
}
/*****************************************************************************
......@@ -655,29 +630,23 @@ struct httpd_stream_t
httpd_header * p_http_headers;
};
static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
static int httpd_StreamCallBack(httpd_callback_sys_t *p_sys,
httpd_client_t *cl, httpd_message_t *answer,
const httpd_message_t *query )
const httpd_message_t *query)
{
httpd_stream_t *stream = (httpd_stream_t*)p_sys;
if( answer == NULL || query == NULL || cl == NULL )
{
if (!answer || !query || !cl)
return VLC_SUCCESS;
}
if( answer->i_body_offset > 0 )
{
int64_t i_write;
if (answer->i_body_offset > 0) {
int i_pos;
if( answer->i_body_offset >= stream->i_buffer_pos )
{
if (answer->i_body_offset >= stream->i_buffer_pos)
return VLC_EGENERIC; /* wait, no data available */
}
if( cl->i_keyframe_wait_to_pass >= 0 )
{
if( stream->i_last_keyframe_seen_pos <= cl->i_keyframe_wait_to_pass )
if (cl->i_keyframe_wait_to_pass >= 0) {
if (stream->i_last_keyframe_seen_pos <= cl->i_keyframe_wait_to_pass)
/* still waiting for the next keyframe */
return VLC_EGENERIC;
......@@ -685,26 +654,20 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer->i_body_offset = stream->i_last_keyframe_seen_pos;
cl->i_keyframe_wait_to_pass = -1;
}
if( answer->i_body_offset + stream->i_buffer_size <
stream->i_buffer_pos )
{
/* this client isn't fast enough */
answer->i_body_offset = stream->i_buffer_last_pos;
}
if (answer->i_body_offset + stream->i_buffer_size < stream->i_buffer_pos)
answer->i_body_offset = stream->i_buffer_last_pos; /* this client isn't fast enough */
i_pos = answer->i_body_offset % stream->i_buffer_size;
i_write = stream->i_buffer_pos - answer->i_body_offset;
if( i_write > HTTPD_CL_BUFSIZE )
{
int64_t i_write = stream->i_buffer_pos - answer->i_body_offset;
if (i_write > HTTPD_CL_BUFSIZE)
i_write = HTTPD_CL_BUFSIZE;
}
else if( i_write <= 0 )
{
else if (i_write <= 0)
return VLC_EGENERIC; /* wait, no data available */
}
/* Don't go past the end of the circular buffer */
i_write = __MIN( i_write, stream->i_buffer_size - i_pos );
i_write = __MIN(i_write, stream->i_buffer_size - i_pos);
/* using HTTPD_MSG_ANSWER -> data available */
answer->i_proto = HTTPD_PROTO_HTTP;
......@@ -712,15 +675,13 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
answer->i_type = HTTPD_MSG_ANSWER;
answer->i_body = i_write;
answer->p_body = xmalloc( i_write );
memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write );
answer->p_body = xmalloc(i_write);
memcpy(answer->p_body, &stream->p_buffer[i_pos], i_write);
answer->i_body_offset += i_write;
return VLC_SUCCESS;
}
else
{
} else {
answer->i_proto = HTTPD_PROTO_HTTP;
answer->i_version= 0;
answer->i_type = HTTPD_MSG_ANSWER;
......@@ -730,108 +691,91 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
bool b_has_content_type = false;
bool b_has_cache_control = false;
vlc_mutex_lock( &stream->lock );
for( size_t i = 0; i < stream->i_http_headers; i++ )
{
if( strncasecmp( stream->p_http_headers[i].name, "Content-Length", 14 ) )
{
httpd_MsgAdd( answer, stream->p_http_headers[i].name,
stream->p_http_headers[i].value );
vlc_mutex_lock(&stream->lock);
for (size_t i = 0; i < stream->i_http_headers; i++)
if (strncasecmp(stream->p_http_headers[i].name, "Content-Length", 14)) {
httpd_MsgAdd(answer, stream->p_http_headers[i].name,
stream->p_http_headers[i].value);
if( !strncasecmp( stream->p_http_headers[i].name, "Content-Type", 12 ) )
if (!strncasecmp(stream->p_http_headers[i].name, "Content-Type", 12))
b_has_content_type = true;
else if( !strncasecmp( stream->p_http_headers[i].name, "Cache-Control", 13 ) )
else if (!strncasecmp(stream->p_http_headers[i].name, "Cache-Control", 13))
b_has_cache_control = true;
}
}
vlc_mutex_unlock( &stream->lock );
vlc_mutex_unlock(&stream->lock);
if( query->i_type != HTTPD_MSG_HEAD )
{
if (query->i_type != HTTPD_MSG_HEAD) {
cl->b_stream_mode = true;
vlc_mutex_lock( &stream->lock );
vlc_mutex_lock(&stream->lock);
/* Send the header */
if( stream->i_header > 0 )
{
if (stream->i_header > 0) {
answer->i_body = stream->i_header;
answer->p_body = xmalloc( stream->i_header );
memcpy( answer->p_body, stream->p_header, stream->i_header );
answer->p_body = xmalloc(stream->i_header);
memcpy(answer->p_body, stream->p_header, stream->i_header);
}
answer->i_body_offset = stream->i_buffer_last_pos;
if( stream->b_has_keyframes )
if (stream->b_has_keyframes)
cl->i_keyframe_wait_to_pass = stream->i_last_keyframe_seen_pos;
else
cl->i_keyframe_wait_to_pass = -1;
vlc_mutex_unlock( &stream->lock );
}
else
{
httpd_MsgAdd( answer, "Content-Length", "0" );
vlc_mutex_unlock(&stream->lock);
} else {
httpd_MsgAdd(answer, "Content-Length", "0");
answer->i_body_offset = 0;
}
/* FIXME: move to http access_output */
if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
{
if (!strcmp(stream->psz_mime, "video/x-ms-asf-stream")) {
bool b_xplaystream = false;
httpd_MsgAdd( answer, "Content-type", "application/octet-stream" );
httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
httpd_MsgAdd( answer, "Pragma", "no-cache" );
httpd_MsgAdd( answer, "Pragma", "client-id=%lu",
vlc_mrand48()&0x7fff );
httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
httpd_MsgAdd(answer, "Content-type", "application/octet-stream");
httpd_MsgAdd(answer, "Server", "Cougar 4.1.0.3921");
httpd_MsgAdd(answer, "Pragma", "no-cache");
httpd_MsgAdd(answer, "Pragma", "client-id=%lu",
vlc_mrand48()&0x7fff);
httpd_MsgAdd(answer, "Pragma", "features=\"broadcast\"");
/* Check if there is a xPlayStrm=1 */
for( size_t i = 0; i < query->i_headers; i++ )
{
if( !strcasecmp( query->p_headers[i].name, "Pragma" ) &&
strstr( query->p_headers[i].value, "xPlayStrm=1" ) )
{
for (size_t i = 0; i < query->i_headers; i++)
if (!strcasecmp(query->p_headers[i].name, "Pragma") &&
strstr(query->p_headers[i].value, "xPlayStrm=1"))
b_xplaystream = true;
}
}
if( !b_xplaystream )
{
if (!b_xplaystream)
answer->i_body_offset = 0;
}
}
else if( !b_has_content_type )
{
httpd_MsgAdd( answer, "Content-type", stream->psz_mime );
}
if( !b_has_cache_control )
httpd_MsgAdd( answer, "Cache-Control", "no-cache" );
} else if (!b_has_content_type)
httpd_MsgAdd(answer, "Content-type", stream->psz_mime);
if (!b_has_cache_control)
httpd_MsgAdd(answer, "Cache-Control", "no-cache");
return VLC_SUCCESS;
}
}
httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
httpd_stream_t *httpd_StreamNew(httpd_host_t *host,
const char *psz_url, const char *psz_mime,
const char *psz_user, const char *psz_password )
const char *psz_user, const char *psz_password)
{
httpd_stream_t *stream = xmalloc( sizeof( httpd_stream_t ) );
httpd_stream_t *stream = malloc(sizeof(*stream));
if (!stream)
return NULL;
stream->url = httpd_UrlNew( host, psz_url, psz_user, psz_password );
if( stream->url == NULL )
{
free( stream );
stream->url = httpd_UrlNew(host, psz_url, psz_user, psz_password);
if (!stream->url) {
free(stream);
return NULL;
}
vlc_mutex_init( &stream->lock );
if( psz_mime && *psz_mime )
{
stream->psz_mime = strdup( psz_mime );
}
vlc_mutex_init(&stream->lock);
if (psz_mime && *psz_mime)
stream->psz_mime = strdup(psz_mime);
else
{
stream->psz_mime = strdup( vlc_mime_Ext2Mime( psz_url ) );
}
stream->psz_mime = strdup(vlc_mime_Ext2Mime(psz_url));
stream->i_header = 0;
stream->p_header = NULL;
stream->i_buffer_size = 5000000; /* 5 Mo per stream */
stream->p_buffer = xmalloc( stream->i_buffer_size );
stream->p_buffer = xmalloc(stream->i_buffer_size);
/* We set to 1 to make life simpler
* (this way i_body_offset can never be 0) */
stream->i_buffer_pos = 1;
......@@ -841,47 +785,43 @@ httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
stream->i_http_headers = 0;
stream->p_http_headers = NULL;
httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream );
httpd_UrlCatch( stream->url, HTTPD_MSG_GET, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream );
httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream );
httpd_UrlCatch(stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream);
httpd_UrlCatch(stream->url, HTTPD_MSG_GET, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream);
httpd_UrlCatch(stream->url, HTTPD_MSG_POST, httpd_StreamCallBack,
(httpd_callback_sys_t*)stream);
return stream;
}
int httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data )
int httpd_StreamHeader(httpd_stream_t *stream, uint8_t *p_data, int i_data)
{
vlc_mutex_lock( &stream->lock );
free( stream->p_header );
vlc_mutex_lock(&stream->lock);
free(stream->p_header);
stream->p_header = NULL;
stream->i_header = i_data;
if( i_data > 0 )
{
stream->p_header = xmalloc( i_data );
memcpy( stream->p_header, p_data, i_data );
if (i_data > 0) {
stream->p_header = xmalloc(i_data);
memcpy(stream->p_header, p_data, i_data);
}
vlc_mutex_unlock( &stream->lock );
vlc_mutex_unlock(&stream->lock);
return VLC_SUCCESS;
}
static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_data )
static void httpd_AppendData(httpd_stream_t *stream, uint8_t *p_data, int i_data)
{
int i_pos = stream->i_buffer_pos % stream->i_buffer_size;
int i_count = i_data;
while( i_count > 0)
{
int i_copy;
i_copy = __MIN( i_count, stream->i_buffer_size - i_pos );
while (i_count > 0) {
int i_copy = __MIN(i_count, stream->i_buffer_size - i_pos);
/* Ok, we can't go past the end of our buffer */
memcpy( &stream->p_buffer[i_pos], p_data, i_copy );
memcpy(&stream->p_buffer[i_pos], p_data, i_copy);
i_pos = ( i_pos + i_copy ) % stream->i_buffer_size;
i_pos = (i_pos + i_copy) % stream->i_buffer_size;
i_count -= i_copy;
p_data += i_copy;
}
......@@ -889,115 +829,106 @@ static void httpd_AppendData( httpd_stream_t *stream, uint8_t *p_data, int i_dat
stream->i_buffer_pos += i_data;
}
int httpd_StreamSend( httpd_stream_t *stream, const block_t *p_block )
int httpd_StreamSend(httpd_stream_t *stream, const block_t *p_block)
{
if( p_block == NULL || p_block->p_buffer == NULL )
{
if (!p_block || !p_block->p_buffer)
return VLC_SUCCESS;
}
vlc_mutex_lock( &stream->lock );
vlc_mutex_lock(&stream->lock);
/* save this pointer (to be used by new connection) */
stream->i_buffer_last_pos = stream->i_buffer_pos;
if( p_block->i_flags & BLOCK_FLAG_TYPE_I )
{
if (p_block->i_flags & BLOCK_FLAG_TYPE_I) {
stream->b_has_keyframes = true;
stream->i_last_keyframe_seen_pos = stream->i_buffer_pos;
}
httpd_AppendData( stream, p_block->p_buffer, p_block->i_buffer );
httpd_AppendData(stream, p_block->p_buffer, p_block->i_buffer);
vlc_mutex_unlock( &stream->lock );
vlc_mutex_unlock(&stream->lock);
return VLC_SUCCESS;
}
void httpd_StreamDelete( httpd_stream_t *stream )
void httpd_StreamDelete(httpd_stream_t *stream)
{
httpd_UrlDelete( stream->url );
for( size_t i = 0; i < stream->i_http_headers; i++ )
{
free( stream->p_http_headers[i].name );
free( stream->p_http_headers[i].value );
}
free( stream->p_http_headers );
vlc_mutex_destroy( &stream->lock );
free( stream->psz_mime );
free( stream->p_header );
free( stream->p_buffer );
free( stream );
httpd_UrlDelete(stream->url);
for (size_t i = 0; i < stream->i_http_headers; i++) {
free(stream->p_http_headers[i].name);
free(stream->p_http_headers[i].value);
}
free(stream->p_http_headers);
vlc_mutex_destroy(&stream->lock);
free(stream->psz_mime);
free(stream->p_header);
free(stream->p_buffer);
free(stream);
}
/*****************************************************************************
* Low level
*****************************************************************************/
static void* httpd_HostThread( void * );
static httpd_host_t *httpd_HostCreate( vlc_object_t *, const char *,
const char *, vlc_tls_creds_t * );
static void* httpd_HostThread(void *);
static httpd_host_t *httpd_HostCreate(vlc_object_t *, const char *,
const char *, vlc_tls_creds_t *);
/* create a new host */
httpd_host_t *vlc_http_HostNew( vlc_object_t *p_this )
httpd_host_t *vlc_http_HostNew(vlc_object_t *p_this)
{
return httpd_HostCreate( p_this, "http-host", "http-port", NULL );
return httpd_HostCreate(p_this, "http-host", "http-port", NULL);
}
httpd_host_t *vlc_https_HostNew( vlc_object_t *obj )
httpd_host_t *vlc_https_HostNew(vlc_object_t *obj)
{
char *cert = var_InheritString( obj, "http-cert" );
if( cert == NULL )
{
msg_Err( obj, "HTTP/TLS certificate not specified!" );
char *cert = var_InheritString(obj, "http-cert");
if (!cert) {
msg_Err(obj, "HTTP/TLS certificate not specified!");
return NULL;
}
char *key = var_InheritString( obj, "http-key" );
vlc_tls_creds_t *tls = vlc_tls_ServerCreate( obj, cert, key );
char *key = var_InheritString(obj, "http-key");
vlc_tls_creds_t *tls = vlc_tls_ServerCreate(obj, cert, key);
if( tls == NULL )
{
msg_Err( obj, "HTTP/TLS certificate error (%s and %s)",
cert, (key != NULL) ? key : cert );
free( key );
free( cert );
if (!tls) {
msg_Err(obj, "HTTP/TLS certificate error (%s and %s)",
cert, key ? key : cert);
free(key);
free(cert);
return NULL;
}
free( key );
free( cert );
free(key);
free(cert);
char *ca = var_InheritString( obj, "http-ca" );
if( ca != NULL )
{
if( vlc_tls_ServerAddCA( tls, ca ) )
{
msg_Err( obj, "HTTP/TLS CA error (%s)", ca );
free( ca );
char *ca = var_InheritString(obj, "http-ca");
if (ca) {
if (vlc_tls_ServerAddCA(tls, ca)) {
msg_Err(obj, "HTTP/TLS CA error (%s)", ca);
free(ca);
goto error;
}
free( ca );
free(ca);
}
char *crl = var_InheritString( obj, "http-crl" );
if( crl != NULL )
{
if( vlc_tls_ServerAddCRL( tls, crl ) )
{
msg_Err( obj, "TLS CRL error (%s)", crl );
free( crl );
char *crl = var_InheritString(obj, "http-crl");
if (crl) {
if (vlc_tls_ServerAddCRL(tls, crl)) {
msg_Err(obj, "TLS CRL error (%s)", crl);
free(crl);
goto error;
}
free( crl );
free(crl);
}
return httpd_HostCreate( obj, "http-host", "https-port", tls );
return httpd_HostCreate(obj, "http-host", "https-port", tls);
error:
vlc_tls_Delete( tls );
vlc_tls_Delete(tls);
return NULL;
}
httpd_host_t *vlc_rtsp_HostNew( vlc_object_t *p_this )
httpd_host_t *vlc_rtsp_HostNew(vlc_object_t *p_this)
{
return httpd_HostCreate( p_this, "rtsp-host", "rtsp-port", NULL );
return httpd_HostCreate(p_this, "rtsp-host", "rtsp-port", NULL);
}
static struct httpd
......@@ -1008,73 +939,69 @@ static struct httpd
int i_host;
} httpd = { VLC_STATIC_MUTEX, NULL, 0 };
static httpd_host_t *httpd_HostCreate( vlc_object_t *p_this,
static httpd_host_t *httpd_HostCreate(vlc_object_t *p_this,
const char *hostvar,
const char *portvar,
vlc_tls_creds_t *p_tls )
vlc_tls_creds_t *p_tls)
{
httpd_host_t *host;
char *hostname = var_InheritString( p_this, hostvar );
unsigned port = var_InheritInteger( p_this, portvar );
char *hostname = var_InheritString(p_this, hostvar);
unsigned port = var_InheritInteger(p_this, portvar);
vlc_url_t url;
vlc_UrlParse( &url, hostname, 0 );
free( hostname );
if( url.i_port != 0 )
{
msg_Err( p_this, "Ignoring port %d (using %d)", url.i_port, port );
msg_Info( p_this, "Specify port %d separately with the "
"%s option instead.", url.i_port, portvar );
vlc_UrlParse(&url, hostname, 0);
free(hostname);
if (url.i_port != 0) {
msg_Err(p_this, "Ignoring port %d (using %d)", url.i_port, port);
msg_Info(p_this, "Specify port %d separately with the "
"%s option instead.", url.i_port, portvar);
}
/* to be sure to avoid multiple creation */
vlc_mutex_lock( &httpd.mutex );
vlc_mutex_lock(&httpd.mutex);
/* verify if it already exist */
for( int i = 0; i < httpd.i_host; i++ )
{
for (int i = 0; i < httpd.i_host; i++) {
host = httpd.host[i];
/* cannot mix TLS and non-TLS hosts */
if( host->port != port
|| (host->p_tls != NULL) != (p_tls != NULL) )
if (host->port != port
|| (host->p_tls != NULL) != (p_tls != NULL))
continue;
/* Increase existing matching host reference count.
* The reference count is written under both the global httpd and the
* host lock. It is read with either or both locks held. The global
* lock is always acquired first. */
vlc_mutex_lock( &host->lock );
vlc_mutex_lock(&host->lock);
host->i_ref++;
vlc_mutex_unlock( &host->lock );
vlc_mutex_unlock(&host->lock);
vlc_mutex_unlock( &httpd.mutex );
vlc_UrlClean( &url );
vlc_tls_Delete( p_tls );
vlc_mutex_unlock(&httpd.mutex);
vlc_UrlClean(&url);
vlc_tls_Delete(p_tls);
return host;
}
/* create the new host */
host = (httpd_host_t *)vlc_custom_create( p_this, sizeof (*host),
"http host" );
if (host == NULL)
host = (httpd_host_t *)vlc_custom_create(p_this, sizeof (*host),
"http host");
if (!host)
goto error;
vlc_mutex_init( &host->lock );
vlc_cond_init( &host->wait );
vlc_mutex_init(&host->lock);
vlc_cond_init(&host->wait);
host->i_ref = 1;
host->fds = net_ListenTCP( p_this, url.psz_host, port );
if( host->fds == NULL )
{
msg_Err( p_this, "cannot create socket(s) for HTTP host" );
host->fds = net_ListenTCP(p_this, url.psz_host, port);
if (!host->fds) {
msg_Err(p_this, "cannot create socket(s) for HTTP host");
goto error;
}
for (host->nfd = 0; host->fds[host->nfd] != -1; host->nfd++);
if( vlc_object_waitpipe( VLC_OBJECT( host ) ) == -1 )
{
msg_Err( host, "signaling pipe error: %s", vlc_strerror_c(errno) );
if (vlc_object_waitpipe(VLC_OBJECT(host)) == -1) {
msg_Err(host, "signaling pipe error: %s", vlc_strerror_c(errno));
goto error;
}
......@@ -1086,170 +1013,159 @@ static httpd_host_t *httpd_HostCreate( vlc_object_t *p_this,
host->p_tls = p_tls;
/* create the thread */
if( vlc_clone( &host->thread, httpd_HostThread, host,
VLC_THREAD_PRIORITY_LOW ) )
{
msg_Err( p_this, "cannot spawn http host thread" );
if (vlc_clone(&host->thread, httpd_HostThread, host,
VLC_THREAD_PRIORITY_LOW)) {
msg_Err(p_this, "cannot spawn http host thread");
goto error;
}
/* now add it to httpd */
TAB_APPEND( httpd.i_host, httpd.host, host );
vlc_mutex_unlock( &httpd.mutex );
TAB_APPEND(httpd.i_host, httpd.host, host);
vlc_mutex_unlock(&httpd.mutex);
vlc_UrlClean( &url );
vlc_UrlClean(&url);
return host;
error:
vlc_mutex_unlock( &httpd.mutex );
vlc_mutex_unlock(&httpd.mutex);
if( host != NULL )
{
net_ListenClose( host->fds );
vlc_cond_destroy( &host->wait );
vlc_mutex_destroy( &host->lock );
vlc_object_release( host );
if (host) {
net_ListenClose(host->fds);
vlc_cond_destroy(&host->wait);
vlc_mutex_destroy(&host->lock);
vlc_object_release(host);
}
vlc_UrlClean( &url );
vlc_tls_Delete( p_tls );
vlc_UrlClean(&url);
vlc_tls_Delete(p_tls);
return NULL;
}
/* delete a host */
void httpd_HostDelete( httpd_host_t *host )
void httpd_HostDelete(httpd_host_t *host)
{
bool delete = false;
vlc_mutex_lock( &httpd.mutex );
vlc_mutex_lock(&httpd.mutex);
vlc_mutex_lock( &host->lock );
vlc_mutex_lock(&host->lock);
host->i_ref--;
if( host->i_ref == 0 )
if (host->i_ref == 0)
delete = true;
vlc_mutex_unlock( &host->lock );
if( !delete )
{
vlc_mutex_unlock(&host->lock);
if (!delete) {
/* still used */
vlc_mutex_unlock( &httpd.mutex );
msg_Dbg( host, "httpd_HostDelete: host still in use" );
vlc_mutex_unlock(&httpd.mutex);
msg_Dbg(host, "httpd_HostDelete: host still in use");
return;
}
TAB_REMOVE( httpd.i_host, httpd.host, host );
TAB_REMOVE(httpd.i_host, httpd.host, host);
vlc_cancel( host->thread );
vlc_join( host->thread, NULL );
vlc_cancel(host->thread);
vlc_join(host->thread, NULL);
msg_Dbg( host, "HTTP host removed" );
msg_Dbg(host, "HTTP host removed");
for( int i = 0; i < host->i_url; i++ )
{
msg_Err( host, "url still registered: %s", host->url[i]->psz_url );
}
for( int i = 0; i < host->i_client; i++ )
{
for (int i = 0; i < host->i_url; i++)
msg_Err(host, "url still registered: %s", host->url[i]->psz_url);
for (int i = 0; i < host->i_client; i++) {
httpd_client_t *cl = host->client[i];
msg_Warn( host, "client still connected" );
httpd_ClientClean( cl );
TAB_REMOVE( host->i_client, host->client, cl );
free( cl );
msg_Warn(host, "client still connected");
httpd_ClientClean(cl);
TAB_REMOVE(host->i_client, host->client, cl);
free(cl);
i--;
/* TODO */
}
vlc_tls_Delete( host->p_tls );
net_ListenClose( host->fds );
vlc_cond_destroy( &host->wait );
vlc_mutex_destroy( &host->lock );
vlc_object_release( host );
vlc_mutex_unlock( &httpd.mutex );
vlc_tls_Delete(host->p_tls);
net_ListenClose(host->fds);
vlc_cond_destroy(&host->wait);
vlc_mutex_destroy(&host->lock);
vlc_object_release(host);
vlc_mutex_unlock(&httpd.mutex);
}
/* register a new url */
httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url,
const char *psz_user, const char *psz_password )
httpd_url_t *httpd_UrlNew(httpd_host_t *host, const char *psz_url,
const char *psz_user, const char *psz_password)
{
httpd_url_t *url;
assert( psz_url != NULL );
assert(psz_url);
vlc_mutex_lock( &host->lock );
for( int i = 0; i < host->i_url; i++ )
{
if( !strcmp( psz_url, host->url[i]->psz_url ) )
{
msg_Warn( host,
"cannot add '%s' (url already defined)", psz_url );
vlc_mutex_unlock( &host->lock );
vlc_mutex_lock(&host->lock);
for (int i = 0; i < host->i_url; i++)
if (!strcmp(psz_url, host->url[i]->psz_url)) {
msg_Warn(host, "cannot add '%s' (url already defined)", psz_url);
vlc_mutex_unlock(&host->lock);
return NULL;
}
}
url = xmalloc( sizeof( httpd_url_t ) );
url = xmalloc(sizeof(httpd_url_t));
url->host = host;
vlc_mutex_init( &url->lock );
url->psz_url = strdup( psz_url );
url->psz_user = strdup( psz_user ? psz_user : "" );
url->psz_password = strdup( psz_password ? psz_password : "" );
for( int i = 0; i < HTTPD_MSG_MAX; i++ )
{
vlc_mutex_init(&url->lock);
url->psz_url = strdup(psz_url);
url->psz_user = strdup(psz_user ? psz_user : "");
url->psz_password = strdup(psz_password ? psz_password : "");
for (int i = 0; i < HTTPD_MSG_MAX; i++) {
url->catch[i].cb = NULL;
url->catch[i].p_sys = NULL;
}
TAB_APPEND( host->i_url, host->url, url );
vlc_cond_signal( &host->wait );
vlc_mutex_unlock( &host->lock );
TAB_APPEND(host->i_url, host->url, url);
vlc_cond_signal(&host->wait);
vlc_mutex_unlock(&host->lock);
return url;
}
/* register callback on a url */
int httpd_UrlCatch( httpd_url_t *url, int i_msg, httpd_callback_t cb,
httpd_callback_sys_t *p_sys )
int httpd_UrlCatch(httpd_url_t *url, int i_msg, httpd_callback_t cb,
httpd_callback_sys_t *p_sys)
{
vlc_mutex_lock( &url->lock );
vlc_mutex_lock(&url->lock);
url->catch[i_msg].cb = cb;
url->catch[i_msg].p_sys= p_sys;
vlc_mutex_unlock( &url->lock );
vlc_mutex_unlock(&url->lock);
return VLC_SUCCESS;
}
/* delete a url */
void httpd_UrlDelete( httpd_url_t *url )
void httpd_UrlDelete(httpd_url_t *url)
{
httpd_host_t *host = url->host;
vlc_mutex_lock( &host->lock );
TAB_REMOVE( host->i_url, host->url, url );
vlc_mutex_lock(&host->lock);
TAB_REMOVE(host->i_url, host->url, url);
vlc_mutex_destroy( &url->lock );
free( url->psz_url );
free( url->psz_user );
free( url->psz_password );
vlc_mutex_destroy(&url->lock);
free(url->psz_url);
free(url->psz_user);
free(url->psz_password);
for( int i = 0; i < host->i_client; i++ )
{
for (int i = 0; i < host->i_client; i++) {
httpd_client_t *client = host->client[i];
if( client->url == url )
{
/* TODO complete it */
msg_Warn( host, "force closing connections" );
httpd_ClientClean( client );
TAB_REMOVE( host->i_client, host->client, client );
free( client );
i--;
}
if (client->url != url)
continue;
/* TODO complete it */
msg_Warn(host, "force closing connections");
httpd_ClientClean(client);
TAB_REMOVE(host->i_client, host->client, client);
free(client);
i--;
}
free( url );
vlc_mutex_unlock( &host->lock );
free(url);
vlc_mutex_unlock(&host->lock);
}
static void httpd_MsgInit( httpd_message_t *msg )
static void httpd_MsgInit(httpd_message_t *msg)
{
msg->cl = NULL;
msg->i_type = HTTPD_MSG_NONE;
......@@ -1269,35 +1185,30 @@ static void httpd_MsgInit( httpd_message_t *msg )
msg->p_body = NULL;
}
static void httpd_MsgClean( httpd_message_t *msg )
static void httpd_MsgClean(httpd_message_t *msg)
{
free( msg->psz_url );
free( msg->psz_args );
for( size_t i = 0; i < msg->i_headers; i++ )
{
free( msg->p_headers[i].name );
free( msg->p_headers[i].value );
}
free( msg->p_headers );
free( msg->p_body );
httpd_MsgInit( msg );
free(msg->psz_url);
free(msg->psz_args);
for (size_t i = 0; i < msg->i_headers; i++) {
free(msg->p_headers[i].name);
free(msg->p_headers[i].value);
}
free(msg->p_headers);
free(msg->p_body);
httpd_MsgInit(msg);
}
const char *httpd_MsgGet( const httpd_message_t *msg, const char *name )
const char *httpd_MsgGet(const httpd_message_t *msg, const char *name)
{
for( size_t i = 0; i < msg->i_headers; i++ )
{
if( !strcasecmp( msg->p_headers[i].name, name ))
{
for (size_t i = 0; i < msg->i_headers; i++)
if (!strcasecmp(msg->p_headers[i].name, name))
return msg->p_headers[i].value;
}
}
return NULL;
}
void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value, ... )
void httpd_MsgAdd(httpd_message_t *msg, const char *name, const char *psz_value, ...)
{
httpd_header *p_tmp = realloc( msg->p_headers, sizeof(httpd_header) * (msg->i_headers + 1));
httpd_header *p_tmp = realloc(msg->p_headers, sizeof(httpd_header) * (msg->i_headers + 1));
if (!p_tmp)
return;
......@@ -1311,11 +1222,11 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value
h->value = NULL;
va_list args;
va_start( args, psz_value );
va_start(args, psz_value);
int ret = us_vasprintf(&h->value, psz_value, args);
va_end( args );
va_end(args);
if (ret == -1 ) {
if (ret == -1) {
free(h->name);
return;
}
......@@ -1323,61 +1234,60 @@ void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value
msg->i_headers++;
}
static void httpd_ClientInit( httpd_client_t *cl, mtime_t now )
static void httpd_ClientInit(httpd_client_t *cl, mtime_t now)
{
cl->i_state = HTTPD_CLIENT_RECEIVING;
cl->i_activity_date = now;
cl->i_activity_timeout = INT64_C(10000000);
cl->i_buffer_size = HTTPD_CL_BUFSIZE;
cl->i_buffer = 0;
cl->p_buffer = xmalloc( cl->i_buffer_size );
cl->p_buffer = xmalloc(cl->i_buffer_size);
cl->i_keyframe_wait_to_pass = -1;
cl->b_stream_mode = false;
httpd_MsgInit( &cl->query );
httpd_MsgInit( &cl->answer );
httpd_MsgInit(&cl->query);
httpd_MsgInit(&cl->answer);
}
char* httpd_ClientIP( const httpd_client_t *cl, char *ip, int *port )
char* httpd_ClientIP(const httpd_client_t *cl, char *ip, int *port)
{
return net_GetPeerAddress( cl->fd, ip, port ) ? NULL : ip;
return net_GetPeerAddress(cl->fd, ip, port) ? NULL : ip;
}
char* httpd_ServerIP( const httpd_client_t *cl, char *ip, int *port )
char* httpd_ServerIP(const httpd_client_t *cl, char *ip, int *port)
{
return net_GetSockAddress( cl->fd, ip, port ) ? NULL : ip;
return net_GetSockAddress(cl->fd, ip, port) ? NULL : ip;
}
static void httpd_ClientClean( httpd_client_t *cl )
static void httpd_ClientClean(httpd_client_t *cl)
{
if( cl->fd >= 0 )
{
if( cl->p_tls != NULL )
vlc_tls_SessionDelete( cl->p_tls );
net_Close( cl->fd );
if (cl->fd >= 0) {
if (cl->p_tls)
vlc_tls_SessionDelete(cl->p_tls);
net_Close(cl->fd);
cl->fd = -1;
}
httpd_MsgClean( &cl->answer );
httpd_MsgClean( &cl->query );
httpd_MsgClean(&cl->answer);
httpd_MsgClean(&cl->query);
free( cl->p_buffer );
free(cl->p_buffer);
cl->p_buffer = NULL;
}
static httpd_client_t *httpd_ClientNew( int fd, vlc_tls_t *p_tls, mtime_t now )
static httpd_client_t *httpd_ClientNew(int fd, vlc_tls_t *p_tls, mtime_t now)
{
httpd_client_t *cl = malloc( sizeof( httpd_client_t ) );
httpd_client_t *cl = malloc(sizeof(httpd_client_t));
if( !cl ) return NULL;
if (!cl) return NULL;
cl->i_ref = 0;
cl->fd = fd;
cl->url = NULL;
cl->p_tls = p_tls;
httpd_ClientInit( cl, now );
if( p_tls != NULL )
httpd_ClientInit(cl, now);
if (p_tls)
cl->i_state = HTTPD_CLIENT_TLS_HS_OUT;
return cl;
......@@ -1405,7 +1315,7 @@ ssize_t httpd_NetSend (httpd_client_t *cl, const uint8_t *p, size_t i_len)
p_tls = cl->p_tls;
do
val = p_tls ? tls_Send( p_tls, p, i_len )
val = p_tls ? tls_Send(p_tls, p, i_len)
: send (cl->fd, p, i_len, 0);
while (val == -1 && errno == EINTR);
return val;
......@@ -1434,455 +1344,355 @@ msg_type[] =
};
static void httpd_ClientRecv( httpd_client_t *cl )
static void httpd_ClientRecv(httpd_client_t *cl)
{
int i_len;
/* ignore leading whites */
if( ( cl->query.i_proto == HTTPD_PROTO_NONE ) &&
( cl->i_buffer == 0 ) )
{
if (cl->query.i_proto == HTTPD_PROTO_NONE && cl->i_buffer == 0) {
unsigned char c;
i_len = httpd_NetRecv( cl, &c, 1 );
i_len = httpd_NetRecv(cl, &c, 1);
if( ( i_len > 0 ) && ( strchr( "\r\n\t ", c ) == NULL ) )
{
if (i_len > 0 && !strchr("\r\n\t ", c)) {
cl->p_buffer[0] = c;
cl->i_buffer++;
}
}
else
if( cl->query.i_proto == HTTPD_PROTO_NONE )
{
} else if (cl->query.i_proto == HTTPD_PROTO_NONE) {
/* enough to see if it's Interleaved RTP over RTSP or RTSP/HTTP */
i_len = httpd_NetRecv( cl, &cl->p_buffer[cl->i_buffer],
7 - cl->i_buffer );
if( i_len > 0 )
{
i_len = httpd_NetRecv(cl, &cl->p_buffer[cl->i_buffer],
7 - cl->i_buffer);
if (i_len > 0)
cl->i_buffer += i_len;
}
/* The smallest legal request is 7 bytes ("GET /\r\n"),
* this is the maximum we can ask at this point. */
if( cl->i_buffer >= 7 )
{
if( !memcmp( cl->p_buffer, "HTTP/1.", 7 ) )
{
if (cl->i_buffer >= 7) {
if (!memcmp(cl->p_buffer, "HTTP/1.", 7)) {
cl->query.i_proto = HTTPD_PROTO_HTTP;
cl->query.i_type = HTTPD_MSG_ANSWER;
}
else if( !memcmp( cl->p_buffer, "RTSP/1.", 7 ) )
{
} else if (!memcmp(cl->p_buffer, "RTSP/1.", 7)) {
cl->query.i_proto = HTTPD_PROTO_RTSP;
cl->query.i_type = HTTPD_MSG_ANSWER;
}
else
{
} else {
/* We need the full request line to determine the protocol. */
cl->query.i_proto = HTTPD_PROTO_HTTP0;
cl->query.i_type = HTTPD_MSG_NONE;
}
}
}
else if( cl->query.i_body > 0 )
{
} else if (cl->query.i_body > 0) {
/* we are reading the body of a request or a channel */
i_len = httpd_NetRecv( cl, &cl->query.p_body[cl->i_buffer],
cl->query.i_body - cl->i_buffer );
if( i_len > 0 )
{
i_len = httpd_NetRecv(cl, &cl->query.p_body[cl->i_buffer],
cl->query.i_body - cl->i_buffer);
if (i_len > 0)
cl->i_buffer += i_len;
}
if( cl->i_buffer >= cl->query.i_body )
{
if (cl->i_buffer >= cl->query.i_body)
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
} else for (;;) { /* we are reading a header -> char by char */
if (cl->i_buffer == cl->i_buffer_size) {
uint8_t *newbuf = realloc(cl->p_buffer, cl->i_buffer_size + 1024);
if (!newbuf) {
i_len = 0;
break;
}
cl->p_buffer = newbuf;
cl->i_buffer_size += 1024;
}
}
else
{
/* we are reading a header -> char by char */
for( ;; )
i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1);
if (i_len <= 0)
break;
cl->i_buffer++;
if ((cl->query.i_proto == HTTPD_PROTO_HTTP0)
&& (cl->p_buffer[cl->i_buffer - 1] == '\n'))
{
if( cl->i_buffer == cl->i_buffer_size )
{
uint8_t *newbuf = realloc( cl->p_buffer, cl->i_buffer_size + 1024 );
if( newbuf == NULL )
{
i_len = 0;
break;
}
/* Request line is now complete */
const char *p = memchr(cl->p_buffer, ' ', cl->i_buffer);
size_t len;
cl->p_buffer = newbuf;
cl->i_buffer_size += 1024;
}
assert(cl->query.i_type == HTTPD_MSG_NONE);
i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1 );
if( i_len <= 0 )
{
if (!p) { /* no URI: evil guy */
i_len = 0; /* drop connection */
break;
}
cl->i_buffer++;
if( ( cl->query.i_proto == HTTPD_PROTO_HTTP0 )
&& ( cl->p_buffer[cl->i_buffer - 1] == '\n' ) )
{
/* Request line is now complete */
const char *p = memchr( cl->p_buffer, ' ', cl->i_buffer );
size_t len;
do
p++; /* skips extra spaces */
while (*p == ' ');
assert( cl->query.i_type == HTTPD_MSG_NONE );
if( p == NULL ) /* no URI: evil guy */
{
i_len = 0; /* drop connection */
break;
}
p = memchr(p, ' ', ((char *)cl->p_buffer) + cl->i_buffer - p);
if (!p) { /* no explicit protocol: HTTP/0.9 */
i_len = 0; /* not supported currently -> drop */
break;
}
do
p++; /* skips extra spaces */
while( *p == ' ' );
do
p++; /* skips extra spaces ever again */
while (*p == ' ');
p = memchr( p, ' ', ((char *)cl->p_buffer) + cl->i_buffer - p );
if( p == NULL ) /* no explicit protocol: HTTP/0.9 */
{
i_len = 0; /* not supported currently -> drop */
break;
}
len = ((char *)cl->p_buffer) + cl->i_buffer - p;
if (len < 7) /* foreign protocol */
i_len = 0; /* I don't understand -> drop */
else if (!memcmp(p, "HTTP/1.", 7)) {
cl->query.i_proto = HTTPD_PROTO_HTTP;
cl->query.i_version = atoi(p + 7);
} else if (!memcmp(p, "RTSP/1.", 7)) {
cl->query.i_proto = HTTPD_PROTO_RTSP;
cl->query.i_version = atoi(p + 7);
} else if (!memcmp(p, "HTTP/", 5)) {
const uint8_t sorry[] =
"HTTP/1.1 505 Unknown HTTP version\r\n\r\n";
httpd_NetSend(cl, sorry, sizeof(sorry) - 1);
i_len = 0; /* drop */
} else if (!memcmp(p, "RTSP/", 5)) {
const uint8_t sorry[] =
"RTSP/1.0 505 Unknown RTSP version\r\n\r\n";
httpd_NetSend(cl, sorry, sizeof(sorry) - 1);
i_len = 0; /* drop */
} else /* yet another foreign protocol */
i_len = 0;
if (i_len == 0)
break;
}
do
p++; /* skips extra spaces ever again */
while( *p == ' ' );
len = ((char *)cl->p_buffer) + cl->i_buffer - p;
if( len < 7 ) /* foreign protocol */
i_len = 0; /* I don't understand -> drop */
else
if( memcmp( p, "HTTP/1.", 7 ) == 0 )
{
cl->query.i_proto = HTTPD_PROTO_HTTP;
cl->query.i_version = atoi( p + 7 );
}
else
if( memcmp( p, "RTSP/1.", 7 ) == 0 )
{
cl->query.i_proto = HTTPD_PROTO_RTSP;
cl->query.i_version = atoi( p + 7 );
}
else
if( memcmp( p, "HTTP/", 5 ) == 0 )
{
const uint8_t sorry[] =
"HTTP/1.1 505 Unknown HTTP version\r\n\r\n";
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
i_len = 0; /* drop */
}
else
if( memcmp( p, "RTSP/", 5 ) == 0 )
{
const uint8_t sorry[] =
"RTSP/1.0 505 Unknown RTSP version\r\n\r\n";
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
i_len = 0; /* drop */
}
else /* yet another foreign protocol */
i_len = 0;
if ((cl->i_buffer >= 2 && !memcmp(&cl->p_buffer[cl->i_buffer-2], "\n\n", 2))||
(cl->i_buffer >= 4 && !memcmp(&cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4)))
{
char *p;
/* we have finished the header so parse it and set i_body */
cl->p_buffer[cl->i_buffer] = '\0';
if (cl->query.i_type == HTTPD_MSG_ANSWER) {
/* FIXME:
* assume strlen("HTTP/1.x") = 8
*/
cl->query.i_status =
strtol((char *)&cl->p_buffer[8],
&p, 0);
while (*p == ' ')
p++;
} else {
p = NULL;
cl->query.i_type = HTTPD_MSG_NONE;
for (unsigned i = 0; msg_type[i].name[0]; i++)
if (!strncmp((char *)cl->p_buffer, msg_type[i].name,
strlen(msg_type[i].name))) {
p = (char *)&cl->p_buffer[strlen(msg_type[i].name) + 1 ];
cl->query.i_type = msg_type[i].i_type;
if (cl->query.i_proto != msg_type[i].i_proto) {
p = NULL;
cl->query.i_proto = HTTPD_PROTO_NONE;
cl->query.i_type = HTTPD_MSG_NONE;
}
break;
}
if( i_len == 0 )
break;
}
if (!p) {
if (strstr((char *)cl->p_buffer, "HTTP/1."))
cl->query.i_proto = HTTPD_PROTO_HTTP;
else if (strstr((char *)cl->p_buffer, "RTSP/1."))
cl->query.i_proto = HTTPD_PROTO_RTSP;
} else {
char *p2;
char *p3;
if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )||
( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) )
{
char *p;
/* we have finished the header so parse it and set i_body */
cl->p_buffer[cl->i_buffer] = '\0';
if( cl->query.i_type == HTTPD_MSG_ANSWER )
{
/* FIXME:
* assume strlen( "HTTP/1.x" ) = 8
*/
cl->query.i_status =
strtol( (char *)&cl->p_buffer[8],
&p, 0 );
while( *p == ' ' )
while (*p == ' ')
p++;
}
else
{
p = NULL;
cl->query.i_type = HTTPD_MSG_NONE;
for( unsigned i = 0; msg_type[i].name[0]; i++ )
{
if( !strncmp( (char *)cl->p_buffer, msg_type[i].name,
strlen( msg_type[i].name ) ) )
{
p = (char *)&cl->p_buffer[strlen(msg_type[i].name) + 1 ];
cl->query.i_type = msg_type[i].i_type;
if( cl->query.i_proto != msg_type[i].i_proto )
{
p = NULL;
cl->query.i_proto = HTTPD_PROTO_NONE;
cl->query.i_type = HTTPD_MSG_NONE;
}
break;
p2 = strchr(p, ' ');
if (p2)
*p2++ = '\0';
if (!strncasecmp(p, (cl->query.i_proto == HTTPD_PROTO_HTTP) ? "http:" : "rtsp:", 5)) {
/* Skip hier-part of URL (if present) */
p += 5;
if (!strncmp(p, "//", 2)) { /* skip authority */
/* see RFC3986 §3.2 */
p += 2;
p += strcspn(p, "/?#");
}
}
if( p == NULL )
{
if( strstr( (char *)cl->p_buffer, "HTTP/1." ) )
{
cl->query.i_proto = HTTPD_PROTO_HTTP;
}
else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) )
{
cl->query.i_proto = HTTPD_PROTO_RTSP;
else if (!strncasecmp(p, (cl->query.i_proto == HTTPD_PROTO_HTTP) ? "https:" : "rtsps:", 6)) {
/* Skip hier-part of URL (if present) */
p += 6;
if (!strncmp(p, "//", 2)) { /* skip authority */
/* see RFC3986 §3.2 */
p += 2;
p += strcspn(p, "/?#");
}
}
else
{
char *p2;
char *p3;
while( *p == ' ' )
{
p++;
}
p2 = strchr( p, ' ' );
if( p2 )
{
*p2++ = '\0';
}
if( !strncasecmp( p, ( cl->query.i_proto
== HTTPD_PROTO_HTTP ) ? "http:" : "rtsp:", 5 ) )
{ /* Skip hier-part of URL (if present) */
p += 5;
if( !strncmp( p, "//", 2 ) ) /* skip authority */
{ /* see RFC3986 §3.2 */
p += 2;
p += strcspn( p, "/?#" );
}
}
else
if( !strncasecmp( p, ( cl->query.i_proto
== HTTPD_PROTO_HTTP ) ? "https:" : "rtsps:", 6 ) )
{ /* Skip hier-part of URL (if present) */
p += 6;
if( !strncmp( p, "//", 2 ) ) /* skip authority */
{ /* see RFC3986 §3.2 */
p += 2;
p += strcspn( p, "/?#" );
}
}
cl->query.psz_url = strdup( p );
if( ( p3 = strchr( cl->query.psz_url, '?' ) ) )
{
*p3++ = '\0';
cl->query.psz_args = (uint8_t *)strdup( p3 );
}
p = p2;
cl->query.psz_url = strdup(p);
if ((p3 = strchr(cl->query.psz_url, '?')) ) {
*p3++ = '\0';
cl->query.psz_args = (uint8_t *)strdup(p3);
}
p = p2;
}
if( p )
{
p = strchr( p, '\n' );
}
if( p )
{
while( *p == '\n' || *p == '\r' )
{
p++;
}
while( p && *p != '\0' )
{
char *line = p;
char *eol = p = strchr( p, '\n' );
char *colon;
while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) )
{
*eol-- = '\0';
}
}
if (p)
p = strchr(p, '\n');
if( ( colon = strchr( line, ':' ) ) )
{
*colon++ = '\0';
while( *colon == ' ' )
{
colon++;
}
httpd_MsgAdd( &cl->query, line, colon );
if (p) {
while (*p == '\n' || *p == '\r')
p++;
if( !strcasecmp( line, "Content-Length" ) )
{
cl->query.i_body = atol( colon );
}
}
while (p && *p) {
char *line = p;
char *eol = p = strchr(p, '\n');
char *colon;
if( p )
{
while (eol && eol >= line && (*eol == '\n' || *eol == '\r'))
*eol-- = '\0';
if ((colon = strchr(line, ':'))) {
*colon++ = '\0';
while (*colon == ' ')
colon++;
httpd_MsgAdd(&cl->query, line, colon);
if (!strcasecmp(line, "Content-Length"))
cl->query.i_body = atol(colon);
}
if (p) {
p++;
while (*p == '\n' || *p == '\r')
p++;
while( *p == '\n' || *p == '\r' )
{
p++;
}
}
}
}
if( cl->query.i_body > 0 )
{
/* TODO Mhh, handle the case where the client only
* sends a request and closes the connection to
* mark the end of the body (probably only RTSP) */
cl->query.p_body = malloc( cl->query.i_body );
cl->i_buffer = 0;
if ( cl->query.p_body == NULL ) {
switch (cl->query.i_proto) {
}
if (cl->query.i_body > 0) {
/* TODO Mhh, handle the case where the client only
* sends a request and closes the connection to
* mark the end of the body (probably only RTSP) */
cl->query.p_body = malloc(cl->query.i_body);
cl->i_buffer = 0;
if (!cl->query.p_body) {
switch (cl->query.i_proto) {
case HTTPD_PROTO_HTTP: {
const uint8_t sorry[] =
"HTTP/1.1 413 Request Entity Too Large\r\n\r\n";
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
break;
}
const uint8_t sorry[] =
"HTTP/1.1 413 Request Entity Too Large\r\n\r\n";
httpd_NetSend(cl, sorry, sizeof(sorry) - 1);
break;
}
case HTTPD_PROTO_RTSP: {
const uint8_t sorry[] =
"RTSP/1.0 413 Request Entity Too Large\r\n\r\n";
httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 );
break;
}
const uint8_t sorry[] =
"RTSP/1.0 413 Request Entity Too Large\r\n\r\n";
httpd_NetSend(cl, sorry, sizeof(sorry) - 1);
break;
}
default:
assert( 0 );
}
i_len = 0; /* drop */
assert(0);
}
break;
}
else
{
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
i_len = 0; /* drop */
}
}
break;
} else
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
}
}
/* check if the client is to be set to dead */
#if defined( _WIN32 )
if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
#if defined(_WIN32)
if ((i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK) || (i_len == 0))
#else
if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )
if ((i_len < 0 && errno != EAGAIN) || (i_len == 0))
#endif
{
if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE )
{
if (cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE) {
/* connection closed -> end of data */
if( cl->query.i_body > 0 )
{
if (cl->query.i_body > 0)
cl->query.i_body = cl->i_buffer;
}
cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
}
else
{
cl->i_state = HTTPD_CLIENT_DEAD;
}
}
/* XXX: for QT I have to disable timeout. Try to find why */
if( cl->query.i_proto == HTTPD_PROTO_RTSP )
if (cl->query.i_proto == HTTPD_PROTO_RTSP)
cl->i_activity_timeout = 0;
}
static void httpd_ClientSend( httpd_client_t *cl )
static void httpd_ClientSend(httpd_client_t *cl)
{
int i_len;
if( cl->i_buffer < 0 )
{
if (cl->i_buffer < 0) {
/* We need to create the header */
int i_size = 0;
char *p;
const char *psz_status = httpd_ReasonFromCode( cl->answer.i_status );
const char *psz_status = httpd_ReasonFromCode(cl->answer.i_status);
i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( psz_status ) + 5;
for( size_t i = 0; i < cl->answer.i_headers; i++ )
{
i_size += strlen( cl->answer.p_headers[i].name ) + 2 +
strlen( cl->answer.p_headers[i].value ) + 2;
}
i_size = strlen("HTTP/1.") + 10 + 10 + strlen(psz_status) + 5;
for (size_t i = 0; i < cl->answer.i_headers; i++)
i_size += strlen(cl->answer.p_headers[i].name) + 2 +
strlen(cl->answer.p_headers[i].value) + 2;
if( cl->i_buffer_size < i_size )
{
if (cl->i_buffer_size < i_size) {
cl->i_buffer_size = i_size;
free( cl->p_buffer );
cl->p_buffer = xmalloc( i_size );
free(cl->p_buffer);
cl->p_buffer = xmalloc(i_size);
}
p = (char *)cl->p_buffer;
p += sprintf( p, "%s.%u %d %s\r\n",
p += sprintf(p, "%s.%u %d %s\r\n",
cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP/1" : "RTSP/1",
cl->answer.i_version,
cl->answer.i_status, psz_status );
for( size_t i = 0; i < cl->answer.i_headers; i++ )
{
p += sprintf( p, "%s: %s\r\n", cl->answer.p_headers[i].name,
cl->answer.p_headers[i].value );
}
p += sprintf( p, "\r\n" );
cl->answer.i_status, psz_status);
for (size_t i = 0; i < cl->answer.i_headers; i++)
p += sprintf(p, "%s: %s\r\n", cl->answer.p_headers[i].name,
cl->answer.p_headers[i].value);
p += sprintf(p, "\r\n");
cl->i_buffer = 0;
cl->i_buffer_size = (uint8_t*)p - cl->p_buffer;
}
i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer],
cl->i_buffer_size - cl->i_buffer );
if( i_len >= 0 )
{
i_len = httpd_NetSend(cl, &cl->p_buffer[cl->i_buffer],
cl->i_buffer_size - cl->i_buffer);
if (i_len >= 0) {
cl->i_buffer += i_len;
if( cl->i_buffer >= cl->i_buffer_size )
{
if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 )
{
if (cl->i_buffer >= cl->i_buffer_size) {
if (cl->answer.i_body == 0 && cl->answer.i_body_offset > 0) {
/* catch more body data */
int i_msg = cl->query.i_type;
int64_t i_offset = cl->answer.i_body_offset;
httpd_MsgClean( &cl->answer );
httpd_MsgClean(&cl->answer);
cl->answer.i_body_offset = i_offset;
cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
&cl->answer, &cl->query );
cl->url->catch[i_msg].cb(cl->url->catch[i_msg].p_sys, cl,
&cl->answer, &cl->query);
}
if( cl->answer.i_body > 0 )
{
if (cl->answer.i_body > 0) {
/* send the body data */
free( cl->p_buffer );
free(cl->p_buffer);
cl->p_buffer = cl->answer.p_body;
cl->i_buffer_size = cl->answer.i_body;
cl->i_buffer = 0;
cl->answer.i_body = 0;
cl->answer.p_body = NULL;
}
else
{
/* send finished */
} else /* send finished */
cl->i_state = HTTPD_CLIENT_SEND_DONE;
}
}
}
else
{
#if defined( _WIN32 )
if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
} else {
#if defined(_WIN32)
if ((i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK) || (i_len == 0))
#else
if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )
if ((i_len < 0 && errno != EAGAIN) || (i_len == 0))
#endif
{
/* error */
......@@ -1891,9 +1701,9 @@ static void httpd_ClientSend( httpd_client_t *cl )
}
}
static void httpd_ClientTlsHandshake( httpd_client_t *cl )
static void httpd_ClientTlsHandshake(httpd_client_t *cl)
{
switch( vlc_tls_SessionHandshake( cl->p_tls, NULL, NULL ) ) {
switch(vlc_tls_SessionHandshake(cl->p_tls, NULL, NULL)) {
case -1: cl->i_state = HTTPD_CLIENT_DEAD; break;
case 0: cl->i_state = HTTPD_CLIENT_RECEIVING; break;
case 1: cl->i_state = HTTPD_CLIENT_TLS_HS_IN; break;
......@@ -1933,11 +1743,11 @@ static bool httpdAuthOk(const char *user, const char *pass, const char *b64)
if (strcmp (given_pass, pass))
goto auth_failed;
free( given_user );
free(given_user);
return true;
auth_failed:
free( given_user );
free(given_user);
return false;
}
......@@ -1945,18 +1755,16 @@ static void httpdLoop(httpd_host_t *host)
{
struct pollfd ufd[host->nfd + host->i_client];
unsigned nfd;
for( nfd = 0; nfd < host->nfd; nfd++ )
{
for (nfd = 0; nfd < host->nfd; nfd++) {
ufd[nfd].fd = host->fds[nfd];
ufd[nfd].events = POLLIN;
ufd[nfd].revents = 0;
}
/* add all socket that should be read/write and close dead connection */
while( host->i_url <= 0 )
{
mutex_cleanup_push( &host->lock );
vlc_cond_wait( &host->wait, &host->lock );
while (host->i_url <= 0) {
mutex_cleanup_push(&host->lock);
vlc_cond_wait(&host->wait, &host->lock);
vlc_cleanup_pop();
}
......@@ -1964,18 +1772,16 @@ static void httpdLoop(httpd_host_t *host)
bool b_low_delay = false;
int canc = vlc_savecancel();
for(int i_client = 0; i_client < host->i_client; i_client++ )
{
for (int i_client = 0; i_client < host->i_client; i_client++) {
int64_t i_offset;
httpd_client_t *cl = host->client[i_client];
if( cl->i_ref < 0 || ( cl->i_ref == 0 &&
( cl->i_state == HTTPD_CLIENT_DEAD ||
( cl->i_activity_timeout > 0 &&
cl->i_activity_date+cl->i_activity_timeout < now) ) ) )
{
httpd_ClientClean( cl );
TAB_REMOVE( host->i_client, host->client, cl );
free( cl );
if (cl->i_ref < 0 || (cl->i_ref == 0 &&
(cl->i_state == HTTPD_CLIENT_DEAD ||
(cl->i_activity_timeout > 0 &&
cl->i_activity_date+cl->i_activity_timeout < now)))) {
httpd_ClientClean(cl);
TAB_REMOVE(host->i_client, host->client, cl);
free(cl);
i_client--;
continue;
}
......@@ -2001,7 +1807,7 @@ static void httpdLoop(httpd_host_t *host)
httpd_message_t *answer = &cl->answer;
httpd_message_t *query = &cl->query;
httpd_MsgInit( answer );
httpd_MsgInit(answer);
/* Handle what we received */
switch (query->i_type) {
......@@ -2017,11 +1823,10 @@ static void httpdLoop(httpd_host_t *host)
answer->i_body = 0;
answer->p_body = NULL;
httpd_MsgAdd( answer, "Server", "VLC/%s", VERSION );
httpd_MsgAdd( answer, "Content-Length", "0" );
httpd_MsgAdd(answer, "Server", "VLC/%s", VERSION);
httpd_MsgAdd(answer, "Content-Length", "0");
switch( query->i_proto )
{
switch(query->i_proto) {
case HTTPD_PROTO_HTTP:
answer->i_version = 1;
httpd_MsgAdd(answer, "Allow", "GET,HEAD,POST,OPTIONS");
......@@ -2030,21 +1835,21 @@ static void httpdLoop(httpd_host_t *host)
case HTTPD_PROTO_RTSP:
answer->i_version = 0;
const char *p = httpd_MsgGet( query, "Cseq" );
if( p != NULL )
httpd_MsgAdd( answer, "Cseq", "%s", p );
p = httpd_MsgGet( query, "Timestamp" );
if( p != NULL )
httpd_MsgAdd( answer, "Timestamp", "%s", p );
const char *p = httpd_MsgGet(query, "Cseq");
if (p)
httpd_MsgAdd(answer, "Cseq", "%s", p);
p = httpd_MsgGet(query, "Timestamp");
if (p)
httpd_MsgAdd(answer, "Timestamp", "%s", p);
p = httpd_MsgGet( query, "Require" );
if( p != NULL ) {
p = httpd_MsgGet(query, "Require");
if (p) {
answer->i_status = 551;
httpd_MsgAdd( query, "Unsupported", "%s", p );
httpd_MsgAdd(query, "Unsupported", "%s", p);
}
httpd_MsgAdd( answer, "Public", "DESCRIBE,SETUP,"
"TEARDOWN,PLAY,PAUSE,GET_PARAMETER" );
httpd_MsgAdd(answer, "Public", "DESCRIBE,SETUP,"
"TEARDOWN,PLAY,PAUSE,GET_PARAMETER");
break;
}
......@@ -2054,7 +1859,7 @@ static void httpdLoop(httpd_host_t *host)
break;
case HTTPD_MSG_NONE:
if( query->i_proto == HTTPD_PROTO_NONE ) {
if (query->i_proto == HTTPD_PROTO_NONE) {
cl->url = NULL;
cl->i_state = HTTPD_CLIENT_DEAD;
} else {
......@@ -2067,7 +1872,7 @@ static void httpdLoop(httpd_host_t *host)
char *p;
answer->i_body = httpd_HtmlError (&p, 501, NULL);
answer->p_body = (uint8_t *)p;
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
httpd_MsgAdd(answer, "Content-Length", "%d", answer->i_body);
cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */
cl->i_state = HTTPD_CLIENT_SENDING;
......@@ -2079,7 +1884,7 @@ static void httpdLoop(httpd_host_t *host)
bool b_auth_failed = false;
/* Search the url and trigger callbacks */
for(int i = 0; i < host->i_url; i++ ) {
for (int i = 0; i < host->i_url; i++) {
httpd_url_t *url = host->url[i];
if (strcmp(url->psz_url, query->psz_url))
......@@ -2098,25 +1903,25 @@ static void httpdLoop(httpd_host_t *host)
if (url->catch[i_msg].cb(url->catch[i_msg].p_sys, cl, answer, query))
continue;
if( answer->i_proto == HTTPD_PROTO_NONE )
if (answer->i_proto == HTTPD_PROTO_NONE)
cl->i_buffer = cl->i_buffer_size; /* Raw answer from a CGI */
else
cl->i_buffer = -1;
/* only one url can answer */
answer = NULL;
if( cl->url == NULL )
if (!cl->url)
cl->url = url;
}
if( answer ) {
if (answer) {
answer->i_proto = query->i_proto;
answer->i_type = HTTPD_MSG_ANSWER;
answer->i_version= 0;
if( b_auth_failed ) {
httpd_MsgAdd( answer, "WWW-Authenticate",
"Basic realm=\"VLC stream\"" );
if (b_auth_failed) {
httpd_MsgAdd(answer, "WWW-Authenticate",
"Basic realm=\"VLC stream\"");
answer->i_status = 401;
} else
answer->i_status = 404; /* no url registered */
......@@ -2127,8 +1932,8 @@ static void httpdLoop(httpd_host_t *host)
answer->p_body = (uint8_t *)p;
cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */
httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
httpd_MsgAdd( answer, "Content-Type", "%s", "text/html" );
httpd_MsgAdd(answer, "Content-Length", "%d", answer->i_body);
httpd_MsgAdd(answer, "Content-Type", "%s", "text/html");
}
cl->i_state = HTTPD_CLIENT_SENDING;
......@@ -2138,54 +1943,44 @@ static void httpdLoop(httpd_host_t *host)
}
case HTTPD_CLIENT_SEND_DONE:
if( !cl->b_stream_mode || cl->answer.i_body_offset == 0 )
{
const char *psz_connection = httpd_MsgGet( &cl->answer, "Connection" );
const char *psz_query = httpd_MsgGet( &cl->query, "Connection" );
if (!cl->b_stream_mode || cl->answer.i_body_offset == 0) {
const char *psz_connection = httpd_MsgGet(&cl->answer, "Connection");
const char *psz_query = httpd_MsgGet(&cl->query, "Connection");
bool b_connection = false;
bool b_keepalive = false;
bool b_query = false;
cl->url = NULL;
if( psz_connection )
{
b_connection = ( strcasecmp( psz_connection, "Close" ) == 0 );
b_keepalive = ( strcasecmp( psz_connection, "Keep-Alive" ) == 0 );
if (psz_connection) {
b_connection = (strcasecmp(psz_connection, "Close") == 0);
b_keepalive = (strcasecmp(psz_connection, "Keep-Alive") == 0);
}
if( psz_query )
{
b_query = ( strcasecmp( psz_query, "Close" ) == 0 );
}
if (psz_query)
b_query = (strcasecmp(psz_query, "Close") == 0);
if( ( ( cl->query.i_proto == HTTPD_PROTO_HTTP ) &&
( ( cl->query.i_version == 0 && b_keepalive ) ||
( cl->query.i_version == 1 && !b_connection ) ) ) ||
( ( cl->query.i_proto == HTTPD_PROTO_RTSP ) &&
!b_query && !b_connection ) )
{
httpd_MsgClean( &cl->query );
httpd_MsgInit( &cl->query );
if (((cl->query.i_proto == HTTPD_PROTO_HTTP) &&
((cl->query.i_version == 0 && b_keepalive) ||
(cl->query.i_version == 1 && !b_connection))) ||
((cl->query.i_proto == HTTPD_PROTO_RTSP) &&
!b_query && !b_connection)) {
httpd_MsgClean(&cl->query);
httpd_MsgInit(&cl->query);
cl->i_buffer = 0;
cl->i_buffer_size = 1000;
free( cl->p_buffer );
cl->p_buffer = xmalloc( cl->i_buffer_size );
free(cl->p_buffer);
cl->p_buffer = xmalloc(cl->i_buffer_size);
cl->i_state = HTTPD_CLIENT_RECEIVING;
}
else
{
} else
cl->i_state = HTTPD_CLIENT_DEAD;
}
httpd_MsgClean( &cl->answer );
}
else
{
httpd_MsgClean(&cl->answer);
} else {
i_offset = cl->answer.i_body_offset;
httpd_MsgClean( &cl->answer );
httpd_MsgClean(&cl->answer);
cl->answer.i_body_offset = i_offset;
free( cl->p_buffer );
free(cl->p_buffer);
cl->p_buffer = NULL;
cl->i_buffer = 0;
cl->i_buffer_size = 0;
......@@ -2198,13 +1993,12 @@ static void httpdLoop(httpd_host_t *host)
i_offset = cl->answer.i_body_offset;
int i_msg = cl->query.i_type;
httpd_MsgInit( &cl->answer );
httpd_MsgInit(&cl->answer);
cl->answer.i_body_offset = i_offset;
cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
&cl->answer, &cl->query );
if( cl->answer.i_type != HTTPD_MSG_NONE )
{
cl->url->catch[i_msg].cb(cl->url->catch[i_msg].p_sys, cl,
&cl->answer, &cl->query);
if (cl->answer.i_type != HTTPD_MSG_NONE) {
/* we have new data, so re-enter send mode */
cl->i_buffer = 0;
cl->p_buffer = cl->answer.p_body;
......@@ -2220,23 +2014,23 @@ static void httpdLoop(httpd_host_t *host)
else
b_low_delay = true;
}
vlc_mutex_unlock( &host->lock );
vlc_restorecancel( canc );
vlc_mutex_unlock(&host->lock);
vlc_restorecancel(canc);
/* we will wait 20ms (not too big) if HTTPD_CLIENT_WAITING */
int ret = poll( ufd, nfd, b_low_delay ? 20 : -1 );
int ret = poll(ufd, nfd, b_low_delay ? 20 : -1);
canc = vlc_savecancel();
vlc_mutex_lock( &host->lock );
switch( ret ) {
vlc_mutex_lock(&host->lock);
switch(ret) {
case -1:
if (errno != EINTR) {
/* Kernel on low memory or a bug: pace */
msg_Err( host, "polling error: %s", vlc_strerror_c(errno) );
msleep( 100000 );
msg_Err(host, "polling error: %s", vlc_strerror_c(errno));
msleep(100000);
}
case 0:
vlc_restorecancel( canc );
vlc_restorecancel(canc);
return;
}
......@@ -2244,38 +2038,36 @@ static void httpdLoop(httpd_host_t *host)
now = mdate();
nfd = host->nfd;
for( int i_client = 0; i_client < host->i_client; i_client++ )
{
for (int i_client = 0; i_client < host->i_client; i_client++) {
httpd_client_t *cl = host->client[i_client];
const struct pollfd *pufd = &ufd[nfd];
assert( pufd < &ufd[sizeof(ufd) / sizeof(ufd[0])] );
assert(pufd < &ufd[sizeof(ufd) / sizeof(ufd[0])]);
if( cl->fd != pufd->fd )
if (cl->fd != pufd->fd)
continue; // we were not waiting for this client
++nfd;
if( pufd->revents == 0 )
if (pufd->revents == 0)
continue; // no event received
cl->i_activity_date = now;
switch (cl->i_state) {
case HTTPD_CLIENT_RECEIVING: httpd_ClientRecv( cl ); break;
case HTTPD_CLIENT_SENDING: httpd_ClientSend( cl ); break;
case HTTPD_CLIENT_RECEIVING: httpd_ClientRecv(cl); break;
case HTTPD_CLIENT_SENDING: httpd_ClientSend(cl); break;
case HTTPD_CLIENT_TLS_HS_IN:
case HTTPD_CLIENT_TLS_HS_OUT: httpd_ClientTlsHandshake( cl ); break;
case HTTPD_CLIENT_TLS_HS_OUT: httpd_ClientTlsHandshake(cl); break;
}
}
/* Handle server sockets (accept new connections) */
for( nfd = 0; nfd < host->nfd; nfd++ )
{
for (nfd = 0; nfd < host->nfd; nfd++) {
httpd_client_t *cl;
int fd = ufd[nfd].fd;
assert (fd == host->fds[nfd]);
if( ufd[nfd].revents == 0 )
if (ufd[nfd].revents == 0)
continue;
/* */
......@@ -2287,80 +2079,74 @@ static void httpdLoop(httpd_host_t *host)
vlc_tls_t *p_tls;
if( host->p_tls != NULL )
p_tls = vlc_tls_SessionCreate( host->p_tls, fd, NULL );
if (host->p_tls)
p_tls = vlc_tls_SessionCreate(host->p_tls, fd, NULL);
else
p_tls = NULL;
cl = httpd_ClientNew( fd, p_tls, now );
cl = httpd_ClientNew(fd, p_tls, now);
TAB_APPEND( host->i_client, host->client, cl );
TAB_APPEND(host->i_client, host->client, cl);
}
vlc_restorecancel(canc);
}
static void* httpd_HostThread( void *data )
static void* httpd_HostThread(void *data)
{
httpd_host_t *host = data;
vlc_mutex_lock( &host->lock );
while( host->i_ref > 0 )
vlc_mutex_lock(&host->lock);
while (host->i_ref > 0)
httpdLoop(host);
vlc_mutex_unlock( &host->lock );
vlc_mutex_unlock(&host->lock);
return NULL;
}
int httpd_StreamSetHTTPHeaders(httpd_stream_t * p_stream, httpd_header * p_headers, size_t i_headers )
int httpd_StreamSetHTTPHeaders(httpd_stream_t * p_stream, httpd_header * p_headers, size_t i_headers)
{
if( !p_stream )
if (!p_stream)
return VLC_EGENERIC;
vlc_mutex_lock( &p_stream->lock );
if( p_stream->p_http_headers )
{
for( size_t i = 0; i < p_stream->i_http_headers; i++)
{
free( p_stream->p_http_headers[i].name );
free( p_stream->p_http_headers[i].value );
vlc_mutex_lock(&p_stream->lock);
if (p_stream->p_http_headers) {
for (size_t i = 0; i < p_stream->i_http_headers; i++) {
free(p_stream->p_http_headers[i].name);
free(p_stream->p_http_headers[i].value);
}
free( p_stream->p_http_headers );
free(p_stream->p_http_headers);
p_stream->p_http_headers = NULL;
p_stream->i_http_headers = 0;
}
if( !p_headers || !i_headers )
{
vlc_mutex_unlock( &p_stream->lock );
if (!p_headers || !i_headers) {
vlc_mutex_unlock(&p_stream->lock);
return VLC_SUCCESS;
}
p_stream->p_http_headers = malloc(sizeof(httpd_header) * i_headers );
if( !p_stream->p_http_headers )
{
vlc_mutex_unlock( &p_stream->lock );
p_stream->p_http_headers = malloc(sizeof(httpd_header) * i_headers);
if (!p_stream->p_http_headers) {
vlc_mutex_unlock(&p_stream->lock);
return VLC_ENOMEM;
}
size_t j = 0;
for( size_t i = 0; i < i_headers; i++ )
{
if( unlikely( !p_headers[i].name || !p_headers[i].value ) )
for (size_t i = 0; i < i_headers; i++) {
if (unlikely(!p_headers[i].name || !p_headers[i].value))
continue;
p_stream->p_http_headers[j].name = strdup( p_headers[i].name );
p_stream->p_http_headers[j].value = strdup( p_headers[i].value );
p_stream->p_http_headers[j].name = strdup(p_headers[i].name);
p_stream->p_http_headers[j].value = strdup(p_headers[i].value);
if( unlikely( !p_stream->p_http_headers[j].name ||
!p_stream->p_http_headers[j].value ) )
{
free( p_stream->p_http_headers[j].name );
free( p_stream->p_http_headers[j].value );
if (unlikely(!p_stream->p_http_headers[j].name ||
!p_stream->p_http_headers[j].value)) {
free(p_stream->p_http_headers[j].name);
free(p_stream->p_http_headers[j].value);
break;
}
j++;
}
p_stream->i_http_headers = j;
vlc_mutex_unlock( &p_stream->lock );
vlc_mutex_unlock(&p_stream->lock);
return VLC_SUCCESS;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment