proxy-test: work even when the upstream DNS lies
[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 *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           break;
490         }
491       else
492         g_assert_no_error (error);
493
494       nread = g_socket_receive (proxy->client_sock, command, 1, NULL, &error);
495       g_assert_no_error (error);
496
497       if (nread == 0)
498         {
499           g_clear_object (&proxy->client_sock);
500           continue;
501         }
502
503       g_assert_cmpint (nread, ==, 1);
504       g_assert_cmpstr (command, ==, proxy->proxy_command);
505
506       *command = g_ascii_toupper (*command);
507       nwrote = g_socket_send (proxy->client_sock, command, 1, NULL, &error);
508       g_assert_no_error (error);
509       g_assert_cmpint (nwrote, ==, 1);
510
511       proxy->server_sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
512                                          G_SOCKET_TYPE_STREAM,
513                                          G_SOCKET_PROTOCOL_DEFAULT,
514                                          &error);
515       g_assert_no_error (error);
516       g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
517       g_assert_no_error (error);
518
519       source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
520       g_source_set_callback (source, (GSourceFunc)proxy_bytes, proxy, NULL);
521       g_source_attach (source, context);
522       g_source_unref (source);
523
524       source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
525       g_source_set_callback (source, (GSourceFunc)proxy_bytes, proxy, NULL);
526       g_source_attach (source, context);
527       g_source_unref (source);
528
529       g_main_loop_run (proxy->loop);
530
531       g_socket_close (proxy->client_sock, &error);
532       g_assert_no_error (error);
533       g_clear_object (&proxy->client_sock);
534
535       g_socket_close (proxy->server_sock, &error);
536       g_assert_no_error (error);
537       g_clear_object (&proxy->server_sock);
538     }
539
540   g_main_loop_unref (proxy->loop);
541   g_main_context_unref (context);
542
543   g_object_unref (proxy->server);
544   g_object_unref (proxy->cancellable);
545
546   return NULL;
547 }
548
549 static void
550 create_proxy (ProxyData    *proxy,
551               gchar         proxy_protocol,
552               const gchar  *destination_protocol,
553               GCancellable *cancellable)
554 {
555   GError *error = NULL;
556   GSocketAddress *addr;
557   GInetAddress *iaddr;
558
559   proxy->proxy_command = g_strdup_printf ("%c", proxy_protocol);
560   proxy->supported_protocol = g_strdup (destination_protocol);
561   proxy->cancellable = g_object_ref (cancellable);
562
563   proxy->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
564                                 G_SOCKET_TYPE_STREAM,
565                                 G_SOCKET_PROTOCOL_DEFAULT,
566                                 &error);
567   g_assert_no_error (error);
568
569   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
570   addr = g_inet_socket_address_new (iaddr, 0);
571   g_object_unref (iaddr);
572
573   g_socket_bind (proxy->server, addr, TRUE, &error);
574   g_assert_no_error (error);
575   g_object_unref (addr);
576
577   addr = g_socket_get_local_address (proxy->server, &error);
578   proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
579   proxy->uri = g_strdup_printf ("proxy-%c://127.0.0.1:%u",
580                                 g_ascii_tolower (proxy_protocol),
581                                 proxy->port);
582   g_object_unref (addr);
583
584   g_socket_listen (proxy->server, &error);
585   g_assert_no_error (error);
586
587   proxy->thread = g_thread_new ("proxy", proxy_thread, proxy);
588 }
589
590
591
592 /**************************/
593 /* The actual echo server */
594 /**************************/
595
596 static gpointer
597 echo_server_thread (gpointer user_data)
598 {
599   ServerData *data = user_data;
600   GSocket *sock;
601   GError *error = NULL;
602   gssize nread, nwrote;
603   gchar buf[128];
604
605   while (TRUE)
606     {
607       sock = g_socket_accept (data->server, data->cancellable, &error);
608       if (!sock)
609         {
610           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
611           break;
612         }
613       else
614         g_assert_no_error (error);
615
616       while (TRUE)
617         {
618           nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
619           g_assert_no_error (error);
620           g_assert_cmpint (nread, >=, 0);
621
622           if (nread == 0)
623             break;
624
625           nwrote = g_socket_send (sock, buf, nread, NULL, &error);
626           g_assert_no_error (error);
627           g_assert_cmpint (nwrote, ==, nread);
628         }
629
630       g_socket_close (sock, &error);
631       g_assert_no_error (error);
632       g_object_unref (sock);
633     }
634
635   g_object_unref (data->server);
636   g_object_unref (data->cancellable);
637
638   return NULL;
639 }
640
641 static void
642 create_server (ServerData *data, GCancellable *cancellable)
643 {
644   GError *error = NULL;
645   GSocketAddress *addr;
646   GInetAddress *iaddr;
647
648   data->cancellable = g_object_ref (cancellable);
649
650   data->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
651                                G_SOCKET_TYPE_STREAM,
652                                G_SOCKET_PROTOCOL_DEFAULT,
653                                &error);
654   g_assert_no_error (error);
655
656   g_socket_set_blocking (data->server, TRUE);
657   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
658   addr = g_inet_socket_address_new (iaddr, 0);
659   g_object_unref (iaddr);
660
661   g_socket_bind (data->server, addr, TRUE, &error);
662   g_assert_no_error (error);
663   g_object_unref (addr);
664
665   data->server_addr = g_socket_get_local_address (data->server, &error);
666   g_assert_no_error (error);
667
668   data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
669
670   g_socket_listen (data->server, &error);
671   g_assert_no_error (error);
672
673   data->server_thread = g_thread_new ("server", echo_server_thread, data);
674 }
675
676
677 /******************************************************************/
678 /* Now a GResolver implementation, so the can't-resolve test will */
679 /* pass even if you have an evil DNS-faking ISP.                  */
680 /******************************************************************/
681
682 typedef GResolver GFakeResolver;
683 typedef GResolverClass GFakeResolverClass;
684
685 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
686
687 static void
688 g_fake_resolver_init (GFakeResolver *gtr)
689 {
690 }
691
692 static GList *
693 g_fake_resolver_lookup_by_name (GResolver     *resolver,
694                                 const gchar   *hostname,
695                                 GCancellable  *cancellable,
696                                 GError       **error)
697 {
698   /* This is only ever called with lookups that are expected to
699    * fail.
700    */
701   g_set_error (error,
702                G_RESOLVER_ERROR,
703                G_RESOLVER_ERROR_NOT_FOUND,
704                "Not found");
705   return NULL;
706 }
707
708 static void
709 g_fake_resolver_lookup_by_name_async (GResolver           *resolver,
710                                       const gchar         *hostname,
711                                       GCancellable        *cancellable,
712                                       GAsyncReadyCallback  callback,
713                                       gpointer             user_data)
714 {
715   g_simple_async_report_error_in_idle (G_OBJECT (resolver),
716                                        callback, user_data,
717                                        G_RESOLVER_ERROR,
718                                        G_RESOLVER_ERROR_NOT_FOUND,
719                                        "Not found");
720 }
721
722 static void
723 g_fake_resolver_class_init (GFakeResolverClass *fake_class)
724 {
725   GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
726
727   resolver_class->lookup_by_name        = g_fake_resolver_lookup_by_name;
728   resolver_class->lookup_by_name_async  = g_fake_resolver_lookup_by_name_async;
729 }
730
731
732
733 /****************************************/
734 /* We made it! Now for the actual test! */
735 /****************************************/
736
737 static void
738 setup_test (gpointer fixture,
739             gconstpointer user_data)
740 {
741 }
742
743 static void
744 teardown_test (gpointer fixture,
745                gconstpointer user_data)
746 {
747   if (last_proxies)
748     {
749       g_strfreev (last_proxies);
750       last_proxies = NULL;
751     }
752   g_clear_error (&proxy_a.last_error);
753   g_clear_error (&proxy_b.last_error);
754 }
755
756
757 static const gchar *testbuf = "0123456789abcdef";
758
759 static void
760 do_echo_test (GSocketConnection *conn)
761 {
762   GIOStream *iostream = G_IO_STREAM (conn);
763   GInputStream *istream = g_io_stream_get_input_stream (iostream);
764   GOutputStream *ostream = g_io_stream_get_output_stream (iostream);
765   gssize nread, total;
766   gsize nwrote;
767   gchar buf[128];
768   GError *error = NULL;
769
770   g_output_stream_write_all (ostream, testbuf, strlen (testbuf),
771                              &nwrote, NULL, &error);
772   g_assert_no_error (error);
773   g_assert_cmpint (nwrote, ==, strlen (testbuf));
774
775   for (total = 0; total < nwrote; total += nread)
776     {
777       nread = g_input_stream_read (istream,
778                                    buf + total, sizeof (buf) - total,
779                                    NULL, &error);
780       g_assert_no_error (error);
781       g_assert_cmpint (nread, >, 0);
782     }
783
784   buf[total] = '\0';
785   g_assert_cmpstr (buf, ==, testbuf);
786 }
787
788 static void
789 async_got_conn (GObject      *source,
790                 GAsyncResult *result,
791                 gpointer      user_data)
792 {
793   GSocketConnection **conn = user_data;
794   GError *error = NULL;
795
796   *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
797                                           result, &error);
798   g_assert_no_error (error);
799 }
800
801 static void
802 async_got_error (GObject      *source,
803                  GAsyncResult *result,
804                  gpointer      user_data)
805 {
806   GError **error = user_data;
807
808   g_assert (error != NULL && *error == NULL);
809   g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
810                                   result, error);
811   g_assert (*error != NULL);
812 }
813
814
815 static void
816 assert_direct (GSocketConnection *conn)
817 {
818   GSocketAddress *addr;
819   GError *error = NULL;
820
821   g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
822   g_assert_cmpstr (last_proxies[0], ==, "direct://");
823   g_assert_no_error (proxy_a.last_error);
824   g_assert_no_error (proxy_b.last_error);
825
826   addr = g_socket_connection_get_remote_address (conn, &error);
827   g_assert_no_error (error);
828   g_assert (!G_IS_PROXY_ADDRESS (addr));
829 }
830
831 static void
832 test_direct_sync (gpointer fixture,
833                   gconstpointer user_data)
834 {
835   GSocketConnection *conn;
836   gchar *uri;
837   GError *error = NULL;
838
839   /* The simple:// URI should not require any proxy. */
840
841   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
842   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
843   g_free (uri);
844   g_assert_no_error (error);
845
846   assert_direct (conn);
847   do_echo_test (conn);
848   g_object_unref (conn);
849 }
850
851 static void
852 test_direct_async (gpointer fixture,
853                    gconstpointer user_data)
854 {
855   GSocketConnection *conn;
856   gchar *uri;
857
858   /* The simple:// URI should not require any proxy. */
859   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
860   conn = NULL;
861   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
862                                         async_got_conn, &conn);
863   g_free (uri);
864   while (conn == NULL)
865     g_main_context_iteration (NULL, TRUE);
866
867   assert_direct (conn);
868   do_echo_test (conn);
869   g_object_unref (conn);
870 }
871
872 static void
873 assert_single (GSocketConnection *conn)
874 {
875   GSocketAddress *addr;
876   const gchar *proxy_uri;
877   gushort proxy_port;
878   GError *error = NULL;
879
880   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
881   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
882   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
883   g_assert_no_error (proxy_a.last_error);
884   g_assert_no_error (proxy_b.last_error);
885
886   addr = g_socket_connection_get_remote_address (conn, &error);
887   g_assert_no_error (error);
888   g_assert (G_IS_PROXY_ADDRESS (addr));
889   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
890   g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
891   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
892   g_assert_cmpint (proxy_port, ==, proxy_a.port);
893 }
894
895 static void
896 test_single_sync (gpointer fixture,
897                   gconstpointer user_data)
898 {
899   GSocketConnection *conn;
900   GError *error = NULL;
901   gchar *uri;
902
903   /* The alpha:// URI should be proxied via Proxy A */
904   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
905   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
906   g_free (uri);
907   g_assert_no_error (error);
908
909   assert_single (conn);
910
911   do_echo_test (conn);
912   g_object_unref (conn);
913 }
914
915 static void
916 test_single_async (gpointer fixture,
917                    gconstpointer user_data)
918 {
919   GSocketConnection *conn;
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 = NULL;
925   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
926                                         async_got_conn, &conn);
927   g_free (uri);
928   while (conn == NULL)
929     g_main_context_iteration (NULL, TRUE);
930
931   assert_single (conn);
932   do_echo_test (conn);
933   g_object_unref (conn);
934 }
935
936 static void
937 assert_multiple (GSocketConnection *conn)
938 {
939   GSocketAddress *addr;
940   const gchar *proxy_uri;
941   gushort proxy_port;
942   GError *error = NULL;
943
944   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
945   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
946   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
947   g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
948   g_assert_no_error (proxy_b.last_error);
949
950   addr = g_socket_connection_get_remote_address (conn, &error);
951   g_assert_no_error (error);
952   g_assert (G_IS_PROXY_ADDRESS (addr));
953   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
954   g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
955   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
956   g_assert_cmpint (proxy_port, ==, proxy_b.port);
957 }
958
959 static void
960 test_multiple_sync (gpointer fixture,
961                     gconstpointer user_data)
962 {
963   GSocketConnection *conn;
964   GError *error = NULL;
965   gchar *uri;
966
967   /* The beta:// URI should be proxied via Proxy B, after failing
968    * via Proxy A.
969    */
970   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
971   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
972   g_free (uri);
973   g_assert_no_error (error);
974
975   assert_multiple (conn);
976   do_echo_test (conn);
977   g_object_unref (conn);
978 }
979
980 static void
981 test_multiple_async (gpointer fixture,
982                      gconstpointer user_data)
983 {
984   GSocketConnection *conn;
985   gchar *uri;
986
987   /* The beta:// URI should be proxied via Proxy B, after failing
988    * via Proxy A.
989    */
990   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
991   conn = NULL;
992   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
993                                         async_got_conn, &conn);
994   g_free (uri);
995   while (conn == NULL)
996     g_main_context_iteration (NULL, TRUE);
997
998   assert_multiple (conn);
999   do_echo_test (conn);
1000   g_object_unref (conn);
1001 }
1002
1003 static void
1004 test_dns (gpointer fixture,
1005           gconstpointer user_data)
1006 {
1007   GSocketConnection *conn;
1008   GError *error = NULL;
1009   gchar *uri;
1010
1011   /* The simple:// and alpha:// URIs should fail with a DNS error,
1012    * but the beta:// URI should succeed, because we pass it to
1013    * Proxy B without trying to resolve it first
1014    */
1015
1016   /* simple */
1017   uri = g_strdup_printf ("simple://no-such-host.xx:%u", server.server_port);
1018   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1019   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1020   g_clear_error (&error);
1021
1022   g_assert_no_error (proxy_a.last_error);
1023   g_assert_no_error (proxy_b.last_error);
1024   teardown_test (NULL, NULL);
1025
1026   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1027                                         async_got_error, &error);
1028   while (error == NULL)
1029     g_main_context_iteration (NULL, TRUE);
1030   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1031   g_clear_error (&error);
1032   g_free (uri);
1033
1034   g_assert_no_error (proxy_a.last_error);
1035   g_assert_no_error (proxy_b.last_error);
1036   teardown_test (NULL, NULL);
1037
1038   /* alpha */
1039   uri = g_strdup_printf ("alpha://no-such-host.xx:%u", server.server_port);
1040   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1041   /* Since Proxy A fails, @client will try Proxy B too, which won't
1042    * load an alpha:// URI.
1043    */
1044   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1045   g_clear_error (&error);
1046
1047   g_assert_no_error (proxy_a.last_error);
1048   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1049   teardown_test (NULL, NULL);
1050
1051   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1052                                         async_got_error, &error);
1053   while (error == NULL)
1054     g_main_context_iteration (NULL, TRUE);
1055   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1056   g_clear_error (&error);
1057   g_free (uri);
1058
1059   g_assert_no_error (proxy_a.last_error);
1060   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1061   teardown_test (NULL, NULL);
1062
1063   /* beta */
1064   uri = g_strdup_printf ("beta://no-such-host.xx:%u", server.server_port);
1065   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1066   g_assert_no_error (error);
1067   g_clear_object (&conn);
1068
1069   g_assert_no_error (proxy_a.last_error);
1070   g_assert_no_error (proxy_b.last_error);
1071   teardown_test (NULL, NULL);
1072
1073   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1074                                         async_got_conn, &conn);
1075   while (conn == NULL)
1076     g_main_context_iteration (NULL, TRUE);
1077   g_clear_object (&conn);
1078   g_free (uri);
1079
1080   g_assert_no_error (proxy_a.last_error);
1081   g_assert_no_error (proxy_b.last_error);
1082   teardown_test (NULL, NULL);
1083 }
1084
1085 int
1086 main (int   argc,
1087       char *argv[])
1088 {
1089   GResolver *fake_resolver;
1090   GCancellable *cancellable;
1091   gint result;
1092
1093   g_type_init ();
1094   g_test_init (&argc, &argv, NULL);
1095
1096   /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1097    * is to force _g_io_modules_ensure_extension_points_registered() to
1098    * get called, so we can then register a proxy resolver extension
1099    * point.
1100    */
1101   g_proxy_get_default_for_protocol ("foo");
1102   g_test_proxy_resolver_get_type ();
1103   g_proxy_a_get_type ();
1104   g_proxy_b_get_type ();
1105   g_setenv ("GIO_USE_PROXY_RESOLVER", "test", TRUE);
1106
1107   fake_resolver = g_object_new (g_fake_resolver_get_type (), NULL);
1108   g_resolver_set_default (fake_resolver);
1109
1110   cancellable = g_cancellable_new ();
1111   create_server (&server, cancellable);
1112   create_proxy (&proxy_a, 'a', "alpha", cancellable);
1113   create_proxy (&proxy_b, 'b', "beta", cancellable);
1114
1115   client = g_socket_client_new ();
1116   g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1117
1118   g_test_add_vtable ("/proxy/direct_sync", 0, NULL, setup_test, test_direct_sync, teardown_test);
1119   g_test_add_vtable ("/proxy/direct_async", 0, NULL, setup_test, test_direct_async, teardown_test);
1120   g_test_add_vtable ("/proxy/single_sync", 0, NULL, setup_test, test_single_sync, teardown_test);
1121   g_test_add_vtable ("/proxy/single_async", 0, NULL, setup_test, test_single_async, teardown_test);
1122   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
1123   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
1124   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
1125
1126   result = g_test_run();
1127
1128   g_object_unref (client);
1129
1130   g_cancellable_cancel (cancellable);
1131   g_thread_join (proxy_a.thread);
1132   g_thread_join (proxy_b.thread);
1133   g_thread_join (server.server_thread);
1134
1135   return result;
1136 }
1137