]> git.sesse.net Git - vlc/blobdiff - modules/misc/httpd.c
* Fix segfault when we have two announces with the same URI but different names on...
[vlc] / modules / misc / httpd.c
index c5756a38ce27bbedb8295c1ec5749296042a5dc7..c32323bac3cc45c86a7ed9f1fcddfbda3e8573e3 100644 (file)
@@ -2,7 +2,7 @@
  * httpd.c
  *****************************************************************************
  * Copyright (C) 2001-2003 VideoLAN
- * $Id: httpd.c,v 1.20 2003/07/01 21:32:32 fenrir Exp $
+ * $Id: httpd.c,v 1.29 2003/10/08 11:24:59 zorglub 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
 {
@@ -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;
@@ -247,8 +267,11 @@ 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:
  *****************************************************************************/
@@ -269,19 +292,36 @@ 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;
 
-    vlc_mutex_init( p_httpd, &p_httpt->ban_lock );
+    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;
 
@@ -311,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 );
 }
@@ -539,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;
@@ -622,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 );
@@ -643,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;
 }
 
@@ -673,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
     {
@@ -743,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
     {
@@ -768,6 +862,11 @@ static httpd_stream_t  *_RegisterStream( httpd_sys_t *p_httpt,
     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;
@@ -880,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) */
@@ -895,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 );
@@ -909,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 ) );
@@ -929,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 );
@@ -938,196 +1045,167 @@ static int             HeaderStream( httpd_t *p_httpd, httpd_stream_t *p_stream,
     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 )
+static void httpd_info_add_ss( httpd_info_t *p_info, char *name, char *value )
 {
-    char *p;
-
-    p = *pp_data = malloc( 1024 );
-
-    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;
+    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 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 );
+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 */
 
-    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" );
+    sprintf( v, "%d", i_value );
+    httpd_info_add_ss( p_info, name, v );
+}
 
-    *pi_data = strlen( *pp_data ) + 1;
+static void httpd_info_add_sp( httpd_info_t *p_info, char *name, void *value )
+{
+    char v[40];
 
-    return VLC_SUCCESS;
+    sprintf( v, "%p", value );
+    httpd_info_add_ss( p_info, name, v );
 }
 
 
-static int _httpd_page_admin_get_status( httpd_file_callback_args_t *p_args,
-                                         uint8_t **pp_data, int *pi_data )
+static int Control( httpd_t *p_httpd,
+                    int i_query, void *arg1, void *arg2 )
 {
-    httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
+    httpd_sys_t  *p_httpt = p_httpd->p_sys;
+    httpd_info_t *p_info;
     httpd_connection_t *p_con;
-    httpd_banned_ip_t *p_ip;
-
     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, "<li>Ban count: %d</li>\n", p_httpt->i_banned_ip_count );
-    p += sprintf( p, "</ul>\n" );
-
-    /* ban list */
-    /* XXX do not lock on ban_lock */
-    p += sprintf( p, "<h3>Ban list</h3>\n" );
-    p += sprintf( p, "<table border=\"1\" cellspacing=\"0\" >\n" );
-    p += sprintf( p, "<tr>\n<th>IP</th>\n<th>Action</th></tr>\n" );
-    for( p_ip = p_httpt->p_first_banned_ip;p_ip != NULL; p_ip = p_ip->p_next )
-    {
-        p += sprintf( p, "<tr>\n" );
-        p += sprintf( p, "<td>%s</td>\n", p_ip->psz_ip );
-        p += sprintf( p, "<td><form method=\"get\" action=\"\">"
-                         "<select name=\"action\">"
-                         "<option selected>unban_ip</option>"
-                         "</select>"
-                         "<input type=\"hidden\" name=\"id\" value=\"%s\"/>"
-                         "<input type=\"submit\" value=\"Do it\" />"
-                         "</form></td>\n", p_ip->psz_ip);
-        p += sprintf( p, "</tr>\n" );
-    }
-    p += sprintf( p, "</table>\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" );
+    void *id;
 
-    for( i = 0; i < p_httpt->i_host_count; i++ )
+    switch( i_query )
     {
-        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" );
+        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;
 
-    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" );
+        case HTTPD_SET_CLOSE:
+            sscanf( arg1, "%p", &id );
+            fprintf( stderr, "Control: HTTPD_SET_CLOSE: id=%p", id );
 
-    /* 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( 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;
 
-    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" );
-        }
+        case HTTPD_SET_ACL:
+            sscanf( arg1, "%p", &id );
+            fprintf( stderr, "Control: %p", id );
+        default:
+            return VLC_EGENERIC;
     }
-    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" );
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+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;
 
-    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>"
-                         "<option>close_connection_and_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, "<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" );
@@ -1135,27 +1213,27 @@ static int _httpd_page_admin_get_status( httpd_file_callback_args_t *p_args,
 
     *pi_data = strlen( *pp_data ) + 1;
 
-    return( VLC_SUCCESS );
+    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 )
+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( 8096 );
+    p = *pp_data = malloc( 1024 );
+    if( !p )
+    {
+        return VLC_ENOMEM ;
+    }
 
     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 401</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, "<a href=\"admin.html\">Retour a la page d'administration</a>\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" );
@@ -1163,27 +1241,26 @@ static int _httpd_page_admin_get_success( httpd_file_callback_args_t *p_args,
 
     *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 )
+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( 8096 );
+    p = *pp_data = malloc( 1024 );
+    if( !p )
+    {
+        return VLC_ENOMEM ;
+    }
 
     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>Error=`%s'</p>", psz_error );
-    p += sprintf( p, "<a href=\"admin.html\">Retour a la page d'administration</a>\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" );
@@ -1191,154 +1268,10 @@ static int _httpd_page_admin_get_error( httpd_file_callback_args_t *p_args,
 
     *pi_data = strlen( *pp_data ) + 1;
 
-    return( VLC_SUCCESS );
-}
-
-static void _httpd_uri_extract_value( char *psz_uri, char *psz_name, char *psz_value, int i_value_max )
-{
-    char *p;
-
-    p = strstr( psz_uri, psz_name );
-    if( p )
-    {
-        int i_len;
-
-        p += strlen( psz_name );
-        if( *p == '=' ) p++;
-
-        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
-        {
-            strncpy( psz_value, "", i_value_max );
-        }
-    }
-    else
-    {
-        strncpy( psz_value, "", i_value_max );
-    }
-}
-
-
-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 )
-{
-    httpd_sys_t *p_httpt = (httpd_sys_t*)p_args;
-    httpd_connection_t *p_con;
-
-    if( i_request > 0)
-    {
-        char action[512];
-
-        _httpd_uri_extract_value( p_request, "action", action, 512 );
-
-        if( !strcmp( action, "close_connection" ) )
-        {
-            char id[128];
-            void *i_id;
-
-            _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" ) )
-        {
-            char id[128];
-            void *i_id;
-
-            _httpd_uri_extract_value( p_request, "id", id, 512 );
-            i_id = (void*)strtol( id, NULL, 0 );
-
-            msg_Dbg( p_httpt, "requested banning ip 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 )
-                {
-                    if( httpd_BanIP( p_httpt,inet_ntoa( p_con->sock.sin_addr ) ) == 0)
-                        return( _httpd_page_admin_get_success( p_args, pp_data, pi_data, "IP banned" ) );
-                    else
-                        break;
-                }
-            }
-
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, action ) );
-        }
-        else if( !strcmp( action, "unban_ip" ) )
-        {
-            char id[128];
-
-            _httpd_uri_extract_value( p_request, "id", id, 512 );
-            msg_Dbg( p_httpt, "requested unbanning ip %s", id);
-
-            if( httpd_UnbanIP( p_httpt, httpd_GetbannedIP ( p_httpt, id ) ) == 0)
-                return( _httpd_page_admin_get_success( p_args, pp_data, pi_data, "IP Unbanned" ) );
-            else
-                return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, action ) );
-        }
-        else if( !strcmp( action, "close_connection_and_ban_ip" ) )
-        {
-            char id[128];
-            void *i_id;
-
-            _httpd_uri_extract_value( p_request, "id", id, 512 );
-            i_id = (void*)strtol( id, NULL, 0 );
-            msg_Dbg( p_httpt, "requested closing connection and banning ip 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;
-
-                    if( httpd_BanIP( p_httpt,inet_ntoa( p_con->sock.sin_addr ) ) == 0)
-                        return( _httpd_page_admin_get_success( p_args, pp_data, pi_data, "Connection closed and IP banned" ) );
-                    else
-                        break;
-                }
-
-            }
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, "invalid id" ) );
-
-
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, action ) );
-        }
-        else
-        {
-            return( _httpd_page_admin_get_error( p_args, pp_data, pi_data, action ) );
-        }
-    }
-    else
-    {
-        return( _httpd_page_admin_get_status( p_args, pp_data, pi_data ) );
-    }
-
     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 ;
@@ -1382,7 +1315,7 @@ static int httpd_BanIP( httpd_sys_t *p_httpt, char * psz_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;
@@ -1449,6 +1382,11 @@ static void httpd_ConnnectionNew( httpd_sys_t *p_httpt, int fd, struct sockaddr_
 
     /* 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();
@@ -1466,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 )
@@ -1568,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;
@@ -1632,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;
@@ -1647,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" ) )
@@ -1659,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 */
@@ -1683,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" ) )
         {
@@ -1705,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, ':' );
@@ -1719,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, '?' ) )
@@ -1754,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 );
@@ -1765,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 ) )
             {
@@ -1792,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;
@@ -1839,19 +1831,56 @@ search_file:
     }
 
     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 );
     }
-    p += sprintf( p, "Cache-Control: no-cache\r\n" );
+#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],
@@ -1860,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;
 
@@ -1873,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,
@@ -1885,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 )
     {
@@ -1967,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;
         }
 
@@ -2068,7 +2104,9 @@ 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 defined( WIN32 ) || defined( UNDER_CE )
                 if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )
@@ -2094,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,
@@ -2111,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;
                                 }
@@ -2153,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;
                     }
 
@@ -2202,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 );
 }