• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 #include "test-utils.h"
4 
5 static gboolean server_processed_message;
6 static gboolean timeout;
7 static GMainLoop *loop;
8 static SoupMessagePriority expected_priorities[3];
9 
10 static gboolean
timeout_cb(gpointer user_data)11 timeout_cb (gpointer user_data)
12 {
13 	gboolean *timeout = user_data;
14 
15 	*timeout = TRUE;
16 	return FALSE;
17 }
18 
19 static void
server_handler(SoupServer * server,SoupMessage * msg,const char * path,GHashTable * query,SoupClientContext * client,gpointer user_data)20 server_handler (SoupServer        *server,
21 		SoupMessage       *msg,
22 		const char        *path,
23 		GHashTable        *query,
24 		SoupClientContext *client,
25 		gpointer           user_data)
26 {
27 	if (!strcmp (path, "/request-timeout")) {
28 		GMainContext *context = g_main_context_get_thread_default ();
29 		GSource *timer;
30 
31 		timer = g_timeout_source_new (100);
32 		g_source_set_callback (timer, timeout_cb, &timeout, NULL);
33 		g_source_attach (timer, context);
34 		g_source_unref (timer);
35 	} else
36 		server_processed_message = TRUE;
37 
38 	soup_message_set_status (msg, SOUP_STATUS_OK);
39 	soup_message_set_response (msg, "text/plain",
40 				   SOUP_MEMORY_STATIC,
41 				   "ok\r\n", 4);
42 }
43 
44 static void
finished_cb(SoupSession * session,SoupMessage * msg,gpointer user_data)45 finished_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
46 {
47 	gboolean *finished = user_data;
48 
49 	*finished = TRUE;
50 }
51 
52 static void
cancel_message_cb(SoupMessage * msg,gpointer session)53 cancel_message_cb (SoupMessage *msg, gpointer session)
54 {
55 	soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
56 	g_main_loop_quit (loop);
57 }
58 
59 static void
do_test_for_session(SoupSession * session,SoupURI * uri,gboolean queue_is_async,gboolean send_is_blocking,gboolean cancel_is_immediate)60 do_test_for_session (SoupSession *session, SoupURI *uri,
61 		     gboolean queue_is_async,
62 		     gboolean send_is_blocking,
63 		     gboolean cancel_is_immediate)
64 {
65 	SoupMessage *msg;
66 	gboolean finished, local_timeout;
67 	guint timeout_id;
68 	SoupURI *timeout_uri;
69 
70 	debug_printf (1, "  queue_message\n");
71 	debug_printf (2, "    requesting timeout\n");
72 	timeout_uri = soup_uri_new_with_base (uri, "/request-timeout");
73 	msg = soup_message_new_from_uri ("GET", timeout_uri);
74 	soup_uri_free (timeout_uri);
75 	soup_session_send_message (session, msg);
76 	g_object_unref (msg);
77 
78 	msg = soup_message_new_from_uri ("GET", uri);
79 	server_processed_message = timeout = finished = FALSE;
80 	soup_session_queue_message (session, msg, finished_cb, &finished);
81 	while (!timeout)
82 		g_usleep (100);
83 	debug_printf (2, "    got timeout\n");
84 
85 	if (queue_is_async) {
86 		g_assert_false (server_processed_message);
87 		debug_printf (2, "    waiting for finished\n");
88 		while (!finished)
89 			g_main_context_iteration (NULL, TRUE);
90 		g_assert_true (server_processed_message);
91 	} else {
92 		g_assert_true (server_processed_message);
93 		g_assert_false (finished);
94 		debug_printf (2, "    waiting for finished\n");
95 		while (!finished)
96 			g_main_context_iteration (NULL, TRUE);
97 	}
98 
99 	debug_printf (1, "  send_message\n");
100 	msg = soup_message_new_from_uri ("GET", uri);
101 	server_processed_message = local_timeout = FALSE;
102 	timeout_id = g_idle_add_full (G_PRIORITY_HIGH, timeout_cb, &local_timeout, NULL);
103 	soup_session_send_message (session, msg);
104 	g_object_unref (msg);
105 
106 	g_assert_true (server_processed_message);
107 
108 	if (send_is_blocking) {
109 		soup_test_assert (!local_timeout,
110 				  "send_message ran main loop");
111 	} else {
112 		soup_test_assert (local_timeout,
113 				  "send_message didn't run main loop");
114 	}
115 
116 	if (!local_timeout)
117 		g_source_remove (timeout_id);
118 
119 	if (!queue_is_async)
120 		return;
121 
122 	debug_printf (1, "  cancel_message\n");
123 	msg = soup_message_new_from_uri ("GET", uri);
124 	g_object_ref (msg);
125 	finished = FALSE;
126 	soup_session_queue_message (session, msg, finished_cb, &finished);
127 	g_signal_connect (msg, "wrote-headers",
128 			  G_CALLBACK (cancel_message_cb), session);
129 
130 	loop = g_main_loop_new (NULL, FALSE);
131 	g_main_loop_run (loop);
132 
133 	if (cancel_is_immediate)
134 		g_assert_true (finished);
135 	else
136 		g_assert_false (finished);
137 
138 	if (!finished) {
139 		debug_printf (2, "    waiting for finished\n");
140 		while (!finished)
141 			g_main_context_iteration (NULL, TRUE);
142 	}
143 	g_main_loop_unref (loop);
144 
145 	soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
146 	g_object_unref (msg);
147 }
148 
149 static void
do_plain_tests(gconstpointer data)150 do_plain_tests (gconstpointer data)
151 {
152 	SoupURI *uri = (SoupURI *)data;
153 	SoupSession *session;
154 
155 	session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
156 	do_test_for_session (session, uri, TRUE, TRUE, FALSE);
157 	soup_test_session_abort_unref (session);
158 }
159 
160 static void
do_async_tests(gconstpointer data)161 do_async_tests (gconstpointer data)
162 {
163 	SoupURI *uri = (SoupURI *)data;
164 	SoupSession *session;
165 
166 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
167 	do_test_for_session (session, uri, TRUE, FALSE, TRUE);
168 	soup_test_session_abort_unref (session);
169 }
170 
171 static void
do_sync_tests(gconstpointer data)172 do_sync_tests (gconstpointer data)
173 {
174 	SoupURI *uri = (SoupURI *)data;
175 	SoupSession *session;
176 
177 	session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
178 	do_test_for_session (session, uri, FALSE, TRUE, FALSE);
179 	soup_test_session_abort_unref (session);
180 }
181 
182 static void
priority_test_finished_cb(SoupSession * session,SoupMessage * msg,gpointer user_data)183 priority_test_finished_cb (SoupSession *session, SoupMessage *msg, gpointer user_data)
184 {
185 	guint *finished_count = user_data;
186 	SoupMessagePriority priority = soup_message_get_priority (msg);
187 
188 	debug_printf (1, "  received message %d with priority %d\n",
189 		      *finished_count, priority);
190 
191 	soup_test_assert (priority == expected_priorities[*finished_count],
192 			  "message %d should have priority %d (%d found)",
193 			  *finished_count, expected_priorities[*finished_count], priority);
194 
195 	(*finished_count)++;
196 }
197 
198 static void
do_priority_tests(gconstpointer data)199 do_priority_tests (gconstpointer data)
200 {
201 	SoupURI *uri = (SoupURI *)data;
202 	SoupSession *session;
203 	int i, finished_count = 0;
204 	SoupMessagePriority priorities[] =
205 		{ SOUP_MESSAGE_PRIORITY_LOW,
206 		  SOUP_MESSAGE_PRIORITY_HIGH,
207 		  SOUP_MESSAGE_PRIORITY_NORMAL };
208 
209 	g_test_bug ("696277");
210 
211 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
212 	g_object_set (session, "max-conns", 1, NULL);
213 
214 	expected_priorities[0] = SOUP_MESSAGE_PRIORITY_HIGH;
215 	expected_priorities[1] = SOUP_MESSAGE_PRIORITY_NORMAL;
216 	expected_priorities[2] = SOUP_MESSAGE_PRIORITY_LOW;
217 
218 	for (i = 0; i < 3; i++) {
219 		SoupURI *msg_uri;
220 		SoupMessage *msg;
221 		char buf[5];
222 
223 		g_snprintf (buf, sizeof (buf), "%d", i);
224 		msg_uri = soup_uri_new_with_base (uri, buf);
225 		msg = soup_message_new_from_uri ("GET", msg_uri);
226 		soup_uri_free (msg_uri);
227 
228 		soup_message_set_priority (msg, priorities[i]);
229 		soup_session_queue_message (session, msg, priority_test_finished_cb, &finished_count);
230 	}
231 
232 	debug_printf (2, "    waiting for finished\n");
233 	while (finished_count != 3)
234 		g_main_context_iteration (NULL, TRUE);
235 
236 	soup_test_session_abort_unref (session);
237 }
238 
239 static void
test_session_properties(const char * name,SoupSession * session,GProxyResolver * expected_proxy_resolver,GTlsDatabase * expected_tls_database)240 test_session_properties (const char *name,
241 			 SoupSession *session,
242 			 GProxyResolver *expected_proxy_resolver,
243 			 GTlsDatabase *expected_tls_database)
244 {
245 	GProxyResolver *proxy_resolver = NULL;
246 	GTlsDatabase *tlsdb = NULL;
247 
248 	g_object_get (G_OBJECT (session),
249 		      SOUP_SESSION_PROXY_RESOLVER, &proxy_resolver,
250 		      SOUP_SESSION_TLS_DATABASE, &tlsdb,
251 		      NULL);
252 
253 	soup_test_assert (proxy_resolver == expected_proxy_resolver,
254 			  "%s has %s proxy resolver",
255 			  name, proxy_resolver ? (expected_proxy_resolver ? "wrong" : "a") : "no");
256 	soup_test_assert (tlsdb == expected_tls_database,
257 			  "%s has %s TLS database",
258 			  name, tlsdb ? (expected_tls_database ? "wrong" : "a") : "no");
259 
260 	g_clear_object (&proxy_resolver);
261 	g_clear_object (&tlsdb);
262 }
263 
264 static void
do_property_tests(void)265 do_property_tests (void)
266 {
267 	SoupSession *session;
268 	GProxyResolver *proxy_resolver, *default_proxy_resolver;
269 	GTlsDatabase *tlsdb, *default_tlsdb;
270 	SoupURI *uri;
271 
272 	g_test_bug ("708696");
273 
274 	default_proxy_resolver = g_proxy_resolver_get_default ();
275 	default_tlsdb = g_tls_backend_get_default_database (g_tls_backend_get_default ());
276 
277 	/* NOTE: We intentionally do not use soup_test_session_new() here */
278 
279 	session = g_object_new (SOUP_TYPE_SESSION,
280 				NULL);
281 	test_session_properties ("Base plain session", session,
282 				 default_proxy_resolver, default_tlsdb);
283 	g_object_unref (session);
284 
285 	session = g_object_new (SOUP_TYPE_SESSION,
286 				SOUP_SESSION_PROXY_RESOLVER, NULL,
287 				NULL);
288 	test_session_properties ("Session with NULL :proxy-resolver", session,
289 				 NULL, default_tlsdb);
290 	g_object_unref (session);
291 
292 	proxy_resolver = g_simple_proxy_resolver_new (NULL, NULL);
293 	session = g_object_new (SOUP_TYPE_SESSION,
294 				SOUP_SESSION_PROXY_RESOLVER, proxy_resolver,
295 				NULL);
296 	test_session_properties ("Session with non-NULL :proxy-resolver", session,
297 				 proxy_resolver, default_tlsdb);
298 	g_object_unref (proxy_resolver);
299 	g_object_unref (session);
300 
301 	session = g_object_new (SOUP_TYPE_SESSION,
302 				SOUP_SESSION_PROXY_URI, NULL,
303 				NULL);
304 	test_session_properties ("Session with NULL :proxy-uri", session,
305 				 NULL, default_tlsdb);
306 	g_object_unref (session);
307 
308 	uri = soup_uri_new ("http://example.com/");
309 	session = g_object_new (SOUP_TYPE_SESSION,
310 				SOUP_SESSION_PROXY_URI, uri,
311 				NULL);
312 	g_object_get (G_OBJECT (session),
313 		      SOUP_SESSION_PROXY_RESOLVER, &proxy_resolver,
314 		      NULL);
315 	test_session_properties ("Session with non-NULL :proxy-uri", session,
316 				 proxy_resolver, default_tlsdb);
317 	g_assert_cmpstr (G_OBJECT_TYPE_NAME (proxy_resolver), ==, "GSimpleProxyResolver");
318 	g_object_unref (proxy_resolver);
319 	g_object_unref (session);
320 	soup_uri_free (uri);
321 
322 	G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
323 	session = g_object_new (SOUP_TYPE_SESSION,
324 				SOUP_SESSION_REMOVE_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_URI_RESOLVER,
325 				NULL);
326 	test_session_properties ("Session with removed proxy resolver feature", session,
327 				 NULL, default_tlsdb);
328 	g_object_unref (session);
329 	G_GNUC_END_IGNORE_DEPRECATIONS;
330 
331 	session = g_object_new (SOUP_TYPE_SESSION,
332 				SOUP_SESSION_TLS_DATABASE, NULL,
333 				NULL);
334 	test_session_properties ("Session with NULL :tls-database", session,
335 				 default_proxy_resolver, NULL);
336 	g_object_unref (session);
337 
338 	/* g_tls_file_database_new() will fail with the dummy backend,
339 	 * so we can only do this test if we have a real TLS backend.
340 	 */
341 	if (tls_available) {
342 		GError *error = NULL;
343 
344 		tlsdb = g_tls_file_database_new (g_test_get_filename (G_TEST_DIST,
345 								      "test-cert.pem",
346 								      NULL), &error);
347 		g_assert_no_error (error);
348 
349 		session = g_object_new (SOUP_TYPE_SESSION,
350 					SOUP_SESSION_TLS_DATABASE, tlsdb,
351 					NULL);
352 		test_session_properties ("Session with non-NULL :tls-database", session,
353 					 default_proxy_resolver, tlsdb);
354 		g_object_unref (tlsdb);
355 		g_object_unref (session);
356 	}
357 
358 	session = g_object_new (SOUP_TYPE_SESSION,
359 				SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, FALSE,
360 				NULL);
361 	test_session_properties ("Session with :ssl-use-system-ca-file FALSE", session,
362 				 default_proxy_resolver, NULL);
363 	g_object_unref (session);
364 
365 	session = g_object_new (SOUP_TYPE_SESSION,
366 				SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
367 				NULL);
368 	test_session_properties ("Session with :ssl-use-system-ca-file TRUE", session,
369 				 default_proxy_resolver, default_tlsdb);
370 	g_object_unref (session);
371 }
372 
373 static gint
compare_by_gtype(gconstpointer a,gconstpointer b)374 compare_by_gtype (gconstpointer a,
375 		  gconstpointer b)
376 {
377 	return G_TYPE_CHECK_INSTANCE_TYPE (a, GPOINTER_TO_SIZE (b)) ? 0 : 1;
378 }
379 
380 static void
do_features_test(void)381 do_features_test (void)
382 {
383 	SoupSession *session;
384 	GSList *features;
385 	SoupSessionFeature *feature;
386 
387 	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
388 
389 	features = soup_session_get_features (session, SOUP_TYPE_SESSION_FEATURE);
390 	/* SoupAuthManager is always added */
391 	g_assert_cmpuint (g_slist_length (features), >=, 1);
392 	g_assert_nonnull (g_slist_find_custom (features, GSIZE_TO_POINTER (SOUP_TYPE_AUTH_MANAGER), compare_by_gtype));
393 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_AUTH_MANAGER));
394 	feature = soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER);
395 	g_assert_true (SOUP_IS_AUTH_MANAGER (feature));
396 	soup_session_remove_feature (session, feature);
397 	g_assert_false (soup_session_has_feature (session, SOUP_TYPE_AUTH_MANAGER));
398 	g_assert_null (soup_session_get_feature (session, SOUP_TYPE_AUTH_MANAGER));
399 	g_slist_free (features);
400 
401 	/* HTTP, File and Data requests are always added */
402 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_REQUEST_HTTP));
403 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_REQUEST_FILE));
404 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_REQUEST_DATA));
405 	soup_session_remove_feature_by_type (session, SOUP_TYPE_REQUEST_FILE);
406 	g_assert_false (soup_session_has_feature (session, SOUP_TYPE_REQUEST_FILE));
407 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_REQUEST_HTTP));
408 	g_assert_true (soup_session_has_feature (session, SOUP_TYPE_REQUEST_DATA));
409 
410 	soup_test_session_abort_unref (session);
411 }
412 
413 int
main(int argc,char ** argv)414 main (int argc, char **argv)
415 {
416 	SoupServer *server;
417 	SoupURI *uri;
418 	int ret;
419 
420 	test_init (argc, argv, NULL);
421 
422 	server = soup_test_server_new (TRUE);
423 	soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
424 	uri = soup_test_server_get_uri (server, "http", NULL);
425 
426 	g_test_add_data_func ("/session/SoupSession", uri, do_plain_tests);
427 	g_test_add_data_func ("/session/SoupSessionAsync", uri, do_async_tests);
428 	g_test_add_data_func ("/session/SoupSessionSync", uri, do_sync_tests);
429 	g_test_add_data_func ("/session/priority", uri, do_priority_tests);
430 	g_test_add_func ("/session/property", do_property_tests);
431 	g_test_add_func ("/session/features", do_features_test);
432 
433 	ret = g_test_run ();
434 
435 	soup_uri_free (uri);
436 	soup_test_server_quit_unref (server);
437 
438 	test_cleanup ();
439 	return ret;
440 }
441