X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmisc%2Fhttpd.c;h=f217f7d57abf2d5d59b783e620d8a20fd7f46e5e;hb=aed69fef6220413ac7cd26d36d294ba4c9156015;hp=97f433126e9f677b1ae6ddb2a3989f7aae5c1f2e;hpb=1c672a3d5cead318809db9b030f928e9fc4a8c72;p=vlc diff --git a/src/misc/httpd.c b/src/misc/httpd.c index 97f433126e..f217f7d57a 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -1,11 +1,11 @@ /***************************************************************************** * httpd.c ***************************************************************************** - * Copyright (C) 2004 VideoLAN + * Copyright (C) 2004-2005 the VideoLAN team * $Id$ * * Authors: Laurent Aimar - * Remi Denis-Courmont + * Rémi Denis-Courmont * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,6 +30,7 @@ #include "vlc_httpd.h" #include "network.h" #include "vlc_tls.h" +#include "vlc_acl.h" #include #include @@ -50,20 +51,13 @@ #else # include /* hostent ... */ # include +/* FIXME: should not be needed */ # include # ifdef HAVE_ARPA_INET_H # include /* inet_ntoa(), inet_aton() */ # endif #endif -#if defined(WIN32) -static const struct in6_addr in6addr_any = {{IN6ADDR_ANY_INIT}}; -#endif - -#ifndef PF_INET -# define PF_INET AF_INET /* BeOS */ -#endif - #if 0 typedef struct httpd_t httpd_t; @@ -215,9 +209,9 @@ struct httpd_host_t int i_ref; /* address/port and socket for listening at connections */ - struct sockaddr_storage sock; - int i_sock_size; - int fd; + char *psz_hostname; + int i_port; + int *fd; vlc_mutex_t lock; @@ -241,9 +235,10 @@ struct httpd_url_t vlc_mutex_t lock; - char *psz_url; - char *psz_user; - char *psz_password; + char *psz_url; + char *psz_user; + char *psz_password; + vlc_acl_t *p_acl; struct { @@ -369,8 +364,8 @@ static void b64_decode( char *dest, char *src ) static struct { - char *psz_ext; - char *psz_mime; + const char *psz_ext; + const char *psz_mime; } http_mime[] = { { ".htm", "text/html" }, @@ -414,7 +409,7 @@ static struct /* end */ { NULL, NULL } }; -static char *httpd_MimeFromUrl( char *psz_url ) +static const char *httpd_MimeFromUrl( const char *psz_url ) { char *psz_ext; @@ -471,7 +466,7 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, if( query->i_type != HTTPD_MSG_HEAD ) { - char *psz_args = query->psz_args; + uint8_t *psz_args = query->psz_args; if( query->i_type == HTTPD_MSG_POST ) { /* Check that */ @@ -494,15 +489,16 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_file_t *httpd_FileNew( httpd_host_t *host, - char *psz_url, char *psz_mime, - char *psz_user, char *psz_password, - httpd_file_callback_t pf_fill, + const char *psz_url, const char *psz_mime, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill, httpd_file_sys_t *p_sys ) { httpd_file_t *file = malloc( sizeof( httpd_file_t ) ); if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, p_acl ) + ) == NULL ) { free( file ); return NULL; @@ -568,16 +564,22 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, answer->psz_status = strdup( "Moved Permanently" ); p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Redirection\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

You should be redirected

\n", rdir->psz_dst ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "\n" + "\n" + "\n" + "\n" + "Redirection\n" + "\n" + "\n" + "

You should be " + "redirected

\n" + "
\n" + "

VideoLAN\n

" + "
\n" + "\n" + "\n", rdir->psz_dst ); answer->i_body = p - answer->p_body; /* XXX check if it's ok or we need to set an absolute url */ @@ -588,12 +590,12 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, return VLC_SUCCESS; } -httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, - char *psz_url_src ) +httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst, + const char *psz_url_src ) { httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) ); - if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) ) + if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, NULL ) ) ) { free( rdir ); return NULL; @@ -767,13 +769,15 @@ static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, } httpd_stream_t *httpd_StreamNew( httpd_host_t *host, - char *psz_url, char *psz_mime, - char *psz_user, char *psz_password ) + const char *psz_url, const char *psz_mime, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) ); if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, - psz_password ) ) == NULL ) + psz_password, p_acl ) + ) == NULL ) { free( stream ); return NULL; @@ -875,122 +879,38 @@ void httpd_StreamDelete( httpd_stream_t *stream ) /***************************************************************************** * Low level *****************************************************************************/ -#define LISTEN_BACKLOG 100 - -#if defined(HAVE_GETNAMEINFO) && !defined(HAVE_GETADDRINFO) -/* - * For now, VLC's configure script does not check for getaddrinfo(), - * but it should be present if getnameinfo() is (the opposite is untrue, with - * Debian potato as an example) - */ -# define HAVE_GETADDRINFO 1 -#endif - static void httpd_HostThread( httpd_host_t * ); -static int GetAddrPort( const struct sockaddr_storage *p_ss ); - -#ifndef HAVE_GETADDRINFO -struct httpd_addrinfo -{ - int ai_family; - int ai_socktype; - int ai_protocol; - /*int ai_flags;*/ - struct sockaddr *ai_addr; - int ai_addrlen; - struct httpd_addrinfo *ai_next; -}; -# define addrinfo httpd_addrinfo - -static int BuildAddr( struct sockaddr_in * p_socket, - const char * psz_address, int i_port ); -#endif - /* create a new host */ -httpd_host_t *httpd_HostNew( vlc_object_t *p_this, char *psz_host, +httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host, int i_port ) { - return httpd_TLSHostNew( p_this, psz_host, i_port, NULL ); + return httpd_TLSHostNew( p_this, psz_host, i_port, NULL, NULL, NULL, NULL + ); } -httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, - int i_port, tls_server_t *p_tls ) +httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, + int i_port, + const char *psz_cert, const char *psz_key, + const char *psz_ca, const char *psz_crl ) { httpd_t *httpd; - httpd_host_t *host = NULL; - vlc_value_t lockval; - int fd = -1; - struct addrinfo *res, *ptr; - - /* resolv */ -#ifdef HAVE_GETADDRINFO - { - vlc_value_t val; - char psz_port[6]; - struct addrinfo hints; - - memset( &hints, 0, sizeof( hints ) ); - -#if 0 - /* - * For now, keep IPv4 by default. That said, it should be safe to use - * IPv6 by default *on the server side*, as, apart from NetBSD, most - * systems accept IPv4 clients on IPv6 listening sockets. - */ - hints.ai_family = PF_INET; -#else - hints.ai_family = 0; - - /* Check if ipv4 or ipv6 were forced */ - var_Create( p_this, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Get( p_this, "ipv4", &val ); - if( val.b_bool ) - hints.ai_family = PF_INET; -#endif - var_Create( p_this, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); - var_Get( p_this, "ipv6", &val ); - if( val.b_bool ) - hints.ai_family = PF_INET6; - - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - if (*psz_host == '\0') - psz_host = NULL; - - snprintf( psz_port, sizeof( psz_port ), "%d", i_port ); - psz_port[sizeof( psz_port ) - 1] = '\0'; - - if( getaddrinfo( psz_host, psz_port, &hints, &res ) ) - { - msg_Err( p_this, "cannot resolve %s:%d", psz_host, i_port ); - return NULL; - } - } + httpd_host_t *host; + tls_server_t *p_tls; + char *psz_host; + vlc_value_t lockval; + int i; -#else - struct sockaddr_in sock; - struct httpd_addrinfo info; - - info.ai_family = PF_INET; - info.ai_socktype = SOCK_STREAM; - info.ai_protocol = 0; - info.ai_addr = (struct sockaddr *)&sock; - info.ai_addrlen = sizeof( sock ); - info.ai_next = NULL; - - res = &info; + if( psz_hostname == NULL ) + psz_hostname = ""; - if( BuildAddr( &sock, psz_host, i_port ) ) + psz_host = strdup( psz_hostname ); + if( psz_host == NULL ) { - msg_Err( p_this, "cannot build address for %s:%d", psz_host, i_port ); + msg_Err( p_this, "memory error" ); return NULL; } -# define freeaddrinfo( r ) (void)0; -#endif - /* to be sure to avoid multiple creation */ var_Create( p_this->p_libvlc, "httpd_mutex", VLC_VAR_MUTEX ); var_Get( p_this->p_libvlc, "httpd_mutex", &lockval ); @@ -1002,7 +922,7 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL ) { vlc_mutex_unlock( lockval.p_address ); - freeaddrinfo( res ); + free( psz_host ); return NULL; } @@ -1013,159 +933,72 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, char *psz_host, vlc_object_attach( httpd, p_this->p_vlc ); } - for( ptr = res; (ptr != NULL) && (fd == -1); ptr = ptr->ai_next ) + /* verify if it already exist */ + for( i = httpd->i_host - 1; i >= 0; i-- ) { - int i; + host = httpd->host[i]; - if( ((unsigned)ptr->ai_addrlen) > sizeof( struct sockaddr_storage ) ) - { - msg_Dbg( p_this, "socket address too big" ); + /* cannot mix TLS and non-TLS hosts */ + if( ( ( httpd->host[i]->p_tls != NULL ) != ( psz_cert != NULL ) ) + || ( host->i_port != i_port ) + || strcmp( host->psz_hostname, psz_hostname ) ) continue; - } - - /* verify if it already exist */ - for( i = 0; i < httpd->i_host; i++ ) - { - if( GetAddrPort (&httpd->host[i]->sock) != i_port ) - continue; - - /* Cannot re-use host if it uses TLS/SSL */ - if( httpd->host[i]->p_tls != NULL ) - continue; - -#ifdef AF_INET6 - if( httpd->host[i]->sock.ss_family == AF_INET6 ) - { - const struct sockaddr_in6 *p_hsock, *p_sock; - - p_hsock = (const struct sockaddr_in6 *)&httpd->host[i]->sock; - p_sock = (const struct sockaddr_in6 *)ptr->ai_addr; - - if( memcmp( &p_hsock->sin6_addr, &in6addr_any, - sizeof( struct in6_addr ) ) && - ( p_sock->sin6_family != AF_INET6 || - memcmp( &p_hsock->sin6_addr, &p_sock->sin6_addr, - sizeof( struct in6_addr ) ) ) ) - continue; /* does not match */ - } - else if( ptr->ai_family == PF_INET6 ) - continue; - else -#endif - if( httpd->host[i]->sock.ss_family == AF_INET ) - { - const struct sockaddr_in *p_hsock, *p_sock; - - p_hsock = (const struct sockaddr_in *)&httpd->host[i]->sock; - p_sock = (const struct sockaddr_in *)ptr->ai_addr; - - if( p_hsock->sin_addr.s_addr != INADDR_ANY && - ( p_sock->sin_family != AF_INET || - p_hsock->sin_addr.s_addr != p_sock->sin_addr.s_addr ) ) - continue; /* does not match */ - } - else if( ptr->ai_family == PF_INET ) - continue; - else - { - msg_Dbg( p_this, "host with unknown address family" ); - continue; - } - - freeaddrinfo( res ); - - /* yep found */ - host = httpd->host[i]; - host->i_ref++; - vlc_mutex_unlock( lockval.p_address ); + /* yep found */ + host->i_ref++; - msg_Dbg( p_this, "host already registered" ); - return host; - } + vlc_mutex_unlock( lockval.p_address ); + return host; + } - /* create the listening socket */ - fd = socket( ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol ); - if( fd == -1 ) - continue; + host = NULL; - /* reuse socket */ + /* determine TLS configuration */ + if ( psz_cert != NULL ) + { + p_tls = tls_ServerCreate( p_this, psz_cert, psz_key ); + if ( p_tls == NULL ) { - int dummy = 1; - if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, - (void *)&dummy, sizeof( dummy ) ) < 0 ) - { - msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" ); - } + msg_Err( p_this, "TLS initialization error" ); + goto error; } - /* bind it */ - if( bind( fd, ptr->ai_addr, ptr->ai_addrlen ) ) + if ( ( psz_ca != NULL) && tls_ServerAddCA( p_tls, psz_ca ) ) { - msg_Err( p_this, "cannot bind socket" ); - goto socket_error; + msg_Err( p_this, "TLS CA error" ); + goto error; } - /* set to non-blocking */ -#if defined( WIN32 ) || defined( UNDER_CE ) - { - unsigned long i_dummy = 1; - if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 ) - { - msg_Err( p_this, "cannot set socket to non-blocking mode" ); - goto socket_error; - } - } -#else - { - unsigned int i_flags; - if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 ) - { - msg_Err( p_this, "cannot F_GETFL socket" ); - goto socket_error; - } - if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 ) - { - msg_Err( p_this, "cannot F_SETFL O_NONBLOCK" ); - goto socket_error; - } - } -#endif - /* listen */ - if( listen( fd, LISTEN_BACKLOG ) < 0 ) + + if ( ( psz_crl != NULL) && tls_ServerAddCRL( p_tls, psz_crl ) ) { - msg_Err( p_this, "cannot listen socket" ); - goto socket_error; + msg_Err( p_this, "TLS CRL error" ); + goto error; } - - break; // success - -socket_error: - net_Close( fd ); - fd = -1; - } - - - if( fd == -1 ) - { - freeaddrinfo( res ); - goto error; } + else + p_tls = NULL; /* create the new host */ host = vlc_object_create( p_this, sizeof( httpd_host_t ) ); host->httpd = httpd; vlc_mutex_init( httpd, &host->lock ); host->i_ref = 1; - host->fd = fd; - memcpy( &host->sock, ptr->ai_addr, ptr->ai_addrlen ); - host->i_sock_size = ptr->ai_addrlen; + host->fd = net_ListenTCP( p_this, psz_host, i_port ); + if( host->fd == 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; - freeaddrinfo( res ); host->p_tls = p_tls; /* create the thread */ @@ -1183,19 +1016,25 @@ socket_error: return host; error: + free( psz_host ); + if( httpd->i_host <= 0 ) + { + vlc_object_release( httpd ); + vlc_object_detach( httpd ); + vlc_object_destroy( httpd ); + } vlc_mutex_unlock( lockval.p_address ); - if( fd != -1 ) - net_Close( fd ); - if( host != NULL ) { + net_ListenClose( host->fd ); vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); } - /* TODO destroy no more used httpd TODO */ - vlc_object_release( httpd ); + if( p_tls != NULL ) + tls_ServerDelete( p_tls ); + return NULL; } @@ -1211,8 +1050,6 @@ void httpd_HostDelete( httpd_host_t *host ) var_Get( httpd->p_libvlc, "httpd_mutex", &lockval ); vlc_mutex_lock( lockval.p_address ); - vlc_object_release( httpd ); - host->i_ref--; if( host->i_ref > 0 ) { @@ -1247,13 +1084,17 @@ void httpd_HostDelete( httpd_host_t *host ) if( host->p_tls != NULL) tls_ServerDelete( host->p_tls ); - net_Close( host->fd ); + + net_ListenClose( host->fd ); + free( host->psz_hostname ); + vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); if( httpd->i_host <= 0 ) { msg_Info( httpd, "httpd doesn't reference any host, deleting" ); + vlc_object_release( httpd ); vlc_object_detach( httpd ); vlc_object_destroy( httpd ); } @@ -1261,9 +1102,9 @@ void httpd_HostDelete( httpd_host_t *host ) } /* register a new url */ -static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password, - vlc_bool_t b_check ) +static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl, vlc_bool_t b_check ) { httpd_url_t *url; int i; @@ -1290,6 +1131,7 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, url->psz_url = strdup( psz_url ); url->psz_user = strdup( psz_user ? psz_user : "" ); url->psz_password = strdup( psz_password ? psz_password : "" ); + url->p_acl = ACL_Duplicate( host, p_acl ); for( i = 0; i < HTTPD_MSG_MAX; i++ ) { url->catch[i].cb = NULL; @@ -1302,18 +1144,20 @@ static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, return url; } -httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) +httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_FALSE ); + psz_password, p_acl, VLC_FALSE ); } -httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, - char *psz_user, char *psz_password ) +httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, const char *psz_url, + const char *psz_user, const char *psz_password, + const vlc_acl_t *p_acl ) { return httpd_UrlNewPrivate( host, psz_url, psz_user, - psz_password, VLC_TRUE ); + psz_password, p_acl, VLC_TRUE ); } /* register callback on a url */ @@ -1342,6 +1186,7 @@ void httpd_UrlDelete( httpd_url_t *url ) free( url->psz_url ); free( url->psz_user ); free( url->psz_password ); + ACL_Destroy( url->p_acl ); for( i = 0; i < host->i_client; i++ ) { @@ -1484,52 +1329,14 @@ void httpd_ClientModeBidir( httpd_client_t *cl ) cl->i_mode = HTTPD_CLIENT_BIDIR; } -char* httpd_ClientIP( httpd_client_t *cl ) +char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { -#ifdef HAVE_GETNAMEINFO - char sz_ip[INET6_ADDRSTRLEN + 2]; - int i; - - if( (cl->sock.ss_family == AF_INET6) && - IN6_IS_ADDR_V4MAPPED( &((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr) ) - { - /* If client is using IPv4 but server is using IPv6 */ - struct sockaddr_in a; - - memset( &a, 0, sizeof( a ) ); - a.sin_family = AF_INET; - a.sin_port = ((const struct sockaddr_in6 *)&cl->sock)->sin6_port; - a.sin_addr.s_addr = ((const uint32_t *)&((const struct sockaddr_in6 *) - &cl->sock)->sin6_addr)[3]; - i = getnameinfo( (const struct sockaddr *)&a, sizeof( a ), - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, NI_NUMERICHOST ); - } - else - i = getnameinfo( (const struct sockaddr *)&cl->sock, cl->i_sock_size, - &sz_ip[1], INET6_ADDRSTRLEN, NULL, 0, - NI_NUMERICHOST ); - - if( i != 0 ) - /* FIXME: msg_Err */ - return NULL; - - if( strchr( &sz_ip[1], ':' ) != NULL ) - { - *sz_ip = '['; - i = strlen( sz_ip ); - sz_ip[i++] = ']'; - sz_ip[i] = '\0'; - - return strdup( sz_ip ); - } - - return strdup( &sz_ip[1] ); + return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip; +} -#else - /* FIXME not thread safe */ - return strdup( inet_ntoa( ((const struct sockaddr_in *)&cl->sock)->sin_addr ) ); -#endif +char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) +{ + return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip; } static void httpd_ClientClean( httpd_client_t *cl ) @@ -1537,7 +1344,7 @@ static void httpd_ClientClean( httpd_client_t *cl ) if( cl->fd >= 0 ) { if( cl->p_tls != NULL ) - tls_SessionClose( cl->p_tls ); + tls_ServerSessionClose( cl->p_tls ); net_Close( cl->fd ); cl->fd = -1; } @@ -1570,7 +1377,7 @@ static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock, } -static int httpd_NetRecv( httpd_client_t *cl, char *p, int i_len ) +static int httpd_NetRecv( httpd_client_t *cl, uint8_t *p, int i_len ) { tls_session_t *p_tls; @@ -1582,7 +1389,7 @@ static int httpd_NetRecv( httpd_client_t *cl, char *p, int i_len ) } -static int httpd_NetSend( httpd_client_t *cl, const char *p, int i_len ) +static int httpd_NetSend( httpd_client_t *cl, const uint8_t *p, int i_len ) { tls_session_t *p_tls; @@ -1610,7 +1417,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( cl->i_buffer >= 4 ) { - fprintf( stderr, "peek=%4.4s\n", cl->p_buffer ); + /*fprintf( stderr, "peek=%4.4s\n", cl->p_buffer );*/ /* detect type */ if( cl->p_buffer[0] == '$' ) { @@ -1623,19 +1430,19 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_buffer = 0; } - else if( !strncmp( cl->p_buffer, "HTTP", 4 ) ) + else if( !memcmp( cl->p_buffer, "HTTP", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_type = HTTPD_MSG_ANSWER; } - else if( !strncmp( cl->p_buffer, "RTSP", 4 ) ) + else if( !memcmp( cl->p_buffer, "RTSP", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; cl->query.i_type = HTTPD_MSG_ANSWER; } - else if( !strncmp( cl->p_buffer, "GET", 3 ) || - !strncmp( cl->p_buffer, "HEAD", 4 ) || - !strncmp( cl->p_buffer, "POST", 4 ) ) + else if( !memcmp( cl->p_buffer, "GET", 3 ) || + !memcmp( cl->p_buffer, "HEAD", 4 ) || + !memcmp( cl->p_buffer, "POST", 4 ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_type = HTTPD_MSG_NONE; @@ -1678,8 +1485,8 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_buffer_size += 1024; cl->p_buffer = realloc( cl->p_buffer, cl->i_buffer_size ); } - if( ( cl->i_buffer >= 2 && !strncmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )|| - ( cl->i_buffer >= 4 && !strncmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) ) + if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )|| + ( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) ) { char *p; @@ -1688,8 +1495,12 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( cl->query.i_type == HTTPD_MSG_ANSWER ) { + /* FIXME: + * assume strlen( "HTTP/1.x" ) = 8 + */ cl->query.i_status = - strtol( &cl->p_buffer[strlen( "HTTP/1.x" )], &p, 0 ); + strtol( (char *)&cl->p_buffer[8], + &p, 0 ); while( *p == ' ' ) { p++; @@ -1724,14 +1535,14 @@ static void httpd_ClientRecv( httpd_client_t *cl ) p = NULL; cl->query.i_type = HTTPD_MSG_NONE; - fprintf( stderr, "received new request=%s\n", cl->p_buffer); + /*fprintf( stderr, "received new request=%s\n", cl->p_buffer);*/ for( i = 0; msg_type[i].name != NULL; i++ ) { - if( !strncmp( cl->p_buffer, msg_type[i].name, + if( !strncmp( (char *)cl->p_buffer, msg_type[i].name, strlen( msg_type[i].name ) ) ) { - p = &cl->p_buffer[strlen(msg_type[i].name) + 1 ]; + p = (char *)&cl->p_buffer[strlen((char *)msg_type[i].name) + 1 ]; cl->query.i_type = msg_type[i].i_type; if( cl->query.i_proto != msg_type[i].i_proto ) { @@ -1744,11 +1555,11 @@ static void httpd_ClientRecv( httpd_client_t *cl ) } if( p == NULL ) { - if( strstr( cl->p_buffer, "HTTP/1." ) ) + if( strstr( (char *)cl->p_buffer, "HTTP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; } - else if( strstr( cl->p_buffer, "RTSP/1." ) ) + else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; } @@ -1778,7 +1589,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) if( ( p3 = strchr( cl->query.psz_url, '?' ) ) ) { *p3++ = '\0'; - cl->query.psz_args = strdup( p3 ); + cl->query.psz_args = (uint8_t *)strdup( p3 ); } if( p2 ) { @@ -1896,7 +1707,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_activity_timeout = 0; /* Debugging only */ - if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) + /*if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) { int i; @@ -1919,7 +1730,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) fprintf( stderr, " - option name='%s' value='%s'\n", cl->query.name[i], cl->query.value[i] ); } - } + }*/ } @@ -1948,7 +1759,7 @@ static void httpd_ClientSend( httpd_client_t *cl ) free( cl->p_buffer ); cl->p_buffer = malloc( i_size ); } - p = cl->p_buffer; + p = (char *)cl->p_buffer; p += sprintf( p, "%s/1.%d %d %s\r\n", cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP", @@ -1964,8 +1775,8 @@ static void httpd_ClientSend( httpd_client_t *cl ) cl->i_buffer = 0; cl->i_buffer_size = (uint8_t*)p - cl->p_buffer; - fprintf( stderr, "sending answer\n" ); - fprintf( stderr, "%s", cl->p_buffer ); + /*fprintf( stderr, "sending answer\n" ); + fprintf( stderr, "%s", cl->p_buffer );*/ } i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer], @@ -2033,6 +1844,7 @@ static void httpd_ClientTlsHsIn( httpd_client_t *cl ) case -1: cl->i_state = HTTPD_CLIENT_DEAD; + cl->p_tls = NULL; break; case 2: @@ -2050,6 +1862,7 @@ static void httpd_ClientTlsHsOut( httpd_client_t *cl ) case -1: cl->i_state = HTTPD_CLIENT_DEAD; + cl->p_tls = NULL; break; case 1: @@ -2067,6 +1880,8 @@ static void httpd_HostThread( httpd_host_t *host ) struct timeval timeout; fd_set fds_read; fd_set fds_write; + /* FIXME: (too) many int variables */ + int fd, i_fd; int i_handle_max = 0; int i_ret; int i_client; @@ -2083,8 +1898,14 @@ static void httpd_HostThread( httpd_host_t *host ) FD_ZERO( &fds_read ); FD_ZERO( &fds_write ); - FD_SET( host->fd, &fds_read ); - i_handle_max = host->fd; + i_handle_max = -1; + + for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) + { + FD_SET( fd, &fds_read ); + if( fd > i_handle_max ) + i_handle_max = fd; + } /* prepare a new TLS session */ if( ( p_tls == NULL ) && ( host->p_tls != NULL ) ) @@ -2101,14 +1922,6 @@ static void httpd_HostThread( httpd_host_t *host ) ( cl->i_activity_timeout > 0 && cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) ) { - char *ip; - - // FIXME: it sucks to allocate memory on the stack for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "connection closed(%s)", - (ip != NULL) ? ip : "unknown" ); - free( ip ); - httpd_ClientClean( cl ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); @@ -2212,16 +2025,20 @@ static void httpd_HostThread( httpd_host_t *host ) p = answer->p_body = malloc( 1000 ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 501\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

501 Unimplemented

\n" ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 501\n" + "\n" + "\n" + "

501 Unimplemented

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n" ); answer->i_body = p - answer->p_body; httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); @@ -2233,6 +2050,7 @@ static void httpd_HostThread( httpd_host_t *host ) else { vlc_bool_t b_auth_failed = VLC_FALSE; + vlc_bool_t b_hosts_failed = VLC_FALSE; int i; /* Search the url and trigger callbacks */ @@ -2244,6 +2062,22 @@ static void httpd_HostThread( httpd_host_t *host ) { if( url->catch[i_msg].cb ) { + if( answer && ( url->p_acl != NULL ) ) + { + char ip[NI_MAXNUMERICHOST]; + + if( httpd_ClientIP( cl, ip ) != NULL ) + { + if( ACL_Check( url->p_acl, ip ) ) + { + b_hosts_failed = VLC_TRUE; + break; + } + } + else + b_hosts_failed = VLC_TRUE; + } + if( answer && ( *url->psz_user || *url->psz_password ) ) { /* create the headers */ @@ -2302,21 +2136,46 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_version= 0; p = answer->p_body = malloc( 1000 + strlen(query->psz_url) ); - if( b_auth_failed ) + if( b_hosts_failed ) + { + answer->i_status = 403; + answer->psz_status = strdup( "Forbidden" ); + + /* FIXME: lots of code duplication */ + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 403\n" + "\n" + "\n" + "

403 Forbidden (%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); + } + else if( b_auth_failed ) { answer->i_status = 401; answer->psz_status = strdup( "Authorization Required" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 401\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

401 Authorization Required (%s)

\n", query->psz_url ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 401\n" + "\n" + "\n" + "

401 Authorization Required (%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); } else { @@ -2324,16 +2183,20 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_status = 404; answer->psz_status = strdup( "Not found" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "Error 404\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "

404 Resource not found(%s)

\n", query->psz_url ); - p += sprintf( p, "
\n" ); - p += sprintf( p, "VideoLAN\n" ); - p += sprintf( p, "\n" ); - p += sprintf( p, "\n" ); + p += sprintf( (char *)p, + "" + "\n" + "\n" + "\n" + "Error 404\n" + "\n" + "\n" + "

404 Resource not found(%s)

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", query->psz_url ); } answer->i_body = p - answer->p_body; @@ -2443,7 +2306,11 @@ static void httpd_HostThread( httpd_host_t *host ) if( i_ret == -1 && errno != EINTR ) { - msg_Warn( host, "cannot select sockets" ); +#if defined(WIN32) || defined(UNDER_CE) + msg_Warn( host, "cannot select sockets (%d)", WSAGetLastError( ) ); +#else + msg_Warn( host, "cannot select sockets : %s", strerror( errno ) ); +#endif msleep( 1000 ); continue; } @@ -2453,71 +2320,66 @@ static void httpd_HostThread( httpd_host_t *host ) } /* accept new connections */ - if( FD_ISSET( host->fd, &fds_read ) ) + for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) { - int i_sock_size = sizeof( struct sockaddr_storage ); - struct sockaddr_storage sock; - int fd; - - fd = accept( host->fd, (struct sockaddr *)&sock, &i_sock_size ); - if( fd >= 0 ) + if( FD_ISSET( fd, &fds_read ) ) { - int i_state = 0; - - /* set this new socket non-block */ -#if defined( WIN32 ) || defined( UNDER_CE ) - { - unsigned long i_dummy = 1; - ioctlsocket( fd, FIONBIO, &i_dummy ); - } -#else - fcntl( fd, F_SETFL, O_NONBLOCK ); -#endif - - /* FIXME: that MUST be non-blocking */ - if( p_tls != NULL) + socklen_t i_sock_size = sizeof( struct sockaddr_storage ); + struct sockaddr_storage sock; + + fd = accept( fd, (struct sockaddr *)&sock, &i_sock_size ); + if( fd >= 0 ) { - switch ( tls_SessionHandshake( p_tls, fd ) ) + int i_state = 0; + + /* set this new socket non-block */ + #if defined( WIN32 ) || defined( UNDER_CE ) { - case -1: - msg_Err( host, "Rejecting TLS connection" ); - net_Close( fd ); - fd = -1; - break; - - case 1: /* missing input - most likely */ - i_state = HTTPD_CLIENT_TLS_HS_IN; - break; - - case 2: /* missing output */ - i_state = HTTPD_CLIENT_TLS_HS_OUT; - break; + unsigned long i_dummy = 1; + ioctlsocket( fd, FIONBIO, &i_dummy ); + } + #else + fcntl( fd, F_SETFL, O_NONBLOCK ); + #endif + + if( p_tls != NULL) + { + switch ( tls_ServerSessionHandshake( p_tls, fd ) ) + { + case -1: + msg_Err( host, "Rejecting TLS connection" ); + net_Close( fd ); + fd = -1; + p_tls = NULL; + break; + + case 1: /* missing input - most likely */ + i_state = HTTPD_CLIENT_TLS_HS_IN; + break; + + case 2: /* missing output */ + i_state = HTTPD_CLIENT_TLS_HS_OUT; + break; + } + } + + if( fd >= 0 ) + { + httpd_client_t *cl; + + cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); + p_tls = NULL; + vlc_mutex_lock( &host->lock ); + TAB_APPEND( host->i_client, host->client, cl ); + vlc_mutex_unlock( &host->lock ); + + if( i_state != 0 ) + cl->i_state = i_state; // override state for TLS } - } - - if( fd >= 0 ) - { - char *ip; - httpd_client_t *cl; - - cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); - p_tls = NULL; - vlc_mutex_lock( &host->lock ); - TAB_APPEND( host->i_client, host->client, cl ); - vlc_mutex_unlock( &host->lock ); - - if( i_state != 0 ) - cl->i_state = i_state; // override state for TLS - - // FIXME: it sucks to allocate memory for debug - ip = httpd_ClientIP( cl ); - msg_Dbg( host, "new connection (%s)", - ip != NULL ? ip : "unknown" ); - if( ip != NULL) - free( ip ); } } } + /* now try all others socket */ vlc_mutex_lock( &host->lock ); for( i_client = 0; i_client < host->i_client; i_client++ ) @@ -2549,71 +2411,9 @@ static void httpd_HostThread( httpd_host_t *host ) } vlc_mutex_unlock( &host->lock ); } -} - -#ifndef HAVE_GETADDRINFO -static int BuildAddr( struct sockaddr_in * p_socket, - const char * psz_address, int i_port ) -{ - /* Reset struct */ - memset( p_socket, 0, sizeof( struct sockaddr_in ) ); - p_socket->sin_family = AF_INET; /* family */ - p_socket->sin_port = htons( (uint16_t)i_port ); - if( !*psz_address ) - { - p_socket->sin_addr.s_addr = INADDR_ANY; - } - else - { - struct hostent * p_hostent; - - /* Try to convert address directly from in_addr - this will work if - * psz_address is dotted decimal. */ -#ifdef HAVE_ARPA_INET_H - if( !inet_aton( psz_address, &p_socket->sin_addr ) ) -#else - p_socket->sin_addr.s_addr = inet_addr( psz_address ); -/* if( p_socket->sin_addr.s_addr == INADDR_NONE )*/ - if( p_socket->sin_addr.s_addr == INADDR_BROADCAST ) -#endif - { - /* We have a fqdn, try to find its address */ - if ( (p_hostent = gethostbyname( psz_address )) == NULL ) - { - return( -1 ); - } - - /* Copy the first address of the host in the socket address */ - memcpy( &((struct sockaddr_in *)p_socket)->sin_addr, p_hostent->h_addr_list[0], - p_hostent->h_length ); - } - } - return( 0 ); -} -#endif - -static int GetAddrPort( const struct sockaddr_storage *p_ss ) -{ - int i_port = 0; - - switch (p_ss->ss_family) - { -#ifdef AF_INET6 - case AF_INET6: - i_port = ((const struct sockaddr_in6 *)p_ss)->sin6_port; - break; -#endif - - case AF_INET: - i_port = ((const struct sockaddr_in *)p_ss)->sin_port; - break; - - default: - return -1; - } - - return ntohs( i_port ); + if( p_tls != NULL ) + tls_ServerSessionClose( p_tls ); } #else /* ENABLE_HTTPD */ @@ -2630,15 +2430,28 @@ httpd_host_t *httpd_HostNew( vlc_object_t *a, char *b, int c ) msg_Err( a, "HTTP daemon support is disabled" ); return 0; } -void httpd_HostDelete( httpd_host_t *a ){} -httpd_url_t *httpd_UrlNew( httpd_host_t *a, char *b ){ return 0; } -httpd_url_t *httpd_UrlNewUnique( httpd_host_t *a, char *b, char *c, - char *d ){ return 0; } +void httpd_HostDelete( httpd_host_t *a ) +{ +} +httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} +httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, + char *psz_user, char *psz_password, + const vlc_acl_t *p_acl ) +{ + return NULL; +} int httpd_UrlCatch( httpd_url_t *a, int b, httpd_callback_t c, httpd_callback_sys_t *d ){ return 0; } void httpd_UrlDelete( httpd_url_t *a ){} -char *httpd_ClientIP( httpd_client_t *a ){ return 0; } +char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { return NULL; } +char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) { return NULL; } + void httpd_ClientModeStream( httpd_client_t *a ){} void httpd_ClientModeBidir( httpd_client_t *a ){}