]> git.sesse.net Git - vlc/commitdiff
* include/httpd.h, modules/misc/httpd.c: remove old http daemon.
authorLaurent Aimar <fenrir@videolan.org>
Wed, 3 Mar 2004 13:23:47 +0000 (13:23 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Wed, 3 Mar 2004 13:23:47 +0000 (13:23 +0000)
 * include/vlc_httpd.h src/misc/httpd.c: added new http daemon,
 it will allow http 1.1, redirection, RTSP, ...

include/httpd.h [deleted file]
include/vlc_httpd.h [new file with mode: 0644]
modules/misc/httpd.c [deleted file]
src/misc/httpd.c [new file with mode: 0644]

diff --git a/include/httpd.h b/include/httpd.h
deleted file mode 100644 (file)
index 6d04a8d..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/*****************************************************************************
- * httpd.h
- *****************************************************************************
- * Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.h,v 1.7 2003/07/11 09:50:10 gbazin Exp $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-typedef struct httpd_host_t     httpd_host_t;
-
-typedef struct httpd_file_t     httpd_file_t;
-//typedef struct httpd_stream_t   httpd_stream_t;
-typedef httpd_file_t httpd_stream_t;
-
-typedef struct httpd_file_callback_args_t httpd_file_callback_args_t;
-typedef int (*httpd_file_callback)( httpd_file_callback_args_t *p_args,
-    uint8_t *p_request, int i_request, uint8_t **pp_data, int *pi_data );
-
-typedef struct httpd_sys_t httpd_sys_t;
-
-enum httpdControl_e
-{
-    HTTPD_GET_HOSTS,
-    HTTPD_GET_URLS,
-    HTTPD_GET_CONNECTIONS,
-    HTTPD_GET_ACL,          /* not implemented */
-
-    HTTPD_SET_CLOSE,
-    HTTPD_SET_ACL           /* not implemented */
-};
-
-typedef struct
-{
-    char *psz_name;
-    char *psz_value;
-} httpd_val_t;
-
-typedef struct
-{
-    int         i_count;
-    httpd_val_t *info;
-} httpd_info_t;
-
-
-typedef struct httpd_t httpd_t;
-
-struct httpd_t
-{
-    VLC_COMMON_MEMBERS
-
-    module_t        *p_module;
-    httpd_sys_t     *p_sys;
-
-    httpd_host_t   *(*pf_register_host)     ( httpd_t *, char *, int );
-    void            (*pf_unregister_host)   ( httpd_t *, httpd_host_t * );
-
-    httpd_file_t   *(*pf_register_file)     ( httpd_t *,
-                                              char *psz_file, char *psz_mime,
-                                              char *psz_user, char *psz_password,
-                                              httpd_file_callback pf_get,
-                                              httpd_file_callback pf_post,
-                                              httpd_file_callback_args_t *p_args );
-    void            (*pf_unregister_file)   ( httpd_t *, httpd_file_t * );
-
-    httpd_stream_t *(*pf_register_stream)   ( httpd_t *,
-                                              char *psz_file, char *psz_mime,
-                                              char *psz_user, char *psz_password );
-    int             (*pf_send_stream)       ( httpd_t *,
-                                              httpd_stream_t *,
-                                              uint8_t *, int );
-    int             (*pf_header_stream)     ( httpd_t *,
-                                              httpd_stream_t *,
-                                              uint8_t *, int );
-    void            (*pf_unregister_stream) ( httpd_t *, httpd_stream_t * );
-    int             (*pf_control)           ( httpd_t *,
-                                              int i_query,
-                                              void *arg1, void *arg2 );
-};
-
-
-/*****************************************************************************
- * httpd_Find:
- *  Return the running httpd instance (if none and b_create then a new one is created)
- * httpd_release:
- *****************************************************************************/
-
-static inline httpd_t* httpd_Find( vlc_object_t *p_this, vlc_bool_t b_create )
-{
-    httpd_t *p_httpd = NULL;
-    vlc_value_t lockval;
-
-    var_Get( p_this->p_libvlc, "httpd", &lockval );
-    vlc_mutex_lock( lockval.p_address );
-
-    p_httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE );
-    if( !p_httpd && b_create)
-    {
-        msg_Info(p_this, "creating new http daemon" );
-
-        p_httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD );
-        if( !p_httpd )
-        {
-            msg_Err( p_this, "out of memory" );
-            vlc_mutex_unlock( lockval.p_address );
-            return( NULL );
-        }
-
-        p_httpd->p_module = module_Need( p_httpd, "httpd", "" );
-
-        if( !p_httpd->p_module )
-        {
-            msg_Err( p_this, "no suitable httpd module" );
-            vlc_object_destroy( p_httpd );
-            vlc_mutex_unlock( lockval.p_address );
-            return( NULL );
-        }
-
-        vlc_object_yield( p_httpd );
-        vlc_object_attach( p_httpd, p_this->p_vlc );
-    }
-    vlc_mutex_unlock( lockval.p_address );
-
-    return( p_httpd );
-}
-
-static inline void  httpd_Release( httpd_t *p_httpd )
-{
-    vlc_object_release( p_httpd );
-
-    if( p_httpd->i_refcount <= 0 )
-    {
-        msg_Info( p_httpd, "destroying unused httpd" );
-        vlc_object_detach( p_httpd );
-        module_Unneed( p_httpd, p_httpd->p_module );
-        vlc_object_destroy( p_httpd );
-    }
-}
diff --git a/include/vlc_httpd.h b/include/vlc_httpd.h
new file mode 100644 (file)
index 0000000..cd95b7f
--- /dev/null
@@ -0,0 +1,154 @@
+/*****************************************************************************
+ * vlc_httpd.h: builtin HTTP/RTSP server.
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id: vlc_httpd.h,v 1.1 2004/03/03 13:23:47 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#ifndef _VLC_HTTPD_H
+#define _VLC_HTTPD_H 1
+
+/* NEVER touch that, it's here only because src/misc/objects.c
+ * need sizeof(httpd_t) */
+struct httpd_t
+{
+    VLC_COMMON_MEMBERS
+
+    int          i_host;
+    httpd_host_t **host;
+};
+
+enum
+{
+    HTTPD_MSG_NONE,
+
+    /* answer */
+    HTTPD_MSG_ANSWER,
+
+    /* channel communication */
+    HTTPD_MSG_CHANNEL,
+
+    /* http request */
+    HTTPD_MSG_GET,
+    HTTPD_MSG_HEAD,
+    HTTPD_MSG_POST,
+
+    /* rtsp request */
+    HTTPD_MSG_OPTIONS,
+    HTTPD_MSG_DESCRIBE,
+    HTTPD_MSG_SETUP,
+    HTTPD_MSG_PLAY,
+    HTTPD_MSG_PAUSE,
+    HTTPD_MSG_TEARDOWN,
+
+    /* just to track the count of MSG */
+    HTTPD_MSG_MAX
+};
+
+enum
+{
+    HTTPD_PROTO_NONE,
+    HTTPD_PROTO_HTTP,
+    HTTPD_PROTO_RTSP,
+};
+
+struct httpd_message_t
+{
+    httpd_client_t *cl; /* NULL if not throught a connection e vlc internal */
+
+    int     i_type;
+    int     i_proto;
+    int     i_version;
+
+    /* for an answer */
+    int     i_status;
+    char    *psz_status;
+
+    /* for a query */
+    char    *psz_url;
+    char    *psz_args;  /* FIXME find a clean way to handle GET(psz_args) and POST(body) through the same code */
+
+    /* for rtp over rtsp */
+    int     i_channel;
+
+    /* options */
+    int     i_name;
+    char    **name;
+    int     i_value;
+    char    **value;
+
+    /* body */
+    int64_t i_body_offset;
+    int     i_body;
+    uint8_t *p_body;
+
+};
+
+/* I keep the definition here, easier than looking at vlc_common.h
+
+ * answer could be null, int this case no answer is requested
+typedef int (*httpd_callback_t)( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *answer, httpd_message_t *query );
+typedef struct httpd_callback_sys_t httpd_callback_sys_t;
+
+typedef struct httpd_file_t     httpd_file_t;
+typedef struct httpd_file_sys_t httpd_file_sys_t;
+typedef int (*httpd_file_callback_t)( httpd_file_sys_t*, httpd_file_t *, uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
+*/
+
+/* create a new host */
+VLC_EXPORT( httpd_host_t *, httpd_HostNew, ( vlc_object_t *, char *psz_host, int i_port ) );
+/* delete a host */
+VLC_EXPORT( void,           httpd_HostDelete, ( httpd_host_t * ) );
+
+/* register a new url */
+VLC_EXPORT( httpd_url_t *,  httpd_UrlNew, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password ) );
+VLC_EXPORT( httpd_url_t *,  httpd_UrlNewUnique, ( httpd_host_t *, char *psz_url, char *psz_user, char *psz_password ) );
+/* register callback on a url */
+VLC_EXPORT( int,            httpd_UrlCatch, ( httpd_url_t *, int i_msg, httpd_callback_t, httpd_callback_sys_t * ) );
+/* delete an url */
+VLC_EXPORT( void,           httpd_UrlDelete, ( httpd_url_t * ) );
+
+/* Default client mode is FILE, use these to change it */
+VLC_EXPORT( void,           httpd_ClientModeStream, ( httpd_client_t *cl ) );
+VLC_EXPORT( void,           httpd_ClientModeBidir, ( httpd_client_t *cl ) );
+
+/* High level */
+
+VLC_EXPORT( httpd_file_t *, httpd_FileNew, ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password, httpd_file_callback_t pf_fill, httpd_file_sys_t * ) );
+VLC_EXPORT( void,           httpd_FileDelete, ( httpd_file_t * ) );
+
+
+VLC_EXPORT( httpd_redirect_t *, httpd_RedirectNew, ( httpd_host_t *, char *psz_url_dst, char *psz_url_src ) );
+VLC_EXPORT( void,               httpd_RedirectDelete, ( httpd_redirect_t * ) );
+
+
+VLC_EXPORT( httpd_stream_t *, httpd_StreamNew,    ( httpd_host_t *, char *psz_url, char *psz_mime, char *psz_user, char *psz_password ) );
+VLC_EXPORT( void,             httpd_StreamDelete, ( httpd_stream_t * ) );
+VLC_EXPORT( int,              httpd_StreamHeader, ( httpd_stream_t *, uint8_t *p_data, int i_data ) );
+VLC_EXPORT( int,              httpd_StreamSend,   ( httpd_stream_t *, uint8_t *p_data, int i_data ) );
+
+
+/* Msg functions facilities */
+VLC_EXPORT( void,         httpd_MsgInit, ( httpd_message_t * )  );
+VLC_EXPORT( void,         httpd_MsgAdd, ( httpd_message_t *, char *psz_name, char *psz_value, ... ) );
+/* return "" if not found. The string is not allocated */
+VLC_EXPORT( char *,       httpd_MsgGet, ( httpd_message_t *, char *psz_name ) );
+VLC_EXPORT( void,         httpd_MsgClean, ( httpd_message_t * ) );
+
+#endif /* _VLC_HTTPD_H */
diff --git a/modules/misc/httpd.c b/modules/misc/httpd.c
deleted file mode 100644 (file)
index 90eef94..0000000
+++ /dev/null
@@ -1,2251 +0,0 @@
-/*****************************************************************************
- * httpd.c
- *****************************************************************************
- * Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.c,v 1.31 2004/02/05 19:51:46 fenrir Exp $
- *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- *****************************************************************************/
-
-/*****************************************************************************
- * Preamble
- *
- * TODO:
- *  - make that two distinct host:port use different daemon
- *****************************************************************************/
-#include <stdlib.h>
-#include <vlc/vlc.h>
-
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <fcntl.h>
-
-#include "httpd.h"
-
-#ifdef HAVE_SYS_TIME_H
-#    include <sys/time.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-#   include <unistd.h>
-#endif
-
-#if defined( UNDER_CE )
-#   include <winsock.h>
-#elif defined( WIN32 )
-#   include <winsock2.h>
-#   include <ws2tcpip.h>
-#   ifndef IN_MULTICAST
-#       define IN_MULTICAST(a) IN_CLASSD(a)
-#   endif
-#else
-#   include <netdb.h>                                         /* hostent ... */
-#   include <sys/socket.h>
-#   include <netinet/in.h>
-#   ifdef HAVE_ARPA_INET_H
-#       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
-#   endif
-#endif
-
-#include "network.h"
-
-#ifndef INADDR_ANY
-#   define INADDR_ANY  0x00000000
-#endif
-#ifndef INADDR_NONE
-#   define INADDR_NONE 0xFFFFFFFF
-#endif
-
-#define LISTEN_BACKLOG          100
-#define HTTPD_MAX_CONNECTION    512
-#define HTTPD_CONNECTION_MAX_UNUSED 10000000
-
-
-#define FREE( p ) if( p ) { free( p); (p) = NULL; }
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-#define SOCKET_CLOSE(a)    closesocket(a)
-#else
-#define SOCKET_CLOSE(a)    close(a)
-#endif
-
-/*****************************************************************************
- * Exported prototypes
- *****************************************************************************/
-static int              Open   ( vlc_object_t * );
-static void             Close  ( vlc_object_t * );
-
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-vlc_module_begin();
-    set_description( _("HTTP 1.0 daemon") );
-    set_capability( "httpd", 42 );
-    set_callbacks( Open, Close );
-    var_Create( p_module->p_libvlc, "httpd", VLC_VAR_MUTEX );
-vlc_module_end();
-
-/*****************************************************************************
- * Prototypes
- *****************************************************************************/
-static httpd_host_t     *RegisterHost   ( httpd_t *, char *, int );
-static void             UnregisterHost  ( httpd_t *, httpd_host_t * );
-
-static httpd_file_t     *RegisterFile   ( httpd_t *,
-                                          char *psz_file, char *psz_mime,
-                                          char *psz_user, char *psz_password,
-                                          httpd_file_callback pf_get,
-                                          httpd_file_callback pf_post,
-                                          httpd_file_callback_args_t *p_args );
-static void             UnregisterFile  ( httpd_t *, httpd_file_t * );
-
-#if 0
- #define httpd_stream_t              httpd_file_t
-#endif
-static httpd_stream_t   *RegisterStream ( httpd_t *,
-                                         char *psz_file, char *psz_mime,
-                                         char *psz_user, char *psz_password );
-static int              SendStream      ( httpd_t *, httpd_stream_t *, uint8_t *, int );
-static int              HeaderStream    ( httpd_t *, httpd_stream_t *, uint8_t *, int );
-static void             UnregisterStream( httpd_t *, httpd_stream_t* );
-static int              Control         ( httpd_t *, int , void*, void* );
-/*****************************************************************************
- * Internal definitions
- *****************************************************************************/
-struct httpd_host_t
-{
-    int    i_ref;
-
-    char   *psz_host_addr;
-    int    i_port;
-
-    struct sockaddr_in sock;
-    int    fd;
-
-};
-
-enum httpd_authenticate_e
-{
-    HTTPD_AUTHENTICATE_NONE = 0,
-    HTTPD_AUTHENTICATE_BASIC = 1
-};
-
-#if 0
-  typedef httpd_file_t httpd_stream_t;
-#endif
-
-struct httpd_file_t
-{
-    int         i_ref;
-
-    char        *psz_file;
-    char        *psz_mime;
-
-
-    int         i_authenticate_method;
-        char        *psz_user;          /* NULL if no auth */
-        char        *psz_password;      /* NULL if no auth */
-
-    vlc_bool_t  b_stream;               /* if false: httpd will retreive data by a callback
-                                              true:  it's up to the program to give data to httpd */
-    void                *p_sys;         /* provided for user */
-    httpd_file_callback pf_get;         /* it should allocate and fill *pp_data and *pi_data */
-    httpd_file_callback pf_post;        /* it should allocate and fill *pp_data and *pi_data */
-
-    /* private */
-
-    /* circular buffer for stream only */
-    int         i_buffer_size;      /* buffer size, can't be reallocated smaller */
-    uint8_t     *p_buffer;          /* buffer */
-    int64_t     i_buffer_pos;       /* absolute position from begining */
-    int64_t     i_buffer_last_pos;  /* a new connection will start with that */
-
-    /* data to be send at connection time (if any) */
-    int         i_header_size;
-    uint8_t     *p_header;
-};
-
-
-enum httpd_connection_state_e
-{
-    HTTPD_CONNECTION_RECEIVING_REQUEST = 1,
-    HTTPD_CONNECTION_SENDING_HEADER = 2,
-    HTTPD_CONNECTION_SENDING_FILE = 3,
-    HTTPD_CONNECTION_SENDING_STREAM = 4,
-    HTTPD_CONNECTION_TO_BE_CLOSED = 5
-};
-
-enum httpd_connection_method_e
-{
-    HTTPD_CONNECTION_METHOD_GET     = 1,
-    HTTPD_CONNECTION_METHOD_POST    = 2,
-    HTTPD_CONNECTION_METHOD_HEAD    = 3,
-    /* cludgy, only used when parsing connection request */
-    HTTPD_CONNECTION_METHOD_ASFHEAD = 4
-};
-
-typedef struct httpd_connection_s
-{
-    struct httpd_connection_s *p_next;
-    struct httpd_connection_s *p_prev;
-
-    struct  sockaddr_in sock;
-    int     fd;
-    mtime_t i_last_activity_date;
-
-    int    i_state;
-    int    i_method;       /* get/post */
-
-    char    *psz_file;      /* file to be send */
-    int     i_http_error;   /* error to be send with the file */
-    char    *psz_user;      /* if Authorization in the request header */
-    char    *psz_password;
-
-    uint8_t *p_request;     /* whith get: ?<*>, with post: main data */
-    int      i_request_size;
-
-    httpd_file_t    *p_file;
-
-    /* used while sending header and file */
-    int     i_buffer_size;
-    uint8_t *p_buffer;
-    int     i_buffer;            /* private */
-
-    /* used for stream */
-    int64_t i_stream_pos;   /* absolute pos in stream */
-} httpd_connection_t;
-
-/* Linked List of banned IP */
-typedef struct httpd_banned_ip_s
-{
-    struct httpd_banned_ip_s *p_next;
-    struct httpd_banned_ip_s *p_prev;
-
-    char *psz_ip;
-
-} httpd_banned_ip_t;
-/*
- * The httpd thread
- */
-struct httpd_sys_t
-{
-    VLC_COMMON_MEMBERS
-
-    vlc_mutex_t             host_lock;
-    volatile int            i_host_count;
-    httpd_host_t            **host;
-
-    vlc_mutex_t             file_lock;
-    int                     i_file_count;
-    httpd_file_t            **file;
-
-    vlc_mutex_t             connection_lock;
-    int                     i_connection_count;
-    httpd_connection_t      *p_first_connection;
-
-    vlc_mutex_t             ban_lock;
-    int                     i_banned_ip_count;
-    httpd_banned_ip_t       *p_first_banned_ip;
-};
-
-static void httpd_Thread( httpd_sys_t *p_httpt );
-static void httpd_ConnnectionNew( httpd_sys_t *, int , struct sockaddr_in * );
-static void httpd_ConnnectionClose( httpd_sys_t *, httpd_connection_t * );
-static int httpd_UnbanIP( httpd_sys_t *, httpd_banned_ip_t *);
-#if 0
-static int httpd_BanIP( httpd_sys_t *, char *);
-#endif
-static httpd_banned_ip_t *httpd_GetbannedIP( httpd_sys_t *, char * );
-
-/*****************************************************************************
- * Open:
- *****************************************************************************/
-
-static int Open( vlc_object_t *p_this )
-{
-    httpd_t     *p_httpd = (httpd_t*)p_this;
-    httpd_sys_t *p_httpt;
-
-    /* Launch httpt thread */
-    if( !( p_httpt = vlc_object_create( p_this, sizeof( httpd_sys_t ) ) ) )
-    {
-        msg_Err( p_this, "out of memory" );
-        return( VLC_EGENERIC );
-    }
-
-    p_httpt->b_die  = 0;
-    p_httpt->b_error= 0;
-
-    /* init httpt_t structure */
-    if( vlc_mutex_init( p_httpd, &p_httpt->host_lock ) )
-    {
-        msg_Err( p_httpd, "Error in mutex creation");
-        return( VLC_EGENERIC );
-    }
-    p_httpt->i_host_count = 0;
-    p_httpt->host = NULL;
-
-    if( vlc_mutex_init( p_httpd, &p_httpt->file_lock ) )
-    {
-        msg_Err( p_httpd, "Error in mutex creation");
-        return( VLC_EGENERIC );
-    }
-    p_httpt->i_file_count = 0;
-    p_httpt->file = NULL;
-
-    if( vlc_mutex_init( p_httpd, &p_httpt->connection_lock ) )
-    {
-        msg_Err( p_httpd, "Error in mutex creation");
-        return( VLC_EGENERIC );
-    }
-    p_httpt->i_connection_count = 0;
-    p_httpt->p_first_connection = NULL;
-
-    if( vlc_mutex_init( p_httpd, &p_httpt->ban_lock ) )
-    {
-        msg_Err( p_httpd, "Error in mutex creation");
-        return( VLC_EGENERIC );
-    }
-
-    p_httpt->i_banned_ip_count = 0;
-    p_httpt->p_first_banned_ip = NULL;
-
-    /* start the thread */
-    if( vlc_thread_create( p_httpt, "httpd thread",
-                           httpd_Thread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
-    {
-        msg_Err( p_this, "cannot spawn http thread" );
-
-        vlc_mutex_destroy( &p_httpt->host_lock );
-        vlc_mutex_destroy( &p_httpt->file_lock );
-        vlc_mutex_destroy( &p_httpt->connection_lock );
-        vlc_mutex_destroy( &p_httpt->ban_lock );
-
-        vlc_object_destroy( p_httpt );
-        return( VLC_EGENERIC );
-    }
-
-    msg_Info( p_httpd, "http thread launched" );
-
-    p_httpd->p_sys = p_httpt;
-    p_httpd->pf_register_host   = RegisterHost;
-    p_httpd->pf_unregister_host = UnregisterHost;
-    p_httpd->pf_register_file   = RegisterFile;
-    p_httpd->pf_unregister_file = UnregisterFile;
-    p_httpd->pf_register_stream = RegisterStream;
-    p_httpd->pf_header_stream   = HeaderStream;
-    p_httpd->pf_send_stream     = SendStream;
-    p_httpd->pf_unregister_stream=UnregisterStream;
-    p_httpd->pf_control         = Control;
-
-    return( VLC_SUCCESS );
-}
-
-/*****************************************************************************
- * Close: close the target
- *****************************************************************************/
-static void Close( vlc_object_t * p_this )
-{
-    httpd_t     *p_httpd = (httpd_t*)p_this;
-    httpd_sys_t *p_httpt = p_httpd->p_sys;
-
-    httpd_connection_t *p_con;
-    httpd_banned_ip_t *p_banned_ip;
-
-    int i;
-
-    p_httpt->b_die = 1;
-    vlc_thread_join( p_httpt );
-
-    /* first close all host */
-    vlc_mutex_destroy( &p_httpt->host_lock );
-    if( p_httpt->i_host_count )
-    {
-        msg_Err( p_httpd, "still have %d hosts registered !", p_httpt->i_host_count );
-    }
-    for( i = 0; i < p_httpt->i_host_count; i++ )
-    {
-#define p_host p_httpt->host[i]
-        FREE( p_host->psz_host_addr );
-        SOCKET_CLOSE( p_host->fd );
-
-        FREE( p_host );
-#undef p_host
-    }
-    FREE( p_httpt->host );
-
-    /* now all file */
-    vlc_mutex_destroy( &p_httpt->file_lock );
-    if( p_httpt->i_file_count )
-    {
-        msg_Err( p_httpd, "still have %d files registered !", p_httpt->i_file_count );
-    }
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-#define p_file p_httpt->file[i]
-        FREE( p_file->psz_file );
-        FREE( p_file->psz_mime );
-        if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
-        {
-            FREE( p_file->psz_user );
-            FREE( p_file->psz_password );
-        }
-        FREE( p_file->p_buffer );
-
-        FREE( p_file );
-#undef p_file
-    }
-    FREE( p_httpt->file );
-
-    /* andd close all connection */
-    vlc_mutex_destroy( &p_httpt->connection_lock );
-    if( p_httpt->i_connection_count )
-    {
-        msg_Warn( p_httpd, "%d connections still in use", p_httpt->i_connection_count );
-    }
-    while( ( p_con = p_httpt->p_first_connection ) )
-    {
-        httpd_ConnnectionClose( p_httpt, p_con );
-    }
-
-    /* Free all banned IP */
-    vlc_mutex_destroy( &p_httpt->ban_lock );
-    while( ( p_banned_ip = p_httpt->p_first_banned_ip))
-    {
-        httpd_UnbanIP(p_httpt,p_banned_ip);
-    }
-
-    msg_Info( p_httpd, "httpd instance closed" );
-    vlc_object_destroy( p_httpt );
-}
-
-
-/****************************************************************************
- ****************************************************************************
- ***
- ***
- ****************************************************************************
- ****************************************************************************/
-static int BuildAddr( struct sockaddr_in * p_socket,
-                      const char * psz_address, int i_port )
-{
-    /* Reset struct */
-    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
-    p_socket->sin_family = AF_INET;                                /* family */
-    p_socket->sin_port = htons( (uint16_t)i_port );
-    if( !*psz_address )
-    {
-        p_socket->sin_addr.s_addr = INADDR_ANY;
-    }
-    else
-    {
-        struct hostent    * p_hostent;
-
-        /* Try to convert address directly from in_addr - this will work if
-         * psz_address is dotted decimal. */
-#ifdef HAVE_ARPA_INET_H
-        if( !inet_aton( psz_address, &p_socket->sin_addr ) )
-#else
-        p_socket->sin_addr.s_addr = inet_addr( psz_address );
-        if( p_socket->sin_addr.s_addr == INADDR_NONE )
-#endif
-        {
-            /* We have a fqdn, try to find its address */
-            if ( (p_hostent = gethostbyname( psz_address )) == NULL )
-            {
-                return( -1 );
-            }
-
-            /* Copy the first address of the host in the socket address */
-            memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
-                     p_hostent->h_length );
-        }
-    }
-    return( 0 );
-}
-
-
-/*
- * listen on a host for a httpd instance
- */
-
-static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, int i_port )
-{
-    httpd_host_t    *p_host;
-    struct sockaddr_in  sock;
-    int i;
-    int fd = -1;
-    int i_opt;
-#if !defined( WIN32 ) && !defined( UNDER_CE )
-    int i_flags;
-#endif
-
-    if( BuildAddr( &sock, psz_host_addr, i_port ) )
-    {
-        msg_Err( p_httpt, "cannot build address for %s:%d", psz_host_addr, i_port );
-        return NULL;
-    }
-
-    /* is it already declared ? */
-    vlc_mutex_lock( &p_httpt->host_lock );
-    for( i = 0; i < p_httpt->i_host_count; i++ )
-    {
-        if( p_httpt->host[i]->sock.sin_port == sock.sin_port &&
-            ( p_httpt->host[i]->sock.sin_addr.s_addr == INADDR_ANY ||
-            p_httpt->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr ) )
-        {
-            break;
-        }
-    }
-
-    if( i < p_httpt->i_host_count )
-    {
-        /* yes, increment ref count and succed */
-        p_httpt->host[i]->i_ref++;
-        vlc_mutex_unlock( &p_httpt->host_lock );
-        return( p_httpt->host[i] );
-    }
-
-    /* need to add a new listening socket */
-
-    /* open socket */
-    fd = socket( AF_INET, SOCK_STREAM, 0 );
-    if( fd < 0 )
-    {
-        msg_Err( p_httpt, "cannot open socket" );
-        goto socket_failed;
-    }
-    /* reuse socket */
-    i_opt = 1;
-    if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
-                    (void *) &i_opt, sizeof( i_opt ) ) < 0 )
-    {
-        msg_Warn( p_httpt, "cannot configure socket (SO_REUSEADDR)" );
-    }
-    /* bind it */
-    if( bind( fd, (struct sockaddr *)&sock, sizeof( struct sockaddr_in ) ) < 0 )
-    {
-        msg_Err( p_httpt, "cannot bind socket" );
-        goto socket_failed;
-    }
-    /* set to non-blocking */
-#if defined( WIN32 ) || defined( UNDER_CE )
-    {
-        unsigned long i_dummy = 1;
-        if( ioctlsocket( fd, FIONBIO, &i_dummy ) != 0 )
-        {
-            msg_Err( p_httpt, "cannot set socket to non-blocking mode" );
-            goto socket_failed;
-        }
-    }
-#else
-    if( ( i_flags = fcntl( fd, F_GETFL, 0 ) ) < 0 )
-    {
-        msg_Err( p_httpt, "cannot F_GETFL socket" );
-        goto socket_failed;
-    }
-    if( fcntl( fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
-    {
-        msg_Err( p_httpt, "cannot F_SETFL O_NONBLOCK" );
-        goto socket_failed;
-    }
-#endif
-    /* listen */
-    if( listen( fd, LISTEN_BACKLOG ) < 0 )
-    {
-        msg_Err( p_httpt, "cannot listen socket" );
-        goto socket_failed;
-    }
-
-    if( p_httpt->host )
-    {
-        p_httpt->host = realloc( p_httpt->host, sizeof( httpd_host_t *)  * ( p_httpt->i_host_count + 1 ) );
-    }
-    else
-    {
-        p_httpt->host = malloc( sizeof( httpd_host_t *) );
-    }
-    if( !p_httpt->host )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    p_host                = malloc( sizeof( httpd_host_t ) );
-    if( !p_host )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    p_host->i_ref         = 1;
-    p_host->psz_host_addr = strdup( psz_host_addr );
-    if( !p_host->psz_host_addr )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    p_host->i_port        = i_port;
-    p_host->sock          = sock;
-    p_host->fd            = fd;
-
-    p_httpt->host[p_httpt->i_host_count++] = p_host;
-    vlc_mutex_unlock( &p_httpt->host_lock );
-
-    return p_host;
-
-socket_failed:
-    vlc_mutex_unlock( &p_httpt->host_lock );
-    if( fd >= 0 )
-    {
-        SOCKET_CLOSE( fd );
-    }
-    return NULL;
-}
-static httpd_host_t     *RegisterHost( httpd_t *p_httpd, char *psz_host_addr, int i_port )
-{
-    return( _RegisterHost( p_httpd->p_sys, psz_host_addr, i_port ) );
-}
-
-/*
- * remove a listening host for an httpd instance
- */
-static void            _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_host )
-{
-    int i;
-
-    vlc_mutex_lock( &p_httpt->host_lock );
-    for( i = 0; i < p_httpt->i_host_count; i++ )
-    {
-        if( p_httpt->host[i] == p_host )
-        {
-            break;
-        }
-    }
-    if( i >= p_httpt->i_host_count )
-    {
-        vlc_mutex_unlock( &p_httpt->host_lock );
-        msg_Err( p_httpt, "cannot unregister host" );
-        return;
-    }
-
-    p_host->i_ref--;
-
-    if( p_host->i_ref > 0 )
-    {
-        /* still in use */
-        vlc_mutex_unlock( &p_httpt->host_lock );
-        return;
-    }
-
-    /* no more used */
-    FREE( p_host->psz_host_addr );
-    SOCKET_CLOSE( p_host->fd );
-
-    FREE( p_host );
-
-    if( p_httpt->i_host_count <= 1 )
-    {
-        FREE( p_httpt->host );
-        p_httpt->i_host_count = 0;
-    }
-    else
-    {
-        int i_move;
-
-        i_move = p_httpt->i_host_count - i - 1;
-
-        if( i_move > 0 )
-        {
-            memmove( &p_httpt->host[i],
-                     &p_httpt->host[i+1],
-                     i_move * sizeof( httpd_host_t * ) );
-        }
-
-        p_httpt->i_host_count--;
-        p_httpt->host = realloc( p_httpt->host,
-                                 p_httpt->i_host_count * sizeof( httpd_host_t * ) );
-        if( !p_httpt->host )
-        {
-            msg_Err( p_httpt, "Out of memory" );
-            return;
-        }
-    }
-
-    vlc_mutex_unlock( &p_httpt->host_lock );
-}
-static void             UnregisterHost( httpd_t *p_httpd, httpd_host_t *p_host )
-{
-    _UnregisterHost( p_httpd->p_sys, p_host );
-}
-
-
-static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
-{
-    /* add a new file */
-    if( p_httpt->i_file_count )
-    {
-        p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *)  * ( p_httpt->i_file_count + 1 ) );
-    }
-    else
-    {
-        p_httpt->file = malloc( sizeof( httpd_file_t *) );
-    }
-    if( !p_httpt->file )
-    {
-        return;
-    }
-    p_httpt->file[p_httpt->i_file_count++] = p_file;
-}
-
-static httpd_file_t    *_RegisterFile( httpd_sys_t *p_httpt,
-                                       char *psz_file, char *psz_mime,
-                                       char *psz_user, char *psz_password,
-                                       httpd_file_callback pf_get,
-                                       httpd_file_callback pf_post,
-                                       httpd_file_callback_args_t *p_args )
-{
-    httpd_file_t    *p_file;
-    int i;
-
-    vlc_mutex_lock( &p_httpt->file_lock );
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
-        {
-            break;
-        }
-    }
-    if( i < p_httpt->i_file_count )
-    {
-        vlc_mutex_unlock( &p_httpt->file_lock );
-        msg_Err( p_httpt, "%s already registered", psz_file );
-        return NULL;
-    }
-
-    p_file              = malloc( sizeof( httpd_file_t ) );
-    if( !p_file )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    p_file->i_ref       = 0;
-    p_file->psz_file    = strdup( psz_file );
-    p_file->psz_mime    = strdup( psz_mime );
-    if( !p_file->psz_file || !p_file->psz_mime )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    if( psz_user && *psz_user )
-    {
-        p_file->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
-        p_file->psz_user              = strdup( psz_user );
-        p_file->psz_password          = strdup( psz_password );
-        if( !p_file->psz_user || !p_file->psz_password )
-        {
-            msg_Err( p_httpt, "Out of memory" );
-            return NULL;
-        }
-    }
-    else
-    {
-        p_file->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
-        p_file->psz_user              = NULL;
-        p_file->psz_password          = NULL;
-    }
-
-    p_file->b_stream          = VLC_FALSE;
-    p_file->p_sys             = p_args;
-    p_file->pf_get            = pf_get;
-    p_file->pf_post           = pf_post;
-
-    p_file->i_buffer_size     = 0;
-    p_file->i_buffer_last_pos = 0;
-    p_file->i_buffer_pos      = 0;
-    p_file->p_buffer          = NULL;
-
-    p_file->i_header_size     = 0;
-    p_file->p_header          = NULL;
-
-    __RegisterFile( p_httpt, p_file );
-
-    vlc_mutex_unlock( &p_httpt->file_lock );
-
-    return p_file;
-}
-static httpd_file_t     *RegisterFile( httpd_t *p_httpd,
-                                       char *psz_file, char *psz_mime,
-                                       char *psz_user, char *psz_password,
-                                       httpd_file_callback pf_get,
-                                       httpd_file_callback pf_post,
-                                       httpd_file_callback_args_t *p_args )
-{
-    return( _RegisterFile( p_httpd->p_sys,
-                           psz_file, psz_mime, psz_user, psz_password,
-                           pf_get, pf_post, p_args ) );
-}
-
-static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
-                                         char *psz_file, char *psz_mime,
-                                         char *psz_user, char *psz_password )
-{
-    httpd_stream_t    *p_stream;
-    int i;
-
-    vlc_mutex_lock( &p_httpt->file_lock );
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        if( !strcmp( psz_file, p_httpt->file[i]->psz_file ) )
-        {
-            break;
-        }
-    }
-    if( i < p_httpt->i_file_count )
-    {
-        vlc_mutex_unlock( &p_httpt->file_lock );
-        msg_Err( p_httpt, "%s already registered", psz_file );
-        return NULL;
-    }
-
-    p_stream              = malloc( sizeof( httpd_stream_t ) );
-    if( !p_stream )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    p_stream->i_ref       = 0;
-    p_stream->psz_file    = strdup( psz_file );
-    p_stream->psz_mime    = strdup( psz_mime );
-    if( !p_stream->psz_file || !p_stream->psz_mime )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-    if( psz_user && *psz_user )
-    {
-        p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_BASIC;
-        p_stream->psz_user              = strdup( psz_user );
-        p_stream->psz_password          = strdup( psz_password );
-        if( !p_stream->psz_user || !p_stream->psz_password )
-        {
-            msg_Err( p_httpt, "Out of memory" );
-            return NULL;
-        }
-    }
-    else
-    {
-        p_stream->i_authenticate_method = HTTPD_AUTHENTICATE_NONE;
-        p_stream->psz_user              = NULL;
-        p_stream->psz_password          = NULL;
-    }
-
-    p_stream->b_stream        = VLC_TRUE;
-    p_stream->p_sys           = NULL;
-    p_stream->pf_get          = NULL;
-    p_stream->pf_post         = NULL;
-
-    p_stream->i_buffer_size   = 5*1024*1024;
-    p_stream->i_buffer_pos      = 0;
-    p_stream->i_buffer_last_pos = 0;
-    p_stream->p_buffer        = malloc( p_stream->i_buffer_size );
-    if( !p_stream->p_buffer )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return NULL;
-    }
-
-    p_stream->i_header_size   = 0;
-    p_stream->p_header        = NULL;
-
-    __RegisterFile( p_httpt, p_stream );
-
-    vlc_mutex_unlock( &p_httpt->file_lock );
-
-    return p_stream;
-}
-static httpd_stream_t   *RegisterStream( httpd_t *p_httpd,
-                                         char *psz_file, char *psz_mime,
-                                         char *psz_user, char *psz_password )
-{
-    return( _RegisterStream( p_httpd->p_sys,
-                             psz_file, psz_mime, psz_user, psz_password ) );
-}
-
-static void            _UnregisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
-{
-    int i;
-
-    vlc_mutex_lock( &p_httpt->file_lock );
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        if( !strcmp( p_file->psz_file, p_httpt->file[i]->psz_file ) )
-        {
-            break;
-        }
-    }
-    if( i >= p_httpt->i_file_count )
-    {
-        vlc_mutex_unlock( &p_httpt->file_lock );
-        msg_Err( p_httpt, "cannot unregister file" );
-        return;
-    }
-
-    if( p_file->i_ref > 0 )
-    {
-        httpd_connection_t *p_con;
-        /* force closing all connection for this file */
-        msg_Err( p_httpt, "closing all client connection" );
-
-        vlc_mutex_lock( &p_httpt->connection_lock );
-        for( p_con = p_httpt->p_first_connection; p_con != NULL; )
-        {
-            httpd_connection_t *p_next;
-
-            p_next = p_con->p_next;
-            if( p_con->p_file == p_file )
-            {
-                httpd_ConnnectionClose( p_httpt, p_con );
-            }
-            p_con = p_next;
-        }
-        vlc_mutex_unlock( &p_httpt->connection_lock );
-    }
-
-    FREE( p_file->psz_file );
-    FREE( p_file->psz_mime );
-    if( p_file->i_authenticate_method != HTTPD_AUTHENTICATE_NONE )
-    {
-        FREE( p_file->psz_user );
-        FREE( p_file->psz_password );
-    }
-    FREE( p_file->p_buffer );
-    FREE( p_file->p_header );
-
-    FREE( p_file );
-
-
-    if( p_httpt->i_file_count == 1 )
-    {
-        FREE( p_httpt->file );
-        p_httpt->i_file_count = 0;
-    }
-    else
-    {
-        int i_move;
-
-        i_move = p_httpt->i_file_count - i - 1;
-        if( i_move > 0  )
-        {
-            memmove( &p_httpt->file[i], &p_httpt->file[i + 1], sizeof( httpd_file_t *) * i_move );
-        }
-        p_httpt->i_file_count--;
-        p_httpt->file = realloc( p_httpt->file, sizeof( httpd_file_t *) * p_httpt->i_file_count );
-    }
-
-    vlc_mutex_unlock( &p_httpt->file_lock );
-}
-static void            UnregisterFile( httpd_t *p_httpd, httpd_file_t *p_file )
-{
-    _UnregisterFile( p_httpd->p_sys, p_file );
-}
-
-static void             UnregisterStream( httpd_t *p_httpd, httpd_stream_t *p_stream )
-{
-    _UnregisterFile( p_httpd->p_sys, p_stream );
-}
-
-
-
-static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
-{
-    int i_count;
-    int i_pos;
-
-    if( i_data <= 0 || p_data == NULL )
-    {
-        return( VLC_SUCCESS );
-    }
-#if 0
-    fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
-#endif
-    vlc_mutex_lock( &p_httpt->file_lock );
-
-    /* save this pointer (to be used by new connection) */
-    p_stream->i_buffer_last_pos = p_stream->i_buffer_pos;
-
-    i_pos = p_stream->i_buffer_pos % p_stream->i_buffer_size;
-    i_count = i_data;
-    while( i_count > 0)
-    {
-        int i_copy;
-
-        i_copy = __MIN( i_count, p_stream->i_buffer_size - i_pos );
-
-        /* Ok, we can't go past the end of our buffer */
-        memcpy( &p_stream->p_buffer[i_pos],
-                p_data,
-                i_copy );
-
-        i_pos = ( i_pos + i_copy ) % p_stream->i_buffer_size;
-        i_count -= i_copy;
-        p_data += i_copy;
-    }
-
-    p_stream->i_buffer_pos += i_data;
-    vlc_mutex_unlock( &p_httpt->file_lock );
-
-    return( VLC_SUCCESS );
-}
-
-static int             SendStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
-{
-    return( _SendStream( p_httpd->p_sys, p_stream, p_data, i_data ) );
-}
-
-static int             HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream, uint8_t *p_data, int i_data )
-{
-    httpd_sys_t *p_httpt = p_httpd->p_sys;
-
-    vlc_mutex_lock( &p_httpt->file_lock );
-
-    FREE( p_stream->p_header );
-    if( p_data == NULL || i_data <= 0 )
-    {
-        p_stream->i_header_size = 0;
-    }
-    else
-    {
-        p_stream->i_header_size = i_data;
-        p_stream->p_header = malloc( i_data );
-        if( !p_stream->p_header )
-        {
-            msg_Err( p_httpt, "Out of memory" );
-            return( VLC_ENOMEM );
-        }
-        memcpy( p_stream->p_header,
-                p_data,
-                i_data );
-    }
-    vlc_mutex_unlock( &p_httpt->file_lock );
-
-    return( VLC_SUCCESS );
-}
-
-static void httpd_info_add_ss( httpd_info_t *p_info, char *name, char *value )
-{
-    if( p_info->i_count == 0 )
-    {
-        p_info->info = malloc( sizeof( httpd_val_t ) );
-    }
-    else
-    {
-        p_info->info =
-            realloc( p_info->info,
-                     sizeof( httpd_val_t ) * ( p_info->i_count + 1 ) );
-    }
-    if( !p_info->info )
-    {
-        return;
-    }
-    p_info->info[p_info->i_count].psz_name  = strdup( name );
-    if( ! p_info->info[p_info->i_count].psz_name )
-    {
-        return;
-    }
-    p_info->info[p_info->i_count].psz_value = strdup( value ? value : "(null)");
-    p_info->i_count++;
-}
-
-static void httpd_info_add_si( httpd_info_t *p_info, char *name, int i_value )
-{
-    char v[40]; /* Ok, int is not so long */
-
-    sprintf( v, "%d", i_value );
-    httpd_info_add_ss( p_info, name, v );
-}
-
-static void httpd_info_add_sp( httpd_info_t *p_info, char *name, void *value )
-{
-    char v[40];
-
-    sprintf( v, "%p", value );
-    httpd_info_add_ss( p_info, name, v );
-}
-
-
-static int Control( httpd_t *p_httpd,
-                    int i_query, void *arg1, void *arg2 )
-{
-    httpd_sys_t  *p_httpt = p_httpd->p_sys;
-    httpd_info_t *p_info;
-    httpd_connection_t *p_con;
-    int i;
-    void *id;
-
-    switch( i_query )
-    {
-        case HTTPD_GET_HOSTS:
-            p_info = arg1;
-            p_info->i_count = 0;
-            vlc_mutex_lock( &p_httpt->host_lock );
-            for( i = 0; i < p_httpt->i_host_count; i++ )
-            {
-                httpd_info_add_sp( p_info,
-                                   "id", p_httpt->host[i] );
-                httpd_info_add_ss( p_info,
-                                   "host", p_httpt->host[i]->psz_host_addr );
-                httpd_info_add_ss( p_info,
-                                   "ip",
-                                   inet_ntoa(p_httpt->host[i]->sock.sin_addr));
-                httpd_info_add_si( p_info,
-                                   "port", p_httpt->host[i]->i_port );
-            }
-            vlc_mutex_unlock( &p_httpt->host_lock );
-            return VLC_SUCCESS;
-        case HTTPD_GET_URLS:
-            p_info = arg1;
-            p_info->i_count = 0;
-            /* we can't take file_lock */
-            for( i = 0; i < p_httpt->i_file_count; i++ )
-            {
-                httpd_info_add_sp( p_info,
-                                   "id", p_httpt->file[i] );
-                httpd_info_add_si( p_info,
-                                   "stream", p_httpt->file[i]->b_stream ? 1 : 0 );
-                httpd_info_add_ss( p_info,
-                                   "url", p_httpt->file[i]->psz_file );
-                httpd_info_add_ss( p_info,
-                                   "mime", p_httpt->file[i]->psz_mime );
-                httpd_info_add_si( p_info,
-                                   "protected", p_httpt->file[i]->psz_user ? 1 : 0 );
-                httpd_info_add_si( p_info,
-                                   "used", p_httpt->file[i]->i_ref );
-            }
-            return VLC_SUCCESS;
-        case HTTPD_GET_CONNECTIONS:
-            p_info = arg1;
-            p_info->i_count = 0;
-            /* we can't take lock */
-            for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
-            {
-                if( p_con->i_state != HTTPD_CONNECTION_TO_BE_CLOSED )
-                {
-                    httpd_info_add_sp( p_info,
-                                       "id", p_con );
-                    httpd_info_add_ss( p_info,
-                                       "ip", inet_ntoa( p_con->sock.sin_addr ) );
-                    httpd_info_add_ss( p_info,
-                                       "url", p_con->psz_file );
-                    httpd_info_add_si( p_info,
-                                       "status", p_con->i_http_error );
-                }
-            }
-            return VLC_SUCCESS;
-        case HTTPD_GET_ACL:
-            p_info = arg1;
-            p_info->i_count = 0;
-            return VLC_EGENERIC;
-
-        case HTTPD_SET_CLOSE:
-            sscanf( arg1, "%p", &id );
-            fprintf( stderr, "Control: HTTPD_SET_CLOSE: id=%p", id );
-
-            for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
-            {
-                if( (void*)p_con == id )
-                {
-                    /* XXX don't free p_con as it could be the one that it is sending ... */
-                    p_con->i_state = HTTPD_CONNECTION_TO_BE_CLOSED;
-                    return VLC_SUCCESS;
-                }
-            }
-            return VLC_EGENERIC;
-
-        case HTTPD_SET_ACL:
-            sscanf( arg1, "%p", &id );
-            fprintf( stderr, "Control: %p", id );
-        default:
-            return VLC_EGENERIC;
-    }
-}
-
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-/****************************************************************************/
-
-static int  httpd_page_400_get( httpd_file_callback_args_t *p_args,
-                                uint8_t *p_request, int i_request,
-                                uint8_t **pp_data, int *pi_data )
-{
-    char *p;
-
-    p = *pp_data = malloc( 1024 );
-    if( !p )
-    {
-        return VLC_ENOMEM ;
-    }
-    p += sprintf( p, "<html>\n" );
-    p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>Error 400</title>\n" );
-    p += sprintf( p, "</head>\n" );
-    p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center> 400  Bad Request</center></h1>\n" );
-    p += sprintf( p, "<hr />\n" );
-    p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
-    p += sprintf( p, "</body>\n" );
-    p += sprintf( p, "</html>\n" );
-
-    *pi_data = strlen( *pp_data ) + 1;
-
-    return VLC_SUCCESS;
-}
-
-static int  httpd_page_401_get( httpd_file_callback_args_t *p_args,
-                                uint8_t *p_request, int i_request,
-                                uint8_t **pp_data, int *pi_data )
-{
-    char *p;
-
-    p = *pp_data = malloc( 1024 );
-    if( !p )
-    {
-        return VLC_ENOMEM ;
-    }
-
-    p += sprintf( p, "<html>\n" );
-    p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>Error 401</title>\n" );
-    p += sprintf( p, "</head>\n" );
-    p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center> 401 authentification needed</center></h1>\n" );
-    p += sprintf( p, "<hr />\n" );
-    p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
-    p += sprintf( p, "</body>\n" );
-    p += sprintf( p, "</html>\n" );
-
-    *pi_data = strlen( *pp_data ) + 1;
-
-    return VLC_SUCCESS;
-}
-static int  httpd_page_404_get( httpd_file_callback_args_t *p_args,
-                                uint8_t *p_request, int i_request,
-                                uint8_t **pp_data, int *pi_data )
-{
-    char *p;
-
-    p = *pp_data = malloc( 1024 );
-    if( !p )
-    {
-        return VLC_ENOMEM ;
-    }
-
-    p += sprintf( p, "<html>\n" );
-    p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>Error 404</title>\n" );
-    p += sprintf( p, "</head>\n" );
-    p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center> 404 Ressource not found</center></h1>\n" );
-    p += sprintf( p, "<hr />\n" );
-    p += sprintf( p, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
-    p += sprintf( p, "</body>\n" );
-    p += sprintf( p, "</html>\n" );
-
-    *pi_data = strlen( *pp_data ) + 1;
-
-    return VLC_SUCCESS;
-}
-
-#if 0
-static int httpd_BanIP( httpd_sys_t *p_httpt, char * psz_new_banned_ip)
-{
-    httpd_banned_ip_t *p_new_banned_ip ;
-
-    p_new_banned_ip = malloc( sizeof( httpd_banned_ip_t ) );
-    if( !p_new_banned_ip )
-    {
-        return -1;
-    }
-    p_new_banned_ip->p_next=NULL;
-    p_new_banned_ip->psz_ip = malloc( strlen( psz_new_banned_ip ) + 1 );
-    if( !p_new_banned_ip->psz_ip )
-    {
-        return -2;
-    }
-
-    strcpy( p_new_banned_ip->psz_ip, psz_new_banned_ip );
-
-    msg_Dbg( p_httpt, "Banning IP %s", psz_new_banned_ip );
-
-    if( p_httpt->p_first_banned_ip )
-    {
-        httpd_banned_ip_t *p_last;
-
-        p_last = p_httpt->p_first_banned_ip;
-        while( p_last->p_next )
-        {
-            p_last = p_last->p_next;
-        }
-
-        p_last->p_next = p_new_banned_ip;
-        p_new_banned_ip->p_prev = p_last;
-    }
-    else
-    {
-        p_new_banned_ip->p_prev = NULL;
-
-        p_httpt->p_first_banned_ip = p_new_banned_ip;
-    }
-
-    p_httpt->i_banned_ip_count++;
-    return 0;
-}
-#endif
-static httpd_banned_ip_t *httpd_GetbannedIP( httpd_sys_t *p_httpt, char *psz_ip )
-{
-    httpd_banned_ip_t *p_ip;
-
-    p_ip = p_httpt->p_first_banned_ip;
-
-    while( p_ip)
-    {
-        if( strcmp( psz_ip, p_ip->psz_ip ) == 0 )
-        {
-            return p_ip;
-        }
-        p_ip = p_ip->p_next;
-    }
-
-    return NULL;
-}
-
-static int httpd_UnbanIP( httpd_sys_t *p_httpt, httpd_banned_ip_t *p_banned_ip )
-{
-    if(!p_banned_ip)
-    {
-        return -1;
-    }
-
-    msg_Dbg( p_httpt, "Unbanning IP %s",p_banned_ip->psz_ip);
-
-    /* first cut out from list */
-    if( p_banned_ip->p_prev )
-    {
-        p_banned_ip->p_prev->p_next = p_banned_ip->p_next;
-    }
-    else
-    {
-        p_httpt->p_first_banned_ip = p_banned_ip->p_next;
-    }
-
-    if( p_banned_ip->p_next )
-    {
-        p_banned_ip->p_next->p_prev = p_banned_ip->p_prev;
-    }
-
-    FREE( p_banned_ip->psz_ip );
-    FREE( p_banned_ip );
-
-    p_httpt->i_banned_ip_count--;
-
-    return 0;
-}
-
-static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_in *p_sock )
-{
-    httpd_connection_t *p_con;
-
-    msg_Dbg( p_httpt, "new connection from %s", inet_ntoa( p_sock->sin_addr ) );
-
-    /* verify if it's a banned ip */
-    if(httpd_GetbannedIP( p_httpt,inet_ntoa( p_sock->sin_addr ) ) )
-    {
-        msg_Dbg( p_httpt, "Ip %s banned : closing connection", inet_ntoa( p_sock->sin_addr ) );
-        close(fd);
-        return;
-    }
-
-    /* create a new connection and link it */
-    p_con = malloc( sizeof( httpd_connection_t ) );
-    if( !p_con )
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return;
-    }
-    p_con->i_state  = HTTPD_CONNECTION_RECEIVING_REQUEST;
-    p_con->fd       = fd;
-    p_con->i_last_activity_date = mdate();
-
-    p_con->sock     = *p_sock;
-    p_con->psz_file = NULL;
-    p_con->i_http_error = 0;
-    p_con->psz_user = NULL;
-    p_con->psz_password = NULL;
-    p_con->p_file   = NULL;
-
-    p_con->i_request_size = 0;
-    p_con->p_request = NULL;
-
-    p_con->i_buffer = 0;
-    p_con->i_buffer_size = 8096;
-    p_con->p_buffer = malloc( p_con->i_buffer_size );
-    if( !p_con->p_buffer )
-    {
-        msg_Err( p_httpt, "Out of memory");
-        return ;
-    }
-
-    p_con->i_stream_pos = 0; /* updated by httpd_thread */
-    p_con->p_next = NULL;
-
-    if( p_httpt->p_first_connection )
-    {
-        httpd_connection_t *p_last;
-
-        p_last = p_httpt->p_first_connection;
-        while( p_last->p_next )
-        {
-            p_last = p_last->p_next;
-        }
-
-        p_last->p_next = p_con;
-        p_con->p_prev = p_last;
-    }
-    else
-    {
-        p_con->p_prev = NULL;
-
-        p_httpt->p_first_connection = p_con;
-    }
-
-    p_httpt->i_connection_count++;
-}
-
-static void httpd_ConnnectionClose( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
-{
-    msg_Dbg( p_httpt, "close connection from %s", inet_ntoa( p_con->sock.sin_addr ) );
-
-    p_httpt->i_connection_count--;
-    /* first cut out from list */
-    if( p_con->p_prev )
-    {
-        p_con->p_prev->p_next = p_con->p_next;
-    }
-    else
-    {
-        p_httpt->p_first_connection = p_con->p_next;
-    }
-
-    if( p_con->p_next )
-    {
-        p_con->p_next->p_prev = p_con->p_prev;
-    }
-
-    if( p_con->p_file ) p_con->p_file->i_ref--;
-    FREE( p_con->psz_file );
-
-    FREE( p_con->p_buffer );
-    SOCKET_CLOSE( p_con->fd );
-
-    FREE( p_con->psz_user );
-    FREE( p_con->psz_password );
-
-    FREE( p_con->p_request );
-    free( p_con );
-}
-
-static void httpd_RequestGetWord( char *word, int i_word_max, char **pp_buffer, char *p_end )
-{
-    char *p = *pp_buffer;
-    int i;
-
-    while( p < p_end && *p && ( *p == ' ' || *p == '\t' ) )
-    {
-        p++;
-    }
-
-    i = 0;
-    for( i = 0; i < i_word_max && p < p_end && *p && *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r'; i++,p++)
-    {
-        word[i] = *p;
-    }
-
-    word[__MIN( i, i_word_max -1 )] = '\0';
-
-    *pp_buffer = p;
-
-}
-static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
-{
-    char *p;
-
-    for( p = *pp_buffer; p < p_end; p++ )
-    {
-        if( p + 1 < p_end && *p == '\n' )
-        {
-            *pp_buffer = p + 1;
-            return VLC_SUCCESS;
-        }
-        if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
-        {
-            *pp_buffer = p + 2;
-            return VLC_SUCCESS;
-        }
-    }
-    *pp_buffer = p_end;
-    return VLC_EGENERIC;
-}
-
-/*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/
-static void b64_decode( char *dest, char *src )
-{
-    int  i_level;
-    int  last = 0;
-    int  b64[256] = {
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
-        52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
-        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
-        15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
-        -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
-        41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
-        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
-        };
-
-    for( i_level = 0; *src != '\0'; src++ )
-    {
-        int  c;
-
-        c = b64[(unsigned int)*src];
-        if( c == -1 )
-        {
-            src++;
-            continue;
-        }
-
-        switch( i_level )
-        {
-            case 0:
-                i_level++;
-                break;
-            case 1:
-                *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
-                i_level++;
-                break;
-            case 2:
-                *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
-                i_level++;
-                break;
-            case 3:
-                *dest++ = ( ( last &0x03 ) << 6 ) | c;
-                i_level = 0;
-        }
-        last = c;
-    }
-
-    *dest = '\0';
-}
-
-static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection_t *p_con )
-{
-    char *psz_status;
-    char *p, *p_end;
-
-    int  i;
-    int  b_xplaystream = VLC_FALSE;
-    /* Size is checked for all of these */
-    char command[32];
-    char url[1024];
-    char version[32];
-    char user[512] = "";
-    char password[512] = "";
-
-    msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
-
-
-    p = p_con->p_buffer;
-    p_end = p + strlen( p ) + 1;
-
-    httpd_RequestGetWord( command, 32, &p, p_end );
-    httpd_RequestGetWord( url, 1024, &p, p_end );
-    httpd_RequestGetWord( version, 32, &p, p_end );
-#if 0
-    msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
-#endif
-    p_con->p_request      = NULL;
-    p_con->i_request_size = 0;
-    if( !strcmp( command, "GET" ) )
-    {
-        p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
-    }
-    else if( !strcmp( command, "POST" ))
-    {
-        p_con->i_method = HTTPD_CONNECTION_METHOD_POST;
-    }
-    else if( !strcmp( command, "HEAD" ))
-    {
-        p_con->i_method = HTTPD_CONNECTION_METHOD_HEAD;
-    }
-    else
-    {
-        /* unimplemented */
-        p_con->psz_file = strdup( "/501.html" );
-        p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
-        p_con->i_http_error = 501;
-        goto create_header;
-    }
-
-    if( strcmp( version, "HTTP/1.0" ) && strcmp( version, "HTTP/1.1" ) )
-    {
-        p_con->psz_file = strdup( "/505.html" );
-        p_con->i_http_error = 505;
-
-        goto create_header;
-    }
-
-    /* parse headers */
-    for( ;; )
-    {
-        char header[1024];
-
-        if( httpd_RequestNextLine( &p, p_end ) )
-        {
-#if 0
-            msg_Dbg( p_httpt, "failled new line" );
-#endif
-            break;;
-        }
-#if 0
-        msg_Dbg( p_httpt, "new line=%s", p );
-#endif
-        httpd_RequestGetWord( header, 1024, &p, p_end );
-        if( !strcmp( header, "\r\n" ) || !strcmp( header, "\n" ) )
-        {
-            break;
-        }
-
-        if( !strcmp( header, "Authorization:" ) )
-        {
-            char method[32];
-
-            httpd_RequestGetWord( method, 32, &p, p_end );
-            if( !strcasecmp( method, "BASIC" ) )
-            {
-                char basic[1024];
-                char decoded[1024];
-
-                httpd_RequestGetWord( basic, 1024, &p, p_end );
-#if 0
-                msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
-#endif
-                b64_decode( decoded, basic );
-#if 0
-                msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
-#endif
-                if( strchr( decoded, ':' ) )
-                {
-                    char *p = strchr( decoded, ':' );
-
-                    p[0] = '\0'; p++;
-                    strcpy( user, decoded );
-                    strcpy( password, p );
-                }
-            }
-        }
-        else if( !strcmp( header, "Pragma:" ) )
-        {
-            char method[128];
-
-            httpd_RequestGetWord( method, 128, &p, p_end );
-            if( !strcasecmp( method, "xPlayStrm=1" ) )
-            {
-                b_xplaystream = VLC_TRUE;
-            }
-        }
-    }
-
-    if( strchr( url, '?' ) )
-    {
-        char *p_request = strchr( url, '?' );
-        *p_request++ = '\0';
-        p_con->psz_file = strdup( url );
-        p_con->p_request = strdup( p_request );
-        p_con->i_request_size = strlen( p_con->p_request );
-    }
-    else
-    {
-        p_con->psz_file = strdup( url );
-    }
-
-    /* fix p_request */
-    if( p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
-    {
-        char *p_request;
-        if( strstr( p_con->p_buffer, "\r\n\r\n" ) )
-        {
-            p_request = strstr( p_con->p_buffer, "\r\n\r\n" ) + 4;
-        }
-        else if( strstr( p_con->p_buffer, "\n\n" ) )
-        {
-            p_request = strstr( p_con->p_buffer, "\n\n" ) + 2;
-        }
-        else
-        {
-            p_request = NULL;
-        }
-        if( p_request && p_request < p_end )
-        {
-            p_con->i_request_size = p_end - p_request;
-            p_con->p_request = malloc( p_con->i_request_size + 1);
-            if( !p_con->p_request)
-            {
-                msg_Err( p_httpt, "Out of memory" );
-                return;
-            }
-            memcpy( p_con->p_request,
-                    p_request,
-                    p_con->i_request_size );
-
-            p_con->p_request[p_con->i_request_size] = '\0';
-        }
-    }
-    p_con->i_http_error = 200;
-
-create_header:
-#if 0
-    msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
-#endif
-    FREE( p_con->p_buffer );
-    p_con->i_buffer = 0;
-    p_con->i_buffer_size = 0;
-
-#if 0
-    vlc_mutex_lock( &p_httpt->file_lock );
-#endif
-search_file:
-    /* search file */
-    p_con->p_file = NULL;
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        /* Our strdup call failed */
-        if( !p_con->psz_file ) return;
-        if( !strcmp( p_httpt->file[i]->psz_file, p_con->psz_file ) )
-        {
-            if( p_httpt->file[i]->b_stream ||
-                p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD ||
-                ( p_con->i_method == HTTPD_CONNECTION_METHOD_GET  && p_httpt->file[i]->pf_get ) ||
-                ( p_con->i_method == HTTPD_CONNECTION_METHOD_POST && p_httpt->file[i]->pf_post ) )
-            {
-                p_con->p_file = p_httpt->file[i];
-                break;
-            }
-        }
-    }
-
-    if( !p_con->p_file )
-    {
-        p_con->psz_file = strdup( "/404.html" );
-        p_con->i_http_error = 404;
-        p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
-
-        /* XXX be sure that "/404.html" exist else ... */
-        goto search_file;
-    }
-    if( p_con->p_file->i_authenticate_method == HTTPD_AUTHENTICATE_BASIC )
-    {
-        if( strcmp( user, p_con->p_file->psz_user ) ||
-            strcmp( password, p_con->p_file->psz_password ) )
-        {
-            p_con->psz_file = strdup( "/401.html" );
-            strcpy( user, p_con->p_file->psz_user );
-            p_con->i_http_error = 401;
-            p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
-
-            /* XXX do not put password on 404 else ... */
-            goto search_file;
-        }
-    }
-    if( !strcmp( p_con->p_file->psz_mime, "video/x-ms-asf-stream" ) &&
-        p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
-    {
-        p_con->psz_file = strdup( "/400.html" );
-        p_con->i_http_error = 400;
-        p_con->i_method = HTTPD_CONNECTION_METHOD_GET;
-
-        goto search_file;
-    }
-
-    p_con->p_file->i_ref++;
-#if 0
-    vlc_mutex_unlock( &p_httpt->file_lock );
-#endif
-
-    switch( p_con->i_http_error )
-    {
-        case 200:
-            psz_status = "OK";
-            break;
-        case 400:
-            psz_status = "Bad Request";
-            break;
-        case 401:
-            psz_status = "Authorization Required";
-            break;
-        default:
-            psz_status = "Unknown";
-            break;
-    }
-
-    p_con->i_state = HTTPD_CONNECTION_SENDING_HEADER;
-
-    p_con->i_buffer_size = 4096;
-    p_con->i_buffer = 0;
-
-    /* we send stream header with this one */
-    if( p_con->i_http_error == 200 && p_con->p_file->b_stream )
-    {
-        p_con->i_buffer_size += p_con->p_file->i_header_size;
-    }
-
-    p = p_con->p_buffer = malloc( p_con->i_buffer_size );
-    if( !p)
-    {
-        msg_Err( p_httpt, "Out of memory" );
-        return;
-    }
-    p += sprintf( p, "HTTP/1.0 %d %s\r\n", p_con->i_http_error, psz_status );
-
-    /* Special mmsh case cludgy but ...*/
-    if( !strcmp( p_con->p_file->psz_mime, "video/x-ms-asf-stream" ) &&
-        p_con->i_method == HTTPD_CONNECTION_METHOD_GET )
-    {
-        p += sprintf( p, "Content-type: application/octet-stream\r\n" );
-        p += sprintf( p, "Server: Cougar 4.1.0.3921\r\n" );
-        p += sprintf( p, "Cache-Control: no-cache\r\n" );
-        p += sprintf( p, "Pragma: no-cache\r\n" );
-        p += sprintf( p, "Pragma: client-id=%d\r\n", rand()&0x7fff );
-        p += sprintf( p, "Pragma: features=\"broadcast\"\r\n" );
-
-        if( !b_xplaystream )
-        {
-            p_con->i_method = HTTPD_CONNECTION_METHOD_ASFHEAD;
-        }
-    }
-    else
-    {
-        p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
-        p += sprintf( p, "Cache-Control: no-cache\r\n" );
-    }
-    if( p_con->i_http_error == 401 )
-    {
-        p += sprintf( p, "WWW-Authenticate: Basic realm=\"%s\"\r\n", user );
-    }
-#if 0
-    if( p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD )
-    {
-        p += sprintf( p, "Content-Length: 0\r\n" );
-    }
-    else if( p_con->i_method == HTTPD_CONNECTION_METHOD_ASFHEAD &&
-             p_con->p_file->i_header_size > 0 )
-    {
-        p += sprintf( p, "Content-Length: %d\r\n", p_con->p_file->i_header_size );
-    }
-#endif
-    p += sprintf( p, "\r\n" );
-
-    p_con->i_buffer_size = strlen( p_con->p_buffer );// + 1;
-
-    if( p_con->i_http_error == 200 &&
-        p_con->i_method != HTTPD_CONNECTION_METHOD_HEAD &&
-        p_con->p_file->b_stream && p_con->p_file->i_header_size > 0 )
-    {
-        /* add stream header */
-        memcpy( &p_con->p_buffer[p_con->i_buffer_size],
-                p_con->p_file->p_header,
-                p_con->p_file->i_header_size );
-        p_con->i_buffer_size += p_con->p_file->i_header_size;
-    }
-
-    if( p_con->i_method == HTTPD_CONNECTION_METHOD_ASFHEAD )
-    {
-        p_con->i_method = HTTPD_CONNECTION_METHOD_HEAD;
-    }
-#if 0
-    msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
-#endif
-}
-#define HTTPD_STREAM_PACKET 10000
-static void httpd_Thread( httpd_sys_t *p_httpt )
-{
-    httpd_file_t    *p_page_400;
-    httpd_file_t    *p_page_401;
-    httpd_file_t    *p_page_404;
-
-    httpd_connection_t *p_con;
-
-    msg_Info( p_httpt, "httpd started" );
-
-    p_page_400 = _RegisterFile( p_httpt,
-                                "/400.html", "text/html",
-                                NULL, NULL,
-                                httpd_page_400_get,
-                                NULL,
-                                (httpd_file_callback_args_t*)NULL );
-
-    p_page_401 = _RegisterFile( p_httpt,
-                                "/401.html", "text/html",
-                                NULL, NULL,
-                                httpd_page_401_get,
-                                NULL,
-                                (httpd_file_callback_args_t*)NULL );
-    p_page_404 = _RegisterFile( p_httpt,
-                                "/404.html", "text/html",
-                                NULL, NULL,
-                                httpd_page_404_get,
-                                NULL,
-                                (httpd_file_callback_args_t*)NULL );
-
-    while( !p_httpt->b_die )
-    {
-        struct timeval  timeout;
-        fd_set          fds_read;
-        fd_set          fds_write;
-        int             i_handle_max = 0;
-        int             i_ret;
-        int i;
-        if( p_httpt->i_host_count <= 0 )
-        {
-            msleep( 100 * 1000 );
-            continue;
-        }
-
-        /* we will create a socket set with host and connection */
-        FD_ZERO( &fds_read );
-        FD_ZERO( &fds_write );
-
-        vlc_mutex_lock( &p_httpt->host_lock );
-        vlc_mutex_lock( &p_httpt->connection_lock );
-        for( i = 0; i < p_httpt->i_host_count; i++ )
-        {
-            FD_SET( p_httpt->host[i]->fd, &fds_read );
-            i_handle_max = __MAX( i_handle_max, p_httpt->host[i]->fd );
-        }
-        for( p_con = p_httpt->p_first_connection; p_con != NULL; )
-        {
-            /* no more than 10s of inactivity */
-            if( p_con->i_last_activity_date + (mtime_t)HTTPD_CONNECTION_MAX_UNUSED < mdate() ||
-                p_con->i_state == HTTPD_CONNECTION_TO_BE_CLOSED)
-            {
-                httpd_connection_t *p_next = p_con->p_next;
-
-                msg_Dbg( p_httpt,  "close unused connection" );
-                httpd_ConnnectionClose( p_httpt, p_con );
-                p_con = p_next;
-                continue;
-            }
-
-            if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM && p_con->i_stream_pos + HTTPD_STREAM_PACKET >= p_con->p_file->i_buffer_pos )
-            {
-                p_con = p_con->p_next;
-                continue;
-            }
-
-            if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
-            {
-                FD_SET( p_con->fd, &fds_read );
-            }
-            else
-            {
-                FD_SET( p_con->fd, &fds_write );
-            }
-            i_handle_max = __MAX( i_handle_max, p_con->fd );
-
-            p_con = p_con->p_next;
-        }
-        vlc_mutex_unlock( &p_httpt->host_lock );
-        vlc_mutex_unlock( &p_httpt->connection_lock );
-
-        /* we will wait 0.5s */
-        timeout.tv_sec = 0;
-        timeout.tv_usec = 500*1000;
-
-        i_ret = select( i_handle_max + 1,
-                        &fds_read,
-                        &fds_write,
-                        NULL,
-                        &timeout );
-        if( i_ret == -1 && errno != EINTR )
-        {
-            msg_Warn( p_httpt, "cannot select sockets" );
-            msleep( 1000 );
-            continue;
-        }
-
-        if( i_ret <= 0 )
-        {
-            continue;
-        }
-
-        vlc_mutex_lock( &p_httpt->host_lock );
-        /* accept/refuse new connection */
-        for( i = 0; i < p_httpt->i_host_count; i++ )
-        {
-            int     i_sock_size = sizeof( struct sockaddr_in );
-            struct  sockaddr_in sock;
-            int     fd;
-
-            fd = accept( p_httpt->host[i]->fd, (struct sockaddr *)&sock,
-                         &i_sock_size );
-            if( fd > 0 )
-            {
-#if defined( WIN32 ) || defined( UNDER_CE )
-                {
-                    unsigned long i_dummy = 1;
-                    ioctlsocket( fd, FIONBIO, &i_dummy );
-                }
-#else
-                fcntl( fd, F_SETFL, O_NONBLOCK );
-#endif
-
-                if( p_httpt->i_connection_count >= HTTPD_MAX_CONNECTION )
-                {
-                    msg_Warn( p_httpt, "max connection reached" );
-                    SOCKET_CLOSE( fd );
-                    continue;
-                }
-                /* create a new connection and link it */
-                httpd_ConnnectionNew( p_httpt, fd, &sock );
-
-            }
-        }
-        vlc_mutex_unlock( &p_httpt->host_lock );
-
-        vlc_mutex_lock( &p_httpt->file_lock );
-        /* now do work for all connections */
-        for( p_con = p_httpt->p_first_connection; p_con != NULL; )
-        {
-            if( p_con->i_state == HTTPD_CONNECTION_RECEIVING_REQUEST )
-            {
-                int i_len;
-                /* read data */
-                i_len = recv( p_con->fd,
-                              p_con->p_buffer + p_con->i_buffer,
-                              p_con->i_buffer_size - p_con->i_buffer, 0 );
-
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-                if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
-#else
-                if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
-#endif
-                {
-                    httpd_connection_t *p_next = p_con->p_next;
-
-                    httpd_ConnnectionClose( p_httpt, p_con );
-                    p_con = p_next;
-                }
-                else if( i_len > 0 )
-                {
-                    uint8_t *ptr;
-                    p_con->i_last_activity_date = mdate();
-                    p_con->i_buffer += i_len;
-
-                    ptr = p_con->p_buffer + p_con->i_buffer;
-
-                    if( ( p_con->i_buffer >= 2 && !strncmp( ptr - 2, "\n\n", 2 ) )||
-                        ( p_con->i_buffer >= 4 && !strncmp( ptr - 4, "\r\n\r\n", 4 ) ) ||
-                        p_con->i_buffer >= p_con->i_buffer_size )
-                    {
-                        p_con->p_buffer[__MIN( p_con->i_buffer, p_con->i_buffer_size - 1 )] = '\0';
-                        httpd_ConnectionParseRequest( p_httpt, p_con );
-                    }
-
-                    p_con = p_con->p_next;
-                }
-                else
-                {
-                    p_con = p_con->p_next;
-                }
-                continue;   /* just for clarity */
-            }
-            else if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER || p_con->i_state == HTTPD_CONNECTION_SENDING_FILE )
-            {
-                int i_len;
-
-                /* write data */
-                if( p_con->i_buffer_size - p_con->i_buffer > 0 )
-                {
-                    i_len = send( p_con->fd, p_con->p_buffer + p_con->i_buffer, p_con->i_buffer_size - p_con->i_buffer, 0 );
-                }
-                else
-                {
-                    i_len = 0;
-                }
-#if 0
-                msg_Warn( p_httpt, "on %d send %d bytes %s", p_con->i_buffer_size, i_len, p_con->p_buffer + p_con->i_buffer );
-#endif
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-                if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
-#else
-                if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
-#endif
-                {
-                    httpd_connection_t *p_next = p_con->p_next;
-
-                    httpd_ConnnectionClose( p_httpt, p_con );
-                    p_con = p_next;
-                }
-                else if( i_len > 0 )
-                {
-                    p_con->i_last_activity_date = mdate();
-                    p_con->i_buffer += i_len;
-
-                    if( p_con->i_buffer >= p_con->i_buffer_size )
-                    {
-                        if( p_con->i_state == HTTPD_CONNECTION_SENDING_HEADER )
-                        {
-                            p_con->i_buffer_size = 0;
-                            p_con->i_buffer = 0;
-                            FREE( p_con->p_buffer );
-
-                            if( !p_con->p_file->b_stream || p_con->i_method == HTTPD_CONNECTION_METHOD_HEAD )
-                            {
-                                p_con->i_state = HTTPD_CONNECTION_SENDING_FILE; /* be sure to out from HTTPD_CONNECTION_SENDING_HEADER */
-                                if( p_con->i_method == HTTPD_CONNECTION_METHOD_GET )
-                                {
-                                    p_con->p_file->pf_get( p_con->p_file->p_sys,
-                                                           p_con->p_request, p_con->i_request_size,
-                                                           &p_con->p_buffer, &p_con->i_buffer_size );
-                                }
-                                else if( p_con->i_method == HTTPD_CONNECTION_METHOD_POST )
-                                {
-                                    p_con->p_file->pf_post( p_con->p_file->p_sys,
-                                                            p_con->p_request, p_con->i_request_size,
-                                                            &p_con->p_buffer, &p_con->i_buffer_size );
-                                }
-                                else
-                                {
-                                    /* HTTPD_CONNECTION_METHOD_HEAD for example */
-                                    p_con->p_buffer = NULL;
-                                    p_con->i_buffer_size = 0;
-                                }
-                            }
-                            else
-                            {
-                                p_con->i_state = HTTPD_CONNECTION_SENDING_STREAM;
-                                p_con->i_stream_pos = p_con->p_file->i_buffer_last_pos;
-                            }
-                            p_con = p_con->p_next;
-                        }
-                        else
-                        {
-                            httpd_connection_t *p_next = p_con->p_next;
-
-                            httpd_ConnnectionClose( p_httpt, p_con );
-                            p_con = p_next;
-                        }
-                    }
-                    else
-                    {
-                        p_con = p_con->p_next;
-                    }
-                }
-                else
-                {
-                    p_con = p_con->p_next;
-                }
-                continue;   /* just for clarity */
-            }
-            else if( p_con->i_state == HTTPD_CONNECTION_SENDING_STREAM )
-            {
-                httpd_stream_t *p_stream = p_con->p_file;
-                int i_send;
-                int i_write;
-
-                if( p_con->i_stream_pos < p_stream->i_buffer_pos )
-                {
-                    int i_pos;
-                    /* check if this p_con aren't to late */
-                    if( p_con->i_stream_pos + p_stream->i_buffer_size < p_stream->i_buffer_pos )
-                    {
-                        fprintf( stderr, "fixing i_stream_pos (old=%lld i_buffer_pos=%lld\n",
-                                 p_con->i_stream_pos, p_stream->i_buffer_pos  );
-                        p_con->i_stream_pos = p_stream->i_buffer_last_pos;
-                    }
-
-                    i_pos = p_con->i_stream_pos % p_stream->i_buffer_size;
-                    /* size until end of buffer */
-                    i_write = p_stream->i_buffer_size - i_pos;
-                    /* is it more than valid data */
-                    if( i_write >= p_stream->i_buffer_pos - p_con->i_stream_pos )
-                    {
-                        i_write = p_stream->i_buffer_pos - p_con->i_stream_pos;
-                    }
-                    /* limit to HTTPD_STREAM_PACKET */
-                    if( i_write > HTTPD_STREAM_PACKET )
-                    {
-                        i_write = HTTPD_STREAM_PACKET;
-                    }
-                    i_send = send( p_con->fd, &p_stream->p_buffer[i_pos], i_write, 0 );
-
-#if defined( WIN32 ) || defined( UNDER_CE )
-                    if( ( i_send < 0 && WSAGetLastError() != WSAEWOULDBLOCK )|| ( i_send == 0 ) )
-#else
-                    if( ( i_send < 0 && errno != EAGAIN && errno != EINTR )|| ( i_send == 0 ) )
-#endif
-                    {
-                        httpd_connection_t *p_next = p_con->p_next;
-
-                        httpd_ConnnectionClose( p_httpt, p_con );
-                        p_con = p_next;
-                        continue;
-                    }
-                    else if( i_send > 0 )
-                    {
-                        p_con->i_last_activity_date = mdate();
-                        p_con->i_stream_pos += i_send;
-                    }
-                }
-                p_con = p_con->p_next;
-                continue;   /* just for clarity */
-            }
-            else if( p_con->i_state != HTTPD_CONNECTION_TO_BE_CLOSED )
-            {
-                msg_Warn( p_httpt, "cannot occur (Invalid p_con->i_state)" );
-                p_con = p_con->p_next;
-            }
-        }   /* for over connection */
-
-        vlc_mutex_unlock( &p_httpt->file_lock );
-    }
-
-    msg_Info( p_httpt, "httpd stopped" );
-
-    _UnregisterFile( p_httpt, p_page_400 );
-    _UnregisterFile( p_httpt, p_page_401 );
-    _UnregisterFile( p_httpt, p_page_404 );
-}
diff --git a/src/misc/httpd.c b/src/misc/httpd.c
new file mode 100644 (file)
index 0000000..d758110
--- /dev/null
@@ -0,0 +1,2125 @@
+/*****************************************************************************
+ * httpd.c
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id: httpd.c,v 1.1 2004/03/03 13:23:47 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <vlc/vlc.h>
+
+#include "vlc_httpd.h"
+
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#if defined( UNDER_CE )
+#   include <winsock.h>
+#elif defined( WIN32 )
+#   include <winsock2.h>
+#   include <ws2tcpip.h>
+#   ifndef IN_MULTICAST
+#       define IN_MULTICAST(a) IN_CLASSD(a)
+#   endif
+#else
+#   include <netdb.h>                                         /* hostent ... */
+#   include <sys/socket.h>
+#   include <netinet/in.h>
+#   ifdef HAVE_ARPA_INET_H
+#       include <arpa/inet.h>                    /* inet_ntoa(), inet_aton() */
+#   endif
+#endif
+
+#if 0
+typedef struct httpd_t          httpd_t;
+
+typedef struct httpd_host_t     httpd_host_t;
+typedef struct httpd_url_t      httpd_url_t;
+typedef struct httpd_client_t   httpd_client_t;
+
+enum
+{
+    HTTPD_MSG_NONE,
+
+    /* answer */
+    HTTPD_MSG_ANSWER,
+
+    /* channel communication */
+    HTTPD_MSG_CHANNEL,
+
+    /* http request */
+    HTTPD_MSG_GET,
+    HTTPD_MSG_HEAD,
+    HTTPD_MSG_POST,
+
+    /* rtsp request */
+    HTTPD_MSG_OPTIONS,
+    HTTPD_MSG_DESCRIBE,
+    HTTPD_MSG_SETUP,
+    HTTPD_MSG_PLAY,
+    HTTPD_MSG_PAUSE,
+    HTTPD_MSG_TEARDOWN,
+
+    /* just to track the count of MSG */
+    HTTPD_MSG_MAX
+};
+
+enum
+{
+    HTTPD_PROTO_NONE,
+    HTTPD_PROTO_HTTP,
+    HTTPD_PROTO_RTSP,
+};
+
+typedef struct
+{
+    httpd_client_t *cl; /* NULL if not throught a connection e vlc internal */
+
+    int     i_type;
+    int     i_proto;
+    int     i_version;
+
+    /* for an answer */
+    int     i_status;
+    char    *psz_status;
+
+    /* for a query */
+    char    *psz_url;
+    char    *psz_args;  /* FIXME find a clean way to handle GET(psz_args) and POST(body) through the same code */
+
+    /* for rtp over rtsp */
+    int     i_channel;
+
+    /* options */
+    int     i_name;
+    char    **name;
+    int     i_value;
+    char    **value;
+
+    /* body */
+    int64_t i_body_offset;
+    int     i_body;
+    uint8_t *p_body;
+
+} httpd_message_t;
+
+typedef struct httpd_callback_sys_t httpd_callback_sys_t;
+/* answer could be null, int this case no answer is requested */
+typedef int (*httpd_callback_t)( httpd_callback_sys_t *, httpd_client_t *, httpd_message_t *answer, httpd_message_t *query );
+
+
+/* create a new host */
+httpd_host_t *httpd_HostNew( vlc_object_t *, char *psz_host, int i_port );
+/* delete a host */
+void          httpd_HostDelete( httpd_host_t * );
+
+/* register a new url */
+httpd_url_t *httpd_UrlNew( httpd_host_t *, char *psz_url );
+/* register callback on a url */
+int          httpd_UrlCatch( httpd_url_t *, int i_msg,
+                             httpd_callback_t, httpd_callback_sys_t * );
+/* delete an url */
+void         httpd_UrlDelete( httpd_url_t * );
+
+
+void         httpd_ClientModeStream( httpd_client_t *cl );
+void         httpd_ClientModeBidir( httpd_client_t *cl );
+
+/* High level */
+typedef struct httpd_file_t     httpd_file_t;
+typedef struct httpd_file_sys_t httpd_file_sys_t;
+typedef int (*httpd_file_callback_t)( httpd_file_sys_t*, httpd_file_t *, uint8_t *psz_request, uint8_t **pp_data, int *pi_data );
+httpd_file_t *httpd_FileNew( httpd_host_t *,
+                             char *psz_url, char *psz_mime,
+                             char *psz_user, char *psz_password,
+                             httpd_file_callback_t pf_fill,
+                             httpd_file_sys_t *p_sys );
+void         httpd_FileDelete( httpd_file_t * );
+
+typedef struct httpd_redirect_t httpd_redirect_t;
+httpd_redirect_t *httpd_RedirectNew( httpd_host_t *, char *psz_url_dst, char *psz_url_src );
+void              httpd_RedirectDelete( httpd_redirect_t * );
+
+#if 0
+typedef struct httpd_stream_t httpd_stream_t;
+httpd_stream_t *httpd_StreamNew( httpd_host_t * );
+int             httpd_StreamHeader( httpd_stream_t *, uint8_t *p_data, int i_data );
+int             httpd_StreamSend( httpd_stream_t *, uint8_t *p_data, int i_data );
+void            httpd_StreamDelete( httpd_stream_t * );
+#endif
+
+/* Msg functions facilities */
+void         httpd_MsgInit( httpd_message_t * );
+void         httpd_MsgAdd( httpd_message_t *, char *psz_name, char *psz_value, ... );
+/* return "" if not found. The string is not allocated */
+char        *httpd_MsgGet( httpd_message_t *, char *psz_name );
+void         httpd_MsgClean( httpd_message_t * );
+#endif
+
+#if 0
+struct httpd_t
+{
+    VLC_COMMON_MEMBERS
+
+    /* vlc_mutex_t  lock; */
+    int          i_host;
+    httpd_host_t **host;
+};
+#endif
+
+/* each host run in his own thread */
+struct httpd_host_t
+{
+    VLC_COMMON_MEMBERS
+
+    httpd_t     *httpd;
+
+    /* ref count */
+    int         i_ref;
+
+    /* address/port and socket for listening at connections */
+    struct sockaddr_in sock;
+    int                fd;
+
+    vlc_mutex_t lock;
+
+    /* all registered url (becarefull that 2 httpd_url_t could point at the same url)
+     * This will slow down the url research but make my live easier
+     * All url will have their cb trigger, but only the first one can answer
+     * */
+    int         i_url;
+    httpd_url_t **url;
+
+    int            i_client;
+    httpd_client_t **client;
+};
+
+struct httpd_url_t
+{
+    httpd_host_t *host;
+
+    vlc_mutex_t lock;
+
+    char    *psz_url;
+    char    *psz_user;
+    char    *psz_password;
+
+    struct
+    {
+        httpd_callback_t     cb;
+        httpd_callback_sys_t *p_sys;
+    } catch[HTTPD_MSG_MAX];
+};
+
+/* status */
+enum
+{
+    HTTPD_CLIENT_RECEIVING,
+    HTTPD_CLIENT_RECEIVE_DONE,
+
+    HTTPD_CLIENT_SENDING,
+    HTTPD_CLIENT_SEND_DONE,
+
+    HTTPD_CLIENT_WAITING,
+
+    HTTPD_CLIENT_DEAD,
+};
+/* mode */
+enum
+{
+    HTTPD_CLIENT_FILE,      /* default */
+    HTTPD_CLIENT_STREAM,    /* regulary get data from cb */
+    HTTPD_CLIENT_BIDIR,     /* check for reading and get data from cb */
+};
+
+struct httpd_client_t
+{
+    httpd_url_t *url;
+
+    int     i_ref;
+
+    struct  sockaddr_in sock;
+    int     fd;
+
+    int     i_mode;
+    int     i_state;
+    int     b_read_waiting; /* stop as soon as possible sending */
+
+    mtime_t i_activity_date;
+    mtime_t i_activity_timeout;
+
+    /* buffer for reading header */
+    int     i_buffer_size;
+    int     i_buffer;
+    uint8_t *p_buffer;
+
+    /* */
+    httpd_message_t query;  /* client -> httpd */
+    httpd_message_t answer; /* httpd -> client */
+};
+
+
+/*****************************************************************************
+ * Various functions
+ *****************************************************************************/
+/*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/
+static void b64_decode( char *dest, char *src )
+{
+    int  i_level;
+    int  last = 0;
+    int  b64[256] = {
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 00-0F */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 10-1F */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,  /* 20-2F */
+        52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1,  /* 30-3F */
+        -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,  /* 40-4F */
+        15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,  /* 50-5F */
+        -1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,  /* 60-6F */
+        41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,  /* 70-7F */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 80-8F */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* 90-9F */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* A0-AF */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* B0-BF */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* C0-CF */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* D0-DF */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,  /* E0-EF */
+        -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1   /* F0-FF */
+        };
+
+    for( i_level = 0; *src != '\0'; src++ )
+    {
+        int  c;
+
+        c = b64[(unsigned int)*src];
+        if( c == -1 )
+        {
+            continue;
+        }
+
+        switch( i_level )
+        {
+            case 0:
+                i_level++;
+                break;
+            case 1:
+                *dest++ = ( last << 2 ) | ( ( c >> 4)&0x03 );
+                i_level++;
+                break;
+            case 2:
+                *dest++ = ( ( last << 4 )&0xf0 ) | ( ( c >> 2 )&0x0f );
+                i_level++;
+                break;
+            case 3:
+                *dest++ = ( ( last &0x03 ) << 6 ) | c;
+                i_level = 0;
+        }
+        last = c;
+    }
+
+    *dest = '\0';
+}
+
+static struct
+{
+    char *psz_ext;
+    char *psz_mime;
+} http_mime[] =
+{
+    { ".htm",   "text/html" },
+    { ".html",  "text/html" },
+    { ".txt",   "text/plain" },
+    { ".xml",   "text/xml" },
+    { ".dtd",   "text/dtd" },
+
+    { ".css",   "text/css" },
+
+    /* image mime */
+    { ".gif",   "image/gif" },
+    { ".jpe",   "image/jpeg" },
+    { ".jpg",   "image/jpeg" },
+    { ".jpeg",  "image/jpeg" },
+    { ".png",   "image/png" },
+
+    /* media mime */
+    { ".avi",   "video/avi" },
+    { ".asf",   "video/x-ms-asf" },
+    { ".m1a",   "audio/mpeg" },
+    { ".m2a",   "audio/mpeg" },
+    { ".m1v",   "video/mpeg" },
+    { ".m2v",   "video/mpeg" },
+    { ".mp2",   "audio/mpeg" },
+    { ".mp3",   "audio/mpeg" },
+    { ".mpa",   "audio/mpeg" },
+    { ".mpg",   "video/mpeg" },
+    { ".mpeg",  "video/mpeg" },
+    { ".mpe",   "video/mpeg" },
+    { ".mov",   "video/quicktime" },
+    { ".moov",  "video/quicktime" },
+    { ".ogg",   "application/ogg" },
+    { ".ogm",   "application/ogg" },
+    { ".wav",   "audio/wav" },
+    { ".wma",   "audio/x-ms-wma" },
+    { ".wmv",   "video/x-ms-wmv" },
+
+
+    /* end */
+    { NULL,     NULL }
+};
+static char *httpd_MimeFromUrl( char *psz_url )
+{
+
+    char *psz_ext;
+
+    psz_ext = strrchr( psz_url, '.' );
+    if( psz_ext )
+    {
+        int i;
+
+        for( i = 0; http_mime[i].psz_ext != NULL ; i++ )
+        {
+            if( !strcasecmp( http_mime[i].psz_ext, psz_ext ) )
+            {
+                return http_mime[i].psz_mime;
+            }
+        }
+    }
+    return "application/octet-stream";
+}
+
+/*****************************************************************************
+ * High Level Funtions: httpd_file_t
+ *****************************************************************************/
+struct httpd_file_t
+{
+    httpd_url_t *url;
+
+    char *psz_url;
+    char *psz_mime;
+
+    httpd_file_callback_t pf_fill;
+    httpd_file_sys_t      *p_sys;
+
+};
+
+
+static int httpd_FileCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
+{
+    httpd_file_t *file = (httpd_file_t*)p_sys;
+
+    if( answer == NULL || query == NULL )
+    {
+        return VLC_SUCCESS;
+    }
+    answer->i_proto  = HTTPD_PROTO_HTTP;
+    answer->i_version= query->i_version;
+    answer->i_type   = HTTPD_MSG_ANSWER;
+
+    answer->i_status = 200;
+    answer->psz_status = strdup( "OK" );
+
+    httpd_MsgAdd( answer, "Content-type",  "%s", file->psz_mime );
+    httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
+
+    if( query->i_type != HTTPD_MSG_HEAD )
+    {
+        char *psz_args = query->psz_args;
+        if( query->i_type == HTTPD_MSG_POST )
+        {
+            /* Check that */
+            psz_args = query->p_body;
+        }
+        file->pf_fill( file->p_sys, file, psz_args, &answer->p_body, &answer->i_body );
+    }
+    httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
+
+    return VLC_SUCCESS;
+}
+
+
+httpd_file_t *httpd_FileNew( httpd_host_t *host,
+                             char *psz_url, char *psz_mime,
+                             char *psz_user, char *psz_password,
+                             httpd_file_callback_t pf_fill,
+                             httpd_file_sys_t *p_sys )
+{
+    httpd_file_t *file = malloc( sizeof( httpd_file_t ) );
+
+    if( ( file->url = httpd_UrlNewUnique( host, psz_url, psz_user, psz_password ) ) == NULL )
+    {
+        free( file );
+        return NULL;
+    }
+
+    file->psz_url  = strdup( psz_url );
+    if( psz_mime && *psz_mime )
+    {
+        file->psz_mime = strdup( psz_mime );
+    }
+    else
+    {
+        file->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
+    }
+
+    file->pf_fill = pf_fill;
+    file->p_sys   = p_sys;
+
+    httpd_UrlCatch( file->url, HTTPD_MSG_HEAD, httpd_FileCallBack, (httpd_callback_sys_t*)file );
+    httpd_UrlCatch( file->url, HTTPD_MSG_GET,  httpd_FileCallBack, (httpd_callback_sys_t*)file );
+    httpd_UrlCatch( file->url, HTTPD_MSG_POST, httpd_FileCallBack, (httpd_callback_sys_t*)file );
+
+    return file;
+}
+
+void         httpd_FileDelete( httpd_file_t *file )
+{
+    httpd_UrlDelete( file->url );
+
+    free( file->psz_url );
+    free( file->psz_mime );
+
+    free( file );
+}
+
+/*****************************************************************************
+ * High Level Funtions: httpd_redirect_t
+ *****************************************************************************/
+struct httpd_redirect_t
+{
+    httpd_url_t *url;
+    char        *psz_dst;
+};
+
+static int httpd_RedirectCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
+{
+    httpd_redirect_t *rdir = (httpd_redirect_t*)p_sys;
+    uint8_t *p;
+
+    if( answer == NULL || query == NULL )
+    {
+        return VLC_SUCCESS;
+    }
+    answer->i_proto  = query->i_proto;
+    answer->i_version= query->i_version;
+    answer->i_type   = HTTPD_MSG_ANSWER;
+    answer->i_status = 301;
+    answer->psz_status = strdup( "Moved Permanently" );
+
+    p = answer->p_body = malloc( 1000 + strlen( rdir->psz_dst ) );
+    p += sprintf( p, "<html>\n" );
+    p += sprintf( p, "<head>\n" );
+    p += sprintf( p, "<title>Redirection</title>\n" );
+    p += sprintf( p, "</head>\n" );
+    p += sprintf( p, "<body>\n" );
+    p += sprintf( p, "<h1><center>You should be <a href=\"%s\">redirected</a></center></h1>\n", rdir->psz_dst );
+    p += sprintf( p, "<hr />\n" );
+    p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
+    p += sprintf( p, "</body>\n" );
+    p += sprintf( p, "</html>\n" );
+    answer->i_body = p - answer->p_body;
+
+    /* XXX check if it's ok or we need to set an absolute url */
+    httpd_MsgAdd( answer, "Location",  "%s", rdir->psz_dst );
+
+    httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
+
+    return VLC_SUCCESS;
+}
+
+httpd_redirect_t *httpd_RedirectNew( httpd_host_t *host, char *psz_url_dst, char *psz_url_src )
+{
+    httpd_redirect_t *rdir = malloc( sizeof( httpd_redirect_t ) );
+
+    if( ( rdir->url = httpd_UrlNewUnique( host, psz_url_src, NULL, NULL ) ) == NULL )
+    {
+        free( rdir );
+        return NULL;
+    }
+    rdir->psz_dst = strdup( psz_url_dst );
+    /* Redirect apply for all HTTP request and RTSP DESCRIBE resquest */
+    httpd_UrlCatch( rdir->url, HTTPD_MSG_HEAD,      httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir );
+    httpd_UrlCatch( rdir->url, HTTPD_MSG_GET,       httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir );
+    httpd_UrlCatch( rdir->url, HTTPD_MSG_POST,      httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir );
+
+    httpd_UrlCatch( rdir->url, HTTPD_MSG_DESCRIBE,  httpd_RedirectCallBack, (httpd_callback_sys_t*)rdir );
+
+    return rdir;
+}
+void              httpd_RedirectDelete( httpd_redirect_t *rdir )
+{
+    httpd_UrlDelete( rdir->url );
+    free( rdir->psz_dst );
+    free( rdir );
+}
+
+/*****************************************************************************
+ * High Level Funtions: httpd_stream_t
+ *****************************************************************************/
+struct httpd_stream_t
+{
+    vlc_mutex_t lock;
+    httpd_url_t *url;
+
+    char    *psz_mime;
+
+    /* Header to send as first packet */
+    uint8_t *p_header;
+    int     i_header;
+
+    /* circular buffer */
+    int         i_buffer_size;      /* buffer size, can't be reallocated smaller */
+    uint8_t     *p_buffer;          /* buffer */
+    int64_t     i_buffer_pos;       /* absolute position from begining */
+    int64_t     i_buffer_last_pos;  /* a new connection will start with that */
+};
+
+static int httpd_StreamCallBack( httpd_callback_sys_t *p_sys, httpd_client_t *cl, httpd_message_t *answer, httpd_message_t *query )
+{
+    httpd_stream_t *stream = (httpd_stream_t*)p_sys;
+
+    if( answer == NULL || query == NULL || cl == NULL )
+    {
+        return VLC_SUCCESS;
+    }
+    if( answer->i_body_offset > 0 )
+    {
+        int64_t i_write;
+        int     i_pos;
+
+        /* fprintf( stderr, "httpd_StreamCallBack i_body_offset=%lld\n", answer->i_body_offset ); */
+
+        if( answer->i_body_offset >= stream->i_buffer_pos )
+        {
+            /* fprintf( stderr, "httpd_StreamCallBack: no data\n" ); */
+            return VLC_EGENERIC;    /* wait, no data available */
+        }
+        if( answer->i_body_offset + stream->i_buffer_size < stream->i_buffer_pos )
+        {
+            /* this client isn't fast enough */
+            fprintf( stderr, "fixing i_body_offset (old=%lld new=%lld)\n",
+                     answer->i_body_offset, stream->i_buffer_last_pos );
+            answer->i_body_offset = stream->i_buffer_last_pos;
+        }
+
+        i_pos   = answer->i_body_offset % stream->i_buffer_size;
+        i_write = stream->i_buffer_pos - answer->i_body_offset;
+        if( i_write > 10000 )
+        {
+            i_write = 10000;
+        }
+        else if( i_write <= 0 )
+        {
+            return VLC_EGENERIC;    /* wait, no data available */
+        }
+
+        /* using HTTPD_MSG_ANSWER -> data available */
+        answer->i_proto  = HTTPD_PROTO_HTTP;
+        answer->i_version= 0;
+        answer->i_type   = HTTPD_MSG_ANSWER;
+
+        answer->i_body = i_write;
+        answer->p_body = malloc( i_write );
+        memcpy( answer->p_body, &stream->p_buffer[i_pos], i_write );
+
+        answer->i_body_offset += i_write;
+
+        return VLC_SUCCESS;
+    }
+    else
+    {
+        answer->i_proto  = HTTPD_PROTO_HTTP;
+        answer->i_version= 0;
+        answer->i_type   = HTTPD_MSG_ANSWER;
+
+        answer->i_status = 200;
+        answer->psz_status = strdup( "OK" );
+
+        if( query->i_type != HTTPD_MSG_HEAD )
+        {
+            httpd_ClientModeStream( cl );
+            vlc_mutex_lock( &stream->lock );
+            /* Send the header */
+            if( stream->i_header > 0 )
+            {
+                answer->i_body = stream->i_header;
+                answer->p_body = malloc( stream->i_header );
+                memcpy( answer->p_body, stream->p_header, stream->i_header );
+            }
+            answer->i_body_offset = stream->i_buffer_last_pos;
+            vlc_mutex_unlock( &stream->lock );
+        }
+        else
+        {
+            httpd_MsgAdd( answer, "Content-Length", "%d", 0 );
+        }
+
+        if( !strcmp( stream->psz_mime, "video/x-ms-asf-stream" ) )
+        {
+            vlc_bool_t b_xplaystream = VLC_FALSE;
+            int i;
+
+            httpd_MsgAdd( answer, "Content-type", "%s", "application/octet-stream" );
+            httpd_MsgAdd( answer, "Server", "Cougar 4.1.0.3921" );
+            httpd_MsgAdd( answer, "Pragma", "no-cache" );
+            httpd_MsgAdd( answer, "Pragma", "client-id=%d", rand()&0x7fff );
+            httpd_MsgAdd( answer, "Pragma", "features=\"broadcast\"" );
+
+            /* Check if there is a xPlayStrm=1 */
+            for( i = 0; i < query->i_name; i++ )
+            {
+                if( !strcasecmp( query->name[i],  "Pragma" ) &&
+                    !strcasecmp( query->value[i], "xPlayStrm=1" ) )
+                {
+                    b_xplaystream = VLC_TRUE;
+                }
+            }
+
+            if( !b_xplaystream )
+            {
+                answer->i_body_offset = 0;
+            }
+        }
+        else
+        {
+            httpd_MsgAdd( answer, "Content-type",  "%s", stream->psz_mime );
+        }
+        httpd_MsgAdd( answer, "Cache-Control", "%s", "no-cache" );
+        return VLC_SUCCESS;
+    }
+}
+
+httpd_stream_t *httpd_StreamNew( httpd_host_t *host,
+                                 char *psz_url, char *psz_mime,
+                                 char *psz_user, char *psz_password )
+{
+    httpd_stream_t *stream = malloc( sizeof( httpd_stream_t ) );
+
+    if( ( stream->url = httpd_UrlNewUnique( host, psz_url, psz_user, psz_password ) ) == NULL )
+    {
+        free( stream );
+        return NULL;
+    }
+    vlc_mutex_init( host, &stream->lock );
+    if( psz_mime && *psz_mime )
+    {
+        stream->psz_mime = strdup( psz_mime );
+    }
+    else
+    {
+        stream->psz_mime = strdup( httpd_MimeFromUrl( psz_url ) );
+    }
+    stream->i_header = 0;
+    stream->p_header = NULL;
+    stream->i_buffer_size = 5000000;    /* 5 Mo per stream */
+    stream->p_buffer = malloc( stream->i_buffer_size );
+    /* We set to 1, to make life simpler (this way i_body_offset can never be 0) */
+    stream->i_buffer_pos = 1;
+    stream->i_buffer_last_pos = 1;
+
+    httpd_UrlCatch( stream->url, HTTPD_MSG_HEAD, httpd_StreamCallBack, (httpd_callback_sys_t*)stream );
+    httpd_UrlCatch( stream->url, HTTPD_MSG_GET,  httpd_StreamCallBack, (httpd_callback_sys_t*)stream );
+    httpd_UrlCatch( stream->url, HTTPD_MSG_POST, httpd_StreamCallBack, (httpd_callback_sys_t*)stream );
+
+    return stream;
+}
+
+int  httpd_StreamHeader( httpd_stream_t *stream, uint8_t *p_data, int i_data )
+{
+    vlc_mutex_lock( &stream->lock );
+    if( stream->p_header )
+    {
+        free( stream->p_header );
+        stream->p_header = NULL;
+    }
+    stream->i_header = i_data;
+    if( i_data > 0 )
+    {
+        stream->p_header = malloc( i_data );
+        memcpy( stream->p_header, p_data, i_data );
+    }
+    vlc_mutex_unlock( &stream->lock );
+
+    return VLC_SUCCESS;
+}
+
+int  httpd_StreamSend( httpd_stream_t *stream, uint8_t *p_data, int i_data )
+{
+    int i_count;
+    int i_pos;
+
+    if( i_data < 0 || p_data == NULL )
+    {
+        return VLC_SUCCESS;
+    }
+    vlc_mutex_lock( &stream->lock );
+
+    /* save this pointer (to be used by new connection) */
+    stream->i_buffer_last_pos = stream->i_buffer_pos;
+
+    i_pos = stream->i_buffer_pos % stream->i_buffer_size;
+    i_count = i_data;
+    while( i_count > 0)
+    {
+        int i_copy;
+
+        i_copy = __MIN( i_count, stream->i_buffer_size - i_pos );
+
+        /* Ok, we can't go past the end of our buffer */
+        memcpy( &stream->p_buffer[i_pos], p_data, i_copy );
+
+        i_pos = ( i_pos + i_copy ) % stream->i_buffer_size;
+        i_count -= i_copy;
+        p_data  += i_copy;
+    }
+
+    stream->i_buffer_pos += i_data;
+
+    vlc_mutex_unlock( &stream->lock );
+    return VLC_SUCCESS;
+}
+
+void httpd_StreamDelete( httpd_stream_t *stream )
+{
+    httpd_UrlDelete( stream->url );
+    vlc_mutex_destroy( &stream->lock );
+    if( stream->psz_mime ) free( stream->psz_mime );
+    if( stream->p_header ) free( stream->p_header );
+    if( stream->p_buffer ) free( stream->p_buffer );
+    free( stream );
+}
+
+
+/*****************************************************************************
+ * Low level
+ *****************************************************************************/
+#define LISTEN_BACKLOG          100
+
+#if defined( WIN32 ) || defined( UNDER_CE )
+#define SOCKET_CLOSE(a)    closesocket(a)
+#else
+#define SOCKET_CLOSE(a)    close(a)
+#endif
+
+static void httpd_HostThread( httpd_host_t * );
+static int BuildAddr( struct sockaddr_in * p_socket,
+                      const char * psz_address, int i_port );
+
+
+/* create a new host */
+httpd_host_t *httpd_HostNew( vlc_object_t *p_this, char *psz_host, int i_port )
+{
+    httpd_t      *httpd;
+    httpd_host_t *host;
+    vlc_value_t lockval;
+    struct sockaddr_in sock;
+    int i;
+
+    /* resolv */
+    if( BuildAddr( &sock, psz_host, i_port ) )
+    {
+        msg_Err( p_this, "cannot build address for %s:%d", psz_host, i_port );
+        return NULL;
+    }
+
+    /* to be sure to avoid multiple creation */
+    var_Create( p_this->p_libvlc, "httpd_mutex", VLC_VAR_MUTEX );
+    var_Get( p_this->p_libvlc, "httpd_mutex", &lockval );
+    vlc_mutex_lock( lockval.p_address );
+
+    if( ( httpd = vlc_object_find( p_this, VLC_OBJECT_HTTPD, FIND_ANYWHERE ) ) == NULL )
+    {
+        msg_Info( p_this, "creating httpd" );
+        if( ( httpd = vlc_object_create( p_this, VLC_OBJECT_HTTPD ) ) == NULL )
+        {
+            vlc_mutex_unlock( lockval.p_address );
+            return NULL;
+        }
+
+        httpd->i_host = 0;
+        httpd->host   = NULL;
+
+        vlc_object_yield( httpd );
+        vlc_object_attach( httpd, p_this->p_vlc );
+    }
+
+    /* verify if it already exist */
+    for( i = 0; i < httpd->i_host; i++ )
+    {
+        if( httpd->host[i]->sock.sin_port == sock.sin_port &&
+            ( httpd->host[i]->sock.sin_addr.s_addr == INADDR_ANY ||
+              httpd->host[i]->sock.sin_addr.s_addr == sock.sin_addr.s_addr ) )
+        {
+            /* yep found */
+            host = httpd->host[i];
+            host->i_ref++;
+
+            vlc_mutex_unlock( lockval.p_address );
+
+            msg_Dbg( p_this, "host already registered" );
+            return host;
+        }
+    }
+    /* create the new host */
+    host = vlc_object_create( p_this, sizeof( httpd_host_t ) );
+    host->httpd = httpd;
+    vlc_mutex_init( httpd, &host->lock );
+    host->i_ref = 1;
+    memcpy( &host->sock, &sock, sizeof( struct sockaddr_in ) );
+    host->i_url     = 0;
+    host->url       = NULL;
+    host->i_client  = 0;
+    host->client    = NULL;
+
+    /* create the listening socket */
+    if( ( host->fd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
+    {
+        goto socket_error;
+    }
+    /* reuse socket */
+    i = 1;
+    if( setsockopt( host->fd, SOL_SOCKET, SO_REUSEADDR,
+                    (void *) &i, sizeof( i ) ) < 0 )
+    {
+        msg_Warn( p_this, "cannot configure socket (SO_REUSEADDR)" );
+    }
+    /* bind it */
+    if( bind( host->fd, (struct sockaddr *)&host->sock, sizeof( struct sockaddr_in ) ) < 0 )
+    {
+        msg_Err( p_this, "cannot bind socket" );
+        goto socket_error;
+    }
+    /* set to non-blocking */
+#if defined( WIN32 ) || defined( UNDER_CE )
+    {
+        unsigned long i_dummy = 1;
+        if( ioctlsocket( host->fd, FIONBIO, &i_dummy ) != 0 )
+        {
+            msg_Err( p_this, "cannot set socket to non-blocking mode" );
+            goto socket_error;
+        }
+    }
+#else
+    {
+        unsigned int i_flags;
+        if( ( i_flags = fcntl( host->fd, F_GETFL, 0 ) ) < 0 )
+        {
+            msg_Err( p_this, "cannot F_GETFL socket" );
+            goto socket_error;
+        }
+        if( fcntl( host->fd, F_SETFL, i_flags | O_NONBLOCK ) < 0 )
+        {
+            msg_Err( p_this, "cannot F_SETFL O_NONBLOCK" );
+            goto socket_error;
+        }
+    }
+#endif
+    /* listen */
+    if( listen( host->fd, LISTEN_BACKLOG ) < 0 )
+    {
+        msg_Err( p_this, "cannot listen socket" );
+        goto socket_error;
+    }
+
+    /* create the thread */
+    if( vlc_thread_create( host, "httpd host thread",
+                           httpd_HostThread, VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
+    {
+        msg_Err( p_this, "cannot spawn http host thread" );
+        goto socket_error;
+    }
+
+    /* now add it to httpd */
+    TAB_APPEND( httpd->i_host, httpd->host, host );
+    vlc_mutex_unlock( lockval.p_address );
+
+    return host;
+
+socket_error:
+    vlc_mutex_unlock( lockval.p_address );
+
+    if( host->fd > 0 )
+    {
+        SOCKET_CLOSE( host->fd );
+    }
+    vlc_mutex_destroy( &host->lock );
+    vlc_object_destroy( host );
+
+    /* TODO destroy no more used httpd TODO */
+    vlc_object_release( httpd );
+    return NULL;
+}
+
+/* delete a host */
+void          httpd_HostDelete( httpd_host_t *host )
+{
+    httpd_t *httpd = host->httpd;
+    vlc_value_t lockval;
+    int i;
+
+    msg_Dbg( host, "httpd_HostDelete" );
+
+    var_Get( httpd->p_libvlc, "httpd_mutex", &lockval );
+    vlc_mutex_lock( lockval.p_address );
+
+    vlc_object_release( httpd );
+
+    host->i_ref--;
+    if( host->i_ref > 0 )
+    {
+        /* still used */
+        vlc_mutex_unlock( lockval.p_address );
+        msg_Dbg( host, "httpd_HostDelete: host still used" );
+        return;
+    }
+    TAB_REMOVE( httpd->i_host, httpd->host, host );
+
+    msg_Dbg( host, "httpd_HostDelete: host removed from http" );
+
+    host->b_die = 1;
+    vlc_thread_join( host );
+
+    msg_Dbg( host, "httpd_HostDelete: host thread joined" );
+
+    for( i = 0; i < host->i_url; i++ )
+    {
+        msg_Err( host, "url still registered:%s", host->url[i]->psz_url );
+    }
+    for( i = 0; i < host->i_client; i++ )
+    {
+        httpd_client_t *cl = host->client[i];
+        msg_Warn( host, "client still connected" );
+        SOCKET_CLOSE( cl->fd );
+        /* TODO */
+    }
+
+    SOCKET_CLOSE( host->fd );
+    vlc_mutex_destroy( &host->lock );
+    vlc_object_destroy( host );
+
+    if( httpd->i_host <= 0 )
+    {
+        msg_Info( httpd, "httpd doesn't reference any host, deleting" );
+        vlc_object_detach( httpd );
+        vlc_object_destroy( httpd );
+    }
+    vlc_mutex_unlock( lockval.p_address );
+}
+
+/* register a new url */
+static httpd_url_t *httpd_UrlNewPrivate( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password, vlc_bool_t b_check )
+{
+    httpd_url_t *url;
+    int         i;
+
+    vlc_mutex_lock( &host->lock );
+    if( b_check )
+    {
+        for( i = 0; i < host->i_url; i++ )
+        {
+            if( !strcmp( psz_url, host->url[i]->psz_url ) )
+            {
+                msg_Warn( host->httpd,
+                          "cannot add '%s' (url already defined)", psz_url );
+                vlc_mutex_unlock( &host->lock );
+                return NULL;
+            }
+        }
+    }
+
+    url = malloc( sizeof( httpd_url_t ) );
+    url->host = host;
+
+    vlc_mutex_init( host->httpd, &url->lock );
+    url->psz_url = strdup( psz_url );
+    url->psz_user = strdup( psz_user ? psz_user : "" );
+    url->psz_password = strdup( psz_password ? psz_password : "" );
+    for( i = 0; i < HTTPD_MSG_MAX; i++ )
+    {
+        url->catch[i].cb = NULL;
+        url->catch[i].p_sys = NULL;
+    }
+
+    TAB_APPEND( host->i_url, host->url, url );
+    vlc_mutex_unlock( &host->lock );
+
+    return url;
+}
+
+httpd_url_t *httpd_UrlNew( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password )
+{
+    return httpd_UrlNewPrivate( host, psz_url, psz_user, psz_password, VLC_FALSE );
+}
+
+httpd_url_t *httpd_UrlNewUnique( httpd_host_t *host, char *psz_url, char *psz_user, char *psz_password )
+{
+    return httpd_UrlNewPrivate( host, psz_url, psz_user, psz_password, VLC_TRUE );
+}
+
+/* register callback on a url */
+int          httpd_UrlCatch( httpd_url_t *url, int i_msg,
+                             httpd_callback_t cb,
+                             httpd_callback_sys_t *p_sys )
+{
+    vlc_mutex_lock( &url->lock );
+    url->catch[i_msg].cb   = cb;
+    url->catch[i_msg].p_sys= p_sys;
+    vlc_mutex_unlock( &url->lock );
+
+    return VLC_SUCCESS;
+}
+
+
+/* delete an url */
+void         httpd_UrlDelete( httpd_url_t *url )
+{
+    httpd_host_t *host = url->host;
+    int          i;
+
+    vlc_mutex_lock( &host->lock );
+    TAB_REMOVE( host->i_url, host->url, url );
+
+    vlc_mutex_destroy( &url->lock );
+    free( url->psz_url );
+    free( url->psz_user );
+    free( url->psz_password );
+
+    for( i = 0; i < host->i_client; i++ )
+    {
+        httpd_client_t *client = host->client[i];
+
+        if( client->url == url )
+        {
+            /* TODO complete it */
+            msg_Warn( host, "force closing connections" );
+            SOCKET_CLOSE( client->fd );
+            TAB_REMOVE( host->i_client, host->client, client );
+            i--;
+        }
+    }
+    vlc_mutex_unlock( &host->lock );
+}
+
+void httpd_MsgInit( httpd_message_t *msg )
+{
+    msg->cl         = NULL;
+    msg->i_type     = HTTPD_MSG_NONE;
+    msg->i_proto    = HTTPD_PROTO_NONE;
+    msg->i_version  = -1;
+
+    msg->i_status   = 0;
+    msg->psz_status = NULL;
+
+    msg->psz_url = NULL;
+    msg->psz_args = NULL;
+
+    msg->i_channel = -1;
+
+    msg->i_name = 0;
+    msg->name   = NULL;
+    msg->i_value= 0;
+    msg->value  = NULL;
+
+    msg->i_body_offset = 0;
+    msg->i_body        = 0;
+    msg->p_body        = 0;
+}
+
+void httpd_MsgClean( httpd_message_t *msg )
+{
+    int i;
+
+    if( msg->psz_status )
+    {
+        free( msg->psz_status );
+    }
+    if( msg->psz_url )
+    {
+        free( msg->psz_url );
+    }
+    if( msg->psz_args )
+    {
+        free( msg->psz_args );
+    }
+    for( i = 0; i < msg->i_name; i++ )
+    {
+        free( msg->name[i] );
+        free( msg->value[i] );
+    }
+    if( msg->name )
+    {
+        free( msg->name );
+    }
+    if( msg->value )
+    {
+        free( msg->value );
+    }
+    if( msg->p_body )
+    {
+        free( msg->p_body );
+    }
+    httpd_MsgInit( msg );
+}
+
+char *httpd_MsgGet( httpd_message_t *msg, char *name )
+{
+    int i;
+
+    for( i = 0; i < msg->i_name; i++ )
+    {
+        if( !strcasecmp( msg->name[i], name ))
+        {
+            return msg->value[i];
+        }
+    }
+    return "";
+}
+void httpd_MsgAdd( httpd_message_t *msg, char *name, char *psz_value, ... )
+{
+    va_list args;
+    char *value = NULL;
+
+    va_start( args, psz_value );
+#if defined(HAVE_VASPRINTF) && !defined(SYS_DARWIN) && !defined(SYS_BEOS)
+    vasprintf( &value, psz_value, args );
+#else
+    {
+        int i_size = strlen( psz_value ) + 4096;    /* FIXME stupid system */
+        value = calloc( i_size, sizeof( char ) );
+        vsnprintf( value, i_size, psz_value, args );
+        value[i_size - 1] = 0;
+    }
+#endif
+    va_end( args );
+
+    name = strdup( name );
+
+    TAB_APPEND( msg->i_name,  msg->name,  name );
+    TAB_APPEND( msg->i_value, msg->value, value );
+}
+
+static void httpd_ClientInit( httpd_client_t *cl )
+{
+    cl->i_state = HTTPD_CLIENT_RECEIVING;
+    cl->i_activity_date = mdate();
+    cl->i_activity_timeout = 1500000000LL;
+    cl->i_buffer_size = 10000;
+    cl->i_buffer = 0;
+    cl->p_buffer = malloc( cl->i_buffer_size );
+    cl->i_mode   = HTTPD_CLIENT_FILE;
+    cl->b_read_waiting = VLC_FALSE;
+
+    httpd_MsgInit( &cl->query );
+    httpd_MsgInit( &cl->answer );
+}
+void httpd_ClientModeStream( httpd_client_t *cl )
+{
+    cl->i_mode   = HTTPD_CLIENT_STREAM;
+}
+void httpd_ClientModeBidir( httpd_client_t *cl )
+{
+    cl->i_mode   = HTTPD_CLIENT_BIDIR;
+}
+
+static void httpd_ClientClean( httpd_client_t *cl )
+{
+    if( cl->fd > 0 )
+    {
+        SOCKET_CLOSE( cl->fd );
+    }
+
+    httpd_MsgClean( &cl->answer );
+    httpd_MsgClean( &cl->query );
+
+    if( cl->p_buffer )
+    {
+        free( cl->p_buffer );
+    }
+}
+
+static httpd_client_t *httpd_ClientNew( int fd, struct sockaddr_in *sock )
+{
+    httpd_client_t *cl = malloc( sizeof( httpd_client_t ) );
+    /* set this new socket non-block */
+#if defined( WIN32 ) || defined( UNDER_CE )
+    {
+        unsigned long i_dummy = 1;
+        ioctlsocket( fd, FIONBIO, &i_dummy );
+    }
+#else
+    fcntl( fd, F_SETFL, O_NONBLOCK );
+#endif
+    cl->i_ref   = 0;
+    cl->fd      = fd;
+    cl->sock    = *sock;
+    cl->url     = NULL;
+
+    httpd_ClientInit( cl );
+
+    return cl;
+}
+
+static void httpd_ClientRecv( httpd_client_t *cl )
+{
+    int i_len;
+
+    if( cl->query.i_proto == HTTPD_PROTO_NONE )
+    {
+        /* enought to see if it's rtp over rtsp or RTSP/HTTP */
+        i_len = recv( cl->fd, &cl->p_buffer[cl->i_buffer], 4 - cl->i_buffer, 0 );
+
+        if( i_len > 0 )
+        {
+            cl->i_buffer += i_len;
+        }
+
+        if( cl->i_buffer >= 4 )
+        {
+            fprintf( stderr, "peek=%4.4s\n", cl->p_buffer );
+            /* detect type */
+            if( cl->p_buffer[0] == '$' )
+            {
+                /* RTSP (rtp over rtsp) */
+                cl->query.i_proto = HTTPD_PROTO_RTSP;
+                cl->query.i_type  = HTTPD_MSG_CHANNEL;
+                cl->query.i_channel = cl->p_buffer[1];
+                cl->query.i_body  = (cl->p_buffer[2] << 8)|cl->p_buffer[3];
+                cl->query.p_body  = malloc( cl->query.i_body );
+
+                cl->i_buffer      = 0;
+            }
+            else if( !strncmp( cl->p_buffer, "HTTP", 4 ) )
+            {
+                cl->query.i_proto = HTTPD_PROTO_HTTP;
+                cl->query.i_type  = HTTPD_MSG_ANSWER;
+            }
+            else if( !strncmp( cl->p_buffer, "RTSP", 4 ) )
+            {
+                cl->query.i_proto = HTTPD_PROTO_RTSP;
+                cl->query.i_type  = HTTPD_MSG_ANSWER;
+            }
+            else if( !strncmp( cl->p_buffer, "GET", 3 ) || !strncmp( cl->p_buffer, "HEAD", 4 ) || !strncmp( cl->p_buffer, "POST", 4 ) )
+            {
+                cl->query.i_proto = HTTPD_PROTO_HTTP;
+                cl->query.i_type  = HTTPD_MSG_NONE;
+            }
+            else
+            {
+                cl->query.i_proto = HTTPD_PROTO_RTSP;
+                cl->query.i_type  = HTTPD_MSG_NONE;
+            }
+        }
+    }
+    else if( cl->query.i_body > 0 )
+    {
+        /* we are reading the body of a request or a channel */
+        i_len = recv( cl->fd, &cl->query.p_body[cl->i_buffer], cl->query.i_body - cl->i_buffer, 0 );
+        if( i_len > 0 )
+        {
+            cl->i_buffer += i_len;
+        }
+        if( cl->i_buffer >= cl->query.i_body )
+        {
+            cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
+        }
+    }
+    else
+    {
+        /* we are reading a header -> char by char */
+        for( ;; )
+        {
+            i_len = recv( cl->fd, &cl->p_buffer[cl->i_buffer], 1, 0 );
+            if( i_len <= 0 )
+            {
+                break;
+            }
+            cl->i_buffer++;
+
+            if( cl->i_buffer + 1 >= cl->i_buffer_size )
+            {
+                cl->i_buffer_size += 1024;
+                cl->p_buffer = realloc( cl->p_buffer, cl->i_buffer_size );
+            }
+            if( ( cl->i_buffer >= 2 && !strncmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )||
+                ( cl->i_buffer >= 4 && !strncmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) )
+            {
+                char *p;
+
+                /* we have finished the header so parse it and set i_body */
+                cl->p_buffer[cl->i_buffer] = '\0';
+
+                if( cl->query.i_type == HTTPD_MSG_ANSWER )
+                {
+                    cl->query.i_status = strtol( &cl->p_buffer[strlen( "HTTP/1.x" )], &p, 0 );
+                    while( *p == ' ' )
+                    {
+                        p++;
+                    }
+                    cl->query.psz_status = strdup( p );
+                }
+                else
+                {
+                    static const struct
+                    {
+                        char *name;
+                        int  i_type;
+                        int  i_proto;
+                    }
+                    msg_type[] =
+                    {
+                        { "GET",        HTTPD_MSG_GET,  HTTPD_PROTO_HTTP },
+                        { "HEAD",       HTTPD_MSG_HEAD, HTTPD_PROTO_HTTP },
+                        { "POST",       HTTPD_MSG_POST, HTTPD_PROTO_HTTP },
+
+                        { "OPTIONS",    HTTPD_MSG_OPTIONS,  HTTPD_PROTO_RTSP },
+                        { "DESCRIBE",   HTTPD_MSG_DESCRIBE, HTTPD_PROTO_RTSP },
+                        { "SETUP",      HTTPD_MSG_SETUP,    HTTPD_PROTO_RTSP },
+                        { "PLAY",       HTTPD_MSG_PLAY,     HTTPD_PROTO_RTSP },
+                        { "PAUSE",      HTTPD_MSG_PAUSE,    HTTPD_PROTO_RTSP },
+                        { "TEARDOWN",   HTTPD_MSG_TEARDOWN, HTTPD_PROTO_RTSP },
+
+                        { NULL,         HTTPD_MSG_NONE,     HTTPD_PROTO_NONE }
+                    };
+                    int  i;
+
+                    p = NULL;
+                    cl->query.i_type = HTTPD_MSG_NONE;
+
+                    fprintf( stderr, "received new request=%s\n", cl->p_buffer);
+
+                    for( i = 0; msg_type[i].name != NULL; i++ )
+                    {
+                        if( !strncmp( cl->p_buffer, msg_type[i].name, strlen( msg_type[i].name ) ) )
+                        {
+                            p = &cl->p_buffer[strlen(msg_type[i].name) + 1 ];
+                            cl->query.i_type = msg_type[i].i_type;
+                            if( cl->query.i_proto != msg_type[i].i_proto )
+                            {
+                                p = NULL;
+                                cl->query.i_proto = HTTPD_PROTO_NONE;
+                                cl->query.i_type = HTTPD_MSG_NONE;
+                            }
+                            break;
+                        }
+                    }
+                    if( p == NULL )
+                    {
+                        if( strstr( cl->p_buffer, "HTTP/1." ) )
+                        {
+                            cl->query.i_proto = HTTPD_PROTO_HTTP;
+                        }
+                        else if( strstr( cl->p_buffer, "RTSP/1." ) )
+                        {
+                            cl->query.i_proto = HTTPD_PROTO_RTSP;
+                        }
+                    }
+                    else
+                    {
+                        char *p2;
+                        char *p3;
+
+                        while( *p == ' ' )
+                        {
+                            p++;
+                        }
+                        p2 = strchr( p, ' ' );
+                        if( p2 )
+                        {
+                            *p2++ = '\0';
+                        }
+                        if( !strncasecmp( p, "rtsp:", 5 ) )
+                        {
+                            /* for rtsp url, you have rtsp://localhost:port/path */
+                            p += 5;
+                            while( *p == '/' ) p++;
+                            while( *p && *p != '/' ) p++;
+                        }
+                        cl->query.psz_url = strdup( p );
+                        if( ( p3 = strchr( cl->query.psz_url, '?' ) )  )
+                        {
+                            *p3++ = '\0';
+                            cl->query.psz_args = strdup( p3 );
+                        }
+                        if( p2 )
+                        {
+                            while( *p2 == ' ' )
+                            {
+                                p2++;
+                            }
+                            if( !strncasecmp( p2, "HTTP/1.", 7 ) )
+                            {
+                                cl->query.i_proto = HTTPD_PROTO_HTTP;
+                                cl->query.i_version = atoi( p2+7 );
+                            }
+                            else if( !strncasecmp( p2, "RTSP/1.", 7 ) )
+                            {
+                                cl->query.i_proto = HTTPD_PROTO_RTSP;
+                                cl->query.i_version = atoi( p2+7 );
+                            }
+                        }
+                        p = p2;
+                    }
+                }
+                if( p )
+                {
+                    p = strchr( p, '\n' );
+                }
+                if( p )
+                {
+                    while( *p == '\n' || *p == '\r' )
+                    {
+                        p++;
+                    }
+                    while( p && *p != '\0' )
+                    {
+                        char *line = p;
+                        char *eol = p = strchr( p, '\n' );
+                        char *colon;
+
+                        while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) )
+                        {
+                            *eol-- = '\0';
+                        }
+
+                        if( ( colon = strchr( line, ':' ) ) )
+                        {
+                            char *name;
+                            char *value;
+
+                            *colon++ = '\0';
+                            while( *colon == ' ' )
+                            {
+                                colon++;
+                            }
+                            name = strdup( line );
+                            value = strdup( colon );
+
+                            TAB_APPEND( cl->query.i_name, cl->query.name, name );
+                            TAB_APPEND( cl->query.i_value,cl->query.value,value);
+
+                            if( !strcasecmp( name, "Content-Length" ) )
+                            {
+                                cl->query.i_body = atol( value );
+                            }
+                        }
+
+                        if( p )
+                        {
+                            p++;
+                            while( *p == '\n' || *p == '\r' )
+                            {
+                                p++;
+                            }
+                        }
+                    }
+                }
+                if( cl->query.i_body > 0 )
+                {
+                    /* TODO Mhh, handle the case client will only send a request and close the connection
+                     * to mark and of body (probably only RTSP) */
+                    cl->query.p_body = malloc( cl->query.i_body );
+                    cl->i_buffer = 0;
+                }
+                else
+                {
+                    cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
+                }
+            }
+        }
+    }
+
+    /* check if the client is to be set to dead */
+#if defined( WIN32 ) || defined( UNDER_CE )
+    if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
+#else
+    if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
+#endif
+    {
+        if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE )
+        {
+            /* connection closed -> end of data */
+            if( cl->query.i_body > 0 )
+            {
+                cl->query.i_body = cl->i_buffer;
+            }
+            cl->i_state = HTTPD_CLIENT_RECEIVE_DONE;
+        }
+        else
+        {
+            cl->i_state = HTTPD_CLIENT_DEAD;
+        }
+    }
+    cl->i_activity_date = mdate();
+
+    /* Debugging only */
+    if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
+    {
+        int i;
+
+        fprintf( stderr, "received new request\n" );
+        fprintf( stderr, "  - proto=%s\n", cl->query.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP" );
+        fprintf( stderr, "  - version=%d\n", cl->query.i_version );
+        fprintf( stderr, "  - msg=%d\n", cl->query.i_type );
+        if( cl->query.i_type == HTTPD_MSG_ANSWER )
+        {
+            fprintf( stderr, "  - answer=%d '%s'\n", cl->query.i_status, cl->query.psz_status );
+        }
+        else if( cl->query.i_type != HTTPD_MSG_NONE )
+        {
+            fprintf( stderr, "  - url=%s\n", cl->query.psz_url );
+        }
+        for( i = 0; i < cl->query.i_name; i++ )
+        {
+            fprintf( stderr, "  - option name='%s' value='%s'\n", cl->query.name[i], cl->query.value[i] );
+        }
+    }
+}
+
+static void httpd_ClientSend( httpd_client_t *cl )
+{
+    int i;
+    int i_len;
+
+    if( cl->i_buffer < 0 )
+    {
+        /* We need to create the header */
+        int i_size = 0;
+        char *p;
+
+        i_size = strlen( "HTTP/1.") + 10 + 10 +
+                 strlen( cl->answer.psz_status ? cl->answer.psz_status : "" ) + 5;
+        for( i = 0; i < cl->answer.i_name; i++ )
+        {
+            i_size += strlen( cl->answer.name[i] ) + 2 + strlen( cl->answer.value[i] ) + 2;
+        }
+
+        if( cl->i_buffer_size < i_size )
+        {
+            cl->i_buffer_size = i_size;
+            free( cl->p_buffer );
+            cl->p_buffer = malloc( i_size );
+        }
+        p = cl->p_buffer;
+
+        p += sprintf( p, "%s/1.%d %d %s\r\n",
+                      cl->answer.i_proto ==  HTTPD_PROTO_HTTP ? "HTTP" : "RTSP",
+                      cl->answer.i_version,
+                      cl->answer.i_status, cl->answer.psz_status );
+        for( i = 0; i < cl->answer.i_name; i++ )
+        {
+            p += sprintf( p, "%s: %s\r\n", cl->answer.name[i], cl->answer.value[i] );
+        }
+        p += sprintf( p, "\r\n" );
+
+        cl->i_buffer = 0;
+        cl->i_buffer_size = (uint8_t*)p - cl->p_buffer;
+
+        fprintf( stderr, "sending answer\n" );
+        fprintf( stderr, "%s",  cl->p_buffer );
+    }
+
+    i_len = send( cl->fd, &cl->p_buffer[cl->i_buffer], cl->i_buffer_size - cl->i_buffer, 0 );
+    if( i_len > 0 )
+    {
+        cl->i_activity_date = mdate();
+        cl->i_buffer += i_len;
+
+        if( cl->i_buffer >= cl->i_buffer_size )
+        {
+            if( cl->answer.i_body == 0  && cl->answer.i_body_offset > 0 && !cl->b_read_waiting )
+            {
+                /* catch more body data */
+                int i_msg = cl->query.i_type;
+                cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl,
+                                          &cl->answer, &cl->query );
+            }
+
+            if( cl->answer.i_body > 0 )
+            {
+                /* send the body data */
+                free( cl->p_buffer );
+                cl->p_buffer = cl->answer.p_body;
+                cl->i_buffer_size = cl->answer.i_body;
+                cl->i_buffer = 0;
+
+                cl->answer.i_body = 0;
+                cl->answer.p_body = NULL;
+            }
+            else
+            {
+                /* send finished */
+                cl->i_state = HTTPD_CLIENT_SEND_DONE;
+            }
+        }
+    }
+    else
+    {
+#if defined( WIN32 ) || defined( UNDER_CE )
+        if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
+#else
+        if( ( i_len < 0 && errno != EAGAIN && errno != EINTR ) || ( i_len == 0 ) )
+#endif
+        {
+            /* error */
+            cl->i_state = HTTPD_CLIENT_DEAD;
+        }
+    }
+}
+
+static void httpd_HostThread( httpd_host_t *host )
+{
+    while( !host->b_die )
+    {
+        struct timeval  timeout;
+        fd_set          fds_read;
+        fd_set          fds_write;
+        int             i_handle_max = 0;
+        int             i_ret;
+        int             i_client;
+        int             b_low_delay = 0;
+
+        if( host->i_url <= 0 )
+        {
+            /* 0.2s */
+            msleep( 200000 );
+            continue;
+        }
+
+        /* built a set of handle to select */
+        FD_ZERO( &fds_read );
+        FD_ZERO( &fds_write );
+
+        FD_SET( host->fd, &fds_read );
+        i_handle_max = host->fd;
+
+        /* add all socket that should be read/write and close dead connection */
+        vlc_mutex_lock( &host->lock );
+        for( i_client = 0; i_client < host->i_client; i_client++ )
+        {
+            httpd_client_t *cl = host->client[i_client];
+
+            if( cl->i_ref < 0 ||
+                ( cl->i_ref == 0 &&
+                    ( cl->i_state == HTTPD_CLIENT_DEAD ||
+                      cl->i_activity_date + cl->i_activity_timeout < mdate() ) ) )
+            {
+                msg_Dbg( host, "connection closed(%s)", inet_ntoa(cl->sock.sin_addr) );
+
+                httpd_ClientClean( cl );
+
+                TAB_REMOVE( host->i_client, host->client, cl );
+                i_client--;
+            }
+            else if( cl->i_state == HTTPD_CLIENT_RECEIVING )
+            {
+                FD_SET( cl->fd, &fds_read );
+                i_handle_max = __MAX( i_handle_max, cl->fd );
+            }
+            else if( cl->i_state == HTTPD_CLIENT_SENDING )
+            {
+                FD_SET( cl->fd, &fds_write );
+                i_handle_max = __MAX( i_handle_max, cl->fd );
+            }
+            else if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE )
+            {
+                httpd_message_t *answer = &cl->answer;
+                httpd_message_t *query  = &cl->query;
+                int i_msg = query->i_type;
+
+                httpd_MsgInit( answer );
+
+                /* Handle what we received */
+                if( cl->i_mode != HTTPD_CLIENT_BIDIR && ( i_msg == HTTPD_MSG_ANSWER || i_msg == HTTPD_MSG_CHANNEL ) )
+                {
+                    /* we can only receive request from client when not in BIDIR mode */
+                    cl->url     = NULL;
+                    cl->i_state = HTTPD_CLIENT_DEAD;
+                }
+                else if( i_msg == HTTPD_MSG_ANSWER )
+                {
+                    /* We are in BIDIR mode, trigger the callback and then check for new data */
+                    if( cl->url && cl->url->catch[i_msg].cb )
+                    {
+                        cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, NULL, query );
+                    }
+                    cl->i_state = HTTPD_CLIENT_WAITING;
+                }
+                else if( i_msg == HTTPD_MSG_CHANNEL )
+                {
+                    /* We are in BIDIR mode, trigger the callback and then check for new data */
+                    if( cl->url && cl->url->catch[i_msg].cb )
+                    {
+                        cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, NULL, query );
+                    }
+                    cl->i_state = HTTPD_CLIENT_WAITING;
+                }
+                else if( i_msg == HTTPD_MSG_OPTIONS )
+                {
+                    int i_cseq;
+
+                    /* unimplemented */
+                    answer->i_proto  = query->i_proto ;
+                    answer->i_type   = HTTPD_MSG_ANSWER;
+                    answer->i_version= 0;
+                    answer->i_status = 200;
+                    answer->psz_status = strdup( "Ok" );
+
+                    answer->i_body = 0;
+                    answer->p_body = NULL;
+
+                    i_cseq = atoi( httpd_MsgGet( query, "Cseq" ) );
+                    httpd_MsgAdd( answer, "Cseq", "%d", i_cseq );
+                    httpd_MsgAdd( answer, "Server", "VLC Server" );
+                    httpd_MsgAdd( answer, "Public", "DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE" );
+                    httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
+
+                    cl->i_buffer = -1;  /* Force the creation of the answer in httpd_ClientSend */
+                    cl->i_state = HTTPD_CLIENT_SENDING;
+                }
+                else if( i_msg == HTTPD_MSG_NONE )
+                {
+                    if( query->i_proto == HTTPD_PROTO_NONE )
+                    {
+                        cl->url = NULL;
+                        cl->i_state = HTTPD_CLIENT_DEAD;
+                    }
+                    else
+                    {
+                        uint8_t *p;
+
+                        /* unimplemented */
+                        answer->i_proto  = query->i_proto ;
+                        answer->i_type   = HTTPD_MSG_ANSWER;
+                        answer->i_version= 0;
+                        answer->i_status = 501;
+                        answer->psz_status = strdup( "Unimplemented" );
+
+                        p = answer->p_body = malloc( 1000 );
+
+                        p += sprintf( p, "<html>\n" );
+                        p += sprintf( p, "<head>\n" );
+                        p += sprintf( p, "<title>Error 501</title>\n" );
+                        p += sprintf( p, "</head>\n" );
+                        p += sprintf( p, "<body>\n" );
+                        p += sprintf( p, "<h1><center> 501 Unimplemented</center></h1>\n" );
+                        p += sprintf( p, "<hr />\n" );
+                        p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
+                        p += sprintf( p, "</body>\n" );
+                        p += sprintf( p, "</html>\n" );
+
+                        answer->i_body = p - answer->p_body;
+                        httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
+
+                        cl->i_buffer = -1;  /* Force the creation of the answer in httpd_ClientSend */
+                        cl->i_state = HTTPD_CLIENT_SENDING;
+                    }
+                }
+                else
+                {
+                    vlc_bool_t b_auth_failed = VLC_FALSE;
+                    int i;
+
+                    /* Search the url and trigger callbacks */
+                    for( i = 0; i < host->i_url; i++ )
+                    {
+                        httpd_url_t *url = host->url[i];
+
+                        if( !strcmp( url->psz_url, query->psz_url ) )
+                        {
+                            if( url->catch[i_msg].cb )
+                            {
+                                if( answer && ( *url->psz_user || *url->psz_password ) )
+                                {
+                                    /* create the headers */
+                                    char id[strlen(url->psz_user)+strlen(url->psz_password) + 2];
+                                    char *b64 = httpd_MsgGet( query, "Authorization" ); /* BASIC id */
+                                    char auth[strlen(b64) +1];
+
+                                    sprintf( id, "%s:%s", url->psz_user, url->psz_password );
+                                    if( !strncasecmp( b64, "BASIC", 5 ) )
+                                    {
+                                        b64 += 5;
+                                        while( *b64 == ' ' )
+                                        {
+                                            b64++;
+                                        }
+                                        b64_decode( auth, b64 );
+                                    }
+                                    else
+                                    {
+                                        strcpy( auth, "" );
+                                    }
+                                    if( strcmp( id, auth ) )
+                                    {
+                                        httpd_MsgAdd( answer, "WWW-Authenticate", "Basic realm=\"%s\"", url->psz_user );
+                                        /* We fail for all url */
+                                        b_auth_failed = VLC_TRUE;
+                                        break;
+                                    }
+                                }
+
+                                if( !url->catch[i_msg].cb( url->catch[i_msg].p_sys, cl, answer, query ) )
+                                {
+                                    /* only one url can answer */
+                                    answer = NULL;
+                                    if( cl->url == NULL )
+                                    {
+                                        cl->url = url;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if( answer )
+                    {
+                        uint8_t *p;
+
+                        answer->i_proto  = query->i_proto;
+                        answer->i_type   = HTTPD_MSG_ANSWER;
+                        answer->i_version= 0;
+                        p = answer->p_body = malloc( 1000 + strlen(query->psz_url) );
+
+                        if( b_auth_failed )
+                        {
+                            answer->i_status = 401;
+                            answer->psz_status = strdup( "Authorization Required" );
+
+                            p += sprintf( p, "<html>\n" );
+                            p += sprintf( p, "<head>\n" );
+                            p += sprintf( p, "<title>Error 401</title>\n" );
+                            p += sprintf( p, "</head>\n" );
+                            p += sprintf( p, "<body>\n" );
+                            p += sprintf( p, "<h1><center> 401 Authorization Required (%s)</center></h1>\n", query->psz_url );
+                            p += sprintf( p, "<hr />\n" );
+                            p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
+                            p += sprintf( p, "</body>\n" );
+                            p += sprintf( p, "</html>\n" );
+                        }
+                        else
+                        {
+                            /* no url registered */
+                            answer->i_status = 404;
+                            answer->psz_status = strdup( "Not found" );
+
+                            p += sprintf( p, "<html>\n" );
+                            p += sprintf( p, "<head>\n" );
+                            p += sprintf( p, "<title>Error 404</title>\n" );
+                            p += sprintf( p, "</head>\n" );
+                            p += sprintf( p, "<body>\n" );
+                            p += sprintf( p, "<h1><center> 404 Ressource not found(%s)</center></h1>\n", query->psz_url );
+                            p += sprintf( p, "<hr />\n" );
+                            p += sprintf( p, "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" );
+                            p += sprintf( p, "</body>\n" );
+                            p += sprintf( p, "</html>\n" );
+                        }
+
+                        answer->i_body = p - answer->p_body;
+                        httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body );
+                    }
+                    cl->i_buffer = -1;  /* Force the creation of the answer in httpd_ClientSend */
+                    cl->i_state = HTTPD_CLIENT_SENDING;
+                }
+            }
+            else if( cl->i_state == HTTPD_CLIENT_SEND_DONE )
+            {
+                if( cl->i_mode == HTTPD_CLIENT_FILE )
+                {
+                    cl->url = NULL;
+                    if( ( cl->query.i_proto == HTTPD_PROTO_HTTP &&
+                          ( !strcasecmp( httpd_MsgGet( &cl->query, "Connection" ), "Keep-Alive" )||
+                          ( cl->answer.i_version == 1 && strcasecmp( httpd_MsgGet( &cl->query, "Connection" ), "Close" ) ) ) ) ||
+                        ( cl->query.i_proto == HTTPD_PROTO_RTSP &&
+                          strcasecmp( httpd_MsgGet( &cl->query, "Connection" ), "Close" ) &&
+                          strcasecmp( httpd_MsgGet( &cl->answer, "Connection" ), "Close" ) ) )
+                    {
+                        httpd_MsgClean( &cl->query );
+                        httpd_MsgInit( &cl->query );
+
+                        cl->i_buffer = 0;
+                        cl->i_buffer_size = 1000;
+                        free( cl->p_buffer );
+                        cl->p_buffer = malloc( cl->i_buffer_size );
+                        cl->i_state = HTTPD_CLIENT_RECEIVING;
+                    }
+                    else
+                    {
+                        cl->i_state = HTTPD_CLIENT_DEAD;
+                    }
+                    httpd_MsgClean( &cl->answer );
+                }
+                else if( cl->b_read_waiting )
+                {
+                    /* we have a message waiting for us to read it */
+                    httpd_MsgClean( &cl->answer );
+                    httpd_MsgClean( &cl->query );
+
+                    cl->i_buffer = 0;
+                    cl->i_buffer_size = 1000;
+                    free( cl->p_buffer );
+                    cl->p_buffer = malloc( cl->i_buffer_size );
+                    cl->i_state = HTTPD_CLIENT_RECEIVING;
+                    cl->b_read_waiting = VLC_FALSE;
+                }
+                else
+                {
+                    int64_t i_offset = cl->answer.i_body_offset;
+                    httpd_MsgClean( &cl->answer );
+
+                    cl->answer.i_body_offset = i_offset;
+                    cl->i_state = HTTPD_CLIENT_WAITING;
+                }
+            }
+            else if( cl->i_state == HTTPD_CLIENT_WAITING )
+            {
+                int64_t i_offset = cl->answer.i_body_offset;
+                int     i_msg = cl->query.i_type;
+
+                httpd_MsgInit( &cl->answer );
+                cl->answer.i_body_offset = i_offset;
+
+                cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, &cl->answer, &cl->query );
+                if( cl->answer.i_type != HTTPD_MSG_NONE )
+                {
+                    /* we have new data, so reenter send mode */
+                    cl->i_buffer      = 0;
+                    cl->p_buffer      = cl->answer.p_body;
+                    cl->i_buffer_size = cl->answer.i_body;
+                    cl->answer.p_body = NULL;
+                    cl->answer.i_body = 0;
+                    cl->i_state = HTTPD_CLIENT_SENDING;
+                }
+                else
+                {
+                    /* we shouldn't wait too long */
+                    b_low_delay = VLC_TRUE;
+                }
+            }
+
+            /* Special for BIDIR mode we also check reading */
+            if( cl->i_mode == HTTPD_CLIENT_BIDIR && cl->i_state == HTTPD_CLIENT_SENDING )
+            {
+                FD_SET( cl->fd, &fds_read );
+                i_handle_max = __MAX( i_handle_max, cl->fd );
+            }
+        }
+        vlc_mutex_unlock( &host->lock );
+
+        /* we will wait 100ms or 20ms (not too big 'cause HTTPD_CLIENT_WAITING) */
+        timeout.tv_sec = 0;
+        timeout.tv_usec = b_low_delay ? 20000 : 100000;
+
+        i_ret = select( i_handle_max + 1,
+                        &fds_read, &fds_write, NULL, &timeout );
+
+        if( i_ret == -1 && errno != EINTR )
+        {
+            msg_Warn( host, "cannot select sockets" );
+            msleep( 1000 );
+            continue;
+        }
+        else if( i_ret <= 0 )
+        {
+            continue;
+        }
+
+        /* accept new connections */
+        if( FD_ISSET( host->fd, &fds_read ) )
+        {
+            int     i_sock_size = sizeof( struct sockaddr_in );
+            struct  sockaddr_in sock;
+            int     fd;
+
+            fd = accept( host->fd, (struct sockaddr *)&sock, &i_sock_size );
+            if( fd > 0 )
+            {
+                httpd_client_t *cl = httpd_ClientNew( fd, &sock );
+
+                vlc_mutex_lock( &host->lock );
+                TAB_APPEND( host->i_client, host->client, cl );
+                vlc_mutex_unlock( &host->lock );
+
+                msg_Dbg( host, "new connection (%s)", inet_ntoa(sock.sin_addr) );
+            }
+        }
+        /* now try all others socket */
+        vlc_mutex_lock( &host->lock );
+        for( i_client = 0; i_client < host->i_client; i_client++ )
+        {
+            httpd_client_t *cl = host->client[i_client];
+            if( cl->i_state == HTTPD_CLIENT_RECEIVING )
+            {
+                httpd_ClientRecv( cl );
+            }
+            else if( cl->i_state == HTTPD_CLIENT_SENDING )
+            {
+                httpd_ClientSend( cl );
+            }
+
+            if( cl->i_mode == HTTPD_CLIENT_BIDIR && cl->i_state == HTTPD_CLIENT_SENDING &&
+                FD_ISSET( cl->fd, &fds_read ) )
+            {
+                cl->b_read_waiting = VLC_TRUE;
+            }
+        }
+        vlc_mutex_unlock( &host->lock );
+    }
+}
+
+
+
+
+
+static int BuildAddr( struct sockaddr_in * p_socket,
+                      const char * psz_address, int i_port )
+{
+    /* Reset struct */
+    memset( p_socket, 0, sizeof( struct sockaddr_in ) );
+    p_socket->sin_family = AF_INET;                                /* family */
+    p_socket->sin_port = htons( (uint16_t)i_port );
+    if( !*psz_address )
+    {
+        p_socket->sin_addr.s_addr = INADDR_ANY;
+    }
+    else
+    {
+        struct hostent    * p_hostent;
+
+        /* Try to convert address directly from in_addr - this will work if
+         * psz_address is dotted decimal. */
+#ifdef HAVE_ARPA_INET_H
+        if( !inet_aton( psz_address, &p_socket->sin_addr ) )
+#else
+        p_socket->sin_addr.s_addr = inet_addr( psz_address );
+        if( p_socket->sin_addr.s_addr == INADDR_NONE )
+#endif
+        {
+            /* We have a fqdn, try to find its address */
+            if ( (p_hostent = gethostbyname( psz_address )) == NULL )
+            {
+                return( -1 );
+            }
+
+            /* Copy the first address of the host in the socket address */
+            memcpy( &p_socket->sin_addr, p_hostent->h_addr_list[0],
+                     p_hostent->h_length );
+        }
+    }
+    return( 0 );
+}