Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

httpd.c

00001 /*****************************************************************************
00002  * httpd.c
00003  *****************************************************************************
00004  * Copyright (C) 2004-2005 the VideoLAN team
00005  * $Id: httpd.c 12916 2005-10-22 16:23:01Z md $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          RĂ©mi Denis-Courmont <rem # videolan.org>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 #include <stdlib.h>
00026 #include <vlc/vlc.h>
00027 
00028 #ifdef ENABLE_HTTPD
00029 
00030 #include "vlc_httpd.h"
00031 #include "network.h"
00032 #include "vlc_tls.h"
00033 #include "vlc_acl.h"
00034 
00035 #include <string.h>
00036 #include <errno.h>
00037 
00038 #ifdef HAVE_UNISTD_H
00039 #   include <unistd.h>
00040 #endif
00041 
00042 #ifdef HAVE_FCNTL_H
00043 #   include <fcntl.h>
00044 #endif
00045 
00046 #if defined( UNDER_CE )
00047 #   include <winsock.h>
00048 #elif defined( WIN32 )
00049 #   include <winsock2.h>
00050 #   include <ws2tcpip.h>
00051 #else
00052 #   include <netdb.h>                                         /* hostent ... */
00053 #   include <sys/socket.h>
00054 /* FIXME: should not be needed */
00055 #   include <netinet/in.h>
00056 #   ifdef HAVE_ARPA_INET_H
00057 #       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
00058 #   endif
00059 #endif
00060 
00061 #if defined( WIN32 )
00062 /* We need HUGE buffer otherwise TCP throughput is very limited */
00063 #define HTTPD_CL_BUFSIZE 1000000
00064 #else
00065 #define HTTPD_CL_BUFSIZE 10000
00066 #endif
00067 
00068 #if 0
00069 typedef struct httpd_t          httpd_t;
00070 
00071 typedef struct httpd_host_t     httpd_host_t;
00072 typedef struct httpd_url_t      httpd_url_t;
00073 typedef struct httpd_client_t   httpd_client_t;
00074 
00075 enum
00076 {
00077     HTTPD_MSG_NONE,
00078 
00079     /* answer */
00080     HTTPD_MSG_ANSWER,
00081 
00082     /* channel communication */
00083     HTTPD_MSG_CHANNEL,
00084 
00085     /* http request */
00086     HTTPD_MSG_GET,
00087     HTTPD_MSG_HEAD,
00088     HTTPD_MSG_POST,
00089 
00090     /* rtsp request */
00091     HTTPD_MSG_OPTIONS,
00092     HTTPD_MSG_DESCRIBE,
00093     HTTPD_MSG_SETUP,
00094     HTTPD_MSG_PLAY,
00095     HTTPD_MSG_PAUSE,
00096     HTTPD_MSG_TEARDOWN,
00097 
00098     /* just to track the count of MSG */
00099     HTTPD_MSG_MAX
00100 };
00101 
00102 enum
00103 {
00104     HTTPD_PROTO_NONE,
00105     HTTPD_PROTO_HTTP,
00106     HTTPD_PROTO_RTSP,
00107 };
00108 
00109 typedef struct
00110 {
00111     httpd_client_t *cl; /* NULL if not throught a connection e vlc internal */
00112 
00113     int     i_type;
00114     int     i_proto;
00115     int     i_version;
00116 
00117     /* for an answer */
00118     int     i_status;
00119     char    *psz_status;
00120 
00121     /* for a query */
00122     char    *psz_url;
00123     char    *psz_args;  /* FIXME find a clean way to handle GET(psz_args) and POST(body) through the same code */
00124 
00125     /* for rtp over rtsp */
00126     int     i_channel;
00127 
00128     /* options */
00129     int     i_name;
00130     char    **name;
00131     int     i_value;
00132     char    **value;
00133 
00134     /* body */
00135     int64_t i_body_offset;
00136     int     i_body;
00137     uint8_t *p_body;
00138 
00139 } httpd_message_t;
00140 
00141 typedef struct httpd_callback_sys_t httpd_callback_sys_t;
00142 /* answer could be null, int this case no answer is requested */
00143 typedef int (*httpd_callback_t)( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *answer, httpd_message_t *query );
00144 
00145 
00146 /* create a new host */
00147 httpd_host_t *httpd_HostNew( vlc_object_t *, char *psz_host, int i_port );
00148 /* delete a host */
00149 void          httpd_HostDelete( httpd_host_t * );
00150 
00151 /* register a new url */
00152 httpd_url_t *httpd_UrlNew( httpd_host_t *, char *psz_url );
00153 /* register callback on a url */
00154 int          httpd_UrlCatch( httpd_url_t *, int i_msg,
00155                              httpd_callback_t, httpd_callback_sys_t * );
00156 /* delete an url */
00157 void         httpd_UrlDelete( httpd_url_t * );
00158 
00159 
00160 void httpd_ClientModeStream( httpd_client_t *cl );
00161 void httpd_ClientModeBidir( httpd_client_t *cl );
00162 static void httpd_ClientClean( httpd_client_t *cl );
00163 
00164 /* High level */
00165 typedef struct httpd_file_t     httpd_file_t;
00166 typedef struct httpd_file_sys_t httpd_file_sys_t;
00167 typedef int (*httpd_file_callback_t)( httpd_file_sys_t*, httpd_file_t *, uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
00168 httpd_file_t *httpd_FileNew( httpd_host_t *,
00169                              char *psz_url, char *psz_mime,
00170                              char *psz_user, char *psz_password,
00171                              httpd_file_callback_t pf_fill,
00172                              httpd_file_sys_t *p_sys );
00173 void         httpd_FileDelete( httpd_file_t * );
00174 
00175 typedef struct httpd_redirect_t httpd_redirect_t;
00176 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *, char *psz_url_dst, char *psz_url_src );
00177 void              httpd_RedirectDelete( httpd_redirect_t * );
00178 
00179 #if 0
00180 typedef struct httpd_stream_t httpd_stream_t;
00181 httpd_stream_t *httpd_StreamNew( httpd_host_t * );
00182 int             httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data );
00183 int             httpd_StreamSend( httpd_stream_t *, uint8_t *p_data, int i_data );
00184 void            httpd_StreamDelete( httpd_stream_t * );
00185 #endif
00186 
00187 /* Msg functions facilities */
00188 void         httpd_MsgInit( httpd_message_t * );
00189 void         httpd_MsgAdd( httpd_message_t *, char *psz_name, char *psz_value, ... );
00190 /* return "" if not found. The string is not allocated */
00191 char        *httpd_MsgGet( httpd_message_t *, char *psz_name );
00192 void         httpd_MsgClean( httpd_message_t * );
00193 #endif
00194 
00195 #if 0
00196 struct httpd_t
00197 {
00198     VLC_COMMON_MEMBERS
00199 
00200     /* vlc_mutex_t  lock; */
00201     int          i_host;
00202     httpd_host_t **host;
00203 };
00204 #endif
00205 
00206 static void httpd_ClientClean( httpd_client_t *cl );
00207 
00208 /* each host run in his own thread */
00209 struct httpd_host_t
00210 {
00211     VLC_COMMON_MEMBERS
00212 
00213     httpd_t     *httpd;
00214 
00215     /* ref count */
00216     int         i_ref;
00217 
00218     /* address/port and socket for listening at connections */
00219     char        *psz_hostname;
00220     int         i_port;
00221     int         *fd;
00222 
00223     vlc_mutex_t lock;
00224 
00225     /* all registered url (becarefull that 2 httpd_url_t could point at the same url)
00226      * This will slow down the url research but make my live easier
00227      * All url will have their cb trigger, but only the first one can answer
00228      * */
00229     int         i_url;
00230     httpd_url_t **url;
00231 
00232     int            i_client;
00233     httpd_client_t **client;
00234     
00235     /* TLS data */
00236     tls_server_t *p_tls;
00237 };
00238 
00239 struct httpd_url_t
00240 {
00241     httpd_host_t *host;
00242 
00243     vlc_mutex_t lock;
00244 
00245     char      *psz_url;
00246     char      *psz_user;
00247     char      *psz_password;
00248     vlc_acl_t *p_acl;
00249 
00250     struct
00251     {
00252         httpd_callback_t     cb;
00253         httpd_callback_sys_t *p_sys;
00254     } catch[HTTPD_MSG_MAX];
00255 };
00256 
00257 /* status */
00258 enum
00259 {
00260     HTTPD_CLIENT_RECEIVING,
00261     HTTPD_CLIENT_RECEIVE_DONE,
00262 
00263     HTTPD_CLIENT_SENDING,
00264     HTTPD_CLIENT_SEND_DONE,
00265 
00266     HTTPD_CLIENT_WAITING,
00267 
00268     HTTPD_CLIENT_DEAD,
00269 
00270     HTTPD_CLIENT_TLS_HS_IN,
00271     HTTPD_CLIENT_TLS_HS_OUT
00272 };
00273 /* mode */
00274 enum
00275 {
00276     HTTPD_CLIENT_FILE,      /* default */
00277     HTTPD_CLIENT_STREAM,    /* regulary get data from cb */
00278     HTTPD_CLIENT_BIDIR,     /* check for reading and get data from cb */
00279 };
00280 
00281 struct httpd_client_t
00282 {
00283     httpd_url_t *url;
00284 
00285     int     i_ref;
00286 
00287     struct  sockaddr_storage sock;
00288     int     i_sock_size;
00289     int     fd;
00290 
00291     int     i_mode;
00292     int     i_state;
00293     int     b_read_waiting; /* stop as soon as possible sending */
00294 
00295     mtime_t i_activity_date;
00296     mtime_t i_activity_timeout;
00297 
00298     /* buffer for reading header */
00299     int     i_buffer_size;
00300     int     i_buffer;
00301     uint8_t *p_buffer;
00302 
00303     /* */
00304     httpd_message_t query;  /* client -> httpd */
00305     httpd_message_t answer; /* httpd -> client */
00306     
00307     /* TLS data */
00308     tls_session_t *p_tls;
00309 };
00310 
00311 
00312 /*****************************************************************************
00313  * Various functions
00314  *****************************************************************************/
00315 /*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/
00316 static void b64_decode( char *dest, char *src )
00317 {
00318     int  i_level;
00319     int  last = 0;
00320     int  b64[256] = {
00321         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
00322         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
00323         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
00324         52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
00325         -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
00326         15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
00327         -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
00328         41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
00329         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
00330         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
00331         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
00332         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
00333         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
00334         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
00335         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
00336         -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
00337         };
00338 
00339     for( i_level = 0; *src != '\0'; src++ )
00340     {
00341         int  c;
00342 
00343         c = b64[(unsigned int)*src];
00344         if( c == -1 )
00345         {
00346             continue;
00347         }
00348 
00349         switch( i_level )
00350         {
00351             case 0:
00352                 i_level++;
00353                 break;
00354             case 1:
00355                 *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
00356                 i_level++;
00357                 break;
00358             case 2:
00359                 *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
00360                 i_level++;
00361                 break;
00362             case 3:
00363                 *dest++ = ( ( last &0x03 ) << 6 ) | c;
00364                 i_level = 0;
00365         }
00366         last = c;
00367     }
00368 
00369     *dest = '\0';
00370 }
00371 
00372 static struct
00373 {
00374     const char *psz_ext;
00375     const char *psz_mime;
00376 } http_mime[] =
00377 {
00378     { ".htm",   "text/html" },
00379     { ".html",  "text/html" },
00380     { ".txt",   "text/plain" },
00381     { ".xml",   "text/xml" },
00382     { ".dtd",   "text/dtd" },
00383 
00384     { ".css",   "text/css" },
00385 
00386     /* image mime */
00387     { ".gif",   "image/gif" },
00388     { ".jpe",   "image/jpeg" },
00389     { ".jpg",   "image/jpeg" },
00390     { ".jpeg",  "image/jpeg" },
00391     { ".png",   "image/png" },
00392     { ".mpjpeg","multipart/x-mixed-replace; boundary=This Random String" },
00393 
00394     /* media mime */
00395     { ".avi",   "video/avi" },
00396     { ".asf",   "video/x-ms-asf" },
00397     { ".m1a",   "audio/mpeg" },
00398     { ".m2a",   "audio/mpeg" },
00399     { ".m1v",   "video/mpeg" },
00400     { ".m2v",   "video/mpeg" },
00401     { ".mp2",   "audio/mpeg" },
00402     { ".mp3",   "audio/mpeg" },
00403     { ".mpa",   "audio/mpeg" },
00404     { ".mpg",   "video/mpeg" },
00405     { ".mpeg",  "video/mpeg" },
00406     { ".mpe",   "video/mpeg" },
00407     { ".mov",   "video/quicktime" },
00408     { ".moov",  "video/quicktime" },
00409     { ".ogg",   "application/ogg" },
00410     { ".ogm",   "application/ogg" },
00411     { ".wav",   "audio/wav" },
00412     { ".wma",   "audio/x-ms-wma" },
00413     { ".wmv",   "video/x-ms-wmv" },
00414 
00415 
00416     /* end */
00417     { NULL,     NULL }
00418 };
00419 static const char *httpd_MimeFromUrl( const char *psz_url )
00420 {
00421 
00422     char *psz_ext;
00423 
00424     psz_ext = strrchr( psz_url, '.' );
00425     if( psz_ext )
00426     {
00427         int i;
00428 
00429         for( i = 0; http_mime[i].psz_ext != NULL ; i++ )
00430         {
00431             if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) )
00432             {
00433                 return http_mime[i].psz_mime;
00434             }
00435         }
00436     }
00437     return "application/octet-stream";
00438 }
00439 
00440 /*****************************************************************************
00441  * High Level Functions: httpd_file_t
00442  *****************************************************************************/
00443 struct httpd_file_t
00444 {
00445     httpd_url_t *url;
00446 
00447     char *psz_url;
00448     char *psz_mime;
00449 
00450     httpd_file_callback_t pf_fill;
00451     httpd_file_sys_t      *p_sys;
00452 
00453 };
00454 
00455 
00456 static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
00457 {
00458     httpd_file_t *file = (httpd_file_t*)p_sys;
00459     uint8_t *psz_args = query->psz_args;
00460     uint8_t **pp_body, *p_body;
00461     int *pi_body, i_body;
00462 
00463     if( answer == NULL || query == NULL )
00464     {
00465         return VLC_SUCCESS;
00466     }
00467     answer->i_proto  = HTTPD_PROTO_HTTP;
00468     answer->i_version= query->i_version;
00469     answer->i_type   = HTTPD_MSG_ANSWER;
00470 
00471     answer->i_status = 200;
00472     answer->psz_status = strdup( "OK" );
00473 
00474     httpd_MsgAdd( answer, "Content-type",  "%s", file->psz_mime );
00475     httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
00476 
00477     if( query->i_type != HTTPD_MSG_HEAD )
00478     {
00479         pp_body = &answer->p_body;
00480         pi_body = &answer->i_body;
00481     }
00482     else
00483     {
00484         /* The file still needs to be executed. */
00485         p_body = NULL;
00486         i_body = 0;
00487         pp_body = &p_body;
00488         pi_body = &i_body;
00489     }
00490 
00491     if( query->i_type == HTTPD_MSG_POST )
00492     {
00493         /* msg_Warn not supported */
00494     }
00495 
00496     file->pf_fill( file->p_sys, file, psz_args, pp_body, pi_body );
00497 
00498     if( query->i_type == HTTPD_MSG_HEAD && p_body != NULL )
00499     {
00500         free( p_body );
00501     }
00502 
00503     /* We respect client request */
00504     if( strcmp( httpd_MsgGet( &cl->query, "Connection" ), "" ) )
00505     {
00506         httpd_MsgAdd( answer, "Connection",
00507                       httpd_MsgGet( &cl->query, "Connection" ) );
00508     }
00509 
00510     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
00511 
00512     return VLC_SUCCESS;
00513 }
00514 
00515 
00516 httpd_file_t *httpd_FileNew( httpd_host_t *host,
00517                              const char *psz_url, const char *psz_mime,
00518                              const char *psz_user, const char *psz_password,
00519                              const vlc_acl_t *p_acl, httpd_file_callback_t pf_fill,
00520                              httpd_file_sys_t *p_sys )
00521 {
00522     httpd_file_t *file = malloc( sizeof( httpd_file_t ) );
00523 
00524     if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00525                                           psz_password, p_acl )
00526         ) == NULL )
00527     {
00528         free( file );
00529         return NULL;
00530     }
00531 
00532     file->psz_url  = strdup( psz_url );
00533     if( psz_mime && *psz_mime )
00534     {
00535         file->psz_mime = strdup( psz_mime );
00536     }
00537     else
00538     {
00539         file->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
00540     }
00541 
00542     file->pf_fill = pf_fill;
00543     file->p_sys   = p_sys;
00544 
00545     httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack,
00546                     (httpd_callback_sys_t*)file );
00547     httpd_UrlCatch( file->url, HTTPD_MSG_GET,  httpd_FileCallBack,
00548                     (httpd_callback_sys_t*)file );
00549     httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack,
00550                     (httpd_callback_sys_t*)file );
00551 
00552     return file;
00553 }
00554 
00555 void httpd_FileDelete( httpd_file_t *file )
00556 {
00557     httpd_UrlDelete( file->url );
00558 
00559     free( file->psz_url );
00560     free( file->psz_mime );
00561 
00562     free( file );
00563 }
00564 
00565 /*****************************************************************************
00566  * High Level Functions: httpd_handler_t (for CGIs)
00567  *****************************************************************************/
00568 struct httpd_handler_t
00569 {
00570     httpd_url_t *url;
00571 
00572     httpd_handler_callback_t pf_fill;
00573     httpd_handler_sys_t      *p_sys;
00574 
00575 };
00576 
00577 static int httpd_HandlerCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
00578 {
00579     httpd_handler_t *handler = (httpd_handler_t*)p_sys;
00580     uint8_t *psz_args = query->psz_args;
00581     char psz_remote_addr[100];
00582 
00583     if( answer == NULL || query == NULL )
00584     {
00585         return VLC_SUCCESS;
00586     }
00587     answer->i_proto  = HTTPD_PROTO_NONE;
00588     answer->i_type   = HTTPD_MSG_ANSWER;
00589 
00590     /* We do it ourselves, thanks */
00591     answer->i_status = 0;
00592     answer->psz_status = NULL;
00593 
00594     switch( cl->sock.ss_family )
00595     {
00596 #ifdef HAVE_INET_PTON
00597     case AF_INET:
00598         inet_ntop( cl->sock.ss_family,
00599                    &((struct sockaddr_in *)&cl->sock)->sin_addr,
00600                    psz_remote_addr, sizeof(psz_remote_addr) );
00601         break;
00602     case AF_INET6:
00603         inet_ntop( cl->sock.ss_family,
00604                    &((struct sockaddr_in6 *)&cl->sock)->sin6_addr,
00605                    psz_remote_addr, sizeof(psz_remote_addr) );
00606         break;
00607 #else
00608     case AF_INET:
00609     {
00610         char *psz_tmp = inet_ntoa( ((struct sockaddr_in *)&cl->sock)->sin_addr );
00611         strncpy( psz_remote_addr, psz_tmp, sizeof(psz_remote_addr) );
00612         break;
00613     }
00614 #endif
00615     default:
00616         psz_remote_addr[0] = '\0';
00617     }
00618 
00619     handler->pf_fill( handler->p_sys, handler, query->psz_url, psz_args,
00620                       query->i_type, query->p_body, query->i_body,
00621                       psz_remote_addr, NULL,
00622                       &answer->p_body, &answer->i_body );
00623 
00624     if( query->i_type == HTTPD_MSG_HEAD )
00625     {
00626         char *p = answer->p_body;
00627         while ( (p = strchr( p, '\r' )) != NULL )
00628         {
00629             if( p[1] && p[1] == '\n' && p[2] && p[2] == '\r'
00630                  && p[3] && p[3] == '\n' )
00631             {
00632                 break;
00633             }
00634         }
00635         if( p != NULL )
00636         {
00637             p[4] = '\0';
00638             answer->i_body = strlen(answer->p_body) + 1;
00639             answer->p_body = realloc( answer->p_body, answer->i_body );
00640         }
00641     }
00642 
00643     if( strncmp( answer->p_body, "HTTP/1.", 7 ) )
00644     {
00645         int i_status, i_headers;
00646         char *psz_headers, *psz_new, *psz_status;
00647         char psz_code[12];
00648         if( !strncmp( answer->p_body, "Status: ", 8 ) )
00649         {
00650             /* Apache-style */
00651             i_status = strtol( &answer->p_body[8], &psz_headers, 0 );
00652             if( *psz_headers ) psz_headers++;
00653             if( *psz_headers ) psz_headers++;
00654             i_headers = answer->i_body - (psz_headers - (char *)answer->p_body);
00655         }
00656         else
00657         {
00658             i_status = 200;
00659             psz_headers = answer->p_body;
00660             i_headers = answer->i_body;
00661         }
00662         switch( i_status )
00663         {
00664         case 200:
00665             psz_status = "OK";
00666             break;
00667         case 401:
00668             psz_status = "Unauthorized";
00669             break;
00670         default:
00671             psz_status = "Undefined";
00672             break;
00673         }
00674         snprintf( psz_code, sizeof(psz_code), "%d", i_status );
00675         answer->i_body = sizeof("HTTP/1.0  \r\n") + strlen(psz_code)
00676                            + strlen(psz_status) + i_headers - 1;
00677         psz_new = malloc( answer->i_body + 1);
00678         sprintf( psz_new, "HTTP/1.0 %s %s\r\n", psz_code, psz_status );
00679         memcpy( &psz_new[strlen(psz_new)], psz_headers, i_headers );
00680         free( answer->p_body );
00681         answer->p_body = psz_new;
00682     }
00683 
00684     return VLC_SUCCESS;
00685 }
00686 
00687 httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
00688                                    const char *psz_user,
00689                                    const char *psz_password,
00690                                    const vlc_acl_t *p_acl,
00691                                    httpd_handler_callback_t pf_fill,
00692                                    httpd_handler_sys_t *p_sys )
00693 {
00694     httpd_handler_t *handler = malloc( sizeof( httpd_handler_t ) );
00695 
00696     if( ( handler->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00697                                              psz_password, p_acl )
00698         ) == NULL )
00699     {
00700         free( handler );
00701         return NULL;
00702     }
00703 
00704     handler->pf_fill = pf_fill;
00705     handler->p_sys   = p_sys;
00706 
00707     httpd_UrlCatch( handler->url, HTTPD_MSG_HEAD, httpd_HandlerCallBack,
00708                     (httpd_callback_sys_t*)handler );
00709     httpd_UrlCatch( handler->url, HTTPD_MSG_GET,  httpd_HandlerCallBack,
00710                     (httpd_callback_sys_t*)handler );
00711     httpd_UrlCatch( handler->url, HTTPD_MSG_POST, httpd_HandlerCallBack,
00712                     (httpd_callback_sys_t*)handler );
00713 
00714     return handler;
00715 }
00716 
00717 void httpd_HandlerDelete( httpd_handler_t *handler )
00718 {
00719     httpd_UrlDelete( handler->url );
00720     free( handler );
00721 }
00722 
00723 /*****************************************************************************
00724  * High Level Functions: httpd_redirect_t
00725  *****************************************************************************/
00726 struct httpd_redirect_t
00727 {
00728     httpd_url_t *url;
00729     char        *psz_dst;
00730 };
00731 
00732 static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys,
00733                                    httpd_client_t *cl, httpd_message_t *answer,
00734                                    httpd_message_t *query )
00735 {
00736     httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys;
00737     uint8_t *p;
00738 
00739     if( answer == NULL || query == NULL )
00740     {
00741         return VLC_SUCCESS;
00742     }
00743     answer->i_proto  = query->i_proto;
00744     answer->i_version= query->i_version;
00745     answer->i_type   = HTTPD_MSG_ANSWER;
00746     answer->i_status = 301;
00747     answer->psz_status = strdup( "Moved Permanently" );
00748 
00749     p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) );
00750     p += sprintf( (char *)p,
00751         "<?xml version=\"1.0\" encoding=\"ascii\" ?>\n"
00752         "<!DOCTYPE html PUBLIC \"-//W3C//DTD  XHTML 1.0 Strict//EN\" "
00753         "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
00754         "<html>\n"
00755         "<head>\n"
00756         "<title>Redirection</title>\n"
00757         "</head>\n"
00758         "<body>\n"
00759         "<h1>You should be " 
00760         "<a href=\"%s\">redirected</a></h1>\n"
00761         "<hr />\n"
00762         "<p><a href=\"http://www.videolan.org\">VideoLAN</a>\n</p>"
00763         "<hr />\n"
00764         "</body>\n"
00765         "</html>\n", rdir->psz_dst );
00766     answer->i_body = p - answer->p_body;
00767 
00768     /* XXX check if it's ok or we need to set an absolute url */
00769     httpd_MsgAdd( answer, "Location",  "%s", rdir->psz_dst );
00770 
00771     httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
00772 
00773     return VLC_SUCCESS;
00774 }
00775 
00776 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, const char *psz_url_dst,
00777                                      const char *psz_url_src )
00778 {
00779     httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) );
00780 
00781     if( !( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL, NULL ) ) )
00782     {
00783         free( rdir );
00784         return NULL;
00785     }
00786     rdir->psz_dst = strdup( psz_url_dst );
00787 
00788     /* Redirect apply for all HTTP request and RTSP DESCRIBE resquest */
00789     httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD, httpd_RedirectCallBack,
00790                     (httpd_callback_sys_t*)rdir );
00791     httpd_UrlCatch( rdir->url, HTTPD_MSG_GET, httpd_RedirectCallBack,
00792                     (httpd_callback_sys_t*)rdir );
00793     httpd_UrlCatch( rdir->url, HTTPD_MSG_POST, httpd_RedirectCallBack,
00794                     (httpd_callback_sys_t*)rdir );
00795     httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE, httpd_RedirectCallBack,
00796                     (httpd_callback_sys_t*)rdir );
00797 
00798     return rdir;
00799 }
00800 void httpd_RedirectDelete( httpd_redirect_t *rdir )
00801 {
00802     httpd_UrlDelete( rdir->url );
00803     free( rdir->psz_dst );
00804     free( rdir );
00805 }
00806 
00807 /*****************************************************************************
00808  * High Level Funtions: httpd_stream_t
00809  *****************************************************************************/
00810 struct httpd_stream_t
00811 {
00812     vlc_mutex_t lock;
00813     httpd_url_t *url;
00814 
00815     char    *psz_mime;
00816 
00817     /* Header to send as first packet */
00818     uint8_t *p_header;
00819     int     i_header;
00820 
00821     /* circular buffer */
00822     int         i_buffer_size;      /* buffer size, can't be reallocated smaller */
00823     uint8_t     *p_buffer;          /* buffer */
00824     int64_t     i_buffer_pos;       /* absolute position from begining */
00825     int64_t     i_buffer_last_pos;  /* a new connection will start with that */
00826 };
00827 
00828 static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys,
00829                                  httpd_client_t *cl, httpd_message_t *answer,
00830                                  httpd_message_t *query )
00831 {
00832     httpd_stream_t *stream = (httpd_stream_t*)p_sys;
00833 
00834     if( answer == NULL || query == NULL || cl == NULL )
00835     {
00836         return VLC_SUCCESS;
00837     }
00838     if( answer->i_body_offset > 0 )
00839     {
00840         int64_t i_write;
00841         int     i_pos;
00842 
00843 #if 0
00844         fprintf( stderr, "httpd_StreamCallBack i_body_offset=%lld\n",
00845                  answer->i_body_offset );
00846 #endif
00847 
00848         if( answer->i_body_offset >= stream->i_buffer_pos )
00849         {
00850             /* fprintf( stderr, "httpd_StreamCallBack: no data\n" ); */
00851             return VLC_EGENERIC;    /* wait, no data available */
00852         }
00853         if( answer->i_body_offset + stream->i_buffer_size <
00854             stream->i_buffer_pos )
00855         {
00856             /* this client isn't fast enough */
00857             fprintf( stderr, "fixing i_body_offset (old=%lld new=%lld)\n",
00858                      answer->i_body_offset, stream->i_buffer_last_pos );
00859             answer->i_body_offset = stream->i_buffer_last_pos;
00860         }
00861 
00862         i_pos   = answer->i_body_offset % stream->i_buffer_size;
00863         i_write = stream->i_buffer_pos - answer->i_body_offset;
00864         if( i_write > HTTPD_CL_BUFSIZE )
00865         {
00866             i_write = HTTPD_CL_BUFSIZE;
00867         }
00868         else if( i_write <= 0 )
00869         {
00870             return VLC_EGENERIC;    /* wait, no data available */
00871         }
00872 
00873         /* Don't go past the end of the circular buffer */
00874         i_write = __MIN( i_write, stream->i_buffer_size - i_pos );
00875 
00876         /* using HTTPD_MSG_ANSWER -> data available */
00877         answer->i_proto  = HTTPD_PROTO_HTTP;
00878         answer->i_version= 0;
00879         answer->i_type   = HTTPD_MSG_ANSWER;
00880 
00881         answer->i_body = i_write;
00882         answer->p_body = malloc( i_write );
00883         memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write );
00884 
00885         answer->i_body_offset += i_write;
00886 
00887         return VLC_SUCCESS;
00888     }
00889     else
00890     {
00891         answer->i_proto  = HTTPD_PROTO_HTTP;
00892         answer->i_version= 0;
00893         answer->i_type   = HTTPD_MSG_ANSWER;
00894 
00895         answer->i_status = 200;
00896         answer->psz_status = strdup( "OK" );
00897 
00898         if( query->i_type != HTTPD_MSG_HEAD )
00899         {
00900             httpd_ClientModeStream( cl );
00901             vlc_mutex_lock( &stream->lock );
00902             /* Send the header */
00903             if( stream->i_header > 0 )
00904             {
00905                 answer->i_body = stream->i_header;
00906                 answer->p_body = malloc( stream->i_header );
00907                 memcpy( answer->p_body, stream->p_header, stream->i_header );
00908             }
00909             answer->i_body_offset = stream->i_buffer_last_pos;
00910             vlc_mutex_unlock( &stream->lock );
00911         }
00912         else
00913         {
00914             httpd_MsgAdd( answer, "Content-Length", "%d", 0 );
00915             answer->i_body_offset = 0;
00916         }
00917 
00918         if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
00919         {
00920             vlc_bool_t b_xplaystream = VLC_FALSE;
00921             int i;
00922 
00923             httpd_MsgAdd( answer, "Content-type", "%s",
00924                           "application/octet-stream" );
00925             httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
00926             httpd_MsgAdd( answer, "Pragma", "no-cache" );
00927             httpd_MsgAdd( answer, "Pragma", "client-id=%d", rand()&0x7fff );
00928             httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
00929 
00930             /* Check if there is a xPlayStrm=1 */
00931             for( i = 0; i < query->i_name; i++ )
00932             {
00933                 if( !strcasecmp( query->name[i],  "Pragma" ) &&
00934                     strstr( query->value[i], "xPlayStrm=1" ) )
00935                 {
00936                     b_xplaystream = VLC_TRUE;
00937                 }
00938             }
00939 
00940             if( !b_xplaystream )
00941             {
00942                 answer->i_body_offset = 0;
00943             }
00944         }
00945         else
00946         {
00947             httpd_MsgAdd( answer, "Content-type",  "%s", stream->psz_mime );
00948         }
00949         httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
00950         return VLC_SUCCESS;
00951     }
00952 }
00953 
00954 httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
00955                                  const char *psz_url, const char *psz_mime,
00956                                  const char *psz_user, const char *psz_password,
00957                                  const vlc_acl_t *p_acl )
00958 {
00959     httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) );
00960 
00961     if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user,
00962                                             psz_password, p_acl )
00963         ) == NULL )
00964     {
00965         free( stream );
00966         return NULL;
00967     }
00968     vlc_mutex_init( host, &stream->lock );
00969     if( psz_mime && *psz_mime )
00970     {
00971         stream->psz_mime = strdup( psz_mime );
00972     }
00973     else
00974     {
00975         stream->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
00976     }
00977     stream->i_header = 0;
00978     stream->p_header = NULL;
00979     stream->i_buffer_size = 5000000;    /* 5 Mo per stream */
00980     stream->p_buffer = malloc( stream->i_buffer_size );
00981     /* We set to 1 to make life simpler
00982      * (this way i_body_offset can never be 0) */
00983     stream->i_buffer_pos = 1;
00984     stream->i_buffer_last_pos = 1;
00985 
00986     httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack,
00987                     (httpd_callback_sys_t*)stream );
00988     httpd_UrlCatch( stream->url, HTTPD_MSG_GET, httpd_StreamCallBack,
00989                     (httpd_callback_sys_t*)stream );
00990     httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack,
00991                     (httpd_callback_sys_t*)stream );
00992 
00993     return stream;
00994 }
00995 
00996 int httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data )
00997 {
00998     vlc_mutex_lock( &stream->lock );
00999     if( stream->p_header )
01000     {
01001         free( stream->p_header );
01002         stream->p_header = NULL;
01003     }
01004     stream->i_header = i_data;
01005     if( i_data > 0 )
01006     {
01007         stream->p_header = malloc( i_data );
01008         memcpy( stream->p_header, p_data, i_data );
01009     }
01010     vlc_mutex_unlock( &stream->lock );
01011 
01012     return VLC_SUCCESS;
01013 }
01014 
01015 int httpd_StreamSend( httpd_stream_t *stream, uint8_t *p_data, int i_data )
01016 {
01017     int i_count;
01018     int i_pos;
01019 
01020     if( i_data < 0 || p_data == NULL )
01021     {
01022         return VLC_SUCCESS;
01023     }
01024     vlc_mutex_lock( &stream->lock );
01025 
01026     /* save this pointer (to be used by new connection) */
01027     stream->i_buffer_last_pos = stream->i_buffer_pos;
01028 
01029     i_pos = stream->i_buffer_pos % stream->i_buffer_size;
01030     i_count = i_data;
01031     while( i_count > 0)
01032     {
01033         int i_copy;
01034 
01035         i_copy = __MIN( i_count, stream->i_buffer_size - i_pos );
01036 
01037         /* Ok, we can't go past the end of our buffer */
01038         memcpy( &stream->p_buffer[i_pos], p_data, i_copy );
01039 
01040         i_pos = ( i_pos + i_copy ) % stream->i_buffer_size;
01041         i_count -= i_copy;
01042         p_data  += i_copy;
01043     }
01044 
01045     stream->i_buffer_pos += i_data;
01046 
01047     vlc_mutex_unlock( &stream->lock );
01048     return VLC_SUCCESS;
01049 }
01050 
01051 void httpd_StreamDelete( httpd_stream_t *stream )
01052 {
01053     httpd_UrlDelete( stream->url );
01054     vlc_mutex_destroy( &stream->lock );
01055     if( stream->psz_mime ) free( stream->psz_mime );
01056     if( stream->p_header ) free( stream->p_header );
01057     if( stream->p_buffer ) free( stream->p_buffer );
01058     free( stream );
01059 }
01060 
01061 
01062 /*****************************************************************************
01063  * Low level
01064  *****************************************************************************/
01065 static void httpd_HostThread( httpd_host_t * );
01066 
01067 /* create a new host */
01068 httpd_host_t *httpd_HostNew( vlc_object_t *p_this, const char *psz_host,
01069                              int i_port )
01070 {
01071     return httpd_TLSHostNew( p_this, psz_host, i_port, NULL, NULL, NULL, NULL
01072                            );
01073 }
01074 
01075 httpd_host_t *httpd_TLSHostNew( vlc_object_t *p_this, const char *psz_hostname,
01076                                 int i_port,
01077                                 const char *psz_cert, const char *psz_key,
01078                                 const char *psz_ca, const char *psz_crl )
01079 {
01080     httpd_t      *httpd;
01081     httpd_host_t *host;
01082     tls_server_t *p_tls;
01083     char *psz_host;
01084     vlc_value_t  lockval;
01085     int i;
01086 
01087     if( psz_hostname == NULL )
01088         psz_hostname = "";
01089 
01090     psz_host = strdup( psz_hostname );
01091     if( psz_host == NULL )
01092     {
01093         msg_Err( p_this, "memory error" );
01094         return NULL;
01095     }
01096 
01097     /* to be sure to avoid multiple creation */
01098     var_Create( p_this->p_libvlc, "httpd_mutex", VLC_VAR_MUTEX );
01099     var_Get( p_this->p_libvlc, "httpd_mutex", &lockval );
01100     vlc_mutex_lock( lockval.p_address );
01101 
01102     if( !(httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE )) )
01103     {
01104         msg_Info( p_this, "creating httpd" );
01105         if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL )
01106         {
01107             vlc_mutex_unlock( lockval.p_address );
01108             free( psz_host );
01109             return NULL;
01110         }
01111 
01112         httpd->i_host = 0;
01113         httpd->host   = NULL;
01114 
01115         vlc_object_yield( httpd );
01116         vlc_object_attach( httpd, p_this->p_vlc );
01117     }
01118 
01119     /* verify if it already exist */
01120     for( i = httpd->i_host - 1; i >= 0; i-- )
01121     {
01122         host = httpd->host[i];
01123 
01124         /* cannot mix TLS and non-TLS hosts */
01125         if( ( ( httpd->host[i]->p_tls != NULL ) != ( psz_cert != NULL ) )
01126          || ( host->i_port != i_port )
01127          || strcmp( host->psz_hostname, psz_hostname ) )
01128             continue;
01129 
01130         /* yep found */
01131         host->i_ref++;
01132 
01133         vlc_mutex_unlock( lockval.p_address );
01134         return host;
01135     }
01136 
01137     host = NULL;
01138 
01139     /* determine TLS configuration */
01140     if ( psz_cert != NULL )
01141     {
01142         p_tls = tls_ServerCreate( p_this, psz_cert, psz_key );
01143         if ( p_tls == NULL )
01144         {
01145             msg_Err( p_this, "TLS initialization error" );
01146             goto error;
01147         }
01148 
01149         if ( ( psz_ca != NULL) && tls_ServerAddCA( p_tls, psz_ca ) )
01150         {
01151             msg_Err( p_this, "TLS CA error" );
01152             goto error;
01153         }
01154 
01155         if ( ( psz_crl != NULL) && tls_ServerAddCRL( p_tls, psz_crl ) )
01156         {
01157             msg_Err( p_this, "TLS CRL error" );
01158             goto error;
01159         }
01160     }
01161     else
01162         p_tls = NULL;
01163 
01164     /* create the new host */
01165     host = vlc_object_create( p_this, sizeof( httpd_host_t ) );
01166     host->httpd = httpd;
01167     vlc_mutex_init( httpd, &host->lock );
01168     host->i_ref = 1;
01169 
01170     host->fd = net_ListenTCP( p_this, psz_host, i_port );
01171     if( host->fd == NULL )
01172     {
01173         msg_Err( p_this, "cannot create socket(s) for HTTP host" );
01174         goto error;
01175     }
01176        
01177     host->i_port = i_port;
01178     host->psz_hostname = psz_host;
01179 
01180     host->i_url     = 0;
01181     host->url       = NULL;
01182     host->i_client  = 0;
01183     host->client    = NULL;
01184 
01185     host->p_tls = p_tls;
01186 
01187     /* create the thread */
01188     if( vlc_thread_create( host, "httpd host thread", httpd_HostThread,
01189                            VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
01190     {
01191         msg_Err( p_this, "cannot spawn http host thread" );
01192         goto error;
01193     }
01194 
01195     /* now add it to httpd */
01196     TAB_APPEND( httpd->i_host, httpd->host, host );
01197     vlc_mutex_unlock( lockval.p_address );
01198 
01199     return host;
01200 
01201 error:
01202     free( psz_host );
01203     if( httpd->i_host <= 0 )
01204     {
01205         vlc_object_release( httpd );
01206         vlc_object_detach( httpd );
01207         vlc_object_destroy( httpd );
01208     }
01209     vlc_mutex_unlock( lockval.p_address );
01210 
01211     if( host != NULL )
01212     {
01213         net_ListenClose( host->fd );
01214         vlc_mutex_destroy( &host->lock );
01215         vlc_object_destroy( host );
01216     }
01217 
01218     if( p_tls != NULL )
01219         tls_ServerDelete( p_tls );
01220 
01221     return NULL;
01222 }
01223 
01224 /* delete a host */
01225 void httpd_HostDelete( httpd_host_t *host )
01226 {
01227     httpd_t *httpd = host->httpd;
01228     vlc_value_t lockval;
01229     int i;
01230 
01231     msg_Dbg( host, "httpd_HostDelete" );
01232 
01233     var_Get( httpd->p_libvlc, "httpd_mutex", &lockval );
01234     vlc_mutex_lock( lockval.p_address );
01235 
01236     host->i_ref--;
01237     if( host->i_ref > 0 )
01238     {
01239         /* still used */
01240         vlc_mutex_unlock( lockval.p_address );
01241         msg_Dbg( host, "httpd_HostDelete: host still used" );
01242         return;
01243     }
01244     TAB_REMOVE( httpd->i_host, httpd->host, host );
01245 
01246     msg_Dbg( host, "httpd_HostDelete: host removed from http" );
01247 
01248     host->b_die = 1;
01249     vlc_thread_join( host );
01250 
01251     msg_Dbg( host, "httpd_HostDelete: host thread joined" );
01252 
01253     for( i = 0; i < host->i_url; i++ )
01254     {
01255         msg_Err( host, "url still registered:%s", host->url[i]->psz_url );
01256     }
01257     for( i = 0; i < host->i_client; i++ )
01258     {
01259         httpd_client_t *cl = host->client[i];
01260         msg_Warn( host, "client still connected" );
01261         httpd_ClientClean( cl );
01262         TAB_REMOVE( host->i_client, host->client, cl );
01263         free( cl );
01264         i--;
01265         /* TODO */
01266     }
01267 
01268     if( host->p_tls != NULL)
01269         tls_ServerDelete( host->p_tls );
01270 
01271     net_ListenClose( host->fd );
01272     free( host->psz_hostname );
01273 
01274     vlc_mutex_destroy( &host->lock );
01275     vlc_object_destroy( host );
01276 
01277     vlc_object_release( httpd );
01278     if( httpd->i_host <= 0 )
01279     {
01280         msg_Info( httpd, "httpd doesn't reference any host, deleting" );
01281         vlc_object_detach( httpd );
01282         vlc_object_destroy( httpd );
01283     }
01284     vlc_mutex_unlock( lockval.p_address );
01285 }
01286 
01287 /* register a new url */
01288 static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, const char *psz_url,
01289                                          const char *psz_user, const char *psz_password,
01290                                          const vlc_acl_t *p_acl, vlc_bool_t b_check )
01291 {
01292     httpd_url_t *url;
01293     int         i;
01294 
01295     vlc_mutex_lock( &host->lock );
01296     if( b_check )
01297     {
01298         for( i = 0; i < host->i_url; i++ )
01299         {
01300             if( !strcmp( psz_url, host->url[i]->psz_url ) )
01301             {
01302                 msg_Warn( host->httpd,
01303                           "cannot add '%s' (url already defined)", psz_url );
01304                 vlc_mutex_unlock( &host->lock );
01305                 return NULL;
01306             }
01307         }
01308     }
01309 
01310     url = malloc( sizeof( httpd_url_t ) );
01311     url->host = host;
01312 
01313     vlc_mutex_init( host->httpd, &url->lock );
01314     url->psz_url = strdup( psz_url );
01315     url->psz_user = strdup( psz_user ? psz_user : "" );
01316     url->psz_password = strdup( psz_password ? psz_password : "" );
01317     url->p_acl = ACL_Duplicate( host, p_acl );
01318     for( i = 0; i < HTTPD_MSG_MAX; i++ )
01319     {
01320         url->catch[i].cb = NULL;
01321         url->catch[i].p_sys = NULL;
01322     }
01323 
01324     TAB_APPEND( host->i_url, host->url, url );
01325     vlc_mutex_unlock( &host->lock );
01326 
01327     return url;
01328 }
01329 
01330 httpd_url_t *httpd_UrlNew( httpd_host_t *host, const char *psz_url,
01331                            const char *psz_user, const char *psz_password,
01332                            const vlc_acl_t *p_acl )
01333 {
01334     return httpd_UrlNewPrivate( host, psz_url, psz_user,
01335                                 psz_password, p_acl, VLC_FALSE );
01336 }
01337 
01338 httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, const char *psz_url,
01339                                  const char *psz_user, const char *psz_password,
01340                                  const vlc_acl_t *p_acl )
01341 {
01342     return httpd_UrlNewPrivate( host, psz_url, psz_user,
01343                                 psz_password, p_acl, VLC_TRUE );
01344 }
01345 
01346 /* register callback on a url */
01347 int httpd_UrlCatch( httpd_url_t *url, int i_msg, httpd_callback_t cb,
01348                     httpd_callback_sys_t *p_sys )
01349 {
01350     vlc_mutex_lock( &url->lock );
01351     url->catch[i_msg].cb   = cb;
01352     url->catch[i_msg].p_sys= p_sys;
01353     vlc_mutex_unlock( &url->lock );
01354 
01355     return VLC_SUCCESS;
01356 }
01357 
01358 
01359 /* delete an url */
01360 void httpd_UrlDelete( httpd_url_t *url )
01361 {
01362     httpd_host_t *host = url->host;
01363     int          i;
01364 
01365     vlc_mutex_lock( &host->lock );
01366     TAB_REMOVE( host->i_url, host->url, url );
01367 
01368     vlc_mutex_destroy( &url->lock );
01369     free( url->psz_url );
01370     free( url->psz_user );
01371     free( url->psz_password );
01372     ACL_Destroy( url->p_acl );
01373 
01374     for( i = 0; i < host->i_client; i++ )
01375     {
01376         httpd_client_t *client = host->client[i];
01377 
01378         if( client->url == url )
01379         {
01380             /* TODO complete it */
01381             msg_Warn( host, "force closing connections" );
01382             httpd_ClientClean( client );
01383             TAB_REMOVE( host->i_client, host->client, client );
01384             free( client );
01385             i--;
01386         }
01387     }
01388     free( url );
01389     vlc_mutex_unlock( &host->lock );
01390 }
01391 
01392 void httpd_MsgInit( httpd_message_t *msg )
01393 {
01394     msg->cl         = NULL;
01395     msg->i_type     = HTTPD_MSG_NONE;
01396     msg->i_proto    = HTTPD_PROTO_NONE;
01397     msg->i_version  = -1;
01398 
01399     msg->i_status   = 0;
01400     msg->psz_status = NULL;
01401 
01402     msg->psz_url = NULL;
01403     msg->psz_args = NULL;
01404 
01405     msg->i_channel = -1;
01406 
01407     msg->i_name = 0;
01408     msg->name   = NULL;
01409     msg->i_value= 0;
01410     msg->value  = NULL;
01411 
01412     msg->i_body_offset = 0;
01413     msg->i_body        = 0;
01414     msg->p_body        = 0;
01415 }
01416 
01417 void httpd_MsgClean( httpd_message_t *msg )
01418 {
01419     int i;
01420 
01421     if( msg->psz_status )
01422     {
01423         free( msg->psz_status );
01424     }
01425     if( msg->psz_url )
01426     {
01427         free( msg->psz_url );
01428     }
01429     if( msg->psz_args )
01430     {
01431         free( msg->psz_args );
01432     }
01433     for( i = 0; i < msg->i_name; i++ )
01434     {
01435         free( msg->name[i] );
01436         free( msg->value[i] );
01437     }
01438     if( msg->name )
01439     {
01440         free( msg->name );
01441     }
01442     if( msg->value )
01443     {
01444         free( msg->value );
01445     }
01446     if( msg->p_body )
01447     {
01448         free( msg->p_body );
01449     }
01450     httpd_MsgInit( msg );
01451 }
01452 
01453 char *httpd_MsgGet( httpd_message_t *msg, char *name )
01454 {
01455     int i;
01456 
01457     for( i = 0; i < msg->i_name; i++ )
01458     {
01459         if( !strcasecmp( msg->name[i], name ))
01460         {
01461             return msg->value[i];
01462         }
01463     }
01464     return "";
01465 }
01466 void httpd_MsgAdd( httpd_message_t *msg, char *name, char *psz_value, ... )
01467 {
01468     va_list args;
01469     char *value = NULL;
01470 
01471     va_start( args, psz_value );
01472 #if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined(SYS_BEOS)
01473     vasprintf( &value, psz_value, args );
01474 #else
01475     {
01476         int i_size = strlen( psz_value ) + 4096;    /* FIXME stupid system */
01477         value = calloc( i_size, sizeof( char ) );
01478         vsnprintf( value, i_size, psz_value, args );
01479         value[i_size - 1] = 0;
01480     }
01481 #endif
01482     va_end( args );
01483 
01484     name = strdup( name );
01485 
01486     TAB_APPEND( msg->i_name,  msg->name,  name );
01487     TAB_APPEND( msg->i_value, msg->value, value );
01488 }
01489 
01490 static void httpd_ClientInit( httpd_client_t *cl )
01491 {
01492     cl->i_state = HTTPD_CLIENT_RECEIVING;
01493     cl->i_activity_date = mdate();
01494     cl->i_activity_timeout = I64C(10000000);
01495     cl->i_buffer_size = HTTPD_CL_BUFSIZE;
01496     cl->i_buffer = 0;
01497     cl->p_buffer = malloc( cl->i_buffer_size );
01498     cl->i_mode   = HTTPD_CLIENT_FILE;
01499     cl->b_read_waiting = VLC_FALSE;
01500 
01501     httpd_MsgInit( &cl->query );
01502     httpd_MsgInit( &cl->answer );
01503 }
01504 
01505 void httpd_ClientModeStream( httpd_client_t *cl )
01506 {
01507     cl->i_mode   = HTTPD_CLIENT_STREAM;
01508 }
01509 
01510 void httpd_ClientModeBidir( httpd_client_t *cl )
01511 {
01512     cl->i_mode   = HTTPD_CLIENT_BIDIR;
01513 }
01514 
01515 char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip )
01516 {
01517     return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
01518 }
01519 
01520 char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip )
01521 {
01522     return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;
01523 }
01524 
01525 static void httpd_ClientClean( httpd_client_t *cl )
01526 {
01527     if( cl->fd >= 0 )
01528     {
01529         if( cl->p_tls != NULL )
01530             tls_ServerSessionClose( cl->p_tls );
01531         net_Close( cl->fd );
01532         cl->fd = -1;
01533     }
01534 
01535     httpd_MsgClean( &cl->answer );
01536     httpd_MsgClean( &cl->query );
01537 
01538     if( cl->p_buffer )
01539     {
01540         free( cl->p_buffer );
01541         cl->p_buffer = NULL;
01542     }
01543 }
01544 
01545 static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_storage *sock,
01546                                         int i_sock_size,
01547                                         tls_session_t *p_tls )
01548 {
01549     httpd_client_t *cl = malloc( sizeof( httpd_client_t ) );
01550     cl->i_ref   = 0;
01551     cl->fd      = fd;
01552     memcpy( &cl->sock, sock, sizeof( cl->sock ) );
01553     cl->i_sock_size = i_sock_size;
01554     cl->url     = NULL;
01555     cl->p_tls = p_tls;
01556 
01557     httpd_ClientInit( cl );
01558 
01559     return cl;
01560 }
01561 
01562 
01563 static int httpd_NetRecv( httpd_client_t *cl, uint8_t *p, int i_len )
01564 {
01565     tls_session_t *p_tls;
01566     
01567     p_tls = cl->p_tls;
01568     if( p_tls != NULL)
01569         return tls_Recv( p_tls, p, i_len );
01570 
01571     return recv( cl->fd, p, i_len, 0 );
01572 }
01573 
01574 
01575 static int httpd_NetSend( httpd_client_t *cl, const uint8_t *p, int i_len )
01576 {
01577     tls_session_t *p_tls;
01578 
01579     p_tls = cl->p_tls;
01580     if( p_tls != NULL)
01581         return tls_Send( p_tls, p, i_len );
01582 
01583     return send( cl->fd, p, i_len, 0 );
01584 }
01585 
01586 
01587 static void httpd_ClientRecv( httpd_client_t *cl )
01588 {
01589     int i_len;
01590 
01591     if( cl->query.i_proto == HTTPD_PROTO_NONE )
01592     {
01593         /* enough to see if it's rtp over rtsp or RTSP/HTTP */
01594         i_len = httpd_NetRecv( cl, &cl->p_buffer[cl->i_buffer],
01595                                4 - cl->i_buffer );
01596         if( i_len > 0 )
01597         {
01598             cl->i_buffer += i_len;
01599         }
01600 
01601         if( cl->i_buffer >= 4 )
01602         {
01603             /*fprintf( stderr, "peek=%4.4s\n", cl->p_buffer );*/
01604             /* detect type */
01605             if( cl->p_buffer[0] == '$' )
01606             {
01607                 /* RTSP (rtp over rtsp) */
01608                 cl->query.i_proto = HTTPD_PROTO_RTSP;
01609                 cl->query.i_type  = HTTPD_MSG_CHANNEL;
01610                 cl->query.i_channel = cl->p_buffer[1];
01611                 cl->query.i_body  = (cl->p_buffer[2] << 8)|cl->p_buffer[3];
01612                 cl->query.p_body  = malloc( cl->query.i_body );
01613 
01614                 cl->i_buffer      = 0;
01615             }
01616             else if( !memcmp( cl->p_buffer, "HTTP", 4 ) )
01617             {
01618                 cl->query.i_proto = HTTPD_PROTO_HTTP;
01619                 cl->query.i_type  = HTTPD_MSG_ANSWER;
01620             }
01621             else if( !memcmp( cl->p_buffer, "RTSP", 4 ) )
01622             {
01623                 cl->query.i_proto = HTTPD_PROTO_RTSP;
01624                 cl->query.i_type  = HTTPD_MSG_ANSWER;
01625             }
01626             else if( !memcmp( cl->p_buffer, "GET", 3 ) ||
01627                      !memcmp( cl->p_buffer, "HEAD", 4 ) ||
01628                      !memcmp( cl->p_buffer, "POST", 4 ) )
01629             {
01630                 cl->query.i_proto = HTTPD_PROTO_HTTP;
01631                 cl->query.i_type  = HTTPD_MSG_NONE;
01632             }
01633             else
01634             {
01635                 cl->query.i_proto = HTTPD_PROTO_RTSP;
01636                 cl->query.i_type  = HTTPD_MSG_NONE;
01637             }
01638         }
01639     }
01640     else if( cl->query.i_body > 0 )
01641     {
01642         /* we are reading the body of a request or a channel */
01643         i_len = httpd_NetRecv( cl, &cl->query.p_body[cl->i_buffer],
01644                                cl->query.i_body - cl->i_buffer );
01645         if( i_len > 0 )
01646         {
01647             cl->i_buffer += i_len;
01648         }
01649         if( cl->i_buffer >= cl->query.i_body )
01650         {
01651             cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01652         }
01653     }
01654     else
01655     {
01656         /* we are reading a header -> char by char */
01657         for( ;; )
01658         {
01659             i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1 );
01660             if( i_len <= 0 )
01661             {
01662                 break;
01663             }
01664             cl->i_buffer++;
01665 
01666             if( cl->i_buffer + 1 >= cl->i_buffer_size )
01667             {
01668                 cl->i_buffer_size += 1024;
01669                 cl->p_buffer = realloc( cl->p_buffer, cl->i_buffer_size );
01670             }
01671             if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )||
01672                 ( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) )
01673             {
01674                 char *p;
01675 
01676                 /* we have finished the header so parse it and set i_body */
01677                 cl->p_buffer[cl->i_buffer] = '\0';
01678 
01679                 if( cl->query.i_type == HTTPD_MSG_ANSWER )
01680                 {
01681                     /* FIXME:
01682                      * assume strlen( "HTTP/1.x" ) = 8
01683                      */
01684                     cl->query.i_status =
01685                         strtol( (char *)&cl->p_buffer[8],
01686                                 &p, 0 );
01687                     while( *p == ' ' )
01688                     {
01689                         p++;
01690                     }
01691                     cl->query.psz_status = strdup( p );
01692                 }
01693                 else
01694                 {
01695                     static const struct
01696                     {
01697                         char *name;
01698                         int  i_type;
01699                         int  i_proto;
01700                     }
01701                     msg_type[] =
01702                     {
01703                         { "GET",        HTTPD_MSG_GET,  HTTPD_PROTO_HTTP },
01704                         { "HEAD",       HTTPD_MSG_HEAD, HTTPD_PROTO_HTTP },
01705                         { "POST",       HTTPD_MSG_POST, HTTPD_PROTO_HTTP },
01706 
01707                         { "OPTIONS",    HTTPD_MSG_OPTIONS,  HTTPD_PROTO_RTSP },
01708                         { "DESCRIBE",   HTTPD_MSG_DESCRIBE, HTTPD_PROTO_RTSP },
01709                         { "SETUP",      HTTPD_MSG_SETUP,    HTTPD_PROTO_RTSP },
01710                         { "PLAY",       HTTPD_MSG_PLAY,     HTTPD_PROTO_RTSP },
01711                         { "PAUSE",      HTTPD_MSG_PAUSE,    HTTPD_PROTO_RTSP },
01712                         { "TEARDOWN",   HTTPD_MSG_TEARDOWN, HTTPD_PROTO_RTSP },
01713 
01714                         { NULL,         HTTPD_MSG_NONE,     HTTPD_PROTO_NONE }
01715                     };
01716                     int  i;
01717 
01718                     p = NULL;
01719                     cl->query.i_type = HTTPD_MSG_NONE;
01720 
01721                     /*fprintf( stderr, "received new request=%s\n", cl->p_buffer);*/
01722 
01723                     for( i = 0; msg_type[i].name != NULL; i++ )
01724                     {
01725                         if( !strncmp( (char *)cl->p_buffer, msg_type[i].name,
01726                                       strlen( msg_type[i].name ) ) )
01727                         {
01728                             p = (char *)&cl->p_buffer[strlen((char *)msg_type[i].name) + 1 ];
01729                             cl->query.i_type = msg_type[i].i_type;
01730                             if( cl->query.i_proto != msg_type[i].i_proto )
01731                             {
01732                                 p = NULL;
01733                                 cl->query.i_proto = HTTPD_PROTO_NONE;
01734                                 cl->query.i_type = HTTPD_MSG_NONE;
01735                             }
01736                             break;
01737                         }
01738                     }
01739                     if( p == NULL )
01740                     {
01741                         if( strstr( (char *)cl->p_buffer, "HTTP/1." ) )
01742                         {
01743                             cl->query.i_proto = HTTPD_PROTO_HTTP;
01744                         }
01745                         else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) )
01746                         {
01747                             cl->query.i_proto = HTTPD_PROTO_RTSP;
01748                         }
01749                     }
01750                     else
01751                     {
01752                         char *p2;
01753                         char *p3;
01754 
01755                         while( *p == ' ' )
01756                         {
01757                             p++;
01758                         }
01759                         p2 = strchr( p, ' ' );
01760                         if( p2 )
01761                         {
01762                             *p2++ = '\0';
01763                         }
01764                         if( !strncasecmp( p, "rtsp:", 5 ) )
01765                         {
01766                             /* for rtsp url, you have rtsp://localhost:port/path */
01767                             p += 5;
01768                             while( *p == '/' ) p++;
01769                             while( *p && *p != '/' ) p++;
01770                         }
01771                         cl->query.psz_url = strdup( p );
01772                         if( ( p3 = strchr( cl->query.psz_url, '?' ) )  )
01773                         {
01774                             *p3++ = '\0';
01775                             cl->query.psz_args = (uint8_t *)strdup( p3 );
01776                         }
01777                         if( p2 )
01778                         {
01779                             while( *p2 == ' ' )
01780                             {
01781                                 p2++;
01782                             }
01783                             if( !strncasecmp( p2, "HTTP/1.", 7 ) )
01784                             {
01785                                 cl->query.i_proto = HTTPD_PROTO_HTTP;
01786                                 cl->query.i_version = atoi( p2+7 );
01787                             }
01788                             else if( !strncasecmp( p2, "RTSP/1.", 7 ) )
01789                             {
01790                                 cl->query.i_proto = HTTPD_PROTO_RTSP;
01791                                 cl->query.i_version = atoi( p2+7 );
01792                             }
01793                         }
01794                         p = p2;
01795                     }
01796                 }
01797                 if( p )
01798                 {
01799                     p = strchr( p, '\n' );
01800                 }
01801                 if( p )
01802                 {
01803                     while( *p == '\n' || *p == '\r' )
01804                     {
01805                         p++;
01806                     }
01807                     while( p && *p != '\0' )
01808                     {
01809                         char *line = p;
01810                         char *eol = p = strchr( p, '\n' );
01811                         char *colon;
01812 
01813                         while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) )
01814                         {
01815                             *eol-- = '\0';
01816                         }
01817 
01818                         if( ( colon = strchr( line, ':' ) ) )
01819                         {
01820                             char *name;
01821                             char *value;
01822 
01823                             *colon++ = '\0';
01824                             while( *colon == ' ' )
01825                             {
01826                                 colon++;
01827                             }
01828                             name = strdup( line );
01829                             value = strdup( colon );
01830 
01831                             TAB_APPEND( cl->query.i_name, cl->query.name, name );
01832                             TAB_APPEND( cl->query.i_value,cl->query.value,value);
01833 
01834                             if( !strcasecmp( name, "Content-Length" ) )
01835                             {
01836                                 cl->query.i_body = atol( value );
01837                             }
01838                         }
01839 
01840                         if( p )
01841                         {
01842                             p++;
01843                             while( *p == '\n' || *p == '\r' )
01844                             {
01845                                 p++;
01846                             }
01847                         }
01848                     }
01849                 }
01850                 if( cl->query.i_body > 0 )
01851                 {
01852                     /* TODO Mhh, handle the case client will only send a request and close the connection
01853                      * to mark and of body (probably only RTSP) */
01854                     cl->query.p_body = malloc( cl->query.i_body );
01855                     cl->i_buffer = 0;
01856                 }
01857                 else
01858                 {
01859                     cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01860                 }
01861             }
01862         }
01863     }
01864 
01865     /* check if the client is to be set to dead */
01866 #if defined( WIN32 ) || defined( UNDER_CE )
01867     if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
01868 #else
01869     if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
01870 #endif
01871     {
01872         if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE )
01873         {
01874             /* connection closed -> end of data */
01875             if( cl->query.i_body > 0 )
01876             {
01877                 cl->query.i_body = cl->i_buffer;
01878             }
01879             cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
01880         }
01881         else
01882         {
01883             cl->i_state = HTTPD_CLIENT_DEAD;
01884         }
01885     }
01886     cl->i_activity_date = mdate();
01887 
01888     /* XXX: for QT I have to disable timeout. Try to find why */
01889     if( cl->query.i_proto == HTTPD_PROTO_RTSP )
01890         cl->i_activity_timeout = 0;
01891 
01892     /* Debugging only */
01893     /*if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
01894     {
01895         int i;
01896 
01897         fprintf( stderr, "received new request\n" );
01898         fprintf( stderr, "  - proto=%s\n",
01899                  cl->query.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP" );
01900         fprintf( stderr, "  - version=%d\n", cl->query.i_version );
01901         fprintf( stderr, "  - msg=%d\n", cl->query.i_type );
01902         if( cl->query.i_type == HTTPD_MSG_ANSWER )
01903         {
01904             fprintf( stderr, "  - answer=%d '%s'\n", cl->query.i_status,
01905                      cl->query.psz_status );
01906         }
01907         else if( cl->query.i_type != HTTPD_MSG_NONE )
01908         {
01909             fprintf( stderr, "  - url=%s\n", cl->query.psz_url );
01910         }
01911         for( i = 0; i < cl->query.i_name; i++ )
01912         {
01913             fprintf( stderr, "  - option name='%s' value='%s'\n",
01914                      cl->query.name[i], cl->query.value[i] );
01915         }
01916     }*/
01917 }
01918 
01919 
01920 static void httpd_ClientSend( httpd_client_t *cl )
01921 {
01922     int i;
01923     int i_len;
01924 
01925     if( cl->i_buffer < 0 )
01926     {
01927         /* We need to create the header */
01928         int i_size = 0;
01929         char *p;
01930 
01931         i_size = strlen( "HTTP/1.") + 10 + 10 +
01932                  strlen( cl->answer.psz_status ? cl->answer.psz_status : "" ) + 5;
01933         for( i = 0; i < cl->answer.i_name; i++ )
01934         {
01935             i_size += strlen( cl->answer.name[i] ) + 2 +
01936                       strlen( cl->answer.value[i] ) + 2;
01937         }
01938 
01939         if( cl->i_buffer_size < i_size )
01940         {
01941             cl->i_buffer_size = i_size;
01942             free( cl->p_buffer );
01943             cl->p_buffer = malloc( i_size );
01944         }
01945         p = (char *)cl->p_buffer;
01946 
01947         p += sprintf( p, "%s/1.%d %d %s\r\n",
01948                       cl->answer.i_proto ==  HTTPD_PROTO_HTTP ? "HTTP" : "RTSP",
01949                       cl->answer.i_version,
01950                       cl->answer.i_status, cl->answer.psz_status );
01951         for( i = 0; i < cl->answer.i_name; i++ )
01952         {
01953             p += sprintf( p, "%s: %s\r\n", cl->answer.name[i],
01954                           cl->answer.value[i] );
01955         }
01956         p += sprintf( p, "\r\n" );
01957 
01958         cl->i_buffer = 0;
01959         cl->i_buffer_size = (uint8_t*)p - cl->p_buffer;
01960 
01961         /*fprintf( stderr, "sending answer\n" );
01962         fprintf( stderr, "%s",  cl->p_buffer );*/
01963     }
01964 
01965     i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer],
01966                            cl->i_buffer_size - cl->i_buffer );
01967     if( i_len >= 0 )
01968     {
01969         cl->i_activity_date = mdate();
01970         cl->i_buffer += i_len;
01971 
01972         if( cl->i_buffer >= cl->i_buffer_size )
01973         {
01974             if( cl->answer.i_body == 0  && cl->answer.i_body_offset > 0 &&
01975                 !cl->b_read_waiting )
01976             {
01977                 /* catch more body data */
01978                 int     i_msg = cl->query.i_type;
01979                 int64_t i_offset = cl->answer.i_body_offset;
01980 
01981                 httpd_MsgClean( &cl->answer );
01982                 cl->answer.i_body_offset = i_offset;
01983 
01984                 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
01985                                           &cl->answer, &cl->query );
01986             }
01987 
01988             if( cl->answer.i_body > 0 )
01989             {
01990                 /* send the body data */
01991                 free( cl->p_buffer );
01992                 cl->p_buffer = cl->answer.p_body;
01993                 cl->i_buffer_size = cl->answer.i_body;
01994                 cl->i_buffer = 0;
01995 
01996                 cl->answer.i_body = 0;
01997                 cl->answer.p_body = NULL;
01998             }
01999             else
02000             {
02001                 /* send finished */
02002                 cl->i_state = HTTPD_CLIENT_SEND_DONE;
02003             }
02004         }
02005     }
02006     else
02007     {
02008 #if defined( WIN32 ) || defined( UNDER_CE )
02009         if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
02010 #else
02011         if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
02012 #endif
02013         {
02014             /* error */
02015             cl->i_state = HTTPD_CLIENT_DEAD;
02016         }
02017     }
02018 }
02019 
02020 static void httpd_ClientTlsHsIn( httpd_client_t *cl )
02021 {
02022     switch( tls_SessionContinueHandshake( cl->p_tls ) )
02023     {
02024         case 0:
02025             cl->i_state = HTTPD_CLIENT_RECEIVING;
02026             break;
02027 
02028         case -1:
02029             cl->i_state = HTTPD_CLIENT_DEAD;
02030             cl->p_tls = NULL;
02031             break;
02032 
02033         case 2:
02034             cl->i_state = HTTPD_CLIENT_TLS_HS_OUT;
02035     }
02036 }
02037 
02038 static void httpd_ClientTlsHsOut( httpd_client_t *cl )
02039 {
02040     switch( tls_SessionContinueHandshake( cl->p_tls ) )
02041     {
02042         case 0:
02043             cl->i_state = HTTPD_CLIENT_RECEIVING;
02044             break;
02045 
02046         case -1:
02047             cl->i_state = HTTPD_CLIENT_DEAD;
02048             cl->p_tls = NULL;
02049             break;
02050 
02051         case 1:
02052             cl->i_state = HTTPD_CLIENT_TLS_HS_IN;
02053             break;
02054     }
02055 }
02056 
02057 static void httpd_HostThread( httpd_host_t *host )
02058 {
02059     tls_session_t *p_tls = NULL;
02060 
02061     while( !host->b_die )
02062     {
02063         struct timeval  timeout;
02064         fd_set          fds_read;
02065         fd_set          fds_write;
02066         /* FIXME: (too) many int variables */
02067         int             fd, i_fd;
02068         int             i_handle_max = 0;
02069         int             i_ret;
02070         int             i_client;
02071         int             b_low_delay = 0;
02072 
02073         if( host->i_url <= 0 )
02074         {
02075             /* 0.2s */
02076             msleep( 200000 );
02077             continue;
02078         }
02079 
02080         /* built a set of handle to select */
02081         FD_ZERO( &fds_read );
02082         FD_ZERO( &fds_write );
02083 
02084         i_handle_max = -1;
02085 
02086         for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ )
02087         {
02088             FD_SET( fd, &fds_read );
02089             if( fd > i_handle_max )
02090                 i_handle_max = fd;
02091         }
02092 
02093         /* prepare a new TLS session */
02094         if( ( p_tls == NULL ) && ( host->p_tls != NULL ) )
02095             p_tls = tls_ServerSessionPrepare( host->p_tls );
02096 
02097         /* add all socket that should be read/write and close dead connection */
02098         vlc_mutex_lock( &host->lock );
02099         for( i_client = 0; i_client < host->i_client; i_client++ )
02100         {
02101             httpd_client_t *cl = host->client[i_client];
02102 
02103             if( cl->i_ref < 0 || ( cl->i_ref == 0 &&
02104                 ( cl->i_state == HTTPD_CLIENT_DEAD ||
02105                   ( cl->i_activity_timeout > 0 &&
02106                     cl->i_activity_date+cl->i_activity_timeout < mdate()) ) ) )
02107             {
02108                 httpd_ClientClean( cl );
02109                 TAB_REMOVE( host->i_client, host->client, cl );
02110                 free( cl );
02111                 i_client--;
02112                 continue;
02113             }
02114             else if( ( cl->i_state == HTTPD_CLIENT_RECEIVING )
02115                   || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) )
02116             {
02117                 FD_SET( cl->fd, &fds_read );
02118                 i_handle_max = __MAX( i_handle_max, cl->fd );
02119             }
02120             else if( ( cl->i_state == HTTPD_CLIENT_SENDING )
02121                   || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) )
02122             {
02123                 FD_SET( cl->fd, &fds_write );
02124                 i_handle_max = __MAX( i_handle_max, cl->fd );
02125             }
02126             else if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
02127             {
02128                 httpd_message_t *answer = &cl->answer;
02129                 httpd_message_t *query  = &cl->query;
02130                 int i_msg = query->i_type;
02131 
02132                 httpd_MsgInit( answer );
02133 
02134                 /* Handle what we received */
02135                 if( cl->i_mode != HTTPD_CLIENT_BIDIR &&
02136                     (i_msg == HTTPD_MSG_ANSWER || i_msg == HTTPD_MSG_CHANNEL) )
02137                 {
02138                     /* we can only receive request from client when not
02139                      * in BIDIR mode */
02140                     cl->url     = NULL;
02141                     cl->i_state = HTTPD_CLIENT_DEAD;
02142                 }
02143                 else if( i_msg == HTTPD_MSG_ANSWER )
02144                 {
02145                     /* We are in BIDIR mode, trigger the callback and then
02146                      * check for new data */
02147                     if( cl->url && cl->url->catch[i_msg].cb )
02148                     {
02149                         cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
02150                                                   cl, NULL, query );
02151                     }
02152                     cl->i_state = HTTPD_CLIENT_WAITING;
02153                 }
02154                 else if( i_msg == HTTPD_MSG_CHANNEL )
02155                 {
02156                     /* We are in BIDIR mode, trigger the callback and then
02157                      * check for new data */
02158                     if( cl->url && cl->url->catch[i_msg].cb )
02159                     {
02160                         cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys,
02161                                                   cl, NULL, query );
02162                     }
02163                     cl->i_state = HTTPD_CLIENT_WAITING;
02164                 }
02165                 else if( i_msg == HTTPD_MSG_OPTIONS )
02166                 {
02167                     int i_cseq;
02168 
02169                     /* unimplemented */
02170                     answer->i_proto  = query->i_proto ;
02171                     answer->i_type   = HTTPD_MSG_ANSWER;
02172                     answer->i_version= 0;
02173                     answer->i_status = 200;
02174                     answer->psz_status = strdup( "Ok" );
02175 
02176                     answer->i_body = 0;
02177                     answer->p_body = NULL;
02178 
02179                     i_cseq = atoi( httpd_MsgGet( query, "Cseq" ) );
02180                     httpd_MsgAdd( answer, "Cseq", "%d", i_cseq );
02181                     httpd_MsgAdd( answer, "Server", "VLC Server" );
02182                     httpd_MsgAdd( answer, "Public", "DESCRIBE, SETUP, "
02183                                  "TEARDOWN, PLAY, PAUSE" );
02184                     httpd_MsgAdd( answer, "Content-Length", "%d",
02185                                   answer->i_body );
02186 
02187                     cl->i_buffer = -1;  /* Force the creation of the answer in
02188                                          * httpd_ClientSend */
02189                     cl->i_state = HTTPD_CLIENT_SENDING;
02190                 }
02191                 else if( i_msg == HTTPD_MSG_NONE )
02192                 {
02193                     if( query->i_proto == HTTPD_PROTO_NONE )
02194                     {
02195                         cl->url = NULL;
02196                         cl->i_state = HTTPD_CLIENT_DEAD;
02197                     }
02198                     else
02199                     {
02200                         uint8_t *p;
02201 
02202                         /* unimplemented */
02203                         answer->i_proto  = query->i_proto ;
02204                         answer->i_type   = HTTPD_MSG_ANSWER;
02205                         answer->i_version= 0;
02206                         answer->i_status = 501;
02207                         answer->psz_status = strdup( "Unimplemented" );
02208 
02209                         p = answer->p_body = malloc( 1000 );
02210 
02211                         p += sprintf( (char *)p,
02212                             "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02213                             "<!DOCTYPE html PUBLIC \"-//W3C//DTD  XHTML 1.0 Strict//EN\" "
02214                             "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02215                             "<html>\n"
02216                             "<head>\n"
02217                             "<title>Error 501</title>\n"
02218                             "</head>\n"
02219                             "<body>\n"
02220                             "<h1>501 Unimplemented</h1>\n"
02221                             "<hr />\n"
02222                             "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02223                             "</body>\n"
02224                             "</html>\n" );
02225 
02226                         answer->i_body = p - answer->p_body;
02227                         httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
02228 
02229                         cl->i_buffer = -1;  /* Force the creation of the answer in httpd_ClientSend */
02230                         cl->i_state = HTTPD_CLIENT_SENDING;
02231                     }
02232                 }
02233                 else
02234                 {
02235                     vlc_bool_t b_auth_failed = VLC_FALSE;
02236                     vlc_bool_t b_hosts_failed = VLC_FALSE;
02237                     int i;
02238 
02239                     /* Search the url and trigger callbacks */
02240                     for( i = 0; i < host->i_url; i++ )
02241                     {
02242                         httpd_url_t *url = host->url[i];
02243 
02244                         if( !strcmp( url->psz_url, query->psz_url ) )
02245                         {
02246                             if( url->catch[i_msg].cb )
02247                             {
02248                                 if( answer && ( url->p_acl != NULL ) )
02249                                 {
02250                                     char ip[NI_MAXNUMERICHOST];
02251 
02252                                     if( httpd_ClientIP( cl, ip ) != NULL )
02253                                     {
02254                                         if( ACL_Check( url->p_acl, ip ) )
02255                                         {
02256                                             b_hosts_failed = VLC_TRUE;
02257                                             break;
02258                                         }
02259                                     }
02260                                     else
02261                                         b_hosts_failed = VLC_TRUE;
02262                                 }
02263 
02264                                 if( answer && ( *url->psz_user || *url->psz_password ) )
02265                                 {
02266                                     /* create the headers */
02267                                     char *b64 = httpd_MsgGet( query, "Authorization" ); /* BASIC id */
02268                                     char *auth;
02269                                     char *id;
02270 
02271                                     asprintf( &id, "%s:%s", url->psz_user, url->psz_password );
02272                                     auth = malloc( strlen(b64) + 1 );
02273 
02274                                     if( !strncasecmp( b64, "BASIC", 5 ) )
02275                                     {
02276                                         b64 += 5;
02277                                         while( *b64 == ' ' )
02278                                         {
02279                                             b64++;
02280                                         }
02281                                         b64_decode( auth, b64 );
02282                                     }
02283                                     else
02284                                     {
02285                                         strcpy( auth, "" );
02286                                     }
02287                                     if( strcmp( id, auth ) )
02288                                     {
02289                                         httpd_MsgAdd( answer, "WWW-Authenticate", "Basic realm=\"%s\"", url->psz_user );
02290                                         /* We fail for all url */
02291                                         b_auth_failed = VLC_TRUE;
02292                                         free( id );
02293                                         free( auth );
02294                                         break;
02295                                     }
02296 
02297                                     free( id );
02298                                     free( auth );
02299                                 }
02300 
02301                                 if( !url->catch[i_msg].cb( url->catch[i_msg].p_sys, cl, answer, query ) )
02302                                 {
02303                                     if( answer->i_proto == HTTPD_PROTO_NONE )
02304                                     {
02305                                         /* Raw answer from a CGI */
02306                                         cl->i_buffer = cl->i_buffer_size;
02307                                     }
02308                                     else
02309                                         cl->i_buffer = -1;
02310 
02311                                     /* only one url can answer */
02312                                     answer = NULL;
02313                                     if( cl->url == NULL )
02314                                     {
02315                                         cl->url = url;
02316                                     }
02317                                 }
02318                             }
02319                         }
02320                     }
02321                     if( answer )
02322                     {
02323                         uint8_t *p;
02324 
02325                         answer->i_proto  = query->i_proto;
02326                         answer->i_type   = HTTPD_MSG_ANSWER;
02327                         answer->i_version= 0;
02328                         p = answer->p_body = malloc( 1000 + strlen(query->psz_url) );
02329 
02330                         if( b_hosts_failed )
02331                         {
02332                             answer->i_status = 403;
02333                             answer->psz_status = strdup( "Forbidden" );
02334 
02335                             /* FIXME: lots of code duplication */
02336                             p += sprintf( (char *)p,
02337                                 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02338                                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD  XHTML 1.0 Strict//EN\" "
02339                                 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02340                                 "<html>\n"
02341                                 "<head>\n"
02342                                 "<title>Error 403</title>\n"
02343                                 "</head>\n"
02344                                 "<body>\n"
02345                                 "<h1>403 Forbidden (%s)</h1>\n"
02346                                 "<hr />\n"
02347                                 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02348                                 "</body>\n"
02349                                 "</html>\n", query->psz_url );
02350                         }
02351                         else if( b_auth_failed )
02352                         {
02353                             answer->i_status = 401;
02354                             answer->psz_status = strdup( "Authorization Required" );
02355 
02356                             p += sprintf( (char *)p,
02357                                 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02358                                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD  XHTML 1.0 Strict//EN\" "
02359                                 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02360                                 "<html>\n"
02361                                 "<head>\n"
02362                                 "<title>Error 401</title>\n"
02363                                 "</head>\n"
02364                                 "<body>\n"
02365                                 "<h1>401 Authorization Required (%s)</h1>\n"
02366                                 "<hr />\n"
02367                                 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02368                                 "</body>\n"
02369                                 "</html>\n", query->psz_url );
02370                         }
02371                         else
02372                         {
02373                             /* no url registered */
02374                             answer->i_status = 404;
02375                             answer->psz_status = strdup( "Not found" );
02376 
02377                             p += sprintf( (char *)p,
02378                                 "<?xml version=\"1.0\" encoding=\"ascii\" ?>"
02379                                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD  XHTML 1.0 Strict//EN\" "
02380                                 "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n"
02381                                 "<html>\n"
02382                                 "<head>\n"
02383                                 "<title>Error 404</title>\n"
02384                                 "</head>\n"
02385                                 "<body>\n"
02386                                 "<h1>404 Resource not found(%s)</h1>\n"
02387                                 "<hr />\n"
02388                                 "<a href=\"http://www.videolan.org\">VideoLAN</a>\n"
02389                                 "</body>\n"
02390                                 "</html>\n", query->psz_url );
02391                         }
02392 
02393                         answer->i_body = p - answer->p_body;
02394                         cl->i_buffer = -1;  /* Force the creation of the answer in httpd_ClientSend */
02395                         httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
02396                     }
02397 
02398                     cl->i_state = HTTPD_CLIENT_SENDING;
02399                 }
02400             }
02401             else if( cl->i_state == HTTPD_CLIENT_SEND_DONE )
02402             {
02403                 if( cl->i_mode == HTTPD_CLIENT_FILE || cl->answer.i_body_offset == 0 )
02404                 {
02405                     cl->url = NULL;
02406                     if( ( cl->query.i_proto == HTTPD_PROTO_HTTP &&
02407                           ( ( cl->answer.i_version == 0 && !strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Keep-Alive" ) ) ||
02408                             ( cl->answer.i_version == 1 &&  strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Close" ) ) ) ) ||
02409                         ( cl->query.i_proto == HTTPD_PROTO_RTSP &&
02410                           strcasecmp( httpd_MsgGet( &cl->query, "Connection" ), "Close" ) &&
02411                           strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Close" ) ) )
02412                     {
02413                         httpd_MsgClean( &cl->query );
02414                         httpd_MsgInit( &cl->query );
02415 
02416                         cl->i_buffer = 0;
02417                         cl->i_buffer_size = 1000;
02418                         free( cl->p_buffer );
02419                         cl->p_buffer = malloc( cl->i_buffer_size );
02420                         cl->i_state = HTTPD_CLIENT_RECEIVING;
02421                     }
02422                     else
02423                     {
02424                         cl->i_state = HTTPD_CLIENT_DEAD;
02425                     }
02426                     httpd_MsgClean( &cl->answer );
02427                 }
02428                 else if( cl->b_read_waiting )
02429                 {
02430                     /* we have a message waiting for us to read it */
02431                     httpd_MsgClean( &cl->answer );
02432                     httpd_MsgClean( &cl->query );
02433 
02434                     cl->i_buffer = 0;
02435                     cl->i_buffer_size = 1000;
02436                     free( cl->p_buffer );
02437                     cl->p_buffer = malloc( cl->i_buffer_size );
02438                     cl->i_state = HTTPD_CLIENT_RECEIVING;
02439                     cl->b_read_waiting = VLC_FALSE;
02440                 }
02441                 else
02442                 {
02443                     int64_t i_offset = cl->answer.i_body_offset;
02444                     httpd_MsgClean( &cl->answer );
02445 
02446                     cl->answer.i_body_offset = i_offset;
02447                     free( cl->p_buffer );
02448                     cl->p_buffer = NULL;
02449                     cl->i_buffer = 0;
02450                     cl->i_buffer_size = 0;
02451 
02452                     cl->i_state = HTTPD_CLIENT_WAITING;
02453                 }
02454             }
02455             else if( cl->i_state == HTTPD_CLIENT_WAITING )
02456             {
02457                 int64_t i_offset = cl->answer.i_body_offset;
02458                 int     i_msg = cl->query.i_type;
02459 
02460                 httpd_MsgInit( &cl->answer );
02461                 cl->answer.i_body_offset = i_offset;
02462 
02463                 cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
02464                                           &cl->answer, &cl->query );
02465                 if( cl->answer.i_type != HTTPD_MSG_NONE )
02466                 {
02467                     /* we have new data, so reenter send mode */
02468                     cl->i_buffer      = 0;
02469                     cl->p_buffer      = cl->answer.p_body;
02470                     cl->i_buffer_size = cl->answer.i_body;
02471                     cl->answer.p_body = NULL;
02472                     cl->answer.i_body = 0;
02473                     cl->i_state = HTTPD_CLIENT_SENDING;
02474                 }
02475                 else
02476                 {
02477                     /* we shouldn't wait too long */
02478                     b_low_delay = VLC_TRUE;
02479                 }
02480             }
02481 
02482             /* Special for BIDIR mode we also check reading */
02483             if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
02484                 cl->i_state == HTTPD_CLIENT_SENDING )
02485             {
02486                 FD_SET( cl->fd, &fds_read );
02487                 i_handle_max = __MAX( i_handle_max, cl->fd );
02488             }
02489         }
02490         vlc_mutex_unlock( &host->lock );
02491 
02492         /* we will wait 100ms or 20ms (not too big 'cause HTTPD_CLIENT_WAITING) */
02493         timeout.tv_sec = 0;
02494         timeout.tv_usec = b_low_delay ? 20000 : 100000;
02495 
02496         i_ret = select( i_handle_max + 1,
02497                         &fds_read, &fds_write, NULL, &timeout );
02498 
02499         if( i_ret == -1 && errno != EINTR )
02500         {
02501 #if defined(WIN32) || defined(UNDER_CE)
02502             msg_Warn( host, "cannot select sockets (%d)", WSAGetLastError( ) );
02503 #else
02504             msg_Warn( host, "cannot select sockets : %s", strerror( errno ) );
02505 #endif
02506             msleep( 1000 );
02507             continue;
02508         }
02509         else if( i_ret <= 0 )
02510         {
02511             continue;
02512         }
02513 
02514         /* accept new connections */
02515         for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ )
02516         {
02517             if( FD_ISSET( fd, &fds_read ) )
02518             {
02519                 socklen_t i_sock_size = sizeof( struct sockaddr_storage );
02520                 struct  sockaddr_storage sock;
02521     
02522                 fd = accept( fd, (struct sockaddr *)&sock, &i_sock_size );
02523                 if( fd >= 0 )
02524                 {
02525                     int i_state = 0;
02526     
02527                     /* set this new socket non-block */
02528     #if defined( WIN32 ) || defined( UNDER_CE )
02529                     {
02530                         unsigned long i_dummy = 1;
02531                         ioctlsocket( fd, FIONBIO, &i_dummy );
02532                     }
02533     #else
02534                     fcntl( fd, F_SETFL, O_NONBLOCK );
02535     #endif
02536     
02537                     if( p_tls != NULL)
02538                     {
02539                         switch ( tls_ServerSessionHandshake( p_tls, fd ) )
02540                         {
02541                             case -1:
02542                                 msg_Err( host, "Rejecting TLS connection" );
02543                                 net_Close( fd );
02544                                 fd = -1;
02545                                 p_tls = NULL;
02546                                 break;
02547     
02548                             case 1: /* missing input - most likely */
02549                                 i_state = HTTPD_CLIENT_TLS_HS_IN;
02550                                 break;
02551     
02552                             case 2: /* missing output */
02553                                 i_state = HTTPD_CLIENT_TLS_HS_OUT;
02554                                 break;
02555                         }
02556                     }
02557                     
02558                     if( fd >= 0 )
02559                     {
02560                         httpd_client_t *cl;
02561     
02562                         cl = httpd_ClientNew( fd, &sock, i_sock_size, p_tls );
02563                         p_tls = NULL;
02564                         vlc_mutex_lock( &host->lock );
02565                         TAB_APPEND( host->i_client, host->client, cl );
02566                         vlc_mutex_unlock( &host->lock );
02567     
02568                         if( i_state != 0 )
02569                             cl->i_state = i_state; // override state for TLS
02570                     }
02571                 }
02572             }
02573         }
02574 
02575         /* now try all others socket */
02576         vlc_mutex_lock( &host->lock );
02577         for( i_client = 0; i_client < host->i_client; i_client++ )
02578         {
02579             httpd_client_t *cl = host->client[i_client];
02580             if( cl->i_state == HTTPD_CLIENT_RECEIVING )
02581             {
02582                 httpd_ClientRecv( cl );
02583             }
02584             else if( cl->i_state == HTTPD_CLIENT_SENDING )
02585             {
02586                 httpd_ClientSend( cl );
02587             }
02588             else if( cl->i_state == HTTPD_CLIENT_TLS_HS_IN )
02589             {
02590                 httpd_ClientTlsHsIn( cl );
02591             }
02592             else if( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT )
02593             {
02594                 httpd_ClientTlsHsOut( cl );
02595             }
02596 
02597             if( cl->i_mode == HTTPD_CLIENT_BIDIR &&
02598                 cl->i_state == HTTPD_CLIENT_SENDING &&
02599                 FD_ISSET( cl->fd, &fds_read ) )
02600             {
02601                 cl->b_read_waiting = VLC_TRUE;
02602             }
02603         }
02604         vlc_mutex_unlock( &host->lock );
02605     }
02606 
02607     if( p_tls != NULL )
02608         tls_ServerSessionClose( p_tls );
02609 }
02610 
02611 #else /* ENABLE_HTTPD */
02612 
02613 /* We just define an empty wrapper */
02614 httpd_host_t *httpd_TLSHostNew( vlc_object_t *a, char *b, int c,
02615                                 tls_server_t *d )
02616 {
02617     msg_Err( a, "HTTP daemon support is disabled" );
02618     return 0;
02619 }
02620 httpd_host_t *httpd_HostNew( vlc_object_t *a, char *b, int c )
02621 {
02622     msg_Err( a, "HTTP daemon support is disabled" );
02623     return 0;
02624 }
02625 void httpd_HostDelete( httpd_host_t *a )
02626 {
02627 }
02628 httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url,
02629                            char *psz_user, char *psz_password,
02630                            const vlc_acl_t *p_acl )
02631 {
02632     return NULL;
02633 }
02634 httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url,
02635                                  char *psz_user, char *psz_password,
02636                                  const vlc_acl_t *p_acl )
02637 {
02638     return NULL;
02639 }
02640 int httpd_UrlCatch( httpd_url_t *a, int b, httpd_callback_t c,
02641                     httpd_callback_sys_t *d ){ return 0; }
02642 void httpd_UrlDelete( httpd_url_t *a ){}
02643 
02644 char* httpd_ClientIP( httpd_client_t *cl, char *psz_ip ) { return NULL; }
02645 char* httpd_ServerIP( httpd_client_t *cl, char *psz_ip ) { return NULL; }
02646 
02647 void httpd_ClientModeStream( httpd_client_t *a ){}
02648 void httpd_ClientModeBidir( httpd_client_t *a ){}
02649 
02650 void httpd_FileDelete( httpd_file_t *a ){}
02651 httpd_file_t *httpd_FileNew( httpd_host_t *a, char *b, char *c, char *d,
02652                              char *e, httpd_file_callback_t f,
02653                              httpd_file_sys_t *g ){ return 0; }
02654 
02655 httpd_handler_t *httpd_HandlerNew( httpd_host_t *host, const char *psz_url,
02656                                    const char *psz_user,
02657                                    const char *psz_password,
02658                                    const vlc_acl_t *p_acl,
02659                                    httpd_handler_callback_t pf_fill,
02660                                    httpd_handler_sys_t *p_sys )
02661 {
02662     return NULL;
02663 }
02664 void httpd_HandlerDelete( httpd_handler_t *handler ) {}
02665 
02666 void httpd_RedirectDelete( httpd_redirect_t *a ){}
02667 httpd_redirect_t *httpd_RedirectNew( httpd_host_t *a,
02668                                      char *b, char *c ){ return 0; }
02669 
02670 void httpd_StreamDelete( httpd_stream_t *a ){}
02671 int  httpd_StreamHeader( httpd_stream_t *a, uint8_t *b, int c ){ return 0; }
02672 int  httpd_StreamSend  ( httpd_stream_t *a, uint8_t *b, int c ){ return 0; }
02673 httpd_stream_t *httpd_StreamNew( httpd_host_t *a, char *b, char *c,
02674                                  char *d, char *e ){ return 0; }
02675 
02676 void httpd_MsgInit ( httpd_message_t *a ){}
02677 void httpd_MsgAdd  ( httpd_message_t *a, char *b, char *c, ... ){}
02678 char *httpd_MsgGet ( httpd_message_t *a, char *b ){ return 0; }
02679 void httpd_MsgClean( httpd_message_t *a ){}
02680 
02681 #endif /* ENABLE_HTTPD */

Generated on Tue Dec 20 10:15:00 2005 for vlc-0.8.4a by  doxygen 1.4.2