1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright 2007-2012 Red Hat, Inc.
6 #include "test-utils.h"
8 SoupServer *server, *ssl_server;
9 SoupURI *base_uri, *ssl_base_uri;
12 auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg,
13 const char *username, const char *password, gpointer data)
15 return !strcmp (username, "user") && !strcmp (password, "password");
19 timeout_finish_message (gpointer msg)
21 SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
23 soup_server_unpause_message (server, msg);
28 server_callback (SoupServer *server, SoupMessage *msg,
29 const char *path, GHashTable *query,
30 SoupClientContext *context, gpointer data)
32 SoupURI *uri = soup_message_get_uri (msg);
33 const char *server_protocol = data;
35 soup_message_headers_append (msg->response_headers,
36 "X-Handled-By", "server_callback");
38 if (!strcmp (path, "*")) {
39 debug_printf (1, " default server_callback got request for '*'!\n");
41 soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
45 if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
46 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
50 if (!strcmp (path, "/redirect")) {
51 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
55 if (!strcmp (path, "/alias-redirect")) {
56 SoupURI *redirect_uri;
57 char *redirect_string;
58 const char *redirect_protocol;
60 redirect_protocol = soup_message_headers_get_one (msg->request_headers, "X-Redirect-Protocol");
62 redirect_uri = soup_uri_copy (uri);
63 soup_uri_set_scheme (redirect_uri, "foo");
64 if (!g_strcmp0 (redirect_protocol, "https"))
65 soup_uri_set_port (redirect_uri, ssl_base_uri->port);
67 soup_uri_set_port (redirect_uri, base_uri->port);
68 soup_uri_set_path (redirect_uri, "/alias-redirected");
69 redirect_string = soup_uri_to_string (redirect_uri, FALSE);
71 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string);
72 g_free (redirect_string);
73 soup_uri_free (redirect_uri);
75 } else if (!strcmp (path, "/alias-redirected")) {
76 soup_message_set_status (msg, SOUP_STATUS_OK);
77 soup_message_headers_append (msg->response_headers,
78 "X-Redirected-Protocol",
83 if (!strcmp (path, "/slow")) {
84 soup_server_pause_message (server, msg);
85 g_object_set_data (G_OBJECT (msg), "server", server);
86 soup_add_timeout (soup_server_get_async_context (server),
87 1000, timeout_finish_message, msg);
90 soup_message_set_status (msg, SOUP_STATUS_OK);
91 if (!strcmp (uri->host, "foo")) {
92 soup_message_set_response (msg, "text/plain",
93 SOUP_MEMORY_STATIC, "foo-index", 9);
96 soup_message_set_response (msg, "text/plain",
97 SOUP_MEMORY_STATIC, "index", 5);
103 server_star_callback (SoupServer *server, SoupMessage *msg,
104 const char *path, GHashTable *query,
105 SoupClientContext *context, gpointer data)
107 soup_message_headers_append (msg->response_headers,
108 "X-Handled-By", "star_callback");
110 if (strcmp (path, "*") != 0) {
111 debug_printf (1, " server_star_callback got request for '%s'!\n", path);
113 soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR);
117 if (msg->method != SOUP_METHOD_OPTIONS) {
118 soup_message_set_status (msg, SOUP_STATUS_METHOD_NOT_ALLOWED);
122 soup_message_set_status (msg, SOUP_STATUS_OK);
125 /* Host header handling: client must be able to override the default
126 * value, server must be able to recognize different Host values.
132 SoupSession *session;
133 SoupMessage *one, *two;
135 debug_printf (1, "Host handling\n");
137 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
139 one = soup_message_new_from_uri ("GET", base_uri);
140 two = soup_message_new_from_uri ("GET", base_uri);
141 soup_message_headers_replace (two->request_headers, "Host", "foo");
143 soup_session_send_message (session, one);
144 soup_session_send_message (session, two);
146 soup_test_session_abort_unref (session);
148 if (!SOUP_STATUS_IS_SUCCESSFUL (one->status_code)) {
149 debug_printf (1, " Message 1 failed: %d %s\n",
150 one->status_code, one->reason_phrase);
152 } else if (strcmp (one->response_body->data, "index") != 0) {
153 debug_printf (1, " Unexpected response to message 1: '%s'\n",
154 one->response_body->data);
157 g_object_unref (one);
159 if (!SOUP_STATUS_IS_SUCCESSFUL (two->status_code)) {
160 debug_printf (1, " Message 2 failed: %d %s\n",
161 two->status_code, two->reason_phrase);
163 } else if (strcmp (two->response_body->data, "foo-index") != 0) {
164 debug_printf (1, " Unexpected response to message 2: '%s'\n",
165 two->response_body->data);
168 g_object_unref (two);
171 /* Dropping the application's ref on the session from a callback
172 * should not cause the session to be freed at an incorrect time.
173 * (This test will crash if it fails.) #533473
176 cu_one_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
178 debug_printf (2, " Message 1 completed\n");
179 if (msg->status_code != SOUP_STATUS_CANT_CONNECT) {
180 debug_printf (1, " Unexpected status on Message 1: %d %s\n",
181 msg->status_code, msg->reason_phrase);
184 g_object_unref (session);
188 cu_idle_quit (gpointer loop)
190 g_main_loop_quit (loop);
195 cu_two_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
197 debug_printf (2, " Message 2 completed\n");
198 if (msg->status_code != SOUP_STATUS_CANT_CONNECT) {
199 debug_printf (1, " Unexpected status on Message 2: %d %s\n",
200 msg->status_code, msg->reason_phrase);
203 g_idle_add (cu_idle_quit, loop);
207 do_callback_unref_test (void)
209 SoupServer *bad_server;
211 SoupSession *session;
212 SoupMessage *one, *two;
216 debug_printf (1, "\nCallback unref handling (msg api)\n");
218 /* Get a guaranteed-bad URI */
219 addr = soup_address_new ("127.0.0.1", SOUP_ADDRESS_ANY_PORT);
220 soup_address_resolve_sync (addr, NULL);
221 bad_server = soup_server_new (SOUP_SERVER_INTERFACE, addr,
223 g_object_unref (addr);
225 bad_uri = g_strdup_printf ("http://127.0.0.1:%u/",
226 soup_server_get_port (bad_server));
227 g_object_unref (bad_server);
229 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
230 g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
232 loop = g_main_loop_new (NULL, TRUE);
234 one = soup_message_new ("GET", bad_uri);
235 g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
236 two = soup_message_new ("GET", bad_uri);
237 g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
240 soup_session_queue_message (session, one, cu_one_completed, loop);
241 soup_session_queue_message (session, two, cu_two_completed, loop);
243 g_main_loop_run (loop);
244 g_main_loop_unref (loop);
247 g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
248 debug_printf (1, " Session not destroyed?\n");
250 g_object_unref (session);
253 g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
254 debug_printf (1, " Message 1 not destroyed?\n");
256 g_object_unref (one);
259 g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
260 debug_printf (1, " Message 2 not destroyed?\n");
262 g_object_unref (two);
265 /* Otherwise, if we haven't crashed, we're ok. */
269 cur_one_completed (GObject *source, GAsyncResult *result, gpointer session)
271 SoupRequest *one = SOUP_REQUEST (source);
272 GError *error = NULL;
274 debug_printf (2, " Request 1 completed\n");
275 if (soup_request_send_finish (one, result, &error)) {
276 debug_printf (1, " Request 1 succeeded?\n");
278 } else if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT)) {
279 debug_printf (1, " Unexpected error on Request 1: %s\n",
283 g_clear_error (&error);
285 g_object_unref (session);
289 cur_idle_quit (gpointer loop)
291 g_main_loop_quit (loop);
296 cur_two_completed (GObject *source, GAsyncResult *result, gpointer loop)
298 SoupRequest *two = SOUP_REQUEST (source);
299 GError *error = NULL;
301 debug_printf (2, " Request 2 completed\n");
302 if (soup_request_send_finish (two, result, &error)) {
303 debug_printf (1, " Request 2 succeeded?\n");
305 } else if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANT_CONNECT)) {
306 debug_printf (1, " Unexpected error on Request 2: %s\n",
310 g_clear_error (&error);
312 g_idle_add (cur_idle_quit, loop);
316 do_callback_unref_req_test (void)
318 SoupServer *bad_server;
320 SoupSession *session;
321 SoupRequester *requester;
322 SoupRequest *one, *two;
326 debug_printf (1, "\nCallback unref handling (request api)\n");
328 /* Get a guaranteed-bad URI */
329 addr = soup_address_new ("127.0.0.1", SOUP_ADDRESS_ANY_PORT);
330 soup_address_resolve_sync (addr, NULL);
331 bad_server = soup_server_new (SOUP_SERVER_INTERFACE, addr,
333 g_object_unref (addr);
335 bad_uri = g_strdup_printf ("http://127.0.0.1:%u/",
336 soup_server_get_port (bad_server));
337 g_object_unref (bad_server);
339 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
340 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
341 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
343 g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
345 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
347 loop = g_main_loop_new (NULL, TRUE);
349 one = soup_requester_request (requester, bad_uri, NULL);
350 g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
351 two = soup_requester_request (requester, bad_uri, NULL);
352 g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
355 soup_request_send_async (one, NULL, cur_one_completed, session);
356 g_object_unref (one);
357 soup_request_send_async (two, NULL, cur_two_completed, loop);
358 g_object_unref (two);
360 g_main_loop_run (loop);
361 g_main_loop_unref (loop);
364 g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
365 debug_printf (1, " Session not destroyed?\n");
367 g_object_unref (session);
370 g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
371 debug_printf (1, " Request 1 not destroyed?\n");
373 g_object_unref (one);
376 g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
377 debug_printf (1, " Request 2 not destroyed?\n");
379 g_object_unref (two);
382 /* Otherwise, if we haven't crashed, we're ok. */
385 /* SoupSession should clean up all signal handlers on a message after
386 * it is finished, allowing the message to be reused if desired.
390 ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_ids)
394 for (i = 0; i < n_signal_ids; i++) {
395 if (g_signal_handler_find (msg, G_SIGNAL_MATCH_ID, signal_ids[i],
396 0, NULL, NULL, NULL)) {
397 debug_printf (1, " Message has handler for '%s'\n",
398 g_signal_name (signal_ids[i]));
405 reuse_test_authenticate (SoupSession *session, SoupMessage *msg,
406 SoupAuth *auth, gboolean retrying)
408 /* Get it wrong the first time, then succeed */
410 soup_auth_authenticate (auth, "user", "wrong password");
412 soup_auth_authenticate (auth, "user", "password");
416 do_msg_reuse_test (void)
418 SoupSession *session;
421 guint *signal_ids, n_signal_ids;
423 debug_printf (1, "\nSoupMessage reuse\n");
425 signal_ids = g_signal_list_ids (SOUP_TYPE_MESSAGE, &n_signal_ids);
427 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
428 g_signal_connect (session, "authenticate",
429 G_CALLBACK (reuse_test_authenticate), NULL);
431 debug_printf (1, " First message\n");
432 msg = soup_message_new_from_uri ("GET", base_uri);
433 soup_session_send_message (session, msg);
434 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
436 debug_printf (1, " Redirect message\n");
437 uri = soup_uri_new_with_base (base_uri, "/redirect");
438 soup_message_set_uri (msg, uri);
440 soup_session_send_message (session, msg);
441 if (!soup_uri_equal (soup_message_get_uri (msg), base_uri)) {
442 debug_printf (1, " Message did not get redirected!\n");
445 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
447 debug_printf (1, " Auth message\n");
448 uri = soup_uri_new_with_base (base_uri, "/auth");
449 soup_message_set_uri (msg, uri);
451 soup_session_send_message (session, msg);
452 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
453 debug_printf (1, " Message did not get authenticated!\n");
456 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
458 /* One last try to make sure the auth stuff got cleaned up */
459 debug_printf (1, " Last message\n");
460 soup_message_set_uri (msg, base_uri);
461 soup_session_send_message (session, msg);
462 ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
464 soup_test_session_abort_unref (session);
465 g_object_unref (msg);
469 /* Server handlers for "*" work but are separate from handlers for
470 * all other URIs. #590751
475 SoupSession *session;
478 const char *handled_by;
480 debug_printf (1, "\nOPTIONS *\n");
482 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
483 star_uri = soup_uri_copy (base_uri);
484 soup_uri_set_path (star_uri, "*");
486 debug_printf (1, " Testing with no handler\n");
487 msg = soup_message_new_from_uri ("OPTIONS", star_uri);
488 soup_session_send_message (session, msg);
490 if (msg->status_code != SOUP_STATUS_NOT_FOUND) {
491 debug_printf (1, " Unexpected response: %d %s\n",
492 msg->status_code, msg->reason_phrase);
495 handled_by = soup_message_headers_get_one (msg->response_headers,
498 /* Should have been rejected by SoupServer directly */
499 debug_printf (1, " Message reached handler '%s'\n",
503 g_object_unref (msg);
505 soup_server_add_handler (server, "*", server_star_callback, NULL, NULL);
507 debug_printf (1, " Testing with handler\n");
508 msg = soup_message_new_from_uri ("OPTIONS", star_uri);
509 soup_session_send_message (session, msg);
511 if (msg->status_code != SOUP_STATUS_OK) {
512 debug_printf (1, " Unexpected response: %d %s\n",
513 msg->status_code, msg->reason_phrase);
516 handled_by = soup_message_headers_get_one (msg->response_headers,
519 debug_printf (1, " Message did not reach handler!\n");
521 } else if (strcmp (handled_by, "star_callback") != 0) {
522 debug_printf (1, " Message reached incorrect handler '%s'\n",
526 g_object_unref (msg);
528 soup_test_session_abort_unref (session);
529 soup_uri_free (star_uri);
532 /* Handle unexpectedly-early aborts. #596074, #618641 */
534 ea_msg_completed_one (SoupSession *session, SoupMessage *msg, gpointer loop)
536 debug_printf (2, " Message 1 completed\n");
537 if (msg->status_code != SOUP_STATUS_CANCELLED) {
538 debug_printf (1, " Unexpected status on Message 1: %d %s\n",
539 msg->status_code, msg->reason_phrase);
542 g_main_loop_quit (loop);
546 ea_abort_session (gpointer session)
548 soup_session_abort (session);
553 ea_connection_state_changed (GObject *conn, GParamSpec *pspec, gpointer session)
555 SoupConnectionState state;
557 g_object_get (conn, "state", &state, NULL);
558 if (state == SOUP_CONNECTION_CONNECTING) {
559 g_idle_add_full (G_PRIORITY_HIGH,
562 g_signal_handlers_disconnect_by_func (conn, ea_connection_state_changed, session);
567 ea_connection_created (SoupSession *session, GObject *conn, gpointer user_data)
569 g_signal_connect (conn, "notify::state",
570 G_CALLBACK (ea_connection_state_changed), session);
571 g_signal_handlers_disconnect_by_func (session, ea_connection_created, user_data);
575 ea_request_started (SoupSession *session, SoupMessage *msg, SoupSocket *socket, gpointer user_data)
577 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
581 do_early_abort_test (void)
583 SoupSession *session;
585 GMainContext *context;
588 debug_printf (1, "\nAbort with pending connection (msg api)\n");
590 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
591 msg = soup_message_new_from_uri ("GET", base_uri);
593 context = g_main_context_default ();
594 loop = g_main_loop_new (context, TRUE);
595 soup_session_queue_message (session, msg, ea_msg_completed_one, loop);
596 g_main_context_iteration (context, FALSE);
598 soup_session_abort (session);
599 while (g_main_context_pending (context))
600 g_main_context_iteration (context, FALSE);
601 g_main_loop_unref (loop);
602 soup_test_session_abort_unref (session);
604 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
605 msg = soup_message_new_from_uri ("GET", base_uri);
607 g_signal_connect (session, "connection-created",
608 G_CALLBACK (ea_connection_created), NULL);
609 soup_session_send_message (session, msg);
610 debug_printf (2, " Message 2 completed\n");
612 if (msg->status_code != SOUP_STATUS_CANCELLED) {
613 debug_printf (1, " Unexpected response: %d %s\n",
614 msg->status_code, msg->reason_phrase);
617 g_object_unref (msg);
619 while (g_main_context_pending (context))
620 g_main_context_iteration (context, FALSE);
622 soup_test_session_abort_unref (session);
624 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
625 msg = soup_message_new_from_uri ("GET", base_uri);
627 g_signal_connect (session, "request-started",
628 G_CALLBACK (ea_request_started), NULL);
629 soup_session_send_message (session, msg);
630 debug_printf (2, " Message 3 completed\n");
632 if (msg->status_code != SOUP_STATUS_CANCELLED) {
633 debug_printf (1, " Unexpected response: %d %s\n",
634 msg->status_code, msg->reason_phrase);
637 g_object_unref (msg);
639 while (g_main_context_pending (context))
640 g_main_context_iteration (context, FALSE);
642 soup_test_session_abort_unref (session);
646 ear_one_completed (GObject *source, GAsyncResult *result, gpointer user_data)
648 GError *error = NULL;
650 debug_printf (2, " Request 1 completed\n");
651 if (soup_request_send_finish (SOUP_REQUEST (source), result, &error)) {
652 debug_printf (1, " Request 1 succeeded?\n");
654 } else if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED)) {
655 debug_printf (1, " Unexpected error on Request 1: %s\n",
659 g_clear_error (&error);
663 ear_two_completed (GObject *source, GAsyncResult *result, gpointer loop)
665 GError *error = NULL;
667 debug_printf (2, " Request 2 completed\n");
668 if (soup_request_send_finish (SOUP_REQUEST (source), result, &error)) {
669 debug_printf (1, " Request 2 succeeded?\n");
671 } else if (!g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED)) {
672 debug_printf (1, " Unexpected error on Request 2: %s\n",
676 g_clear_error (&error);
678 g_main_loop_quit (loop);
682 ear_three_completed (GObject *source, GAsyncResult *result, gpointer loop)
684 GError *error = NULL;
686 debug_printf (2, " Request 3 completed\n");
687 if (soup_request_send_finish (SOUP_REQUEST (source), result, &error)) {
688 debug_printf (1, " Request 3 succeeded?\n");
690 } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
691 debug_printf (1, " Unexpected error on Request 3: %s\n",
695 g_clear_error (&error);
697 g_main_loop_quit (loop);
701 ear_request_started (SoupSession *session, SoupMessage *msg,
702 SoupSocket *socket, gpointer cancellable)
704 g_cancellable_cancel (cancellable);
708 do_early_abort_req_test (void)
710 SoupSession *session;
711 SoupRequester *requester;
713 GMainContext *context;
715 GCancellable *cancellable;
717 debug_printf (1, "\nAbort with pending connection (request api)\n");
719 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
720 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
721 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
723 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
724 req = soup_requester_request_uri (requester, base_uri, NULL);
726 context = g_main_context_default ();
727 loop = g_main_loop_new (context, TRUE);
728 soup_request_send_async (req, NULL, ear_one_completed, NULL);
729 g_object_unref (req);
730 g_main_context_iteration (context, FALSE);
732 soup_session_abort (session);
733 while (g_main_context_pending (context))
734 g_main_context_iteration (context, FALSE);
735 soup_test_session_abort_unref (session);
737 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
738 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
739 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
741 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
742 req = soup_requester_request_uri (requester, base_uri, NULL);
744 g_signal_connect (session, "connection-created",
745 G_CALLBACK (ea_connection_created), NULL);
746 soup_request_send_async (req, NULL, ear_two_completed, loop);
747 g_main_loop_run (loop);
748 g_object_unref (req);
750 while (g_main_context_pending (context))
751 g_main_context_iteration (context, FALSE);
753 soup_test_session_abort_unref (session);
755 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
756 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
757 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
759 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
760 req = soup_requester_request_uri (requester, base_uri, NULL);
762 cancellable = g_cancellable_new ();
763 g_signal_connect (session, "request-started",
764 G_CALLBACK (ear_request_started), cancellable);
765 soup_request_send_async (req, cancellable, ear_three_completed, loop);
766 g_main_loop_run (loop);
767 g_object_unref (req);
768 g_object_unref (cancellable);
770 while (g_main_context_pending (context))
771 g_main_context_iteration (context, FALSE);
773 soup_test_session_abort_unref (session);
774 g_main_loop_unref (loop);
778 do_one_accept_language_test (const char *language, const char *expected_header)
780 SoupSession *session;
784 debug_printf (1, " LANGUAGE=%s\n", language);
785 g_setenv ("LANGUAGE", language, TRUE);
786 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
787 SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
789 msg = soup_message_new_from_uri ("GET", base_uri);
790 soup_session_send_message (session, msg);
791 soup_test_session_abort_unref (session);
793 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
794 debug_printf (1, " Message failed? %d %s\n",
795 msg->status_code, msg->reason_phrase);
798 val = soup_message_headers_get_list (msg->request_headers,
801 debug_printf (1, " No Accept-Language set!\n");
803 } else if (strcmp (val, expected_header) != 0) {
804 debug_printf (1, " Wrong Accept-Language: expected '%s', got '%s'\n",
805 expected_header, val);
809 g_object_unref (msg);
813 do_accept_language_test (void)
815 const char *orig_language;
817 debug_printf (1, "\nAutomatic Accept-Language processing\n");
819 orig_language = g_getenv ("LANGUAGE");
820 do_one_accept_language_test ("C", "en");
821 do_one_accept_language_test ("fr_FR", "fr-fr, fr;q=0.9");
822 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");
825 g_setenv ("LANGUAGE", orig_language, TRUE);
827 g_unsetenv ("LANGUAGE");
831 cancel_message_timeout (gpointer msg)
833 SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
835 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
836 g_object_unref (msg);
837 g_object_unref (session);
842 cancel_message_thread (gpointer msg)
844 SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
846 g_usleep (100000); /* .1s */
847 soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
848 g_object_unref (msg);
849 g_object_unref (session);
854 set_done (SoupSession *session, SoupMessage *msg, gpointer user_data)
856 gboolean *done = user_data;
862 do_cancel_while_reading_test_for_session (SoupSession *session)
865 GThread *thread = NULL;
867 gboolean done = FALSE;
869 uri = soup_uri_new_with_base (base_uri, "/slow");
870 msg = soup_message_new_from_uri ("GET", uri);
873 g_object_set_data (G_OBJECT (msg), "session", session);
875 g_object_ref (session);
876 if (SOUP_IS_SESSION_ASYNC (session))
877 g_timeout_add (100, cancel_message_timeout, msg);
879 thread = g_thread_new ("cancel_message_thread", cancel_message_thread, msg);
881 /* We intentionally don't use soup_session_send_message() here,
882 * because it holds an extra ref on the SoupMessageQueueItem
883 * relative to soup_session_queue_message().
886 soup_session_queue_message (session, msg, set_done, &done);
888 g_main_context_iteration (NULL, TRUE);
890 if (msg->status_code != SOUP_STATUS_CANCELLED) {
891 debug_printf (1, " FAILED: %d %s (expected Cancelled)\n",
892 msg->status_code, msg->reason_phrase);
895 g_object_unref (msg);
898 g_thread_join (thread);
902 do_cancel_while_reading_test (void)
904 SoupSession *session;
906 debug_printf (1, "\nCancelling message while reading response (msg api)\n");
908 debug_printf (1, " Async session\n");
909 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
910 do_cancel_while_reading_test_for_session (session);
911 soup_test_session_abort_unref (session);
913 debug_printf (1, " Sync session\n");
914 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
915 do_cancel_while_reading_test_for_session (session);
916 soup_test_session_abort_unref (session);
920 cancel_request_timeout (gpointer cancellable)
922 g_cancellable_cancel (cancellable);
927 cancel_request_thread (gpointer cancellable)
929 g_usleep (100000); /* .1s */
930 g_cancellable_cancel (cancellable);
935 do_cancel_while_reading_req_test_for_session (SoupRequester *requester)
939 GCancellable *cancellable;
940 GError *error = NULL;
942 uri = soup_uri_new_with_base (base_uri, "/slow");
943 req = soup_requester_request_uri (requester, uri, NULL);
946 cancellable = g_cancellable_new ();
948 if (SOUP_IS_SESSION_ASYNC (soup_request_get_session (req))) {
949 g_timeout_add (100, cancel_request_timeout, cancellable);
950 soup_test_request_send_async_as_sync (req, cancellable, &error);
954 thread = g_thread_new ("cancel_request_thread", cancel_request_thread, cancellable);
955 soup_request_send (req, cancellable, &error);
956 g_thread_unref (thread);
960 debug_printf (1, " Request succeeded?\n");
962 } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
963 debug_printf (1, " Unexpected error: %s\n",
967 g_clear_error (&error);
969 g_object_unref (req);
970 g_object_unref (cancellable);
974 do_cancel_while_reading_req_test (void)
976 SoupSession *session;
977 SoupRequester *requester;
979 debug_printf (1, "\nCancelling message while reading response (request api)\n");
981 debug_printf (1, " Async session\n");
982 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
983 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
984 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
986 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
987 do_cancel_while_reading_req_test_for_session (requester);
988 soup_test_session_abort_unref (session);
990 debug_printf (1, " Sync session\n");
991 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
992 SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_REQUESTER,
994 requester = (SoupRequester *)soup_session_get_feature (session, SOUP_TYPE_REQUESTER);
995 do_cancel_while_reading_req_test_for_session (requester);
996 soup_test_session_abort_unref (session);
1000 do_aliases_test_for_session (SoupSession *session,
1001 const char *redirect_protocol)
1005 const char *redirected_protocol;
1007 uri = soup_uri_new_with_base (base_uri, "/alias-redirect");
1008 msg = soup_message_new_from_uri ("GET", uri);
1009 if (redirect_protocol)
1010 soup_message_headers_append (msg->request_headers, "X-Redirect-Protocol", redirect_protocol);
1011 soup_uri_free (uri);
1012 soup_session_send_message (session, msg);
1014 redirected_protocol = soup_message_headers_get_one (msg->response_headers, "X-Redirected-Protocol");
1016 if (g_strcmp0 (redirect_protocol, redirected_protocol)) {
1017 debug_printf (1, " redirect went to %s, should have gone to %s!\n",
1018 redirected_protocol ? redirected_protocol : "(none)",
1019 redirect_protocol ? redirect_protocol : "(none)");
1021 } else if (redirect_protocol && !SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
1022 debug_printf (1, " msg failed? (%d %s)\n",
1023 msg->status_code, msg->reason_phrase);
1025 } else if (!redirect_protocol && SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
1026 debug_printf (1, " msg succeeded? (%d %s)\n",
1027 msg->status_code, msg->reason_phrase);
1031 g_object_unref (msg);
1035 do_aliases_test (void)
1037 SoupSession *session;
1038 char *aliases[] = { "foo", NULL };
1040 debug_printf (1, "\nhttp-aliases / https-aliases\n");
1042 debug_printf (1, " Default behavior\n");
1043 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
1044 do_aliases_test_for_session (session, "http");
1045 soup_test_session_abort_unref (session);
1047 debug_printf (1, " foo-means-https\n");
1048 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
1049 SOUP_SESSION_HTTPS_ALIASES, aliases,
1051 do_aliases_test_for_session (session, "https");
1052 soup_test_session_abort_unref (session);
1054 debug_printf (1, " foo-means-nothing\n");
1055 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
1056 SOUP_SESSION_HTTP_ALIASES, NULL,
1058 do_aliases_test_for_session (session, NULL);
1059 soup_test_session_abort_unref (session);
1063 do_dot_dot_test (void)
1065 SoupSession *session;
1069 debug_printf (1, "\n'..' smuggling test\n");
1071 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
1073 uri = soup_uri_new_with_base (base_uri, "/..%2ftest");
1074 msg = soup_message_new_from_uri ("GET", uri);
1075 soup_uri_free (uri);
1077 soup_session_send_message (session, msg);
1079 if (msg->status_code != SOUP_STATUS_BAD_REQUEST) {
1080 debug_printf (1, " FAILED: %d %s (expected Bad Request)\n",
1081 msg->status_code, msg->reason_phrase);
1084 g_object_unref (msg);
1086 soup_test_session_abort_unref (session);
1092 SoupServer *ipv6_server;
1094 SoupAddress *ipv6_addr;
1095 SoupSession *session;
1098 debug_printf (1, "\nIPv6 server test\n");
1100 ipv6_addr = soup_address_new ("::1", SOUP_ADDRESS_ANY_PORT);
1101 soup_address_resolve_sync (ipv6_addr, NULL);
1102 ipv6_server = soup_server_new (SOUP_SERVER_INTERFACE, ipv6_addr,
1104 g_object_unref (ipv6_addr);
1105 soup_server_add_handler (ipv6_server, NULL, server_callback, NULL, NULL);
1106 soup_server_run_async (ipv6_server);
1108 ipv6_uri = soup_uri_new ("http://[::1]/");
1109 soup_uri_set_port (ipv6_uri, soup_server_get_port (ipv6_server));
1111 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
1113 debug_printf (1, " HTTP/1.1\n");
1114 msg = soup_message_new_from_uri ("GET", ipv6_uri);
1115 soup_session_send_message (session, msg);
1116 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
1117 debug_printf (1, " request failed: %d %s\n",
1118 msg->status_code, msg->reason_phrase);
1121 g_object_unref (msg);
1123 debug_printf (1, " HTTP/1.0\n");
1124 msg = soup_message_new_from_uri ("GET", ipv6_uri);
1125 soup_message_set_http_version (msg, SOUP_HTTP_1_0);
1126 soup_session_send_message (session, msg);
1127 if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
1128 debug_printf (1, " request failed: %d %s\n",
1129 msg->status_code, msg->reason_phrase);
1132 g_object_unref (msg);
1134 soup_uri_free (ipv6_uri);
1135 soup_test_session_abort_unref (session);
1136 soup_test_server_quit_unref (ipv6_server);
1140 do_idle_on_dispose_test (void)
1142 SoupSession *session;
1144 GMainContext *async_context;
1146 debug_printf (1, "\nTesting SoupSessionAsync dispose behavior\n");
1148 async_context = g_main_context_new ();
1149 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
1150 SOUP_SESSION_ASYNC_CONTEXT, async_context,
1153 msg = soup_message_new_from_uri ("GET", base_uri);
1154 soup_session_send_message (session, msg);
1155 g_object_unref (msg);
1157 while (g_main_context_iteration (async_context, FALSE))
1160 g_object_run_dispose (G_OBJECT (session));
1162 if (g_main_context_iteration (async_context, FALSE)) {
1163 debug_printf (1, " idle was queued!\n");
1167 g_object_unref (session);
1168 g_main_context_unref (async_context);
1172 do_pause_abort_test (void)
1174 SoupSession *session;
1178 debug_printf (1, "\nTesting paused messages don't get leaked on abort\n");
1180 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
1182 msg = soup_message_new_from_uri ("GET", base_uri);
1183 soup_session_queue_message (session, msg, NULL, NULL);
1184 soup_session_pause_message (session, msg);
1186 g_object_add_weak_pointer (G_OBJECT (msg), &ptr);
1187 soup_test_session_abort_unref (session);
1190 debug_printf (1, " msg was leaked\n");
1196 main (int argc, char **argv)
1198 SoupAuthDomain *auth_domain;
1200 test_init (argc, argv, NULL);
1202 server = soup_test_server_new (TRUE);
1203 soup_server_add_handler (server, NULL, server_callback, "http", NULL);
1204 base_uri = soup_uri_new ("http://127.0.0.1/");
1205 soup_uri_set_port (base_uri, soup_server_get_port (server));
1207 auth_domain = soup_auth_domain_basic_new (
1208 SOUP_AUTH_DOMAIN_REALM, "misc-test",
1209 SOUP_AUTH_DOMAIN_ADD_PATH, "/auth",
1210 SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, auth_callback,
1212 soup_server_add_auth_domain (server, auth_domain);
1213 g_object_unref (auth_domain);
1215 ssl_server = soup_test_server_new_ssl (TRUE);
1216 soup_server_add_handler (ssl_server, NULL, server_callback, "https", NULL);
1217 ssl_base_uri = soup_uri_new ("https://127.0.0.1/");
1218 soup_uri_set_port (ssl_base_uri, soup_server_get_port (ssl_server));
1221 do_callback_unref_test ();
1222 do_callback_unref_req_test ();
1223 do_msg_reuse_test ();
1225 do_early_abort_test ();
1226 do_early_abort_req_test ();
1227 do_accept_language_test ();
1228 do_cancel_while_reading_test ();
1229 do_cancel_while_reading_req_test ();
1233 do_idle_on_dispose_test ();
1234 do_pause_abort_test ();
1236 soup_uri_free (base_uri);
1237 soup_uri_free (ssl_base_uri);
1238 soup_test_server_quit_unref (server);
1239 soup_test_server_quit_unref (ssl_server);