Remove g_type_init() calls
[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   GTask *task;
163   gchar **proxies;
164
165   proxies = g_test_proxy_resolver_lookup (resolver, uri, cancellable, &error);
166
167   task = g_task_new (resolver, NULL, callback, user_data);
168   if (proxies == NULL)
169     g_task_return_error (task, error);
170   else
171     g_task_return_pointer (task, proxies, (GDestroyNotify) g_strfreev);
172
173   g_object_unref (task);
174 }
175
176 static gchar **
177 g_test_proxy_resolver_lookup_finish (GProxyResolver     *resolver,
178                                      GAsyncResult       *result,
179                                      GError            **error)
180 {
181   return g_task_propagate_pointer (G_TASK (result), error);
182 }
183
184 static void
185 g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
186 {
187 }
188
189 static void
190 g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
191 {
192   iface->is_supported = g_test_proxy_resolver_is_supported;
193   iface->lookup = g_test_proxy_resolver_lookup;
194   iface->lookup_async = g_test_proxy_resolver_lookup_async;
195   iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
196 }
197
198
199 /****************************************/
200 /* Test proxy implementation base class */
201 /****************************************/
202
203 typedef struct {
204   GObject parent;
205
206   ProxyData *proxy_data;
207 } GProxyBase;
208
209 typedef struct {
210   GObjectClass parent_class;
211 } GProxyBaseClass;
212
213 #define g_proxy_base_get_type _g_proxy_base_get_type
214 G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
215
216 static void
217 g_proxy_base_init (GProxyBase *proxy)
218 {
219 }
220
221 static GIOStream *
222 g_proxy_base_connect (GProxy            *proxy,
223                       GIOStream         *io_stream,
224                       GProxyAddress     *proxy_address,
225                       GCancellable      *cancellable,
226                       GError           **error)
227 {
228   ProxyData *data = ((GProxyBase *) proxy)->proxy_data;
229   const gchar *protocol;
230   GOutputStream *ostream;
231   GInputStream *istream;
232   gchar response;
233
234   g_assert_no_error (data->last_error);
235
236   protocol = g_proxy_address_get_destination_protocol (proxy_address);
237   if (strcmp (protocol, data->supported_protocol) != 0)
238     {
239       g_set_error_literal (&data->last_error,
240                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
241                            "Unsupported protocol");
242       goto fail;
243     }
244
245   ostream = g_io_stream_get_output_stream (io_stream);
246   if (g_output_stream_write (ostream, data->proxy_command, 1, cancellable,
247                              &data->last_error) != 1)
248     goto fail;
249
250   istream = g_io_stream_get_input_stream (io_stream);
251   if (g_input_stream_read (istream, &response, 1, cancellable,
252                            &data->last_error) != 1)
253     goto fail;
254
255   if (response != g_ascii_toupper (*data->proxy_command))
256     {
257       g_set_error_literal (&data->last_error,
258                            G_IO_ERROR, G_IO_ERROR_FAILED,
259                            "Failed");
260       goto fail;
261     }
262
263   return g_object_ref (io_stream);
264
265  fail:
266   g_propagate_error (error, g_error_copy (data->last_error));
267   return NULL;
268 }
269
270 static void
271 g_proxy_base_connect_async (GProxy               *proxy,
272                             GIOStream            *io_stream,
273                             GProxyAddress        *proxy_address,
274                             GCancellable         *cancellable,
275                             GAsyncReadyCallback   callback,
276                             gpointer              user_data)
277 {
278   GError *error = NULL;
279   GTask *task;
280   GIOStream *proxy_io_stream;
281
282   task = g_task_new (proxy, NULL, callback, user_data);
283
284   proxy_io_stream = g_proxy_connect (proxy, io_stream, proxy_address,
285                                      cancellable, &error);
286   if (proxy_io_stream)
287     g_task_return_pointer (task, proxy_io_stream, g_object_unref);
288   else
289     g_task_return_error (task, error);
290   g_object_unref (task);
291 }
292
293 static GIOStream *
294 g_proxy_base_connect_finish (GProxy        *proxy,
295                              GAsyncResult  *result,
296                              GError       **error)
297 {
298   return g_task_propagate_pointer (G_TASK (result), error);
299 }
300
301 static void
302 g_proxy_base_class_init (GProxyBaseClass *class)
303 {
304 }
305
306
307 /********************************************/
308 /* Test proxy implementation #1 ("Proxy A") */
309 /********************************************/
310
311 typedef GProxyBase GProxyA;
312 typedef GProxyBaseClass GProxyAClass;
313
314 static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
315
316 #define g_proxy_a_get_type _g_proxy_a_get_type
317 G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
318                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
319                                                 g_proxy_a_iface_init)
320                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
321                                                          g_define_type_id,
322                                                          "proxy-a",
323                                                          0))
324
325 static void
326 g_proxy_a_init (GProxyA *proxy)
327 {
328   ((GProxyBase *) proxy)->proxy_data = &proxy_a;
329 }
330
331 static gboolean
332 g_proxy_a_supports_hostname (GProxy *proxy)
333 {
334   return FALSE;
335 }
336
337 static void
338 g_proxy_a_class_init (GProxyAClass *class)
339 {
340 }
341
342 static void
343 g_proxy_a_iface_init (GProxyInterface *proxy_iface)
344 {
345   proxy_iface->connect = g_proxy_base_connect;
346   proxy_iface->connect_async = g_proxy_base_connect_async;
347   proxy_iface->connect_finish = g_proxy_base_connect_finish;
348   proxy_iface->supports_hostname = g_proxy_a_supports_hostname;
349 }
350
351 /********************************************/
352 /* Test proxy implementation #2 ("Proxy B") */
353 /********************************************/
354
355 typedef GProxyBase GProxyB;
356 typedef GProxyBaseClass GProxyBClass;
357
358 static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
359
360 #define g_proxy_b_get_type _g_proxy_b_get_type
361 G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
362                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
363                                                 g_proxy_b_iface_init)
364                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
365                                                          g_define_type_id,
366                                                          "proxy-b",
367                                                          0))
368
369 static void
370 g_proxy_b_init (GProxyB *proxy)
371 {
372   ((GProxyBase *) proxy)->proxy_data = &proxy_b;
373 }
374
375 static gboolean
376 g_proxy_b_supports_hostname (GProxy *proxy)
377 {
378   return TRUE;
379 }
380
381 static void
382 g_proxy_b_class_init (GProxyBClass *class)
383 {
384 }
385
386 static void
387 g_proxy_b_iface_init (GProxyInterface *proxy_iface)
388 {
389   proxy_iface->connect = g_proxy_base_connect;
390   proxy_iface->connect_async = g_proxy_base_connect_async;
391   proxy_iface->connect_finish = g_proxy_base_connect_finish;
392   proxy_iface->supports_hostname = g_proxy_b_supports_hostname;
393 }
394
395
396 /***********************************/
397 /* The proxy server implementation */
398 /***********************************/
399
400 static gboolean
401 proxy_bytes (GSocket      *socket,
402              GIOCondition  condition,
403              gpointer      user_data)
404 {
405   ProxyData *proxy = user_data;
406   gssize nread, nwrote, total;
407   gchar buffer[8];
408   GSocket *out_socket;
409   GError *error = NULL;
410
411   nread = g_socket_receive_with_blocking (socket, buffer, sizeof (buffer),
412                                           TRUE, NULL, &error);
413   if (nread == -1)
414     {
415       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
416       return FALSE;
417     }
418   else
419     g_assert_no_error (error);
420
421   if (nread == 0)
422     {
423       g_main_loop_quit (proxy->loop);
424       return FALSE;
425     }
426
427   if (socket == proxy->client_sock)
428     out_socket = proxy->server_sock;
429   else
430     out_socket = proxy->client_sock;
431
432   for (total = 0; total < nread; total += nwrote)
433     {
434       nwrote = g_socket_send_with_blocking (out_socket,
435                                             buffer + total, nread - total,
436                                             TRUE, NULL, &error);
437       g_assert_no_error (error);
438     }
439
440   return TRUE;
441 }
442
443 static gpointer
444 proxy_thread (gpointer user_data)
445 {
446   ProxyData *proxy = user_data;
447   GError *error = NULL;
448   gssize nread, nwrote;
449   gchar command[2] = { 0, 0 };
450   GMainContext *context;
451   GSource *read_source, *write_source;
452
453   context = g_main_context_new ();
454   proxy->loop = g_main_loop_new (context, FALSE);
455
456   while (TRUE)
457     {
458       proxy->client_sock = g_socket_accept (proxy->server, proxy->cancellable, &error);
459       if (!proxy->client_sock)
460         {
461           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
462           g_error_free (error);
463           break;
464         }
465       else
466         g_assert_no_error (error);
467
468       nread = g_socket_receive (proxy->client_sock, command, 1, NULL, &error);
469       g_assert_no_error (error);
470
471       if (nread == 0)
472         {
473           g_clear_object (&proxy->client_sock);
474           continue;
475         }
476
477       g_assert_cmpint (nread, ==, 1);
478       g_assert_cmpstr (command, ==, proxy->proxy_command);
479
480       *command = g_ascii_toupper (*command);
481       nwrote = g_socket_send (proxy->client_sock, command, 1, NULL, &error);
482       g_assert_no_error (error);
483       g_assert_cmpint (nwrote, ==, 1);
484
485       proxy->server_sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
486                                          G_SOCKET_TYPE_STREAM,
487                                          G_SOCKET_PROTOCOL_DEFAULT,
488                                          &error);
489       g_assert_no_error (error);
490       g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
491       g_assert_no_error (error);
492
493       read_source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
494       g_source_set_callback (read_source, (GSourceFunc)proxy_bytes, proxy, NULL);
495       g_source_attach (read_source, context);
496
497       write_source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
498       g_source_set_callback (write_source, (GSourceFunc)proxy_bytes, proxy, NULL);
499       g_source_attach (write_source, context);
500
501       g_main_loop_run (proxy->loop);
502
503       g_socket_close (proxy->client_sock, &error);
504       g_assert_no_error (error);
505       g_clear_object (&proxy->client_sock);
506
507       g_socket_close (proxy->server_sock, &error);
508       g_assert_no_error (error);
509       g_clear_object (&proxy->server_sock);
510
511       g_source_destroy (read_source);
512       g_source_unref (read_source);
513       g_source_destroy (write_source);
514       g_source_unref (write_source);
515     }
516
517   g_main_loop_unref (proxy->loop);
518   g_main_context_unref (context);
519
520   g_object_unref (proxy->server);
521   g_object_unref (proxy->cancellable);
522
523   g_free (proxy->proxy_command);
524   g_free (proxy->supported_protocol);
525   g_free (proxy->uri);
526
527   return NULL;
528 }
529
530 static void
531 create_proxy (ProxyData    *proxy,
532               gchar         proxy_protocol,
533               const gchar  *destination_protocol,
534               GCancellable *cancellable)
535 {
536   GError *error = NULL;
537   GSocketAddress *addr;
538   GInetAddress *iaddr;
539
540   proxy->proxy_command = g_strdup_printf ("%c", proxy_protocol);
541   proxy->supported_protocol = g_strdup (destination_protocol);
542   proxy->cancellable = g_object_ref (cancellable);
543
544   proxy->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
545                                 G_SOCKET_TYPE_STREAM,
546                                 G_SOCKET_PROTOCOL_DEFAULT,
547                                 &error);
548   g_assert_no_error (error);
549
550   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
551   addr = g_inet_socket_address_new (iaddr, 0);
552   g_object_unref (iaddr);
553
554   g_socket_bind (proxy->server, addr, TRUE, &error);
555   g_assert_no_error (error);
556   g_object_unref (addr);
557
558   addr = g_socket_get_local_address (proxy->server, &error);
559   proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
560   proxy->uri = g_strdup_printf ("proxy-%c://127.0.0.1:%u",
561                                 g_ascii_tolower (proxy_protocol),
562                                 proxy->port);
563   g_object_unref (addr);
564
565   g_socket_listen (proxy->server, &error);
566   g_assert_no_error (error);
567
568   proxy->thread = g_thread_new ("proxy", proxy_thread, proxy);
569 }
570
571
572
573 /**************************/
574 /* The actual echo server */
575 /**************************/
576
577 static gpointer
578 echo_server_thread (gpointer user_data)
579 {
580   ServerData *data = user_data;
581   GSocket *sock;
582   GError *error = NULL;
583   gssize nread, nwrote;
584   gchar buf[128];
585
586   while (TRUE)
587     {
588       sock = g_socket_accept (data->server, data->cancellable, &error);
589       if (!sock)
590         {
591           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
592           g_error_free (error);
593           break;
594         }
595       else
596         g_assert_no_error (error);
597
598       while (TRUE)
599         {
600           nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
601           g_assert_no_error (error);
602           g_assert_cmpint (nread, >=, 0);
603
604           if (nread == 0)
605             break;
606
607           nwrote = g_socket_send (sock, buf, nread, NULL, &error);
608           g_assert_no_error (error);
609           g_assert_cmpint (nwrote, ==, nread);
610         }
611
612       g_socket_close (sock, &error);
613       g_assert_no_error (error);
614       g_object_unref (sock);
615     }
616
617   g_object_unref (data->server);
618   g_object_unref (data->server_addr);
619   g_object_unref (data->cancellable);
620
621   return NULL;
622 }
623
624 static void
625 create_server (ServerData *data, GCancellable *cancellable)
626 {
627   GError *error = NULL;
628   GSocketAddress *addr;
629   GInetAddress *iaddr;
630
631   data->cancellable = g_object_ref (cancellable);
632
633   data->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
634                                G_SOCKET_TYPE_STREAM,
635                                G_SOCKET_PROTOCOL_DEFAULT,
636                                &error);
637   g_assert_no_error (error);
638
639   g_socket_set_blocking (data->server, TRUE);
640   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
641   addr = g_inet_socket_address_new (iaddr, 0);
642   g_object_unref (iaddr);
643
644   g_socket_bind (data->server, addr, TRUE, &error);
645   g_assert_no_error (error);
646   g_object_unref (addr);
647
648   data->server_addr = g_socket_get_local_address (data->server, &error);
649   g_assert_no_error (error);
650
651   data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
652
653   g_socket_listen (data->server, &error);
654   g_assert_no_error (error);
655
656   data->server_thread = g_thread_new ("server", echo_server_thread, data);
657 }
658
659
660 /******************************************************************/
661 /* Now a GResolver implementation, so the can't-resolve test will */
662 /* pass even if you have an evil DNS-faking ISP.                  */
663 /******************************************************************/
664
665 typedef GResolver GFakeResolver;
666 typedef GResolverClass GFakeResolverClass;
667
668 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
669
670 static void
671 g_fake_resolver_init (GFakeResolver *gtr)
672 {
673 }
674
675 static GList *
676 g_fake_resolver_lookup_by_name (GResolver     *resolver,
677                                 const gchar   *hostname,
678                                 GCancellable  *cancellable,
679                                 GError       **error)
680 {
681   /* This is only ever called with lookups that are expected to
682    * fail.
683    */
684   g_set_error (error,
685                G_RESOLVER_ERROR,
686                G_RESOLVER_ERROR_NOT_FOUND,
687                "Not found");
688   return NULL;
689 }
690
691 static void
692 g_fake_resolver_lookup_by_name_async (GResolver           *resolver,
693                                       const gchar         *hostname,
694                                       GCancellable        *cancellable,
695                                       GAsyncReadyCallback  callback,
696                                       gpointer             user_data)
697 {
698   g_task_report_new_error (resolver, callback, user_data,
699                            g_fake_resolver_lookup_by_name_async,
700                            G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
701                            "Not found");
702 }
703
704 static GList *
705 g_fake_resolver_lookup_by_name_finish (GResolver            *resolver,
706                                        GAsyncResult         *result,
707                                        GError              **error)
708 {
709   return g_task_propagate_pointer (G_TASK (result), error);
710 }
711
712 static void
713 g_fake_resolver_class_init (GFakeResolverClass *fake_class)
714 {
715   GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
716
717   resolver_class->lookup_by_name        = g_fake_resolver_lookup_by_name;
718   resolver_class->lookup_by_name_async  = g_fake_resolver_lookup_by_name_async;
719   resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish;
720 }
721
722
723
724 /****************************************/
725 /* We made it! Now for the actual test! */
726 /****************************************/
727
728 static void
729 setup_test (gpointer fixture,
730             gconstpointer user_data)
731 {
732 }
733
734 static void
735 teardown_test (gpointer fixture,
736                gconstpointer user_data)
737 {
738   if (last_proxies)
739     {
740       g_strfreev (last_proxies);
741       last_proxies = NULL;
742     }
743   g_clear_error (&proxy_a.last_error);
744   g_clear_error (&proxy_b.last_error);
745 }
746
747
748 static const gchar *testbuf = "0123456789abcdef";
749
750 static void
751 do_echo_test (GSocketConnection *conn)
752 {
753   GIOStream *iostream = G_IO_STREAM (conn);
754   GInputStream *istream = g_io_stream_get_input_stream (iostream);
755   GOutputStream *ostream = g_io_stream_get_output_stream (iostream);
756   gssize nread, total;
757   gsize nwrote;
758   gchar buf[128];
759   GError *error = NULL;
760
761   g_output_stream_write_all (ostream, testbuf, strlen (testbuf),
762                              &nwrote, NULL, &error);
763   g_assert_no_error (error);
764   g_assert_cmpint (nwrote, ==, strlen (testbuf));
765
766   for (total = 0; total < nwrote; total += nread)
767     {
768       nread = g_input_stream_read (istream,
769                                    buf + total, sizeof (buf) - total,
770                                    NULL, &error);
771       g_assert_no_error (error);
772       g_assert_cmpint (nread, >, 0);
773     }
774
775   buf[total] = '\0';
776   g_assert_cmpstr (buf, ==, testbuf);
777 }
778
779 static void
780 async_got_conn (GObject      *source,
781                 GAsyncResult *result,
782                 gpointer      user_data)
783 {
784   GSocketConnection **conn = user_data;
785   GError *error = NULL;
786
787   *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
788                                           result, &error);
789   g_assert_no_error (error);
790 }
791
792 static void
793 async_got_error (GObject      *source,
794                  GAsyncResult *result,
795                  gpointer      user_data)
796 {
797   GError **error = user_data;
798
799   g_assert (error != NULL && *error == NULL);
800   g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
801                                   result, error);
802   g_assert (*error != NULL);
803 }
804
805
806 static void
807 assert_direct (GSocketConnection *conn)
808 {
809   GSocketAddress *addr;
810   GError *error = NULL;
811
812   g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
813   g_assert_cmpstr (last_proxies[0], ==, "direct://");
814   g_assert_no_error (proxy_a.last_error);
815   g_assert_no_error (proxy_b.last_error);
816
817   addr = g_socket_connection_get_remote_address (conn, &error);
818   g_assert_no_error (error);
819   g_assert (!G_IS_PROXY_ADDRESS (addr));
820   g_object_unref (addr);
821
822   addr = g_socket_connection_get_local_address (conn, &error);
823   g_assert_no_error (error);
824   g_object_unref (addr);
825
826   g_assert (g_socket_connection_is_connected (conn));
827 }
828
829 static void
830 test_direct_sync (gpointer fixture,
831                   gconstpointer user_data)
832 {
833   GSocketConnection *conn;
834   gchar *uri;
835   GError *error = NULL;
836
837   /* The simple:// URI should not require any proxy. */
838
839   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
840   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
841   g_free (uri);
842   g_assert_no_error (error);
843
844   assert_direct (conn);
845   do_echo_test (conn);
846   g_object_unref (conn);
847 }
848
849 static void
850 test_direct_async (gpointer fixture,
851                    gconstpointer user_data)
852 {
853   GSocketConnection *conn;
854   gchar *uri;
855
856   /* The simple:// URI should not require any proxy. */
857   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
858   conn = NULL;
859   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
860                                         async_got_conn, &conn);
861   g_free (uri);
862   while (conn == NULL)
863     g_main_context_iteration (NULL, TRUE);
864
865   assert_direct (conn);
866   do_echo_test (conn);
867   g_object_unref (conn);
868 }
869
870 static void
871 assert_single (GSocketConnection *conn)
872 {
873   GSocketAddress *addr;
874   const gchar *proxy_uri;
875   gushort proxy_port;
876   GError *error = NULL;
877
878   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
879   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
880   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
881   g_assert_no_error (proxy_a.last_error);
882   g_assert_no_error (proxy_b.last_error);
883
884   addr = g_socket_connection_get_remote_address (conn, &error);
885   g_assert_no_error (error);
886   g_assert (G_IS_PROXY_ADDRESS (addr));
887   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
888   g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
889   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
890   g_assert_cmpint (proxy_port, ==, proxy_a.port);
891
892   g_object_unref (addr);
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   g_object_unref (addr);
959 }
960
961 static void
962 test_multiple_sync (gpointer fixture,
963                     gconstpointer user_data)
964 {
965   GSocketConnection *conn;
966   GError *error = NULL;
967   gchar *uri;
968
969   /* The beta:// URI should be proxied via Proxy B, after failing
970    * via Proxy A.
971    */
972   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
973   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
974   g_free (uri);
975   g_assert_no_error (error);
976
977   assert_multiple (conn);
978   do_echo_test (conn);
979   g_object_unref (conn);
980 }
981
982 static void
983 test_multiple_async (gpointer fixture,
984                      gconstpointer user_data)
985 {
986   GSocketConnection *conn;
987   gchar *uri;
988
989   /* The beta:// URI should be proxied via Proxy B, after failing
990    * via Proxy A.
991    */
992   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
993   conn = NULL;
994   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
995                                         async_got_conn, &conn);
996   g_free (uri);
997   while (conn == NULL)
998     g_main_context_iteration (NULL, TRUE);
999
1000   assert_multiple (conn);
1001   do_echo_test (conn);
1002   g_object_unref (conn);
1003 }
1004
1005 static void
1006 test_dns (gpointer fixture,
1007           gconstpointer user_data)
1008 {
1009   GSocketConnection *conn;
1010   GError *error = NULL;
1011   gchar *uri;
1012
1013   /* The simple:// and alpha:// URIs should fail with a DNS error,
1014    * but the beta:// URI should succeed, because we pass it to
1015    * Proxy B without trying to resolve it first
1016    */
1017
1018   /* simple */
1019   uri = g_strdup_printf ("simple://no-such-host.xx:%u", server.server_port);
1020   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1021   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1022   g_clear_error (&error);
1023
1024   g_assert_no_error (proxy_a.last_error);
1025   g_assert_no_error (proxy_b.last_error);
1026   teardown_test (NULL, NULL);
1027
1028   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1029                                         async_got_error, &error);
1030   while (error == NULL)
1031     g_main_context_iteration (NULL, TRUE);
1032   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1033   g_clear_error (&error);
1034   g_free (uri);
1035
1036   g_assert_no_error (proxy_a.last_error);
1037   g_assert_no_error (proxy_b.last_error);
1038   teardown_test (NULL, NULL);
1039
1040   /* alpha */
1041   uri = g_strdup_printf ("alpha://no-such-host.xx:%u", server.server_port);
1042   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1043   /* Since Proxy A fails, @client will try Proxy B too, which won't
1044    * load an alpha:// URI.
1045    */
1046   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1047   g_clear_error (&error);
1048
1049   g_assert_no_error (proxy_a.last_error);
1050   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1051   teardown_test (NULL, NULL);
1052
1053   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1054                                         async_got_error, &error);
1055   while (error == NULL)
1056     g_main_context_iteration (NULL, TRUE);
1057   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1058   g_clear_error (&error);
1059   g_free (uri);
1060
1061   g_assert_no_error (proxy_a.last_error);
1062   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1063   teardown_test (NULL, NULL);
1064
1065   /* beta */
1066   uri = g_strdup_printf ("beta://no-such-host.xx:%u", server.server_port);
1067   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1068   g_assert_no_error (error);
1069
1070   g_assert_no_error (proxy_a.last_error);
1071   g_assert_no_error (proxy_b.last_error);
1072
1073   do_echo_test (conn);
1074   g_clear_object (&conn);
1075   teardown_test (NULL, NULL);
1076
1077   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1078                                         async_got_conn, &conn);
1079   while (conn == NULL)
1080     g_main_context_iteration (NULL, TRUE);
1081   g_free (uri);
1082
1083   g_assert_no_error (proxy_a.last_error);
1084   g_assert_no_error (proxy_b.last_error);
1085
1086   do_echo_test (conn);
1087   g_clear_object (&conn);
1088   teardown_test (NULL, NULL);
1089 }
1090
1091 int
1092 main (int   argc,
1093       char *argv[])
1094 {
1095   GResolver *fake_resolver;
1096   GCancellable *cancellable;
1097   gint result;
1098
1099   g_test_init (&argc, &argv, NULL);
1100
1101   /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1102    * is to force _g_io_modules_ensure_extension_points_registered() to
1103    * get called, so we can then register a proxy resolver extension
1104    * point.
1105    */
1106   g_proxy_get_default_for_protocol ("foo");
1107   g_test_proxy_resolver_get_type ();
1108   g_proxy_a_get_type ();
1109   g_proxy_b_get_type ();
1110   g_setenv ("GIO_USE_PROXY_RESOLVER", "test", TRUE);
1111
1112   fake_resolver = g_object_new (g_fake_resolver_get_type (), NULL);
1113   g_resolver_set_default (fake_resolver);
1114
1115   cancellable = g_cancellable_new ();
1116   create_server (&server, cancellable);
1117   create_proxy (&proxy_a, 'a', "alpha", cancellable);
1118   create_proxy (&proxy_b, 'b', "beta", cancellable);
1119
1120   client = g_socket_client_new ();
1121   g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1122
1123   g_test_add_vtable ("/proxy/direct_sync", 0, NULL, setup_test, test_direct_sync, teardown_test);
1124   g_test_add_vtable ("/proxy/direct_async", 0, NULL, setup_test, test_direct_async, teardown_test);
1125   g_test_add_vtable ("/proxy/single_sync", 0, NULL, setup_test, test_single_sync, teardown_test);
1126   g_test_add_vtable ("/proxy/single_async", 0, NULL, setup_test, test_single_async, teardown_test);
1127   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
1128   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
1129   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
1130
1131   result = g_test_run();
1132
1133   g_object_unref (client);
1134
1135   g_cancellable_cancel (cancellable);
1136   g_thread_join (proxy_a.thread);
1137   g_thread_join (proxy_b.thread);
1138   g_thread_join (server.server_thread);
1139
1140   g_object_unref (cancellable);
1141
1142   return result;
1143 }
1144