X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fnetwork%2Fhttpd.c;h=24e5d9bb1d10a7332f673b30948b65bb873b128a;hb=bee10796b392ea8a0f708728e1e2fc59440b44e9;hp=8b7c883836f87e9d7ed381dc21856d822bf5ee11;hpb=fba89f71376c52418dc3335e8707b0f0babdbfa8;p=vlc diff --git a/src/network/httpd.c b/src/network/httpd.c index 8b7c883836..24e5d9bb1d 100644 --- a/src/network/httpd.c +++ b/src/network/httpd.c @@ -2,6 +2,7 @@ * httpd.c ***************************************************************************** * Copyright (C) 2004-2006 the VideoLAN team + * Copyright © 2004-2007 Rémi Denis-Courmont * $Id$ * * Authors: Laurent Aimar @@ -22,17 +23,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ -#include #include #ifdef ENABLE_HTTPD #include -#include "vlc_httpd.h" -#include "network.h" -#include "vlc_tls.h" -#include "vlc_acl.h" +#include +#include +#include +#include +#include +#include "../libvlc.h" #include #include @@ -45,6 +47,10 @@ # include #endif +#ifdef HAVE_POLL +# include +#endif + #if defined( UNDER_CE ) # include #elif defined( WIN32 ) @@ -62,6 +68,48 @@ 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 */ + int i_ref; + + /* address/port and socket for listening at connections */ + char *psz_hostname; + int i_port; + int *fds; + unsigned nfd; + + vlc_mutex_t lock; + + /* all registered url (becarefull that 2 httpd_url_t could point at the same url) + * This will slow down the url research but make my live easier + * All url will have their cb trigger, but only the first one can answer + * */ + int i_url; + httpd_url_t **url; + + int i_client; + httpd_client_t **client; + + /* TLS data */ + tls_server_t *p_tls; +}; + + struct httpd_url_t { httpd_host_t *host; @@ -111,8 +159,6 @@ struct httpd_client_t int i_ref; - struct sockaddr_storage sock; - int i_sock_size; int fd; int i_mode; @@ -139,66 +185,9 @@ struct httpd_client_t /***************************************************************************** * Various functions *****************************************************************************/ -/*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/ -static void b64_decode( char *dest, char *src ) -{ - int i_level; - int last = 0; - int b64[256] = { - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 00-0F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 10-1F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63, /* 20-2F */ - 52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1, /* 30-3F */ - -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, /* 40-4F */ - 15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1, /* 50-5F */ - -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, /* 60-6F */ - 41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1, /* 70-7F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 80-8F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 90-9F */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* A0-AF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* B0-BF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* C0-CF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* D0-DF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-EF */ - -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 /* F0-FF */ - }; - - for( i_level = 0; *src != '\0'; src++ ) - { - int c; - - c = b64[(unsigned int)*src]; - if( c == -1 ) - { - continue; - } - - switch( i_level ) - { - case 0: - i_level++; - break; - case 1: - *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 ); - i_level++; - break; - case 2: - *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f ); - i_level++; - break; - case 3: - *dest++ = ( ( last &0x03 ) << 6 ) | c; - i_level = 0; - } - last = c; - } - - *dest = '\0'; -} - static struct { - const char *psz_ext; + const char psz_ext[8]; const char *psz_mime; } http_mime[] = { @@ -241,7 +230,7 @@ static struct /* end */ - { NULL, NULL } + { "", "" } }; static const char *httpd_MimeFromUrl( const char *psz_url ) @@ -254,7 +243,7 @@ static const char *httpd_MimeFromUrl( const char *psz_url ) { int i; - for( i = 0; http_mime[i].psz_ext != NULL ; i++ ) + for( i = 0; http_mime[i].psz_ext[0] ; i++ ) { if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) ) { @@ -265,7 +254,7 @@ static const char *httpd_MimeFromUrl( const char *psz_url ) return "application/octet-stream"; } -#if 0 + typedef struct { int i_code; @@ -345,7 +334,38 @@ static const char *httpd_ReasonFromCode( int i_code ) assert( ( i_code >= 100 ) && ( i_code <= 599 ) ); return psz_fallback_reason[(i_code / 100) - 1]; } -#endif + + +static size_t httpd_HtmlError (char **body, int code, const char *url) +{ + const char *errname = httpd_ReasonFromCode (code); + assert (errname != NULL); + + int res = asprintf (body, + "\n" + "\n" + "\n" + "\n" + "%s\n" + "\n" + "\n" + "

%d %s%s%s%s

\n" + "
\n" + "VideoLAN\n" + "\n" + "\n", errname, code, errname, + (url ? " (" : ""), (url ?: ""), (url ? ")" : "")); + + if (res == -1) + { + *body = NULL; + return 0; + } + + return (size_t)res; +} + /***************************************************************************** * High Level Functions: httpd_file_t @@ -367,7 +387,7 @@ static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_file_t *file = (httpd_file_t*)p_sys; uint8_t *psz_args = query->psz_args; uint8_t **pp_body, *p_body; - char *psz_connection = NULL; + const char *psz_connection; int *pi_body, i_body; if( answer == NULL || query == NULL ) @@ -530,7 +550,8 @@ static int httpd_HandlerCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *c if( strncmp( (char *)answer->p_body, "HTTP/1.", 7 ) ) { int i_status, i_headers; - char *psz_headers, *psz_new, *psz_status; + char *psz_headers, *psz_new; + const char *psz_status; if( !strncmp( (char *)answer->p_body, "Status: ", 8 ) ) { @@ -623,6 +644,7 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, { httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys; char *p_body; + (void)cl; if( answer == NULL || query == NULL ) { @@ -634,22 +656,7 @@ static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, answer->i_status = 301; answer->psz_status = strdup( "Moved Permanently" ); - answer->i_body = asprintf( &p_body, - "\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 = httpd_HtmlError (&p_body, 301, rdir->psz_dst); answer->p_body = (unsigned char *)p_body; /* XXX check if it's ok or we need to set an absolute url */ @@ -961,6 +968,8 @@ httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host, ); } +static const char psz_object_type[] = "http server"; + 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, @@ -991,7 +1000,10 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, if( !(httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE )) ) { msg_Info( p_this, "creating httpd" ); - if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL ) + httpd = (httpd_t *)vlc_custom_create( p_this, sizeof (*httpd), + VLC_OBJECT_HTTPD, + psz_object_type ); + if (httpd == NULL) { vlc_mutex_unlock( lockval.p_address ); free( psz_host ); @@ -1002,7 +1014,7 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, httpd->host = NULL; vlc_object_yield( httpd ); - vlc_object_attach( httpd, p_this->p_vlc ); + vlc_object_attach( httpd, p_this->p_libvlc ); } /* verify if it already exist */ @@ -1051,17 +1063,23 @@ httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname, p_tls = NULL; /* create the new host */ - host = vlc_object_create( p_this, VLC_OBJECT_HTTPD_HOST ); + host = (httpd_host_t *)vlc_custom_create( p_this, sizeof (*host), + VLC_OBJECT_HTTPD_HOST, + psz_object_type ); + if (host == NULL) + goto error; + host->httpd = httpd; vlc_mutex_init( httpd, &host->lock ); host->i_ref = 1; - host->fd = net_ListenTCP( p_this, psz_host, i_port ); - if( host->fd == NULL ) + host->fds = net_ListenTCP( p_this, psz_host, i_port ); + if( host->fds == NULL ) { msg_Err( p_this, "cannot create socket(s) for HTTP host" ); goto error; } + for (host->nfd = 0; host->fds[host->nfd] != -1; host->nfd++); host->i_port = i_port; host->psz_hostname = psz_host; @@ -1099,7 +1117,7 @@ error: if( host != NULL ) { - net_ListenClose( host->fd ); + net_ListenClose( host->fds ); vlc_mutex_destroy( &host->lock ); vlc_object_destroy( host ); } @@ -1130,7 +1148,7 @@ void httpd_HostDelete( httpd_host_t *host ) } TAB_REMOVE( httpd->i_host, httpd->host, host ); - host->b_die = 1; + vlc_object_kill( host ); vlc_thread_join( host ); msg_Dbg( host, "HTTP host removed" ); @@ -1153,7 +1171,7 @@ void httpd_HostDelete( httpd_host_t *host ) if( host->p_tls != NULL) tls_ServerDelete( host->p_tls ); - net_ListenClose( host->fd ); + net_ListenClose( host->fds ); free( host->psz_hostname ); vlc_mutex_destroy( &host->lock ); @@ -1334,7 +1352,7 @@ void httpd_MsgClean( httpd_message_t *msg ) httpd_MsgInit( msg ); } -char *httpd_MsgGet( httpd_message_t *msg, char *name ) +const char *httpd_MsgGet( httpd_message_t *msg, const char *name ) { int i; @@ -1348,34 +1366,34 @@ char *httpd_MsgGet( httpd_message_t *msg, char *name ) return NULL; } -void httpd_MsgAdd( httpd_message_t *msg, char *name, char *psz_value, ... ) +void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value, ... ) { va_list args; char *value = NULL; va_start( args, psz_value ); -#if defined(HAVE_VASPRINTF) && !defined(__APPLE__) && !defined(SYS_BEOS) - vasprintf( &value, psz_value, args ); -#else - { - int i_size = strlen( psz_value ) + 4096; /* FIXME stupid system */ - value = calloc( i_size, sizeof( char ) ); - vsnprintf( value, i_size, psz_value, args ); - value[i_size - 1] = 0; - } -#endif + if( vasprintf( &value, psz_value, args ) == -1 ) + value = NULL; va_end( args ); + if( value == NULL ) + return; + name = strdup( name ); + if( name == NULL ) + { + free( value ); + return; + } - TAB_APPEND( msg->i_name, msg->name, name ); + TAB_APPEND( msg->i_name, msg->name, (char*)name ); TAB_APPEND( msg->i_value, msg->value, value ); } -static void httpd_ClientInit( httpd_client_t *cl ) +static void httpd_ClientInit( httpd_client_t *cl, mtime_t now ) { cl->i_state = HTTPD_CLIENT_RECEIVING; - cl->i_activity_date = mdate(); + cl->i_activity_date = now; cl->i_activity_timeout = I64C(10000000); cl->i_buffer_size = HTTPD_CL_BUFSIZE; cl->i_buffer = 0; @@ -1427,9 +1445,7 @@ static void httpd_ClientClean( httpd_client_t *cl ) } } -static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock, - int i_sock_size, - tls_session_t *p_tls ) +static httpd_client_t *httpd_ClientNew( int fd, tls_session_t *p_tls, mtime_t now ) { httpd_client_t *cl = malloc( sizeof( httpd_client_t ) ); @@ -1437,12 +1453,10 @@ static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock, cl->i_ref = 0; cl->fd = fd; - memcpy( &cl->sock, sock, sizeof( cl->sock ) ); - cl->i_sock_size = i_sock_size; cl->url = NULL; cl->p_tls = p_tls; - httpd_ClientInit( cl ); + httpd_ClientInit( cl, now ); return cl; } @@ -1579,7 +1593,7 @@ static void httpd_ClientRecv( httpd_client_t *cl ) { static const struct { - char *name; + const char *name; int i_type; int i_proto; } @@ -1769,7 +1783,6 @@ static void httpd_ClientRecv( httpd_client_t *cl ) cl->i_state = HTTPD_CLIENT_DEAD; } } - cl->i_activity_date = mdate(); /* XXX: for QT I have to disable timeout. Try to find why */ if( cl->query.i_proto == HTTPD_PROTO_RTSP ) @@ -1852,7 +1865,6 @@ static void httpd_ClientSend( httpd_client_t *cl ) cl->i_buffer_size - cl->i_buffer ); if( i_len >= 0 ) { - cl->i_activity_date = mdate(); cl->i_buffer += i_len; if( cl->i_buffer >= cl->i_buffer_size ) @@ -1943,24 +1955,11 @@ static void httpd_ClientTlsHsOut( httpd_client_t *cl ) static void httpd_HostThread( httpd_host_t *host ) { tls_session_t *p_tls = NULL; - - host->p_total_counter = stats_CounterCreate( host, - VLC_VAR_INTEGER, STATS_COUNTER ); - host->p_active_counter = stats_CounterCreate( host, - VLC_VAR_INTEGER, STATS_COUNTER ); + counter_t *p_total_counter = stats_CounterCreate( host, VLC_VAR_INTEGER, STATS_COUNTER ); + counter_t *p_active_counter = stats_CounterCreate( host, VLC_VAR_INTEGER, STATS_COUNTER ); while( !host->b_die ) { - 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; - int b_low_delay = 0; - if( host->i_url <= 0 ) { /* 0.2s */ @@ -1968,52 +1967,55 @@ static void httpd_HostThread( httpd_host_t *host ) continue; } - /* built a set of handle to select */ - FD_ZERO( &fds_read ); - FD_ZERO( &fds_write ); - - 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 ) ) p_tls = tls_ServerSessionPrepare( host->p_tls ); + struct pollfd ufd[host->nfd + host->i_client]; + unsigned nfd; + for( nfd = 0; nfd < host->nfd; nfd++ ) + { + ufd[nfd].fd = host->fds[nfd]; + ufd[nfd].events = POLLIN; + ufd[nfd].revents = 0; + } + /* add all socket that should be read/write and close dead connection */ vlc_mutex_lock( &host->lock ); - for( i_client = 0; i_client < host->i_client; i_client++ ) + mtime_t now = mdate(); + vlc_bool_t b_low_delay = VLC_FALSE; + + for(int i_client = 0; i_client < host->i_client; i_client++ ) { httpd_client_t *cl = host->client[i_client]; - if( cl->i_ref < 0 || ( cl->i_ref == 0 && ( cl->i_state == HTTPD_CLIENT_DEAD || ( cl->i_activity_timeout > 0 && - cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) ) + cl->i_activity_date+cl->i_activity_timeout < now) ) ) ) { httpd_ClientClean( cl ); - stats_UpdateInteger( host, host->p_active_counter, -1, NULL ); + stats_UpdateInteger( host, p_active_counter, -1, NULL ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); i_client--; continue; } - else if( ( cl->i_state == HTTPD_CLIENT_RECEIVING ) + + struct pollfd *pufd = ufd + nfd; + assert (pufd < ufd + (sizeof (ufd) / sizeof (ufd[0]))); + + pufd->fd = cl->fd; + pufd->events = pufd->revents = 0; + + if( ( cl->i_state == HTTPD_CLIENT_RECEIVING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) ) { - FD_SET( cl->fd, &fds_read ); - i_handle_max = __MAX( i_handle_max, cl->fd ); + pufd->events = POLLIN; } else if( ( cl->i_state == HTTPD_CLIENT_SENDING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) ) { - FD_SET( cl->fd, &fds_write ); - i_handle_max = __MAX( i_handle_max, cl->fd ); + pufd->events = POLLOUT; } else if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) { @@ -2056,7 +2058,7 @@ static void httpd_HostThread( httpd_host_t *host ) } else if( i_msg == HTTPD_MSG_OPTIONS ) { - char *psz_cseq = NULL; + const char *psz_cseq; int i_cseq; /* unimplemented */ @@ -2094,7 +2096,7 @@ static void httpd_HostThread( httpd_host_t *host ) } else { - uint8_t *p; + char *p; /* unimplemented */ answer->i_proto = query->i_proto ; @@ -2103,24 +2105,8 @@ static void httpd_HostThread( httpd_host_t *host ) answer->i_status = 501; answer->psz_status = strdup( "Unimplemented" ); - p = answer->p_body = malloc( 1000 ); - - 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; + answer->i_body = httpd_HtmlError (&p, 501, NULL); + answer->p_body = (uint8_t *)p; httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */ @@ -2131,10 +2117,9 @@ static void httpd_HostThread( httpd_host_t *host ) { vlc_bool_t b_auth_failed = VLC_FALSE; vlc_bool_t b_hosts_failed = VLC_FALSE; - int i; /* Search the url and trigger callbacks */ - for( i = 0; i < host->i_url; i++ ) + for(int i = 0; i < host->i_url; i++ ) { httpd_url_t *url = host->url[i]; @@ -2146,56 +2131,51 @@ static void httpd_HostThread( httpd_host_t *host ) { char ip[NI_MAXNUMERICHOST]; - if( httpd_ClientIP( cl, ip ) != NULL ) + if( ( httpd_ClientIP( cl, ip ) == NULL ) + || ACL_Check( url->p_acl, ip ) ) { - if( ACL_Check( url->p_acl, ip ) ) - { - b_hosts_failed = VLC_TRUE; - break; - } - } - else b_hosts_failed = VLC_TRUE; + break; + } } if( answer && ( *url->psz_user || *url->psz_password ) ) { /* create the headers */ - char *b64 = httpd_MsgGet( query, "Authorization" ); /* BASIC id */ - char *auth; - char *id; - - asprintf( &id, "%s:%s", url->psz_user, url->psz_password ); - if( b64 ) auth = malloc( strlen(b64) + 1 ); - else auth = malloc( strlen("") + 1 ); + const char *b64 = httpd_MsgGet( query, "Authorization" ); /* BASIC id */ + char *user = NULL, *pass = NULL; if( b64 != NULL - && !strncasecmp( b64, "BASIC", 5 ) ) + && !strncasecmp( b64, "BASIC", 5 ) ) { b64 += 5; while( *b64 == ' ' ) - { b64++; + + user = vlc_b64_decode( b64 ); + if (user != NULL) + { + pass = strchr (user, ':'); + if (pass != NULL) + *pass++ = '\0'; } - b64_decode( auth, b64 ); - } - else - { - strcpy( auth, "" ); } - if( strcmp( id, auth ) ) + if ((user == NULL) || (pass == NULL) + || strcmp (user, url->psz_user) + || strcmp (pass, url->psz_password)) { - httpd_MsgAdd( answer, "WWW-Authenticate", "Basic realm=\"%s\"", url->psz_user ); + httpd_MsgAdd( answer, + "WWW-Authenticate", + "Basic realm=\"%s\"", + url->psz_user ); /* We fail for all url */ b_auth_failed = VLC_TRUE; - free( id ); - free( auth ); + free( user ); break; } - free( id ); - free( auth ); + free( user ); } if( !url->catch[i_msg].cb( url->catch[i_msg].p_sys, cl, answer, query ) ) @@ -2221,77 +2201,34 @@ static void httpd_HostThread( httpd_host_t *host ) if( answer ) { - uint8_t *p; + char *p; answer->i_proto = query->i_proto; answer->i_type = HTTPD_MSG_ANSWER; answer->i_version= 0; - p = answer->p_body = malloc( 1000 + strlen(query->psz_url) ); 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( (char *)p, - "" - "\n" - "\n" - "\n" - "Error 401\n" - "\n" - "\n" - "

401 Authorization Required (%s)

\n" - "
\n" - "

VideoLAN

\n" - "\n" - "\n", query->psz_url ); } else { /* no url registered */ answer->i_status = 404; answer->psz_status = strdup( "Not found" ); - - 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; + answer->i_body = httpd_HtmlError (&p, + answer->i_status, + query->psz_url); + answer->p_body = (uint8_t *)p; + cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */ httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); httpd_MsgAdd( answer, "Content-Type", "%s", "text/html" ); @@ -2304,8 +2241,8 @@ static void httpd_HostThread( httpd_host_t *host ) { if( cl->i_mode == HTTPD_CLIENT_FILE || cl->answer.i_body_offset == 0 ) { - char *psz_connection = httpd_MsgGet( &cl->answer, "Connection" ); - char *psz_query = httpd_MsgGet( &cl->query, "Connection" ); + const char *psz_connection = httpd_MsgGet( &cl->answer, "Connection" ); + const char *psz_query = httpd_MsgGet( &cl->query, "Connection" ); vlc_bool_t b_connection = VLC_FALSE; vlc_bool_t b_keepalive = VLC_FALSE; vlc_bool_t b_query = VLC_FALSE; @@ -2382,7 +2319,7 @@ static void httpd_HostThread( httpd_host_t *host ) &cl->answer, &cl->query ); if( cl->answer.i_type != HTTPD_MSG_NONE ) { - /* we have new data, so reenter send mode */ + /* we have new data, so re-enter send mode */ cl->i_buffer = 0; cl->p_buffer = cl->answer.p_body; cl->i_buffer_size = cl->answer.i_body; @@ -2401,121 +2338,45 @@ static void httpd_HostThread( httpd_host_t *host ) if( cl->i_mode == HTTPD_CLIENT_BIDIR && cl->i_state == HTTPD_CLIENT_SENDING ) { - FD_SET( cl->fd, &fds_read ); - i_handle_max = __MAX( i_handle_max, cl->fd ); + pufd->events |= POLLIN; } + + if (pufd->events != 0) + nfd++; } vlc_mutex_unlock( &host->lock ); /* we will wait 100ms or 20ms (not too big 'cause HTTPD_CLIENT_WAITING) */ - timeout.tv_sec = 0; - timeout.tv_usec = b_low_delay ? 20000 : 100000; - - i_ret = select( i_handle_max + 1, - &fds_read, &fds_write, NULL, &timeout ); - - if( (i_ret == -1) && (errno != EINTR) ) + switch( poll( ufd, nfd, b_low_delay ? 20 : 100) ) { -#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; - } - else if( i_ret <= 0 ) - { - continue; - } - - /* accept new connections */ - for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) - { - if( FD_ISSET( fd, &fds_read ) ) - { - 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 ) + case -1: + if (errno != EINTR) { - int i_state = 1; - - setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &i_state, sizeof (i_state)); - 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_SETFD, FD_CLOEXEC ); - { - int i_val = fcntl( fd, F_GETFL ); - fcntl( fd, F_SETFL, - O_NONBLOCK | ((i_val != -1) ? i_val : 0) ); - } - - if( fd >= FD_SETSIZE ) - { - net_Close( fd ); - fd = -1; - } - else -#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; - char ip[NI_MAXNUMERICHOST]; - stats_UpdateInteger( host, host->p_total_counter, - 1, NULL ); - stats_UpdateInteger( host, host->p_active_counter, - 1, NULL ); - cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls ); - httpd_ClientIP( cl, ip ); - msg_Dbg( host, "Connection from %s", ip ); - 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 - } + /* This is most likely a bug */ + msg_Err( host, "polling error: %s", strerror (errno)); + msleep( 1000 ); } - } + case 0: + continue; } - /* now try all others socket */ + /* Handle client sockets */ vlc_mutex_lock( &host->lock ); - for( i_client = 0; i_client < host->i_client; i_client++ ) + now = mdate(); + for( int i_client = 0; i_client < host->i_client; i_client++ ) { httpd_client_t *cl = host->client[i_client]; + const struct pollfd *pufd = &ufd[host->nfd + i_client]; + + assert( pufd < &ufd[sizeof(ufd) / sizeof(ufd[0])] ); + + if( cl->fd != pufd->fd ) + continue; // we were not waiting for this client + if( pufd->revents == 0 ) + continue; // no event received + + cl->i_activity_date = now; + if( cl->i_state == HTTPD_CLIENT_RECEIVING ) { httpd_ClientRecv( cl ); @@ -2535,16 +2396,76 @@ static void httpd_HostThread( httpd_host_t *host ) if( cl->i_mode == HTTPD_CLIENT_BIDIR && cl->i_state == HTTPD_CLIENT_SENDING && - FD_ISSET( cl->fd, &fds_read ) ) + (pufd->revents & POLLIN) ) { cl->b_read_waiting = VLC_TRUE; } } vlc_mutex_unlock( &host->lock ); + + /* Handle server sockets (accept new connections) */ + for( nfd = 0; nfd < host->nfd; nfd++ ) + { + httpd_client_t *cl; + int i_state = -1; + + assert (ufd[nfd].fd == host->fds[nfd]); + + if( ufd[nfd].revents == 0 ) + continue; + + /* */ + int kludge[] = { ufd[nfd].fd, -1 }; + int fd = net_Accept( host, kludge, 0 ); + if( fd < 0 ) + continue; + + 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( (p_tls == NULL) != (host->p_tls == NULL) ) + break; // wasted TLS session, cannot accept() anymore + } + + stats_UpdateInteger( host, p_total_counter, 1, NULL ); + stats_UpdateInteger( host, p_active_counter, 1, NULL ); + cl = httpd_ClientNew( fd, p_tls, now ); + p_tls = NULL; + vlc_mutex_lock( &host->lock ); + TAB_APPEND( host->i_client, host->client, cl ); + vlc_mutex_unlock( &host->lock ); + if( i_state != -1 ) + cl->i_state = i_state; // override state for TLS + + if (host->p_tls != NULL) + break; // cannot accept further without new TLS session + } + } if( p_tls != NULL ) tls_ServerSessionClose( p_tls ); + if( p_total_counter ) + stats_CounterClean( p_total_counter ); + if( p_active_counter ) + stats_CounterClean( p_active_counter ); } #else /* ENABLE_HTTPD */ @@ -2668,13 +2589,13 @@ void httpd_MsgInit ( httpd_message_t *a ) { } -void httpd_MsgAdd ( httpd_message_t *a, char *b, char *c, ... ) +void httpd_MsgAdd ( httpd_message_t *a, const char *b, const char *c, ... ) { } -char *httpd_MsgGet ( httpd_message_t *a, char *b ) +const char *httpd_MsgGet ( httpd_message_t *a, const char *b ) { - return NULL; + return ""; } void httpd_MsgClean( httpd_message_t *a )