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