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