Improve GSettings test coverage
[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 two GProxyResolver implementations.
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 default GProxyResolver (GTestProxyResolver) looks at its URI
46  * and returns [ "direct://" ] for "simple://" URIs, and [
47  * proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver
48  * (GTestAltProxyResolver) always returns [ proxy_a.uri ].
49  */
50
51 typedef struct {
52   gchar *proxy_command;
53   gchar *supported_protocol;
54
55   GSocket *server;
56   GThread *thread;
57   GCancellable *cancellable;
58   gchar *uri;
59   gushort port;
60
61   GSocket *client_sock, *server_sock;
62   GMainLoop *loop;
63
64   GError *last_error;
65 } ProxyData;
66
67 static ProxyData proxy_a, proxy_b;
68
69 typedef struct {
70   GSocket *server;
71   GThread *server_thread;
72   GCancellable *cancellable;
73   GSocketAddress *server_addr;
74   gushort server_port;
75 } ServerData;
76
77 static ServerData server;
78
79 static gchar **last_proxies;
80
81 static GSocketClient *client;
82
83
84 /**************************************/
85 /* Test GProxyResolver implementation */
86 /**************************************/
87
88 typedef struct {
89   GObject parent_instance;
90 } GTestProxyResolver;
91
92 typedef struct {
93   GObjectClass parent_class;
94 } GTestProxyResolverClass;
95
96 static void g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface);
97
98 static GType _g_test_proxy_resolver_get_type (void);
99 #define g_test_proxy_resolver_get_type _g_test_proxy_resolver_get_type
100 G_DEFINE_TYPE_WITH_CODE (GTestProxyResolver, g_test_proxy_resolver, G_TYPE_OBJECT,
101                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
102                                                 g_test_proxy_resolver_iface_init)
103                          g_io_extension_point_implement (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
104                                                          g_define_type_id,
105                                                          "test",
106                                                          0))
107
108 static void
109 g_test_proxy_resolver_init (GTestProxyResolver *resolver)
110 {
111 }
112
113 static gboolean
114 g_test_proxy_resolver_is_supported (GProxyResolver *resolver)
115 {
116   return TRUE;
117 }
118
119 static gchar **
120 g_test_proxy_resolver_lookup (GProxyResolver  *resolver,
121                               const gchar     *uri,
122                               GCancellable    *cancellable,
123                               GError         **error)
124 {
125   gchar **proxies;
126
127   g_assert (last_proxies == NULL);
128
129   if (g_cancellable_set_error_if_cancelled (cancellable, error))
130     return NULL;
131
132   proxies = g_new (gchar *, 3);
133
134   if (!strncmp (uri, "simple://", 4))
135     {
136       proxies[0] = g_strdup ("direct://");
137       proxies[1] = NULL;
138     }
139   else
140     {
141       /* Proxy A can only deal with "alpha://" URIs, not
142        * "beta://", but we always return both URIs
143        * anyway so we can test error handling when the first
144        * fails.
145        */
146       proxies[0] = g_strdup (proxy_a.uri);
147       proxies[1] = g_strdup (proxy_b.uri);
148       proxies[2] = NULL;
149     }
150
151   last_proxies = g_strdupv (proxies);
152
153   return proxies;
154 }
155
156 static void
157 g_test_proxy_resolver_lookup_async (GProxyResolver      *resolver,
158                                     const gchar         *uri,
159                                     GCancellable        *cancellable,
160                                     GAsyncReadyCallback  callback,
161                                     gpointer             user_data)
162 {
163   GError *error = NULL;
164   GTask *task;
165   gchar **proxies;
166
167   proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
168
169   task = g_task_new (resolver, NULL, callback, user_data);
170   if (proxies == NULL)
171     g_task_return_error (task, error);
172   else
173     g_task_return_pointer (task, proxies, (GDestroyNotify) g_strfreev);
174
175   g_object_unref (task);
176 }
177
178 static gchar **
179 g_test_proxy_resolver_lookup_finish (GProxyResolver     *resolver,
180                                      GAsyncResult       *result,
181                                      GError            **error)
182 {
183   return g_task_propagate_pointer (G_TASK (result), error);
184 }
185
186 static void
187 g_test_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
188 {
189 }
190
191 static void
192 g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
193 {
194   iface->is_supported = g_test_proxy_resolver_is_supported;
195   iface->lookup = g_test_proxy_resolver_lookup;
196   iface->lookup_async = g_test_proxy_resolver_lookup_async;
197   iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
198 }
199
200 /****************************/
201 /* Alternate GProxyResolver */
202 /****************************/
203
204 typedef GTestProxyResolver GTestAltProxyResolver;
205 typedef GTestProxyResolverClass GTestAltProxyResolverClass;
206
207 static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
208
209 static GType _g_test_alt_proxy_resolver_get_type (void);
210 #define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
211 G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
212                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
213                                                 g_test_alt_proxy_resolver_iface_init);
214                          )
215
216 static void
217 g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
218 {
219 }
220
221 static gchar **
222 g_test_alt_proxy_resolver_lookup (GProxyResolver  *resolver,
223                                   const gchar     *uri,
224                                   GCancellable    *cancellable,
225                                   GError         **error)
226 {
227   gchar **proxies;
228
229   proxies = g_new (gchar *, 2);
230
231   proxies[0] = g_strdup (proxy_a.uri);
232   proxies[1] = NULL;
233
234   last_proxies = g_strdupv (proxies);
235
236   return proxies;
237 }
238
239 static void
240 g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
241 {
242 }
243
244 static void
245 g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
246 {
247   iface->lookup = g_test_alt_proxy_resolver_lookup;
248 }
249
250
251 /****************************************/
252 /* Test proxy implementation base class */
253 /****************************************/
254
255 typedef struct {
256   GObject parent;
257
258   ProxyData *proxy_data;
259 } GProxyBase;
260
261 typedef struct {
262   GObjectClass parent_class;
263 } GProxyBaseClass;
264
265 static GType _g_proxy_base_get_type (void);
266 #define g_proxy_base_get_type _g_proxy_base_get_type
267 G_DEFINE_ABSTRACT_TYPE (GProxyBase, g_proxy_base, G_TYPE_OBJECT)
268
269 static void
270 g_proxy_base_init (GProxyBase *proxy)
271 {
272 }
273
274 static GIOStream *
275 g_proxy_base_connect (GProxy            *proxy,
276                       GIOStream         *io_stream,
277                       GProxyAddress     *proxy_address,
278                       GCancellable      *cancellable,
279                       GError           **error)
280 {
281   ProxyData *data = ((GProxyBase *) proxy)->proxy_data;
282   const gchar *protocol;
283   GOutputStream *ostream;
284   GInputStream *istream;
285   gchar response;
286
287   g_assert_no_error (data->last_error);
288
289   protocol = g_proxy_address_get_destination_protocol (proxy_address);
290   if (strcmp (protocol, data->supported_protocol) != 0)
291     {
292       g_set_error_literal (&data->last_error,
293                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
294                            "Unsupported protocol");
295       goto fail;
296     }
297
298   ostream = g_io_stream_get_output_stream (io_stream);
299   if (g_output_stream_write (ostream, data->proxy_command, 1, cancellable,
300                              &data->last_error) != 1)
301     goto fail;
302
303   istream = g_io_stream_get_input_stream (io_stream);
304   if (g_input_stream_read (istream, &response, 1, cancellable,
305                            &data->last_error) != 1)
306     goto fail;
307
308   if (response != g_ascii_toupper (*data->proxy_command))
309     {
310       g_set_error_literal (&data->last_error,
311                            G_IO_ERROR, G_IO_ERROR_FAILED,
312                            "Failed");
313       goto fail;
314     }
315
316   return g_object_ref (io_stream);
317
318  fail:
319   g_propagate_error (error, g_error_copy (data->last_error));
320   return NULL;
321 }
322
323 static void
324 g_proxy_base_connect_async (GProxy               *proxy,
325                             GIOStream            *io_stream,
326                             GProxyAddress        *proxy_address,
327                             GCancellable         *cancellable,
328                             GAsyncReadyCallback   callback,
329                             gpointer              user_data)
330 {
331   GError *error = NULL;
332   GTask *task;
333   GIOStream *proxy_io_stream;
334
335   task = g_task_new (proxy, NULL, callback, user_data);
336
337   proxy_io_stream = g_proxy_connect (proxy, io_stream, proxy_address,
338                                      cancellable, &error);
339   if (proxy_io_stream)
340     g_task_return_pointer (task, proxy_io_stream, g_object_unref);
341   else
342     g_task_return_error (task, error);
343   g_object_unref (task);
344 }
345
346 static GIOStream *
347 g_proxy_base_connect_finish (GProxy        *proxy,
348                              GAsyncResult  *result,
349                              GError       **error)
350 {
351   return g_task_propagate_pointer (G_TASK (result), error);
352 }
353
354 static void
355 g_proxy_base_class_init (GProxyBaseClass *class)
356 {
357 }
358
359
360 /********************************************/
361 /* Test proxy implementation #1 ("Proxy A") */
362 /********************************************/
363
364 typedef GProxyBase GProxyA;
365 typedef GProxyBaseClass GProxyAClass;
366
367 static void g_proxy_a_iface_init (GProxyInterface *proxy_iface);
368
369 static GType _g_proxy_a_get_type (void);
370 #define g_proxy_a_get_type _g_proxy_a_get_type
371 G_DEFINE_TYPE_WITH_CODE (GProxyA, g_proxy_a, g_proxy_base_get_type (),
372                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
373                                                 g_proxy_a_iface_init)
374                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
375                                                          g_define_type_id,
376                                                          "proxy-a",
377                                                          0))
378
379 static void
380 g_proxy_a_init (GProxyA *proxy)
381 {
382   ((GProxyBase *) proxy)->proxy_data = &proxy_a;
383 }
384
385 static gboolean
386 g_proxy_a_supports_hostname (GProxy *proxy)
387 {
388   return FALSE;
389 }
390
391 static void
392 g_proxy_a_class_init (GProxyAClass *class)
393 {
394 }
395
396 static void
397 g_proxy_a_iface_init (GProxyInterface *proxy_iface)
398 {
399   proxy_iface->connect = g_proxy_base_connect;
400   proxy_iface->connect_async = g_proxy_base_connect_async;
401   proxy_iface->connect_finish = g_proxy_base_connect_finish;
402   proxy_iface->supports_hostname = g_proxy_a_supports_hostname;
403 }
404
405 /********************************************/
406 /* Test proxy implementation #2 ("Proxy B") */
407 /********************************************/
408
409 typedef GProxyBase GProxyB;
410 typedef GProxyBaseClass GProxyBClass;
411
412 static void g_proxy_b_iface_init (GProxyInterface *proxy_iface);
413
414 static GType _g_proxy_b_get_type (void);
415 #define g_proxy_b_get_type _g_proxy_b_get_type
416 G_DEFINE_TYPE_WITH_CODE (GProxyB, g_proxy_b, g_proxy_base_get_type (),
417                          G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
418                                                 g_proxy_b_iface_init)
419                          g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
420                                                          g_define_type_id,
421                                                          "proxy-b",
422                                                          0))
423
424 static void
425 g_proxy_b_init (GProxyB *proxy)
426 {
427   ((GProxyBase *) proxy)->proxy_data = &proxy_b;
428 }
429
430 static gboolean
431 g_proxy_b_supports_hostname (GProxy *proxy)
432 {
433   return TRUE;
434 }
435
436 static void
437 g_proxy_b_class_init (GProxyBClass *class)
438 {
439 }
440
441 static void
442 g_proxy_b_iface_init (GProxyInterface *proxy_iface)
443 {
444   proxy_iface->connect = g_proxy_base_connect;
445   proxy_iface->connect_async = g_proxy_base_connect_async;
446   proxy_iface->connect_finish = g_proxy_base_connect_finish;
447   proxy_iface->supports_hostname = g_proxy_b_supports_hostname;
448 }
449
450
451 /***********************************/
452 /* The proxy server implementation */
453 /***********************************/
454
455 static gboolean
456 proxy_bytes (GSocket      *socket,
457              GIOCondition  condition,
458              gpointer      user_data)
459 {
460   ProxyData *proxy = user_data;
461   gssize nread, nwrote, total;
462   gchar buffer[8];
463   GSocket *out_socket;
464   GError *error = NULL;
465
466   nread = g_socket_receive_with_blocking (socket, buffer, sizeof (buffer),
467                                           TRUE, NULL, &error);
468   if (nread == -1)
469     {
470       g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED);
471       return FALSE;
472     }
473   else
474     g_assert_no_error (error);
475
476   if (nread == 0)
477     {
478       g_main_loop_quit (proxy->loop);
479       return FALSE;
480     }
481
482   if (socket == proxy->client_sock)
483     out_socket = proxy->server_sock;
484   else
485     out_socket = proxy->client_sock;
486
487   for (total = 0; total < nread; total += nwrote)
488     {
489       nwrote = g_socket_send_with_blocking (out_socket,
490                                             buffer + total, nread - total,
491                                             TRUE, NULL, &error);
492       g_assert_no_error (error);
493     }
494
495   return TRUE;
496 }
497
498 static gpointer
499 proxy_thread (gpointer user_data)
500 {
501   ProxyData *proxy = user_data;
502   GError *error = NULL;
503   gssize nread, nwrote;
504   gchar command[2] = { 0, 0 };
505   GMainContext *context;
506   GSource *read_source, *write_source;
507
508   context = g_main_context_new ();
509   proxy->loop = g_main_loop_new (context, FALSE);
510
511   while (TRUE)
512     {
513       proxy->client_sock = g_socket_accept (proxy->server, proxy->cancellable, &error);
514       if (!proxy->client_sock)
515         {
516           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
517           g_error_free (error);
518           break;
519         }
520       else
521         g_assert_no_error (error);
522
523       nread = g_socket_receive (proxy->client_sock, command, 1, NULL, &error);
524       g_assert_no_error (error);
525
526       if (nread == 0)
527         {
528           g_clear_object (&proxy->client_sock);
529           continue;
530         }
531
532       g_assert_cmpint (nread, ==, 1);
533       g_assert_cmpstr (command, ==, proxy->proxy_command);
534
535       *command = g_ascii_toupper (*command);
536       nwrote = g_socket_send (proxy->client_sock, command, 1, NULL, &error);
537       g_assert_no_error (error);
538       g_assert_cmpint (nwrote, ==, 1);
539
540       proxy->server_sock = g_socket_new (G_SOCKET_FAMILY_IPV4,
541                                          G_SOCKET_TYPE_STREAM,
542                                          G_SOCKET_PROTOCOL_DEFAULT,
543                                          &error);
544       g_assert_no_error (error);
545       g_socket_connect (proxy->server_sock, server.server_addr, NULL, &error);
546       g_assert_no_error (error);
547
548       read_source = g_socket_create_source (proxy->client_sock, G_IO_IN, NULL);
549       g_source_set_callback (read_source, (GSourceFunc)proxy_bytes, proxy, NULL);
550       g_source_attach (read_source, context);
551
552       write_source = g_socket_create_source (proxy->server_sock, G_IO_IN, NULL);
553       g_source_set_callback (write_source, (GSourceFunc)proxy_bytes, proxy, NULL);
554       g_source_attach (write_source, context);
555
556       g_main_loop_run (proxy->loop);
557
558       g_socket_close (proxy->client_sock, &error);
559       g_assert_no_error (error);
560       g_clear_object (&proxy->client_sock);
561
562       g_socket_close (proxy->server_sock, &error);
563       g_assert_no_error (error);
564       g_clear_object (&proxy->server_sock);
565
566       g_source_destroy (read_source);
567       g_source_unref (read_source);
568       g_source_destroy (write_source);
569       g_source_unref (write_source);
570     }
571
572   g_main_loop_unref (proxy->loop);
573   g_main_context_unref (context);
574
575   g_object_unref (proxy->server);
576   g_object_unref (proxy->cancellable);
577
578   g_free (proxy->proxy_command);
579   g_free (proxy->supported_protocol);
580   g_free (proxy->uri);
581
582   return NULL;
583 }
584
585 static void
586 create_proxy (ProxyData    *proxy,
587               gchar         proxy_protocol,
588               const gchar  *destination_protocol,
589               GCancellable *cancellable)
590 {
591   GError *error = NULL;
592   GSocketAddress *addr;
593   GInetAddress *iaddr;
594
595   proxy->proxy_command = g_strdup_printf ("%c", proxy_protocol);
596   proxy->supported_protocol = g_strdup (destination_protocol);
597   proxy->cancellable = g_object_ref (cancellable);
598
599   proxy->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
600                                 G_SOCKET_TYPE_STREAM,
601                                 G_SOCKET_PROTOCOL_DEFAULT,
602                                 &error);
603   g_assert_no_error (error);
604
605   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
606   addr = g_inet_socket_address_new (iaddr, 0);
607   g_object_unref (iaddr);
608
609   g_socket_bind (proxy->server, addr, TRUE, &error);
610   g_assert_no_error (error);
611   g_object_unref (addr);
612
613   addr = g_socket_get_local_address (proxy->server, &error);
614   proxy->port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
615   proxy->uri = g_strdup_printf ("proxy-%c://127.0.0.1:%u",
616                                 g_ascii_tolower (proxy_protocol),
617                                 proxy->port);
618   g_object_unref (addr);
619
620   g_socket_listen (proxy->server, &error);
621   g_assert_no_error (error);
622
623   proxy->thread = g_thread_new ("proxy", proxy_thread, proxy);
624 }
625
626
627
628 /**************************/
629 /* The actual echo server */
630 /**************************/
631
632 static gpointer
633 echo_server_thread (gpointer user_data)
634 {
635   ServerData *data = user_data;
636   GSocket *sock;
637   GError *error = NULL;
638   gssize nread, nwrote;
639   gchar buf[128];
640
641   while (TRUE)
642     {
643       sock = g_socket_accept (data->server, data->cancellable, &error);
644       if (!sock)
645         {
646           g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
647           g_error_free (error);
648           break;
649         }
650       else
651         g_assert_no_error (error);
652
653       while (TRUE)
654         {
655           nread = g_socket_receive (sock, buf, sizeof (buf), NULL, &error);
656           g_assert_no_error (error);
657           g_assert_cmpint (nread, >=, 0);
658
659           if (nread == 0)
660             break;
661
662           nwrote = g_socket_send (sock, buf, nread, NULL, &error);
663           g_assert_no_error (error);
664           g_assert_cmpint (nwrote, ==, nread);
665         }
666
667       g_socket_close (sock, &error);
668       g_assert_no_error (error);
669       g_object_unref (sock);
670     }
671
672   g_object_unref (data->server);
673   g_object_unref (data->server_addr);
674   g_object_unref (data->cancellable);
675
676   return NULL;
677 }
678
679 static void
680 create_server (ServerData *data, GCancellable *cancellable)
681 {
682   GError *error = NULL;
683   GSocketAddress *addr;
684   GInetAddress *iaddr;
685
686   data->cancellable = g_object_ref (cancellable);
687
688   data->server = g_socket_new (G_SOCKET_FAMILY_IPV4,
689                                G_SOCKET_TYPE_STREAM,
690                                G_SOCKET_PROTOCOL_DEFAULT,
691                                &error);
692   g_assert_no_error (error);
693
694   g_socket_set_blocking (data->server, TRUE);
695   iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4);
696   addr = g_inet_socket_address_new (iaddr, 0);
697   g_object_unref (iaddr);
698
699   g_socket_bind (data->server, addr, TRUE, &error);
700   g_assert_no_error (error);
701   g_object_unref (addr);
702
703   data->server_addr = g_socket_get_local_address (data->server, &error);
704   g_assert_no_error (error);
705
706   data->server_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (data->server_addr));
707
708   g_socket_listen (data->server, &error);
709   g_assert_no_error (error);
710
711   data->server_thread = g_thread_new ("server", echo_server_thread, data);
712 }
713
714
715 /******************************************************************/
716 /* Now a GResolver implementation, so the can't-resolve test will */
717 /* pass even if you have an evil DNS-faking ISP.                  */
718 /******************************************************************/
719
720 typedef GResolver GFakeResolver;
721 typedef GResolverClass GFakeResolverClass;
722
723 static GType g_fake_resolver_get_type (void);
724 G_DEFINE_TYPE (GFakeResolver, g_fake_resolver, G_TYPE_RESOLVER)
725
726 static void
727 g_fake_resolver_init (GFakeResolver *gtr)
728 {
729 }
730
731 static GList *
732 g_fake_resolver_lookup_by_name (GResolver     *resolver,
733                                 const gchar   *hostname,
734                                 GCancellable  *cancellable,
735                                 GError       **error)
736 {
737   if (!strcmp (hostname, "example.com"))
738     return g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
739   else
740     {
741       /* Anything else is expected to fail. */
742       g_set_error (error,
743                    G_RESOLVER_ERROR,
744                    G_RESOLVER_ERROR_NOT_FOUND,
745                    "Not found");
746       return NULL;
747     }
748 }
749
750 static void
751 g_fake_resolver_lookup_by_name_async (GResolver           *resolver,
752                                       const gchar         *hostname,
753                                       GCancellable        *cancellable,
754                                       GAsyncReadyCallback  callback,
755                                       gpointer             user_data)
756 {
757   GTask *task;
758
759   task = g_task_new (resolver, cancellable, callback, user_data);
760
761   if (!strcmp (hostname, "example.com"))
762     {
763       GList *result;
764
765       result = g_list_prepend (NULL, g_inet_address_new_from_string ("127.0.0.1"));
766       g_task_return_pointer (task, result, (GDestroyNotify) g_resolver_free_addresses);
767     }
768   else
769     {
770       g_task_return_new_error (task,
771                                G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND,
772                                "Not found");
773     }
774   g_object_unref (task);
775 }
776
777 static GList *
778 g_fake_resolver_lookup_by_name_finish (GResolver            *resolver,
779                                        GAsyncResult         *result,
780                                        GError              **error)
781 {
782   return g_task_propagate_pointer (G_TASK (result), error);
783 }
784
785 static void
786 g_fake_resolver_class_init (GFakeResolverClass *fake_class)
787 {
788   GResolverClass *resolver_class = G_RESOLVER_CLASS (fake_class);
789
790   resolver_class->lookup_by_name        = g_fake_resolver_lookup_by_name;
791   resolver_class->lookup_by_name_async  = g_fake_resolver_lookup_by_name_async;
792   resolver_class->lookup_by_name_finish = g_fake_resolver_lookup_by_name_finish;
793 }
794
795
796
797 /****************************************/
798 /* We made it! Now for the actual test! */
799 /****************************************/
800
801 static void
802 setup_test (gpointer fixture,
803             gconstpointer user_data)
804 {
805 }
806
807 static void
808 teardown_test (gpointer fixture,
809                gconstpointer user_data)
810 {
811   if (last_proxies)
812     {
813       g_strfreev (last_proxies);
814       last_proxies = NULL;
815     }
816   g_clear_error (&proxy_a.last_error);
817   g_clear_error (&proxy_b.last_error);
818 }
819
820
821 static const gchar *testbuf = "0123456789abcdef";
822
823 static void
824 do_echo_test (GSocketConnection *conn)
825 {
826   GIOStream *iostream = G_IO_STREAM (conn);
827   GInputStream *istream = g_io_stream_get_input_stream (iostream);
828   GOutputStream *ostream = g_io_stream_get_output_stream (iostream);
829   gssize nread, total;
830   gsize nwrote;
831   gchar buf[128];
832   GError *error = NULL;
833
834   g_output_stream_write_all (ostream, testbuf, strlen (testbuf),
835                              &nwrote, NULL, &error);
836   g_assert_no_error (error);
837   g_assert_cmpint (nwrote, ==, strlen (testbuf));
838
839   for (total = 0; total < nwrote; total += nread)
840     {
841       nread = g_input_stream_read (istream,
842                                    buf + total, sizeof (buf) - total,
843                                    NULL, &error);
844       g_assert_no_error (error);
845       g_assert_cmpint (nread, >, 0);
846     }
847
848   buf[total] = '\0';
849   g_assert_cmpstr (buf, ==, testbuf);
850 }
851
852 static void
853 async_got_conn (GObject      *source,
854                 GAsyncResult *result,
855                 gpointer      user_data)
856 {
857   GSocketConnection **conn = user_data;
858   GError *error = NULL;
859
860   *conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
861                                           result, &error);
862   g_assert_no_error (error);
863 }
864
865 static void
866 async_got_error (GObject      *source,
867                  GAsyncResult *result,
868                  gpointer      user_data)
869 {
870   GError **error = user_data;
871
872   g_assert (error != NULL && *error == NULL);
873   g_socket_client_connect_finish (G_SOCKET_CLIENT (source),
874                                   result, error);
875   g_assert (*error != NULL);
876 }
877
878
879 static void
880 assert_direct (GSocketConnection *conn)
881 {
882   GSocketAddress *addr;
883   GError *error = NULL;
884
885   g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
886   g_assert_cmpstr (last_proxies[0], ==, "direct://");
887   g_assert_no_error (proxy_a.last_error);
888   g_assert_no_error (proxy_b.last_error);
889
890   addr = g_socket_connection_get_remote_address (conn, &error);
891   g_assert_no_error (error);
892   g_assert (addr != NULL && !G_IS_PROXY_ADDRESS (addr));
893   g_object_unref (addr);
894
895   addr = g_socket_connection_get_local_address (conn, &error);
896   g_assert_no_error (error);
897   g_object_unref (addr);
898
899   g_assert (g_socket_connection_is_connected (conn));
900 }
901
902 static void
903 test_direct_sync (gpointer fixture,
904                   gconstpointer user_data)
905 {
906   GSocketConnection *conn;
907   gchar *uri;
908   GError *error = NULL;
909
910   /* The simple:// URI should not require any proxy. */
911
912   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
913   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
914   g_free (uri);
915   g_assert_no_error (error);
916
917   assert_direct (conn);
918   do_echo_test (conn);
919   g_object_unref (conn);
920 }
921
922 static void
923 test_direct_async (gpointer fixture,
924                    gconstpointer user_data)
925 {
926   GSocketConnection *conn;
927   gchar *uri;
928
929   /* The simple:// URI should not require any proxy. */
930   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
931   conn = NULL;
932   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
933                                         async_got_conn, &conn);
934   g_free (uri);
935   while (conn == NULL)
936     g_main_context_iteration (NULL, TRUE);
937
938   assert_direct (conn);
939   do_echo_test (conn);
940   g_object_unref (conn);
941 }
942
943 static void
944 assert_single (GSocketConnection *conn)
945 {
946   GSocketAddress *addr;
947   const gchar *proxy_uri;
948   gushort proxy_port;
949   GError *error = NULL;
950
951   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
952   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
953   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
954   g_assert_no_error (proxy_a.last_error);
955   g_assert_no_error (proxy_b.last_error);
956
957   addr = g_socket_connection_get_remote_address (conn, &error);
958   g_assert_no_error (error);
959   g_assert (G_IS_PROXY_ADDRESS (addr));
960   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
961   g_assert_cmpstr (proxy_uri, ==, proxy_a.uri);
962   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
963   g_assert_cmpint (proxy_port, ==, proxy_a.port);
964
965   g_object_unref (addr);
966 }
967
968 static void
969 test_single_sync (gpointer fixture,
970                   gconstpointer user_data)
971 {
972   GSocketConnection *conn;
973   GError *error = NULL;
974   gchar *uri;
975
976   /* The alpha:// URI should be proxied via Proxy A */
977   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
978   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
979   g_free (uri);
980   g_assert_no_error (error);
981
982   assert_single (conn);
983
984   do_echo_test (conn);
985   g_object_unref (conn);
986 }
987
988 static void
989 test_single_async (gpointer fixture,
990                    gconstpointer user_data)
991 {
992   GSocketConnection *conn;
993   gchar *uri;
994
995   /* The alpha:// URI should be proxied via Proxy A */
996   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
997   conn = NULL;
998   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
999                                         async_got_conn, &conn);
1000   g_free (uri);
1001   while (conn == NULL)
1002     g_main_context_iteration (NULL, TRUE);
1003
1004   assert_single (conn);
1005   do_echo_test (conn);
1006   g_object_unref (conn);
1007 }
1008
1009 static void
1010 assert_multiple (GSocketConnection *conn)
1011 {
1012   GSocketAddress *addr;
1013   const gchar *proxy_uri;
1014   gushort proxy_port;
1015   GError *error = NULL;
1016
1017   g_assert_cmpint (g_strv_length (last_proxies), ==, 2);
1018   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1019   g_assert_cmpstr (last_proxies[1], ==, proxy_b.uri);
1020   g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1021   g_assert_no_error (proxy_b.last_error);
1022
1023   addr = g_socket_connection_get_remote_address (conn, &error);
1024   g_assert_no_error (error);
1025   g_assert (G_IS_PROXY_ADDRESS (addr));
1026   proxy_uri = g_proxy_address_get_uri (G_PROXY_ADDRESS (addr));
1027   g_assert_cmpstr (proxy_uri, ==, proxy_b.uri);
1028   proxy_port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
1029   g_assert_cmpint (proxy_port, ==, proxy_b.port);
1030
1031   g_object_unref (addr);
1032 }
1033
1034 static void
1035 test_multiple_sync (gpointer fixture,
1036                     gconstpointer user_data)
1037 {
1038   GSocketConnection *conn;
1039   GError *error = NULL;
1040   gchar *uri;
1041
1042   /* The beta:// URI should be proxied via Proxy B, after failing
1043    * via Proxy A.
1044    */
1045   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1046   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1047   g_free (uri);
1048   g_assert_no_error (error);
1049
1050   assert_multiple (conn);
1051   do_echo_test (conn);
1052   g_object_unref (conn);
1053 }
1054
1055 static void
1056 test_multiple_async (gpointer fixture,
1057                      gconstpointer user_data)
1058 {
1059   GSocketConnection *conn;
1060   gchar *uri;
1061
1062   /* The beta:// URI should be proxied via Proxy B, after failing
1063    * via Proxy A.
1064    */
1065   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1066   conn = NULL;
1067   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1068                                         async_got_conn, &conn);
1069   g_free (uri);
1070   while (conn == NULL)
1071     g_main_context_iteration (NULL, TRUE);
1072
1073   assert_multiple (conn);
1074   do_echo_test (conn);
1075   g_object_unref (conn);
1076 }
1077
1078 static void
1079 test_dns (gpointer fixture,
1080           gconstpointer user_data)
1081 {
1082   GSocketConnection *conn;
1083   GError *error = NULL;
1084   gchar *uri;
1085
1086   /* The simple:// and alpha:// URIs should fail with a DNS error,
1087    * but the beta:// URI should succeed, because we pass it to
1088    * Proxy B without trying to resolve it first
1089    */
1090
1091   /* simple */
1092   uri = g_strdup_printf ("simple://no-such-host.xx:%u", server.server_port);
1093   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1094   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1095   g_clear_error (&error);
1096
1097   g_assert_no_error (proxy_a.last_error);
1098   g_assert_no_error (proxy_b.last_error);
1099   teardown_test (NULL, NULL);
1100
1101   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1102                                         async_got_error, &error);
1103   while (error == NULL)
1104     g_main_context_iteration (NULL, TRUE);
1105   g_assert_error (error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND);
1106   g_clear_error (&error);
1107   g_free (uri);
1108
1109   g_assert_no_error (proxy_a.last_error);
1110   g_assert_no_error (proxy_b.last_error);
1111   teardown_test (NULL, NULL);
1112
1113   /* alpha */
1114   uri = g_strdup_printf ("alpha://no-such-host.xx:%u", server.server_port);
1115   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1116   /* Since Proxy A fails, @client will try Proxy B too, which won't
1117    * load an alpha:// URI.
1118    */
1119   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1120   g_clear_error (&error);
1121
1122   g_assert_no_error (proxy_a.last_error);
1123   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1124   teardown_test (NULL, NULL);
1125
1126   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1127                                         async_got_error, &error);
1128   while (error == NULL)
1129     g_main_context_iteration (NULL, TRUE);
1130   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1131   g_clear_error (&error);
1132   g_free (uri);
1133
1134   g_assert_no_error (proxy_a.last_error);
1135   g_assert_error (proxy_b.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1136   teardown_test (NULL, NULL);
1137
1138   /* beta */
1139   uri = g_strdup_printf ("beta://no-such-host.xx:%u", server.server_port);
1140   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1141   g_assert_no_error (error);
1142
1143   g_assert_no_error (proxy_a.last_error);
1144   g_assert_no_error (proxy_b.last_error);
1145
1146   do_echo_test (conn);
1147   g_clear_object (&conn);
1148   teardown_test (NULL, NULL);
1149
1150   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1151                                         async_got_conn, &conn);
1152   while (conn == NULL)
1153     g_main_context_iteration (NULL, TRUE);
1154   g_free (uri);
1155
1156   g_assert_no_error (proxy_a.last_error);
1157   g_assert_no_error (proxy_b.last_error);
1158
1159   do_echo_test (conn);
1160   g_clear_object (&conn);
1161   teardown_test (NULL, NULL);
1162 }
1163
1164 static void
1165 assert_override (GSocketConnection *conn)
1166 {
1167   g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
1168   g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
1169
1170   if (conn)
1171     g_assert_no_error (proxy_a.last_error);
1172   else
1173     g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1174 }
1175
1176 static void
1177 test_override (gpointer fixture,
1178                gconstpointer user_data)
1179 {
1180   GProxyResolver *alt_resolver;
1181   GSocketConnection *conn;
1182   GError *error = NULL;
1183   gchar *uri;
1184
1185   g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1186   alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
1187   g_socket_client_set_proxy_resolver (client, alt_resolver);
1188   g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1189
1190   /* Alt proxy resolver always returns Proxy A, so alpha:// should
1191    * succeed, and simple:// and beta:// should fail.
1192    */
1193
1194   /* simple */
1195   uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
1196   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1197   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1198   g_clear_error (&error);
1199   assert_override (conn);
1200   teardown_test (NULL, NULL);
1201
1202   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1203                                         async_got_error, &error);
1204   while (error == NULL)
1205     g_main_context_iteration (NULL, TRUE);
1206   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1207   g_clear_error (&error);
1208   assert_override (conn);
1209   g_free (uri);
1210   teardown_test (NULL, NULL);
1211
1212   /* alpha */
1213   uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
1214   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1215   g_assert_no_error (error);
1216   assert_override (conn);
1217   do_echo_test (conn);
1218   g_clear_object (&conn);
1219   teardown_test (NULL, NULL);
1220
1221   conn = NULL;
1222   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1223                                         async_got_conn, &conn);
1224   while (conn == NULL)
1225     g_main_context_iteration (NULL, TRUE);
1226   assert_override (conn);
1227   do_echo_test (conn);
1228   g_clear_object (&conn);
1229   g_free (uri);
1230   teardown_test (NULL, NULL);
1231
1232   /* beta */
1233   uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
1234   conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
1235   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1236   g_clear_error (&error);
1237   assert_override (conn);
1238   teardown_test (NULL, NULL);
1239
1240   g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
1241                                         async_got_error, &error);
1242   while (error == NULL)
1243     g_main_context_iteration (NULL, TRUE);
1244   g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
1245   g_clear_error (&error);
1246   assert_override (conn);
1247   g_free (uri);
1248   teardown_test (NULL, NULL);
1249
1250   g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
1251   g_socket_client_set_proxy_resolver (client, NULL);
1252   g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
1253   g_object_unref (alt_resolver);
1254 }
1255
1256 static void
1257 assert_destination_port (GSocketAddressEnumerator *etor,
1258                          guint16                   port)
1259 {
1260   GSocketAddress *addr;
1261   GProxyAddress *paddr;
1262   GError *error = NULL;
1263
1264   while ((addr = g_socket_address_enumerator_next (etor, NULL, &error)))
1265     {
1266       g_assert_no_error (error);
1267
1268       g_assert (G_IS_PROXY_ADDRESS (addr));
1269       paddr = G_PROXY_ADDRESS (addr);
1270       g_assert_cmpint (g_proxy_address_get_destination_port (paddr), ==, port);
1271       g_object_unref (addr);
1272     }
1273   g_assert_no_error (error);
1274 }
1275
1276 static void
1277 test_proxy_enumerator_ports (void)
1278 {
1279   GSocketAddressEnumerator *etor;
1280
1281   etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1282                        "uri", "http://example.com/",
1283                        NULL);
1284   assert_destination_port (etor, 0);
1285   g_object_unref (etor);
1286
1287   /* Have to call this to clear last_proxies so the next call to
1288    * g_test_proxy_resolver_lookup() won't assert.
1289    */
1290   teardown_test (NULL, NULL);
1291
1292   etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1293                        "uri", "http://example.com:8080/",
1294                        NULL);
1295   assert_destination_port (etor, 8080);
1296   g_object_unref (etor);
1297
1298   teardown_test (NULL, NULL);
1299
1300   etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1301                        "uri", "http://example.com/",
1302                        "default-port", 80,
1303                        NULL);
1304   assert_destination_port (etor, 80);
1305   g_object_unref (etor);
1306
1307   teardown_test (NULL, NULL);
1308
1309   etor = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
1310                        "uri", "http://example.com:8080/",
1311                        "default-port", 80,
1312                        NULL);
1313   assert_destination_port (etor, 8080);
1314   g_object_unref (etor);
1315
1316   teardown_test (NULL, NULL);
1317 }
1318
1319 int
1320 main (int   argc,
1321       char *argv[])
1322 {
1323   GResolver *fake_resolver;
1324   GCancellable *cancellable;
1325   gint result;
1326
1327   g_test_init (&argc, &argv, NULL);
1328
1329   /* Register stuff. The dummy g_proxy_get_default_for_protocol() call
1330    * is to force _g_io_modules_ensure_extension_points_registered() to
1331    * get called, so we can then register a proxy resolver extension
1332    * point.
1333    */
1334   g_proxy_get_default_for_protocol ("foo");
1335   g_test_proxy_resolver_get_type ();
1336   g_proxy_a_get_type ();
1337   g_proxy_b_get_type ();
1338   g_setenv ("GIO_USE_PROXY_RESOLVER", "test", TRUE);
1339
1340   fake_resolver = g_object_new (g_fake_resolver_get_type (), NULL);
1341   g_resolver_set_default (fake_resolver);
1342
1343   cancellable = g_cancellable_new ();
1344   create_server (&server, cancellable);
1345   create_proxy (&proxy_a, 'a', "alpha", cancellable);
1346   create_proxy (&proxy_b, 'b', "beta", cancellable);
1347
1348   client = g_socket_client_new ();
1349   g_assert_cmpint (g_socket_client_get_enable_proxy (client), ==, TRUE);
1350
1351   g_test_add_vtable ("/proxy/direct_sync", 0, NULL, setup_test, test_direct_sync, teardown_test);
1352   g_test_add_vtable ("/proxy/direct_async", 0, NULL, setup_test, test_direct_async, teardown_test);
1353   g_test_add_vtable ("/proxy/single_sync", 0, NULL, setup_test, test_single_sync, teardown_test);
1354   g_test_add_vtable ("/proxy/single_async", 0, NULL, setup_test, test_single_async, teardown_test);
1355   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
1356   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
1357   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
1358   g_test_add_vtable ("/proxy/override", 0, NULL, setup_test, test_override, teardown_test);
1359   g_test_add_func ("/proxy/enumerator-ports", test_proxy_enumerator_ports);
1360
1361   result = g_test_run();
1362
1363   g_object_unref (client);
1364
1365   g_cancellable_cancel (cancellable);
1366   g_thread_join (proxy_a.thread);
1367   g_thread_join (proxy_b.thread);
1368   g_thread_join (server.server_thread);
1369
1370   g_object_unref (cancellable);
1371
1372   return result;
1373 }
1374