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

Antti Ajanki antti.ajanki at iki.fi
Sat Sep 13 13:58:46 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  |   61 ++++++++++++++++++++++++++++----------
 src/libvlccore.sym     |    3 +-
 src/misc/httpcookies.c |   76 ++++++++++++++++++++++++++++++++++++++++--------
 src/playlist/engine.c  |   17 +++++++++++
 6 files changed, 149 insertions(+), 31 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 490e0a2..3e0d9f8 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 http_cookie_jar_t;
+typedef struct http_cookie_jar_t 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 http_cookie_jar_t * http_cookies_new( void ) VLC_USED;
-VLC_API void http_cookies_destroy( http_cookie_jar_t * p_jar );
+
+/**
+ * Increase reference count of a cookie jar.
+ */
+VLC_API void http_cookies_retain( http_cookie_jar_t * p_jar );
+
+/**
+ * Decrease reference count of a cookie jar and release it if necessary.
+ */
+VLC_API void http_cookies_release( 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 5ec14f1..8956e3e 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;
 
+    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;
-
-    http_cookie_jar_t * cookies;
 };
 
 /* */
-static int OpenWithCookies( vlc_object_t *p_this, const char *psz_access,
-                            unsigned i_redirect, 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,8 @@ 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 http_cookie_jar_t *GetCookieJarReference( vlc_object_t *p_this );
+static void ReleaseCookieJar( vlc_object_t *p_this, access_sys_t *p_sys );
 
 /*****************************************************************************
  * Open:
@@ -215,20 +217,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, 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 +279,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 : http_cookies_new();
+        p_sys->cookies = GetCookieJarReference( p_this );
     else
         p_sys->cookies = NULL;
 
@@ -509,15 +510,15 @@ connect:
 
         Disconnect( p_access );
         vlc_tls_Delete( p_sys->p_creds );
-        cookies = p_sys->cookies;
+        if ( p_sys->cookies )
+            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 )
@@ -596,7 +597,7 @@ error:
     Disconnect( p_access );
     vlc_tls_Delete( p_sys->p_creds );
 
-    http_cookies_destroy( p_sys->cookies );
+    ReleaseCookieJar( p_this, p_sys );
 
 #ifdef HAVE_ZLIB_H
     inflateEnd( &p_sys->inflate.stream );
@@ -632,7 +633,7 @@ static void Close( vlc_object_t *p_this )
     Disconnect( p_access );
     vlc_tls_Delete( p_sys->p_creds );
 
-    http_cookies_destroy( p_sys->cookies );
+    ReleaseCookieJar( p_this, p_sys );
 
 #ifdef HAVE_ZLIB_H
     inflateEnd( &p_sys->inflate.stream );
@@ -1582,3 +1583,33 @@ 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
+ * http_cookies_release.
+ *
+ * @param p_this: http access object
+ * @return A new reference to a http_cookie_jar_t
+ */
+static http_cookie_jar_t *GetCookieJarReference( vlc_object_t *p_this )
+{
+    http_cookie_jar_t *cookies = var_CreateGetAddress( p_this, "http-cookies" );
+    if ( cookies )
+        http_cookies_retain( cookies );
+    return cookies;
+}
+
+static void ReleaseCookieJar( vlc_object_t *p_this, access_sys_t *p_sys )
+{
+    var_Destroy( p_this, "http-cookies" );
+    if ( p_sys->cookies ) {
+        http_cookies_release( p_sys->cookies );
+        p_sys->cookies = NULL;
+    }
+}
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 13c4ead..f3d3cfb 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -145,7 +145,8 @@ http_auth_ParseWwwAuthenticateHeader
 http_auth_ParseAuthenticationInfoHeader
 http_auth_FormatAuthorizationHeader
 http_cookies_new
-http_cookies_destroy
+http_cookies_retain
+http_cookies_release
 http_cookies_append
 http_cookies_for_url
 httpd_ClientIP
diff --git a/src/misc/httpcookies.c b/src/misc/httpcookies.c
index 856bc61..a67afed 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 http_cookie_jar_t
+{
+    vlc_array_t cookies;
+    vlc_mutex_t lock;
+    unsigned int i_ref_count;
+};
+
+static void http_cookies_destroy( 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,7 +68,40 @@ static char * cookie_default_path( const char *request_path );
 
 http_cookie_jar_t * http_cookies_new()
 {
-    return vlc_array_new();
+    http_cookie_jar_t * jar = malloc( sizeof( 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 http_cookies_retain( http_cookie_jar_t * p_jar )
+{
+    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 http_cookies_release( http_cookie_jar_t * p_jar )
+{
+    unsigned int refs;
+
+    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 )
+        http_cookies_destroy( p_jar );
 }
 
 void http_cookies_destroy( http_cookie_jar_t * p_jar )
@@ -69,9 +110,11 @@ void http_cookies_destroy( http_cookie_jar_t * 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 http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t *p_url )
@@ -85,9 +128,11 @@ bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_hea
         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 +145,28 @@ bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_hea
         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 *http_cookies_for_url( 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 +178,7 @@ char *http_cookies_for_url( http_cookie_jar_t * p_jar, const vlc_url_t * p_url )
             {
                 // TODO: report error
                 free( psz_cookiebuf );
+                vlc_mutex_unlock( &p_jar->lock );
                 return NULL;
             }
             free( psz_cookiebuf );
@@ -136,6 +186,8 @@ char *http_cookies_for_url( http_cookie_jar_t * p_jar, const vlc_url_t * p_url )
         }
     }
 
+    vlc_mutex_unlock( &p_jar->lock );
+
     return psz_cookiebuf;
 }
 
diff --git a/src/playlist/engine.c b/src/playlist/engine.c
index de1f76b..31436ad 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 = 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 );
 
+    http_cookie_jar_t *cookies = var_GetAddress( p_playlist, "http-cookies" );
+    if ( cookies )
+    {
+        var_Destroy( p_playlist, "http-cookies" );
+        http_cookies_release( cookies );
+    }
+
     vlc_object_release( p_playlist );
 }
 
-- 
1.7.10.4




More information about the vlc-devel mailing list