#include <vlc_input.h>
#include <vlc_md5.h>
#include <vlc_http.h>
+#include "httpcookies.h"
#ifdef HAVE_ZLIB_H
# include <zlib.h>
char *psz_icy_title;
uint64_t i_remaining;
+ uint64_t size;
bool b_seekable;
bool b_reconnect;
bool b_persist;
bool b_has_size;
- vlc_array_t * cookies;
+ http_cookie_jar_t * cookies;
};
/* */
static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
- unsigned i_redirect, vlc_array_t *cookies );
+ unsigned i_redirect, http_cookie_jar_t *cookies );
/* */
static ssize_t Read( access_t *, uint8_t *, size_t );
static int Request( access_t *p_access, uint64_t i_tell );
static void Disconnect( access_t * );
-/* Small Cookie utilities. Cookies support is partial. */
-static char * cookie_get_content( const char * cookie );
-static char * cookie_get_domain( const char * cookie );
-static char * cookie_get_name( const char * cookie );
-static void cookie_append( vlc_array_t * cookies, char * cookie );
-
static void AuthReply( access_t *p_acces, const char *psz_prefix,
vlc_url_t *p_url, http_auth_t *p_auth );
* @return vlc error codes
*/
static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
- unsigned i_redirect, vlc_array_t *cookies )
+ unsigned i_redirect, http_cookie_jar_t *cookies )
{
access_t *p_access = (access_t*)p_this;
access_sys_t *p_sys;
char *psz, *p;
- /* Only forward an store cookies if the corresponding option is activated */
- bool b_forward_cookies = var_InheritBool( p_access, "http-forward-cookies" );
- vlc_array_t * saved_cookies = b_forward_cookies ? (cookies ? cookies : vlc_array_new()) : NULL;
-
/* Set up p_access */
STANDARD_READ_ACCESS_INIT;
#ifdef HAVE_ZLIB_H
p_sys->i_remaining = 0;
p_sys->b_persist = false;
p_sys->b_has_size = false;
- p_access->info.i_size = 0;
+ p_sys->size = 0;
p_access->info.i_pos = 0;
p_access->info.b_eof = false;
- p_sys->cookies = saved_cookies;
+ /* Only forward an store cookies if the corresponding option is activated */
+ if( var_CreateGetBool( p_access, "http-forward-cookies" ) )
+ p_sys->cookies = (cookies != NULL) ? cookies : http_cookies_new();
+ else
+ p_sys->cookies = NULL;
http_auth_Init( &p_sys->auth );
http_auth_Init( &p_sys->proxy_auth );
free( p_access->psz_demux );
p_access->psz_demux = strdup( "podcast" );
}
- else if( p_sys->psz_mime &&
- !strncasecmp( p_sys->psz_mime, "application/xspf+xml", 20 ) &&
- ( memchr( " ;\t", p_sys->psz_mime[20], 4 ) != NULL ) )
- {
- free( p_access->psz_demux );
- p_access->psz_demux = strdup( "xspf-open" );
- }
if( p_sys->b_reconnect ) msg_Dbg( p_access, "auto re-connect enabled" );
Disconnect( p_access );
vlc_tls_Delete( p_sys->p_creds );
- 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 );
- }
+ http_cookies_destroy( p_sys->cookies );
#ifdef HAVE_ZLIB_H
inflateEnd( &p_sys->inflate.stream );
Disconnect( p_access );
vlc_tls_Delete( p_sys->p_creds );
- 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 );
- }
+ http_cookies_destroy( p_sys->cookies );
#ifdef HAVE_ZLIB_H
inflateEnd( &p_sys->inflate.stream );
if( p_sys->b_has_size )
{
/* Remaining bytes in the file */
- uint64_t remainder = p_access->info.i_size - p_access->info.i_pos;
+ uint64_t remainder = p_sys->size - p_access->info.i_pos;
if( remainder < i_len )
i_len = remainder;
p_access->info.i_pos += i_read;
if( p_sys->b_has_size )
{
- assert( p_access->info.i_pos <= p_access->info.i_size );
+ assert( p_access->info.i_pos <= p_sys->size );
assert( (unsigned)i_read <= p_sys->i_remaining );
p_sys->i_remaining -= i_read;
}
p_sys->psz_icy_title = EnsureUTF8( psz_tmp );
if( !p_sys->psz_icy_title )
free( psz_tmp );
- p_access->info.i_update |= INPUT_UPDATE_META;
- msg_Dbg( p_access, "New Title=%s", p_sys->psz_icy_title );
+ msg_Dbg( p_access, "New Icy-Title=%s", p_sys->psz_icy_title );
+ input_thread_t *p_input = access_GetParentInput( p_access );
+ if( p_input )
+ {
+ input_item_t *p_input_item = input_GetItem( p_access->p_input );
+ if( p_input_item )
+ input_item_SetMeta( p_input_item, vlc_meta_NowPlaying, p_sys->psz_icy_title );
+ vlc_object_release( p_input );
+ }
}
}
free( psz_meta );
*****************************************************************************/
static int Seek( access_t *p_access, uint64_t i_pos )
{
- msg_Dbg( p_access, "trying to seek to %"PRId64, i_pos );
+ access_sys_t *p_sys = p_access->p_sys;
+ msg_Dbg( p_access, "trying to seek to %"PRId64, i_pos );
Disconnect( p_access );
- if( p_access->info.i_size
- && i_pos >= p_access->info.i_size ) {
+ if( p_sys->size && i_pos >= p_sys->size )
+ {
msg_Err( p_access, "seek too far" );
- int retval = Seek( p_access, p_access->info.i_size - 1 );
+ int retval = Seek( p_access, p_sys->size - 1 );
if( retval == VLC_SUCCESS ) {
uint8_t p_buffer[2];
Read( p_access, p_buffer, 1);
access_sys_t *p_sys = p_access->p_sys;
bool *pb_bool;
int64_t *pi_64;
- vlc_meta_t *p_meta;
switch( i_query )
{
* var_InheritInteger( p_access, "network-caching" );
break;
+ case ACCESS_GET_SIZE:
+ pi_64 = (int64_t*)va_arg( args, int64_t * );
+ *pi_64 = p_sys->size;
+ break;
+
/* */
case ACCESS_SET_PAUSE_STATE:
break;
- case ACCESS_GET_META:
- p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t* );
-
- if( p_sys->psz_icy_name )
- vlc_meta_Set( p_meta, vlc_meta_Title, p_sys->psz_icy_name );
- if( p_sys->psz_icy_genre )
- vlc_meta_Set( p_meta, vlc_meta_Genre, p_sys->psz_icy_genre );
- if( p_sys->psz_icy_title )
- vlc_meta_Set( p_meta, vlc_meta_NowPlaying, p_sys->psz_icy_title );
- break;
-
case ACCESS_GET_CONTENT_TYPE:
*va_arg( args, char ** ) =
p_sys->psz_mime ? strdup( p_sys->psz_mime ) : NULL;
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;
}
p_sys->i_remaining = 0;
p_sys->b_persist = false;
p_sys->b_has_size = false;
- p_access->info.i_size = 0;
+ p_sys->size = 0;
p_access->info.i_pos = i_tell;
p_access->info.b_eof = false;
}
/* TLS/SSL handshake */
+ const char *alpn[] = { "http/1.1", NULL };
+
p_sys->p_tls = vlc_tls_ClientSessionCreate( p_sys->p_creds, p_sys->fd,
- p_sys->url.psz_host, "https" );
+ p_sys->url.psz_host, "https",
+ p_sys->i_version ? alpn : NULL, NULL );
if( p_sys->p_tls == NULL )
{
msg_Err( p_access, "cannot establish HTTP/TLS session" );
/* Cookies */
if( p_sys->cookies )
{
- int i;
- for( i = 0; i < vlc_array_count( p_sys->cookies ); i++ )
+ char * psz_cookiestring = http_cookies_for_url( p_sys->cookies, &p_sys->url );
+ if ( psz_cookiestring )
{
- 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 */
- bool 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( 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 );
+ msg_Dbg( p_access, "Sending Cookie %s", psz_cookiestring );
+ if( net_Printf( p_access, p_sys->fd, pvs, "Cookie: %s\r\n", psz_cookiestring ) < 0 )
+ msg_Err( p_access, "failed to send Cookie" );
+ free( psz_cookiestring );
}
}
/* Authentication */
- if( p_sys->url.psz_username || p_sys->url.psz_password )
+ if( p_sys->url.psz_username && p_sys->url.psz_password )
AuthReply( p_access, "", &p_sys->url, &p_sys->auth );
/* Proxy Authentication */
- if( p_sys->proxy.psz_username || p_sys->proxy.psz_password )
+ if( p_sys->proxy.psz_username && p_sys->proxy.psz_password )
AuthReply( p_access, "Proxy-", &p_sys->proxy, &p_sys->proxy_auth );
/* ICY meta data request */
if( !strcasecmp( psz, "Content-Length" ) )
{
uint64_t i_size = i_tell + (p_sys->i_remaining = (uint64_t)atoll( p ));
- if(i_size > p_access->info.i_size) {
+ if(i_size > p_sys->size) {
p_sys->b_has_size = true;
- p_access->info.i_size = i_size;
+ p_sys->size = i_size;
}
msg_Dbg( p_access, "this frame size=%"PRIu64, p_sys->i_remaining );
}
else if( !strcasecmp( psz, "Content-Range" ) ) {
uint64_t i_ntell = i_tell;
- uint64_t i_nend = (p_access->info.i_size > 0)?(p_access->info.i_size - 1):i_tell;
- uint64_t i_nsize = p_access->info.i_size;
+ uint64_t i_nend = (p_sys->size > 0) ? (p_sys->size - 1) : i_tell;
+ uint64_t i_nsize = p_sys->size;
sscanf(p,"bytes %"SCNu64"-%"SCNu64"/%"SCNu64,&i_ntell,&i_nend,&i_nsize);
if(i_nend > i_ntell ) {
p_access->info.i_pos = i_ntell;
p_sys->i_icy_offset = i_ntell;
p_sys->i_remaining = i_nend+1-i_ntell;
uint64_t i_size = (i_nsize > i_nend) ? i_nsize : (i_nend + 1);
- if(i_size > p_access->info.i_size) {
+ if(i_size > p_sys->size) {
p_sys->b_has_size = true;
- p_access->info.i_size = i_size;
+ p_sys->size = i_size;
}
msg_Dbg( p_access, "stream size=%"PRIu64",pos=%"PRIu64",remaining=%"PRIu64,
i_nsize, i_ntell, p_sys->i_remaining);
if( !p_sys->psz_icy_name )
free( psz_tmp );
msg_Dbg( p_access, "Icy-Name: %s", p_sys->psz_icy_name );
+ input_thread_t *p_input = access_GetParentInput( p_access );
+ if ( p_input )
+ {
+ input_item_t *p_input_item = input_GetItem( p_access->p_input );
+ if ( p_input_item )
+ input_item_SetMeta( p_input_item, vlc_meta_Title, p_sys->psz_icy_name );
+ vlc_object_release( p_input );
+ }
p_sys->b_icecast = true; /* be on the safeside. set it here as well. */
p_sys->b_reconnect = true;
if( !p_sys->psz_icy_genre )
free( psz_tmp );
msg_Dbg( p_access, "Icy-Genre: %s", p_sys->psz_icy_genre );
+ input_thread_t *p_input = access_GetParentInput( p_access );
+ if( p_input )
+ {
+ input_item_t *p_input_item = input_GetItem( p_access->p_input );
+ if( p_input_item )
+ input_item_SetMeta( p_input_item, vlc_meta_Genre, p_sys->psz_icy_genre );
+ vlc_object_release( p_input );
+ }
}
else if( !strncasecmp( psz, "Icy-Notice", 10 ) )
{
{
if( p_sys->cookies )
{
- msg_Dbg( p_access, "Accepting Cookie: %s", p );
- cookie_append( p_sys->cookies, strdup(p) );
+ if ( http_cookies_append( p_sys->cookies, p, &p_sys->url ) )
+ msg_Dbg( p_access, "Accepting Cookie: %s", p );
+ else
+ msg_Dbg( p_access, "Rejected Cookie: %s", p );
}
else
msg_Dbg( p_access, "We have a Cookie we won't remember: %s", p );
}
-/*****************************************************************************
- * Cookies (FIXME: we may want to rewrite that using a nice structure to hold
- * them) (FIXME: only support the "domain=" param)
- *****************************************************************************/
-
-/* Get the NAME=VALUE part of the Cookie */
-static char * cookie_get_content( const char * cookie )
-{
- char * ret = strdup( cookie );
- if( !ret ) return NULL;
- char * str = ret;
- /* Look for a ';' */
- while( *str && *str != ';' ) str++;
- /* Replace it by a end-char */
- if( *str == ';' ) *str = 0;
- return ret;
-}
-
-/* Get the domain where the cookie is stored */
-static char * cookie_get_domain( const char * cookie )
-{
- const char * str = cookie;
- static const char domain[] = "domain=";
- if( !str )
- return NULL;
- /* Look for a ';' */
- while( *str )
- {
- if( !strncmp( str, domain, sizeof(domain) - 1 /* minus \0 */ ) )
- {
- str += sizeof(domain) - 1 /* minus \0 */;
- char * ret = strdup( str );
- /* Now remove the next ';' if present */
- char * ret_iter = ret;
- while( *ret_iter && *ret_iter != ';' ) ret_iter++;
- if( *ret_iter == ';' )
- *ret_iter = 0;
- return ret;
- }
- /* Go to next ';' field */
- while( *str && *str != ';' ) str++;
- if( *str == ';' ) str++;
- /* skip blank */
- while( *str && *str == ' ' ) str++;
- }
- return NULL;
-}
-
-/* Get NAME in the NAME=VALUE field */
-static char * cookie_get_name( const char * cookie )
-{
- char * ret = cookie_get_content( cookie ); /* NAME=VALUE */
- if( !ret ) return NULL;
- char * str = ret;
- while( *str && *str != '=' ) str++;
- *str = 0;
- return ret;
-}
-
-/* Add a cookie in cookies, checking to see how it should be added */
-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 );
-
- assert( current_cookie_name );
-
- bool is_domain_matching = (
- ( !cookie_domain && !current_cookie_domain ) ||
- ( 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( current_cookie_name );
- free( current_cookie_domain );
- break;
- }
- free( current_cookie_name );
- free( current_cookie_domain );
- }
- free( cookie_name );
- free( cookie_domain );
- vlc_array_append( cookies, cookie );
-}
-
-
/*****************************************************************************
* HTTP authentication
*****************************************************************************/