[vlc-devel] [PATCH v3 2/2] access/http: Share cookies between all playlist items

Antti Ajanki antti.ajanki at iki.fi
Sun Sep 14 09:27:42 CEST 2014


Shared cookies are required, for example, by certain HDS and HLS streams
that set a cookie when the manifest is read and expect it to be sent
back on subsequent fragment requests.

The cookie jar is created during playlist initialization. HTTP requests
inherit the cookie jar from the playlist.
---
 NEWS                   |    3 +-
 include/vlc_http.h     |   20 ++++++++++--
 modules/access/http.c  |   59 +++++++++++++++++++++++----------
 src/libvlccore.sym     |    3 +-
 src/misc/httpcookies.c |   85 ++++++++++++++++++++++++++++++++++++++++--------
 src/playlist/engine.c  |   17 ++++++++++
 6 files changed, 153 insertions(+), 34 deletions(-)

diff --git a/NEWS b/NEWS
index d56b014..4ba2741 100644
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,8 @@ Access:
  * Support HDS (Http Dynamic Streaming) from Adobe (f4m, f4v, etc.)
  * New SMB access module using libdsm
  * Support decompression and extraction through libarchive (tar, zip, rar...)
- * Improvements of cookie handling (domain / path matching, Secure cookies)
+ * Improvements of cookie handling (share cookies between playlist items,
+   domain / path matching, Secure cookies)
 
 Decoder:
  * OMX GPU-zerocopy support for decoding and display on Android using OpenMax IL
diff --git a/include/vlc_http.h b/include/vlc_http.h
index 47e3139..4a3959f 100644
--- a/include/vlc_http.h
+++ b/include/vlc_http.h
@@ -69,10 +69,26 @@ VLC_API char *http_auth_FormatAuthorizationHeader
 
 /* RFC 6265: cookies */
 
-typedef struct vlc_array_t vlc_http_cookie_jar_t;
+typedef struct vlc_http_cookie_jar_t vlc_http_cookie_jar_t;
 
+/**
+ * Create and initializes a new HTTP cookie jar.
+ *
+ * The initial reference count is 1.
+ *
+ * @return the cookie jar instance or NULL in case of error
+ */
 VLC_API vlc_http_cookie_jar_t * vlc_http_cookies_new( void ) VLC_USED;
-VLC_API void vlc_http_cookies_destroy( vlc_http_cookie_jar_t * p_jar );
+
+/**
+ * Increase reference count of a cookie jar.
+ */
+VLC_API void vlc_http_cookies_retain( vlc_http_cookie_jar_t * p_jar );
+
+/**
+ * Decrease reference count of a cookie jar and release it if necessary.
+ */
+VLC_API void vlc_http_cookies_release( vlc_http_cookie_jar_t * p_jar );
 
 /**
  * Parse a value of an incoming Set-Cookie header and append the
diff --git a/modules/access/http.c b/modules/access/http.c
index 37df233..af103e3 100644
--- a/modules/access/http.c
+++ b/modules/access/http.c
@@ -178,19 +178,19 @@ struct access_sys_t
     uint64_t i_remaining;
     uint64_t size;
 
+    vlc_http_cookie_jar_t * cookies;
+
     bool b_seekable;
     bool b_reconnect;
     bool b_continuous;
     bool b_pace_control;
     bool b_persist;
     bool b_has_size;
-
-    vlc_http_cookie_jar_t * cookies;
 };
 
 /* */
-static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
-                            unsigned i_redirect, vlc_http_cookie_jar_t *cookies );
+static int OpenRedirected( vlc_object_t *p_this, const char *psz_access,
+                           unsigned i_redirect );
 
 /* */
 static ssize_t Read( access_t *, uint8_t *, size_t );
@@ -208,6 +208,7 @@ static void AuthReply( access_t *p_acces, const char *psz_prefix,
                        vlc_url_t *p_url, http_auth_t *p_auth );
 static int AuthCheckReply( access_t *p_access, const char *psz_header,
                            vlc_url_t *p_url, http_auth_t *p_auth );
+static vlc_http_cookie_jar_t *GetCookieJarReference( vlc_object_t *p_this );
 
 /*****************************************************************************
  * Open:
@@ -215,20 +216,19 @@ static int AuthCheckReply( access_t *p_access, const char *psz_header,
 static int Open( vlc_object_t *p_this )
 {
     access_t *p_access = (access_t*)p_this;
-    return OpenWithCookies( p_this, p_access->psz_access, 5, NULL );
+    return OpenRedirected( p_this, p_access->psz_access, 5 );
 }
 
 /**
- * Open the given url using the given cookies
+ * Open the given url with limited redirects
  * @param p_this: the vlc object
  * @psz_access: the acces to use (http, https, ...) (this value must be used
  *              instead of p_access->psz_access)
  * @i_redirect: number of redirections remaining
- * @cookies: the available cookies
  * @return vlc error codes
  */
-static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
-                            unsigned i_redirect, vlc_http_cookie_jar_t *cookies )
+static int OpenRedirected( vlc_object_t *p_this, const char *psz_access,
+                           unsigned i_redirect )
 {
     access_t     *p_access = (access_t*)p_this;
     access_sys_t *p_sys;
@@ -278,7 +278,7 @@ static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
 
     /* 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 : vlc_http_cookies_new();
+        p_sys->cookies = GetCookieJarReference( p_this );
     else
         p_sys->cookies = NULL;
 
@@ -509,15 +509,14 @@ connect:
 
         Disconnect( p_access );
         vlc_tls_Delete( p_sys->p_creds );
-        cookies = p_sys->cookies;
+        vlc_http_cookies_release( p_sys->cookies );
 #ifdef HAVE_ZLIB_H
         inflateEnd( &p_sys->inflate.stream );
 #endif
         free( p_sys );
 
         /* Do new Open() run with new data */
-        return OpenWithCookies( p_this, psz_protocol, i_redirect - 1,
-                                cookies );
+        return OpenRedirected( p_this, psz_protocol, i_redirect - 1 );
     }
 
     if( p_sys->b_mms )
@@ -595,8 +594,7 @@ error:
 
     Disconnect( p_access );
     vlc_tls_Delete( p_sys->p_creds );
-
-    vlc_http_cookies_destroy( p_sys->cookies );
+    vlc_http_cookies_release( p_sys->cookies );
 
 #ifdef HAVE_ZLIB_H
     inflateEnd( &p_sys->inflate.stream );
@@ -631,8 +629,7 @@ static void Close( vlc_object_t *p_this )
 
     Disconnect( p_access );
     vlc_tls_Delete( p_sys->p_creds );
-
-    vlc_http_cookies_destroy( p_sys->cookies );
+    vlc_http_cookies_release( p_sys->cookies );
 
 #ifdef HAVE_ZLIB_H
     inflateEnd( &p_sys->inflate.stream );
@@ -1582,3 +1579,31 @@ static int AuthCheckReply( access_t *p_access, const char *psz_header,
                                                  p_url->psz_username,
                                                  p_url->psz_password );
 }
+
+/*****************************************************************************
+ * HTTP cookies
+ *****************************************************************************/
+
+/**
+ * Inherit a cookie jar reference from the playlist
+ *
+ * The returned pointer must be disposed of by calling
+ * vlc_http_cookies_release.
+ *
+ * @param p_this: http access object
+ * @return A new reference to a vlc_http_cookie_jar_t
+ */
+static vlc_http_cookie_jar_t *GetCookieJarReference( vlc_object_t *p_this )
+{
+    vlc_http_cookie_jar_t *cookies = NULL;
+    vlc_value_t val;
+
+    if ( var_Inherit( p_this, "http-cookies", VLC_VAR_ADDRESS, &val ) == VLC_SUCCESS )
+    {
+        cookies = val.p_address;
+        if ( cookies )
+            vlc_http_cookies_retain( cookies );
+    }
+
+    return cookies;
+}
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 6bab760..6804907 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -145,7 +145,8 @@ http_auth_ParseWwwAuthenticateHeader
 http_auth_ParseAuthenticationInfoHeader
 http_auth_FormatAuthorizationHeader
 vlc_http_cookies_new
-vlc_http_cookies_destroy
+vlc_http_cookies_retain
+vlc_http_cookies_release
 vlc_http_cookies_append
 vlc_http_cookies_for_url
 httpd_ClientIP
diff --git a/src/misc/httpcookies.c b/src/misc/httpcookies.c
index 9eccbe7..51b3c25 100644
--- a/src/misc/httpcookies.c
+++ b/src/misc/httpcookies.c
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * httpcookies.h: HTTP cookie utilities
+ * httpcookies.c: HTTP cookie utilities
  *****************************************************************************
  * Copyright (C) 2014 VLC authors and VideoLAN
  * $Id$
@@ -45,6 +45,14 @@ typedef struct http_cookie_t
     bool b_secure;
 } http_cookie_t;
 
+struct vlc_http_cookie_jar_t
+{
+    vlc_array_t cookies;
+    vlc_mutex_t lock;
+    unsigned int i_ref_count;
+};
+
+static void cookies_destroy( vlc_http_cookie_jar_t * p_jar );
 static http_cookie_t * cookie_parse( const char * cookie_header, const vlc_url_t * url );
 static void cookie_destroy( http_cookie_t * p_cookie );
 static char * cookie_get_content( const char * cookie );
@@ -60,18 +68,60 @@ static char * cookie_default_path( const char *request_path );
 
 vlc_http_cookie_jar_t * vlc_http_cookies_new()
 {
-    return vlc_array_new();
+    vlc_http_cookie_jar_t * jar = malloc( sizeof( vlc_http_cookie_jar_t ) );
+    if ( !jar )
+        return NULL;
+
+    vlc_array_init( &jar->cookies );
+    vlc_mutex_init( &jar->lock );
+    jar->i_ref_count = 1;
+
+    return jar;
+}
+
+void vlc_http_cookies_retain( vlc_http_cookie_jar_t * p_jar )
+{
+    if ( !p_jar )
+        return;
+
+    assert( p_jar );
+    assert( p_jar->i_ref_count < UINT_MAX );
+
+    vlc_mutex_lock( &p_jar->lock );
+    p_jar->i_ref_count++;
+    vlc_mutex_unlock( &p_jar->lock );
+}
+
+void vlc_http_cookies_release( vlc_http_cookie_jar_t * p_jar )
+{
+    unsigned int refs;
+
+    if ( !p_jar )
+        return;
+
+    assert( p_jar );
+    assert( p_jar->i_ref_count > 0 );
+
+    vlc_mutex_lock( &p_jar->lock );
+    p_jar->i_ref_count--;
+    refs = p_jar->i_ref_count;
+    vlc_mutex_unlock( &p_jar->lock );
+
+    if ( refs == 0 )
+        cookies_destroy( p_jar );
 }
 
-void vlc_http_cookies_destroy( vlc_http_cookie_jar_t * p_jar )
+static void cookies_destroy( vlc_http_cookie_jar_t * p_jar )
 {
     if ( !p_jar )
         return;
 
     int i;
-    for( i = 0; i < vlc_array_count( p_jar ); i++ )
-        cookie_destroy( vlc_array_item_at_index( p_jar, i ) );
-    vlc_array_destroy( p_jar );
+    for( i = 0; i < vlc_array_count( &p_jar->cookies ); i++ )
+        cookie_destroy( vlc_array_item_at_index( &p_jar->cookies, i ) );
+
+    vlc_array_clear( &p_jar->cookies );
+    vlc_mutex_destroy( &p_jar->lock );
 }
 
 bool vlc_http_cookies_append( vlc_http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t *p_url )
@@ -85,9 +135,11 @@ bool vlc_http_cookies_append( vlc_http_cookie_jar_t * p_jar, const char * psz_co
         return false;
     }
 
-    for( i = 0; i < vlc_array_count( p_jar ); i++ )
+    vlc_mutex_lock( &p_jar->lock );
+
+    for( i = 0; i < vlc_array_count( &p_jar->cookies ); i++ )
     {
-        http_cookie_t *iter = vlc_array_item_at_index( p_jar, i );
+        http_cookie_t *iter = vlc_array_item_at_index( &p_jar->cookies, i );
 
         assert( iter->psz_name );
         assert( iter->psz_domain );
@@ -100,24 +152,28 @@ bool vlc_http_cookies_append( vlc_http_cookie_jar_t * p_jar, const char * psz_co
         if( domains_match && paths_match && names_match )
         {
             /* Remove previous value for this cookie */
-            vlc_array_remove( p_jar, i );
+            vlc_array_remove( &p_jar->cookies, i );
             cookie_destroy(iter);
             break;
         }
     }
-    vlc_array_append( p_jar, cookie );
+    vlc_array_append( &p_jar->cookies, cookie );
+
+    vlc_mutex_unlock( &p_jar->lock );
 
     return true;
 }
 
-
 char *vlc_http_cookies_for_url( vlc_http_cookie_jar_t * p_jar, const vlc_url_t * p_url )
 {
     int i;
     char *psz_cookiebuf = NULL;
-    for( i = 0; i < vlc_array_count( p_jar ); i++ )
+
+    vlc_mutex_lock( &p_jar->lock );
+
+    for( i = 0; i < vlc_array_count( &p_jar->cookies ); i++ )
     {
-        const http_cookie_t * cookie = vlc_array_item_at_index( p_jar, i );
+        const http_cookie_t * cookie = vlc_array_item_at_index( &p_jar->cookies, i );
         if ( cookie_should_be_sent( cookie, p_url ) )
         {
             char *psz_updated_buf = NULL;
@@ -129,6 +185,7 @@ char *vlc_http_cookies_for_url( vlc_http_cookie_jar_t * p_jar, const vlc_url_t *
             {
                 // TODO: report error
                 free( psz_cookiebuf );
+                vlc_mutex_unlock( &p_jar->lock );
                 return NULL;
             }
             free( psz_cookiebuf );
@@ -136,6 +193,8 @@ char *vlc_http_cookies_for_url( vlc_http_cookie_jar_t * p_jar, const vlc_url_t *
         }
     }
 
+    vlc_mutex_unlock( &p_jar->lock );
+
     return psz_cookiebuf;
 }
 
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index de1f76b..8d6928c 100644
--- a/src/playlist/engine.c
+++ b/src/playlist/engine.c
@@ -32,6 +32,7 @@
 #include <vlc_sout.h>
 #include <vlc_playlist.h>
 #include <vlc_interface.h>
+#include <vlc_http.h>
 #include "playlist_internal.h"
 #include "input/resource.h"
 
@@ -296,6 +297,15 @@ playlist_t *playlist_Create( vlc_object_t *p_parent )
     if( aout != NULL )
         input_resource_PutAout( p->p_input_resource, aout );
 
+    /* Initialize the shared HTTP cookie jar */
+    vlc_value_t cookies;
+    cookies.p_address = vlc_http_cookies_new();
+    if ( likely(cookies.p_address) )
+    {
+        var_Create( p_playlist, "http-cookies", VLC_VAR_ADDRESS );
+        var_SetChecked( p_playlist, "http-cookies", VLC_VAR_ADDRESS, cookies );
+    }
+
     /* Thread */
     playlist_Activate (p_playlist);
 
@@ -366,6 +376,13 @@ void playlist_Destroy( playlist_t *p_playlist )
     ARRAY_RESET( p_playlist->items );
     ARRAY_RESET( p_playlist->current );
 
+    vlc_http_cookie_jar_t *cookies = var_GetAddress( p_playlist, "http-cookies" );
+    if ( cookies )
+    {
+        var_Destroy( p_playlist, "http-cookies" );
+        vlc_http_cookies_release( cookies );
+    }
+
     vlc_object_release( p_playlist );
 }
 
-- 
1.7.10.4




More information about the vlc-devel mailing list