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