[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