[vlc-devel] [PATCH v2 1/2] core: Move httpcookies.c to core
Antti Ajanki
antti.ajanki at iki.fi
Sat Sep 13 13:58:45 CEST 2014
---
include/vlc_http.h | 29 ++++
modules/access/Makefile.am | 2 +-
modules/access/http.c | 1 -
modules/access/httpcookies.c | 366 ------------------------------------------
modules/access/httpcookies.h | 62 -------
src/Makefile.am | 1 +
src/libvlccore.sym | 4 +
src/misc/httpcookies.c | 366 ++++++++++++++++++++++++++++++++++++++++++
8 files changed, 401 insertions(+), 430 deletions(-)
delete mode 100644 modules/access/httpcookies.c
delete mode 100644 modules/access/httpcookies.h
create mode 100644 src/misc/httpcookies.c
diff --git a/include/vlc_http.h b/include/vlc_http.h
index ddde13e..490e0a2 100644
--- a/include/vlc_http.h
+++ b/include/vlc_http.h
@@ -33,6 +33,9 @@
* HTTP clients.
*/
+#include <vlc_url.h>
+#include <vlc_arrays.h>
+
/* RFC 2617: Basic and Digest Access Authentication */
typedef struct http_auth_t
{
@@ -64,4 +67,30 @@ VLC_API char *http_auth_FormatAuthorizationHeader
const char *, const char *,
const char *, const char * ) VLC_USED;
+/* RFC 6265: cookies */
+
+typedef struct vlc_array_t http_cookie_jar_t;
+
+VLC_API http_cookie_jar_t * http_cookies_new( void ) VLC_USED;
+VLC_API void http_cookies_destroy( http_cookie_jar_t * p_jar );
+
+/**
+ * Parse a value of an incoming Set-Cookie header and append the
+ * cookie to the cookie jar if appropriate.
+ *
+ * @param p_jar cookie jar object
+ * @param psz_cookie_header value of Set-Cookie
+ * @return true, if the cookie was added, false otherwise
+ */
+VLC_API bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t * p_url );
+
+/**
+ * Returns a cookie value that match the given URL.
+ *
+ * @params p_jar a cookie jar
+ * @params p_url the URL for which the cookies are returned
+ * @return A string consisting of semicolon-separated cookie NAME=VALUE pairs.
+ */
+VLC_API char *http_cookies_for_url( http_cookie_jar_t * p_jar, const vlc_url_t * p_url );
+
#endif /* VLC_HTTP_H */
diff --git a/modules/access/Makefile.am b/modules/access/Makefile.am
index 4ef79bf..f0ad4f4 100644
--- a/modules/access/Makefile.am
+++ b/modules/access/Makefile.am
@@ -356,7 +356,7 @@ libftp_plugin_la_SOURCES = access/ftp.c
libftp_plugin_la_LIBADD = $(SOCKET_LIBS)
access_LTLIBRARIES += libftp_plugin.la
-libhttp_plugin_la_SOURCES = access/http.c access/httpcookies.h access/httpcookies.c
+libhttp_plugin_la_SOURCES = access/http.c
libhttp_plugin_la_LIBADD = $(SOCKET_LIBS)
if HAVE_ZLIB
libhttp_plugin_la_LIBADD += -lz
diff --git a/modules/access/http.c b/modules/access/http.c
index 9afca9f..5ec14f1 100644
--- a/modules/access/http.c
+++ b/modules/access/http.c
@@ -47,7 +47,6 @@
#include <vlc_input.h>
#include <vlc_md5.h>
#include <vlc_http.h>
-#include "httpcookies.h"
#ifdef HAVE_ZLIB_H
# include <zlib.h>
diff --git a/modules/access/httpcookies.c b/modules/access/httpcookies.c
deleted file mode 100644
index 2dc0a6b..0000000
--- a/modules/access/httpcookies.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/*****************************************************************************
- * httpcookies.h: HTTP cookie utilities
- *****************************************************************************
- * Copyright (C) 2014 VLC authors and VideoLAN
- * $Id$
- *
- * Authors: Antti Ajanki <antti.ajanki at iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-#include <vlc_common.h>
-#include <vlc_messages.h>
-#include <vlc_strings.h>
-#include "httpcookies.h"
-
-typedef struct http_cookie_t
-{
- char *psz_name;
- char *psz_value;
- char *psz_domain;
- char *psz_path;
- bool b_host_only;
- bool b_secure;
-} http_cookie_t;
-
-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 );
-static char * cookie_get_domain( const char * cookie );
-static char * cookie_get_attribute_value( const char * cookie, const char *attr );
-static bool cookie_has_attribute( const char * cookie, const char *attr );
-static bool cookie_should_be_sent( const http_cookie_t * cookie, const vlc_url_t * url );
-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 );
-
-http_cookie_jar_t * http_cookies_new()
-{
- return vlc_array_new();
-}
-
-void http_cookies_destroy( 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 );
-}
-
-bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t *p_url )
-{
- int i;
-
- http_cookie_t *cookie = cookie_parse( psz_cookie_header, p_url );
- if( !cookie || !cookie_is_valid( cookie, p_url->psz_host ) )
- {
- cookie_destroy( cookie );
- return false;
- }
-
- for( i = 0; i < vlc_array_count( p_jar ); i++ )
- {
- http_cookie_t *iter = vlc_array_item_at_index( p_jar, i );
-
- assert( iter->psz_name );
- assert( iter->psz_domain );
- assert( iter->psz_path );
-
- bool domains_match =
- vlc_ascii_strcasecmp( cookie->psz_domain, iter->psz_domain ) == 0;
- 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( p_jar, i );
- cookie_destroy(iter);
- break;
- }
- }
- vlc_array_append( p_jar, cookie );
-
- 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++ )
- {
- const http_cookie_t * cookie = vlc_array_item_at_index( p_jar, i );
- if ( cookie_should_be_sent( cookie, p_url ) )
- {
- char *psz_updated_buf = NULL;
- if ( asprintf(&psz_updated_buf, "%s%s%s=%s",
- psz_cookiebuf ? psz_cookiebuf : "",
- psz_cookiebuf ? "; " : "",
- cookie->psz_name ? cookie->psz_name : "",
- cookie->psz_value ? cookie->psz_value : "") == -1 )
- {
- // TODO: report error
- free( psz_cookiebuf );
- return NULL;
- }
- free( psz_cookiebuf );
- psz_cookiebuf = psz_updated_buf;
- }
- }
-
- return psz_cookiebuf;
-}
-
-static http_cookie_t * cookie_parse( const char * cookie_header, const vlc_url_t * url )
-{
- http_cookie_t *cookie = calloc( 1, sizeof( http_cookie_t ) );
- if ( unlikely( !cookie ) )
- return NULL;
-
- char *content = cookie_get_content( cookie_header );
- if ( !content )
- {
- cookie_destroy( cookie );
- return NULL;
- }
-
- const char *eq = strchr( content, '=' );
- if ( eq )
- {
- cookie->psz_name = strndup( content, eq-content );
- cookie->psz_value = strdup( eq + 1 );
- }
- else
- {
- cookie->psz_name = strdup( content );
- cookie->psz_value = NULL;
- }
-
- cookie->psz_domain = cookie_get_domain( cookie_header );
- if ( !cookie->psz_domain || strlen(cookie->psz_domain) == 0 )
- {
- free(cookie->psz_domain);
- 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 );
- }
-
- cookie->b_secure = cookie_has_attribute( cookie_header, "secure" );
-
- FREENULL( content );
-
- if ( !cookie->psz_domain || !cookie->psz_path || !cookie->psz_name )
- {
- cookie_destroy( cookie );
- return NULL;
- }
-
- return cookie;
-}
-
-static void cookie_destroy( http_cookie_t * p_cookie )
-{
- if ( !p_cookie )
- return;
-
- free( p_cookie->psz_name );
- free( p_cookie->psz_value );
- free( p_cookie->psz_domain );
- free( p_cookie->psz_path );
- free( p_cookie );
-}
-
-/* Get the NAME=VALUE part of the Cookie */
-static char * cookie_get_content( const char * cookie )
-{
- size_t content_length = strcspn( cookie, ";" );
- return strndup( cookie, content_length );
-}
-
-/* Get the domain where the cookie is stored */
-static char * cookie_get_domain( const char * cookie )
-{
- char *domain = cookie_get_attribute_value( cookie, "domain" );
- if ( domain && *domain == '.' )
- {
- const char *real_domain = domain + strspn( domain, "." );
- memmove( domain, real_domain, strlen( real_domain ) + 1 );
- }
- return domain;
-}
-
-static char * cookie_get_attribute_value( const char * cookie, const char *attr )
-{
- if( !cookie || !attr )
- return NULL;
-
- size_t attrlen = strlen( attr );
- const char * str = strchr( cookie, ';' );
- while( str )
- {
- /* skip ; and blank */
- str++;
- str = str + strspn( str, " " );
-
- if( !vlc_ascii_strncasecmp( str, attr, attrlen ) &&
- ( str[attrlen] == '=' ) )
- {
- str += attrlen + 1;
- size_t value_length = strcspn( str, ";" );
- return strndup( str, value_length );
- }
-
- str = strchr( str, ';' );
- }
- return NULL;
-}
-
-static bool cookie_has_attribute( const char * cookie, const char *attr )
-{
- if( !cookie || !attr )
- return false;
-
- size_t attrlen = strlen(attr);
- const char * str = strchr(cookie, ';');
- while( str )
- {
- /* skip ; and blank */
- str++;
- str = str + strspn( str, " " );
-
- if( !vlc_ascii_strncasecmp( str, attr, attrlen ) &&
- ( str[attrlen] == '=' || str[attrlen] == ';' || str[attrlen] == '\0' ) )
- return true;
-
- str = strchr(str, ';');
- }
- return false;
-}
-
-static bool cookie_should_be_sent( const http_cookie_t * cookie, const vlc_url_t * url )
-{
- bool protocol_ok = !cookie->b_secure ||
- ( url->psz_protocol && strcasecmp(url->psz_protocol, "https") == 0 );
- bool domain_ok = cookie_domain_matches( cookie, url->psz_host );
- bool path_ok = cookie_path_matches( cookie, url->psz_path );
- return protocol_ok && domain_ok && path_ok;
-}
-
-/* Check if a cookie from host should be added to the cookie jar */
-static bool cookie_is_valid( const http_cookie_t * cookie, const char *host )
-{
- return cookie && cookie->psz_name && strlen(cookie->psz_name) > 0 &&
- cookie->psz_domain &&
- !cookie_domain_is_public_suffix(cookie->psz_domain) &&
- cookie_domain_matches(cookie, host);
-}
-
-static bool cookie_domain_matches( const http_cookie_t * cookie, const char *host )
-{
- assert( !cookie || cookie->psz_domain );
-
- // TODO: should convert domain names to punycode before comparing
-
- if ( !cookie || !host )
- return false;
- if ( vlc_ascii_strcasecmp(cookie->psz_domain, host) == 0 )
- return true;
- else if ( cookie->b_host_only )
- return false;
-
- size_t host_len = strlen(host);
- size_t cookie_domain_len = strlen(cookie->psz_domain);
- int i = host_len - cookie_domain_len;
- bool is_suffix = ( i > 0 ) &&
- vlc_ascii_strcasecmp( &host[i], cookie->psz_domain ) == 0;
- bool has_dot_before_suffix = host[i-1] == '.';
- bool host_is_ipv4 = strspn(host, "0123456789.") == host_len;
- bool host_is_ipv6 = strchr(host, ':') != NULL;
- return is_suffix && has_dot_before_suffix &&
- !( host_is_ipv4 || host_is_ipv6 );
-}
-
-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
- // http://publicsuffix.org/. The purpose of this check is to
- // prevent a host from setting a "too wide" cookie, for example
- // "example.com" should not be able to set a cookie for "com".
- // The current implementation prevents all top-level domains.
- return domain && !strchr(domain, '.');
-}
-
-static char * cookie_default_path( const char *request_path )
-{
- if ( !request_path || *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;
-}
diff --git a/modules/access/httpcookies.h b/modules/access/httpcookies.h
deleted file mode 100644
index bf73191..0000000
--- a/modules/access/httpcookies.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*****************************************************************************
- * httpcookies.h: HTTP cookie utilities
- *****************************************************************************
- * Copyright (C) 2014 VLC authors and VideoLAN
- * $Id$
- *
- * Authors: Antti Ajanki <antti.ajanki at iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifndef HTTPCOOKIES_H_
-#define HTTPCOOKIES_H_ 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <vlc_url.h>
-#include <vlc_arrays.h>
-
-typedef struct vlc_array_t http_cookie_jar_t;
-
-http_cookie_jar_t * http_cookies_new( void );
-void http_cookies_destroy( http_cookie_jar_t * p_jar );
-
-/**
- * Parse a value of an incoming Set-Cookie header and append the
- * cookie to the cookie jar if appropriate.
- *
- * @param p_jar cookie jar object
- * @param psz_cookie_header value of Set-Cookie
- * @return true, if the cookie was added, false otherwise
- */
-bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t * p_url );
-
-/**
- * Returns a cookie value that match the given URL.
- *
- * @params p_jar a cookie jar
- * @params p_url the URL for which the cookies are returned
- * @return A string consisting of semicolon-separated cookie NAME=VALUE pairs.
- */
-char *http_cookies_for_url( http_cookie_jar_t * p_jar, const vlc_url_t * p_url );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index cdddc8d..9111e73 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -480,6 +480,7 @@ SOURCES_libvlc_common = \
misc/filter.c \
misc/filter_chain.c \
misc/http_auth.c \
+ misc/httpcookies.c \
misc/fingerprinter.c \
misc/text_style.c \
misc/subpicture.c \
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index bdd7b06..13c4ead 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -144,6 +144,10 @@ http_auth_Reset
http_auth_ParseWwwAuthenticateHeader
http_auth_ParseAuthenticationInfoHeader
http_auth_FormatAuthorizationHeader
+http_cookies_new
+http_cookies_destroy
+http_cookies_append
+http_cookies_for_url
httpd_ClientIP
httpd_FileDelete
httpd_FileNew
diff --git a/src/misc/httpcookies.c b/src/misc/httpcookies.c
new file mode 100644
index 0000000..856bc61
--- /dev/null
+++ b/src/misc/httpcookies.c
@@ -0,0 +1,366 @@
+/*****************************************************************************
+ * httpcookies.h: HTTP cookie utilities
+ *****************************************************************************
+ * Copyright (C) 2014 VLC authors and VideoLAN
+ * $Id$
+ *
+ * Authors: Antti Ajanki <antti.ajanki at iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include <vlc_common.h>
+#include <vlc_messages.h>
+#include <vlc_strings.h>
+#include <vlc_http.h>
+
+typedef struct http_cookie_t
+{
+ char *psz_name;
+ char *psz_value;
+ char *psz_domain;
+ char *psz_path;
+ bool b_host_only;
+ bool b_secure;
+} http_cookie_t;
+
+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 );
+static char * cookie_get_domain( const char * cookie );
+static char * cookie_get_attribute_value( const char * cookie, const char *attr );
+static bool cookie_has_attribute( const char * cookie, const char *attr );
+static bool cookie_should_be_sent( const http_cookie_t * cookie, const vlc_url_t * url );
+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 );
+
+http_cookie_jar_t * http_cookies_new()
+{
+ return vlc_array_new();
+}
+
+void http_cookies_destroy( 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 );
+}
+
+bool http_cookies_append( http_cookie_jar_t * p_jar, const char * psz_cookie_header, const vlc_url_t *p_url )
+{
+ int i;
+
+ http_cookie_t *cookie = cookie_parse( psz_cookie_header, p_url );
+ if( !cookie || !cookie_is_valid( cookie, p_url->psz_host ) )
+ {
+ cookie_destroy( cookie );
+ return false;
+ }
+
+ for( i = 0; i < vlc_array_count( p_jar ); i++ )
+ {
+ http_cookie_t *iter = vlc_array_item_at_index( p_jar, i );
+
+ assert( iter->psz_name );
+ assert( iter->psz_domain );
+ assert( iter->psz_path );
+
+ bool domains_match =
+ vlc_ascii_strcasecmp( cookie->psz_domain, iter->psz_domain ) == 0;
+ 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( p_jar, i );
+ cookie_destroy(iter);
+ break;
+ }
+ }
+ vlc_array_append( p_jar, cookie );
+
+ 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++ )
+ {
+ const http_cookie_t * cookie = vlc_array_item_at_index( p_jar, i );
+ if ( cookie_should_be_sent( cookie, p_url ) )
+ {
+ char *psz_updated_buf = NULL;
+ if ( asprintf(&psz_updated_buf, "%s%s%s=%s",
+ psz_cookiebuf ? psz_cookiebuf : "",
+ psz_cookiebuf ? "; " : "",
+ cookie->psz_name ? cookie->psz_name : "",
+ cookie->psz_value ? cookie->psz_value : "") == -1 )
+ {
+ // TODO: report error
+ free( psz_cookiebuf );
+ return NULL;
+ }
+ free( psz_cookiebuf );
+ psz_cookiebuf = psz_updated_buf;
+ }
+ }
+
+ return psz_cookiebuf;
+}
+
+static http_cookie_t * cookie_parse( const char * cookie_header, const vlc_url_t * url )
+{
+ http_cookie_t *cookie = calloc( 1, sizeof( http_cookie_t ) );
+ if ( unlikely( !cookie ) )
+ return NULL;
+
+ char *content = cookie_get_content( cookie_header );
+ if ( !content )
+ {
+ cookie_destroy( cookie );
+ return NULL;
+ }
+
+ const char *eq = strchr( content, '=' );
+ if ( eq )
+ {
+ cookie->psz_name = strndup( content, eq-content );
+ cookie->psz_value = strdup( eq + 1 );
+ }
+ else
+ {
+ cookie->psz_name = strdup( content );
+ cookie->psz_value = NULL;
+ }
+
+ cookie->psz_domain = cookie_get_domain( cookie_header );
+ if ( !cookie->psz_domain || strlen(cookie->psz_domain) == 0 )
+ {
+ free(cookie->psz_domain);
+ 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 );
+ }
+
+ cookie->b_secure = cookie_has_attribute( cookie_header, "secure" );
+
+ FREENULL( content );
+
+ if ( !cookie->psz_domain || !cookie->psz_path || !cookie->psz_name )
+ {
+ cookie_destroy( cookie );
+ return NULL;
+ }
+
+ return cookie;
+}
+
+static void cookie_destroy( http_cookie_t * p_cookie )
+{
+ if ( !p_cookie )
+ return;
+
+ free( p_cookie->psz_name );
+ free( p_cookie->psz_value );
+ free( p_cookie->psz_domain );
+ free( p_cookie->psz_path );
+ free( p_cookie );
+}
+
+/* Get the NAME=VALUE part of the Cookie */
+static char * cookie_get_content( const char * cookie )
+{
+ size_t content_length = strcspn( cookie, ";" );
+ return strndup( cookie, content_length );
+}
+
+/* Get the domain where the cookie is stored */
+static char * cookie_get_domain( const char * cookie )
+{
+ char *domain = cookie_get_attribute_value( cookie, "domain" );
+ if ( domain && *domain == '.' )
+ {
+ const char *real_domain = domain + strspn( domain, "." );
+ memmove( domain, real_domain, strlen( real_domain ) + 1 );
+ }
+ return domain;
+}
+
+static char * cookie_get_attribute_value( const char * cookie, const char *attr )
+{
+ if( !cookie || !attr )
+ return NULL;
+
+ size_t attrlen = strlen( attr );
+ const char * str = strchr( cookie, ';' );
+ while( str )
+ {
+ /* skip ; and blank */
+ str++;
+ str = str + strspn( str, " " );
+
+ if( !vlc_ascii_strncasecmp( str, attr, attrlen ) &&
+ ( str[attrlen] == '=' ) )
+ {
+ str += attrlen + 1;
+ size_t value_length = strcspn( str, ";" );
+ return strndup( str, value_length );
+ }
+
+ str = strchr( str, ';' );
+ }
+ return NULL;
+}
+
+static bool cookie_has_attribute( const char * cookie, const char *attr )
+{
+ if( !cookie || !attr )
+ return false;
+
+ size_t attrlen = strlen(attr);
+ const char * str = strchr(cookie, ';');
+ while( str )
+ {
+ /* skip ; and blank */
+ str++;
+ str = str + strspn( str, " " );
+
+ if( !vlc_ascii_strncasecmp( str, attr, attrlen ) &&
+ ( str[attrlen] == '=' || str[attrlen] == ';' || str[attrlen] == '\0' ) )
+ return true;
+
+ str = strchr(str, ';');
+ }
+ return false;
+}
+
+static bool cookie_should_be_sent( const http_cookie_t * cookie, const vlc_url_t * url )
+{
+ bool protocol_ok = !cookie->b_secure ||
+ ( url->psz_protocol && strcasecmp(url->psz_protocol, "https") == 0 );
+ bool domain_ok = cookie_domain_matches( cookie, url->psz_host );
+ bool path_ok = cookie_path_matches( cookie, url->psz_path );
+ return protocol_ok && domain_ok && path_ok;
+}
+
+/* Check if a cookie from host should be added to the cookie jar */
+static bool cookie_is_valid( const http_cookie_t * cookie, const char *host )
+{
+ return cookie && cookie->psz_name && strlen(cookie->psz_name) > 0 &&
+ cookie->psz_domain &&
+ !cookie_domain_is_public_suffix(cookie->psz_domain) &&
+ cookie_domain_matches(cookie, host);
+}
+
+static bool cookie_domain_matches( const http_cookie_t * cookie, const char *host )
+{
+ assert( !cookie || cookie->psz_domain );
+
+ // TODO: should convert domain names to punycode before comparing
+
+ if ( !cookie || !host )
+ return false;
+ if ( vlc_ascii_strcasecmp(cookie->psz_domain, host) == 0 )
+ return true;
+ else if ( cookie->b_host_only )
+ return false;
+
+ size_t host_len = strlen(host);
+ size_t cookie_domain_len = strlen(cookie->psz_domain);
+ int i = host_len - cookie_domain_len;
+ bool is_suffix = ( i > 0 ) &&
+ vlc_ascii_strcasecmp( &host[i], cookie->psz_domain ) == 0;
+ bool has_dot_before_suffix = host[i-1] == '.';
+ bool host_is_ipv4 = strspn(host, "0123456789.") == host_len;
+ bool host_is_ipv6 = strchr(host, ':') != NULL;
+ return is_suffix && has_dot_before_suffix &&
+ !( host_is_ipv4 || host_is_ipv6 );
+}
+
+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
+ // http://publicsuffix.org/. The purpose of this check is to
+ // prevent a host from setting a "too wide" cookie, for example
+ // "example.com" should not be able to set a cookie for "com".
+ // The current implementation prevents all top-level domains.
+ return domain && !strchr(domain, '.');
+}
+
+static char * cookie_default_path( const char *request_path )
+{
+ if ( !request_path || *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;
+}
--
1.7.10.4
More information about the vlc-devel
mailing list