1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2011 Red Hat, Inc.
6 /* Kill SoupRequester-related deprecation warnings */
7 #define SOUP_VERSION_MIN_REQUIRED SOUP_VERSION_2_40
9 #include "test-utils.h"
15 SoupBuffer *response, *auth_response;
17 #define REDIRECT_HTML_BODY "<html><body>Try again</body></html>\r\n"
18 #define AUTH_HTML_BODY "<html><body>Unauthorized</body></html>\r\n"
21 slow_finish_message (gpointer msg)
23 SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
25 soup_server_unpause_message (server, msg);
30 slow_pause_message (SoupMessage *msg, gpointer server)
32 soup_server_pause_message (server, msg);
33 soup_add_timeout (soup_server_get_async_context (server),
34 1000, slow_finish_message, msg);
38 server_callback (SoupServer *server, SoupMessage *msg,
39 const char *path, GHashTable *query,
40 SoupClientContext *context, gpointer data)
42 gboolean chunked = FALSE;
45 if (strcmp (path, "/auth") == 0) {
46 soup_message_set_status (msg, SOUP_STATUS_UNAUTHORIZED);
47 soup_message_set_response (msg, "text/html",
50 strlen (AUTH_HTML_BODY));
51 soup_message_headers_append (msg->response_headers,
53 "Basic: realm=\"requester-test\"");
55 } else if (strcmp (path, "/foo") == 0) {
56 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
57 /* Make the response HTML so if we sniff that instead of the
58 * real body, we'll notice.
60 soup_message_set_response (msg, "text/html",
63 strlen (REDIRECT_HTML_BODY));
65 } else if (strcmp (path, "/chunked") == 0) {
67 } else if (strcmp (path, "/non-persistent") == 0) {
68 soup_message_headers_append (msg->response_headers,
69 "Connection", "close");
70 } else if (!strcmp (path, "/slow")) {
71 g_object_set_data (G_OBJECT (msg), "server", server);
72 g_signal_connect (msg, "wrote-headers",
73 G_CALLBACK (slow_pause_message), server);
76 soup_message_set_status (msg, SOUP_STATUS_OK);
79 soup_message_headers_set_encoding (msg->response_headers,
80 SOUP_ENCODING_CHUNKED);
82 for (i = 0; i < response->length; i += 8192) {
85 tmp = soup_buffer_new_subbuffer (response, i,
86 MIN (8192, response->length - i));
87 soup_message_body_append_buffer (msg->response_body, tmp);
88 soup_buffer_free (tmp);
90 soup_message_body_complete (msg->response_body);
92 soup_message_body_append_buffer (msg->response_body, response);
101 stream_closed (GObject *source, GAsyncResult *res, gpointer user_data)
103 GInputStream *stream = G_INPUT_STREAM (source);
104 GError *error = NULL;
106 g_input_stream_close_finish (stream, res, &error);
107 g_assert_no_error (error);
108 g_main_loop_quit (loop);
109 g_object_unref (stream);
113 test_read_ready (GObject *source, GAsyncResult *res, gpointer user_data)
115 GInputStream *stream = G_INPUT_STREAM (source);
116 RequestData *data = user_data;
117 GString *body = data->body;
118 GError *error = NULL;
121 nread = g_input_stream_read_finish (stream, res, &error);
123 g_assert_no_error (error);
124 g_error_free (error);
125 g_input_stream_close (stream, NULL, NULL);
126 g_object_unref (stream);
127 g_main_loop_quit (loop);
129 } else if (nread == 0) {
130 g_input_stream_close_async (stream,
131 G_PRIORITY_DEFAULT, NULL,
132 stream_closed, NULL);
136 g_string_append_len (body, buf, nread);
137 g_input_stream_read_async (stream, buf, sizeof (buf),
138 G_PRIORITY_DEFAULT, NULL,
139 test_read_ready, data);
143 auth_test_sent (GObject *source, GAsyncResult *res, gpointer user_data)
145 RequestData *data = user_data;
146 GInputStream *stream;
147 GError *error = NULL;
149 const char *content_type;
151 stream = soup_request_send_finish (SOUP_REQUEST (source), res, &error);
153 g_assert_no_error (error);
154 g_clear_error (&error);
155 g_main_loop_quit (loop);
159 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (source));
160 soup_test_assert_message_status (msg, SOUP_STATUS_UNAUTHORIZED);
161 g_object_unref (msg);
163 content_type = soup_request_get_content_type (SOUP_REQUEST (source));
164 g_assert_cmpstr (content_type, ==, "text/html");
166 g_input_stream_read_async (stream, buf, sizeof (buf),
167 G_PRIORITY_DEFAULT, NULL,
168 test_read_ready, data);
172 test_sent (GObject *source, GAsyncResult *res, gpointer user_data)
174 RequestData *data = user_data;
175 GInputStream *stream;
176 GError *error = NULL;
177 const char *content_type;
179 stream = soup_request_send_finish (SOUP_REQUEST (source), res, &error);
181 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
182 g_clear_error (&error);
183 g_main_loop_quit (loop);
186 g_assert_no_error (error);
188 g_main_loop_quit (loop);
189 g_clear_error (&error);
194 content_type = soup_request_get_content_type (SOUP_REQUEST (source));
195 g_assert_cmpstr (content_type, ==, "text/plain");
197 g_input_stream_read_async (stream, buf, sizeof (buf),
198 G_PRIORITY_DEFAULT, NULL,
199 test_read_ready, data);
203 cancel_message (SoupMessage *msg, gpointer session)
205 soup_session_cancel_message (session, msg, SOUP_STATUS_FORBIDDEN);
209 request_started (SoupSession *session, SoupMessage *msg,
210 SoupSocket *socket, gpointer user_data)
212 SoupSocket **save_socket = user_data;
214 g_clear_object (save_socket);
215 *save_socket = g_object_ref (socket);
219 do_async_test (SoupSession *session, SoupURI *uri,
220 GAsyncReadyCallback callback, guint expected_status,
221 SoupBuffer *expected_response,
222 gboolean persistent, gboolean cancel)
224 SoupRequester *requester;
225 SoupRequest *request;
227 SoupSocket *socket = NULL;
231 if (SOUP_IS_SESSION_ASYNC (session))
232 requester = SOUP_REQUESTER (soup_session_get_feature (session, SOUP_TYPE_REQUESTER));
236 data.body = g_string_new (NULL);
237 data.cancel = cancel;
239 request = soup_requester_request_uri (requester, uri, NULL);
241 request = soup_session_request_uri (session, uri, NULL);
242 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
245 g_signal_connect (msg, "got-headers",
246 G_CALLBACK (cancel_message), session);
249 started_id = g_signal_connect (session, "request-started",
250 G_CALLBACK (request_started),
253 soup_request_send_async (request, NULL, callback, &data);
254 g_object_unref (request);
256 loop = g_main_loop_new (soup_session_get_async_context (session), TRUE);
257 g_main_loop_run (loop);
258 g_main_loop_unref (loop);
260 g_signal_handler_disconnect (session, started_id);
262 soup_test_assert_message_status (msg, expected_status);
263 g_object_unref (msg);
265 if (expected_response) {
266 soup_assert_cmpmem (data.body->str, data.body->len,
267 expected_response->data, expected_response->length);
269 g_assert_cmpint (data.body->len, ==, 0);
272 g_assert_true (soup_socket_is_connected (socket));
274 g_assert_false (soup_socket_is_connected (socket));
276 g_object_unref (socket);
278 g_string_free (data.body, TRUE);
282 do_test_for_thread_and_context (SoupSession *session, const char *base_uri)
284 SoupRequester *requester;
287 if (SOUP_IS_SESSION_ASYNC (session)) {
288 requester = soup_requester_new ();
289 soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
290 g_object_unref (requester);
292 soup_session_add_feature_by_type (session, SOUP_TYPE_CONTENT_SNIFFER);
294 debug_printf (1, " basic test\n");
295 uri = soup_uri_new (base_uri);
296 do_async_test (session, uri, test_sent,
297 SOUP_STATUS_OK, response,
301 debug_printf (1, " chunked test\n");
302 uri = soup_uri_new (base_uri);
303 soup_uri_set_path (uri, "/chunked");
304 do_async_test (session, uri, test_sent,
305 SOUP_STATUS_OK, response,
309 debug_printf (1, " auth test\n");
310 uri = soup_uri_new (base_uri);
311 soup_uri_set_path (uri, "/auth");
312 do_async_test (session, uri, auth_test_sent,
313 SOUP_STATUS_UNAUTHORIZED, auth_response,
317 debug_printf (1, " non-persistent test\n");
318 uri = soup_uri_new (base_uri);
319 soup_uri_set_path (uri, "/non-persistent");
320 do_async_test (session, uri, test_sent,
321 SOUP_STATUS_OK, response,
325 debug_printf (1, " cancellation test\n");
326 uri = soup_uri_new (base_uri);
327 soup_uri_set_path (uri, "/");
328 do_async_test (session, uri, test_sent,
329 SOUP_STATUS_FORBIDDEN, NULL,
335 do_simple_plain_test (gconstpointer uri)
337 SoupSession *session;
339 g_test_bug ("653707");
341 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
342 do_test_for_thread_and_context (session, uri);
343 soup_test_session_abort_unref (session);
347 do_simple_async_test (gconstpointer uri)
349 SoupSession *session;
351 g_test_bug ("653707");
353 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
354 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
356 do_test_for_thread_and_context (session, uri);
357 soup_test_session_abort_unref (session);
361 do_test_with_context_and_type (const char *uri, gboolean plain_session)
363 GMainContext *async_context;
364 SoupSession *session;
366 g_test_bug ("653707");
368 async_context = g_main_context_new ();
369 g_main_context_push_thread_default (async_context);
371 session = soup_test_session_new (plain_session ? SOUP_TYPE_SESSION : SOUP_TYPE_SESSION_ASYNC,
372 SOUP_SESSION_ASYNC_CONTEXT, async_context,
373 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
376 do_test_for_thread_and_context (session, uri);
377 soup_test_session_abort_unref (session);
379 g_main_context_pop_thread_default (async_context);
380 g_main_context_unref (async_context);
384 do_async_test_with_context (gconstpointer uri)
386 do_test_with_context_and_type (uri, FALSE);
390 do_plain_test_with_context (gconstpointer uri)
392 do_test_with_context_and_type (uri, TRUE);
396 async_test_thread (gpointer uri)
398 do_test_with_context_and_type (uri, TRUE);
403 plain_test_thread (gpointer uri)
405 do_test_with_context_and_type (uri, FALSE);
410 do_async_test_in_thread (gconstpointer uri)
414 thread = g_thread_new ("do_async_test_in_thread",
417 g_thread_join (thread);
421 do_plain_test_in_thread (gconstpointer uri)
425 thread = g_thread_new ("do_plain_test_in_thread",
428 g_thread_join (thread);
432 do_sync_request (SoupSession *session, SoupRequest *request,
433 guint expected_status, SoupBuffer *expected_response,
434 gboolean persistent, gboolean cancel)
438 GError *error = NULL;
443 SoupSocket *socket = NULL;
445 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
447 g_signal_connect (msg, "got-headers",
448 G_CALLBACK (cancel_message), session);
451 started_id = g_signal_connect (session, "request-started",
452 G_CALLBACK (request_started),
455 in = soup_request_send (request, NULL, &error);
456 g_signal_handler_disconnect (session, started_id);
458 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
459 g_clear_error (&error);
460 g_object_unref (msg);
461 g_object_unref (socket);
464 g_assert_no_error (error);
465 g_clear_error (&error);
466 g_object_unref (msg);
467 g_object_unref (socket);
471 soup_test_assert_message_status (msg, expected_status);
472 g_object_unref (msg);
474 body = g_string_new (NULL);
476 nread = g_input_stream_read (in, buf, sizeof (buf),
478 g_assert_no_error (error);
480 g_clear_error (&error);
483 g_string_append_len (body, buf, nread);
486 g_input_stream_close (in, NULL, &error);
487 g_assert_no_error (error);
488 g_clear_error (&error);
491 if (expected_response) {
492 soup_assert_cmpmem (body->str, body->len,
493 expected_response->data, expected_response->length);
495 g_assert_cmpint (body->len, ==, 0);
498 g_assert_true (soup_socket_is_connected (socket));
500 g_assert_false (soup_socket_is_connected (socket));
501 g_object_unref (socket);
503 g_string_free (body, TRUE);
507 do_sync_tests_for_session (SoupSession *session, const char *uri_string)
509 SoupRequester *requester;
510 SoupRequest *request;
513 requester = SOUP_REQUESTER (soup_session_get_feature (session, SOUP_TYPE_REQUESTER));
515 uri = soup_uri_new (uri_string);
517 debug_printf (1, " basic test\n");
519 request = soup_requester_request_uri (requester, uri, NULL);
521 request = soup_session_request_uri (session, uri, NULL);
522 do_sync_request (session, request,
523 SOUP_STATUS_OK, response,
525 g_object_unref (request);
527 debug_printf (1, " chunked test\n");
528 soup_uri_set_path (uri, "/chunked");
530 request = soup_requester_request_uri (requester, uri, NULL);
532 request = soup_session_request_uri (session, uri, NULL);
533 do_sync_request (session, request,
534 SOUP_STATUS_OK, response,
536 g_object_unref (request);
538 debug_printf (1, " auth test\n");
539 soup_uri_set_path (uri, "/auth");
541 request = soup_requester_request_uri (requester, uri, NULL);
543 request = soup_session_request_uri (session, uri, NULL);
544 do_sync_request (session, request,
545 SOUP_STATUS_UNAUTHORIZED, auth_response,
547 g_object_unref (request);
549 debug_printf (1, " non-persistent test\n");
550 soup_uri_set_path (uri, "/non-persistent");
552 request = soup_requester_request_uri (requester, uri, NULL);
554 request = soup_session_request_uri (session, uri, NULL);
555 do_sync_request (session, request,
556 SOUP_STATUS_OK, response,
558 g_object_unref (request);
560 debug_printf (1, " cancel test\n");
561 soup_uri_set_path (uri, "/");
563 request = soup_requester_request_uri (requester, uri, NULL);
565 request = soup_session_request_uri (session, uri, NULL);
566 do_sync_request (session, request,
567 SOUP_STATUS_FORBIDDEN, NULL,
569 g_object_unref (request);
575 do_plain_sync_test (gconstpointer uri)
577 SoupSession *session;
579 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
580 do_sync_tests_for_session (session, uri);
581 soup_test_session_abort_unref (session);
585 do_sync_sync_test (gconstpointer uri)
587 SoupSession *session;
588 SoupRequester *requester;
590 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
591 requester = soup_requester_new ();
592 soup_session_add_feature (session, SOUP_SESSION_FEATURE (requester));
593 g_object_unref (requester);
594 do_sync_tests_for_session (session, uri);
595 soup_test_session_abort_unref (session);
599 do_null_char_request (SoupSession *session, const char *encoded_data,
600 const char *expected_data, int expected_len)
602 GError *error = NULL;
603 GInputStream *stream;
604 SoupRequest *request;
606 char *uri_string, buf[256];
609 uri_string = g_strdup_printf ("data:text/html,%s", encoded_data);
610 uri = soup_uri_new (uri_string);
613 request = soup_session_request_uri (session, uri, NULL);
614 stream = soup_test_request_send (request, NULL, 0, &error);
615 g_assert_no_error (error);
617 g_error_free (error);
618 g_object_unref (request);
623 g_input_stream_read_all (stream, buf, sizeof (buf), &nread, NULL, &error);
624 g_assert_no_error (error);
625 g_clear_error (&error);
627 soup_test_request_close_stream (request, stream, NULL, &error);
628 g_assert_no_error (error);
629 g_clear_error (&error);
631 soup_assert_cmpmem (buf, nread, expected_data, expected_len);
633 g_object_unref (stream);
634 g_object_unref (request);
639 do_null_char_test_for_session (SoupSession *session)
642 const char *encoded_data;
643 const char *expected_data;
646 { "%3Cscript%3Ea%3D'%00'%3C%2Fscript%3E", "<script>a='\0'</script>", 22 },
647 { "%00%3Cscript%3Ea%3D42%3C%2Fscript%3E", "\0<script>a=42</script>", 22 },
648 { "%3Cscript%3E%00%3Cbr%2F%3E%3C%2Fscript%3E%00", "<script>\0<br/></script>\0", 24 },
650 static int num_test_cases = G_N_ELEMENTS(test_cases);
653 for (i = 0; i < num_test_cases; i++) {
654 do_null_char_request (session, test_cases[i].encoded_data,
655 test_cases[i].expected_data, test_cases[i].expected_len);
660 do_plain_null_char_test (void)
662 SoupSession *session;
664 session = soup_test_session_new (SOUP_TYPE_SESSION, NULL);
665 do_null_char_test_for_session (session);
666 soup_test_session_abort_unref (session);
670 do_async_null_char_test (void)
672 SoupSession *session;
674 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
675 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
677 do_null_char_test_for_session (session);
678 soup_test_session_abort_unref (session);
682 close_test_msg_finished (SoupMessage *msg,
685 gboolean *finished = user_data;
691 do_close_test_for_session (SoupSession *session,
694 GError *error = NULL;
695 GInputStream *stream;
696 SoupRequest *request;
698 GCancellable *cancellable;
700 gboolean finished = FALSE;
702 debug_printf (1, " normal close\n");
704 request = soup_session_request_uri (session, uri, NULL);
705 stream = soup_test_request_send (request, NULL, 0, &error);
706 g_assert_no_error (error);
708 g_error_free (error);
709 g_object_unref (request);
713 start = g_get_monotonic_time ();
714 soup_test_request_close_stream (request, stream, NULL, &error);
715 g_assert_no_error (error);
716 g_clear_error (&error);
717 end = g_get_monotonic_time ();
719 g_assert_cmpint (end - start, <=, 500000);
721 g_object_unref (stream);
722 g_object_unref (request);
725 debug_printf (1, " error close\n");
727 request = soup_session_request_uri (session, uri, NULL);
728 msg = soup_request_http_get_message (SOUP_REQUEST_HTTP (request));
729 g_signal_connect (msg, "finished", G_CALLBACK (close_test_msg_finished), &finished);
730 g_object_unref (msg);
732 stream = soup_test_request_send (request, NULL, 0, &error);
733 g_assert_no_error (error);
735 g_error_free (error);
736 g_object_unref (request);
740 cancellable = g_cancellable_new ();
741 g_cancellable_cancel (cancellable);
742 soup_test_request_close_stream (request, stream, cancellable, &error);
744 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
745 g_clear_error (&error);
747 g_assert_true (finished);
749 g_object_unref (stream);
750 g_object_unref (request);
754 do_async_close_test (gconstpointer uri)
756 SoupSession *session;
759 g_test_bug ("695652");
760 g_test_bug ("711260");
762 slow_uri = soup_uri_new (uri);
763 soup_uri_set_path (slow_uri, "/slow");
765 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
766 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
768 do_close_test_for_session (session, slow_uri);
769 soup_test_session_abort_unref (session);
771 soup_uri_free (slow_uri);
775 do_sync_close_test (gconstpointer uri)
777 SoupSession *session;
780 g_test_bug ("695652");
781 g_test_bug ("711260");
783 slow_uri = soup_uri_new (uri);
784 soup_uri_set_path (slow_uri, "/slow");
786 debug_printf (1, " SoupSessionSync\n");
787 session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
788 SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
790 do_close_test_for_session (session, slow_uri);
791 soup_test_session_abort_unref (session);
793 soup_uri_free (slow_uri);
797 main (int argc, char **argv)
802 test_init (argc, argv, NULL);
804 response = soup_test_get_index ();
805 auth_response = soup_buffer_new (SOUP_MEMORY_STATIC,
807 strlen (AUTH_HTML_BODY));
809 server = soup_test_server_new (TRUE);
810 soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
812 uri = g_strdup_printf ("http://127.0.0.1:%u/foo", soup_server_get_port (server));
814 g_test_add_data_func ("/requester/simple/SoupSession", uri, do_simple_plain_test);
815 g_test_add_data_func ("/requester/simple/SoupSessionAsync", uri, do_simple_async_test);
816 g_test_add_data_func ("/requester/threaded/SoupSession", uri, do_plain_test_in_thread);
817 g_test_add_data_func ("/requester/threaded/SoupSessionAsync", uri, do_async_test_in_thread);
818 g_test_add_data_func ("/requester/context/SoupSession", uri, do_plain_test_with_context);
819 g_test_add_data_func ("/requester/context/SoupSessionAsync", uri, do_async_test_with_context);
820 g_test_add_data_func ("/requester/sync/SoupSession", uri, do_plain_sync_test);
821 g_test_add_data_func ("/requester/sync/SoupSessionSync", uri, do_sync_sync_test);
822 g_test_add_func ("/requester/null-char/SoupSession", do_plain_null_char_test);
823 g_test_add_func ("/requester/null-char/SoupSessionAsync", do_async_null_char_test);
824 g_test_add_data_func ("/requester/close/SoupSessionAsync", uri, do_async_close_test);
825 g_test_add_data_func ("/requester/close/SoupSessionSync", uri, do_sync_close_test);
830 soup_buffer_free (auth_response);
831 soup_test_server_quit_unref (server);