]> git.sesse.net Git - vlc/blobdiff - modules/misc/httpd.c
* httpd: fixed a integer overflow.
[vlc] / modules / misc / httpd.c
index 71c217a4a81181978b54ad10231640ef0501a049..90eef947240d4974cc1a058fa41f23187b84d71a 100644 (file)
@@ -2,7 +2,7 @@
  * httpd.c
  *****************************************************************************
  * Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.c,v 1.9 2003/03/17 23:42:12 fenrir Exp $
+ * $Id: httpd.c,v 1.31 2004/02/05 19:51:46 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
 
 /*****************************************************************************
  * Preamble
+ *
+ * TODO:
+ *  - make that two distinct host:port use different daemon
  *****************************************************************************/
 #include <stdlib.h>
+#include <vlc/vlc.h>
 
-#include <sys/types.h>
 #include <sys/stat.h>
 
-#include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 
-#include <vlc/vlc.h>
 #include "httpd.h"
 
 #ifdef HAVE_SYS_TIME_H
@@ -74,6 +75,7 @@
 #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 )
@@ -95,6 +97,7 @@ 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();
 
 /*****************************************************************************
@@ -111,14 +114,16 @@ static httpd_file_t     *RegisterFile   ( httpd_t *,
                                           httpd_file_callback_args_t *p_args );
 static void             UnregisterFile  ( httpd_t *, httpd_file_t * );
 
-//#define httpd_stream_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
  *****************************************************************************/
@@ -134,10 +139,15 @@ struct httpd_host_t
 
 };
 
-#define HTTPD_AUTHENTICATE_NONE     0
-#define HTTPD_AUTHENTICATE_BASIC    1
+enum httpd_authenticate_e
+{
+    HTTPD_AUTHENTICATE_NONE = 0,
+    HTTPD_AUTHENTICATE_BASIC = 1
+};
 
-//typedef httpd_file_t httpd_stream_t;
+#if 0
+  typedef httpd_file_t httpd_stream_t;
+#endif
 
 struct httpd_file_t
 {
@@ -163,7 +173,7 @@ struct httpd_file_t
     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 */
-    int         i_buffer_last_pos;  /* a new connection will start with that */
+    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;
@@ -171,14 +181,24 @@ struct httpd_file_t
 };
 
 
-#define HTTPD_CONNECTION_RECEIVING_REQUEST      1
-#define HTTPD_CONNECTION_SENDING_HEADER         2
-#define HTTPD_CONNECTION_SENDING_FILE           3
-#define HTTPD_CONNECTION_SENDING_STREAM         4
-#define HTTPD_CONNECTION_TO_BE_CLOSED           5
+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
+};
 
-#define HTTPD_CONNECTION_METHOD_GET             1
-#define HTTPD_CONNECTION_METHOD_POST            2
 typedef struct httpd_connection_s
 {
     struct httpd_connection_s *p_next;
@@ -191,12 +211,12 @@ typedef struct httpd_connection_s
     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_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
+    uint8_t *p_request;     /* whith get: ?<*>, with post: main data */
     int      i_request_size;
 
     httpd_file_t    *p_file;
@@ -210,6 +230,15 @@ typedef struct httpd_connection_s
     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
  */
@@ -228,11 +257,20 @@ struct httpd_sys_t
     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:
@@ -254,18 +292,39 @@ static int Open( vlc_object_t *p_this )
     p_httpt->b_error= 0;
 
     /* init httpt_t structure */
-    vlc_mutex_init( p_httpd, &p_httpt->host_lock );
+    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;
 
-    vlc_mutex_init( p_httpd, &p_httpt->file_lock );
+    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;
 
-    vlc_mutex_init( p_httpd, &p_httpt->connection_lock );
+    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 ) )
@@ -275,6 +334,7 @@ static int Open( vlc_object_t *p_this )
         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 );
@@ -291,6 +351,7 @@ static int Open( vlc_object_t *p_this )
     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 );
 }
@@ -304,6 +365,8 @@ static void Close( vlc_object_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;
@@ -360,6 +423,13 @@ static void Close( vlc_object_t * p_this )
         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 );
 }
@@ -436,7 +506,8 @@ static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, i
     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 == sock.sin_addr.s_addr )
+            ( 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;
         }
@@ -509,9 +580,24 @@ static httpd_host_t *_RegisterHost( httpd_sys_t *p_httpt, char *psz_host_addr, i
     {
         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;
@@ -592,6 +678,11 @@ static void            _UnregisterHost( httpd_sys_t *p_httpt, httpd_host_t *p_ho
         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 );
@@ -613,7 +704,10 @@ static void __RegisterFile( httpd_sys_t *p_httpt, httpd_file_t *p_file )
     {
         p_httpt->file = malloc( sizeof( httpd_file_t *) );
     }
-
+    if( !p_httpt->file )
+    {
+        return;
+    }
     p_httpt->file[p_httpt->i_file_count++] = p_file;
 }
 
@@ -643,14 +737,29 @@ static httpd_file_t    *_RegisterFile( httpd_sys_t *p_httpt,
     }
 
     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
     {
@@ -713,14 +822,29 @@ static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
     }
 
     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
     {
@@ -734,10 +858,15 @@ static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
     p_stream->pf_get          = NULL;
     p_stream->pf_post         = NULL;
 
-    p_stream->i_buffer_size   = 1024*1024;
+    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;
@@ -850,8 +979,9 @@ static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stre
     {
         return( VLC_SUCCESS );
     }
-    //fprintf( stderr, "## i_data=%d pos=%lld\n", i_data, p_stream->i_buffer_pos );
-
+#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) */
@@ -865,6 +995,7 @@ static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stre
 
         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 );
@@ -879,6 +1010,7 @@ static int             _SendStream( httpd_sys_t *p_httpt, httpd_stream_t *p_stre
 
     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 ) );
@@ -899,6 +1031,11 @@ static int             HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream,
     {
         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 );
@@ -908,28 +1045,169 @@ static int             HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream,
     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_401_get( httpd_file_callback_args_t *p_args,
+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 401</title>\n" );
+    p += sprintf( p, "<title>Error 400</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, "<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, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
     p += sprintf( p, "</body>\n" );
     p += sprintf( p, "</html>\n" );
 
@@ -937,22 +1215,27 @@ static int  httpd_page_401_get( httpd_file_callback_args_t *p_args,
 
     return VLC_SUCCESS;
 }
-static int  httpd_page_404_get( httpd_file_callback_args_t *p_args,
+
+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 404</title>\n" );
+    p += sprintf( p, "<title>Error 401</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, "<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, "<a href=\"http://www.videolan.org/\">VideoLAN</a>\n" );
     p += sprintf( p, "</body>\n" );
     p += sprintf( p, "</html>\n" );
 
@@ -960,270 +1243,128 @@ static int  httpd_page_404_get( httpd_file_callback_args_t *p_args,
 
     return VLC_SUCCESS;
 }
-
-
-static int _httpd_page_admin_get_status( httpd_file_callback_args_t *p_args,
-                                         uint8_t **pp_data, int *pi_data )
+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 )
 {
-    httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
-    httpd_connection_t *p_con;
-    int i;
     char *p;
 
-    /* FIXME FIXME do not use static size FIXME FIXME*/
-    p = *pp_data = malloc( 8096 );
-
-    p += sprintf( p, "<html>\n" );
-    p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
-    p += sprintf( p, "</head>\n" );
-    p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
-    p += sprintf( p, "<h2><center>Admin page</center></h2>\n" );
-
-    /* general */
-    p += sprintf( p, "<h3>General state</h3>\n" );
-    p += sprintf( p, "<ul>\n" );
-    p += sprintf( p, "<li>Connection count: %d</li>\n", p_httpt->i_connection_count );
-    //p += sprintf( p, "<li>Total bandwith: %d</li>\n", -1 );
-    /*p += sprintf( p, "<li></li>\n" );*/
-    p += sprintf( p, "</ul>\n" );
-    /* host list */
-    vlc_mutex_lock( &p_httpt->host_lock );
-    p += sprintf( p, "<h3>Host list</h3>\n" );
-    p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
-    p += sprintf( p, "<tr>\n<th>Host</th><th>Port</th><th>IP</th>\n</tr>\n" );
-
-    for( i = 0; i < p_httpt->i_host_count; i++ )
-    {
-        p += sprintf( p, "<tr>\n" );
-        p += sprintf( p, "<td>%s</td>\n", p_httpt->host[i]->psz_host_addr );
-        p += sprintf( p, "<td>%d</td>\n", p_httpt->host[i]->i_port );
-        p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_httpt->host[i]->sock.sin_addr ) );
-        p += sprintf( p, "</tr>\n" );
-    }
-    p += sprintf( p, "</table>\n" );
-    vlc_mutex_unlock( &p_httpt->host_lock );
-
-    /* file list */
-    /* XXX do not take lock on file_lock */
-    p += sprintf( p, "<h3>File list</h3>\n" );
-    p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
-    p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
-
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        if( !p_httpt->file[i]->b_stream )
-        {
-            p += sprintf( p, "<tr>\n" );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
-            p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
-            p += sprintf( p, "</tr>\n" );
-        }
-    }
-    p += sprintf( p, "</table>\n" );
-
-    /* stream list */
-    /* XXX do not take lock on file_lock */
-    p += sprintf( p, "<h3>Stream list</h3>\n" );
-    p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
-    p += sprintf( p, "<tr>\n<th>Name</th><th>Mime</th><th>Protected</th><th>Used</th>\n</tr>\n" );
-
-    for( i = 0; i < p_httpt->i_file_count; i++ )
-    {
-        if( p_httpt->file[i]->b_stream )
-        {
-            p += sprintf( p, "<tr>\n" );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_file );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_mime );
-            p += sprintf( p, "<td>%s</td>\n", p_httpt->file[i]->psz_user ? "Yes" : "No" );
-            p += sprintf( p, "<td>%d</td>\n", p_httpt->file[i]->i_ref);
-            p += sprintf( p, "</tr>\n" );
-        }
-    }
-    p += sprintf( p, "</table>\n" );
-
-    /* connection list */
-    /* XXX do not take lock on connection_lock */
-    p += sprintf( p, "<h3>Connection list</h3>\n" );
-    p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
-    p += sprintf( p, "<tr>\n<th>IP</th><th>Requested File</th><th>Status</th><th>Action</th>\n</tr>\n" );
-
-    for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
+    p = *pp_data = malloc( 1024 );
+    if( !p )
     {
-        p += sprintf( p, "<tr>\n" );
-        p += sprintf( p, "<td>%s</td>\n", inet_ntoa( p_con->sock.sin_addr ) );
-        p += sprintf( p, "<td>%s</td>\n", p_con->psz_file );
-        p += sprintf( p, "<td>%d</td>\n", p_con->i_http_error );
-        p += sprintf( p, "<td><form method=\"get\" action=\"\">"
-                         "<select name=\"action\">"
-                         "<option selected>close_connection</option>"
-                         "<option>ban_ip</option>"
-                         "</select>"
-                         "<input type=\"hidden\" name=\"id\" value=\"%p\"/>"
-                         "<input type=\"submit\" value=\"Do it\" />"
-                              "</form></td>\n", p_con);
-        p += sprintf( p, "</tr>\n" );
+        return VLC_ENOMEM ;
     }
-    p += sprintf( p, "</table>\n" );
-
-
-    /* www.videolan.org */
-    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_admin_get_success( httpd_file_callback_args_t *p_args,
-                                          uint8_t **pp_data, int *pi_data,
-                                          char *psz_msg )
-{
-    char *p;
-
-    p = *pp_data = malloc( 8096 );
 
     p += sprintf( p, "<html>\n" );
     p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
+    p += sprintf( p, "<title>Error 404</title>\n" );
     p += sprintf( p, "</head>\n" );
     p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
-
-    p += sprintf( p, "<p>Success=`%s'</p>", psz_msg );
-
+    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, "<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 );
+    return VLC_SUCCESS;
 }
 
-static int _httpd_page_admin_get_error( httpd_file_callback_args_t *p_args,
-                                        uint8_t **pp_data, int *pi_data,
-                                        char *psz_error )
+#if 0
+static int httpd_BanIP( httpd_sys_t *p_httpt, char * psz_new_banned_ip)
 {
-    char *p;
-
-    p = *pp_data = malloc( 8096 );
+    httpd_banned_ip_t *p_new_banned_ip ;
 
-    p += sprintf( p, "<html>\n" );
-    p += sprintf( p, "<head>\n" );
-    p += sprintf( p, "<title>VideoLAN Client Stream Output</title>\n" );
-    p += sprintf( p, "</head>\n" );
-    p += sprintf( p, "<body>\n" );
-    p += sprintf( p, "<h1><center>VideoLAN Client Stream Output</center></h1>\n" );
-
-    p += sprintf( p, "<p>Error=`%s'</p>", psz_error );
-
-    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;
+    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;
+    }
 
-    return( VLC_SUCCESS );
-}
+    strcpy( p_new_banned_ip->psz_ip, psz_new_banned_ip );
 
-static void _httpd_uri_extract_value( char *psz_uri, char *psz_name, char *psz_value, int i_value_max )
-{
-    char *p;
+    msg_Dbg( p_httpt, "Banning IP %s", psz_new_banned_ip );
 
-    p = strstr( psz_uri, psz_name );
-    if( p )
+    if( p_httpt->p_first_banned_ip )
     {
-        int i_len;
-
-        p += strlen( psz_name );
-        if( *p == '=' ) p++;
+        httpd_banned_ip_t *p_last;
 
-        if( strchr( p, '&' ) )
-        {
-            i_len = strchr( p, '&' ) - p;
-        }
-        else
-        {
-            i_len = strlen( p );
-        }
-        i_len = __MIN( i_value_max - 1, i_len );
-        if( i_len > 0 )
-        {
-            strncpy( psz_value, p, i_len );
-            psz_value[i_len] = '\0';
-        }
-        else
+        p_last = p_httpt->p_first_banned_ip;
+        while( p_last->p_next )
         {
-            strncpy( psz_value, "", i_value_max );
+            p_last = p_last->p_next;
         }
+
+        p_last->p_next = p_new_banned_ip;
+        p_new_banned_ip->p_prev = p_last;
     }
     else
     {
-        strncpy( psz_value, "", i_value_max );
-    }
-}
+        p_new_banned_ip->p_prev = NULL;
 
+        p_httpt->p_first_banned_ip = p_new_banned_ip;
+    }
 
-static int  httpd_page_admin_get( httpd_file_callback_args_t *p_args,
-                                  uint8_t *p_request, int i_request,
-                                  uint8_t **pp_data, int *pi_data )
+    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_sys_t *p_httpt = (httpd_sys_t*)p_args;
-    httpd_connection_t *p_con;
-    int i;
+    httpd_banned_ip_t *p_ip;
+
+    p_ip = p_httpt->p_first_banned_ip;
 
-    if( i_request > 0)
+    while( p_ip)
     {
-        char action[512];
+        if( strcmp( psz_ip, p_ip->psz_ip ) == 0 )
+        {
+            return p_ip;
+        }
+        p_ip = p_ip->p_next;
+    }
 
-        _httpd_uri_extract_value( p_request, "action", action, 512 );
+    return NULL;
+}
 
-        if( !strcmp( action, "close_connection" ) )
-        {
-            char id[128];
-            void *i_id;
+static int httpd_UnbanIP( httpd_sys_t *p_httpt, httpd_banned_ip_t *p_banned_ip )
+{
+    if(!p_banned_ip)
+    {
+        return -1;
+    }
 
-            _httpd_uri_extract_value( p_request, "id", id, 512 );
-            i_id = (void*)strtol( id, NULL, 0 );
-            msg_Dbg( p_httpt, "requested closing connection id=%s %p", id, i_id );
-            for( p_con = p_httpt->p_first_connection;p_con != NULL; p_con = p_con->p_next )
-            {
-                if( (void*)p_con == i_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( _httpd_page_admin_get_success( p_args, pp_data, pi_data, "connection closed" ) );
-                }
-            }
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, "invalid id" ) );
-        }
-        else if( !strcmp( action, "ban_ip" ) )
-        {
-            msg_Dbg( p_httpt, "requested banning ip" );
-            return( _httpd_page_admin_get_success( p_args, pp_data, pi_data, "ip banned" ) );
-        }
-        else
-        {
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, action ) );
-        }
+    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
     {
-        return( _httpd_page_admin_get_status( p_args, pp_data, pi_data ) );
+        p_httpt->p_first_banned_ip = p_banned_ip->p_next;
     }
 
-    return VLC_SUCCESS;
-}
+    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 )
 {
@@ -1231,8 +1372,21 @@ static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_
 
     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();
@@ -1250,8 +1404,13 @@ static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_
     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->i_stream_pos = 0; /* updated by httpd_thread */
     p_con->p_next = NULL;
 
     if( p_httpt->p_first_connection )
@@ -1352,7 +1511,7 @@ static int httpd_RequestNextLine( char **pp_buffer, char *p_end )
     return VLC_EGENERIC;
 }
 
-//char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+/*char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";*/
 static void b64_decode( char *dest, char *src )
 {
     int  i_level;
@@ -1416,13 +1575,15 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
     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 );
+    msg_Dbg( p_httpt, "new request=\n%s", p_con->p_buffer );
 
 
     p = p_con->p_buffer;
@@ -1431,8 +1592,9 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
     httpd_RequestGetWord( command, 32, &p, p_end );
     httpd_RequestGetWord( url, 1024, &p, p_end );
     httpd_RequestGetWord( version, 32, &p, p_end );
-    //msg_Dbg( p_httpt, "ask =%s= =%s= =%s=", command, url, version );
-
+#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" ) )
@@ -1443,6 +1605,10 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
     {
         p_con->i_method = HTTPD_CONNECTION_METHOD_POST;
     }
+    else if( !strcmp( command, "HEAD" ))
+    {
+        p_con->i_method = HTTPD_CONNECTION_METHOD_HEAD;
+    }
     else
     {
         /* unimplemented */
@@ -1467,11 +1633,14 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
 
         if( httpd_RequestNextLine( &p, p_end ) )
         {
-            //msg_Dbg( p_httpt, "failled new line" );
+#if 0
+            msg_Dbg( p_httpt, "failled new line" );
+#endif
             break;;
         }
-        //msg_Dbg( p_httpt, "new line=%s", p );
-
+#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" ) )
         {
@@ -1489,10 +1658,13 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
                 char decoded[1024];
 
                 httpd_RequestGetWord( basic, 1024, &p, p_end );
-                //msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
+#if 0
+                msg_Dbg( p_httpt, "Authorization: basic:%s", basic );
+#endif
                 b64_decode( decoded, basic );
-
-                //msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
+#if 0
+                msg_Dbg( p_httpt, "Authorization: decoded:%s", decoded );
+#endif
                 if( strchr( decoded, ':' ) )
                 {
                     char *p = strchr( decoded, ':' );
@@ -1503,6 +1675,16 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
                 }
             }
         }
+        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, '?' ) )
@@ -1538,7 +1720,11 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
         {
             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 );
@@ -1549,20 +1735,27 @@ static void httpd_ConnectionParseRequest( httpd_sys_t *p_httpt, httpd_connection
     p_con->i_http_error = 200;
 
 create_header:
-    //msg_Dbg( p_httpt, "ask %s %s %d", command, p_con->psz_file, p_con->i_http_error );
+#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;
 
-    //vlc_mutex_lock( &p_httpt->file_lock );
+#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 ) )
             {
@@ -1576,33 +1769,48 @@ search_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 ) )
+        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++;
-//    vlc_mutex_unlock( &p_httpt->file_lock );
+#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;
@@ -1613,27 +1821,66 @@ search_file:
 
     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 = 4096 + p_con->p_file->i_header_size;
+        p_con->i_buffer_size += p_con->p_file->i_header_size;
     }
 
-    p_con->i_buffer_size = 4096;
-    p_con->i_buffer = 0;
     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 );
-    p += sprintf( p, "Content-type: %s\r\n", p_con->p_file->psz_mime );
+
+    /* 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->p_file->b_stream && p_con->p_file->i_header_size > 0 )
+    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],
@@ -1642,12 +1889,18 @@ search_file:
         p_con->i_buffer_size += p_con->p_file->i_header_size;
     }
 
-    //msg_Dbg( p_httpt, "answer=\n%s", p_con->p_buffer );
+    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_admin;
+    httpd_file_t    *p_page_400;
     httpd_file_t    *p_page_401;
     httpd_file_t    *p_page_404;
 
@@ -1655,6 +1908,13 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
 
     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,
@@ -1667,12 +1927,6 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                                 httpd_page_404_get,
                                 NULL,
                                 (httpd_file_callback_args_t*)NULL );
-    p_page_admin = _RegisterFile( p_httpt,
-                                  "/admin.html", "text/html",
-                                  "admin", "salut",
-                                  httpd_page_admin_get,
-                                  NULL,
-                                  (httpd_file_callback_args_t*)p_httpt );
 
     while( !p_httpt->b_die )
     {
@@ -1738,7 +1992,7 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
         timeout.tv_sec = 0;
         timeout.tv_usec = 500*1000;
 
-        i_ret = select( i_handle_max + 1, 
+        i_ret = select( i_handle_max + 1,
                         &fds_read,
                         &fds_write,
                         NULL,
@@ -1749,9 +2003,9 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
             msleep( 1000 );
             continue;
         }
+
         if( i_ret <= 0 )
         {
-//            msg_Dbg( p_httpt, "waiting..." );
             continue;
         }
 
@@ -1801,8 +2055,12 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                               p_con->p_buffer + p_con->i_buffer,
                               p_con->i_buffer_size - p_con->i_buffer, 0 );
 
-                if( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
-                    ( i_len == 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;
 
@@ -1846,10 +2104,15 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                 {
                     i_len = 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 );
+#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( ( i_len < 0 && errno != EAGAIN && errno != EINTR )||
-                    ( i_len == 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;
 
@@ -1869,9 +2132,9 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                             p_con->i_buffer = 0;
                             FREE( p_con->p_buffer );
 
-                            if( !p_con->p_file->b_stream )
+                            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
+                                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,
@@ -1886,6 +2149,7 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                                 }
                                 else
                                 {
+                                    /* HTTPD_CONNECTION_METHOD_HEAD for example */
                                     p_con->p_buffer = NULL;
                                     p_con->i_buffer_size = 0;
                                 }
@@ -1928,7 +2192,8 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                     /* 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  );
+                        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;
                     }
 
@@ -1947,7 +2212,11 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
                     }
                     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;
 
@@ -1973,9 +2242,10 @@ static void httpd_Thread( httpd_sys_t *p_httpt )
 
         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 );
-    _UnregisterFile( p_httpt, p_page_admin );
 }