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