1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2010 Igalia S.L.
6 #include "test-utils.h"
9 SoupURI *first_party_uri, *third_party_uri;
10 const char *first_party = "http://127.0.0.1/";
11 const char *third_party = "http://localhost/";
14 server_callback (SoupServer *server, SoupMessage *msg,
15 const char *path, GHashTable *query,
16 SoupClientContext *context, gpointer data)
18 if (g_str_equal (path, "/index.html")) {
19 soup_message_headers_replace (msg->response_headers,
22 } else if (g_str_equal (path, "/foo.jpg")) {
23 soup_message_headers_replace (msg->response_headers,
26 } else if (soup_message_headers_get_one (msg->request_headers,
28 soup_message_headers_replace (msg->response_headers,
30 soup_message_headers_get_one (msg->request_headers,
34 soup_message_set_status (msg, SOUP_STATUS_OK);
38 SoupCookieJarAcceptPolicy policy;
39 gboolean try_third_party_again;
43 static const CookiesForPolicy validResults[] = {
44 { SOUP_COOKIE_JAR_ACCEPT_ALWAYS, FALSE, 2 },
45 { SOUP_COOKIE_JAR_ACCEPT_NEVER, FALSE, 0 },
46 { SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY, FALSE, 1 },
47 { SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, FALSE, 1 },
48 { SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY, TRUE, 2 }
52 do_cookies_accept_policy_test (void)
61 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
62 soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
63 jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
65 for (i = 0; i < G_N_ELEMENTS (validResults); i++) {
66 soup_cookie_jar_set_accept_policy (jar, validResults[i].policy);
68 /* We can't use two servers due to limitations in
69 * test_server, so let's swap first and third party here
70 * to simulate a cookie coming from a third party.
72 uri = soup_uri_new_with_base (first_party_uri, "/foo.jpg");
73 msg = soup_message_new_from_uri ("GET", uri);
74 soup_message_set_first_party (msg, third_party_uri);
75 soup_session_send_message (session, msg);
79 uri = soup_uri_new_with_base (first_party_uri, "/index.html");
80 msg = soup_message_new_from_uri ("GET", uri);
81 soup_message_set_first_party (msg, first_party_uri);
82 soup_session_send_message (session, msg);
86 if (validResults[i].try_third_party_again) {
87 uri = soup_uri_new_with_base (first_party_uri, "/foo.jpg");
88 msg = soup_message_new_from_uri ("GET", uri);
89 soup_message_set_first_party (msg, third_party_uri);
90 soup_session_send_message (session, msg);
95 l = soup_cookie_jar_all_cookies (jar);
96 g_assert_cmpint (g_slist_length (l), ==, validResults[i].n_cookies);
98 for (p = l; p; p = p->next) {
99 soup_cookie_jar_delete_cookie (jar, p->data);
100 soup_cookie_free (p->data);
106 soup_test_session_abort_unref (session);
110 do_cookies_subdomain_policy_test (void)
118 g_test_bug ("792130");
120 /* Only the base domain should be considered when deciding
121 * whether a cookie is a third-party cookie.
123 uri1 = soup_uri_new ("https://www.gnome.org");
124 uri2 = soup_uri_new ("https://foundation.gnome.org");
125 uri3 = soup_uri_new ("https://www.gnome.org.");
127 /* We can't check subdomains with a test server running on
128 * localhost, so we'll just check the cookie jar API itself.
131 /* Cookie should be accepted. One cookie in the jar. */
132 jar = soup_cookie_jar_new ();
133 soup_cookie_jar_set_accept_policy (jar, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY);
134 soup_cookie_jar_set_cookie_with_first_party (jar, uri1, uri2, "1=foo");
135 cookies = soup_cookie_jar_all_cookies (jar);
136 g_assert_cmpint (g_slist_length (cookies), ==, 1);
137 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
139 /* Cookie should be accepted. Two cookies in the jar. */
140 soup_cookie_jar_set_cookie_with_first_party (jar, uri2, uri1, "2=foo");
141 cookies = soup_cookie_jar_all_cookies (jar);
142 g_assert_cmpint (g_slist_length (cookies), ==, 2);
143 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
145 /* Third-party cookie should be rejected, so there are still
146 * only two cookies in the jar.
148 soup_cookie_jar_set_cookie_with_first_party (jar, third_party_uri, uri1, "3=foo");
149 cookies = soup_cookie_jar_all_cookies (jar);
150 g_assert_cmpint (g_slist_length (cookies), ==, 2);
151 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
153 /* Now, we allow the "third-party" to set one cookie as the
154 * first party. Three cookies in the jar.
156 soup_cookie_jar_set_cookie_with_first_party (jar, third_party_uri, third_party_uri, "4=foo");
157 cookies = soup_cookie_jar_all_cookies (jar);
158 g_assert_cmpint (g_slist_length (cookies), ==, 3);
159 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
161 /* Third-party cookie should now be allowed by grandfathering, though
162 * it was blocked before on the same URL. Four cookies in the jar.
164 soup_cookie_jar_set_accept_policy (jar, SOUP_COOKIE_JAR_ACCEPT_GRANDFATHERED_THIRD_PARTY);
165 soup_cookie_jar_set_cookie_with_first_party (jar, third_party_uri, uri1, "5=foo");
166 cookies = soup_cookie_jar_all_cookies (jar);
167 g_assert_cmpint (g_slist_length (cookies), ==, 4);
168 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
170 /* Now some Domain attribute tests.*/
171 soup_cookie_jar_set_accept_policy (jar, SOUP_COOKIE_JAR_ACCEPT_ALWAYS);
173 /* The cookie must be rejected if the Domain is not an appropriate
174 * match for the URI. Still four cookies in the jar.
176 soup_cookie_jar_set_cookie (jar, uri1, "6=foo; Domain=gitlab.gnome.org");
177 cookies = soup_cookie_jar_all_cookies (jar);
178 g_assert_cmpint (g_slist_length (cookies), ==, 4);
179 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
181 /* Now the Domain is an appropriate match. Five cookies in the jar. */
182 soup_cookie_jar_set_cookie (jar, uri1, "7=foo; Domain=gnome.org");
183 cookies = soup_cookie_jar_all_cookies (jar);
184 g_assert_cmpint (g_slist_length (cookies), ==, 5);
185 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
187 /* A leading dot in the domain property should not affect things.
188 * This cookie should be accepted. Six cookies in the jar.
190 soup_cookie_jar_set_cookie (jar, uri1, "8=foo; Domain=.www.gnome.org");
191 cookies = soup_cookie_jar_all_cookies (jar);
192 g_assert_cmpint (g_slist_length (cookies), ==, 6);
193 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
195 /* The cookie must be rejected if the Domain ends in a trailing dot
196 * but the uri doesn't.
198 soup_cookie_jar_set_cookie (jar, uri1, "9=foo; Domain=www.gnome.org.");
199 cookies = soup_cookie_jar_all_cookies (jar);
200 g_assert_cmpint (g_slist_length (cookies), ==, 6);
201 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
203 /* The cookie should be accepted if both Domain and URI end with a trailing
204 * dot and they are a match. Seven cookies in the jar.
206 soup_cookie_jar_set_cookie (jar, uri3, "10=foo; Domain=gnome.org.");
207 cookies = soup_cookie_jar_all_cookies (jar);
208 g_assert_cmpint (g_slist_length (cookies), ==, 7);
209 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
211 /* The cookie should be rejected if URI has trailing dot but Domain doesn't.
212 * Seven cookies in the jar.
214 soup_cookie_jar_set_cookie (jar, uri3, "11=foo; Domain=gnome.org");
215 cookies = soup_cookie_jar_all_cookies (jar);
216 g_assert_cmpint (g_slist_length (cookies), ==, 7);
217 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
219 /* It should not be possible to set a cookie for a TLD. Still seven
220 * cookies in the jar.
222 soup_cookie_jar_set_cookie (jar, uri1, "12=foo; Domain=.org");
223 cookies = soup_cookie_jar_all_cookies (jar);
224 g_assert_cmpint (g_slist_length (cookies), ==, 7);
225 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
227 /* It should still not be possible to set a cookie for a TLD, even if
228 * we are tricksy and have a trailing dot. Still only seven cookies.
230 soup_cookie_jar_set_cookie (jar, uri3, "13=foo; Domain=.org.");
231 cookies = soup_cookie_jar_all_cookies (jar);
232 g_assert_cmpint (g_slist_length (cookies), ==, 7);
233 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
235 soup_uri_free (uri1);
236 soup_uri_free (uri2);
237 soup_uri_free (uri3);
238 g_object_unref (jar);
242 do_cookies_strict_secure_test (void)
246 SoupURI *insecure_uri;
249 insecure_uri = soup_uri_new ("http://gnome.org");
250 secure_uri = soup_uri_new ("https://gnome.org");
251 jar = soup_cookie_jar_new ();
253 /* Set a cookie from secure origin */
254 soup_cookie_jar_set_cookie (jar, secure_uri, "1=foo; secure");
255 cookies = soup_cookie_jar_all_cookies (jar);
256 g_assert_cmpint (g_slist_length (cookies), ==, 1);
257 g_assert_cmpstr (soup_cookie_get_value(cookies->data), ==, "foo");
258 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
260 /* Do not allow an insecure origin to overwrite a secure cookie */
261 soup_cookie_jar_set_cookie (jar, insecure_uri, "1=bar");
262 cookies = soup_cookie_jar_all_cookies (jar);
263 g_assert_cmpint (g_slist_length (cookies), ==, 1);
264 g_assert_cmpstr (soup_cookie_get_value(cookies->data), ==, "foo");
265 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
267 /* Secure can only be set by from secure origin */
268 soup_cookie_jar_set_cookie (jar, insecure_uri, "2=foo; secure");
269 cookies = soup_cookie_jar_all_cookies (jar);
270 g_assert_cmpint (g_slist_length (cookies), ==, 1);
271 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
273 /* But we can make one for another path */
274 soup_cookie_jar_set_cookie (jar, insecure_uri, "1=foo; path=/foo");
275 cookies = soup_cookie_jar_all_cookies (jar);
276 g_assert_cmpint (g_slist_length (cookies), ==, 2);
277 g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
279 soup_uri_free (insecure_uri);
280 soup_uri_free (secure_uri);
281 g_object_unref (jar);
284 /* FIXME: moar tests! */
286 do_cookies_parsing_test (void)
288 SoupSession *session;
291 GSList *cookies, *iter;
293 gboolean got1, got2, got3;
295 g_test_bug ("678753");
297 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
298 soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
299 jar = SOUP_COOKIE_JAR (soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR));
301 /* "httponly" is case-insensitive, and its value (if any) is ignored */
302 msg = soup_message_new_from_uri ("GET", first_party_uri);
303 soup_message_headers_append (msg->request_headers, "Echo-Set-Cookie",
304 "one=1; httponly; max-age=100");
305 soup_session_send_message (session, msg);
306 g_object_unref (msg);
308 msg = soup_message_new_from_uri ("GET", first_party_uri);
309 soup_message_headers_append (msg->request_headers, "Echo-Set-Cookie",
310 "two=2; HttpOnly; max-age=100; SameSite=Invalid");
311 soup_session_send_message (session, msg);
312 g_object_unref (msg);
314 msg = soup_message_new_from_uri ("GET", first_party_uri);
315 soup_message_headers_append (msg->request_headers, "Echo-Set-Cookie",
316 "three=3; httpONLY=Wednesday; max-age=100; SameSite=Lax");
317 soup_session_send_message (session, msg);
318 g_object_unref (msg);
320 cookies = soup_cookie_jar_get_cookie_list (jar, first_party_uri, TRUE);
321 got1 = got2 = got3 = FALSE;
323 for (iter = cookies; iter; iter = iter->next) {
326 if (!strcmp (soup_cookie_get_name (cookie), "one")) {
328 g_assert_true (soup_cookie_get_http_only (cookie));
329 g_assert_true (soup_cookie_get_expires (cookie) != NULL);
330 } else if (!strcmp (soup_cookie_get_name (cookie), "two")) {
332 g_assert_true (soup_cookie_get_http_only (cookie));
333 g_assert_true (soup_cookie_get_expires (cookie) != NULL);
334 g_assert_cmpint (soup_cookie_get_same_site_policy (cookie), ==, SOUP_SAME_SITE_POLICY_NONE);
335 } else if (!strcmp (soup_cookie_get_name (cookie), "three")) {
337 g_assert_true (soup_cookie_get_http_only (cookie));
338 g_assert_true (soup_cookie_get_expires (cookie) != NULL);
339 g_assert_cmpint (soup_cookie_get_same_site_policy (cookie), ==, SOUP_SAME_SITE_POLICY_LAX);
341 soup_test_assert (FALSE, "got unexpected cookie '%s'",
342 soup_cookie_get_name (cookie));
345 soup_cookie_free (cookie);
347 g_slist_free (cookies);
349 g_assert_true (got1);
350 g_assert_true (got2);
351 g_assert_true (got3);
353 soup_test_session_abort_unref (session);
357 do_cookies_parsing_nopath_nullorigin (void)
359 SoupCookie *cookie = soup_cookie_parse ("NAME=Value", NULL);
360 g_assert_nonnull (cookie);
361 g_assert_cmpstr ("/", ==, soup_cookie_get_path (cookie));
362 soup_cookie_free (cookie);
366 do_get_cookies_empty_host_test (void)
372 jar = soup_cookie_jar_new ();
373 uri = soup_uri_new ("file:///whatever.html");
375 cookies = soup_cookie_jar_get_cookies (jar, uri, FALSE);
377 g_assert_null (cookies);
379 g_object_unref (jar);
384 send_callback (GObject *source_object,
388 g_main_loop_quit (loop);
392 do_remove_feature_test (void)
394 SoupSession *session;
399 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
400 soup_session_add_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
401 uri = soup_uri_new_with_base (first_party_uri, "/index.html");
402 msg = soup_message_new_from_uri ("GET", uri);
403 soup_message_set_first_party (msg, first_party_uri);
405 loop = g_main_loop_new (NULL, TRUE);
406 soup_session_send_async (session, msg, NULL, (GAsyncReadyCallback)send_callback, loop);
407 soup_session_remove_feature_by_type (session, SOUP_TYPE_COOKIE_JAR);
409 g_main_loop_run(loop);
411 g_main_loop_unref (loop);
412 g_object_unref (msg);
417 main (int argc, char **argv)
422 test_init (argc, argv, NULL);
424 server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
425 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
426 server_uri = soup_test_server_get_uri (server, "http", NULL);
428 first_party_uri = soup_uri_new (first_party);
429 third_party_uri = soup_uri_new (third_party);
430 soup_uri_set_port (first_party_uri, server_uri->port);
431 soup_uri_set_port (third_party_uri, server_uri->port);
433 g_test_add_func ("/cookies/accept-policy", do_cookies_accept_policy_test);
434 g_test_add_func ("/cookies/accept-policy-subdomains", do_cookies_subdomain_policy_test);
435 g_test_add_func ("/cookies/parsing", do_cookies_parsing_test);
436 g_test_add_func ("/cookies/parsing/no-path-null-origin", do_cookies_parsing_nopath_nullorigin);
437 g_test_add_func ("/cookies/get-cookies/empty-host", do_get_cookies_empty_host_test);
438 g_test_add_func ("/cookies/remove-feature", do_remove_feature_test);
439 g_test_add_func ("/cookies/secure-cookies", do_cookies_strict_secure_test);
443 soup_uri_free (first_party_uri);
444 soup_uri_free (third_party_uri);
445 soup_uri_free (server_uri);
446 soup_test_server_quit_unref (server);