[vlc-devel] [PATCH 3/5] access/http: Implement the cookie path matching algorithm

Antti Ajanki antti.ajanki at iki.fi
Tue Jul 22 12:09:04 CEST 2014


---
 modules/access/http.c |  121 +++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 98 insertions(+), 23 deletions(-)

diff --git a/modules/access/http.c b/modules/access/http.c
index 2ef6f59..75d871b 100644
--- a/modules/access/http.c
+++ b/modules/access/http.c
@@ -193,6 +193,7 @@ typedef struct http_cookie_t
     char *psz_name;
     char *psz_value;
     char *psz_domain;
+    char *psz_path;
     bool b_host_only;
 } http_cookie_t;
 
@@ -212,14 +213,17 @@ static int Request( access_t *p_access, uint64_t i_tell );
 static void Disconnect( access_t * );
 
 /* Small Cookie utilities. Cookies support is partial. */
-static http_cookie_t * cookie_parse( const char * cookie_header, const char *request_host );
+static http_cookie_t * cookie_parse( const char * cookie_header, const vlc_url_t *url );
 static void cookie_destroy( http_cookie_t * cookie );
 static char * cookie_get_content( const char * cookie );
 static char * cookie_get_domain( const char * cookie );
+static char * cookie_get_attribute_value( const char * cookie, const char *attr );
 static void cookie_append( vlc_array_t * cookies, http_cookie_t * cookie );
 static bool cookie_is_valid( const http_cookie_t * cookie, const char *host );
 static bool cookie_domain_matches( const http_cookie_t * cookie, const char *host );
+static bool cookie_path_matches( const http_cookie_t * cookie, const char *path );
 static bool cookie_domain_is_public_suffix( const char *domain );
+static char * cookie_default_path( const char *request_path );
 
 
 static void AuthReply( access_t *p_acces, const char *psz_prefix,
@@ -1206,8 +1210,9 @@ static int Request( access_t *p_access, uint64_t i_tell )
             const http_cookie_t * cookie = vlc_array_item_at_index( p_sys->cookies, i );
 
             bool is_in_right_domain = cookie_domain_matches( cookie, p_sys->url.psz_host );
+            bool is_in_right_path = cookie_path_matches( cookie, p_sys->url.psz_path );
 
-            if( is_in_right_domain )
+            if( is_in_right_domain && is_in_right_path )
             {
                 msg_Dbg( p_access, "Sending Cookie %s=%s", cookie->psz_name, cookie->psz_value );
                 if( net_Printf( p_access, p_sys->fd, pvs, "Cookie: %s=%s\r\n", cookie->psz_name, cookie->psz_value ) < 0 )
@@ -1509,7 +1514,7 @@ static int Request( access_t *p_access, uint64_t i_tell )
         {
             if( p_sys->cookies )
             {
-                http_cookie_t *cookie = cookie_parse( p, p_sys->url.psz_host );
+                http_cookie_t *cookie = cookie_parse( p, &p_sys->url );
                 if ( cookie_is_valid( cookie, p_sys->url.psz_host ) )
                 {
                     msg_Dbg( p_access, "Accepting Cookie: %s", p );
@@ -1591,11 +1596,10 @@ static void Disconnect( access_t *p_access )
 }
 
 /*****************************************************************************
- * Cookies (FIXME: we may want to rewrite that using a nice structure to hold
- * them) (FIXME: only support the "domain=" param)
+ * Cookies
  *****************************************************************************/
 
-static http_cookie_t * cookie_parse( const char * cookie_header, const char * request_host )
+static http_cookie_t * cookie_parse( const char * cookie_header, const vlc_url_t * url )
 {
     char *content = cookie_get_content( cookie_header );
     if ( !content )
@@ -1620,12 +1624,26 @@ static http_cookie_t * cookie_parse( const char * cookie_header, const char * re
     if ( !cookie->psz_domain || strlen(cookie->psz_domain) == 0 )
     {
         free(cookie->psz_domain);
-        cookie->psz_domain = strdup( request_host );
+        cookie->psz_domain = strdup( url->psz_host );
         cookie->b_host_only = true;
     }
     else
         cookie->b_host_only = false;
 
+    cookie->psz_path = cookie_get_attribute_value( cookie_header, "path" );
+    if ( !cookie->psz_path || strlen(cookie->psz_path) == 0 )
+    {
+        free(cookie->psz_path);
+        cookie->psz_path = cookie_default_path( url->psz_path );
+    }
+
+    if ( !cookie->psz_name || !cookie->psz_value ||
+         !cookie->psz_domain || !cookie->psz_path )
+    {
+        cookie_destroy( cookie );
+        return NULL;
+    }
+
     return cookie;
 }
 
@@ -1637,6 +1655,7 @@ static void cookie_destroy( http_cookie_t * cookie )
     free(cookie->psz_name);
     free(cookie->psz_value);
     free(cookie->psz_domain);
+    free(cookie->psz_path);
     free(cookie);
 }
 
@@ -1656,17 +1675,35 @@ static char * cookie_get_content( const char * cookie )
 /* 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 )
+    char *domain = cookie_get_attribute_value( cookie, "domain" );
+    if ( domain && *domain == '.' )
+    {
+        char *p = domain;
+        while ( *p == '.') p++;
+        memmove( domain, p, strlen( p ) + 1 );
+    }
+
+    return domain;
+}
+
+static char * cookie_get_attribute_value( const char * cookie, const char *attr )
+{
+    if( !cookie )
         return NULL;
-    /* Look for a ';' */
-    while( *str )
+    size_t attrlen = strlen( attr );
+    const char * str = strchr( cookie, ';' );
+    while( str )
     {
-        if( !strncasecmp( str, domain, sizeof(domain) - 1 /* minus \0 */ ) )
+        /* skip ; */
+        str++;
+
+        /* skip blank */
+        while( *str && *str == ' ' ) str++;
+
+        if( ( strlen(str) >= attrlen + 1 ) &&
+            !strncasecmp( str, attr, attrlen ) && ( str[attrlen] == '=' ) )
         {
-            str += sizeof(domain) - 1 /* minus \0 */;
-            while ( *str && *str == '.' ) str++;
+            str += attrlen + 1;
             char * ret = strdup( str );
             /* Now remove the next ';' if present */
             char * ret_iter = ret;
@@ -1675,11 +1712,8 @@ static char * cookie_get_domain( const char * cookie )
                 *ret_iter = 0;
             return ret;
         }
-        /* Go to next ';' field */
-        while( *str && *str != ';' ) str++;
-        if( *str == ';' ) str++;
-        /* skip blank */
-        while( *str && *str == ' ' ) str++;
+
+        str = strchr( str, ';' );
     }
     return NULL;
 }
@@ -1699,10 +1733,11 @@ static void cookie_append( vlc_array_t * cookies, http_cookie_t * cookie )
         assert( iter->psz_name );
         assert( iter->psz_domain );
 
-        bool is_domain_matching = 
+        bool domains_match =
             strcasecmp( cookie->psz_domain, iter->psz_domain ) == 0;
-
-        if( is_domain_matching && !strcmp( cookie->psz_name, iter->psz_name )  )
+        bool paths_match = strcmp( cookie->psz_path, iter->psz_path ) == 0;
+        bool names_match = strcmp( cookie->psz_name, iter->psz_name ) == 0;
+        if( domains_match && paths_match && names_match  )
         {
             /* Remove previous value for this cookie */
             vlc_array_remove( cookies, i );
@@ -1743,6 +1778,20 @@ static bool cookie_domain_matches( const http_cookie_t * cookie, const char *hos
     return is_suffix && has_dot_before_suffix && !host_is_ip;
 }
 
+static bool cookie_path_matches( const http_cookie_t * cookie, const char *uripath )
+{
+    if ( !cookie || !uripath )
+        return false;
+    else if ( strcmp(cookie->psz_path, uripath) == 0 )
+        return true;
+
+    size_t path_len = strlen( uripath );
+    size_t prefix_len = strlen( cookie->psz_path );
+    return ( path_len > prefix_len ) &&
+        ( strncmp(uripath, cookie->psz_path, prefix_len) == 0 ) &&
+        ( uripath[prefix_len - 1] == '/' || uripath[prefix_len] == '/' );
+}
+
 static bool cookie_domain_is_public_suffix( const char *domain )
 {
     // FIXME: should check if domain is one of "public suffixes" at
@@ -1753,6 +1802,32 @@ static bool cookie_domain_is_public_suffix( const char *domain )
     return domain && !strchr(domain, '.');
 }
 
+static char * cookie_default_path( const char *request_path )
+{
+    if ( !request_path || *request_path != '/' ||
+         *request_path == '\0' || *request_path == '?' )
+        return strdup("/");
+
+    char *path;
+    const char *query_start = strchr( request_path, '?' );
+    if ( query_start )
+        path = strndup( request_path, query_start - request_path );
+    else
+        path = strdup( request_path );
+
+    if ( !path )
+        return NULL;
+
+    char *last_slash = strrchr(path, '/');
+    assert(last_slash);
+    if ( last_slash == path )
+        path[1] = '\0';
+    else
+        *last_slash = '\0';
+
+    return path;
+}
+
 /*****************************************************************************
  * HTTP authentication
  *****************************************************************************/
-- 
1.7.10.4




More information about the vlc-devel mailing list