1/* 2 * Copyright (C) 2008 Xan Lopez <xan@gnome.org> 3 * Copyright (C) 2009 Igalia S.L. 4 * Copyright (C) 2008 Apple Inc. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21#include "config.h" 22#include "CookieJarSoup.h" 23 24#include "Cookie.h" 25#include "GOwnPtrSoup.h" 26#include "KURL.h" 27#include "NetworkingContext.h" 28#include "PlatformCookieJar.h" 29#include "ResourceHandle.h" 30#include <wtf/gobject/GRefPtr.h> 31#include <wtf/text/CString.h> 32 33namespace WebCore { 34 35static SoupCookieJar* cookieJarForSession(const NetworkStorageSession& session) 36{ 37 if (!session.soupSession()) 38 return soupCookieJar(); 39 return SOUP_COOKIE_JAR(soup_session_get_feature(session.soupSession(), SOUP_TYPE_COOKIE_JAR)); 40} 41 42static GRefPtr<SoupCookieJar>& defaultCookieJar() 43{ 44 DEFINE_STATIC_LOCAL(GRefPtr<SoupCookieJar>, cookieJar, ()); 45 return cookieJar; 46} 47 48SoupCookieJar* soupCookieJar() 49{ 50 if (GRefPtr<SoupCookieJar>& jar = defaultCookieJar()) 51 return jar.get(); 52 53 SoupCookieJar* jar = soup_cookie_jar_new(); 54 soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY); 55 setSoupCookieJar(jar); 56 return jar; 57} 58 59void setSoupCookieJar(SoupCookieJar* jar) 60{ 61 defaultCookieJar() = jar; 62} 63 64static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name, const gchar* path) 65{ 66 for (const GSList* iter = cookies; iter; iter = g_slist_next(iter)) { 67 SoupCookie* cookie = static_cast<SoupCookie*>(iter->data); 68 if (!strcmp(soup_cookie_get_name(cookie), name) 69 && !g_strcmp0(soup_cookie_get_path(cookie), path)) { 70 if (soup_cookie_get_http_only(cookie)) 71 return true; 72 break; 73 } 74 } 75 return false; 76} 77 78void setCookiesFromDOM(const NetworkStorageSession& session, const KURL& firstParty, const KURL& url, const String& value) 79{ 80 SoupCookieJar* jar = cookieJarForSession(session); 81 if (!jar) 82 return; 83 84 GOwnPtr<SoupURI> origin(soup_uri_new(url.string().utf8().data())); 85 GOwnPtr<SoupURI> firstPartyURI(soup_uri_new(firstParty.string().utf8().data())); 86 87 // Get existing cookies for this origin. 88 GSList* existingCookies = soup_cookie_jar_get_cookie_list(jar, origin.get(), TRUE); 89 90 Vector<String> cookies; 91 value.split('\n', cookies); 92 const size_t cookiesCount = cookies.size(); 93 for (size_t i = 0; i < cookiesCount; ++i) { 94 GOwnPtr<SoupCookie> cookie(soup_cookie_parse(cookies[i].utf8().data(), origin.get())); 95 if (!cookie) 96 continue; 97 98 // Make sure the cookie is not httpOnly since such cookies should not be set from JavaScript. 99 if (soup_cookie_get_http_only(cookie.get())) 100 continue; 101 102 // Make sure we do not overwrite httpOnly cookies from JavaScript. 103 if (httpOnlyCookieExists(existingCookies, soup_cookie_get_name(cookie.get()), soup_cookie_get_path(cookie.get()))) 104 continue; 105 106 soup_cookie_jar_add_cookie_with_first_party(jar, firstPartyURI.get(), cookie.release()); 107 } 108 109 soup_cookies_free(existingCookies); 110} 111 112static String cookiesForSession(const NetworkStorageSession& session, const KURL& url, bool forHTTPHeader) 113{ 114 SoupCookieJar* jar = cookieJarForSession(session); 115 if (!jar) 116 return String(); 117 118 GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data())); 119 GOwnPtr<char> cookies(soup_cookie_jar_get_cookies(jar, uri.get(), forHTTPHeader)); 120 return String::fromUTF8(cookies.get()); 121} 122 123String cookiesForDOM(const NetworkStorageSession& session, const KURL&, const KURL& url) 124{ 125 return cookiesForSession(session, url, false); 126} 127 128String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const KURL& /*firstParty*/, const KURL& url) 129{ 130 return cookiesForSession(session, url, true); 131} 132 133bool cookiesEnabled(const NetworkStorageSession& session, const KURL& /*firstParty*/, const KURL& /*url*/) 134{ 135 return !!cookieJarForSession(session); 136} 137 138bool getRawCookies(const NetworkStorageSession& session, const KURL& /*firstParty*/, const KURL& url, Vector<Cookie>& rawCookies) 139{ 140 rawCookies.clear(); 141 SoupCookieJar* jar = cookieJarForSession(session); 142 if (!jar) 143 return false; 144 145 GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data())); 146 GOwnPtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE)); 147 if (!cookies) 148 return false; 149 150 for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) { 151 SoupCookie* cookie = static_cast<SoupCookie*>(iter->data); 152 rawCookies.append(Cookie(String::fromUTF8(cookie->name), String::fromUTF8(cookie->value), String::fromUTF8(cookie->domain), 153 String::fromUTF8(cookie->path), cookie->expires ? static_cast<double>(soup_date_to_time_t(cookie->expires)) * 1000 : 0, 154 cookie->http_only, cookie->secure, !cookie->expires)); 155 soup_cookie_free(cookie); 156 } 157 158 return true; 159} 160 161void deleteCookie(const NetworkStorageSession& session, const KURL& url, const String& name) 162{ 163 SoupCookieJar* jar = cookieJarForSession(session); 164 if (!jar) 165 return; 166 167 GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data())); 168 GOwnPtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE)); 169 if (!cookies) 170 return; 171 172 CString cookieName = name.utf8(); 173 bool wasDeleted = false; 174 for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) { 175 SoupCookie* cookie = static_cast<SoupCookie*>(iter->data); 176 if (!wasDeleted && cookieName == cookie->name) { 177 soup_cookie_jar_delete_cookie(jar, cookie); 178 wasDeleted = true; 179 } 180 soup_cookie_free(cookie); 181 } 182} 183 184void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames) 185{ 186 SoupCookieJar* cookieJar = cookieJarForSession(session); 187 GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar)); 188 for (GSList* item = cookies.get(); item; item = g_slist_next(item)) { 189 SoupCookie* cookie = static_cast<SoupCookie*>(item->data); 190 if (cookie->domain) 191 hostnames.add(String::fromUTF8(cookie->domain)); 192 soup_cookie_free(cookie); 193 } 194} 195 196void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname) 197{ 198 CString hostNameString = hostname.utf8(); 199 SoupCookieJar* cookieJar = cookieJarForSession(session); 200 GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar)); 201 for (GSList* item = cookies.get(); item; item = g_slist_next(item)) { 202 SoupCookie* cookie = static_cast<SoupCookie*>(item->data); 203 if (soup_cookie_domain_matches(cookie, hostNameString.data())) 204 soup_cookie_jar_delete_cookie(cookieJar, cookie); 205 soup_cookie_free(cookie); 206 } 207} 208 209void deleteAllCookies(const NetworkStorageSession& session) 210{ 211 SoupCookieJar* cookieJar = cookieJarForSession(session); 212 GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar)); 213 for (GSList* item = cookies.get(); item; item = g_slist_next(item)) { 214 SoupCookie* cookie = static_cast<SoupCookie*>(item->data); 215 soup_cookie_jar_delete_cookie(cookieJar, cookie); 216 soup_cookie_free(cookie); 217 } 218} 219 220} 221