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
23#if USE(SOUP)
24
25#include "CookieJarSoup.h"
26
27#include "Cookie.h"
28#include "GUniquePtrSoup.h"
29#include "URL.h"
30#include "NetworkingContext.h"
31#include "PlatformCookieJar.h"
32#include "SoupNetworkSession.h"
33#include <wtf/gobject/GRefPtr.h>
34#include <wtf/text/CString.h>
35
36namespace WebCore {
37
38static SoupCookieJar* cookieJarForSession(const NetworkStorageSession& session)
39{
40    return session.soupNetworkSession().cookieJar();
41}
42
43static GRefPtr<SoupCookieJar>& defaultCookieJar()
44{
45    DEPRECATED_DEFINE_STATIC_LOCAL(GRefPtr<SoupCookieJar>, cookieJar, ());
46    return cookieJar;
47}
48
49SoupCookieJar* soupCookieJar()
50{
51    if (GRefPtr<SoupCookieJar>& jar = defaultCookieJar())
52        return jar.get();
53
54    SoupCookieJar* jar = soup_cookie_jar_new();
55    soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
56    setSoupCookieJar(jar);
57    return jar;
58}
59
60SoupCookieJar* createPrivateBrowsingCookieJar()
61{
62    SoupCookieJar* jar = soup_cookie_jar_new();
63
64    soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
65
66    return jar;
67}
68
69void setSoupCookieJar(SoupCookieJar* jar)
70{
71    defaultCookieJar() = jar;
72}
73
74static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name, const gchar* path)
75{
76    for (const GSList* iter = cookies; iter; iter = g_slist_next(iter)) {
77        SoupCookie* cookie = static_cast<SoupCookie*>(iter->data);
78        if (!strcmp(soup_cookie_get_name(cookie), name)
79            && !g_strcmp0(soup_cookie_get_path(cookie), path)) {
80            if (soup_cookie_get_http_only(cookie))
81                return true;
82            break;
83        }
84    }
85    return false;
86}
87
88void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& value)
89{
90    SoupCookieJar* jar = cookieJarForSession(session);
91    if (!jar)
92        return;
93
94    GUniquePtr<SoupURI> origin = url.createSoupURI();
95    GUniquePtr<SoupURI> firstPartyURI = firstParty.createSoupURI();
96
97    // Get existing cookies for this origin.
98    GSList* existingCookies = soup_cookie_jar_get_cookie_list(jar, origin.get(), TRUE);
99
100    Vector<String> cookies;
101    value.split('\n', cookies);
102    const size_t cookiesCount = cookies.size();
103    for (size_t i = 0; i < cookiesCount; ++i) {
104        GUniquePtr<SoupCookie> cookie(soup_cookie_parse(cookies[i].utf8().data(), origin.get()));
105        if (!cookie)
106            continue;
107
108        // Make sure the cookie is not httpOnly since such cookies should not be set from JavaScript.
109        if (soup_cookie_get_http_only(cookie.get()))
110            continue;
111
112        // Make sure we do not overwrite httpOnly cookies from JavaScript.
113        if (httpOnlyCookieExists(existingCookies, soup_cookie_get_name(cookie.get()), soup_cookie_get_path(cookie.get())))
114            continue;
115
116        soup_cookie_jar_add_cookie_with_first_party(jar, firstPartyURI.get(), cookie.release());
117    }
118
119    soup_cookies_free(existingCookies);
120}
121
122static String cookiesForSession(const NetworkStorageSession& session, const URL& url, bool forHTTPHeader)
123{
124    SoupCookieJar* jar = cookieJarForSession(session);
125    if (!jar)
126        return String();
127
128    GUniquePtr<SoupURI> uri = url.createSoupURI();
129    GUniquePtr<char> cookies(soup_cookie_jar_get_cookies(jar, uri.get(), forHTTPHeader));
130    return String::fromUTF8(cookies.get());
131}
132
133String cookiesForDOM(const NetworkStorageSession& session, const URL&, const URL& url)
134{
135    return cookiesForSession(session, url, false);
136}
137
138String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& url)
139{
140    return cookiesForSession(session, url, true);
141}
142
143bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/)
144{
145    return !!cookieJarForSession(session);
146}
147
148bool getRawCookies(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& url, Vector<Cookie>& rawCookies)
149{
150    rawCookies.clear();
151    SoupCookieJar* jar = cookieJarForSession(session);
152    if (!jar)
153        return false;
154
155    GUniquePtr<SoupURI> uri = url.createSoupURI();
156    GUniquePtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE));
157    if (!cookies)
158        return false;
159
160    for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
161        SoupCookie* cookie = static_cast<SoupCookie*>(iter->data);
162        rawCookies.append(Cookie(String::fromUTF8(cookie->name), String::fromUTF8(cookie->value), String::fromUTF8(cookie->domain),
163            String::fromUTF8(cookie->path), cookie->expires ? static_cast<double>(soup_date_to_time_t(cookie->expires)) * 1000 : 0,
164            cookie->http_only, cookie->secure, !cookie->expires));
165        soup_cookie_free(cookie);
166    }
167
168    return true;
169}
170
171void deleteCookie(const NetworkStorageSession& session, const URL& url, const String& name)
172{
173    SoupCookieJar* jar = cookieJarForSession(session);
174    if (!jar)
175        return;
176
177    GUniquePtr<SoupURI> uri = url.createSoupURI();
178    GUniquePtr<GSList> cookies(soup_cookie_jar_get_cookie_list(jar, uri.get(), TRUE));
179    if (!cookies)
180        return;
181
182    CString cookieName = name.utf8();
183    bool wasDeleted = false;
184    for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
185        SoupCookie* cookie = static_cast<SoupCookie*>(iter->data);
186        if (!wasDeleted && cookieName == cookie->name) {
187            soup_cookie_jar_delete_cookie(jar, cookie);
188            wasDeleted = true;
189        }
190        soup_cookie_free(cookie);
191    }
192}
193
194void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames)
195{
196    SoupCookieJar* cookieJar = cookieJarForSession(session);
197    GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
198    for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
199        SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
200        if (cookie->domain)
201            hostnames.add(String::fromUTF8(cookie->domain));
202        soup_cookie_free(cookie);
203    }
204}
205
206void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname)
207{
208    CString hostNameString = hostname.utf8();
209    SoupCookieJar* cookieJar = cookieJarForSession(session);
210    GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
211    for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
212        SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
213        if (soup_cookie_domain_matches(cookie, hostNameString.data()))
214            soup_cookie_jar_delete_cookie(cookieJar, cookie);
215        soup_cookie_free(cookie);
216    }
217}
218
219void deleteAllCookies(const NetworkStorageSession& session)
220{
221    SoupCookieJar* cookieJar = cookieJarForSession(session);
222    GUniquePtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
223    for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
224        SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
225        soup_cookie_jar_delete_cookie(cookieJar, cookie);
226        soup_cookie_free(cookie);
227    }
228}
229
230void deleteAllCookiesModifiedAfterDate(const NetworkStorageSession&, double)
231{
232}
233
234}
235
236#endif
237