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