/*****************************************************************************
* Preamble
*****************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <vlc/vlc.h>
#include <vlc_strings.h>
#include <vlc_input.h>
+#ifdef HAVE_ZLIB_H
+# include <zlib.h>
+#endif
+
/*****************************************************************************
* Module descriptor
*****************************************************************************/
"You should not globally enable this option as it will break all other " \
"types of HTTP streams." )
+#define FORWARD_COOKIES_TEXT N_("Forward Cookies")
+#define FORWARD_COOKIES_LONGTEXT N_("Forward Cookies Across http redirections ")
+
vlc_module_begin();
set_description( _("HTTP input") );
set_capability( "access2", 0 );
RECONNECT_LONGTEXT, VLC_TRUE );
add_bool( "http-continuous", 0, NULL, CONTINUOUS_TEXT,
CONTINUOUS_LONGTEXT, VLC_TRUE );
+ add_bool( "http-forward-cookies", 0, NULL, FORWARD_COOKIES_TEXT,
+ FORWARD_COOKIES_LONGTEXT, VLC_TRUE );
add_obsolete_string("http-user");
add_obsolete_string("http-pwd");
add_shortcut( "http" );
vlc_bool_t b_mms;
vlc_bool_t b_icecast;
vlc_bool_t b_ssl;
+#ifdef HAVE_ZLIB_H
+ vlc_bool_t b_compressed;
+ struct
+ {
+ z_stream stream;
+ uint8_t *p_buffer;
+ } inflate;
+#endif
vlc_bool_t b_chunked;
int64_t i_chunk;
vlc_bool_t b_reconnect;
vlc_bool_t b_continuous;
vlc_bool_t b_pace_control;
-
+
vlc_array_t * cookies;
};
/* */
-static int OpenWithRedirectionStatus( vlc_object_t *p_this, vlc_bool_t b_is_from_redirection );
+static int OpenWithCookies( vlc_object_t *p_this, vlc_array_t *cookies );
/* */
static ssize_t Read( access_t *, uint8_t *, size_t );
+static ssize_t ReadCompressed( access_t *, uint8_t *, size_t );
static int Seek( access_t *, int64_t );
static int Control( access_t *, int, va_list );
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
- return OpenWithRedirectionStatus( p_this, VLC_FALSE );
+ return OpenWithCookies( p_this, NULL );
}
-static int OpenWithRedirectionStatus( vlc_object_t *p_this, vlc_bool_t b_is_from_redirection )
+static int OpenWithCookies( vlc_object_t *p_this, vlc_array_t *cookies )
{
access_t *p_access = (access_t*)p_this;
access_sys_t *p_sys;
char *psz, *p;
-
- vlc_array_t * saved_cookies = b_is_from_redirection ? p_access->p_sys->cookies : vlc_array_new();
+ /* Only forward an store cookies if the corresponding option is activated */
+ vlc_bool_t b_forward_cookies = var_CreateGetBool( p_access, "http-forward-cookies" );
+ vlc_array_t * saved_cookies = b_forward_cookies ? (cookies ?: vlc_array_new()) : NULL;
/* Set up p_access */
STANDARD_READ_ACCESS_INIT;
+#ifdef HAVE_ZLIB_H
+ p_access->pf_read = ReadCompressed;
+#endif
p_sys->fd = -1;
p_sys->b_proxy = VLC_FALSE;
p_sys->i_version = 1;
p_sys->psz_user_agent = NULL;
p_sys->b_pace_control = VLC_TRUE;
p_sys->b_ssl = VLC_FALSE;
+#ifdef HAVE_ZLIB_H
+ p_sys->b_compressed = VLC_FALSE;
+ /* 15 is the max windowBits, +32 to enable optional gzip decoding */
+ if( inflateInit2( &p_sys->inflate.stream, 32+15 ) != Z_OK )
+ msg_Warn( p_access, "Error during zlib initialisation: %s",
+ p_sys->inflate.stream.msg );
+ if( zlibCompileFlags() & (1<<17) )
+ msg_Warn( p_access, "Your zlib was compiled without gzip support." );
+ p_sys->inflate.p_buffer = NULL;
+#endif
p_sys->p_tls = NULL;
p_sys->p_vs = NULL;
p_sys->i_icy_meta = 0;
p_sys->psz_icy_genre = NULL;
p_sys->psz_icy_title = NULL;
p_sys->i_remaining = 0;
+
p_sys->cookies = saved_cookies;
/* Parse URI - remove spaces */
psz_login, psz_password );
if( psz_login ) p_sys->url.psz_username = strdup( psz_login );
if( psz_password ) p_sys->url.psz_password = strdup( psz_password );
- if( psz_login ) free( psz_login );
- if( psz_password ) free( psz_password );
+ free( psz_login );
+ free( psz_password );
goto connect;
}
else
{
- if( psz_login ) free( psz_login );
- if( psz_password ) free( psz_password );
+ free( psz_login );
+ free( psz_password );
goto error;
}
}
p_sys->psz_location && *p_sys->psz_location )
{
msg_Dbg( p_access, "redirection to %s", p_sys->psz_location );
- printf("redirection to %s", p_sys->psz_location );
-
/* Do not accept redirection outside of HTTP works */
if( strncmp( p_sys->psz_location, "http", 4 )
free( p_sys->psz_user_agent );
Disconnect( p_access );
+ cookies = p_sys->cookies;
free( p_sys );
/* Do new Open() run with new data */
- return OpenWithRedirectionStatus( p_this, VLC_TRUE );
+ return OpenWithCookies( p_this, cookies );
}
if( p_sys->b_mms )
Disconnect( p_access );
- int i;
- for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
- free(vlc_array_item_at_index( p_sys->cookies, i ));
- vlc_array_destroy( p_sys->cookies );
+ if( p_sys->cookies )
+ {
+ int i;
+ for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
+ free(vlc_array_item_at_index( p_sys->cookies, i ));
+ vlc_array_destroy( p_sys->cookies );
+ }
+
+#ifdef HAVE_ZLIB_H
+ inflateEnd( &p_sys->inflate.stream );
+ free( p_sys->inflate.p_buffer );
+#endif
free( p_sys );
}
}
}
- if( p_sys->b_continuous && i_len > p_sys->i_remaining )
+ if( p_sys->b_continuous && (ssize_t)i_len > p_sys->i_remaining )
{
/* Only ask for the remaining length */
int i_new_len = p_sys->i_remaining;
{
/* read the empty line */
char *psz = net_Gets( VLC_OBJECT(p_access), p_sys->fd, p_sys->p_vs );
- if( psz ) free( psz );
+ free( psz );
}
}
}
if( !p_sys->psz_icy_title ||
strcmp( p_sys->psz_icy_title, &p[1] ) )
{
- if( p_sys->psz_icy_title )
- free( p_sys->psz_icy_title );
+ free( p_sys->psz_icy_title );
p_sys->psz_icy_title = strdup( &p[1] );
p_access->info.i_update |= INPUT_UPDATE_META;
return VLC_SUCCESS;
}
+#ifdef HAVE_ZLIB_H
+static ssize_t ReadCompressed( access_t *p_access, uint8_t *p_buffer,
+ size_t i_len )
+{
+ access_sys_t *p_sys = p_access->p_sys;
+
+ if( p_sys->b_compressed )
+ {
+ int i_ret;
+
+ if( !p_sys->inflate.p_buffer )
+ p_sys->inflate.p_buffer = malloc( 256 * 1024 );
+
+ if( p_sys->inflate.stream.avail_in == 0 )
+ {
+ ssize_t i_read = Read( p_access, p_sys->inflate.p_buffer + p_sys->inflate.stream.avail_in, 256 * 1024 );
+ if( i_read <= 0 ) return i_read;
+ p_sys->inflate.stream.next_in = p_sys->inflate.p_buffer;
+ p_sys->inflate.stream.avail_in = i_read;
+ }
+
+ p_sys->inflate.stream.avail_out = i_len;
+ p_sys->inflate.stream.next_out = p_buffer;
+
+ i_ret = inflate( &p_sys->inflate.stream, Z_SYNC_FLUSH );
+ msg_Warn( p_access, "inflate return value: %d, %s", i_ret, p_sys->inflate.stream.msg );
+
+ return i_len - p_sys->inflate.stream.avail_out;
+ }
+ else
+ {
+ return Read( p_access, p_buffer, i_len );
+ }
+}
+#endif
+
/*****************************************************************************
* Seek: close and re-open a connection at the right place
*****************************************************************************/
i_status = 0;
free( psz );
+
+ if( p_access->b_die || p_access->b_error )
+ {
+ Disconnect( p_access );
+ return -1;
+ }
}
while( i_status );
}
{
psz_path = "/";
}
- if( p_sys->url.i_port != 80)
+ if( p_sys->url.i_port != (pvs ? 443 : 80) )
{
net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs,
"GET %s HTTP/1.%d\r\nHost: %s:%d\r\n",
}
/* Cookies */
- int i;
- for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
+ if( p_sys->cookies )
{
- const char * cookie = vlc_array_item_at_index( p_sys->cookies, i );
- char * psz_cookie_content = cookie_get_content( cookie );
- char * psz_cookie_domain = cookie_get_domain( cookie );
- if( psz_cookie_content &&
- /* Check to see if we are in the right domain */
- ( !psz_cookie_domain || strstr( p_sys->url.psz_host, psz_cookie_domain ))
- )
+ int i;
+ for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
{
- msg_Dbg( p_access, "Sending Cookie %s", psz_cookie_content );
- if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "Cookie: %s\r\n", psz_cookie_content ) < 0 )
- msg_Err( p_access, "failed to send Cookie" );
+ const char * cookie = vlc_array_item_at_index( p_sys->cookies, i );
+ char * psz_cookie_content = cookie_get_content( cookie );
+ char * psz_cookie_domain = cookie_get_domain( cookie );
+
+ assert( psz_cookie_content );
+
+ /* FIXME: This is clearly not conforming to the rfc */
+ vlc_bool_t is_in_right_domain = (!psz_cookie_domain || strstr( p_sys->url.psz_host, psz_cookie_domain ));
+
+ if( is_in_right_domain )
+ {
+ msg_Dbg( p_access, "Sending Cookie %s", psz_cookie_content );
+ if( net_Printf( VLC_OBJECT(p_access), p_sys->fd, pvs, "Cookie: %s\r\n", psz_cookie_content ) < 0 )
+ msg_Err( p_access, "failed to send Cookie" );
+ }
+ free( psz_cookie_content );
+ free( psz_cookie_domain );
}
- free( psz_cookie_content );
- free( psz_cookie_domain );
}
/* Authentication */
goto error;
}
+ if( p_access->b_die || p_access->b_error )
+ {
+ free( psz );
+ goto error;
+ }
+
/* msg_Dbg( p_input, "Line=%s", psz ); */
if( *psz == '\0' )
{
break;
}
-
if( ( p = strchr( psz, ':' ) ) == NULL )
{
msg_Err( p_access, "malformed header line: %s", psz );
if( p_sys->url.i_port == ( p_sys->b_ssl ? 443 : 80 ) )
{
- asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
- p_sys->url.psz_host, p);
+ if( asprintf(&psz_new_loc, "http%s://%s%s", psz_http_ext,
+ p_sys->url.psz_host, p) < 0 )
+ goto error;
}
else
{
- asprintf(&psz_new_loc, "http%s://%s:%d%s", psz_http_ext,
- p_sys->url.psz_host, p_sys->url.i_port, p);
+ if( asprintf(&psz_new_loc, "http%s://%s:%d%s", psz_http_ext,
+ p_sys->url.psz_host, p_sys->url.i_port, p) < 0 )
+ goto error;
}
}
else
psz_new_loc = strdup( p );
}
- if( p_sys->psz_location ) free( p_sys->psz_location );
+ free( p_sys->psz_location );
p_sys->psz_location = psz_new_loc;
}
else if( !strcasecmp( psz, "Content-Type" ) )
{
- if( p_sys->psz_mime ) free( 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, "Content-Encoding" ) )
+ {
+ msg_Dbg( p_access, "Content-Encoding: %s", p );
+ if( strcasecmp( p, "identity" ) )
+#ifdef HAVE_ZLIB_H
+ p_sys->b_compressed = VLC_TRUE;
+#else
+ msg_Warn( p_access, "Compressed content not supported. Rebuild with zlib support." );
+#endif
+ }
else if( !strcasecmp( psz, "Pragma" ) )
{
if( !strcasecmp( psz, "Pragma: features" ) )
p_sys->b_mms = VLC_TRUE;
- if( p_sys->psz_pragma ) free( p_sys->psz_pragma );
+ free( p_sys->psz_pragma );
p_sys->psz_pragma = strdup( p );
msg_Dbg( p_access, "Pragma: %s", p_sys->psz_pragma );
}
}
else if( !strcasecmp( psz, "Icy-Name" ) )
{
- if( p_sys->psz_icy_name ) free( p_sys->psz_icy_name );
+ free( p_sys->psz_icy_name );
p_sys->psz_icy_name = strdup( p );
msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name );
}
else if( !strcasecmp( psz, "Icy-Genre" ) )
{
- if( p_sys->psz_icy_genre ) free( p_sys->psz_icy_genre );
+ free( p_sys->psz_icy_genre );
p_sys->psz_icy_genre = strdup( p );
msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre );
}
msg_Dbg( p_access, "Meta-Info: %s: %s", psz, p );
} else if( !strcasecmp( psz, "Set-Cookie" ) )
{
- msg_Dbg( p_access, "Accepting Cookie: %s", p );
- cookie_append( p_sys->cookies, strdup(p) );
+ if( p_sys->cookies )
+ {
+ msg_Dbg( p_access, "Accepting Cookie: %s", p );
+ cookie_append( p_sys->cookies, strdup(p) );
+ }
+ else
+ msg_Dbg( p_access, "We have a Cookie we won't remember: %s", p );
}
free( psz );
static void cookie_append( vlc_array_t * cookies, char * cookie )
{
int i;
+
+ if( !cookie )
+ return;
+
char * cookie_name = cookie_get_name( cookie );
+
+ /* Don't send invalid cookies */
+ if( !cookie_name )
+ return;
+
char * cookie_domain = cookie_get_domain( cookie );
for( i = 0; i < vlc_array_count( cookies ); i++ )
{
char * current_cookie = vlc_array_item_at_index( cookies, i );
char * current_cookie_name = cookie_get_name( current_cookie );
char * current_cookie_domain = cookie_get_domain( current_cookie );
- if(!strcmp( cookie_name, current_cookie_name ) &&
- !strcmp( cookie_domain, current_cookie_domain ))
+
+ assert( current_cookie_name );
+
+ vlc_bool_t is_domain_matching = ( cookie_domain && current_cookie_domain &&
+ !strcmp( cookie_domain, current_cookie_domain ) );
+
+ if( is_domain_matching && !strcmp( cookie_name, current_cookie_name ) )
{
/* Remove previous value for this cookie */
free( current_cookie );
vlc_array_remove( cookies, i );
/* Clean */
- free( cookie_name );
- free( cookie_domain );
free( current_cookie_name );
free( current_cookie_domain );
break;