gio/tests: fix leaks
[platform/upstream/glib.git] / gio / tests / proxy-test.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright 2012 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include <string.h>
22
23 #define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_34
24 #include <gio/gio.h>
25
26 /* Overview:
27  *
28  * We have an echo server, two proxy servers, two GProxy
29  * implementations, and a GProxyResolver implementation.
30  *
31  * The echo server runs at @server.server_addr (on
32  * @server.server_port).
33  *
34  * The two proxy servers, A and B, run on @proxy_a.port and
35  * @proxy_b.port, with @proxy_a.uri and @proxy_b.uri pointing to them.
36  * The "negotiation" with the two proxies is just sending the single
37  * letter "a" or "b" and receiving it back in uppercase; the proxy
38  * then connects to @server_addr.
39  *
40  * Proxy A supports "alpha://" URIs, and does not support hostname
41  * resolution, and Proxy B supports "beta://" URIs, and does support
42  * hostname resolution (but it just ignores the hostname and always
43  * connects to @server_addr anyway).
44  *
45  * The GProxyResolver (GTestProxyResolver) looks at its URI and
46  * returns [ "direct://" ] for "simple://" URIs, and [ proxy_a.uri,
47  * proxy_b.uri ] for other URIs.
48  */
49
50 typedef struct {
51   gchar *proxy_command;
52   gchar *supported_protocol;
53
54   GSocket *server;
55   GThread *thread;
56   GCancellable *cancellable;
57   gchar *uri;
58   gushort port;
59
60   GSocket *client_sock, *server_sock;
61   GMainLoop *loop;
62
63   GError *last_error;
64 } ProxyData;
65
66 static ProxyData proxy_a, proxy_b;
67
68 typedef struct {
69   GSocket *server;
70   GThread *server_thread;
71   GCancellable *cancellable;
72   GSocketAddress *server_addr;
73   gushort server_port;
74 } ServerData;
75
76 static ServerData server;
77
78 static gchar **last_proxies;
79
80 static GSocketClient *client;
81
82
83 /**************************************/
84 /* Test GProxyResolver implementation */
85 /**************************************/
86
87 typedef struct {
88   GObject parent_instance;
89 } GTestProxyResolver;
90
91 typedef struct {
92   GObjectClass parent_class;
93 } GTestProxyResolverClass;
94
95 static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface);
96
97 #define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type
98 G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT,
99                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
100                                                 g_test_proxy_resolver_iface_init)
101                          g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
102                                                          g_define_type_id,
103                                                          "test",
104                                                          0))
105
106 static void
107 g_test_proxy_resolver_init (GTestProxyResolver *resolver)
108 {
109 }
110
111 static gboolean
112 g_test_proxy_resolver_is_supported (GProxyResolver *resolver)
113 {
114   return TRUE;
115 }
116
117 static gchar **
118 g_test_proxy_resolver_lookup (GProxyResolver  *resolver,
119                               const gchar     *uri,
120                               GCancellable    *cancellable,
121                               GError         **error)
122 {
123   gchar **proxies;
124
125   g_assert (last_proxies == NULL);
126
127   if (g_cancellable_set_error_if_cancelled (cancellable, error))
128     return NULL;
129
130   proxies = g_new (gchar *, 3);
131
132   if (!strncmp (uri, "simple://", 4))
133     {
134       proxies[0] = g_strdup ("direct://");
135       proxies[1] = NULL;
136     }
137   else
138     {
139       /* Proxy A can only deal with "alpha://" URIs, not
140        * "beta://", but we always return both URIs
141        * anyway so we can test error handling when the first
142        * fails.
143        */
144       proxies[0] = g_strdup (proxy_a.uri);
145       proxies[1] = g_strdup (proxy_b.uri);
146       proxies[2] = NULL;
147     }
148
149   last_proxies = g_strdupv (proxies);
150
151   return proxies;
152 }
153
154 static void
155 g_test_proxy_resolver_lookup_async (GProxyResolver      *resolver,
156                                     const gchar         *uri,
157                                     GCancellable        *cancellable,
158                                     GAsyncReadyCallback  callback,
159                                     gpointer             user_data)
160 {
161   GError *error = NULL;
162   GSimpleAsyncResult *simple;
163   gchar **proxies;
164
165   proxies = g_test_proxy_resolver_lookup (resolver, uri, cancellable, &error);
166
167   simple = g_simple_async_result_new (G_OBJECT (resolver),
168                                       callback, user_data,
169                                       g_test_proxy_resolver_lookup_async);
170
171   if (proxies == NULL)
172     g_simple_async_result_take_error (simple, error);
173   else
174     g_simple_async_result_set_op_res_gpointer (simple, proxies, (GDestroyNotify) g_strfreev);
175
176   g_simple_async_result_complete_in_idle (simple);
177   g_object_unref (simple);
178 }
179
180 static gchar **
181 g_test_proxy_resolver_lookup_finish (GProxyResolver     *resolver,
182                                      GAsyncResult       *result,
183                                      GError            **error)
184 {
185   if (G_IS_SIMPLE_ASYNC_RESULT (result))
186     {
187       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
188       gchar **proxies;
189
190       if (g_simple_async_result_propagate_error (simple, error))
191         return NULL;
192
193       proxies = g_simple_async_result_get_op_res_gpointer (simple);
194       return g_strdupv (proxies);
195     }
196
197   return NULL;
198 }
199
200 static void
201 g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
202 {
203 }
204
205 static void
206 g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
207 {
208   iface->is_supported = g_test_proxy_resolver_is_supported;
209   iface->lookup = g_test_proxy_resolver_lookup;
210   iface->lookup_async = g_test_proxy_resolver_lookup_async;
211   iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
212 }
213
214
215 /****************************************/
216 /* Test proxy implementation base class */
217 /****************************************/
218
219 typedef struct {
220   GObject parent;
221
222   ProxyData *proxy_data;
223 } GProxyBase;
224
225 typedef struct {
226   GObjectClass parent_class;
227 } GProxyBaseClass;
228
229 #define g_proxy_base_get_type _g_proxy_base_get_type
230 G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
231
232 static void
233 g_proxy_base_init (GProxyBase *proxy)
234 {
235 }
236
237 static GIOStream *
238 g_proxy_base_connect (GProxy            *proxy,
239                       GIOStream         *io_stream,
240                       GProxyAddress     *proxy_address,
241                       GCancellable      *cancellable,
242                       GError           **error)
243 {
244   ProxyData *data = ((GProxyBase *) proxy)->proxy_data;
245   const gchar *protocol;
246   GOutputStream *ostream;
247   GInputStream *istream;
248   gchar response;
249
250   g_assert_no_error (data->last_error);
251
252   protocol = g_proxy_address_get_destination_protocol (proxy_address);
253   if (strcmp (protocol, data->supported_protocol) != 0)
254     {
255       g_set_error_literal (&data->last_error,
256                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
257                            "Unsupported protocol");
258       goto fail;
259     }
260
261   ostream = g_io_stream_get_output_stream (io_stream);
262   if (g_output_stream_write (ostream, data->proxy_command, 1, cancellable,
263                              &data->last_error) != 1)
264     goto fail;
265
266   istream = g_io_stream_get_input_stream (io_stream);
267   if (g_input_stream_read (istream, &response, 1, cancellable,
268                            &data->last_error) != 1)
269     goto fail;
270
271   if (response != g_ascii_toupper (*data->proxy_command))
272     {
273       g_set_error_literal (&data->last_error,
274                            G_IO_ERROR, G_IO_ERROR_FAILED,
275                            "Failed");
276       goto fail;
277     }
278
279   return g_object_ref (io_stream);
280
281  fail:
282   g_propagate_error (error, g_error_copy (data->last_error));
283   return NULL;
284 }
285
286 static void
287 g_proxy_base_connect_async (GProxy               *proxy,
288                             GIOStream            *io_stream,
289                             GProxyAddress        *proxy_address,
290                             GCancellable         *cancellable,
291                             GAsyncReadyCallback   callback,
292                             gpointer              user_data)
293 {
294   GError *error = NULL;
295   GSimpleAsyncResult *simple;
296   GIOStream *proxy_io_stream;
297
298   simple = g_simple_async_result_new (G_OBJECT (proxy),
299                                       callback, user_data,
300                                       g_proxy_base_connect_async);
301
302   proxy_io_stream = g_proxy_connect (proxy, io_stream, proxy_address,
303                                      cancellable, &error);
304   if (proxy_io_stream)
305     {
306       g_simple_async_result_set_op_res_gpointer (simple, proxy_io_stream,
307                                                  g_object_unref);
308     }
309   else
310     g_simple_async_result_take_error (simple, error);
311   g_simple_async_result_complete_in_idle (simple);
312   g_object_unref (simple);
313 }
314
315 static GIOStream *
316 g_proxy_base_connect_finish (GProxy        *proxy,
317                              GAsyncResult  *result,
318                              GError       **error)
319 {
320   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
321
322   if (g_simple_async_result_propagate_error (simple, error))
323     return NULL;
324
325   return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
326 }
327
328 static void
329 g_proxy_base_class_init (GProxyBaseClass *class)
330 {
331 }
332
333
334 /********************************************/
335 /* Test proxy implementation #1 ("Proxy A") */
336 /********************************************/
337
338 typedef GProxyBase GProxyA;
339 typedef GProxyBaseClass GProxyAClass;
340
341 static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
342
343 #define g_proxy_a_get_type _g_proxy_a_get_type
344 G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
345                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
346                                                 g_proxy_a_iface_init)
347                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
348                                                          g_define_type_id,
349                                                          "proxy-a",
350                                                          0))
351
352 static void
353 g_proxy_a_init (GProxyA *proxy)
354 {
355   ((GProxyBase *) proxy)->proxy_data = &proxy_a;
356 }
357
358 static gboolean
359 g_proxy_a_supports_hostname (GProxy *proxy)
360 {
361   return FALSE;
362 }
363
364 static void
365 g_proxy_a_class_init (GProxyAClass *class)
366 {
367 }
368
369 static void
370 g_proxy_a_iface_init (GProxyInterface *proxy_iface)
371 {
372   proxy_iface->connect = g_proxy_base_connect;
373   proxy_iface->connect_async = g_proxy_base_connect_async;
374   proxy_iface->connect_finish = g_proxy_base_connect_finish;
375   proxy_iface->supports_hostname = g_proxy_a_supports_hostname;
376 }
377
378 /********************************************/
379 /* Test proxy implementation #2 ("Proxy B") */
380 /********************************************/
381
382 typedef GProxyBase GProxyB;
383 typedef GProxyBaseClass GProxyBClass;
384
385 static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
386
387 #define g_proxy_b_get_type _g_proxy_b_get_type
388 G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
389                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
390                                                 g_proxy_b_iface_init)
391                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
392                                                          g_define_type_id,
393                                                          "proxy-b",
394                                                          0))
395
396 static void
397 g_proxy_b_init (GProxyB *proxy)
398 {
399   ((GProxyBase *) proxy)->proxy_data = &proxy_b;
400 }
401
402 static gboolean
403 g_proxy_b_supports_hostname (GProxy *proxy)
404 {
405   return TRUE;
406 }
407
408 static void
409 g_proxy_b_class_init (GProxyBClass *class)
410 {
411 }
412
413 static void
414 g_proxy_b_iface_init (GProxyInterface *proxy_iface)
415 {
416   proxy_iface->connect = g_proxy_base_connect;
417   proxy_iface->connect_async = g_proxy_base_connect_async;
418   proxy_iface->connect_finish = g_proxy_base_connect_finish;
419   proxy_iface->supports_hostname = g_proxy_b_supports_hostname;
420 }
421
422
423 /***********************************/
424 /* The proxy server implementation */
425 /***********************************/
426
427 static gboolean
428 proxy_bytes (GSocket      *socket,
429              GIOCondition  condition,
430              gpointer      user_data)
431 {
432   ProxyData *proxy = user_data;
433   gssize nread, nwrote, total;
434   gchar buffer[8];
435   GSocket *out_socket;
436   GError *error = NULL;
437
438   nread = g_socket_receive_with_blocking (socket, buffer, sizeof (buffer),
439                                           TRUE, NULL, &error);
440   if (nread == -1)
441     {
442       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
443       return FALSE;
444     }
445   else
446     g_assert_no_error (error);
447
448   if (nread == 0)
449     {
450       g_main_loop_quit (proxy->loop);
451       return FALSE;
452     }
453
454   if (socket == proxy->client_sock)
455     out_socket = proxy->server_sock;
456   else
457     out_socket = proxy->client_sock;
458
459   for (total = 0; total < nread; total += nwrote)
460     {
461       nwrote = g_socket_send_with_blocking (out_socket,
462                                             buffer + total, nread - total,
463                                             TRUE, NULL, &error);
464       g_assert_no_error (error);
465     }
466
467   return TRUE;
468 }
469
470 static gpointer
471 proxy_thread (gpointer user_data)
472 {
473   ProxyData *proxy = user_data;
474   GError *error = NULL;
475   gssize nread, nwrote;
476   gchar command[2] = { 0, 0 };
477   GMainContext *context;
478   GSource *read_source, *write_source;
479
480   context = g_main_context_new ();
481   proxy->loop = g_main_loop_new (context, FALSE);
482
483   while (TRUE)
484     {
485       proxy->client_sock = g_socket_accept (proxy->server, proxy->cancellable, &error);
486       if (!proxy->client_sock)
487         {
488           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
489           g_error_free (error);
490           break;
491         }
492       else
493         g_assert_no_error (error);
494
495       nread = g_socket_receive (proxy->client_sock, command, 1, NULL, &error);
496       g_assert_no_error (error);
497
498       if (nread == 0)
499         {
500           g_clear_object (&proxy->client_sock);
501           continue;
502         }
503
504       g_assert_cmpint (nread, ==, 1);
505       g_assert_cmpstr (command, ==, proxy->proxy_command);
506
507       *command = g_ascii_toupper (*command);
508       nwrote = g_socket_send (proxy->client_sock, command, 1, NULL, &error);
509       g_assert_no_error (error);
510       g_assert_cmpint (nwrote, ==, 1);
511
512       proxy->server_sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
513                                          G_SOCKET_TYPE_STREAM,
514                                          G_SOCKET_PROTOCOL_DEFAULT,
515                                          &error);
516       g_assert_no_error (error);
517       g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
518       g_assert_no_error (error);
519
520       read_source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
521       g_source_set_callback (read_source, (GSourceFunc)proxy_bytes, proxy, NULL);
522       g_source_attach (read_source, context);
523
524       write_source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
525       g_source_set_callback (write_source, (GSourceFunc)proxy_bytes, proxy, NULL);
526       g_source_attach (write_source, context);
527
528       g_main_loop_run (proxy->loop);
529
530       g_socket_close (proxy->client_sock, &error);
531       g_assert_no_error (error);
532       g_clear_object (&proxy->client_sock);
533
534       g_socket_close (proxy->server_sock, &error);
535       g_assert_no_error (error);
536       g_clear_object (&proxy->server_sock);
537
538       g_source_destroy (read_source);
539       g_source_unref (read_source);
540       g_source_destroy (write_source);
541       g_source_unref (write_source);
542     }
543
544   g_main_loop_unref (proxy->loop);
545   g_main_context_unref (context);
546
547   g_object_unref (proxy->server);
548   g_object_unref (proxy->cancellable);
549
550   g_free (proxy->proxy_command);
551   g_free (proxy->supported_protocol);
552   g_free (proxy->uri);
553
554   return NULL;
555 }
556
557 static void
558 create_proxy (ProxyData    *proxy,
559               gchar         proxy_protocol,
560               const gchar  *destination_protocol,
561               GCancellable *cancellable)
562 {
563   GError *error = NULL;
564   GSocketAddress *addr;
565   GInetAddress *iaddr;
566
567   proxy->proxy_command = g_strdup_printf ("%c", proxy_protocol);
568   proxy->supported_protocol = g_strdup (destination_protocol);
569   proxy->cancellable = g_object_ref (cancellable);
570
571   proxy->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
572                                 G_SOCKET_TYPE_STREAM,
573                                 G_SOCKET_PROTOCOL_DEFAULT,
574                                 &error);
575   g_assert_no_error (error);
576
577   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
578   addr = g_inet_socket_address_new (iaddr, 0);
579   g_object_unref (iaddr);
580
581   g_socket_bind (proxy->server, addr, TRUE, &error);
582   g_assert_no_error (error);
583   g_object_unref (addr);
584
585   addr = g_socket_get_local_address (proxy->server, &error);
586   proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
587   proxy->uri = g_strdup_printf ("proxy-%c://127.0.0.1:%u",
588                                 g_ascii_tolower (proxy_protocol),
589                                 proxy->port);
590   g_object_unref (addr);
591
592   g_socket_listen (proxy->server, &error);
593   g_assert_no_error (error);
594
595   proxy->thread = g_thread_new ("proxy", proxy_thread, proxy);
596 }
597
598
599
600 /**************************/
601 /* The actual echo server */
602 /**************************/
603
604 static gpointer
605 echo_server_thread (gpointer user_data)
606 {
607   ServerData *data = user_data;
608   GSocket *sock;
609   GError *error = NULL;
610   gssize nread, nwrote;
611   gchar buf[128];
612
613   while (TRUE)
614     {
615       sock = g_socket_accept (data->server, data->cancellable, &error);
616       if (!sock)
617         {
618           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
619           g_error_free (error);
620           break;
621         }
622       else
623         g_assert_no_error (error);
624
625       while (TRUE)
626         {
627           nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
628           g_assert_no_error (error);
629           g_assert_cmpint (nread, >=, 0);
630
631           if (nread == 0)
632             break;
633
634           nwrote = g_socket_send (sock, buf, nread, NULL, &error);
635           g_assert_no_error (error);
636           g_assert_cmpint (nwrote, ==, nread);
637         }
638
639       g_socket_close (sock, &error);
640       g_assert_no_error (error);
641       g_object_unref (sock);
642     }
643
644   g_object_unref (data->server);
645   g_object_unref (data->server_addr);
646   g_object_unref (data->cancellable);
647
648   return NULL;
649 }
650
651 static void
652 create_server (ServerData *data, GCancellable *cancellable)
653 {
654   GError *error = NULL;
655   GSocketAddress *addr;
656   GInetAddress *iaddr;
657
658   data->cancellable = g_object_ref (cancellable);
659
660   data->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
661                                G_SOCKET_TYPE_STREAM,
662                                G_SOCKET_PROTOCOL_DEFAULT,
663                                &error);
664   g_assert_no_error (error);
665
666   g_socket_set_blocking (data->server, TRUE);
667   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
668   addr = g_inet_socket_address_new (iaddr, 0);
669   g_object_unref (iaddr);
670
671   g_socket_bind (data->server, addr, TRUE, &error);
672   g_assert_no_error (error);
673   g_object_unref (addr);
674
675   data->server_addr = g_socket_get_local_address (data->server, &error);
676   g_assert_no_error (error);
677
678   data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
679
680   g_socket_listen (data->server, &error);
681   g_assert_no_error (error);
682
683   data->server_thread = g_thread_new ("server", echo_server_thread, data);
684 }
685
686
687 /******************************************************************/
688 /* Now a GResolver implementation, so the can't-resolve test will */
689 /* pass even if you have an evil DNS-faking ISP.                  */
690 /******************************************************************/
691
692 typedef GResolver GFakeResolver;
693 typedef GResolverClass GFakeResolverClass;
694
695 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
696
697 static void
698 g_fake_resolver_init (GFakeResolver *gtr)
699 {
700 }
701
702 static GList *
703 g_fake_resolver_lookup_by_name (GResolver     *resolver,
704                                 const gchar   *hostname,
705                                 GCancellable  *cancellable,
706                                 GError       **error)
707 {
708   /* This is only ever called with lookups that are expected to
709    * fail.
710    */
711   g_set_error (error,
712                G_RESOLVER_ERROR,
713                G_RESOLVER_ERROR_NOT_FOUND,
714                "Not found");
715   return NULL;
716 }
717
718 static void
719 g_fake_resolver_lookup_by_name_async (GResolver           *resolver,
720                                       const gchar         *hostname,
721                                       GCancellable        *cancellable,
722                                       GAsyncReadyCallback  callback,
723                                       gpointer             user_data)
724 {
725   g_simple_async_report_error_in_idle (G_OBJECT (resolver),
726                                        callback, user_data,
727                                        G_RESOLVER_ERROR,
728                                        G_RESOLVER_ERROR_NOT_FOUND,
729                                        "Not found");
730 }
731
732 static void
733 g_fake_resolver_class_init (GFakeResolverClass *fake_class)
734 {
735   GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
736
737   resolver_class->lookup_by_name        = g_fake_resolver_lookup_by_name;
738   resolver_class->lookup_by_name_async  = g_fake_resolver_lookup_by_name_async;
739 }
740
741
742
743 /****************************************/
744 /* We made it! Now for the actual test! */
745 /****************************************/
746
747 static void
748 setup_test (gpointer fixture,
749             gconstpointer user_data)
750 {
751 }
752
753 static void
754 teardown_test (gpointer fixture,
755                gconstpointer user_data)
756 {
757   if (last_proxies)
758     {
759       g_strfreev (last_proxies);
760       last_proxies = NULL;
761     }
762   g_clear_error (&proxy_a.last_error);
763   g_clear_error (&proxy_b.last_error);
764 }
765
766
767 static const gchar *testbuf = "0123456789abcdef";
768
769 static void
770 do_echo_test (GSocketConnection *conn)
771 {
772   GIOStream *iostream = G_IO_STREAM (conn);
773   GInputStream *istream = g_io_stream_get_input_stream (iostream);
774   GOutputStream *ostream = g_io_stream_get_output_stream (iostream);
775   gssize nread, total;
776   gsize nwrote;
777   gchar buf[128];
778   GError *error = NULL;
779
780   g_output_stream_write_all (ostream, testbuf, strlen (testbuf),
781                              &nwrote, NULL, &error);
782   g_assert_no_error (error);
783   g_assert_cmpint (nwrote, ==, strlen (testbuf));
784
785   for (total = 0; total < nwrote; total += nread)
786     {
787       nread = g_input_stream_read (istream,
788                                    buf + total, sizeof (buf) - total,
789                                    NULL, &error);
790       g_assert_no_error (error);
791       g_assert_cmpint (nread, >, 0);
792     }
793
794   buf[total] = '\0';
795   g_assert_cmpstr (buf, ==, testbuf);
796 }
797
798 static void
799 async_got_conn (GObject      *source,
800                 GAsyncResult *result,
801                 gpointer      user_data)
802 {
803   GSocketConnection **conn = user_data;
804   GError *error = NULL;
805
806   *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
807                                           result, &error);
808   g_assert_no_error (error);
809 }
810
811 static void
812 async_got_error (GObject      *source,
813                  GAsyncResult *result,
814                  gpointer      user_data)
815 {
816   GError **error = user_data;
817
818   g_assert (error != NULL && *error == NULL);
819   g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
820                                   result, error);
821   g_assert (*error != NULL);
822 }
823
824
825 static void
826 assert_direct (GSocketConnection *conn)
827 {
828   GSocketAddress *addr;
829   GError *error = NULL;
830
831   g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
832   g_assert_cmpstr (last_proxies[0], ==, "direct://");
833   g_assert_no_error (proxy_a.last_error);
834   g_assert_no_error (proxy_b.last_error);
835
836   addr = g_socket_connection_get_remote_address (conn, &error);
837   g_assert_no_error (error);
838   g_assert (!G_IS_PROXY_ADDRESS (addr));
839   g_object_unref (addr);
840
841   addr = g_socket_connection_get_local_address (conn, &error);
842   g_assert_no_error (error);
843   g_object_unref (addr);
844
845   g_assert (g_socket_connection_is_connected (conn));
846 }
847
848 static void
849 test_direct_sync (gpointer fixture,
850                   gconstpointer user_data)
851 {
852   GSocketConnection *conn;
853   gchar *uri;
854   GError *error = NULL;
855
856   /* The simple:// URI should not require any proxy. */
857
858   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
859   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
860   g_free (uri);
861   g_assert_no_error (error);
862
863   assert_direct (conn);
864   do_echo_test (conn);
865   g_object_unref (conn);
866 }
867
868 static void
869 test_direct_async (gpointer fixture,
870                    gconstpointer user_data)
871 {
872   GSocketConnection *conn;
873   gchar *uri;
874
875   /* The simple:// URI should not require any proxy. */
876   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
877   conn = NULL;
878   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
879                                         async_got_conn, &conn);
880   g_free (uri);
881   while (conn == NULL)
882     g_main_context_iteration (NULL, TRUE);
883
884   assert_direct (conn);
885   do_echo_test (conn);
886   g_object_unref (conn);
887 }
888
889 static void
890 assert_single (GSocketConnection *conn)
891 {
892   GSocketAddress *addr;
893   const gchar *proxy_uri;
894   gushort proxy_port;
895   GError *error = NULL;
896
897   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
898   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
899   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
900   g_assert_no_error (proxy_a.last_error);
901   g_assert_no_error (proxy_b.last_error);
902
903   addr = g_socket_connection_get_remote_address (conn, &error);
904   g_assert_no_error (error);
905   g_assert (G_IS_PROXY_ADDRESS (addr));
906   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
907   g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
908   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
909   g_assert_cmpint (proxy_port, ==, proxy_a.port);
910
911   g_object_unref (addr);
912 }
913
914 static void
915 test_single_sync (gpointer fixture,
916                   gconstpointer user_data)
917 {
918   GSocketConnection *conn;
919   GError *error = NULL;
920   gchar *uri;
921
922   /* The alpha:// URI should be proxied via Proxy A */
923   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
924   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
925   g_free (uri);
926   g_assert_no_error (error);
927
928   assert_single (conn);
929
930   do_echo_test (conn);
931   g_object_unref (conn);
932 }
933
934 static void
935 test_single_async (gpointer fixture,
936                    gconstpointer user_data)
937 {
938   GSocketConnection *conn;
939   gchar *uri;
940
941   /* The alpha:// URI should be proxied via Proxy A */
942   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
943   conn = NULL;
944   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
945                                         async_got_conn, &conn);
946   g_free (uri);
947   while (conn == NULL)
948     g_main_context_iteration (NULL, TRUE);
949
950   assert_single (conn);
951   do_echo_test (conn);
952   g_object_unref (conn);
953 }
954
955 static void
956 assert_multiple (GSocketConnection *conn)
957 {
958   GSocketAddress *addr;
959   const gchar *proxy_uri;
960   gushort proxy_port;
961   GError *error = NULL;
962
963   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
964   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
965   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
966   g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
967   g_assert_no_error (proxy_b.last_error);
968
969   addr = g_socket_connection_get_remote_address (conn, &error);
970   g_assert_no_error (error);
971   g_assert (G_IS_PROXY_ADDRESS (addr));
972   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
973   g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
974   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
975   g_assert_cmpint (proxy_port, ==, proxy_b.port);
976
977   g_object_unref (addr);
978 }
979
980 static void
981 test_multiple_sync (gpointer fixture,
982                     gconstpointer user_data)
983 {
984   GSocketConnection *conn;
985   GError *error = NULL;
986   gchar *uri;
987
988   /* The beta:// URI should be proxied via Proxy B, after failing
989    * via Proxy A.
990    */
991   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
992   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
993   g_free (uri);
994   g_assert_no_error (error);
995
996   assert_multiple (conn);
997   do_echo_test (conn);
998   g_object_unref (conn);
999 }
1000
1001 static void
1002 test_multiple_async (gpointer fixture,
1003                      gconstpointer user_data)
1004 {
1005   GSocketConnection *conn;
1006   gchar *uri;
1007
1008   /* The beta:// URI should be proxied via Proxy B, after failing
1009    * via Proxy A.
1010    */
1011   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1012   conn = NULL;
1013   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1014                                         async_got_conn, &conn);
1015   g_free (uri);
1016   while (conn == NULL)
1017     g_main_context_iteration (NULL, TRUE);
1018
1019   assert_multiple (conn);
1020   do_echo_test (conn);
1021   g_object_unref (conn);
1022 }
1023
1024 static void
1025 test_dns (gpointer fixture,
1026           gconstpointer user_data)
1027 {
1028   GSocketConnection *conn;
1029   GError *error = NULL;
1030   gchar *uri;
1031
1032   /* The simple:// and alpha:// URIs should fail with a DNS error,
1033    * but the beta:// URI should succeed, because we pass it to
1034    * Proxy B without trying to resolve it first
1035    */
1036
1037   /* simple */
1038   uri = g_strdup_printf ("simple://no-such-host.xx:%u", server.server_port);
1039   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1040   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1041   g_clear_error (&error);
1042
1043   g_assert_no_error (proxy_a.last_error);
1044   g_assert_no_error (proxy_b.last_error);
1045   teardown_test (NULL, NULL);
1046
1047   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1048                                         async_got_error, &error);
1049   while (error == NULL)
1050     g_main_context_iteration (NULL, TRUE);
1051   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1052   g_clear_error (&error);
1053   g_free (uri);
1054
1055   g_assert_no_error (proxy_a.last_error);
1056   g_assert_no_error (proxy_b.last_error);
1057   teardown_test (NULL, NULL);
1058
1059   /* alpha */
1060   uri = g_strdup_printf ("alpha://no-such-host.xx:%u", server.server_port);
1061   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1062   /* Since Proxy A fails, @client will try Proxy B too, which won't
1063    * load an alpha:// URI.
1064    */
1065   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1066   g_clear_error (&error);
1067
1068   g_assert_no_error (proxy_a.last_error);
1069   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1070   teardown_test (NULL, NULL);
1071
1072   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1073                                         async_got_error, &error);
1074   while (error == NULL)
1075     g_main_context_iteration (NULL, TRUE);
1076   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1077   g_clear_error (&error);
1078   g_free (uri);
1079
1080   g_assert_no_error (proxy_a.last_error);
1081   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1082   teardown_test (NULL, NULL);
1083
1084   /* beta */
1085   uri = g_strdup_printf ("beta://no-such-host.xx:%u", server.server_port);
1086   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1087   g_assert_no_error (error);
1088
1089   g_assert_no_error (proxy_a.last_error);
1090   g_assert_no_error (proxy_b.last_error);
1091
1092   do_echo_test (conn);
1093   g_clear_object (&conn);
1094   teardown_test (NULL, NULL);
1095
1096   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1097                                         async_got_conn, &conn);
1098   while (conn == NULL)
1099     g_main_context_iteration (NULL, TRUE);
1100   g_free (uri);
1101
1102   g_assert_no_error (proxy_a.last_error);
1103   g_assert_no_error (proxy_b.last_error);
1104
1105   do_echo_test (conn);
1106   g_clear_object (&conn);
1107   teardown_test (NULL, NULL);
1108 }
1109
1110 int
1111 main (int   argc,
1112       char *argv[])
1113 {
1114   GResolver *fake_resolver;
1115   GCancellable *cancellable;
1116   gint result;
1117
1118   g_type_init ();
1119   g_test_init (&argc, &argv, NULL);
1120
1121   /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1122    * is to force _g_io_modules_ensure_extension_points_registered() to
1123    * get called, so we can then register a proxy resolver extension
1124    * point.
1125    */
1126   g_proxy_get_default_for_protocol ("foo");
1127   g_test_proxy_resolver_get_type ();
1128   g_proxy_a_get_type ();
1129   g_proxy_b_get_type ();
1130   g_setenv ("GIO_USE_PROXY_RESOLVER", "test", TRUE);
1131
1132   fake_resolver = g_object_new (g_fake_resolver_get_type (), NULL);
1133   g_resolver_set_default (fake_resolver);
1134
1135   cancellable = g_cancellable_new ();
1136   create_server (&server, cancellable);
1137   create_proxy (&proxy_a, 'a', "alpha", cancellable);
1138   create_proxy (&proxy_b, 'b', "beta", cancellable);
1139
1140   client = g_socket_client_new ();
1141   g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1142
1143   g_test_add_vtable ("/proxy/direct_sync", 0, NULL, setup_test, test_direct_sync, teardown_test);
1144   g_test_add_vtable ("/proxy/direct_async", 0, NULL, setup_test, test_direct_async, teardown_test);
1145   g_test_add_vtable ("/proxy/single_sync", 0, NULL, setup_test, test_single_sync, teardown_test);
1146   g_test_add_vtable ("/proxy/single_async", 0, NULL, setup_test, test_single_async, teardown_test);
1147   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
1148   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
1149   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
1150
1151   result = g_test_run();
1152
1153   g_object_unref (client);
1154
1155   g_cancellable_cancel (cancellable);
1156   g_thread_join (proxy_a.thread);
1157   g_thread_join (proxy_b.thread);
1158   g_thread_join (server.server_thread);
1159
1160   g_object_unref (cancellable);
1161
1162   return result;
1163 }
1164