1/*
2 * Copyright (C) 2012 Igalia S.L.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21
22#include "WebKitTestServer.h"
23#include "WebViewTest.h"
24#include <glib/gstdio.h>
25
26static WebKitTestServer* kServer;
27static char* kTempDirectory;
28
29static const char* kFirstPartyDomain = "127.0.0.1";
30static const char* kThirdPartyDomain = "localhost";
31static const char* kIndexHtmlFormat =
32    "<html><body>"
33    " <p>WebKitGTK+ Cookie Manager test</p>"
34    " <img src='http://localhost:%u/image.png' width=5 height=5></img>"
35    "</body></html>";
36
37class CookieManagerTest: public WebViewTest {
38public:
39    MAKE_GLIB_TEST_FIXTURE(CookieManagerTest);
40
41    static void cookiesChangedCallback(WebKitCookieManager*, CookieManagerTest* test)
42    {
43        test->m_cookiesChanged = true;
44        if (test->m_finishLoopWhenCookiesChange)
45            g_main_loop_quit(test->m_mainLoop);
46    }
47
48    CookieManagerTest()
49        : WebViewTest()
50        , m_cookieManager(webkit_web_context_get_cookie_manager(webkit_web_view_get_context(m_webView)))
51        , m_acceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY)
52        , m_domains(0)
53        , m_cookiesChanged(false)
54        , m_finishLoopWhenCookiesChange(false)
55    {
56        g_signal_connect(m_cookieManager, "changed", G_CALLBACK(cookiesChangedCallback), this);
57    }
58
59    ~CookieManagerTest()
60    {
61        g_strfreev(m_domains);
62        g_signal_handlers_disconnect_matched(m_cookieManager, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this);
63        if (m_cookiesTextFile)
64            g_unlink(m_cookiesTextFile.get());
65        if (m_cookiesSQLiteFile)
66            g_unlink(m_cookiesSQLiteFile.get());
67    }
68
69    void setPersistentStorage(WebKitCookiePersistentStorage storage)
70    {
71        const char* filename = 0;
72        switch (storage) {
73        case WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT:
74            if (!m_cookiesTextFile)
75                m_cookiesTextFile.set(g_build_filename(kTempDirectory, "cookies.txt", NULL));
76            filename = m_cookiesTextFile.get();
77            break;
78        case WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE:
79            if (!m_cookiesSQLiteFile)
80                m_cookiesSQLiteFile.set(g_build_filename(kTempDirectory, "cookies.db", NULL));
81            filename = m_cookiesSQLiteFile.get();
82            break;
83        default:
84            g_assert_not_reached();
85        }
86        webkit_cookie_manager_set_persistent_storage(m_cookieManager, filename, storage);
87    }
88
89    static void getAcceptPolicyReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
90    {
91        GOwnPtr<GError> error;
92        WebKitCookieAcceptPolicy policy = webkit_cookie_manager_get_accept_policy_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
93        g_assert(!error.get());
94
95        CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
96        test->m_acceptPolicy = policy;
97        g_main_loop_quit(test->m_mainLoop);
98    }
99
100    WebKitCookieAcceptPolicy getAcceptPolicy()
101    {
102        m_acceptPolicy = WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY;
103        webkit_cookie_manager_get_accept_policy(m_cookieManager, 0, getAcceptPolicyReadyCallback, this);
104        g_main_loop_run(m_mainLoop);
105
106        return m_acceptPolicy;
107    }
108
109    void setAcceptPolicy(WebKitCookieAcceptPolicy policy)
110    {
111        webkit_cookie_manager_set_accept_policy(m_cookieManager, policy);
112    }
113
114    static void getDomainsReadyCallback(GObject* object, GAsyncResult* result, gpointer userData)
115    {
116        GOwnPtr<GError> error;
117        char** domains = webkit_cookie_manager_get_domains_with_cookies_finish(WEBKIT_COOKIE_MANAGER(object), result, &error.outPtr());
118        g_assert(!error.get());
119
120        CookieManagerTest* test = static_cast<CookieManagerTest*>(userData);
121        test->m_domains = domains;
122        g_main_loop_quit(test->m_mainLoop);
123    }
124
125    char** getDomains()
126    {
127        g_strfreev(m_domains);
128        m_domains = 0;
129        webkit_cookie_manager_get_domains_with_cookies(m_cookieManager, 0, getDomainsReadyCallback, this);
130        g_main_loop_run(m_mainLoop);
131
132        return m_domains;
133    }
134
135    bool hasDomain(const char* domain)
136    {
137        if (!m_domains)
138            return false;
139
140        for (size_t i = 0; m_domains[i]; ++i)
141            if (g_str_equal(m_domains[i], domain))
142                return true;
143        return false;
144    }
145
146    void deleteCookiesForDomain(const char* domain)
147    {
148        webkit_cookie_manager_delete_cookies_for_domain(m_cookieManager, domain);
149    }
150
151    void deleteAllCookies()
152    {
153        webkit_cookie_manager_delete_all_cookies(m_cookieManager);
154    }
155
156    void waitUntilCookiesChanged()
157    {
158        m_cookiesChanged = false;
159        m_finishLoopWhenCookiesChange = true;
160        g_main_loop_run(m_mainLoop);
161        m_finishLoopWhenCookiesChange = false;
162    }
163
164    WebKitCookieManager* m_cookieManager;
165    WebKitCookieAcceptPolicy m_acceptPolicy;
166    char** m_domains;
167    bool m_cookiesChanged;
168    bool m_finishLoopWhenCookiesChange;
169    GOwnPtr<char> m_cookiesTextFile;
170    GOwnPtr<char> m_cookiesSQLiteFile;
171};
172
173static void testCookieManagerAcceptPolicy(CookieManagerTest* test, gconstpointer)
174{
175    // Default policy is NO_THIRD_PARTY.
176    g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
177    test->loadURI(kServer->getURIForPath("/index.html").data());
178    test->waitUntilLoadFinished();
179    char** domains = test->getDomains();
180    g_assert(domains);
181    g_assert_cmpint(g_strv_length(domains), ==, 1);
182    g_assert_cmpstr(domains[0], ==, kFirstPartyDomain);
183    test->deleteAllCookies();
184
185    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
186    g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
187    test->loadURI(kServer->getURIForPath("/index.html").data());
188    test->waitUntilLoadFinished();
189    domains = test->getDomains();
190    g_assert(domains);
191    g_assert_cmpint(g_strv_length(domains), ==, 2);
192    g_assert(test->hasDomain(kFirstPartyDomain));
193    g_assert(test->hasDomain(kThirdPartyDomain));
194    test->deleteAllCookies();
195
196    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_NEVER);
197    g_assert_cmpint(test->getAcceptPolicy(), ==, WEBKIT_COOKIE_POLICY_ACCEPT_NEVER);
198    test->loadURI(kServer->getURIForPath("/index.html").data());
199    test->waitUntilLoadFinished();
200    domains = test->getDomains();
201    g_assert(domains);
202    g_assert_cmpint(g_strv_length(domains), ==, 0);
203}
204
205static void testCookieManagerDeleteCookies(CookieManagerTest* test, gconstpointer)
206{
207    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
208    test->loadURI(kServer->getURIForPath("/index.html").data());
209    test->waitUntilLoadFinished();
210    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
211
212    // Delete first party cookies.
213    test->deleteCookiesForDomain(kFirstPartyDomain);
214    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 1);
215
216    // Delete third party cookies.
217    test->deleteCookiesForDomain(kThirdPartyDomain);
218    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
219
220    test->loadURI(kServer->getURIForPath("/index.html").data());
221    test->waitUntilLoadFinished();
222    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 2);
223
224    // Delete all cookies.
225    test->deleteAllCookies();
226    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
227}
228
229static void testCookieManagerCookiesChanged(CookieManagerTest* test, gconstpointer)
230{
231    g_assert(!test->m_cookiesChanged);
232    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
233    test->loadURI(kServer->getURIForPath("/index.html").data());
234    test->waitUntilLoadFinished();
235    g_assert(test->m_cookiesChanged);
236
237    test->deleteCookiesForDomain(kFirstPartyDomain);
238    test->waitUntilCookiesChanged();
239    g_assert(test->m_cookiesChanged);
240
241    test->deleteAllCookies();
242    test->waitUntilCookiesChanged();
243    g_assert(test->m_cookiesChanged);
244}
245
246static void testCookieManagerPersistentStorage(CookieManagerTest* test, gconstpointer)
247{
248    test->setAcceptPolicy(WEBKIT_COOKIE_POLICY_ACCEPT_ALWAYS);
249
250    // Text storage using a new file.
251    test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
252    char** domains = test->getDomains();
253    g_assert(domains);
254    g_assert_cmpint(g_strv_length(domains), ==, 0);
255
256    test->loadURI(kServer->getURIForPath("/index.html").data());
257    test->waitUntilLoadFinished();
258    g_assert(test->m_cookiesChanged);
259    domains = test->getDomains();
260    g_assert(domains);
261    g_assert_cmpint(g_strv_length(domains), ==, 2);
262
263
264    // SQLite storage using a new file.
265    test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
266    domains = test->getDomains();
267    g_assert(domains);
268    g_assert_cmpint(g_strv_length(domains), ==, 0);
269
270    test->loadURI(kServer->getURIForPath("/index.html").data());
271    test->waitUntilLoadFinished();
272    g_assert(test->m_cookiesChanged);
273    domains = test->getDomains();
274    g_assert(domains);
275    g_assert_cmpint(g_strv_length(domains), ==, 2);
276
277    // Text storage using an existing file.
278    test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
279    domains = test->getDomains();
280    g_assert(domains);
281    g_assert_cmpint(g_strv_length(domains), ==, 2);
282    test->deleteAllCookies();
283    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
284
285    // SQLite storage with an existing file.
286    test->setPersistentStorage(WEBKIT_COOKIE_PERSISTENT_STORAGE_SQLITE);
287    domains = test->getDomains();
288    g_assert(domains);
289    g_assert_cmpint(g_strv_length(domains), ==, 2);
290    test->deleteAllCookies();
291    g_assert_cmpint(g_strv_length(test->getDomains()), ==, 0);
292}
293
294static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer)
295{
296    if (message->method != SOUP_METHOD_GET) {
297        soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED);
298        return;
299    }
300
301    soup_message_set_status(message, SOUP_STATUS_OK);
302    if (g_str_equal(path, "/index.html")) {
303        char* indexHtml = g_strdup_printf(kIndexHtmlFormat, soup_server_get_port(server));
304        soup_message_headers_replace(message->response_headers, "Set-Cookie", "foo=bar; Max-Age=60");
305        soup_message_body_append(message->response_body, SOUP_MEMORY_TAKE, indexHtml, strlen(indexHtml));
306    } else if (g_str_equal(path, "/image.png"))
307        soup_message_headers_replace(message->response_headers, "Set-Cookie", "baz=qux; Max-Age=60");
308    else
309        soup_message_set_status(message, SOUP_STATUS_NOT_FOUND);
310    soup_message_body_complete(message->response_body);
311}
312
313void beforeAll()
314{
315    kServer = new WebKitTestServer();
316    kServer->run(serverCallback);
317
318    kTempDirectory = g_dir_make_tmp("WebKit2Tests-XXXXXX", 0);
319    g_assert(kTempDirectory);
320
321    CookieManagerTest::add("WebKitCookieManager", "accept-policy", testCookieManagerAcceptPolicy);
322    CookieManagerTest::add("WebKitCookieManager", "delete-cookies", testCookieManagerDeleteCookies);
323    CookieManagerTest::add("WebKitCookieManager", "cookies-changed", testCookieManagerCookiesChanged);
324    CookieManagerTest::add("WebKitCookieManager", "persistent-storage", testCookieManagerPersistentStorage);
325}
326
327void afterAll()
328{
329    delete kServer;
330    g_rmdir(kTempDirectory);
331}
332