/* * Copyright (c) 2004 Nokia. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce theb above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the * distribution. * * Neither the name of Nokia nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include // strcmp #include "Cookie.h" #include "CookieStorage.h" #include "uri.h" /** Class storing all cookies from one domain. */ class CookieJar { public: CookieJar(const GURI* host); ~CookieJar(); /** Returned memory must be free'd.*/ gchar* cookiesForPath(const GURI* path); void addCookie(Cookie* cookie); private: GURI* host; GHashTable* cookies; }; extern "C" { static void cookie_jar_cookie_destroy(gpointer data, gpointer user_data) { assert(data); Cookie* c = static_cast(data); delete c; } static void cookie_jar_value_destroy(gpointer item) { assert(item); GList* list = static_cast(item); g_list_foreach(list, cookie_jar_cookie_destroy, NULL); g_list_free(list); } static void concatenate_cookies(gpointer data, gpointer user_data) { assert(data); assert(user_data); Cookie* cookie = static_cast(data); GString* buffer = static_cast(user_data); g_string_append_printf(buffer, "; %s", cookie->cookieString()); } static void cookies_key_destroy(gpointer item) { assert(item); g_free(static_cast(item)); } static void cookiesByURL_value_destroy(gpointer item) { assert(item); CookieJar* jar = static_cast(item); delete jar; } } // extern "C" CookieJar::CookieJar(const GURI* ahost) : host(gnet_uri_clone(ahost)) { cookies = g_hash_table_new_full(g_str_hash, g_str_equal, cookies_key_destroy, cookie_jar_value_destroy); } CookieJar::~CookieJar() { g_hash_table_destroy(cookies); gnet_uri_delete(host); } void CookieJar::addCookie(Cookie* cookie) { assert(cookie); const gchar* path = cookie->path() ? cookie->path() : "/"; gpointer key = 0L, value = 0L; gchar* keyString; GList* cookieList = 0L; // stealing is necessary in order to avoid list being freed in g_hash_table_insert. // Therefore we also need to use original key to avoid memory being leaked // on stolen keys. -- psalmi if (g_hash_table_lookup_extended(cookies, path, &key, &value)) { keyString = static_cast(key); cookieList = static_cast(value); } else { keyString = g_strdup(path); } g_hash_table_steal(cookies, keyString); cookieList = g_list_append(cookieList, cookie); g_hash_table_insert(cookies, keyString, cookieList); } gchar* CookieJar::cookiesForPath(const GURI* uriPath) { assert(uriPath); assert(cookies); if (g_hash_table_size(cookies) == 0) { return 0L; } GString* buffer = NULL; buffer = g_string_sized_new (32); g_string_append_printf (buffer, "$Version=1"); GURI* uri = gnet_uri_clone(uriPath); GURI* parent = 0L; GList* cookieList = 0L; bool haveParent = true; void* item; const gchar* path = 0L; while (haveParent) { if (parent) { gnet_uri_delete(uri); uri = parent; } path = uri->path ? uri->path : "/"; item = g_hash_table_lookup(cookies, path); if (item) { cookieList = static_cast(item); if (cookieList) g_list_foreach(cookieList, concatenate_cookies, buffer); } haveParent = (parent = (uri ? gnet_uri_parent(uri) : 0L)); } gnet_uri_delete(uri); gchar* str = buffer->str; g_string_free (buffer, FALSE); return str; } /** * Dummy implementation for cookie storage * Doesn't implement any sort of policy management. * Stores cookie according to url, * Is not persistent */ CookieStorage::CookieStorage() :m_enabled(true) ,m_cookieString(0) { m_cookiesByURL = g_hash_table_new_full(g_str_hash, g_str_equal, cookies_key_destroy, cookiesByURL_value_destroy); } CookieStorage::~CookieStorage() { g_hash_table_destroy(m_cookiesByURL); if (m_cookieString) g_free(m_cookieString); m_cookieString = 0L; } bool CookieStorage::cookiesEnabled() { return m_enabled; } void CookieStorage::setCookiesEnabled(bool flag) { m_enabled = flag; } const gchar* CookieStorage::cookiesForURL(const gchar* URL) { assert(URL); if (!m_enabled) return 0L; if (m_cookieString) { g_free(m_cookieString); m_cookieString = 0L; } GURI* uri = gnet_uri_new(URL); if (!uri->hostname) return 0L; CookieJar* cj = static_cast(g_hash_table_lookup(m_cookiesByURL, uri->hostname)); if (cj) m_cookieString = cj->cookiesForPath(uri); gnet_uri_delete(uri); return m_cookieString; } void CookieStorage::setCookiesForURL(const gchar* cookies, const gchar* URL, const gchar* policyBaseURL) { assert(cookies); assert(URL); assert(policyBaseURL); if (!m_enabled) return; GURI* uri = gnet_uri_new(URL); if (!cookies) { g_hash_table_remove(m_cookiesByURL, uri->hostname); } else { CookieJar* cj = static_cast(g_hash_table_lookup(m_cookiesByURL, uri->hostname)); if (!cj) { cj = new CookieJar(uri); g_hash_table_replace(m_cookiesByURL, g_strdup(uri->hostname), cj); } cj->addCookie(new Cookie(cookies, URL)); } gnet_uri_delete(uri); } void CookieStorage::useAsSharedAdapter() { WebCoreCookieAdapter::setSharedAdapter(sharedAdapter()); } CookieStorage* CookieStorage::sharedAdapter() { static CookieStorage singleton; return &singleton; }