1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2018 Igalia S.L.
4 * Copyright (C) 2018 Metrological Group B.V.
5 */
6
7 #include "test-utils.h"
8 #include "soup-uri-utils-private.h"
9
10 GUri *http_uri;
11 GUri *https_uri;
12
13 /* This server pseudo-implements the HSTS spec in order to allow us to
14 test the Soup HSTS feature.
15 */
16 static void
server_callback(SoupServer * server,SoupServerMessage * msg,const char * path,GHashTable * query,gpointer data)17 server_callback (SoupServer *server,
18 SoupServerMessage *msg,
19 const char *path,
20 GHashTable *query,
21 gpointer data)
22 {
23 SoupMessageHeaders *response_headers;
24 const char *server_protocol = data;
25
26 response_headers = soup_server_message_get_response_headers (msg);
27
28 if (strcmp (server_protocol, "http") == 0) {
29 if (strcmp (path, "/insecure") == 0) {
30 soup_message_headers_append (response_headers,
31 "Strict-Transport-Security",
32 "max-age=31536000");
33 soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
34 } else {
35 GUri *uri = g_uri_build (SOUP_HTTP_URI_FLAGS, "https", NULL, "localhost", -1, path, NULL, NULL);
36 char *uri_string = g_uri_to_string (uri);
37 soup_server_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, uri_string);
38 g_uri_unref (uri);
39 g_free (uri_string);
40 }
41 } else if (strcmp (server_protocol, "https") == 0) {
42 soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
43 if (strcmp (path, "/long-lasting") == 0) {
44 soup_message_headers_append (response_headers,
45 "Strict-Transport-Security",
46 "max-age=31536000");
47 } else if (strcmp (path, "/two-seconds") == 0) {
48 soup_message_headers_append (response_headers,
49 "Strict-Transport-Security",
50 "max-age=2");
51 } else if (strcmp (path, "/three-seconds") == 0) {
52 soup_message_headers_append (response_headers,
53 "Strict-Transport-Security",
54 "max-age=3");
55 } else if (strcmp (path, "/delete") == 0) {
56 soup_message_headers_append (response_headers,
57 "Strict-Transport-Security",
58 "max-age=0");
59 } else if (strcmp (path, "/subdomains") == 0) {
60 soup_message_headers_append (response_headers,
61 "Strict-Transport-Security",
62 "max-age=31536000; includeSubDomains");
63 } else if (strcmp (path, "/no-sts-header") == 0) {
64 /* Do not add anything */
65 } else if (strcmp (path, "/multiple-headers") == 0) {
66 soup_message_headers_append (response_headers,
67 "Strict-Transport-Security",
68 "max-age=31536000; includeSubDomains");
69 soup_message_headers_append (response_headers,
70 "Strict-Transport-Security",
71 "max-age=1; includeSubDomains");
72 } else if (strcmp (path, "/missing-values") == 0) {
73 soup_message_headers_append (response_headers,
74 "Strict-Transport-Security",
75 "");
76 } else if (strcmp (path, "/invalid-values") == 0) {
77 soup_message_headers_append (response_headers,
78 "Strict-Transport-Security",
79 "max-age=foo");
80 } else if (strcmp (path, "/extra-values-0") == 0) {
81 soup_message_headers_append (response_headers,
82 "Strict-Transport-Security",
83 "max-age=3600; foo");
84 } else if (strcmp (path, "/extra-values-1") == 0) {
85 soup_message_headers_append (response_headers,
86 "Strict-Transport-Security",
87 " max-age=3600; includeDomains; foo");
88 } else if (strcmp (path, "/duplicated-directives") == 0) {
89 soup_message_headers_append (response_headers,
90 "Strict-Transport-Security",
91 "max-age=3600; includeDomains; includeDomains");
92 } else if (strcmp (path, "/case-insensitive-header") == 0) {
93 soup_message_headers_append (response_headers,
94 "STRICT-TRANSPORT-SECURITY",
95 "max-age=3600");
96 } else if (strcmp (path, "/case-insensitive-directives") == 0) {
97 soup_message_headers_append (response_headers,
98 "Strict-Transport-Security",
99 "MAX-AGE=3600; includesubdomains");
100 } else if (strcmp (path, "/optional-quotations") == 0) {
101 soup_message_headers_append (response_headers,
102 "Strict-Transport-Security",
103 "max-age=\"31536000\"");
104 }
105 }
106 }
107
108 static void
hsts_enforced_cb(SoupMessage * msg,gboolean * enforced)109 hsts_enforced_cb (SoupMessage *msg,
110 gboolean *enforced)
111 {
112 *enforced = TRUE;
113 }
114
115 static void
session_get_uri(SoupSession * session,const char * uri,SoupStatus expected_status,gboolean expected_enforced)116 session_get_uri (SoupSession *session,
117 const char *uri,
118 SoupStatus expected_status,
119 gboolean expected_enforced)
120 {
121 SoupMessage *msg;
122 GBytes *body;
123 GError *error = NULL;
124 gboolean enforced = FALSE;
125
126 msg = soup_message_new ("GET", uri);
127 g_signal_connect (msg, "hsts-enforced", G_CALLBACK (hsts_enforced_cb), &enforced);
128 soup_message_add_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
129 body = soup_session_send_and_read (session, msg, NULL, &error);
130 if (expected_status == SOUP_STATUS_NONE)
131 g_assert_error (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE);
132 else
133 g_assert_no_error (error);
134 soup_test_assert_message_status (msg, expected_status);
135 g_assert (enforced == expected_enforced);
136 g_clear_error (&error);
137 g_bytes_unref (body);
138 g_object_unref (msg);
139 }
140
141 /* The HSTS specification does not handle custom ports, so we need to
142 * rewrite the URI in the request and add the port where the server is
143 * listening before it is sent, to be able to connect to the localhost
144 * port where the server is actually running.
145 */
146 static void
rewrite_message_uri(SoupMessage * msg)147 rewrite_message_uri (SoupMessage *msg)
148 {
149 GUri *new_uri;
150 if (soup_uri_is_http (soup_message_get_uri (msg)))
151 new_uri = soup_uri_copy (soup_message_get_uri (msg), SOUP_URI_PORT, g_uri_get_port (http_uri), SOUP_URI_NONE);
152 else if (soup_uri_is_https (soup_message_get_uri (msg)))
153 new_uri = soup_uri_copy (soup_message_get_uri (msg), SOUP_URI_PORT, g_uri_get_port (https_uri), SOUP_URI_NONE);
154 else
155 g_assert_not_reached();
156 soup_message_set_uri (msg, new_uri);
157 g_uri_unref (new_uri);
158 }
159
160 static void
on_message_restarted(SoupMessage * msg,gpointer data)161 on_message_restarted (SoupMessage *msg,
162 gpointer data)
163 {
164 rewrite_message_uri (msg);
165 }
166
167 static void
on_request_queued(SoupSession * session,SoupMessage * msg,gpointer data)168 on_request_queued (SoupSession *session,
169 SoupMessage *msg,
170 gpointer data)
171 {
172 g_signal_connect (msg, "restarted", G_CALLBACK (on_message_restarted), NULL);
173
174 rewrite_message_uri (msg);
175 }
176
177 static SoupSession *
hsts_session_new(SoupHSTSEnforcer * enforcer)178 hsts_session_new (SoupHSTSEnforcer *enforcer)
179 {
180 SoupSession *session = soup_test_session_new (NULL);
181
182 if (enforcer)
183 soup_session_add_feature (session, SOUP_SESSION_FEATURE (enforcer));
184 else
185 soup_session_add_feature_by_type (session, SOUP_TYPE_HSTS_ENFORCER);
186
187 g_signal_connect (session, "request-queued", G_CALLBACK (on_request_queued), NULL);
188
189 return session;
190 }
191
192
193 static void
do_hsts_basic_test(void)194 do_hsts_basic_test (void)
195 {
196 SoupSession *session = hsts_session_new (NULL);
197
198 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
199 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
200 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
201
202 /* The HSTS headers in the url above doesn't include
203 subdomains, so the request should ask for the unchanged
204 HTTP address below, to which the server will respond with a
205 moved permanently status. */
206 session_get_uri (session, "http://subdomain.localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
207
208 soup_test_session_abort_unref (session);
209 }
210
211 static void
do_hsts_expire_test(void)212 do_hsts_expire_test (void)
213 {
214 SoupSession *session = hsts_session_new (NULL);
215
216 session_get_uri (session, "https://localhost/two-seconds", SOUP_STATUS_OK, FALSE);
217 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
218 /* Wait for the policy to expire. */
219 g_usleep (3 * G_USEC_PER_SEC);
220 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
221
222 soup_test_session_abort_unref (session);
223 }
224
225 static void
do_hsts_delete_test(void)226 do_hsts_delete_test (void)
227 {
228 SoupSession *session = hsts_session_new (NULL);
229
230 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
231 session_get_uri (session, "https://localhost/delete", SOUP_STATUS_OK, FALSE);
232 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
233
234 soup_test_session_abort_unref (session);
235 }
236
237 static void
do_hsts_replace_test(void)238 do_hsts_replace_test (void)
239 {
240 SoupSession *session = hsts_session_new (NULL);
241 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
242 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
243 session_get_uri (session, "https://localhost/two-seconds", SOUP_STATUS_OK, FALSE);
244 /* Wait for the policy to expire. */
245 g_usleep (3 * G_USEC_PER_SEC);
246 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
247
248 soup_test_session_abort_unref (session);
249 }
250
251 static void
do_hsts_update_test(void)252 do_hsts_update_test (void)
253 {
254 SoupSession *session = hsts_session_new (NULL);
255 session_get_uri (session, "https://localhost/three-seconds", SOUP_STATUS_OK, FALSE);
256 g_usleep (2 * G_USEC_PER_SEC);
257 session_get_uri (session, "https://localhost/three-seconds", SOUP_STATUS_OK, FALSE);
258 g_usleep (2 * G_USEC_PER_SEC);
259
260 /* At this point, 4 seconds have elapsed since setting the 3 seconds HSTS
261 rule for the first time, and it should have expired by now, but since it
262 was updated, it should still be valid. */
263 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
264 soup_test_session_abort_unref (session);
265 }
266
267 static void
do_hsts_set_and_delete_test(void)268 do_hsts_set_and_delete_test (void)
269 {
270 SoupSession *session = hsts_session_new (NULL);
271 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
272 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
273 session_get_uri (session, "https://localhost/delete", SOUP_STATUS_OK, FALSE);
274 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
275
276 soup_test_session_abort_unref (session);
277 }
278
279 static void
do_hsts_no_hsts_header_test(void)280 do_hsts_no_hsts_header_test (void)
281 {
282 SoupSession *session = hsts_session_new (NULL);
283 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
284 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
285 session_get_uri (session, "https://localhost/no-sts-header", SOUP_STATUS_OK, FALSE);
286 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
287
288 soup_test_session_abort_unref (session);
289 }
290
291 static void
do_hsts_persistency_test(void)292 do_hsts_persistency_test (void)
293 {
294 SoupSession *session = hsts_session_new (NULL);
295 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
296 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
297 soup_test_session_abort_unref (session);
298
299 session = hsts_session_new (NULL);
300 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
301 soup_test_session_abort_unref (session);
302 }
303
304 static void
do_hsts_subdomains_test(void)305 do_hsts_subdomains_test (void)
306 {
307 SoupSession *session = hsts_session_new (NULL);
308 session_get_uri (session, "https://localhost/subdomains", SOUP_STATUS_OK, FALSE);
309 /* The enforcer should cause the request to ask for an HTTPS
310 uri, which will fail with an SSL error as there's no server
311 in subdomain.localhost. */
312 session_get_uri (session, "http://subdomain.localhost", SOUP_STATUS_NONE, TRUE);
313 soup_test_session_abort_unref (session);
314 }
315
316 static void
do_hsts_superdomain_test(void)317 do_hsts_superdomain_test (void)
318 {
319 SoupHSTSEnforcer *enforcer = soup_hsts_enforcer_new ();
320 SoupHSTSPolicy *policy;
321
322 SoupSession *session = hsts_session_new (enforcer);
323 /* This adds a long-lasting policy for localhost. */
324 session_get_uri (session, "https://localhost/long-lasting", SOUP_STATUS_OK, FALSE);
325
326 /* We want to set a policy with age = 0 for a subdomain, to test that the
327 superdomain's policy is not removed. We cannot test this with a
328 server, so we just create one by hand and add it to the enforcer. */
329 policy = soup_hsts_policy_new ("subdomain.localhost", 0, TRUE);
330 soup_hsts_enforcer_set_policy (enforcer, policy);
331 soup_hsts_policy_free (policy);
332
333 /* This should work, as we have a long-lasting policy in place. If it fails,
334 the subdomain policy has modified the superdomain's policy, which is wrong. */
335 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
336 g_object_unref (enforcer);
337 }
338
339 static void
do_hsts_multiple_headers_test(void)340 do_hsts_multiple_headers_test (void)
341 {
342 SoupSession *session = hsts_session_new (NULL);
343 session_get_uri (session, "https://localhost/multiple-headers", SOUP_STATUS_OK, FALSE);
344 g_usleep(2 * G_USEC_PER_SEC);
345 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
346 soup_test_session_abort_unref (session);
347 }
348
349 static void
do_hsts_insecure_sts_test(void)350 do_hsts_insecure_sts_test (void)
351 {
352 SoupSession *session = hsts_session_new (NULL);
353 session_get_uri (session, "http://localhost/insecure", SOUP_STATUS_OK, FALSE);
354 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
355 soup_test_session_abort_unref (session);
356 }
357
358 static void
do_hsts_missing_values_test(void)359 do_hsts_missing_values_test (void)
360 {
361 SoupSession *session = hsts_session_new (NULL);
362 session_get_uri (session, "https://localhost/missing-values", SOUP_STATUS_OK, FALSE);
363 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
364 soup_test_session_abort_unref (session);
365 }
366
367 static void
do_hsts_invalid_values_test(void)368 do_hsts_invalid_values_test (void)
369 {
370 SoupSession *session = hsts_session_new (NULL);
371 session_get_uri (session, "https://localhost/invalid-values", SOUP_STATUS_OK, FALSE);
372 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
373 soup_test_session_abort_unref (session);
374 }
375
376 static void
do_hsts_extra_values_test(void)377 do_hsts_extra_values_test (void)
378 {
379 int i;
380 for (i = 0; i < 2; i++) {
381 SoupSession *session = hsts_session_new (NULL);
382 char *uri = g_strdup_printf ("https://localhost/extra-values-%i", i);
383 session_get_uri (session, uri, SOUP_STATUS_OK, FALSE);
384 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
385 soup_test_session_abort_unref (session);
386 g_free (uri);
387 }
388 }
389
390 static void
do_hsts_duplicated_directives_test(void)391 do_hsts_duplicated_directives_test (void)
392 {
393 SoupSession *session = hsts_session_new (NULL);
394 session_get_uri (session, "https://localhost/duplicated-directives", SOUP_STATUS_OK, FALSE);
395 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
396 soup_test_session_abort_unref (session);
397 }
398
399 static void
do_hsts_case_insensitive_header_test(void)400 do_hsts_case_insensitive_header_test (void)
401 {
402 SoupSession *session = hsts_session_new (NULL);
403 session_get_uri (session, "https://localhost/case-insensitive-header", SOUP_STATUS_OK, FALSE);
404 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
405 soup_test_session_abort_unref (session);
406 }
407
408 static void
do_hsts_case_insensitive_directives_test(void)409 do_hsts_case_insensitive_directives_test (void)
410 {
411 SoupSession *session = hsts_session_new (NULL);
412 session_get_uri (session, "https://localhost/case-insensitive-directives", SOUP_STATUS_OK, FALSE);
413 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
414 soup_test_session_abort_unref (session);
415 }
416
417 static void
do_hsts_optional_quotations_test(void)418 do_hsts_optional_quotations_test (void)
419 {
420 SoupSession *session = hsts_session_new (NULL);
421
422 session_get_uri (session, "https://localhost/optional-quotations", SOUP_STATUS_OK, FALSE);
423 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
424
425 soup_test_session_abort_unref (session);
426 }
427
428 static void
do_hsts_ip_address_test(void)429 do_hsts_ip_address_test (void)
430 {
431 SoupSession *session = hsts_session_new (NULL);
432 session_get_uri (session, "https://127.0.0.1/basic", SOUP_STATUS_OK, FALSE);
433 session_get_uri (session, "http://127.0.0.1/", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
434 soup_test_session_abort_unref (session);
435 }
436
437 static void
do_hsts_utf8_address_test(void)438 do_hsts_utf8_address_test (void)
439 {
440 SoupSession *session = hsts_session_new (NULL);
441 session_get_uri (session, "https://localhost/subdomains", SOUP_STATUS_OK, FALSE);
442 /* The enforcer should cause the request to ask for an HTTPS
443 uri, which will fail with an SSL error as there's no server
444 in 食狮.中国.localhost. */
445 session_get_uri (session, "http://食狮.中国.localhost", SOUP_STATUS_NONE, TRUE);
446 soup_test_session_abort_unref (session);
447 }
448
449 static void
do_hsts_session_policy_test(void)450 do_hsts_session_policy_test (void)
451 {
452 SoupHSTSEnforcer *enforcer = soup_hsts_enforcer_new ();
453 SoupSession *session = hsts_session_new (enforcer);
454
455 session_get_uri (session, "http://localhost", SOUP_STATUS_MOVED_PERMANENTLY, FALSE);
456 soup_hsts_enforcer_set_session_policy (enforcer, "localhost", FALSE);
457 session_get_uri (session, "http://localhost", SOUP_STATUS_OK, TRUE);
458
459 soup_test_session_abort_unref (session);
460 g_object_unref (enforcer);
461 }
462
463 static void
on_idna_test_enforcer_changed(SoupHSTSEnforcer * enforcer,SoupHSTSPolicy * old,SoupHSTSPolicy * new,gpointer data)464 on_idna_test_enforcer_changed (SoupHSTSEnforcer *enforcer, SoupHSTSPolicy *old, SoupHSTSPolicy *new, gpointer data)
465 {
466 /* If NULL, then instead of replacing we're adding a new
467 * policy and somewhere we're failing to canonicalize a hostname. */
468 g_assert_nonnull (old);
469 g_assert_cmpstr (soup_hsts_policy_get_domain (old), ==, soup_hsts_policy_get_domain (new));
470 /* Domains should not have punycoded segments at this point. */
471 g_assert_false (g_hostname_is_ascii_encoded (soup_hsts_policy_get_domain (old)));
472 }
473
474 static void
do_hsts_idna_addresses_test(void)475 do_hsts_idna_addresses_test (void)
476 {
477 SoupHSTSEnforcer *enforcer = soup_hsts_enforcer_new ();
478
479 soup_hsts_enforcer_set_session_policy (enforcer, "áéí.com", FALSE);
480 soup_hsts_enforcer_set_session_policy (enforcer, "xn--6scagyk0fc4c.in", FALSE);
481
482 g_assert_true (soup_hsts_enforcer_has_valid_policy (enforcer, "xn--1caqm.com"));
483
484 g_signal_connect (enforcer, "changed", G_CALLBACK (on_idna_test_enforcer_changed), NULL);
485
486 soup_hsts_enforcer_set_session_policy (enforcer, "xn--1caqm.com", TRUE);
487 soup_hsts_enforcer_set_session_policy (enforcer, "ನೆನಪಿರಲಿ.in", TRUE);
488
489 g_object_unref (enforcer);
490 }
491
492 static void
do_hsts_get_domains_test(void)493 do_hsts_get_domains_test (void)
494 {
495 SoupHSTSEnforcer *enforcer = soup_hsts_enforcer_new ();
496 SoupHSTSPolicy *policy;
497 GList* domains;
498
499 g_assert_null (soup_hsts_enforcer_get_domains (enforcer, TRUE));
500 g_assert_null (soup_hsts_enforcer_get_domains (enforcer, FALSE));
501
502 policy = soup_hsts_policy_new ("gnome.org", 3600, FALSE);
503 g_assert_nonnull (policy);
504 soup_hsts_enforcer_set_policy (enforcer, policy);
505 soup_hsts_policy_free (policy);
506
507 policy = soup_hsts_policy_new_session_policy ("freedesktop.org", FALSE);
508 g_assert_nonnull (policy);
509 soup_hsts_enforcer_set_policy (enforcer, policy);
510 soup_hsts_policy_free (policy);
511
512 domains = soup_hsts_enforcer_get_domains (enforcer, TRUE);
513 g_assert_nonnull (domains);
514 g_assert_cmpint (g_list_length (domains), ==, 2);
515 g_list_free_full (domains, (GDestroyNotify)g_free);
516
517 domains = soup_hsts_enforcer_get_domains (enforcer, FALSE);
518 g_assert_nonnull (domains);
519 g_assert_cmpint (g_list_length (domains), ==, 1);
520 g_assert_cmpstr ((char*)domains->data, ==, "gnome.org");
521 g_list_free_full (domains, (GDestroyNotify)g_free);
522
523 policy = soup_hsts_policy_new ("gnome.org", SOUP_HSTS_POLICY_MAX_AGE_PAST, FALSE);
524 soup_hsts_enforcer_set_policy (enforcer, policy);
525 soup_hsts_policy_free (policy);
526
527 domains = soup_hsts_enforcer_get_domains (enforcer, TRUE);
528 g_assert_cmpint (g_list_length (domains), ==, 1);
529 g_assert_cmpstr ((char*)domains->data, ==, "freedesktop.org");
530 g_list_free_full (domains, g_free);
531 g_object_unref (enforcer);
532 }
533
534 static void
do_hsts_get_policies_test(void)535 do_hsts_get_policies_test (void)
536 {
537 SoupHSTSEnforcer *enforcer = soup_hsts_enforcer_new ();
538 SoupHSTSPolicy *policy;
539 GList* policies;
540
541 g_assert_null (soup_hsts_enforcer_get_policies (enforcer, TRUE));
542 g_assert_null (soup_hsts_enforcer_get_policies (enforcer, FALSE));
543
544 policy = soup_hsts_policy_new ("gnome.org", 3600, FALSE);
545 g_assert_nonnull (policy);
546 soup_hsts_enforcer_set_policy (enforcer, policy);
547 soup_hsts_policy_free (policy);
548
549 policy = soup_hsts_policy_new_session_policy ("freedesktop.org", FALSE);
550 g_assert_nonnull (policy);
551 soup_hsts_enforcer_set_policy (enforcer, policy);
552 soup_hsts_policy_free (policy);
553
554 policies = soup_hsts_enforcer_get_policies (enforcer, TRUE);
555 g_assert_nonnull (policies);
556 g_assert_cmpint (g_list_length (policies), ==, 2);
557 g_list_free_full (policies, (GDestroyNotify)soup_hsts_policy_free);
558
559 policies = soup_hsts_enforcer_get_policies (enforcer, FALSE);
560 g_assert_nonnull (policies);
561 g_assert_cmpint (g_list_length (policies), ==, 1);
562 policy = (SoupHSTSPolicy*)policies->data;
563 g_assert_cmpstr (soup_hsts_policy_get_domain (policy), ==, "gnome.org");
564 g_list_free_full (policies, (GDestroyNotify)soup_hsts_policy_free);
565
566 policy = soup_hsts_policy_new ("gnome.org", SOUP_HSTS_POLICY_MAX_AGE_PAST, FALSE);
567 soup_hsts_enforcer_set_policy (enforcer, policy);
568 soup_hsts_policy_free (policy);
569
570 policies = soup_hsts_enforcer_get_policies (enforcer, TRUE);
571 g_assert_cmpint (g_list_length (policies), ==, 1);
572 policy = (SoupHSTSPolicy*)policies->data;
573 g_assert_cmpstr (soup_hsts_policy_get_domain (policy), ==, "freedesktop.org");
574 g_list_free_full (policies, (GDestroyNotify)soup_hsts_policy_free);
575 g_object_unref(enforcer);
576 }
577
578 int
main(int argc,char ** argv)579 main (int argc, char **argv)
580 {
581 int ret;
582 SoupServer *server;
583 SoupServer *https_server = NULL;
584
585 test_init (argc, argv, NULL);
586
587 server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
588 soup_server_add_handler (server, NULL, server_callback, "http", NULL);
589 http_uri = soup_test_server_get_uri (server, "http", NULL);
590
591 if (tls_available) {
592 https_server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
593 soup_server_add_handler (https_server, NULL, server_callback, "https", NULL);
594 https_uri = soup_test_server_get_uri (https_server, "https", NULL);
595 }
596
597 /* The case sensitivity test is run first because soup_message_headers_append()
598 interns the header name and further uses of the name use the interned version.
599 if we ran this test later, then the casing that this tests uses wouldn't be used. */
600 g_test_add_func ("/hsts/case-insensitive-header", do_hsts_case_insensitive_header_test);
601 g_test_add_func ("/hsts/basic", do_hsts_basic_test);
602 g_test_add_func ("/hsts/expire", do_hsts_expire_test);
603 g_test_add_func ("/hsts/delete", do_hsts_delete_test);
604 g_test_add_func ("/hsts/replace", do_hsts_replace_test);
605 g_test_add_func ("/hsts/update", do_hsts_update_test);
606 g_test_add_func ("/hsts/set_and_delete", do_hsts_set_and_delete_test);
607 g_test_add_func ("/hsts/no_hsts_header", do_hsts_no_hsts_header_test);
608 g_test_add_func ("/hsts/persistency", do_hsts_persistency_test);
609 g_test_add_func ("/hsts/subdomains", do_hsts_subdomains_test);
610 g_test_add_func ("/hsts/superdomain", do_hsts_superdomain_test);
611 g_test_add_func ("/hsts/multiple-headers", do_hsts_multiple_headers_test);
612 g_test_add_func ("/hsts/insecure-sts", do_hsts_insecure_sts_test);
613 g_test_add_func ("/hsts/missing-values", do_hsts_missing_values_test);
614 g_test_add_func ("/hsts/invalid-values", do_hsts_invalid_values_test);
615 g_test_add_func ("/hsts/extra-values", do_hsts_extra_values_test);
616 g_test_add_func ("/hsts/duplicated-directives", do_hsts_duplicated_directives_test);
617 g_test_add_func ("/hsts/case-insensitive-directives", do_hsts_case_insensitive_directives_test);
618 g_test_add_func ("/hsts/optional-quotations", do_hsts_optional_quotations_test);
619 g_test_add_func ("/hsts/ip-address", do_hsts_ip_address_test);
620 g_test_add_func ("/hsts/utf8-address", do_hsts_utf8_address_test);
621 g_test_add_func ("/hsts/session-policy", do_hsts_session_policy_test);
622 g_test_add_func ("/hsts/idna-addresses", do_hsts_idna_addresses_test);
623 g_test_add_func ("/hsts/get-domains", do_hsts_get_domains_test);
624 g_test_add_func ("/hsts/get-policies", do_hsts_get_policies_test);
625
626 ret = g_test_run ();
627
628 g_uri_unref (http_uri);
629 soup_test_server_quit_unref (server);
630
631 if (tls_available) {
632 g_uri_unref (https_uri);
633 soup_test_server_quit_unref (https_server);
634 }
635
636 test_cleanup ();
637 return ret;
638 }
639