]> git.sesse.net Git - vlc/blobdiff - modules/access/http.c
* Don't bitch anymore about not found access_demux plugins.
[vlc] / modules / access / http.c
index c98d1798dc20e1d78fd53efff6116efddc5c14c6..02e82cd27c3da6b0822cec2b9e9795f15c43ade4 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * http.c: HTTP access plug-in
+ * http.c: HTTP input module
  *****************************************************************************
  * Copyright (C) 2001-2004 VideoLAN
- * $Id: http.c,v 1.55 2004/01/15 12:55:41 fenrir Exp $
+ * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Christophe Massiot <massiot@via.ecp.fr>
@@ -39,9 +39,9 @@
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
-#define PROXY_TEXT N_("Specify an HTTP proxy")
+#define PROXY_TEXT N_("HTTP proxy")
 #define PROXY_LONGTEXT N_( \
-    "Specify an HTTP proxy to use. It must be in the form " \
+    "You can specify an HTTP proxy to use. It must be of the form " \
     "http://myproxy.mydomain:myport/. If none is specified, the HTTP_PROXY " \
     "environment variable will be tried." )
 
@@ -50,15 +50,37 @@ static void Close( vlc_object_t * );
     "Allows you to modify the default caching value for http streams. This " \
     "value should be set in millisecond units." )
 
+#define USER_TEXT N_("HTTP user name")
+#define USER_LONGTEXT N_("Allows you to modify the user name that will " \
+    "be used for the connection (Basic authentication only).")
+
+#define PASS_TEXT N_("HTTP password")
+#define PASS_LONGTEXT N_("Allows you to modify the password that will be " \
+    "used for the connection.")
+
+#define AGENT_TEXT N_("HTTP user agent")
+#define AGENT_LONGTEXT N_("Allows you to modify the user agent that will be " \
+    "used for the connection.")
+
+#define RECONNECT_TEXT N_("Auto re-connect")
+#define RECONNECT_LONGTEXT N_("Will automatically attempt a re-connection " \
+    "in case it was untimely closed.")
+
 vlc_module_begin();
     set_description( _("HTTP input") );
-    set_capability( "access", 0 );
-    add_category_hint( N_("http"), NULL, VLC_FALSE );
-        add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT, VLC_FALSE );
-        add_integer( "http-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
-        add_string( "http-user", NULL, NULL, "HTTP user name", "HTTP user name for Basic Authentification", VLC_FALSE );
-        add_string( "http-pwd", NULL , NULL, "HTTP password", "HTTP password for Basic Authentification", VLC_FALSE );
-        add_string( "http-user-agent", COPYRIGHT_MESSAGE , NULL, "HTTP user agent", "HTTP user agent", VLC_FALSE );
+    set_capability( "access2", 0 );
+
+    add_string( "http-proxy", NULL, NULL, PROXY_TEXT, PROXY_LONGTEXT,
+                VLC_FALSE );
+    add_integer( "http-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
+                 CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
+    add_string( "http-user", NULL, NULL, USER_TEXT, USER_LONGTEXT, VLC_FALSE );
+    add_string( "http-pwd", NULL , NULL, PASS_TEXT, PASS_LONGTEXT, VLC_FALSE );
+    add_string( "http-user-agent", COPYRIGHT_MESSAGE , NULL, AGENT_TEXT,
+                AGENT_LONGTEXT, VLC_FALSE );
+    add_bool( "http-reconnect", 0, NULL, RECONNECT_TEXT,
+              RECONNECT_LONGTEXT, VLC_TRUE );
+
     add_shortcut( "http" );
     add_shortcut( "http4" );
     add_shortcut( "http6" );
@@ -90,16 +112,21 @@ struct access_sys_t
     char       *psz_mime;
     char       *psz_location;
 
-    int64_t    i_tell;
-    int64_t    i_size;
-};
+    vlc_bool_t b_chunked;
+    int64_t    i_chunk;
 
-static void    Seek( input_thread_t *, off_t );
-static ssize_t Read( input_thread_t *, byte_t *, size_t );
+    vlc_bool_t b_seekable;
+    vlc_bool_t b_reconnect;
+};
 
-static void    ParseURL( access_sys_t *, char *psz_url );
-static int     Connect( input_thread_t *, vlc_bool_t *, off_t *, off_t );
+/* */
+static int Read( access_t *, uint8_t *, int );
+static int Seek( access_t *, int64_t );
+static int Control( access_t *, int, va_list );
 
+/* */
+static void ParseURL( access_sys_t *, char *psz_url );
+static int  Connect( access_t *, int64_t );
 static char *b64_encode( unsigned char *src );
 
 /*****************************************************************************
@@ -107,50 +134,63 @@ static char *b64_encode( unsigned char *src );
  *****************************************************************************/
 static int  Open ( vlc_object_t *p_this )
 {
-    input_thread_t *p_input = (input_thread_t*)p_this;
-    access_sys_t   *p_sys;
-    vlc_value_t    val;
-
-    /* Create private struct */
-    p_sys = p_input->p_access_data = malloc( sizeof( access_sys_t ) );
-    memset( p_sys, 0, sizeof( access_sys_t ) );
-    p_sys->fd = -1;
-    p_sys->b_proxy = VLC_FALSE;
-    p_sys->i_version = 1;
-    p_sys->psz_mime = NULL;
-    p_sys->psz_location = NULL;
-    p_sys->psz_user_agent = NULL;
+    access_t     *p_access = (access_t*)p_this;
+    access_sys_t *p_sys;
+    char         *psz;
 
     /* First set ipv4/ipv6 */
-    var_Create( p_input, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-    var_Create( p_input, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
+    var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
 
-    if( *p_input->psz_access )
+    if( *p_access->psz_access )
     {
+        vlc_value_t val;
         /* Find out which shortcut was used */
-        if( !strncmp( p_input->psz_access, "http4", 6 ) )
+        if( !strncmp( p_access->psz_access, "http4", 6 ) )
         {
             val.b_bool = VLC_TRUE;
-            var_Set( p_input, "ipv4", val );
+            var_Set( p_access, "ipv4", val );
 
             val.b_bool = VLC_FALSE;
-            var_Set( p_input, "ipv6", val );
+            var_Set( p_access, "ipv6", val );
         }
-        else if( !strncmp( p_input->psz_access, "http6", 6 ) )
+        else if( !strncmp( p_access->psz_access, "http6", 6 ) )
         {
             val.b_bool = VLC_TRUE;
-            var_Set( p_input, "ipv6", val );
+            var_Set( p_access, "ipv6", val );
 
             val.b_bool = VLC_FALSE;
-            var_Set( p_input, "ipv4", val );
+            var_Set( p_access, "ipv4", val );
         }
     }
 
+    /* Set up p_access */
+    p_access->pf_read = Read;
+    p_access->pf_block = NULL;
+    p_access->pf_control = Control;
+    p_access->pf_seek = Seek;
+    p_access->info.i_update = 0;
+    p_access->info.i_size = 0;
+    p_access->info.i_pos = 0;
+    p_access->info.b_eof = VLC_FALSE;
+    p_access->info.i_title = 0;
+    p_access->info.i_seekpoint = 0;
+    p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
+    memset( p_sys, 0, sizeof( access_sys_t ) );
+    p_sys->fd = -1;
+    p_sys->b_proxy = VLC_FALSE;
+    p_sys->i_version = 1;
+    p_sys->b_seekable = VLC_TRUE;
+    p_sys->psz_mime = NULL;
+    p_sys->psz_location = NULL;
+    p_sys->psz_user_agent = NULL;
+
+
     /* Parse URI */
-    ParseURL( p_sys, p_input->psz_name );
+    ParseURL( p_sys, p_access->psz_path );
     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' )
     {
-        msg_Warn( p_input, "invalid host" );
+        msg_Warn( p_access, "invalid host" );
         goto error;
     }
     if( p_sys->url.i_port <= 0 )
@@ -159,27 +199,19 @@ static int  Open ( vlc_object_t *p_this )
     }
     if( !p_sys->psz_user || *p_sys->psz_user == '\0' )
     {
-        var_Create( p_input, "http-user", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-        var_Get( p_input, "http-user", &val );
-        p_sys->psz_user = val.psz_string;
-
-        var_Create( p_input, "http-pwd", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-        var_Get( p_input, "http-pwd", &val );
-        p_sys->psz_passwd = val.psz_string;
+        p_sys->psz_user = var_CreateGetString( p_access, "http-user" );
+        p_sys->psz_passwd = var_CreateGetString( p_access, "http-pwd" );
     }
 
     /* Do user agent */
-    var_Create( p_input, "http-user-agent", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Get( p_input, "http-user-agent", &val );
-    p_sys->psz_user_agent = val.psz_string;
+    p_sys->psz_user_agent = var_CreateGetString( p_access, "http-user-agent" );
 
     /* Check proxy */
-    var_Create( p_input, "http-proxy", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
-    var_Get( p_input, "http-proxy", &val );
-    if( val.psz_string && *val.psz_string )
+    psz = var_CreateGetString( p_access, "http-proxy" );
+    if( *psz )
     {
         p_sys->b_proxy = VLC_TRUE;
-        vlc_UrlParse( &p_sys->proxy, val.psz_string, 0 );
+        vlc_UrlParse( &p_sys->proxy, psz, 0 );
     }
     else
     {
@@ -187,23 +219,18 @@ static int  Open ( vlc_object_t *p_this )
         if( psz_proxy && *psz_proxy )
         {
             p_sys->b_proxy = VLC_TRUE;
-            vlc_UrlParse( &p_sys->proxy, val.psz_string, 0 );
+            vlc_UrlParse( &p_sys->proxy, psz_proxy, 0 );
         }
         if( psz_proxy )
-        {
             free( psz_proxy );
-        }
-    }
-    if( val.psz_string )
-    {
-        free( val.psz_string );
     }
+    free( psz );
 
     if( p_sys->b_proxy )
     {
         if( p_sys->proxy.psz_host == NULL || *p_sys->proxy.psz_host == '\0' )
         {
-            msg_Warn( p_input, "invalid proxy host" );
+            msg_Warn( p_access, "invalid proxy host" );
             goto error;
         }
         if( p_sys->proxy.i_port <= 0 )
@@ -212,24 +239,29 @@ static int  Open ( vlc_object_t *p_this )
         }
     }
 
-    msg_Dbg( p_input, "http: server='%s' port=%d file='%s", p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path );
+    msg_Dbg( p_access, "http: server='%s' port=%d file='%s",
+             p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path );
     if( p_sys->b_proxy )
     {
-        msg_Dbg( p_input, "      proxy %s:%d", p_sys->proxy.psz_host, p_sys->proxy.i_port );
+        msg_Dbg( p_access, "      proxy %s:%d", p_sys->proxy.psz_host,
+                 p_sys->proxy.i_port );
     }
     if( p_sys->psz_user && *p_sys->psz_user )
     {
-        msg_Dbg( p_input, "      user='%s', pwd='%s'", p_sys->psz_user, p_sys->psz_passwd );
+        msg_Dbg( p_access, "      user='%s', pwd='%s'",
+                 p_sys->psz_user, p_sys->psz_passwd );
     }
 
+    p_sys->b_reconnect = var_CreateGetBool( p_access, "http-reconnect" );
+
     /* Connect */
-    if( Connect( p_input, &p_input->stream.b_seekable, &p_input->stream.p_selected_area->i_size, 0 ) )
+    if( Connect( p_access, 0 ) )
     {
         /* Retry with http 1.0 */
         p_sys->i_version = 0;
 
-        if( p_input->b_die ||
-            Connect( p_input, &p_input->stream.b_seekable, &p_input->stream.p_selected_area->i_size, 0 ) )
+        if( p_access->b_die ||
+            Connect( p_access, 0 ) )
         {
             goto error;
         }
@@ -241,12 +273,13 @@ static int  Open ( vlc_object_t *p_this )
     {
         playlist_t * p_playlist;
 
-        msg_Dbg( p_input, "redirection to %s", p_sys->psz_location );
+        msg_Dbg( p_access, "redirection to %s", p_sys->psz_location );
 
-        p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT );
+        p_playlist = vlc_object_find( p_access, VLC_OBJECT_PLAYLIST,
+                                      FIND_ANYWHERE );
         if( !p_playlist )
         {
-            msg_Err( p_input, "redirection failed: can't find playlist" );
+            msg_Err( p_access, "redirection failed: can't find playlist" );
             goto error;
         }
         p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
@@ -255,39 +288,24 @@ static int  Open ( vlc_object_t *p_this )
                       p_playlist->i_index + 1 );
         vlc_object_release( p_playlist );
 
-        p_sys->i_size = 0;  /* Force to stop reading */
+        p_access->info.i_size = 0;  /* Force to stop reading */
     }
 
-    /* Finish to set up p_input */
-    p_input->pf_read = Read;
-    p_input->pf_set_program = input_SetProgram;
-    p_input->pf_set_area = NULL;
-    p_input->pf_seek = Seek;
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.b_pace_control = VLC_TRUE;
-    p_input->stream.p_selected_area->i_tell = 0;
-    p_input->stream.i_method = INPUT_METHOD_NETWORK;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
-    p_input->i_mtu = 0;
-    if( !strcmp( p_sys->psz_protocol, "ICY" ) &&
-        ( !p_input->psz_demux || !*p_input->psz_demux ) )
+    if( !strcmp( p_sys->psz_protocol, "ICY" ) )
     {
-        if( !strcasecmp( p_sys->psz_mime, "video/nsv" ) )
-        {
-            p_input->psz_demux = strdup( "nsv" );
-        }
+        if( p_sys->psz_mime && !strcasecmp( p_sys->psz_mime, "video/nsv" ) )
+            p_access->psz_demux = strdup( "nsv" );
         else
-        {
-            p_input->psz_demux = strdup( "mp3" );
-        }
-        msg_Info( p_input, "ICY server found, %s demuxer selected", p_input->psz_demux );
+            p_access->psz_demux = strdup( "mp3" );
+
+        msg_Info( p_access, "ICY server found, %s demuxer selected",
+                  p_access->psz_demux );
     }
 
-    /* Update default_pts to a suitable value for http access */
-    var_Create( p_input, "http-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
-    var_Get( p_input, "http-caching", &val );
-    p_input->i_pts_delay = val.i_int * 1000;
+    if( p_sys->b_reconnect ) msg_Dbg( p_access, "auto re-connect enabled" );
+
+    /* PTS delay */
+    var_Create( p_access, "http-caching", VLC_VAR_INTEGER |VLC_VAR_DOINHERIT );
 
     return VLC_SUCCESS;
 
@@ -313,8 +331,8 @@ error:
  *****************************************************************************/
 static void Close( vlc_object_t *p_this )
 {
-    input_thread_t *p_input = (input_thread_t*)p_this;
-    access_sys_t   *p_sys   = p_input->p_access_data;
+    access_t     *p_access = (access_t*)p_this;
+    access_sys_t *p_sys = p_access->p_sys;
 
     vlc_UrlClean( &p_sys->url );
     vlc_UrlClean( &p_sys->proxy );
@@ -335,53 +353,181 @@ static void Close( vlc_object_t *p_this )
 }
 
 /*****************************************************************************
- * Seek: close and re-open a connection at the right place
+ * Read: Read up to i_len bytes from the http connection and place in
+ * p_buffer. Return the actual number of bytes read
  *****************************************************************************/
-static void Seek( input_thread_t * p_input, off_t i_pos )
+static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
 {
-    access_sys_t   *p_sys   = p_input->p_access_data;
+    access_sys_t *p_sys = p_access->p_sys;
+    int i_read;
 
-    msg_Dbg( p_input, "trying to seek to "I64Fd, i_pos );
+    if( p_sys->fd < 0 )
+    {
+        p_access->info.b_eof = VLC_TRUE;
+        return 0;
+    }
 
-    net_Close( p_sys->fd ); p_sys->fd = -1;
+    if( p_access->info.i_size > 0 &&
+        i_len + p_access->info.i_pos > p_access->info.i_size )
+    {
+        if( ( i_len = p_access->info.i_size - p_access->info.i_pos ) == 0 )
+        {
+            p_access->info.b_eof = VLC_TRUE;
+            return 0;
+        }
+    }
+    if( p_sys->b_chunked )
+    {
+        if( p_sys->i_chunk < 0 )
+        {
+            p_access->info.b_eof = VLC_TRUE;
+            return 0;
+        }
+
+        if( p_sys->i_chunk <= 0 )
+        {
+            char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
+            /* read the chunk header */
+            if( psz == NULL )
+            {
+                msg_Dbg( p_access, "failed reading chunk-header line" );
+                return -1;
+            }
+            p_sys->i_chunk = strtoll( psz, NULL, 16 );
+            free( psz );
+
+            if( p_sys->i_chunk <= 0 )   /* eof */
+            {
+                p_sys->i_chunk = -1;
+                p_access->info.b_eof = VLC_TRUE;
+                return 0;
+            }
+        }
+
+        if( i_len > p_sys->i_chunk )
+        {
+            i_len = p_sys->i_chunk;
+        }
+    }
+
+
+    i_read = net_Read( p_access, p_sys->fd, p_buffer, i_len, VLC_FALSE );
+    if( i_read > 0 )
+    {
+        p_access->info.i_pos += i_read;
 
-    if( Connect( p_input, &p_input->stream.b_seekable, &p_input->stream.p_selected_area->i_size, i_pos ) )
+        if( p_sys->b_chunked )
+        {
+            p_sys->i_chunk -= i_read;
+            if( p_sys->i_chunk <= 0 )
+            {
+                /* read the empty line */
+                char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
+                if( psz ) free( psz );
+            }
+        }
+    }
+    else if( i_read == 0 )
     {
-        msg_Err( p_input, "seek failed" );
+        if( p_sys->b_reconnect )
+        {
+            msg_Dbg( p_access, "got disconnected, trying to reconnect" );
+            net_Close( p_sys->fd ); p_sys->fd = -1;
+            if( Connect( p_access, p_access->info.i_pos ) )
+            {
+                msg_Dbg( p_access, "reconnection failed" );
+            }
+            else
+            {
+                p_sys->b_reconnect = VLC_FALSE;
+                i_read = Read( p_access, p_buffer, i_len );
+                p_sys->b_reconnect = VLC_TRUE;
+            }
+        }
+
+        if( i_read == 0 ) p_access->info.b_eof = VLC_TRUE;
     }
 
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.p_selected_area->i_tell = i_pos;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    return i_read;
 }
 
 /*****************************************************************************
- * Read: Read up to i_len bytes from the http connection and place in
- * p_buffer. Return the actual number of bytes read
+ * Seek: close and re-open a connection at the right place
  *****************************************************************************/
-static ssize_t Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
+static int Seek( access_t *p_access, int64_t i_pos )
 {
-    access_sys_t   *p_sys   = p_input->p_access_data;
-    int            i_read;
+    access_sys_t *p_sys = p_access->p_sys;
 
-    if( p_sys->fd < 0 )
-    {
-        return -1;
-    }
-    if( p_sys->i_size > 0 && i_len + p_sys->i_tell > p_sys->i_size )
+    msg_Dbg( p_access, "trying to seek to "I64Fd, i_pos );
+
+    net_Close( p_sys->fd ); p_sys->fd = -1;
+
+    if( Connect( p_access, i_pos ) )
     {
-        if( ( i_len = p_sys->i_size - p_sys->i_tell ) == 0 )
-        {
-            return 0;
-        }
+        msg_Err( p_access, "seek failed" );
+        p_access->info.b_eof = VLC_TRUE;
+        return VLC_EGENERIC;
     }
+    return VLC_SUCCESS;
+}
 
-    i_read = net_Read( p_input, p_sys->fd, p_buffer, i_len, VLC_FALSE );
-    if( i_read > 0 )
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( access_t *p_access, int i_query, va_list args )
+{
+    access_sys_t *p_sys = p_access->p_sys;
+    vlc_bool_t   *pb_bool;
+    int          *pi_int;
+    int64_t      *pi_64;
+
+    switch( i_query )
     {
-        p_sys->i_tell += i_read;
+        /* */
+        case ACCESS_CAN_SEEK:
+            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
+            *pb_bool = p_sys->b_seekable;
+            break;
+        case ACCESS_CAN_FASTSEEK:
+            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
+            *pb_bool = VLC_FALSE;
+            break;
+        case ACCESS_CAN_PAUSE:
+            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
+            *pb_bool = VLC_TRUE;    /* FIXME */
+            break;
+        case ACCESS_CAN_CONTROL_PACE:
+            pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
+            *pb_bool = VLC_TRUE;    /* FIXME */
+            break;
+
+        /* */
+        case ACCESS_GET_MTU:
+            pi_int = (int*)va_arg( args, int * );
+            *pi_int = 0;
+            break;
+
+        case ACCESS_GET_PTS_DELAY:
+            pi_64 = (int64_t*)va_arg( args, int64_t * );
+            *pi_64 = (int64_t)var_GetInteger( p_access, "http-caching" ) * 1000;
+            break;
+
+        /* */
+        case ACCESS_SET_PAUSE_STATE:
+            break;
+
+        case ACCESS_GET_TITLE_INFO:
+        case ACCESS_SET_TITLE:
+        case ACCESS_SET_SEEKPOINT:
+        case ACCESS_SET_PRIVATE_ID_STATE:
+            return VLC_EGENERIC;
+
+        default:
+            msg_Warn( p_access, "unimplemented query in control" );
+            return VLC_EGENERIC;
+
     }
-    return i_read;
+    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -435,9 +581,9 @@ static void ParseURL( access_sys_t *p_sys, char *psz_url )
 /*****************************************************************************
  * Connect:
  *****************************************************************************/
-static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_size, off_t i_tell )
+static int Connect( access_t *p_access, int64_t i_tell )
 {
-    access_sys_t   *p_sys   = p_input->p_access_data;
+    access_sys_t   *p_sys = p_access->p_sys;
     vlc_url_t      srv = p_sys->b_proxy ? p_sys->proxy : p_sys->url;
     char           *psz;
 
@@ -447,24 +593,39 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
 
     p_sys->psz_location = NULL;
     p_sys->psz_mime = NULL;
-    p_sys->i_size = -1;
-    p_sys->i_tell = i_tell;
+    p_sys->b_chunked = VLC_FALSE;
+    p_sys->i_chunk = 0;
+
+    p_access->info.i_size = 0;
+    p_access->info.i_pos  = i_tell;
+    p_access->info.b_eof  = VLC_FALSE;
 
 
     /* Open connection */
-    p_sys->fd = net_OpenTCP( p_input, srv.psz_host, srv.i_port );
+    p_sys->fd = net_OpenTCP( p_access, srv.psz_host, srv.i_port );
     if( p_sys->fd < 0 )
     {
-        msg_Err( p_input, "cannot connect to %s:%d", srv.psz_host, srv.i_port );
+        msg_Err( p_access, "cannot connect to %s:%d", srv.psz_host, srv.i_port );
         return VLC_EGENERIC;
     }
 
     if( p_sys->b_proxy )
     {
-        net_Printf( VLC_OBJECT(p_input), p_sys->fd,
-                    "GET http://%s:%d/%s HTTP/1.%d\r\n",
-                    p_sys->url.psz_host, p_sys->url.i_port, p_sys->url.psz_path,
-                    p_sys->i_version );
+        if( p_sys->url.psz_path )
+        {
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+                        "GET http://%s:%d/%s HTTP/1.%d\r\n",
+                        p_sys->url.psz_host, p_sys->url.i_port,
+                        p_sys->url.psz_path, p_sys->i_version );
+        }
+        else
+        {
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+                        "GET http://%s:%d/ HTTP/1.%d\r\n",
+                        p_sys->url.psz_host, p_sys->url.i_port,
+                        p_sys->i_version );
+
+        }
     }
     else
     {
@@ -473,17 +634,27 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
         {
             psz_path = "/";
         }
-        net_Printf( VLC_OBJECT(p_input), p_sys->fd,
-                    "GET %s HTTP/1.%d\r\n"
-                    "Host: %s\r\n",
-                    psz_path, p_sys->i_version, p_sys->url.psz_host );
+        if( p_sys->url.i_port != 80)
+        {
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+                        "GET %s HTTP/1.%d\r\nHost: %s:%d\r\n",
+                        psz_path, p_sys->i_version, p_sys->url.psz_host,
+                        p_sys->url.i_port );
+        }
+        else
+        {        
+            net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+                        "GET %s HTTP/1.%d\r\nHost: %s\r\n",
+                        psz_path, p_sys->i_version, p_sys->url.psz_host );
+        }
     }
     /* User Agent */
-    net_Printf( VLC_OBJECT(p_input), p_sys->fd, "User-Agent: %s\r\n", p_sys->psz_user_agent );
+    net_Printf( VLC_OBJECT(p_access), p_sys->fd, "User-Agent: %s\r\n",
+                p_sys->psz_user_agent );
     /* Offset */
     if( p_sys->i_version == 1 )
     {
-        net_Printf( VLC_OBJECT(p_input), p_sys->fd,
+        net_Printf( VLC_OBJECT(p_access), p_sys->fd,
                     "Range: bytes="I64Fd"-\r\n", i_tell );
     }
     /* Authentification */
@@ -497,26 +668,23 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
 
         b64 = b64_encode( buf );
 
-        net_Printf( VLC_OBJECT(p_input), p_sys->fd, "Authorization: Basic %s", b64 );
+        net_Printf( VLC_OBJECT(p_access), p_sys->fd,
+                    "Authorization: Basic %s\r\n", b64 );
         free( b64 );
     }
-    net_Printf( VLC_OBJECT(p_input), p_sys->fd, "Connection: Close\r\n" );
+    net_Printf( VLC_OBJECT(p_access), p_sys->fd, "Connection: Close\r\n" );
 
-    if( net_Printf( VLC_OBJECT(p_input), p_sys->fd, "\r\n" ) < 0 )
+    if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, "\r\n" ) < 0 )
     {
-        msg_Err( p_input, "Failed to send request\n" );
+        msg_Err( p_access, "failed to send request" );
         net_Close( p_sys->fd ); p_sys->fd = -1;
         return VLC_EGENERIC;
     }
 
-    /* Set values */
-    *pb_seekable = p_sys->i_version == 1 ? VLC_TRUE : VLC_FALSE;
-    *pi_size = 0;
-
     /* Read Answer */
-    if( ( psz = net_Gets( VLC_OBJECT(p_input), p_sys->fd ) ) == NULL )
+    if( ( psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd ) ) == NULL )
     {
-        msg_Err( p_input, "Failed to read answer\n" );
+        msg_Err( p_access, "failed to read answer" );
         goto error;
     }
     if( !strncmp( psz, "HTTP/1.", 7 ) )
@@ -528,25 +696,27 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
     {
         p_sys->psz_protocol = "ICY";
         p_sys->i_code = atoi( &psz[4] );
+        p_sys->b_reconnect = VLC_TRUE;
     }
     else
     {
-        msg_Err( p_input, "invalid HTTP reply '%s'", psz );
+        msg_Err( p_access, "invalid HTTP reply '%s'", psz );
         free( psz );
         goto error;
     }
-    msg_Dbg( p_input, "Protocol '%s' answer code %d", p_sys->psz_protocol, p_sys->i_code );
+    msg_Dbg( p_access, "protocol '%s' answer code %d",
+             p_sys->psz_protocol, p_sys->i_code );
     if( !strcmp( p_sys->psz_protocol, "ICY" ) )
     {
-        *pb_seekable = VLC_FALSE;
+        p_sys->b_seekable = VLC_FALSE;
     }
     if( p_sys->i_code != 206 )
     {
-        *pb_seekable = VLC_FALSE;
+        p_sys->b_seekable = VLC_FALSE;
     }
     if( p_sys->i_code >= 400 )
     {
-        msg_Err( p_input, "error: %s", psz );
+        msg_Err( p_access, "error: %s", psz );
         free( psz );
         goto error;
     }
@@ -554,16 +724,16 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
 
     for( ;; )
     {
-        char *psz = net_Gets( VLC_OBJECT(p_input), p_sys->fd );
+        char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd );
         char *p;
 
         if( psz == NULL )
         {
-            msg_Err( p_input, "Failed to read answer\n" );
+            msg_Err( p_access, "failed to read answer" );
             goto error;
         }
 
-        msg_Dbg( p_input, "Line=%s", psz );
+        /* msg_Dbg( p_input, "Line=%s", psz ); */
         if( *psz == '\0' )
         {
             free( psz );
@@ -573,16 +743,17 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
 
         if( ( p = strchr( psz, ':' ) ) == NULL )
         {
-            msg_Err( p_input, "malformed header line: %s", psz );
+            msg_Err( p_access, "malformed header line: %s", psz );
             free( psz );
             goto error;
         }
         *p++ = '\0';
+        while( *p == ' ' ) p++;
 
         if( !strcasecmp( psz, "Content-Length" ) )
         {
-            *pi_size = p_sys->i_size = i_tell + atoll( p );
-            msg_Dbg( p_input, "stream size="I64Fd, p_sys->i_size );
+            p_access->info.i_size = i_tell + atoll( p );
+            msg_Dbg( p_access, "stream size="I64Fd, p_access->info.i_size );
         }
         else if( !strcasecmp( psz, "Location" ) )
         {
@@ -593,6 +764,21 @@ static int Connect( input_thread_t *p_input, vlc_bool_t *pb_seekable, off_t *pi_
         {
             if( p_sys->psz_mime ) free( p_sys->psz_mime );
             p_sys->psz_mime = strdup( p );
+            msg_Dbg( p_access, "Content-Type: %s", p_sys->psz_mime );
+        }
+        else if( !strcasecmp( psz, "Server" ) &&
+                 !strncasecmp( p, "Icecast", 7 ) )
+        {
+            p_sys->b_reconnect = VLC_TRUE;
+            msg_Dbg( p_access, "Server: %s", p );
+        }
+        else if( !strcasecmp( psz, "Transfer-Encoding" ) )
+        {
+            msg_Dbg( p_access, "Transfer-Encoding: %s", p );
+            if( !strncasecmp( p, "chunked", 7 ) )
+            {
+                p_sys->b_chunked = VLC_TRUE;
+            }
         }
 
         free( psz );