add missing slash in %configure
[platform/upstream/libsoup.git] / tests / misc-test.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright 2007-2012 Red Hat, Inc.
4  */
5
6 #include "test-utils.h"
7
8 SoupServer *server, *ssl_server;
9 SoupURI *base_uri, *ssl_base_uri;
10
11 static gboolean
12 auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg,
13                const char *username, const char *password, gpointer data)
14 {
15         return !strcmp (username, "user") && !strcmp (password, "password");
16 }
17
18 static gboolean
19 timeout_finish_message (gpointer msg)
20 {
21         SoupServer *server = g_object_get_data (G_OBJECT (msg), "server");
22
23         soup_server_unpause_message (server, msg);
24         return FALSE;
25 }
26
27 static void
28 server_callback (SoupServer *server, SoupMessage *msg,
29                  const char *path, GHashTable *query,
30                  SoupClientContext *context, gpointer data)
31 {
32         SoupURI *uri = soup_message_get_uri (msg);
33         const char *server_protocol = data;
34
35         if (msg->method != SOUP_METHOD_GET && msg->method != SOUP_METHOD_POST) {
36                 soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED);
37                 return;
38         }
39
40         if (!strcmp (path, "/redirect")) {
41                 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, "/");
42                 return;
43         }
44
45         if (!strcmp (path, "/alias-redirect")) {
46                 SoupURI *redirect_uri;
47                 char *redirect_string;
48                 const char *redirect_protocol;
49
50                 redirect_protocol = soup_message_headers_get_one (msg->request_headers, "X-Redirect-Protocol");
51
52                 redirect_uri = soup_uri_copy (uri);
53                 soup_uri_set_scheme (redirect_uri, "foo");
54                 if (!g_strcmp0 (redirect_protocol, "https"))
55                         soup_uri_set_port (redirect_uri, ssl_base_uri->port);
56                 else
57                         soup_uri_set_port (redirect_uri, base_uri->port);
58                 soup_uri_set_path (redirect_uri, "/alias-redirected");
59                 redirect_string = soup_uri_to_string (redirect_uri, FALSE);
60
61                 soup_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string);
62                 g_free (redirect_string);
63                 soup_uri_free (redirect_uri);
64                 return;
65         } else if (!strcmp (path, "/alias-redirected")) {
66                 soup_message_set_status (msg, SOUP_STATUS_OK);
67                 soup_message_headers_append (msg->response_headers,
68                                              "X-Redirected-Protocol",
69                                              server_protocol);
70                 return;
71         }
72
73         if (!strcmp (path, "/slow")) {
74                 soup_server_pause_message (server, msg);
75                 g_object_set_data (G_OBJECT (msg), "server", server);
76                 soup_add_timeout (soup_server_get_async_context (server),
77                                   1000, timeout_finish_message, msg);
78         }
79
80         soup_message_set_status (msg, SOUP_STATUS_OK);
81         if (!strcmp (uri->host, "foo")) {
82                 soup_message_set_response (msg, "text/plain",
83                                            SOUP_MEMORY_STATIC, "foo-index", 9);
84                 return;
85         } else {
86                 soup_message_set_response (msg, "text/plain",
87                                            SOUP_MEMORY_STATIC, "index", 5);
88                 return;
89         }
90 }
91
92 /* Host header handling: client must be able to override the default
93  * value, server must be able to recognize different Host values.
94  */
95 static void
96 do_host_test (void)
97 {
98         SoupSession *session;
99         SoupMessage *one, *two;
100
101         g_test_bug ("539803");
102
103         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
104
105         one = soup_message_new_from_uri ("GET", base_uri);
106         two = soup_message_new_from_uri ("GET", base_uri);
107         soup_message_headers_replace (two->request_headers, "Host", "foo");
108
109         soup_session_send_message (session, one);
110         soup_session_send_message (session, two);
111
112         soup_test_session_abort_unref (session);
113
114         soup_test_assert_message_status (one, SOUP_STATUS_OK);
115         g_assert_cmpstr (one->response_body->data, ==, "index");
116         g_object_unref (one);
117
118         soup_test_assert_message_status (two, SOUP_STATUS_OK);
119         g_assert_cmpstr (two->response_body->data, ==, "foo-index");
120         g_object_unref (two);
121 }
122
123 /* Dropping the application's ref on the session from a callback
124  * should not cause the session to be freed at an incorrect time.
125  * (This test will crash if it fails.)
126  */
127 static void
128 cu_one_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
129 {
130         debug_printf (2, "  Message 1 completed\n");
131         soup_test_assert_message_status (msg, SOUP_STATUS_CANT_CONNECT);
132         g_object_unref (session);
133 }
134
135 static gboolean
136 cu_idle_quit (gpointer loop)
137 {
138         g_main_loop_quit (loop);
139         return FALSE;
140 }
141
142 static void
143 cu_two_completed (SoupSession *session, SoupMessage *msg, gpointer loop)
144 {
145         debug_printf (2, "  Message 2 completed\n");
146         soup_test_assert_message_status (msg, SOUP_STATUS_CANT_CONNECT);
147         g_idle_add (cu_idle_quit, loop); 
148 }
149
150 static void
151 do_callback_unref_test (void)
152 {
153         SoupServer *bad_server;
154         SoupAddress *addr;
155         SoupSession *session;
156         SoupMessage *one, *two;
157         GMainLoop *loop;
158         char *bad_uri;
159
160         g_test_bug ("533473");
161
162         /* Get a guaranteed-bad URI */
163         addr = soup_address_new ("127.0.0.1", SOUP_ADDRESS_ANY_PORT);
164         soup_address_resolve_sync (addr, NULL);
165         bad_server = soup_server_new (SOUP_SERVER_INTERFACE, addr,
166                                       NULL);
167         g_object_unref (addr);
168
169         bad_uri = g_strdup_printf ("http://127.0.0.1:%u/",
170                                    soup_server_get_port (bad_server));
171         g_object_unref (bad_server);
172
173         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
174         g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
175
176         loop = g_main_loop_new (NULL, TRUE);
177
178         one = soup_message_new ("GET", bad_uri);
179         g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
180         two = soup_message_new ("GET", bad_uri);
181         g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
182         g_free (bad_uri);
183
184         soup_session_queue_message (session, one, cu_one_completed, loop);
185         soup_session_queue_message (session, two, cu_two_completed, loop);
186
187         g_main_loop_run (loop);
188         g_main_loop_unref (loop);
189
190         g_assert_null (session);
191         if (session) {
192                 g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
193                 g_object_unref (session);
194         }
195         g_assert_null (one);
196         if (one) {
197                 g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
198                 g_object_unref (one);
199         }
200         g_assert_null (two);
201         if (two) {
202                 g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
203                 g_object_unref (two);
204         }
205
206         /* Otherwise, if we haven't crashed, we're ok. */
207 }
208
209 static void
210 cur_one_completed (GObject *source, GAsyncResult *result, gpointer session)
211 {
212         SoupRequest *one = SOUP_REQUEST (source);
213         GError *error = NULL;
214
215         debug_printf (2, "  Request 1 completed\n");
216         soup_request_send_finish (one, result, &error);
217         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED);
218         g_clear_error (&error);
219
220         g_object_unref (session);
221 }
222
223 static gboolean
224 cur_idle_quit (gpointer loop)
225 {
226         g_main_loop_quit (loop);
227         return FALSE;
228 }
229
230 static void
231 cur_two_completed (GObject *source, GAsyncResult *result, gpointer loop)
232 {
233         SoupRequest *two = SOUP_REQUEST (source);
234         GError *error = NULL;
235
236         debug_printf (2, "  Request 2 completed\n");
237         soup_request_send_finish (two, result, &error);
238         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CONNECTION_REFUSED);
239         g_clear_error (&error);
240
241         g_idle_add (cur_idle_quit, loop); 
242 }
243
244 static void
245 do_callback_unref_req_test (void)
246 {
247         SoupServer *bad_server;
248         SoupAddress *addr;
249         SoupSession *session;
250         SoupRequest *one, *two;
251         GMainLoop *loop;
252         char *bad_uri;
253
254         /* Get a guaranteed-bad URI */
255         addr = soup_address_new ("127.0.0.1", SOUP_ADDRESS_ANY_PORT);
256         soup_address_resolve_sync (addr, NULL);
257         bad_server = soup_server_new (SOUP_SERVER_INTERFACE, addr,
258                                       NULL);
259         g_object_unref (addr);
260
261         bad_uri = g_strdup_printf ("http://127.0.0.1:%u/",
262                                    soup_server_get_port (bad_server));
263         g_object_unref (bad_server);
264
265         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
266                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
267                                          NULL);
268         g_object_add_weak_pointer (G_OBJECT (session), (gpointer *)&session);
269
270         loop = g_main_loop_new (NULL, TRUE);
271
272         one = soup_session_request (session, bad_uri, NULL);
273         g_object_add_weak_pointer (G_OBJECT (one), (gpointer *)&one);
274         two = soup_session_request (session, bad_uri, NULL);
275         g_object_add_weak_pointer (G_OBJECT (two), (gpointer *)&two);
276         g_free (bad_uri);
277
278         soup_request_send_async (one, NULL, cur_one_completed, session);
279         g_object_unref (one);
280         soup_request_send_async (two, NULL, cur_two_completed, loop);
281         g_object_unref (two);
282
283         g_main_loop_run (loop);
284         g_main_loop_unref (loop);
285
286         g_assert_null (session);
287         if (session) {
288                 g_object_remove_weak_pointer (G_OBJECT (session), (gpointer *)&session);
289                 g_object_unref (session);
290         }
291         g_assert_null (one);
292         if (one) {
293                 g_object_remove_weak_pointer (G_OBJECT (one), (gpointer *)&one);
294                 g_object_unref (one);
295         }
296         g_assert_null (two);
297         if (two) {
298                 g_object_remove_weak_pointer (G_OBJECT (two), (gpointer *)&two);
299                 g_object_unref (two);
300         }
301
302         /* Otherwise, if we haven't crashed, we're ok. */
303 }
304
305 /* SoupSession should clean up all signal handlers on a message after
306  * it is finished, allowing the message to be reused if desired.
307  */
308 static void
309 ensure_no_signal_handlers (SoupMessage *msg, guint *signal_ids, guint n_signal_ids)
310 {
311         int i;
312         guint id;
313
314         for (i = 0; i < n_signal_ids; i++) {
315                 id = g_signal_handler_find (msg, G_SIGNAL_MATCH_ID, signal_ids[i],
316                                             0, NULL, NULL, NULL);
317                 soup_test_assert (id == 0,
318                                   "message has handler for '%s'",
319                                   g_signal_name (signal_ids[i]));
320         }
321 }
322
323 static void
324 reuse_test_authenticate (SoupSession *session, SoupMessage *msg,
325                          SoupAuth *auth, gboolean retrying)
326 {
327         /* Get it wrong the first time, then succeed */
328         if (!retrying)
329                 soup_auth_authenticate (auth, "user", "wrong password");
330         else
331                 soup_auth_authenticate (auth, "user", "password");
332 }
333
334 static void
335 do_msg_reuse_test (void)
336 {
337         SoupSession *session;
338         SoupMessage *msg;
339         SoupURI *uri;
340         guint *signal_ids, n_signal_ids;
341
342         g_test_bug ("559054");
343
344         signal_ids = g_signal_list_ids (SOUP_TYPE_MESSAGE, &n_signal_ids);
345
346         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
347         g_signal_connect (session, "authenticate",
348                           G_CALLBACK (reuse_test_authenticate), NULL);
349
350         debug_printf (1, "  First message\n");
351         msg = soup_message_new_from_uri ("GET", base_uri);
352         soup_session_send_message (session, msg);
353         ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
354
355         debug_printf (1, "  Redirect message\n");
356         uri = soup_uri_new_with_base (base_uri, "/redirect");
357         soup_message_set_uri (msg, uri);
358         soup_uri_free (uri);
359         soup_session_send_message (session, msg);
360         g_assert_true (soup_uri_equal (soup_message_get_uri (msg), base_uri));
361         ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
362
363         debug_printf (1, "  Auth message\n");
364         uri = soup_uri_new_with_base (base_uri, "/auth");
365         soup_message_set_uri (msg, uri);
366         soup_uri_free (uri);
367         soup_session_send_message (session, msg);
368         soup_test_assert_message_status (msg, SOUP_STATUS_OK);
369         ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
370
371         /* One last try to make sure the auth stuff got cleaned up */
372         debug_printf (1, "  Last message\n");
373         soup_message_set_uri (msg, base_uri);
374         soup_session_send_message (session, msg);
375         ensure_no_signal_handlers (msg, signal_ids, n_signal_ids);
376
377         soup_test_session_abort_unref (session);
378         g_object_unref (msg);
379         g_free (signal_ids);
380 }
381
382 /* Handle unexpectedly-early aborts. */
383 static void
384 ea_msg_completed_one (SoupSession *session, SoupMessage *msg, gpointer loop)
385 {
386         debug_printf (2, "  Message 1 completed\n");
387         soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
388         g_main_loop_quit (loop);
389 }
390
391 static gboolean
392 ea_abort_session (gpointer session)
393 {
394         soup_session_abort (session);
395         return FALSE;
396 }
397
398 static void
399 ea_connection_state_changed (GObject *conn, GParamSpec *pspec, gpointer session)
400 {
401         SoupConnectionState state;
402
403         g_object_get (conn, "state", &state, NULL);
404         if (state == SOUP_CONNECTION_CONNECTING) {
405                 g_idle_add_full (G_PRIORITY_HIGH,
406                                  ea_abort_session,
407                                  session, NULL);
408                 g_signal_handlers_disconnect_by_func (conn, ea_connection_state_changed, session);
409         }
410 }               
411
412 static void
413 ea_connection_created (SoupSession *session, GObject *conn, gpointer user_data)
414 {
415         g_signal_connect (conn, "notify::state",
416                           G_CALLBACK (ea_connection_state_changed), session);
417         g_signal_handlers_disconnect_by_func (session, ea_connection_created, user_data);
418 }
419
420 static void
421 ea_request_started (SoupSession *session, SoupMessage *msg, SoupSocket *socket, gpointer user_data)
422 {
423         soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
424 }
425
426 static void
427 do_early_abort_test (void)
428 {
429         SoupSession *session;
430         SoupMessage *msg;
431         GMainContext *context;
432         GMainLoop *loop;
433
434         g_test_bug ("596074");
435         g_test_bug ("618641");
436
437         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
438         msg = soup_message_new_from_uri ("GET", base_uri);
439
440         context = g_main_context_default ();
441         loop = g_main_loop_new (context, TRUE);
442         soup_session_queue_message (session, msg, ea_msg_completed_one, loop);
443         g_main_context_iteration (context, FALSE);
444
445         soup_session_abort (session);
446         while (g_main_context_pending (context))
447                 g_main_context_iteration (context, FALSE);
448         g_main_loop_unref (loop);
449         soup_test_session_abort_unref (session);
450
451         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
452         msg = soup_message_new_from_uri ("GET", base_uri);
453
454         g_signal_connect (session, "connection-created",
455                           G_CALLBACK (ea_connection_created), NULL);
456         soup_session_send_message (session, msg);
457         debug_printf (2, "  Message 2 completed\n");
458
459         soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
460         g_object_unref (msg);
461
462         while (g_main_context_pending (context))
463                 g_main_context_iteration (context, FALSE);
464
465         soup_test_session_abort_unref (session);
466
467         g_test_bug ("668098");
468
469         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
470         msg = soup_message_new_from_uri ("GET", base_uri);
471
472         g_signal_connect (session, "request-started",
473                           G_CALLBACK (ea_request_started), NULL);
474         soup_session_send_message (session, msg);
475         debug_printf (2, "  Message 3 completed\n");
476
477         soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
478         g_object_unref (msg);
479
480         while (g_main_context_pending (context))
481                 g_main_context_iteration (context, FALSE);
482
483         soup_test_session_abort_unref (session);
484 }
485
486 static void
487 ear_one_completed (GObject *source, GAsyncResult *result, gpointer user_data)
488 {
489         GError *error = NULL;
490
491         debug_printf (2, "  Request 1 completed\n");
492         soup_request_send_finish (SOUP_REQUEST (source), result, &error);
493         g_assert_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED);
494         g_clear_error (&error);
495 }
496
497 static void
498 ear_two_completed (GObject *source, GAsyncResult *result, gpointer loop)
499 {
500         GError *error = NULL;
501
502         debug_printf (2, "  Request 2 completed\n");
503         soup_request_send_finish (SOUP_REQUEST (source), result, &error);
504         g_assert_error (error, SOUP_HTTP_ERROR, SOUP_STATUS_CANCELLED);
505         g_clear_error (&error);
506
507         g_main_loop_quit (loop);
508 }
509
510 static void
511 ear_three_completed (GObject *source, GAsyncResult *result, gpointer loop)
512 {
513         GError *error = NULL;
514
515         debug_printf (2, "  Request 3 completed\n");
516         soup_request_send_finish (SOUP_REQUEST (source), result, &error);
517         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
518         g_clear_error (&error);
519
520         g_main_loop_quit (loop);
521 }
522
523 static void
524 ear_request_started (SoupSession *session, SoupMessage *msg,
525                      SoupSocket *socket, gpointer cancellable)
526 {
527         g_cancellable_cancel (cancellable);
528 }
529
530 static void
531 do_early_abort_req_test (void)
532 {
533         SoupSession *session;
534         SoupRequest *req;
535         GMainContext *context;
536         GMainLoop *loop;
537         GCancellable *cancellable;
538
539         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
540                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
541                                          NULL);
542         req = soup_session_request_uri (session, base_uri, NULL);
543
544         context = g_main_context_default ();
545         loop = g_main_loop_new (context, TRUE);
546         soup_request_send_async (req, NULL, ear_one_completed, NULL);
547         g_object_unref (req);
548         g_main_context_iteration (context, FALSE);
549
550         soup_session_abort (session);
551         while (g_main_context_pending (context))
552                 g_main_context_iteration (context, FALSE);
553         soup_test_session_abort_unref (session);
554
555         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
556                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
557                                          NULL);
558         req = soup_session_request_uri (session, base_uri, NULL);
559
560         g_signal_connect (session, "connection-created",
561                           G_CALLBACK (ea_connection_created), NULL);
562         soup_request_send_async (req, NULL, ear_two_completed, loop);
563         g_main_loop_run (loop);
564         g_object_unref (req);
565
566         while (g_main_context_pending (context))
567                 g_main_context_iteration (context, FALSE);
568
569         soup_test_session_abort_unref (session);
570
571         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
572                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
573                                          NULL);
574         req = soup_session_request_uri (session, base_uri, NULL);
575
576         cancellable = g_cancellable_new ();
577         g_signal_connect (session, "request-started",
578                           G_CALLBACK (ear_request_started), cancellable);
579         soup_request_send_async (req, cancellable, ear_three_completed, loop);
580         g_main_loop_run (loop);
581         g_object_unref (req);
582         g_object_unref (cancellable);
583
584         while (g_main_context_pending (context))
585                 g_main_context_iteration (context, FALSE);
586
587         soup_test_session_abort_unref (session);
588         g_main_loop_unref (loop);
589 }
590
591 static void
592 do_one_accept_language_test (const char *language, const char *expected_header)
593 {
594         SoupSession *session;
595         SoupMessage *msg;
596         const char *val;
597
598         debug_printf (1, "  LANGUAGE=%s\n", language);
599         g_setenv ("LANGUAGE", language, TRUE);
600         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
601                                          SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE,
602                                          NULL);
603         msg = soup_message_new_from_uri ("GET", base_uri);
604         soup_session_send_message (session, msg);
605         soup_test_session_abort_unref (session);
606
607         soup_test_assert_message_status (msg, SOUP_STATUS_OK);
608         val = soup_message_headers_get_list (msg->request_headers,
609                                              "Accept-Language");
610         g_assert_cmpstr (val, ==, expected_header);
611
612         g_object_unref (msg);
613 }
614
615 static void
616 do_accept_language_test (void)
617 {
618         const char *orig_language;
619
620         g_test_bug ("602547");
621
622         orig_language = g_getenv ("LANGUAGE");
623         do_one_accept_language_test ("C", "en");
624         do_one_accept_language_test ("fr_FR", "fr-fr, fr;q=0.9");
625         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");
626
627         if (orig_language)
628                 g_setenv ("LANGUAGE", orig_language, TRUE);
629         else
630                 g_unsetenv ("LANGUAGE");
631 }
632
633 static gboolean
634 cancel_message_timeout (gpointer msg)
635 {
636         SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
637
638         soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
639         g_object_unref (msg);
640         g_object_unref (session);
641         return FALSE;
642 }
643
644 static gpointer
645 cancel_message_thread (gpointer msg)
646 {
647         SoupSession *session = g_object_get_data (G_OBJECT (msg), "session");
648
649         g_usleep (100000); /* .1s */
650         soup_session_cancel_message (session, msg, SOUP_STATUS_CANCELLED);
651         g_object_unref (msg);
652         g_object_unref (session);
653         return NULL;
654 }
655
656 static void
657 set_done (SoupSession *session, SoupMessage *msg, gpointer user_data)
658 {
659         gboolean *done = user_data;
660
661         *done = TRUE;
662 }
663
664 static void
665 do_cancel_while_reading_test_for_session (SoupSession *session)
666 {
667         SoupMessage *msg;
668         GThread *thread = NULL;
669         SoupURI *uri;
670         gboolean done = FALSE;
671
672         uri = soup_uri_new_with_base (base_uri, "/slow");
673         msg = soup_message_new_from_uri ("GET", uri);
674         soup_uri_free (uri);
675
676         g_object_set_data (G_OBJECT (msg), "session", session);
677         g_object_ref (msg);
678         g_object_ref (session);
679         if (SOUP_IS_SESSION_ASYNC (session))
680                 g_timeout_add (100, cancel_message_timeout, msg);
681         else
682                 thread = g_thread_new ("cancel_message_thread", cancel_message_thread, msg);
683
684         /* We intentionally don't use soup_session_send_message() here,
685          * because it holds an extra ref on the SoupMessageQueueItem
686          * relative to soup_session_queue_message().
687          */
688         g_object_ref (msg);
689         soup_session_queue_message (session, msg, set_done, &done);
690         while (!done)
691                 g_main_context_iteration (NULL, TRUE);
692
693         soup_test_assert_message_status (msg, SOUP_STATUS_CANCELLED);
694         g_object_unref (msg);
695
696         if (thread)
697                 g_thread_join (thread);
698 }
699
700 static void
701 do_cancel_while_reading_test (void)
702 {
703         SoupSession *session;
704
705         g_test_bug ("637741");
706         g_test_bug ("676038");
707
708         debug_printf (1, "  Async session\n");
709         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
710         do_cancel_while_reading_test_for_session (session);
711         soup_test_session_abort_unref (session);
712
713         debug_printf (1, "  Sync session\n");
714         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
715         do_cancel_while_reading_test_for_session (session);
716         soup_test_session_abort_unref (session);
717 }
718
719 static void
720 do_cancel_while_reading_req_test_for_session (SoupSession *session,
721                                               guint flags)
722 {
723         SoupRequest *req;
724         SoupURI *uri;
725         GCancellable *cancellable;
726         GError *error = NULL;
727
728         uri = soup_uri_new_with_base (base_uri, "/slow");
729         req = soup_session_request_uri (session, uri, NULL);
730         soup_uri_free (uri);
731
732         cancellable = g_cancellable_new ();
733         soup_test_request_send (req, cancellable, flags, &error);
734         g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
735         g_clear_error (&error);
736
737         g_object_unref (req);
738         g_object_unref (cancellable);
739 }
740
741 static void
742 do_cancel_while_reading_immediate_req_test (void)
743 {
744         SoupSession *session;
745         guint flags;
746
747         g_test_bug ("692310");
748
749         flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_IMMEDIATE;
750
751         debug_printf (1, "  Async session\n");
752         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
753                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
754                                          NULL);
755         do_cancel_while_reading_req_test_for_session (session, flags);
756         soup_test_session_abort_unref (session);
757
758         debug_printf (1, "  Sync session\n");
759         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
760                                          NULL);
761         do_cancel_while_reading_req_test_for_session (session, flags);
762         soup_test_session_abort_unref (session);
763 }
764
765 static void
766 do_cancel_while_reading_delayed_req_test (void)
767 {
768         SoupSession *session;
769         guint flags;
770
771         flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_SOON;
772
773         debug_printf (1, "  Async session\n");
774         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
775                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
776                                          NULL);
777         do_cancel_while_reading_req_test_for_session (session, flags);
778         soup_test_session_abort_unref (session);
779
780         debug_printf (1, "  Sync session\n");
781         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
782                                          NULL);
783         do_cancel_while_reading_req_test_for_session (session, flags);
784         soup_test_session_abort_unref (session);
785 }
786
787 static void
788 do_cancel_while_reading_preemptive_req_test (void)
789 {
790         SoupSession *session;
791         guint flags;
792
793         g_test_bug ("637039");
794
795         flags = SOUP_TEST_REQUEST_CANCEL_CANCELLABLE | SOUP_TEST_REQUEST_CANCEL_PREEMPTIVE;
796
797         debug_printf (1, "  Async session\n");
798         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
799                                          SOUP_SESSION_USE_THREAD_CONTEXT, TRUE,
800                                          NULL);
801         do_cancel_while_reading_req_test_for_session (session, flags);
802         soup_test_session_abort_unref (session);
803
804         debug_printf (1, "  Sync session\n");
805         session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC,
806                                          NULL);
807         do_cancel_while_reading_req_test_for_session (session, flags);
808         soup_test_session_abort_unref (session);
809 }
810
811 static void
812 do_aliases_test_for_session (SoupSession *session,
813                              const char *redirect_protocol)
814 {
815         SoupMessage *msg;
816         SoupURI *uri;
817         const char *redirected_protocol;
818
819         uri = soup_uri_new_with_base (base_uri, "/alias-redirect");
820         msg = soup_message_new_from_uri ("GET", uri);
821         if (redirect_protocol)
822                 soup_message_headers_append (msg->request_headers, "X-Redirect-Protocol", redirect_protocol);
823         soup_uri_free (uri);
824         soup_session_send_message (session, msg);
825
826         redirected_protocol = soup_message_headers_get_one (msg->response_headers, "X-Redirected-Protocol");
827
828         g_assert_cmpstr (redirect_protocol, ==, redirected_protocol);
829         if (redirect_protocol)
830                 soup_test_assert_message_status (msg, SOUP_STATUS_OK);
831         else
832                 soup_test_assert_message_status (msg, SOUP_STATUS_FOUND);
833
834         g_object_unref (msg);
835 }
836
837 static void
838 do_aliases_test (void)
839 {
840         SoupSession *session;
841         char *aliases[] = { "foo", NULL };
842
843         debug_printf (1, "  Default behavior\n");
844         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
845         do_aliases_test_for_session (session, "http");
846         soup_test_session_abort_unref (session);
847
848         if (tls_available) {
849                 debug_printf (1, "  foo-means-https\n");
850                 session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
851                                                  SOUP_SESSION_HTTPS_ALIASES, aliases,
852                                                  NULL);
853                 do_aliases_test_for_session (session, "https");
854                 soup_test_session_abort_unref (session);
855         } else
856                 debug_printf (1, "  foo-means-https -- SKIPPING\n");
857
858         debug_printf (1, "  foo-means-nothing\n");
859         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
860                                          SOUP_SESSION_HTTP_ALIASES, NULL,
861                                          NULL);
862         do_aliases_test_for_session (session, NULL);
863         soup_test_session_abort_unref (session);
864 }
865
866 static void
867 do_idle_on_dispose_test (void)
868 {
869         SoupSession *session;
870         SoupMessage *msg;
871         GMainContext *async_context;
872
873         g_test_bug ("667364");
874
875         async_context = g_main_context_new ();
876         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
877                                          SOUP_SESSION_ASYNC_CONTEXT, async_context,
878                                          NULL);
879
880         msg = soup_message_new_from_uri ("GET", base_uri);
881         soup_session_send_message (session, msg);
882         g_object_unref (msg);
883
884         while (g_main_context_iteration (async_context, FALSE))
885                 ;
886
887         g_object_run_dispose (G_OBJECT (session));
888
889         if (g_main_context_iteration (async_context, FALSE))
890                 soup_test_assert (FALSE, "idle was queued");
891
892         g_object_unref (session);
893         g_main_context_unref (async_context);
894 }
895
896 static void
897 do_pause_abort_test (void)
898 {
899         SoupSession *session;
900         SoupMessage *msg;
901         gpointer ptr;
902
903         g_test_bug ("673905");
904
905         session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
906
907         msg = soup_message_new_from_uri ("GET", base_uri);
908         soup_session_queue_message (session, msg, NULL, NULL);
909         soup_session_pause_message (session, msg);
910
911         g_object_add_weak_pointer (G_OBJECT (msg), &ptr);
912         soup_test_session_abort_unref (session);
913
914         g_assert_null (ptr);
915 }
916
917 int
918 main (int argc, char **argv)
919 {
920         SoupAuthDomain *auth_domain;
921         int ret;
922
923         test_init (argc, argv, NULL);
924
925         server = soup_test_server_new (TRUE);
926         soup_server_add_handler (server, NULL, server_callback, "http", NULL);
927         base_uri = soup_uri_new ("http://127.0.0.1/");
928         soup_uri_set_port (base_uri, soup_server_get_port (server));
929
930         auth_domain = soup_auth_domain_basic_new (
931                 SOUP_AUTH_DOMAIN_REALM, "misc-test",
932                 SOUP_AUTH_DOMAIN_ADD_PATH, "/auth",
933                 SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, auth_callback,
934                 NULL);
935         soup_server_add_auth_domain (server, auth_domain);
936         g_object_unref (auth_domain);
937
938         if (tls_available) {
939                 ssl_server = soup_test_server_new_ssl (TRUE);
940                 soup_server_add_handler (ssl_server, NULL, server_callback, "https", NULL);
941                 ssl_base_uri = soup_uri_new ("https://127.0.0.1/");
942                 soup_uri_set_port (ssl_base_uri, soup_server_get_port (ssl_server));
943         }
944
945         g_test_add_func ("/misc/host", do_host_test);
946         g_test_add_func ("/misc/callback-unref/msg", do_callback_unref_test);
947         g_test_add_func ("/misc/callback-unref/req", do_callback_unref_req_test);
948         g_test_add_func ("/misc/msg-reuse", do_msg_reuse_test);
949         g_test_add_func ("/misc/early-abort/msg", do_early_abort_test);
950         g_test_add_func ("/misc/early-abort/req", do_early_abort_req_test);
951         g_test_add_func ("/misc/accept-language", do_accept_language_test);
952         g_test_add_func ("/misc/cancel-while-reading/msg", do_cancel_while_reading_test);
953         g_test_add_func ("/misc/cancel-while-reading/req/immediate", do_cancel_while_reading_immediate_req_test);
954         g_test_add_func ("/misc/cancel-while-reading/req/delayed", do_cancel_while_reading_delayed_req_test);
955         g_test_add_func ("/misc/cancel-while-reading/req/preemptive", do_cancel_while_reading_preemptive_req_test);
956         g_test_add_func ("/misc/aliases", do_aliases_test);
957         g_test_add_func ("/misc/idle-on-dispose", do_idle_on_dispose_test);
958         g_test_add_func ("/misc/pause-abort", do_pause_abort_test);
959
960         ret = g_test_run ();
961
962         soup_uri_free (base_uri);
963         soup_test_server_quit_unref (server);
964
965         if (tls_available) {
966                 soup_uri_free (ssl_base_uri);
967                 soup_test_server_quit_unref (ssl_server);
968         }
969
970         return ret;
971 }