Add a separate class for networking related storage
[WebKit-https.git] / Source / WebCore / platform / network / soup / CookieJarSoup.cpp
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
33 namespace WebCore {
34
35 static SoupCookieJar* cookieJarForSession(const NetworkStorageSession& session)
36 {
37     if (!session.context())
38         return soupCookieJar();
39     return SOUP_COOKIE_JAR(soup_session_get_feature(session.context()->soupSession(), SOUP_TYPE_COOKIE_JAR));
40 }
41
42 static GRefPtr<SoupCookieJar>& defaultCookieJar()
43 {
44     DEFINE_STATIC_LOCAL(GRefPtr<SoupCookieJar>, cookieJar, ());
45     return cookieJar;
46 }
47
48 SoupCookieJar* 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
59 void setSoupCookieJar(SoupCookieJar* jar)
60 {
61     defaultCookieJar() = jar;
62 }
63
64 static 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
78 void 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
112 static 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
123 String cookiesForDOM(const NetworkStorageSession& session, const KURL&, const KURL& url)
124 {
125     return cookiesForSession(session, url, false);
126 }
127
128 String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const KURL& /*firstParty*/, const KURL& url)
129 {
130     return cookiesForSession(session, url, true);
131 }
132
133 bool cookiesEnabled(const NetworkStorageSession& session, const KURL& /*firstParty*/, const KURL& /*url*/)
134 {
135     return !!cookieJarForSession(session);
136 }
137
138 bool 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<GSList> cookies(soup_cookie_jar_all_cookies(jar));
146     if (!cookies)
147         return false;
148
149     GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data()));
150     for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
151         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(iter->data));
152         if (!soup_cookie_applies_to_uri(cookie.get(), uri.get()))
153             continue;
154         rawCookies.append(Cookie(String::fromUTF8(cookie->name), String::fromUTF8(cookie->value), String::fromUTF8(cookie->domain),
155                                  String::fromUTF8(cookie->path), static_cast<double>(soup_date_to_time_t(cookie->expires)) * 1000,
156                                  cookie->http_only, cookie->secure, soup_cookie_jar_is_persistent(jar)));
157     }
158
159     return true;
160 }
161
162 void deleteCookie(const NetworkStorageSession& session, const KURL& url, const String& name)
163 {
164     SoupCookieJar* jar = cookieJarForSession(session);
165     if (!jar)
166         return;
167
168     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(jar));
169     if (!cookies)
170         return;
171
172     CString cookieName = name.utf8();
173     GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data()));
174     for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
175         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(iter->data));
176         if (!soup_cookie_applies_to_uri(cookie.get(), uri.get()))
177             continue;
178         if (cookieName == cookie->name)
179             soup_cookie_jar_delete_cookie(jar, cookie.get());
180     }
181 }
182
183 void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames)
184 {
185     SoupCookieJar* cookieJar = cookieJarForSession(session);
186     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
187     for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
188         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(item->data));
189         if (!cookie->domain)
190             continue;
191         hostnames.add(String::fromUTF8(cookie->domain));
192     }
193 }
194
195 void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname)
196 {
197     CString hostNameString = hostname.utf8();
198     SoupCookieJar* cookieJar = cookieJarForSession(session);
199     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
200     for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
201         SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
202         if (soup_cookie_domain_matches(cookie, hostNameString.data()))
203             soup_cookie_jar_delete_cookie(cookieJar, cookie);
204         soup_cookie_free(cookie);
205     }
206 }
207
208 void deleteAllCookies(const NetworkStorageSession& session)
209 {
210     SoupCookieJar* cookieJar = cookieJarForSession(session);
211     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
212     for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
213         SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
214         soup_cookie_jar_delete_cookie(cookieJar, cookie);
215         soup_cookie_free(cookie);
216     }
217 }
218
219 }