CookieJar uses Document class, which is a layering violation
[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* cookieJarForContext(NetworkingContext* context)
36 {
37     return SOUP_COOKIE_JAR(soup_session_get_feature(context->soupSession(), SOUP_TYPE_COOKIE_JAR));
38 }
39
40 static GRefPtr<SoupCookieJar>& defaultCookieJar()
41 {
42     DEFINE_STATIC_LOCAL(GRefPtr<SoupCookieJar>, cookieJar, ());
43     return cookieJar;
44 }
45
46 SoupCookieJar* soupCookieJar()
47 {
48     if (GRefPtr<SoupCookieJar>& jar = defaultCookieJar())
49         return jar.get();
50
51     SoupCookieJar* jar = soup_cookie_jar_new();
52     soup_cookie_jar_set_accept_policy(jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
53     setSoupCookieJar(jar);
54     return jar;
55 }
56
57 void setSoupCookieJar(SoupCookieJar* jar)
58 {
59     defaultCookieJar() = jar;
60 }
61
62 static inline bool httpOnlyCookieExists(const GSList* cookies, const gchar* name, const gchar* path)
63 {
64     for (const GSList* iter = cookies; iter; iter = g_slist_next(iter)) {
65         SoupCookie* cookie = static_cast<SoupCookie*>(iter->data);
66         if (!strcmp(soup_cookie_get_name(cookie), name)
67             && !g_strcmp0(soup_cookie_get_path(cookie), path)) {
68             if (soup_cookie_get_http_only(cookie))
69                 return true;
70             break;
71         }
72     }
73     return false;
74 }
75
76 void setCookiesFromDOM(NetworkingContext* context, const KURL& firstParty, const KURL& url, const String& value)
77 {
78     SoupCookieJar* jar = context ? cookieJarForContext(context) : soupCookieJar();
79     if (!jar)
80         return;
81
82     GOwnPtr<SoupURI> origin(soup_uri_new(url.string().utf8().data()));
83     GOwnPtr<SoupURI> firstPartyURI(soup_uri_new(firstParty.string().utf8().data()));
84
85     // Get existing cookies for this origin.
86     GSList* existingCookies = soup_cookie_jar_get_cookie_list(jar, origin.get(), TRUE);
87
88     Vector<String> cookies;
89     value.split('\n', cookies);
90     const size_t cookiesCount = cookies.size();
91     for (size_t i = 0; i < cookiesCount; ++i) {
92         GOwnPtr<SoupCookie> cookie(soup_cookie_parse(cookies[i].utf8().data(), origin.get()));
93         if (!cookie)
94             continue;
95
96         // Make sure the cookie is not httpOnly since such cookies should not be set from JavaScript.
97         if (soup_cookie_get_http_only(cookie.get()))
98             continue;
99
100         // Make sure we do not overwrite httpOnly cookies from JavaScript.
101         if (httpOnlyCookieExists(existingCookies, soup_cookie_get_name(cookie.get()), soup_cookie_get_path(cookie.get())))
102             continue;
103
104         soup_cookie_jar_add_cookie_with_first_party(jar, firstPartyURI.get(), cookie.release());
105     }
106
107     soup_cookies_free(existingCookies);
108 }
109
110 static String cookiesForContext(NetworkingContext* context, const KURL& url, bool forHTTPHeader)
111 {
112     SoupCookieJar* jar = context ? cookieJarForContext(context) : soupCookieJar();
113     if (!jar)
114         return String();
115
116     GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data()));
117     GOwnPtr<char> cookies(soup_cookie_jar_get_cookies(jar, uri.get(), forHTTPHeader));
118     return String::fromUTF8(cookies.get());
119 }
120
121 String cookiesForDOM(NetworkingContext* context, const KURL&, const KURL& url)
122 {
123     return cookiesForContext(context, url, false);
124 }
125
126 String cookieRequestHeaderFieldValue(NetworkingContext* context, const KURL& url)
127 {
128     return cookiesForContext(context, url, true);
129 }
130
131 bool cookiesEnabled(NetworkingContext* context)
132 {
133     return !!cookieJarForContext(context);
134 }
135
136 bool getRawCookies(NetworkingContext* context, const KURL& url, Vector<Cookie>& rawCookies)
137 {
138     rawCookies.clear();
139     SoupCookieJar* jar = context ? cookieJarForContext(context) : soupCookieJar();
140     if (!jar)
141         return false;
142
143     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(jar));
144     if (!cookies)
145         return false;
146
147     GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data()));
148     for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
149         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(iter->data));
150         if (!soup_cookie_applies_to_uri(cookie.get(), uri.get()))
151             continue;
152         rawCookies.append(Cookie(String::fromUTF8(cookie->name), String::fromUTF8(cookie->value), String::fromUTF8(cookie->domain),
153                                  String::fromUTF8(cookie->path), static_cast<double>(soup_date_to_time_t(cookie->expires)) * 1000,
154                                  cookie->http_only, cookie->secure, soup_cookie_jar_is_persistent(jar)));
155     }
156
157     return true;
158 }
159
160 void deleteCookie(NetworkingContext* context, const KURL& url, const String& name)
161 {
162     SoupCookieJar* jar = context ? cookieJarForContext(context) : soupCookieJar();
163     if (!jar)
164         return;
165
166     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(jar));
167     if (!cookies)
168         return;
169
170     CString cookieName = name.utf8();
171     GOwnPtr<SoupURI> uri(soup_uri_new(url.string().utf8().data()));
172     for (GSList* iter = cookies.get(); iter; iter = g_slist_next(iter)) {
173         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(iter->data));
174         if (!soup_cookie_applies_to_uri(cookie.get(), uri.get()))
175             continue;
176         if (cookieName == cookie->name)
177             soup_cookie_jar_delete_cookie(jar, cookie.get());
178     }
179 }
180
181 void getHostnamesWithCookies(NetworkingContext* context, HashSet<String>& hostnames)
182 {
183     SoupCookieJar* cookieJar = context ? cookieJarForContext(context) : soupCookieJar();
184     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
185     for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
186         GOwnPtr<SoupCookie> cookie(static_cast<SoupCookie*>(item->data));
187         if (!cookie->domain)
188             continue;
189         hostnames.add(String::fromUTF8(cookie->domain));
190     }
191 }
192
193 void deleteCookiesForHostname(NetworkingContext* context, const String& hostname)
194 {
195     CString hostNameString = hostname.utf8();
196     SoupCookieJar* cookieJar = context ? cookieJarForContext(context) : soupCookieJar();
197     GOwnPtr<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 (soup_cookie_domain_matches(cookie, hostNameString.data()))
201             soup_cookie_jar_delete_cookie(cookieJar, cookie);
202         soup_cookie_free(cookie);
203     }
204 }
205
206 void deleteAllCookies(NetworkingContext* context)
207 {
208     SoupCookieJar* cookieJar = context ? cookieJarForContext(context) : soupCookieJar();
209     GOwnPtr<GSList> cookies(soup_cookie_jar_all_cookies(cookieJar));
210     for (GSList* item = cookies.get(); item; item = g_slist_next(item)) {
211         SoupCookie* cookie = static_cast<SoupCookie*>(item->data);
212         soup_cookie_jar_delete_cookie(cookieJar, cookie);
213         soup_cookie_free(cookie);
214     }
215 }
216
217 }