1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Red Hat, Inc.
17 #include <libsoup/soup.h>
19 #include "test-utils.h"
26 auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg,
27 const char *username, const char *password, gpointer data)
29 return !strcmp (username, "user") && !strcmp (password, "password");
33 forget_close (SoupMessage *msg, gpointer user_data)
35 soup_message_headers_remove (msg->response_headers, "Connection");
39 close_socket (SoupMessage *msg, gpointer user_data)
41 SoupSocket *sock = user_data;
43 soup_socket_disconnect (sock);
47 timeout_socket (SoupSocket *sock, gpointer user_data)
49 soup_socket_disconnect (sock);
53 timeout_request_started (SoupServer *server, SoupMessage *msg,
54 SoupClientContext *client, gpointer user_data)
57 GMainContext *context = soup_server_get_async_context (server);
60 sock = soup_client_context_get_socket (client);
61 readable = g_signal_connect (sock, "readable",
62 G_CALLBACK (timeout_socket), NULL);
63 while (soup_socket_is_connected (sock))
64 g_main_context_iteration (context, TRUE);
65 g_signal_handler_disconnect (sock, readable);
66 g_signal_handlers_disconnect_by_func (server, timeout_request_started, NULL);
70 setup_timeout_persistent (SoupServer *server, SoupSocket *sock)
75 /* In order for the test to work correctly, we have to
76 * close the connection *after* the client side writes
77 * the request. To ensure that this happens reliably,
78 * regardless of thread scheduling, we:
80 * 1. Try to read off the socket now, knowing it will
81 * fail (since the client is waiting for us to
82 * return a response). This will cause it to
83 * emit "readable" later.
84 * 2. Connect to the server's request-started signal.
85 * 3. Run an inner main loop from that signal handler
86 * until the socket emits "readable". (If we don't
87 * do this then it's possible the client's next
88 * request would be ready before we returned to
89 * the main loop, and so the signal would never be
91 * 4. Close the socket.
94 soup_socket_read (sock, buf, 1, &nread, NULL, NULL);
95 g_signal_connect (server, "request-started",
96 G_CALLBACK (timeout_request_started), NULL);
100 timeout_finish_message (gpointer msg)
102 SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
104 soup_server_unpause_message (server, msg);
109 server_callback (SoupServer *server, SoupMessage *msg,
110 const char *path, GHashTable *query,
111 SoupClientContext *context, gpointer data)
113 SoupURI *uri = soup_message_get_uri (msg);
115 /* The way this gets used in the tests, we don't actually
116 * need to hold it through the whole function, so it's simpler
117 * to just release it right away.
119 g_mutex_lock (server_mutex);
120 g_mutex_unlock (server_mutex);
122 soup_message_headers_append (msg->response_headers,
123 "X-Handled-By", "server_callback");
125 if (!strcmp (path, "*")) {
126 debug_printf (1, " default server_callback got request for '*'!\n");
128 soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
132 if (msg->method != SOUP_METHOD_GET) {
133 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
137 if (!strcmp (path, "/redirect")) {
138 soup_message_set_status (msg, SOUP_STATUS_FOUND);
139 soup_message_headers_append (msg->response_headers,
140 /* Kids: don't try this at home!
141 * RFC2616 says to use an
148 if (g_str_has_prefix (path, "/content-length/")) {
149 gboolean too_long = strcmp (path, "/content-length/long") == 0;
150 gboolean no_close = strcmp (path, "/content-length/noclose") == 0;
152 soup_message_set_status (msg, SOUP_STATUS_OK);
153 soup_message_set_response (msg, "text/plain",
154 SOUP_MEMORY_STATIC, "foobar", 6);
156 soup_message_headers_set_content_length (msg->response_headers, 9);
157 soup_message_headers_append (msg->response_headers,
158 "Connection", "close");
163 /* soup-message-io will wait for us to add
164 * another chunk after the first, to fill out
165 * the declared Content-Length. Instead, we
166 * forcibly close the socket at that point.
168 sock = soup_client_context_get_socket (context);
169 g_signal_connect (msg, "wrote-chunk",
170 G_CALLBACK (close_socket), sock);
171 } else if (no_close) {
172 /* Remove the 'Connection: close' after writing
173 * the headers, so that when we check it after
174 * writing the body, we'll think we aren't
175 * supposed to close it.
177 g_signal_connect (msg, "wrote-headers",
178 G_CALLBACK (forget_close), NULL);
183 if (!strcmp (path, "/timeout-persistent")) {
186 sock = soup_client_context_get_socket (context);
187 setup_timeout_persistent (server, sock);
190 if (!strcmp (path, "/slow")) {
191 soup_server_pause_message (server, msg);
192 g_object_set_data (G_OBJECT (msg), "server", server);
193 soup_add_timeout (soup_server_get_async_context (server),
194 1000, timeout_finish_message, msg);
197 soup_message_set_status (msg, SOUP_STATUS_OK);
198 if (!strcmp (uri->host, "foo")) {
199 soup_message_set_response (msg, "text/plain",
200 SOUP_MEMORY_STATIC, "foo-index", 9);
203 soup_message_set_response (msg, "text/plain",
204 SOUP_MEMORY_STATIC, "index", 5);
210 server_star_callback (SoupServer *server, SoupMessage *msg,
211 const char *path, GHashTable *query,
212 SoupClientContext *context, gpointer data)
214 soup_message_headers_append (msg->response_headers,
215 "X-Handled-By", "star_callback");
217 if (strcmp (path, "*") != 0) {
218 debug_printf (1, " server_star_callback got request for '%s'!\n", path);
220 soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
224 if (msg->method != SOUP_METHOD_OPTIONS) {
225 soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
229 soup_message_set_status (msg, SOUP_STATUS_OK);
232 /* Host header handling: client must be able to override the default
233 * value, server must be able to recognize different Host values.
239 SoupSession *session;
240 SoupMessage *one, *two;
242 debug_printf (1, "Host handling\n");
244 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
246 one = soup_message_new_from_uri ("GET", base_uri);
247 two = soup_message_new_from_uri ("GET", base_uri);
248 soup_message_headers_replace (two->request_headers, "Host", "foo");
250 soup_session_send_message (session, one);
251 soup_session_send_message (session, two);
253 soup_test_session_abort_unref (session);
255 if (!SOUP_STATUS_IS_SUCCESSFUL (one->status_code)) {
256 debug_printf (1, " Message 1 failed: %d %s\n",
257 one->status_code, one->reason_phrase);
259 } else if (strcmp (one->response_body->data, "index") != 0) {
260 debug_printf (1, " Unexpected response to message 1: '%s'\n",
261 one->response_body->data);
264 g_object_unref (one);
266 if (!SOUP_STATUS_IS_SUCCESSFUL (two->status_code)) {
267 debug_printf (1, " Message 2 failed: %d %s\n",
268 two->status_code, two->reason_phrase);
270 } else if (strcmp (two->response_body->data, "foo-index") != 0) {
271 debug_printf (1, " Unexpected response to message 2: '%s'\n",
272 two->response_body->data);
275 g_object_unref (two);
278 /* Dropping the application's ref on the session from a callback
279 * should not cause the session to be freed at an incorrect time.
280 * (This test will crash if it fails.) #533473
283 cu_one_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
285 debug_printf (2, " Message 1 completed\n");
286 if (msg->status_code != SOUP_STATUS_CANT_CONNECT) {
287 debug_printf (1, " Unexpected status on Message 1: %d %s\n",
288 msg->status_code, msg->reason_phrase);
291 g_object_unref (session);
295 cu_idle_quit (gpointer loop)
297 g_main_loop_quit (loop);
302 cu_two_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
304 debug_printf (2, " Message 2 completed\n");
305 if (msg->status_code != SOUP_STATUS_CANT_CONNECT) {
306 debug_printf (1, " Unexpected status on Message 2: %d %s\n",
307 msg->status_code, msg->reason_phrase);
310 g_idle_add (cu_idle_quit, loop);
314 do_callback_unref_test (void)
316 SoupServer *bad_server;
318 SoupSession *session;
319 SoupMessage *one, *two;
323 debug_printf (1, "\nCallback unref handling\n");
325 /* Get a guaranteed-bad URI */
326 addr = soup_address_new ("127.0.0.1", SOUP_ADDRESS_ANY_PORT);
327 soup_address_resolve_sync (addr, NULL);
328 bad_server = soup_server_new (SOUP_SERVER_INTERFACE, addr,
330 g_object_unref (addr);
332 bad_uri = g_strdup_printf ("http://127.0.0.1:%u/",
333 soup_server_get_port (bad_server));
334 g_object_unref (bad_server);
336 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
337 g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
339 loop = g_main_loop_new (NULL, TRUE);
341 one = soup_message_new ("GET", bad_uri);
342 g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
343 two = soup_message_new ("GET", bad_uri);
344 g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
347 soup_session_queue_message (session, one, cu_one_completed, loop);
348 soup_session_queue_message (session, two, cu_two_completed, loop);
350 g_main_loop_run (loop);
351 g_main_loop_unref (loop);
354 g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
355 debug_printf (1, " Session not destroyed?\n");
357 g_object_unref (session);
360 g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
361 debug_printf (1, " Message 1 not destroyed?\n");
363 g_object_unref (one);
366 g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
367 debug_printf (1, " Message 2 not destroyed?\n");
369 g_object_unref (two);
372 /* Otherwise, if we haven't crashed, we're ok. */
375 /* SoupSession should clean up all signal handlers on a message after
376 * it is finished, allowing the message to be reused if desired.
380 ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_ids)
384 for (i = 0; i < n_signal_ids; i++) {
385 if (g_signal_handler_find (msg, G_SIGNAL_MATCH_ID, signal_ids[i],
386 0, NULL, NULL, NULL)) {
387 debug_printf (1, " Message has handler for '%s'\n",
388 g_signal_name (signal_ids[i]));
395 reuse_test_authenticate (SoupSession *session, SoupMessage *msg,
396 SoupAuth *auth, gboolean retrying)
398 /* Get it wrong the first time, then succeed */
400 soup_auth_authenticate (auth, "user", "wrong password");
402 soup_auth_authenticate (auth, "user", "password");
406 do_msg_reuse_test (void)
408 SoupSession *session;
411 guint *signal_ids, n_signal_ids;
413 debug_printf (1, "\nSoupMessage reuse\n");
415 signal_ids = g_signal_list_ids (SOUP_TYPE_MESSAGE, &n_signal_ids);
417 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
418 g_signal_connect (session, "authenticate",
419 G_CALLBACK (reuse_test_authenticate), NULL);
421 debug_printf (1, " First message\n");
422 msg = soup_message_new_from_uri ("GET", base_uri);
423 soup_session_send_message (session, msg);
424 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
426 debug_printf (1, " Redirect message\n");
427 uri = soup_uri_new_with_base (base_uri, "/redirect");
428 soup_message_set_uri (msg, uri);
430 soup_session_send_message (session, msg);
431 if (!soup_uri_equal (soup_message_get_uri (msg), base_uri)) {
432 debug_printf (1, " Message did not get redirected!\n");
435 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
437 debug_printf (1, " Auth message\n");
438 uri = soup_uri_new_with_base (base_uri, "/auth");
439 soup_message_set_uri (msg, uri);
441 soup_session_send_message (session, msg);
442 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
443 debug_printf (1, " Message did not get authenticated!\n");
446 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
448 /* One last try to make sure the auth stuff got cleaned up */
449 debug_printf (1, " Last message\n");
450 soup_message_set_uri (msg, base_uri);
451 soup_session_send_message (session, msg);
452 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
454 soup_test_session_abort_unref (session);
455 g_object_unref (msg);
459 /* Server handlers for "*" work but are separate from handlers for
460 * all other URIs. #590751
465 SoupSession *session;
468 const char *handled_by;
470 debug_printf (1, "\nOPTIONS *\n");
472 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
473 star_uri = soup_uri_copy (base_uri);
474 soup_uri_set_path (star_uri, "*");
476 debug_printf (1, " Testing with no handler\n");
477 msg = soup_message_new_from_uri ("OPTIONS", star_uri);
478 soup_session_send_message (session, msg);
480 if (msg->status_code != SOUP_STATUS_NOT_FOUND) {
481 debug_printf (1, " Unexpected response: %d %s\n",
482 msg->status_code, msg->reason_phrase);
485 handled_by = soup_message_headers_get_one (msg->response_headers,
488 /* Should have been rejected by SoupServer directly */
489 debug_printf (1, " Message reached handler '%s'\n",
493 g_object_unref (msg);
495 soup_server_add_handler (server, "*", server_star_callback, NULL, NULL);
497 debug_printf (1, " Testing with handler\n");
498 msg = soup_message_new_from_uri ("OPTIONS", star_uri);
499 soup_session_send_message (session, msg);
501 if (msg->status_code != SOUP_STATUS_OK) {
502 debug_printf (1, " Unexpected response: %d %s\n",
503 msg->status_code, msg->reason_phrase);
506 handled_by = soup_message_headers_get_one (msg->response_headers,
509 debug_printf (1, " Message did not reach handler!\n");
511 } else if (strcmp (handled_by, "star_callback") != 0) {
512 debug_printf (1, " Message reached incorrect handler '%s'\n",
516 g_object_unref (msg);
518 soup_test_session_abort_unref (session);
519 soup_uri_free (star_uri);
522 /* Handle unexpectedly-early aborts. #596074, #618641 */
524 ea_msg_completed_one (SoupSession *session, SoupMessage *msg, gpointer loop)
526 debug_printf (2, " Message 1 completed\n");
527 if (msg->status_code != SOUP_STATUS_CANCELLED) {
528 debug_printf (1, " Unexpected status on Message 1: %d %s\n",
529 msg->status_code, msg->reason_phrase);
532 g_main_loop_quit (loop);
536 ea_abort_session (gpointer session)
538 soup_session_abort (session);
543 ea_connection_state_changed (GObject *conn, GParamSpec *pspec, gpointer session)
545 SoupConnectionState state;
547 g_object_get (conn, "state", &state, NULL);
548 if (state == SOUP_CONNECTION_CONNECTING) {
549 g_idle_add_full (G_PRIORITY_HIGH,
552 g_signal_handlers_disconnect_by_func (conn, ea_connection_state_changed, session);
557 ea_connection_created (SoupSession *session, GObject *conn, gpointer user_data)
559 g_signal_connect (conn, "notify::state",
560 G_CALLBACK (ea_connection_state_changed), session);
561 g_signal_handlers_disconnect_by_func (session, ea_connection_created, user_data);
565 do_early_abort_test (void)
567 SoupSession *session;
569 GMainContext *context;
572 debug_printf (1, "\nAbort with pending connection\n");
574 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
575 msg = soup_message_new_from_uri ("GET", base_uri);
577 context = g_main_context_default ();
578 loop = g_main_loop_new (context, TRUE);
579 soup_session_queue_message (session, msg, ea_msg_completed_one, loop);
580 g_main_context_iteration (context, FALSE);
582 soup_session_abort (session);
583 while (g_main_context_pending (context))
584 g_main_context_iteration (context, FALSE);
585 g_main_loop_unref (loop);
586 soup_test_session_abort_unref (session);
588 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
589 msg = soup_message_new_from_uri ("GET", base_uri);
591 g_signal_connect (session, "connection-created",
592 G_CALLBACK (ea_connection_created), NULL);
593 soup_session_send_message (session, msg);
594 debug_printf (2, " Message 2 completed\n");
596 if (msg->status_code != SOUP_STATUS_CANCELLED) {
597 debug_printf (1, " Unexpected response: %d %s\n",
598 msg->status_code, msg->reason_phrase);
601 g_object_unref (msg);
603 while (g_main_context_pending (context))
604 g_main_context_iteration (context, FALSE);
606 soup_test_session_abort_unref (session);
610 do_content_length_framing_test (void)
612 SoupSession *session;
614 SoupURI *request_uri;
615 goffset declared_length;
617 debug_printf (1, "\nInvalid Content-Length framing tests\n");
619 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
621 debug_printf (1, " Content-Length larger than message body length\n");
622 request_uri = soup_uri_new_with_base (base_uri, "/content-length/long");
623 msg = soup_message_new_from_uri ("GET", request_uri);
624 soup_session_send_message (session, msg);
625 if (msg->status_code != SOUP_STATUS_OK) {
626 debug_printf (1, " Unexpected response: %d %s\n",
627 msg->status_code, msg->reason_phrase);
630 declared_length = soup_message_headers_get_content_length (msg->response_headers);
631 debug_printf (2, " Content-Length: %lu, body: %s\n",
632 (gulong)declared_length, msg->response_body->data);
633 if (msg->response_body->length >= declared_length) {
634 debug_printf (1, " Body length %lu >= declared length %lu\n",
635 (gulong)msg->response_body->length,
636 (gulong)declared_length);
640 soup_uri_free (request_uri);
641 g_object_unref (msg);
643 debug_printf (1, " Server claims 'Connection: close' but doesn't\n");
644 request_uri = soup_uri_new_with_base (base_uri, "/content-length/noclose");
645 msg = soup_message_new_from_uri ("GET", request_uri);
646 soup_session_send_message (session, msg);
647 if (msg->status_code != SOUP_STATUS_OK) {
648 debug_printf (1, " Unexpected response: %d %s\n",
649 msg->status_code, msg->reason_phrase);
652 declared_length = soup_message_headers_get_content_length (msg->response_headers);
653 debug_printf (2, " Content-Length: %lu, body: %s\n",
654 (gulong)declared_length, msg->response_body->data);
655 if (msg->response_body->length != declared_length) {
656 debug_printf (1, " Body length %lu != declared length %lu\n",
657 (gulong)msg->response_body->length,
658 (gulong)declared_length);
662 soup_uri_free (request_uri);
663 g_object_unref (msg);
665 soup_test_session_abort_unref (session);
669 do_one_accept_language_test (const char *language, const char *expected_header)
671 SoupSession *session;
675 debug_printf (1, " LANGUAGE=%s\n", language);
676 g_setenv ("LANGUAGE", language, TRUE);
677 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
678 SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
680 msg = soup_message_new_from_uri ("GET", base_uri);
681 soup_session_send_message (session, msg);
682 soup_test_session_abort_unref (session);
684 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
685 debug_printf (1, " Message failed? %d %s\n",
686 msg->status_code, msg->reason_phrase);
689 val = soup_message_headers_get_list (msg->request_headers,
692 debug_printf (1, " No Accept-Language set!\n");
694 } else if (strcmp (val, expected_header) != 0) {
695 debug_printf (1, " Wrong Accept-Language: expected '%s', got '%s'\n",
696 expected_header, val);
700 g_object_unref (msg);
704 do_accept_language_test (void)
706 const char *orig_language;
708 debug_printf (1, "\nAutomatic Accept-Language processing\n");
710 orig_language = g_getenv ("LANGUAGE");
711 do_one_accept_language_test ("C", "en");
712 do_one_accept_language_test ("fr_FR", "fr-fr, fr;q=0.9");
713 do_one_accept_language_test ("fr_FR:de:en_US", "fr-fr, fr;q=0.9, de;q=0.8, en-us;q=0.7, en;q=0.6");
716 g_setenv ("LANGUAGE", orig_language, TRUE);
718 g_unsetenv ("LANGUAGE");
722 timeout_test_request_started (SoupSession *session, SoupMessage *msg,
723 SoupSocket *socket, gpointer user_data)
725 SoupSocket **sockets = user_data;
728 debug_printf (2, " msg %p => socket %p\n", msg, socket);
729 for (i = 0; i < 4; i++) {
731 /* We ref the socket to make sure that even if
732 * it gets disconnected, it doesn't get freed,
733 * since our checks would get messed up if the
734 * slice allocator reused the same address for
735 * two consecutive sockets.
737 sockets[i] = g_object_ref (socket);
742 debug_printf (1, " socket queue overflowed!\n");
744 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
748 do_timeout_test_for_session (SoupSession *session)
751 SoupSocket *sockets[4] = { NULL, NULL, NULL, NULL };
752 SoupURI *timeout_uri;
755 g_signal_connect (session, "request-started",
756 G_CALLBACK (timeout_test_request_started),
759 debug_printf (1, " First message\n");
760 timeout_uri = soup_uri_new_with_base (base_uri, "/timeout-persistent");
761 msg = soup_message_new_from_uri ("GET", timeout_uri);
762 soup_uri_free (timeout_uri);
763 soup_session_send_message (session, msg);
764 if (msg->status_code != SOUP_STATUS_OK) {
765 debug_printf (1, " Unexpected response: %d %s\n",
766 msg->status_code, msg->reason_phrase);
770 debug_printf (1, " Message was retried??\n");
772 sockets[1] = sockets[2] = sockets[3] = NULL;
774 g_object_unref (msg);
776 debug_printf (1, " Second message\n");
777 msg = soup_message_new_from_uri ("GET", base_uri);
778 soup_session_send_message (session, msg);
779 if (msg->status_code != SOUP_STATUS_OK) {
780 debug_printf (1, " Unexpected response: %d %s\n",
781 msg->status_code, msg->reason_phrase);
784 if (sockets[1] != sockets[0]) {
785 debug_printf (1, " Message was not retried on existing connection\n");
787 } else if (!sockets[2]) {
788 debug_printf (1, " Message was not retried after disconnect\n");
790 } else if (sockets[2] == sockets[1]) {
791 debug_printf (1, " Message was retried on closed connection??\n");
793 } else if (sockets[3]) {
794 debug_printf (1, " Message was retried again??\n");
797 g_object_unref (msg);
799 for (i = 0; sockets[i]; i++)
800 g_object_unref (sockets[i]);
804 do_persistent_connection_timeout_test (void)
806 SoupSession *session;
808 debug_printf (1, "\nUnexpected timing out of persistent connections\n");
810 debug_printf (1, " Async session\n");
811 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
812 do_timeout_test_for_session (session);
813 soup_test_session_abort_unref (session);
815 debug_printf (1, " Sync session\n");
816 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
817 do_timeout_test_for_session (session);
818 soup_test_session_abort_unref (session);
821 static GMainLoop *max_conns_loop;
822 static int msgs_done;
824 #define TEST_CONNS (MAX_CONNS * 2)
827 idle_start_server (gpointer data)
829 g_mutex_unlock (server_mutex);
834 quit_loop (gpointer data)
836 g_main_loop_quit (max_conns_loop);
841 max_conns_request_started (SoupSession *session, SoupMessage *msg,
842 SoupSocket *socket, gpointer user_data)
844 if (++msgs_done == MAX_CONNS)
845 g_timeout_add (100, quit_loop, NULL);
849 max_conns_message_complete (SoupSession *session, SoupMessage *msg, gpointer user_data)
851 if (++msgs_done == TEST_CONNS)
852 g_main_loop_quit (max_conns_loop);
856 do_max_conns_test_for_session (SoupSession *session)
858 SoupMessage *msgs[TEST_CONNS];
862 max_conns_loop = g_main_loop_new (NULL, TRUE);
864 g_mutex_lock (server_mutex);
866 g_signal_connect (session, "request-started",
867 G_CALLBACK (max_conns_request_started), NULL);
869 for (i = 0; i < TEST_CONNS; i++) {
870 msgs[i] = soup_message_new_from_uri ("GET", base_uri);
871 g_object_ref (msgs[i]);
872 soup_session_queue_message (session, msgs[i],
873 max_conns_message_complete, NULL);
876 g_main_loop_run (max_conns_loop);
877 if (msgs_done != MAX_CONNS) {
878 debug_printf (1, " Queued %d connections out of max %d?",
879 msgs_done, MAX_CONNS);
882 g_signal_handlers_disconnect_by_func (session, max_conns_request_started, NULL);
885 g_idle_add (idle_start_server, NULL);
886 timeout_id = g_timeout_add (1000, quit_loop, NULL);
887 g_main_loop_run (max_conns_loop);
889 for (i = 0; i < TEST_CONNS; i++) {
890 if (!SOUP_STATUS_IS_SUCCESSFUL (msgs[i]->status_code)) {
891 debug_printf (1, " Message %d failed? %d %s\n",
892 i, msgs[i]->status_code,
893 msgs[i]->reason_phrase ? msgs[i]->reason_phrase : "-");
898 if (msgs_done != TEST_CONNS) {
899 /* Clean up so we don't get a spurious "Leaked
902 for (i = 0; i < TEST_CONNS; i++)
903 soup_session_cancel_message (session, msgs[i], SOUP_STATUS_CANCELLED);
904 g_main_loop_run (max_conns_loop);
905 g_source_remove (timeout_id);
908 g_main_loop_unref (max_conns_loop);
910 for (i = 0; i < TEST_CONNS; i++)
911 g_object_unref (msgs[i]);
915 do_max_conns_test (void)
917 SoupSession *session;
919 debug_printf (1, "\nExceeding max-conns\n");
921 debug_printf (1, " Async session\n");
922 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
923 SOUP_SESSION_MAX_CONNS, MAX_CONNS,
925 do_max_conns_test_for_session (session);
926 soup_test_session_abort_unref (session);
928 debug_printf (1, " Sync session\n");
929 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
930 SOUP_SESSION_MAX_CONNS, MAX_CONNS,
932 do_max_conns_test_for_session (session);
933 soup_test_session_abort_unref (session);
937 cancel_message_timeout (gpointer msg)
939 SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
941 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
942 g_object_unref (msg);
943 g_object_unref (session);
948 cancel_message_thread (gpointer msg)
950 SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
952 g_usleep (100000); /* .1s */
953 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
954 g_object_unref (msg);
955 g_object_unref (session);
960 do_cancel_while_reading_test_for_session (SoupSession *session)
963 GThread *thread = NULL;
966 uri = soup_uri_new_with_base (base_uri, "/slow");
967 msg = soup_message_new_from_uri ("GET", uri);
970 g_object_set_data (G_OBJECT (msg), "session", session);
972 g_object_ref (session);
973 if (SOUP_IS_SESSION_ASYNC (session))
974 g_timeout_add (100, cancel_message_timeout, msg);
976 thread = g_thread_create (cancel_message_thread, msg, TRUE, NULL);
978 soup_session_send_message (session, msg);
980 if (msg->status_code != SOUP_STATUS_CANCELLED) {
981 debug_printf (1, " FAILED: %d %s (expected Cancelled)\n",
982 msg->status_code, msg->reason_phrase);
985 g_object_unref (msg);
988 g_thread_join (thread);
992 do_cancel_while_reading_test (void)
994 SoupSession *session;
996 debug_printf (1, "\nCancelling message while reading response\n");
998 debug_printf (1, " Async session\n");
999 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
1000 do_cancel_while_reading_test_for_session (session);
1001 soup_test_session_abort_unref (session);
1003 debug_printf (1, " Sync session\n");
1004 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
1005 do_cancel_while_reading_test_for_session (session);
1006 soup_test_session_abort_unref (session);
1010 main (int argc, char **argv)
1012 SoupAuthDomain *auth_domain;
1014 test_init (argc, argv, NULL);
1016 server_mutex = g_mutex_new ();
1018 server = soup_test_server_new (TRUE);
1019 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
1020 base_uri = soup_uri_new ("http://127.0.0.1/");
1021 soup_uri_set_port (base_uri, soup_server_get_port (server));
1023 auth_domain = soup_auth_domain_basic_new (
1024 SOUP_AUTH_DOMAIN_REALM, "misc-test",
1025 SOUP_AUTH_DOMAIN_ADD_PATH, "/auth",
1026 SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, auth_callback,
1028 soup_server_add_auth_domain (server, auth_domain);
1029 g_object_unref (auth_domain);
1032 do_callback_unref_test ();
1033 do_msg_reuse_test ();
1035 do_early_abort_test ();
1036 do_content_length_framing_test ();
1037 do_accept_language_test ();
1038 do_persistent_connection_timeout_test ();
1039 do_max_conns_test ();
1040 do_cancel_while_reading_test ();
1042 soup_uri_free (base_uri);
1043 soup_test_server_quit_unref (server);