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

httpd: cosmetics

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