(root)/
glib-2.79.0/
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_literal (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  }