Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  httpcookies.c   Sprache: C

 

/*****************************************************************************
 * httpcookies.c: HTTP cookie utilities
 *****************************************************************************
 * Copyright (C) 2014 VLC authors and VideoLAN
 *
 * Authors: Antti Ajanki <antti.ajanki@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_arrays.h>
#include <vlc_messages.h>
#include <vlc_strings.h>
#include <vlc_http.h>
#include <vlc_threads.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 char *cookie_get_attribute_value( const char *cookie, const char *attr )
{
    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 )
{
    size_t attrlen = strlen(attr);
    const char * str = strchr(cookie, ';');
    while( str )
    {
        /* skip ; and blank */
        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;
}

/* 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 == NULL )
        return NULL;

    if( domain[0] == '.' )
    {
        const char *real_domain = domain + strspn( domain, "." );
        memmove( domain, real_domain, strlen( real_domain ) + 1 );
    }
    return domain;
}

static bool cookie_domain_matches( const http_cookie_t *cookie,
                                   const char *host )
{
    // TODO: should convert domain names to punycode before comparing

    if (host == NULL)
        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);
    bool is_suffix = false, has_dot_before_suffix = false;

    if( host_len > cookie_domain_len )
    {
        size_t i = host_len - cookie_domain_len;

        is_suffix = vlc_ascii_strcasecmp( &host[i], cookie->psz_domain ) == 0;
        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 char *cookie_get_path(const char *cookie)
{
    return cookie_get_attribute_value(cookie, "path");
}

static bool cookie_path_matches( const http_cookie_t * cookie, const char *uripath )
{
    if (uripath == NULL )
        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_should_be_sent(const http_cookie_t *cookie, bool secure,
                                  const char *host, const char *path)
{
    bool protocol_ok = secure || !cookie->b_secure;
    bool domain_ok = cookie_domain_matches(cookie, host);
    bool path_ok = cookie_path_matches(cookie, path);
    return protocol_ok && domain_ok && path_ok;
}

static char *cookie_default_path( const char *request_path )
{
    if ( request_path == NULL || request_path[0] != '/' )
        return strdup("/");

    char *path;
    const char *query_start = strchr( request_path, '?' );
    if ( query_start != NULL )
        path = strndup( request_path, query_start - request_path );
    else
        path = strdup( request_path );

    if ( path == NULL )
        return NULL;

    char *last_slash = strrchr(path, '/');
    assert(last_slash != NULL);
    if ( last_slash == path )
        path[1] = '\0';
    else
        *last_slash = '\0';

    return path;
}

static void cookie_destroy(http_cookie_t *cookie)
{
    assert(cookie != NULL);
    free(cookie->psz_name);
    free(cookie->psz_value);
    free(cookie->psz_domain);
    free(cookie->psz_path);
    free(cookie);
}

VLC_MALLOC VLC_USED
static http_cookie_t *cookie_parse(const char *value,
                                   const char *host, const char *path)
{
    http_cookie_t *cookie = malloc(sizeof (*cookie));
    if (unlikely(cookie == NULL))
        return NULL;

    cookie->psz_domain = NULL;
    cookie->psz_path = NULL;

    /* Get the NAME=VALUE part of the Cookie */
    size_t value_length = strcspn(value, ";");
    const char *p = memchr(value, '=', value_length);

    if (p != NULL)
    {
        cookie->psz_name = strndup(value, p - value);
        p++;
        cookie->psz_value = strndup(p, value_length - (p - value));
        if (unlikely(cookie->psz_value == NULL))
            goto error;
    }
    else
    {
        cookie->psz_name = strndup(value, value_length);
        cookie->psz_value = NULL;
    }

    if (unlikely(cookie->psz_name == NULL))
        goto error;

    /* Cookie name is a token; it cannot be empty. */
    if (cookie->psz_name[0] == '\0')
        goto error;

    /* Get domain */
    cookie->psz_domain = cookie_get_domain(value);
    if (cookie->psz_domain == NULL)
    {
        cookie->psz_domain = strdup(host);
        if (unlikely(cookie->psz_domain == NULL))
            goto error;

        cookie->b_host_only = true;
    }
    else
        cookie->b_host_only = false;

    /* Get path */
    cookie->psz_path = cookie_get_path(value);
    if (cookie->psz_path == NULL)
    {
        cookie->psz_path = cookie_default_path(path);
        if (unlikely(cookie->psz_path == NULL))
            goto error;
    }

    /* Get secure flag */
    cookie->b_secure = cookie_has_attribute(value, "secure");

    return cookie;

error:
    cookie_destroy(cookie);
    return NULL;
}

struct vlc_http_cookie_jar_t
{
    vlc_array_t cookies;
    vlc_mutex_t lock;
};

vlc_http_cookie_jar_t * vlc_http_cookies_new(void)
{
    vlc_http_cookie_jar_t * jar = malloc( sizeof( vlc_http_cookie_jar_t ) );
    if ( unlikely(jar == NULL) )
        return NULL;

    vlc_array_init( &jar->cookies );
    vlc_mutex_init( &jar->lock );

    return jar;
}

void vlc_http_cookies_destroy( vlc_http_cookie_jar_t * p_jar )
{
    if ( !p_jar )
        return;

    for( size_t 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 );

    free( p_jar );
}

bool vlc_http_cookies_store(vlc_http_cookie_jar_t *p_jar, const char *cookies,
                            const char *host, const char *path)
{
    assert(host != NULL);
    assert(path != NULL);

    http_cookie_t *cookie = cookie_parse(cookies, host, path);
    if (cookie == NULL)
        return false;

    /* Check if a cookie from host should be added to the cookie jar */
    // 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.
    if (strchr(cookie->psz_domain, '.') == NULL
     || !cookie_domain_matches(cookie, host))
    {
        cookie_destroy(cookie);
        return false;
    }

    vlc_mutex_lock( &p_jar->lock );

    for( size_t i = 0; i < vlc_array_count( &p_jar->cookies ); i++ )
    {
        http_cookie_t *iter = vlc_array_item_at_index( &p_jar->cookies, 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->cookies, i );
            cookie_destroy(iter);
            break;
        }
    }

    bool b_ret = (vlc_array_append( &p_jar->cookies, cookie ) == 0);
    if( !b_ret )
        cookie_destroy( cookie );

    vlc_mutex_unlock( &p_jar->lock );

    return b_ret;
}

char *vlc_http_cookies_fetch(vlc_http_cookie_jar_t *p_jar, bool secure,
                             const char *host, const char *path)
{
    char *psz_cookiebuf = NULL;

    vlc_mutex_lock( &p_jar->lock );

    for( size_t i = 0; i < vlc_array_count( &p_jar->cookies ); i++ )
    {
        const http_cookie_t * cookie = vlc_array_item_at_index( &p_jar->cookies, i );
        if (cookie_should_be_sent(cookie, secure, host, path))
        {
            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 );
                vlc_mutex_unlock( &p_jar->lock );
                return NULL;
            }
            free( psz_cookiebuf );
            psz_cookiebuf = psz_updated_buf;
        }
    }

    vlc_mutex_unlock( &p_jar->lock );

    return psz_cookiebuf;
}

Messung
CHZG
839710093

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499164