static void httpd_ClientClean( httpd_client_t *cl );
-struct httpd_t
-{
- VLC_COMMON_MEMBERS
-
- int i_host;
- httpd_host_t **host;
-};
-
-
/* each host run in his own thread */
struct httpd_host_t
{
VLC_COMMON_MEMBERS
- httpd_t *httpd;
-
/* ref count */
unsigned i_ref;
/* address/port and socket for listening at connections */
- char *psz_hostname;
- int i_port;
int *fds;
unsigned nfd;
+ unsigned port;
vlc_thread_t thread;
vlc_mutex_t lock;
{
HTTPD_CLIENT_FILE, /* default */
HTTPD_CLIENT_STREAM, /* regulary get data from cb */
- HTTPD_CLIENT_BIDIR, /* check for reading and get data from cb */
};
struct httpd_client_t
int fd;
- int i_mode;
- int i_state;
- int b_read_waiting; /* stop as soon as possible sending */
+ bool b_stream_mode;
+ uint8_t i_state;
mtime_t i_activity_date;
mtime_t i_activity_timeout;
/* We do it ourselves, thanks */
answer->i_status = 0;
- if( httpd_ClientIP( cl, psz_remote_addr ) == NULL )
+ if( httpd_ClientIP( cl, psz_remote_addr, NULL ) == NULL )
*psz_remote_addr = '\0';
uint8_t *psz_args = query->psz_args;
if( query->i_type != HTTPD_MSG_HEAD )
{
- httpd_ClientModeStream( cl );
+ cl->b_stream_mode = true;
vlc_mutex_lock( &stream->lock );
/* Send the header */
if( stream->i_header > 0 )
* Low level
*****************************************************************************/
static void* httpd_HostThread( void * );
-static httpd_host_t *httpd_HostCreate( vlc_object_t *, const char *, int,
- vlc_tls_creds_t * );
+static httpd_host_t *httpd_HostCreate( vlc_object_t *, const char *,
+ const char *, vlc_tls_creds_t * );
/* create a new host */
-httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host,
- int i_port )
+httpd_host_t *vlc_http_HostNew( vlc_object_t *p_this )
{
- return httpd_HostCreate( p_this, psz_host, i_port, NULL );
+ return httpd_HostCreate( p_this, "http-host", "http-port", NULL );
}
-httpd_host_t *httpd_TLSHostNew( vlc_object_t *obj, const char *host, int port )
+httpd_host_t *vlc_https_HostNew( vlc_object_t *obj )
{
char *cert = var_InheritString( obj, "http-cert" );
if( cert == NULL )
free( crl );
}
- return httpd_HostCreate( obj, host, port, tls );
+ return httpd_HostCreate( obj, "http-host", "https-port", tls );
error:
vlc_tls_ServerDelete( tls );
return NULL;
}
-static vlc_mutex_t httpd_mutex = VLC_STATIC_MUTEX;
+httpd_host_t *vlc_rtsp_HostNew( vlc_object_t *p_this )
+{
+ return httpd_HostCreate( p_this, "rtsp-host", "rtsp-port", NULL );
+}
+
+static struct httpd_t
+{
+ vlc_mutex_t mutex;
+
+ httpd_host_t **host;
+ int i_host;
+} httpd = { VLC_STATIC_MUTEX, NULL, 0 };
static httpd_host_t *httpd_HostCreate( vlc_object_t *p_this,
- const char *psz_hostname, int i_port,
+ const char *hostvar,
+ const char *portvar,
vlc_tls_creds_t *p_tls )
{
- httpd_t *httpd;
httpd_host_t *host;
- char *psz_host;
- int i;
-
- if( psz_hostname == NULL )
- psz_hostname = "";
-
- psz_host = strdup( psz_hostname );
- if( psz_host == NULL )
- return NULL;
+ unsigned port = var_InheritInteger( p_this, portvar );
/* to be sure to avoid multiple creation */
- vlc_mutex_lock( &httpd_mutex );
- httpd = libvlc_priv (p_this->p_libvlc)->p_httpd;
-
- if( httpd == NULL )
- {
- msg_Info( p_this, "creating httpd" );
- httpd = (httpd_t *)vlc_custom_create( p_this, sizeof (*httpd),
- "http server" );
- if( httpd == NULL )
- {
- vlc_mutex_unlock( &httpd_mutex );
- free( psz_host );
- return NULL;
- }
-
- httpd->i_host = 0;
- httpd->host = NULL;
-
- libvlc_priv (p_this->p_libvlc)->p_httpd = httpd;
- }
+ vlc_mutex_lock( &httpd.mutex );
/* verify if it already exist */
- for( i = httpd->i_host - 1; i >= 0; 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 */
- if( ( ( httpd->host[i]->p_tls != NULL ) != ( p_tls != NULL ) )
- || ( host->i_port != i_port )
- || strcmp( host->psz_hostname, psz_hostname ) )
+ if( host->port != port
+ || (host->p_tls != NULL) != (p_tls != NULL) )
continue;
/* Increase existing matching host reference count.
host->i_ref++;
vlc_mutex_unlock( &host->lock );
- vlc_mutex_unlock( &httpd_mutex );
+ vlc_mutex_unlock( &httpd.mutex );
if( p_tls != NULL )
vlc_tls_ServerDelete( p_tls );
return host;
if (host == NULL)
goto error;
- host->httpd = httpd;
vlc_mutex_init( &host->lock );
vlc_cond_init( &host->wait );
host->i_ref = 1;
- host->fds = net_ListenTCP( p_this, psz_host, i_port );
+ char *hostname = var_InheritString( p_this, hostvar );
+ host->fds = net_ListenTCP( p_this, hostname, port );
+ free( hostname );
if( host->fds == NULL )
{
msg_Err( p_this, "cannot create socket(s) for HTTP host" );
goto error;
}
- host->i_port = i_port;
- host->psz_hostname = psz_host;
-
- host->i_url = 0;
- host->url = NULL;
- host->i_client = 0;
- host->client = NULL;
-
- host->p_tls = p_tls;
+ host->port = port;
+ host->i_url = 0;
+ host->url = NULL;
+ host->i_client = 0;
+ host->client = NULL;
+ host->p_tls = p_tls;
/* create the thread */
if( vlc_clone( &host->thread, httpd_HostThread, host,
}
/* 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 );
return host;
error:
- free( psz_host );
- if( httpd->i_host <= 0 )
- {
- libvlc_priv (httpd->p_libvlc)->p_httpd = NULL;
- vlc_object_release( httpd );
- }
- vlc_mutex_unlock( &httpd_mutex );
+ vlc_mutex_unlock( &httpd.mutex );
if( host != NULL )
{
/* delete a host */
void httpd_HostDelete( httpd_host_t *host )
{
- httpd_t *httpd = host->httpd;
int i;
bool delete = false;
- vlc_mutex_lock( &httpd_mutex );
+ vlc_mutex_lock( &httpd.mutex );
vlc_mutex_lock( &host->lock );
host->i_ref--;
if( !delete )
{
/* still used */
- vlc_mutex_unlock( &httpd_mutex );
+ 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_object_kill( host );
vlc_join( host->thread, NULL );
vlc_tls_ServerDelete( host->p_tls );
net_ListenClose( host->fds );
- free( host->psz_hostname );
-
vlc_cond_destroy( &host->wait );
vlc_mutex_destroy( &host->lock );
vlc_object_release( host );
-
- if( httpd->i_host <= 0 )
- {
- msg_Dbg( httpd, "no hosts left, stopping httpd" );
-
- libvlc_priv (httpd->p_libvlc)->p_httpd = NULL;
- vlc_object_release( httpd );
- }
- vlc_mutex_unlock( &httpd_mutex );
+ vlc_mutex_unlock( &httpd.mutex );
}
/* register a new url */
{
if( !strcmp( psz_url, host->url[i]->psz_url ) )
{
- msg_Warn( host->httpd,
+ msg_Warn( host,
"cannot add '%s' (url already defined)", psz_url );
vlc_mutex_unlock( &host->lock );
return NULL;
msg->psz_url = NULL;
msg->psz_args = NULL;
- msg->i_channel = -1;
-
msg->i_name = 0;
msg->name = NULL;
msg->i_value = 0;
cl->i_buffer_size = HTTPD_CL_BUFSIZE;
cl->i_buffer = 0;
cl->p_buffer = xmalloc( cl->i_buffer_size );
- cl->i_mode = HTTPD_CLIENT_FILE;
- cl->b_read_waiting = false;
+ cl->b_stream_mode = false;
httpd_MsgInit( &cl->query );
httpd_MsgInit( &cl->answer );
}
-void httpd_ClientModeStream( httpd_client_t *cl )
+char* httpd_ClientIP( const httpd_client_t *cl, char *ip, int *port )
{
- cl->i_mode = HTTPD_CLIENT_STREAM;
+ return net_GetPeerAddress( cl->fd, ip, port ) ? NULL : ip;
}
-void httpd_ClientModeBidir( httpd_client_t *cl )
+char* httpd_ServerIP( const httpd_client_t *cl, char *ip, int *port )
{
- cl->i_mode = HTTPD_CLIENT_BIDIR;
-}
-
-char* httpd_ClientIP( const httpd_client_t *cl, char *psz_ip )
-{
- return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
-}
-
-char* httpd_ServerIP( const httpd_client_t *cl, char *psz_ip )
-{
- return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
+ return net_GetSockAddress( cl->fd, ip, port ) ? NULL : ip;
}
static void httpd_ClientClean( httpd_client_t *cl )
cl->i_buffer += i_len;
}
- if( ( cl->i_buffer >= 4 ) && ( cl->p_buffer[0] == '$' ) )
- {
- /* Interleaved RTP over RTSP */
- cl->query.i_proto = HTTPD_PROTO_RTSP;
- cl->query.i_type = HTTPD_MSG_CHANNEL;
- cl->query.i_channel = cl->p_buffer[1];
- cl->query.i_body = (cl->p_buffer[2] << 8)|cl->p_buffer[3];
- cl->query.p_body = xmalloc( cl->query.i_body );
- cl->i_buffer -= 4;
- memcpy( cl->query.p_body, cl->p_buffer + 4, cl->i_buffer );
- }
- else
/* 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 )
*p2++ = '\0';
}
if( !strncasecmp( p, ( cl->query.i_proto
- == HTTPD_PROTO_HTTP ) ? "http" : "rtsp", 4 )
- && p[4 + !!strchr( "sS", p[4] )] == ':' )
+ == HTTPD_PROTO_HTTP ) ? "http:" : "rtsp:", 5 ) )
{ /* Skip hier-part of URL (if present) */
- p = strchr( p, ':' ) + 1; /* skip URI scheme */
+ p += 5;
if( !strncmp( p, "//", 2 ) ) /* skip authority */
{ /* see RFC3986 §3.2 */
p += 2;
- while( *p && !strchr( "/?#", *p ) ) p++;
+ 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, '?' ) ) )
{
if( cl->i_buffer >= cl->i_buffer_size )
{
- if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 &&
- !cl->b_read_waiting )
+ if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 )
{
/* catch more body data */
int i_msg = cl->query.i_type;
httpd_MsgInit( answer );
/* Handle what we received */
- if( (cl->i_mode != HTTPD_CLIENT_BIDIR) &&
- (i_msg == HTTPD_MSG_ANSWER || i_msg == HTTPD_MSG_CHANNEL) )
+ if( i_msg == HTTPD_MSG_ANSWER )
{
- /* we can only receive request from client when not
- * in BIDIR mode */
cl->url = NULL;
cl->i_state = HTTPD_CLIENT_DEAD;
}
- else if( i_msg == HTTPD_MSG_ANSWER )
- {
- /* We are in BIDIR mode, trigger the callback and then
- * check for new data */
- if( cl->url && cl->url->catch[i_msg].cb )
- {
- cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
- cl, NULL, query );
- }
- cl->i_state = HTTPD_CLIENT_WAITING;
- }
- else if( i_msg == HTTPD_MSG_CHANNEL )
- {
- /* We are in BIDIR mode, trigger the callback and then
- * check for new data */
- if( cl->url && cl->url->catch[i_msg].cb )
- {
- cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
- cl, NULL, query );
- }
- cl->i_state = HTTPD_CLIENT_WAITING;
- }
else if( i_msg == HTTPD_MSG_OPTIONS )
{
{
char ip[NI_MAXNUMERICHOST];
- if( ( httpd_ClientIP( cl, ip ) == NULL )
+ if( ( httpd_ClientIP( cl, ip, NULL ) == NULL )
|| ACL_Check( url->p_acl, ip ) )
{
b_hosts_failed = true;
}
else if( cl->i_state == HTTPD_CLIENT_SEND_DONE )
{
- if( cl->i_mode == HTTPD_CLIENT_FILE || 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_query = httpd_MsgGet( &cl->query, "Connection" );
}
httpd_MsgClean( &cl->answer );
}
- else if( cl->b_read_waiting )
- {
- /* we have a message waiting for us to read it */
- httpd_MsgClean( &cl->answer );
- httpd_MsgClean( &cl->query );
-
- cl->i_buffer = 0;
- cl->i_buffer_size = 1000;
- free( cl->p_buffer );
- cl->p_buffer = xmalloc( cl->i_buffer_size );
- cl->i_state = HTTPD_CLIENT_RECEIVING;
- cl->b_read_waiting = false;
- }
else
{
int64_t i_offset = cl->answer.i_body_offset;
}
}
- /* Special for BIDIR mode we also check reading */
- if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
- cl->i_state == HTTPD_CLIENT_SENDING )
- {
- pufd->events |= POLLIN;
- }
-
if (pufd->events != 0)
nfd++;
else
{
httpd_ClientTlsHsOut( cl );
}
-
- if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
- cl->i_state == HTTPD_CLIENT_SENDING &&
- (pufd->revents & POLLIN) )
- {
- cl->b_read_waiting = true;
- }
}
vlc_mutex_unlock( &host->lock );