• 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 #include <glib/gprintf.h>
6 
7 #include <locale.h>
8 #include <signal.h>
9 
10 #ifdef HAVE_APACHE
11 static gboolean apache_running;
12 #endif
13 
14 static SoupLogger *logger;
15 static SoupBuffer *index_buffer;
16 
17 int debug_level;
18 gboolean expect_warning, tls_available;
19 static int http_debug_level;
20 
21 static gboolean
increment_debug_level(const char * option_name,const char * value,gpointer data,GError ** error)22 increment_debug_level (const char *option_name, const char *value,
23 		       gpointer data, GError **error)
24 {
25 	debug_level++;
26 	return TRUE;
27 }
28 
29 static gboolean
increment_http_debug_level(const char * option_name,const char * value,gpointer data,GError ** error)30 increment_http_debug_level (const char *option_name, const char *value,
31 			    gpointer data, GError **error)
32 {
33 	http_debug_level++;
34 	return TRUE;
35 }
36 
37 static GOptionEntry debug_entry[] = {
38 	{ "debug", 'd', G_OPTION_FLAG_NO_ARG,
39 	  G_OPTION_ARG_CALLBACK, increment_debug_level,
40 	  "Enable (or increase) test-specific debugging", NULL },
41 	{ "http-debug", 'H', G_OPTION_FLAG_NO_ARG,
42 	  G_OPTION_ARG_CALLBACK, increment_http_debug_level,
43 	  "Enable (or increase) HTTP-level debugging", NULL },
44 	{ NULL }
45 };
46 
47 static void
quit(int sig)48 quit (int sig)
49 {
50 #ifdef HAVE_APACHE
51 	if (apache_running)
52 		apache_cleanup ();
53 #endif
54 
55 	exit (1);
56 }
57 
58 void
test_init(int argc,char ** argv,GOptionEntry * entries)59 test_init (int argc, char **argv, GOptionEntry *entries)
60 {
61 	GOptionContext *opts;
62 	char *name;
63 	GError *error = NULL;
64 	GTlsBackend *tls_backend;
65 
66 	setlocale (LC_ALL, "");
67 	g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
68 	g_setenv ("GIO_USE_PROXY_RESOLVER", "dummy", TRUE);
69 	g_setenv ("GIO_USE_VFS", "local", TRUE);
70 
71 	name = strrchr (argv[0], '/');
72 	if (!name++)
73 		name = argv[0];
74 	if (!strncmp (name, "lt-", 3))
75 		name += 3;
76 	g_set_prgname (name);
77 
78 	g_test_init (&argc, &argv, NULL);
79 	g_test_set_nonfatal_assertions ();
80 	g_test_bug_base ("https://bugzilla.gnome.org/");
81 
82 	opts = g_option_context_new (NULL);
83 	g_option_context_add_main_entries (opts, debug_entry, NULL);
84 	if (entries)
85 		g_option_context_add_main_entries (opts, entries, NULL);
86 
87 	if (!g_option_context_parse (opts, &argc, &argv, &error)) {
88 		g_printerr ("Could not parse arguments: %s\n",
89 			    error->message);
90 		g_printerr ("%s",
91 			    g_option_context_get_help (opts, TRUE, NULL));
92 		exit (1);
93 	}
94 	g_option_context_free (opts);
95 
96 	/* Exit cleanly on ^C in case we're valgrinding. */
97 	signal (SIGINT, quit);
98 
99 	tls_backend = g_tls_backend_get_default ();
100 	tls_available = g_tls_backend_supports_tls (tls_backend);
101 }
102 
103 void
test_cleanup(void)104 test_cleanup (void)
105 {
106 #ifdef HAVE_APACHE
107 	if (apache_running)
108 		apache_cleanup ();
109 #endif
110 
111 	if (logger)
112 		g_object_unref (logger);
113 	if (index_buffer)
114 		soup_buffer_free (index_buffer);
115 
116 	g_main_context_unref (g_main_context_default ());
117 
118 	debug_printf (1, "\n");
119 }
120 
121 void
debug_printf(int level,const char * format,...)122 debug_printf (int level, const char *format, ...)
123 {
124 	va_list args;
125 
126 	if (debug_level < level)
127 		return;
128 
129 	va_start (args, format);
130 	g_vprintf (format, args);
131 	va_end (args);
132 }
133 
134 gboolean
have_curl(void)135 have_curl(void) {
136 	char *found;
137 
138 	found = g_find_program_in_path ("curl");
139 	if (found) {
140 		g_free (found);
141 		return TRUE;
142 	} else {
143 		return FALSE;
144 	}
145 }
146 
147 #ifdef HAVE_APACHE
148 
149 static gboolean
apache_cmd(const char * cmd)150 apache_cmd (const char *cmd)
151 {
152 	GPtrArray *argv;
153 	char *server_root, *cwd, *pid_file;
154 #ifdef HAVE_APACHE_2_4
155 	char *default_runtime_dir;
156 #endif
157 	int status;
158 	gboolean ok;
159 
160 	server_root = g_test_build_filename (G_TEST_BUILT, "", NULL);
161 
162 	cwd = g_get_current_dir ();
163 #ifdef HAVE_APACHE_2_4
164 	default_runtime_dir = g_strdup_printf ("DefaultRuntimeDir %s", cwd);
165 #endif
166 	pid_file = g_strdup_printf ("PidFile %s/httpd.pid", cwd);
167 
168 	argv = g_ptr_array_new ();
169 	g_ptr_array_add (argv, APACHE_HTTPD);
170 	g_ptr_array_add (argv, "-d");
171 	g_ptr_array_add (argv, server_root);
172 	g_ptr_array_add (argv, "-f");
173 	g_ptr_array_add (argv, "httpd.conf");
174 
175 #ifdef HAVE_APACHE_2_4
176 	g_ptr_array_add (argv, "-c");
177 	g_ptr_array_add (argv, default_runtime_dir);
178 #endif
179 	g_ptr_array_add (argv, "-c");
180 	g_ptr_array_add (argv, pid_file);
181 
182 	g_ptr_array_add (argv, "-k");
183 	g_ptr_array_add (argv, (char *)cmd);
184 	g_ptr_array_add (argv, NULL);
185 
186 	ok = g_spawn_sync (cwd, (char **)argv->pdata, NULL, 0, NULL, NULL,
187 			   NULL, NULL, &status, NULL);
188 	if (ok)
189 		ok = (status == 0);
190 
191 	g_free (server_root);
192 	g_free (cwd);
193 	g_free (pid_file);
194 #ifdef HAVE_APACHE_2_4
195 	g_free (default_runtime_dir);
196 #endif
197 	g_ptr_array_free (argv, TRUE);
198 
199 	return ok;
200 }
201 
202 void
apache_init(void)203 apache_init (void)
204 {
205 	/* Set this environment variable if you are already running a
206 	 * suitably-configured Apache server */
207 	if (g_getenv ("SOUP_TESTS_ALREADY_RUNNING_APACHE"))
208 		return;
209 
210 	if (!apache_cmd ("start")) {
211 		g_printerr ("Could not start apache\n");
212 		exit (1);
213 	}
214 	apache_running = TRUE;
215 }
216 
217 void
apache_cleanup(void)218 apache_cleanup (void)
219 {
220 	pid_t pid;
221 	char *contents;
222 
223 	if (g_file_get_contents ("httpd.pid", &contents, NULL, NULL)) {
224 		pid = strtoul (contents, NULL, 10);
225 		g_free (contents);
226 	} else
227 		pid = 0;
228 
229 	if (!apache_cmd ("graceful-stop"))
230 		return;
231 	apache_running = FALSE;
232 
233 	if (pid) {
234 		while (kill (pid, 0) == 0)
235 			g_usleep (100);
236 	}
237 }
238 
239 #endif /* HAVE_APACHE */
240 
241 SoupSession *
soup_test_session_new(GType type,...)242 soup_test_session_new (GType type, ...)
243 {
244 	va_list args;
245 	const char *propname;
246 	SoupSession *session;
247 	GTlsDatabase *tlsdb;
248 	char *cafile;
249 	GError *error = NULL;
250 
251 	va_start (args, type);
252 	propname = va_arg (args, const char *);
253 	session = (SoupSession *)g_object_new_valist (type, propname, args);
254 	va_end (args);
255 
256 	if (tls_available) {
257 		char *abs_cafile;
258 
259 		cafile = g_test_build_filename (G_TEST_DIST, "test-cert.pem", NULL);
260 		abs_cafile = g_canonicalize_filename (cafile, NULL);
261 		g_free (cafile);
262 		tlsdb = g_tls_file_database_new (abs_cafile, &error);
263 		g_free (abs_cafile);
264 		if (error) {
265 			if (g_strcmp0 (g_getenv ("GIO_USE_TLS"), "dummy") == 0)
266 				g_clear_error (&error);
267 			else
268 				g_assert_no_error (error);
269 		}
270 
271 		g_object_set (G_OBJECT (session),
272 			      SOUP_SESSION_TLS_DATABASE, tlsdb,
273 			      NULL);
274 		g_clear_object (&tlsdb);
275 	}
276 
277 	if (http_debug_level && !logger) {
278 		SoupLoggerLogLevel level = MIN ((SoupLoggerLogLevel)http_debug_level, SOUP_LOGGER_LOG_BODY);
279 
280 		logger = soup_logger_new (level, -1);
281 	}
282 
283 	if (logger)
284 		soup_session_add_feature (session, SOUP_SESSION_FEATURE (logger));
285 
286 	return session;
287 }
288 
289 void
soup_test_session_abort_unref(SoupSession * session)290 soup_test_session_abort_unref (SoupSession *session)
291 {
292 	soup_session_abort (session);
293 
294 	g_assert_cmpint (G_OBJECT (session)->ref_count, ==, 1);
295 	g_object_unref (session);
296 }
297 
298 static void
server_listen(SoupServer * server)299 server_listen (SoupServer *server)
300 {
301 	GError *error = NULL;
302 
303 	soup_server_listen_local (server, 0, 0, &error);
304 	if (error) {
305 		g_printerr ("Unable to create server: %s\n", error->message);
306 		exit (1);
307 	}
308 }
309 
310 static GMutex server_start_mutex;
311 static GCond server_start_cond;
312 
313 static gpointer
run_server_thread(gpointer user_data)314 run_server_thread (gpointer user_data)
315 {
316 	SoupServer *server = user_data;
317 	SoupTestServerOptions options =
318 		GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (server), "options"));
319 	GMainContext *context;
320 	GMainLoop *loop;
321 
322 	context = g_main_context_new ();
323 	g_main_context_push_thread_default (context);
324 	loop = g_main_loop_new (context, FALSE);
325 	g_object_set_data (G_OBJECT (server), "GMainLoop", loop);
326 
327 	if (!(options & SOUP_TEST_SERVER_NO_DEFAULT_LISTENER))
328 		server_listen (server);
329 
330 	g_mutex_lock (&server_start_mutex);
331 	g_cond_signal (&server_start_cond);
332 	g_mutex_unlock (&server_start_mutex);
333 
334 	g_main_loop_run (loop);
335 	g_main_loop_unref (loop);
336 
337 	soup_server_disconnect (server);
338 
339 	g_main_context_pop_thread_default (context);
340 	g_main_context_unref (context);
341 
342 	return NULL;
343 }
344 
345 SoupServer *
soup_test_server_new(SoupTestServerOptions options)346 soup_test_server_new (SoupTestServerOptions options)
347 {
348 	SoupServer *server;
349 	GTlsCertificate *cert = NULL;
350 	GError *error = NULL;
351 
352 	if (tls_available) {
353 		char *ssl_cert_file, *ssl_key_file;
354 
355 		ssl_cert_file = g_test_build_filename (G_TEST_DIST, "test-cert.pem", NULL);
356 		ssl_key_file = g_test_build_filename (G_TEST_DIST, "test-key.pem", NULL);
357 		cert = g_tls_certificate_new_from_files (ssl_cert_file,
358 							 ssl_key_file,
359 							 &error);
360 		g_free (ssl_cert_file);
361 		g_free (ssl_key_file);
362 		if (error) {
363 			g_printerr ("Unable to create server: %s\n", error->message);
364 			exit (1);
365 		}
366 	}
367 
368 	server = soup_server_new (SOUP_SERVER_TLS_CERTIFICATE, cert,
369 				  NULL);
370 	g_clear_object (&cert);
371 
372 	g_object_set_data (G_OBJECT (server), "options", GUINT_TO_POINTER (options));
373 
374 	if (options & SOUP_TEST_SERVER_IN_THREAD) {
375 		GThread *thread;
376 
377 		g_mutex_lock (&server_start_mutex);
378 
379 		thread = g_thread_new ("server_thread", run_server_thread, server);
380 		g_cond_wait (&server_start_cond, &server_start_mutex);
381 		g_mutex_unlock (&server_start_mutex);
382 
383 		g_object_set_data (G_OBJECT (server), "thread", thread);
384 	} else if (!(options & SOUP_TEST_SERVER_NO_DEFAULT_LISTENER))
385 		server_listen (server);
386 
387 	return server;
388 }
389 
390 static SoupURI *
find_server_uri(SoupServer * server,const char * scheme,const char * host)391 find_server_uri (SoupServer *server, const char *scheme, const char *host)
392 {
393 	GSList *uris, *u;
394 	SoupURI *uri, *ret_uri = NULL;
395 
396 	uris = soup_server_get_uris (server);
397 	for (u = uris; u; u = u->next) {
398 		uri = u->data;
399 
400 		if (scheme && strcmp (uri->scheme, scheme) != 0)
401 			continue;
402 		if (host && strcmp (uri->host, host) != 0)
403 			continue;
404 
405 		ret_uri = soup_uri_copy (uri);
406 		break;
407 	}
408 	g_slist_free_full (uris, (GDestroyNotify)soup_uri_free);
409 
410 	return ret_uri;
411 }
412 
413 static SoupURI *
add_listener(SoupServer * server,const char * scheme,const char * host)414 add_listener (SoupServer *server, const char *scheme, const char *host)
415 {
416 	SoupServerListenOptions options = 0;
417 	GError *error = NULL;
418 
419 	if (!g_strcmp0 (scheme, SOUP_URI_SCHEME_HTTPS))
420 		options |= SOUP_SERVER_LISTEN_HTTPS;
421 	if (!g_strcmp0 (host, "127.0.0.1"))
422 		options |= SOUP_SERVER_LISTEN_IPV4_ONLY;
423 	else if (!g_strcmp0 (host, "::1"))
424 		options |= SOUP_SERVER_LISTEN_IPV6_ONLY;
425 
426 	soup_server_listen_local (server, 0, options, &error);
427 	g_assert_no_error (error);
428 
429 	return find_server_uri (server, scheme, host);
430 }
431 
432 typedef struct {
433 	GMutex mutex;
434 	GCond cond;
435 
436 	SoupServer *server;
437 	const char *scheme;
438 	const char *host;
439 
440 	SoupURI *uri;
441 } AddListenerData;
442 
443 static gboolean
add_listener_in_thread(gpointer user_data)444 add_listener_in_thread (gpointer user_data)
445 {
446 	AddListenerData *data = user_data;
447 
448 	data->uri = add_listener (data->server, data->scheme, data->host);
449 	g_mutex_lock (&data->mutex);
450 	g_cond_signal (&data->cond);
451 	g_mutex_unlock (&data->mutex);
452 
453 	return FALSE;
454 }
455 
456 SoupURI *
soup_test_server_get_uri(SoupServer * server,const char * scheme,const char * host)457 soup_test_server_get_uri (SoupServer    *server,
458 			  const char    *scheme,
459 			  const char    *host)
460 {
461 	SoupURI *uri;
462 	GMainLoop *loop;
463 
464 	uri = find_server_uri (server, scheme, host);
465 	if (uri)
466 		return uri;
467 
468 	/* Need to add a new listener */
469 	loop = g_object_get_data (G_OBJECT (server), "GMainLoop");
470 	if (loop) {
471 		GMainContext *context = g_main_loop_get_context (loop);
472 		AddListenerData data;
473 
474 		g_mutex_init (&data.mutex);
475 		g_cond_init (&data.cond);
476 		data.server = server;
477 		data.scheme = scheme;
478 		data.host = host;
479 		data.uri = NULL;
480 
481 		g_mutex_lock (&data.mutex);
482 		soup_add_completion (context, add_listener_in_thread, &data);
483 
484 		while (!data.uri)
485 			g_cond_wait (&data.cond, &data.mutex);
486 
487 		g_mutex_unlock (&data.mutex);
488 		g_mutex_clear (&data.mutex);
489 		g_cond_clear (&data.cond);
490 		uri = data.uri;
491 	} else
492 		uri = add_listener (server, scheme, host);
493 
494 	return uri;
495 }
496 
497 static gboolean
done_waiting(gpointer user_data)498 done_waiting (gpointer user_data)
499 {
500 	gboolean *done = user_data;
501 
502 	*done = TRUE;
503 	return FALSE;
504 }
505 
506 static void
disconnect_and_wait(SoupServer * server,GMainContext * context)507 disconnect_and_wait (SoupServer *server,
508 		     GMainContext *context)
509 {
510 	GSource *source;
511 	gboolean done = FALSE;
512 
513 	source = g_idle_source_new ();
514 	g_source_set_priority (source, G_PRIORITY_LOW);
515 	g_source_set_callback (source, done_waiting, &done, NULL);
516 	g_source_attach (source, context);
517 	g_source_unref (source);
518 
519 	soup_server_disconnect (server);
520 	while (!done)
521 		g_main_context_iteration (context, TRUE);
522 }
523 
524 static gboolean
idle_quit_server(gpointer user_data)525 idle_quit_server (gpointer user_data)
526 {
527 	SoupServer *server = user_data;
528 	GMainLoop *loop = g_object_get_data (G_OBJECT (server), "GMainLoop");
529 
530 	disconnect_and_wait (server, g_main_loop_get_context (loop));
531 	g_main_loop_quit (loop);
532 	return FALSE;
533 }
534 
535 void
soup_test_server_quit_unref(SoupServer * server)536 soup_test_server_quit_unref (SoupServer *server)
537 {
538 	GThread *thread;
539 
540 	thread = g_object_get_data (G_OBJECT (server), "thread");
541 	if (thread) {
542 		GMainLoop *loop;
543 		GMainContext *context;
544 
545 		loop = g_object_get_data (G_OBJECT (server), "GMainLoop");
546 		context = g_main_loop_get_context (loop);
547 		g_main_context_ref (context);
548 		soup_add_completion (context, idle_quit_server, server);
549 		g_main_context_unref (context);
550 		g_thread_join (thread);
551 	} else
552 		disconnect_and_wait (server, NULL);
553 
554 	g_assert_cmpint (G_OBJECT (server)->ref_count, ==, 1);
555 	g_object_unref (server);
556 }
557 
558 typedef struct {
559 	GMainLoop *loop;
560 	GAsyncResult *result;
561 } AsyncAsSyncData;
562 
563 static void
async_as_sync_callback(GObject * object,GAsyncResult * result,gpointer user_data)564 async_as_sync_callback (GObject      *object,
565 			GAsyncResult *result,
566 			gpointer      user_data)
567 {
568 	AsyncAsSyncData *data = user_data;
569 	GMainContext *context;
570 
571 	data->result = g_object_ref (result);
572 	context = g_main_loop_get_context (data->loop);
573 	while (g_main_context_pending (context))
574 		g_main_context_iteration (context, FALSE);
575 	g_main_loop_quit (data->loop);
576 }
577 
578 typedef struct {
579 	SoupRequest  *req;
580 	GCancellable *cancellable;
581 	SoupTestRequestFlags flags;
582 } CancelData;
583 
584 static CancelData *
create_cancel_data(SoupRequest * req,GCancellable * cancellable,SoupTestRequestFlags flags)585 create_cancel_data (SoupRequest          *req,
586 		    GCancellable         *cancellable,
587 		    SoupTestRequestFlags  flags)
588 {
589 	CancelData *cancel_data;
590 
591 	if (!flags)
592 		return NULL;
593 
594 	cancel_data = g_slice_new0 (CancelData);
595 	cancel_data->flags = flags;
596 	if (flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE && SOUP_IS_REQUEST_HTTP (req))
597 		cancel_data->req = g_object_ref (req);
598 	else if (flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE)
599 		cancel_data->cancellable = g_object_ref (cancellable);
600 	return cancel_data;
601 }
602 
603 inline static void
cancel_message_or_cancellable(CancelData * cancel_data)604 cancel_message_or_cancellable (CancelData *cancel_data)
605 {
606 	if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_MESSAGE) {
607 		SoupRequest *req = cancel_data->req;
608 		SoupMessage *msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (req));
609 		soup_session_cancel_message (soup_request_get_session (req), msg,
610 					     SOUP_STATUS_CANCELLED);
611 		g_object_unref (msg);
612 		g_object_unref (req);
613 	} else if (cancel_data->flags & SOUP_TEST_REQUEST_CANCEL_CANCELLABLE) {
614 		g_cancellable_cancel (cancel_data->cancellable);
615 		g_object_unref (cancel_data->cancellable);
616 	}
617 	g_slice_free (CancelData, cancel_data);
618 }
619 
620 static gboolean
cancel_request_timeout(gpointer data)621 cancel_request_timeout (gpointer data)
622 {
623 	cancel_message_or_cancellable ((CancelData *) data);
624 	return FALSE;
625 }
626 
627 static gpointer
cancel_request_thread(gpointer data)628 cancel_request_thread (gpointer data)
629 {
630 	g_usleep (100000); /* .1s */
631 	cancel_message_or_cancellable ((CancelData *) data);
632 	return NULL;
633 }
634 
635 GInputStream *
soup_test_request_send(SoupRequest * req,GCancellable * cancellable,guint flags,GError ** error)636 soup_test_request_send (SoupRequest   *req,
637 			GCancellable  *cancellable,
638 			guint          flags,
639 			GError       **error)
640 {
641 	AsyncAsSyncData data;
642 	GInputStream *stream;
643 	CancelData *cancel_data = create_cancel_data (req, cancellable, flags);
644 
645 	if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req))) {
646 		GThread *thread;
647 
648 		if (cancel_data)
649 			thread = g_thread_new ("cancel_request_thread", cancel_request_thread,
650 					       cancel_data);
651 		stream = soup_request_send (req, cancellable, error);
652 		if (cancel_data)
653 			g_thread_unref (thread);
654 		return stream;
655 	}
656 
657 	data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
658 	if (cancel_data &&
659 	    (flags & SOUP_TEST_REQUEST_CANCEL_SOON || flags & SOUP_TEST_REQUEST_CANCEL_IMMEDIATE)) {
660 		guint interval = flags & SOUP_TEST_REQUEST_CANCEL_SOON ? 100 : 0;
661 		g_timeout_add_full (G_PRIORITY_HIGH, interval, cancel_request_timeout, cancel_data, NULL);
662 	}
663 	if (cancel_data && (flags & SOUP_TEST_REQUEST_CANCEL_PREEMPTIVE))
664 		cancel_message_or_cancellable (cancel_data);
665 	soup_request_send_async (req, cancellable, async_as_sync_callback, &data);
666 	g_main_loop_run (data.loop);
667 
668 	stream = soup_request_send_finish (req, data.result, error);
669 
670 	if (cancel_data && (flags &  SOUP_TEST_REQUEST_CANCEL_AFTER_SEND_FINISH)) {
671 		GMainContext *context;
672 
673 		cancel_message_or_cancellable (cancel_data);
674 
675 		context = g_main_loop_get_context (data.loop);
676 		while (g_main_context_pending (context))
677 			g_main_context_iteration (context, FALSE);
678 	}
679 
680 	g_main_loop_unref (data.loop);
681 	g_object_unref (data.result);
682 
683 	return stream;
684 }
685 
686 gboolean
soup_test_request_read_all(SoupRequest * req,GInputStream * stream,GCancellable * cancellable,GError ** error)687 soup_test_request_read_all (SoupRequest   *req,
688 			    GInputStream  *stream,
689 			    GCancellable  *cancellable,
690 			    GError       **error)
691 {
692 	char buf[8192];
693 	AsyncAsSyncData data;
694 	gsize nread;
695 
696 	if (!SOUP_IS_SESSION_SYNC (soup_request_get_session (req)))
697 		data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
698 	else
699 		data.loop = NULL;
700 
701 	do {
702 		if (!data.loop) {
703 			nread = g_input_stream_read (stream, buf, sizeof (buf),
704 						     cancellable, error);
705 		} else {
706 			g_input_stream_read_async (stream, buf, sizeof (buf),
707 						   G_PRIORITY_DEFAULT, cancellable,
708 						   async_as_sync_callback, &data);
709 			g_main_loop_run (data.loop);
710 			nread = g_input_stream_read_finish (stream, data.result, error);
711 			g_object_unref (data.result);
712 		}
713 	} while (nread > 0);
714 
715 	if (data.loop)
716 		g_main_loop_unref (data.loop);
717 
718 	return nread == 0;
719 }
720 
721 gboolean
soup_test_request_close_stream(SoupRequest * req,GInputStream * stream,GCancellable * cancellable,GError ** error)722 soup_test_request_close_stream (SoupRequest   *req,
723 				GInputStream  *stream,
724 				GCancellable  *cancellable,
725 				GError       **error)
726 {
727 	AsyncAsSyncData data;
728 	gboolean ok;
729 
730 	if (SOUP_IS_SESSION_SYNC (soup_request_get_session (req)))
731 		return g_input_stream_close (stream, cancellable, error);
732 
733 	data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
734 
735 	g_input_stream_close_async (stream, G_PRIORITY_DEFAULT, cancellable,
736 				    async_as_sync_callback, &data);
737 	g_main_loop_run (data.loop);
738 
739 	ok = g_input_stream_close_finish (stream, data.result, error);
740 
741 	g_main_loop_unref (data.loop);
742 	g_object_unref (data.result);
743 
744 	return ok;
745 }
746 
747 void
soup_test_register_resources(void)748 soup_test_register_resources (void)
749 {
750 	static gboolean registered = FALSE;
751 	GResource *resource;
752 	char *path;
753 	GError *error = NULL;
754 
755 	if (registered)
756 		return;
757 
758 	path = g_test_build_filename (G_TEST_BUILT, "soup-tests.gresource", NULL);
759 	resource = g_resource_load (path, &error);
760 	if (!resource) {
761 		g_printerr ("Could not load resource soup-tests.gresource: %s\n",
762 			    error->message);
763 		exit (1);
764 	}
765 	g_free (path);
766 
767 	g_resources_register (resource);
768 	g_resource_unref (resource);
769 
770 	registered = TRUE;
771 }
772 
773 SoupBuffer *
soup_test_load_resource(const char * name,GError ** error)774 soup_test_load_resource (const char  *name,
775 			 GError     **error)
776 {
777 	GBytes *bytes;
778 	char *path;
779 
780 	soup_test_register_resources ();
781 
782 	path = g_build_path ("/", "/org/gnome/libsoup/tests/resources", name, NULL);
783 	bytes = g_resources_lookup_data (path, G_RESOURCE_LOOKUP_FLAGS_NONE, error);
784 	g_free (path);
785 
786 	if (!bytes)
787 		return NULL;
788 
789 	return soup_buffer_new_with_owner (g_bytes_get_data (bytes, NULL),
790 					   g_bytes_get_size (bytes),
791 					   bytes,
792 					   (GDestroyNotify) g_bytes_unref);
793 }
794 
795 SoupBuffer *
soup_test_get_index(void)796 soup_test_get_index (void)
797 {
798 	if (!index_buffer) {
799 		char *path, *contents;
800 		gsize length;
801 		GError *error = NULL;
802 
803 		path = g_test_build_filename (G_TEST_DIST, "index.txt", NULL);
804 		if (!g_file_get_contents (path, &contents, &length, &error)) {
805 			g_printerr ("Could not read index.txt: %s\n",
806 				    error->message);
807 			exit (1);
808 		}
809 		g_free (path);
810 
811 		index_buffer = soup_buffer_new (SOUP_MEMORY_TAKE, contents, length);
812 	}
813 
814 	return index_buffer;
815 }
816 
817 #ifndef G_HAVE_ISO_VARARGS
818 void
soup_test_assert(gboolean expr,const char * fmt,...)819 soup_test_assert (gboolean expr, const char *fmt, ...)
820 {
821 	char *message;
822 	va_list args;
823 
824 	if (G_UNLIKELY (!expr)) {
825 		va_start (args, fmt);
826 		message = g_strdup_vprintf (fmt, args);
827 		va_end (args);
828 
829 		g_assertion_message (G_LOG_DOMAIN,
830 				     "???", 0, "???"
831 				     message);
832 		g_free (message);
833 	}
834 }
835 #endif
836