[glib] GSocketClient: add proxy-resolver property



commit 7c49869eaef4d49c57bbdf4e95989e4d8f864623
Author: Dan Winship <danw gnome org>
Date:   Sun Jan 27 13:53:36 2013 -0500

    GSocketClient: add proxy-resolver property
    
    Add a proxy-resolver property to GSocketClient, to allow overriding
    proxy resolution in situations where you need to force a particular
    proxy rather than using the system defaults.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=691105

 docs/reference/gio/gio-sections.txt |    2 +
 gio/gproxyaddressenumerator.c       |   43 +++++++++-
 gio/gsocketclient.c                 |  113 ++++++++++++++++++++++++-
 gio/gsocketclient.h                 |    5 +
 gio/tests/proxy-test.c              |  154 +++++++++++++++++++++++++++++++++-
 5 files changed, 302 insertions(+), 15 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index dc2b27d..04e9310 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1958,6 +1958,7 @@ g_socket_client_set_protocol
 g_socket_client_set_socket_type
 g_socket_client_set_timeout
 g_socket_client_set_enable_proxy
+g_socket_client_set_proxy_resolver
 g_socket_client_set_tls
 g_socket_client_set_tls_validation_flags
 g_socket_client_get_family
@@ -1966,6 +1967,7 @@ g_socket_client_get_protocol
 g_socket_client_get_socket_type
 g_socket_client_get_timeout
 g_socket_client_get_enable_proxy
+g_socket_client_get_proxy_resolver
 g_socket_client_get_tls
 g_socket_client_get_tls_validation_flags
 g_socket_client_add_application_proxy
diff --git a/gio/gproxyaddressenumerator.c b/gio/gproxyaddressenumerator.c
index fecb4c8..32a684f 100644
--- a/gio/gproxyaddressenumerator.c
+++ b/gio/gproxyaddressenumerator.c
@@ -47,7 +47,8 @@ enum
 {
   PROP_0,
   PROP_URI,
-  PROP_CONNECTABLE
+  PROP_CONNECTABLE,
+  PROP_PROXY_RESOLVER
 };
 
 struct _GProxyAddressEnumeratorPrivate
@@ -60,6 +61,7 @@ struct _GProxyAddressEnumeratorPrivate
   GList              *dest_ips;
 
   /* Proxy enumeration */
+  GProxyResolver           *proxy_resolver;
   gchar                          **proxies;
   gchar                          **next_proxy;
   GSocketAddressEnumerator *addr_enum;
@@ -180,8 +182,7 @@ g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
 
   if (priv->proxies == NULL)
     {
-      GProxyResolver *resolver = g_proxy_resolver_get_default ();
-      priv->proxies = g_proxy_resolver_lookup (resolver,
+      priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
                                               priv->dest_uri,
                                               cancellable,
                                               error);
@@ -530,8 +531,7 @@ g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
 
   if (priv->proxies == NULL)
     {
-      GProxyResolver *resolver = g_proxy_resolver_get_default ();
-      g_proxy_resolver_lookup_async (resolver,
+      g_proxy_resolver_lookup_async (priv->proxy_resolver,
                                     priv->dest_uri,
                                     cancellable,
                                     proxy_lookup_cb,
@@ -586,6 +586,10 @@ g_proxy_address_enumerator_get_property (GObject        *object,
        g_value_set_object (value, priv->connectable);
        break;
 
+      case PROP_PROXY_RESOLVER:
+       g_value_set_object (value, priv->proxy_resolver);
+       break;
+
       default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -643,6 +647,15 @@ g_proxy_address_enumerator_set_property (GObject        *object,
          priv->connectable = g_value_dup_object (value);
          break;
 
+      case PROP_PROXY_RESOLVER:
+          if (priv->proxy_resolver)
+            g_object_unref (priv->proxy_resolver);
+          priv->proxy_resolver = g_value_get_object (value);
+          if (!priv->proxy_resolver)
+            priv->proxy_resolver = g_proxy_resolver_get_default ();
+          g_object_ref (priv->proxy_resolver);
+          break;
+
       default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     }
@@ -656,6 +669,9 @@ g_proxy_address_enumerator_finalize (GObject *object)
   if (priv->connectable)
     g_object_unref (priv->connectable);
 
+  if (priv->proxy_resolver)
+    g_object_unref (priv->proxy_resolver);
+
   g_free (priv->dest_uri);
   g_free (priv->dest_hostname);
 
@@ -720,4 +736,21 @@ g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enume
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT_ONLY |
                                                        G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GProxyAddressEnumerator:proxy-resolver:
+   *
+   * The proxy resolver to use.
+   *
+   * Since: 2.36
+   */
+  g_object_class_install_property (object_class,
+                                   PROP_PROXY_RESOLVER,
+                                   g_param_spec_object ("proxy-resolver",
+                                                        P_("Proxy resolver"),
+                                                        P_("The proxy resolver to use."),
+                                                        G_TYPE_PROXY_RESOLVER,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT |
+                                                        G_PARAM_STATIC_STRINGS));
 }
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index ddbe697..00e3481 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -41,6 +41,7 @@
 #include <gio/gnetworkaddress.h>
 #include <gio/gnetworkservice.h>
 #include <gio/gproxy.h>
+#include <gio/gproxyresolver.h>
 #include <gio/gsocketaddress.h>
 #include <gio/gtcpconnection.h>
 #include <gio/gtcpwrapperconnection.h>
@@ -94,7 +95,8 @@ enum
   PROP_TIMEOUT,
   PROP_ENABLE_PROXY,
   PROP_TLS,
-  PROP_TLS_VALIDATION_FLAGS
+  PROP_TLS_VALIDATION_FLAGS,
+  PROP_PROXY_RESOLVER
 };
 
 struct _GSocketClientPrivate
@@ -108,6 +110,7 @@ struct _GSocketClientPrivate
   GHashTable *app_proxies;
   gboolean tls;
   GTlsCertificateFlags tls_validation_flags;
+  GProxyResolver *proxy_resolver;
 };
 
 static GSocket *
@@ -227,8 +230,8 @@ g_socket_client_finalize (GObject *object)
 {
   GSocketClient *client = G_SOCKET_CLIENT (object);
 
-  if (client->priv->local_address)
-    g_object_unref (client->priv->local_address);
+  g_clear_object (&client->priv->local_address);
+  g_clear_object (&client->priv->proxy_resolver);
 
   if (G_OBJECT_CLASS (g_socket_client_parent_class)->finalize)
     (*G_OBJECT_CLASS (g_socket_client_parent_class)->finalize) (object);
@@ -278,6 +281,10 @@ g_socket_client_get_property (GObject    *object,
        g_value_set_flags (value, g_socket_client_get_tls_validation_flags (client));
        break;
 
+      case PROP_PROXY_RESOLVER:
+       g_value_set_object (value, g_socket_client_get_proxy_resolver (client));
+       break;
+
       default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -325,6 +332,10 @@ g_socket_client_set_property (GObject      *object,
       g_socket_client_set_tls_validation_flags (client, g_value_get_flags (value));
       break;
 
+    case PROP_PROXY_RESOLVER:
+      g_socket_client_set_proxy_resolver (client, g_value_get_object (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -579,6 +590,8 @@ g_socket_client_get_enable_proxy (GSocketClient *client)
  * #GProxyResolver to determine if a proxy protocol such as SOCKS is
  * needed, and automatically do the necessary proxy negotiation.
  *
+ * See also g_socket_client_set_proxy_resolver().
+ *
  * Since: 2.26
  */
 void
@@ -686,6 +699,64 @@ g_socket_client_set_tls_validation_flags (GSocketClient        *client,
     }
 }
 
+/**
+ * g_socket_client_get_proxy_resolver:
+ * @client: a #GSocketClient.
+ *
+ * Gets the #GProxyResolver being used by @client. Normally, this will
+ * be the resolver returned by g_proxy_resolver_get_default(), but you
+ * can override it with g_socket_client_set_proxy_resolver().
+ *
+ * Returns: (transfer none): The #GProxyResolver being used by
+ *   @client.
+ *
+ * Since: 2.36
+ */
+GProxyResolver *
+g_socket_client_get_proxy_resolver (GSocketClient *client)
+{
+  if (client->priv->proxy_resolver)
+    return client->priv->proxy_resolver;
+  else
+    return g_proxy_resolver_get_default ();
+}
+
+/**
+ * g_socket_client_set_proxy_resolver:
+ * @client: a #GSocketClient.
+ * @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL for the
+ *   default.
+ *
+ * Overrides the #GProxyResolver used by @client. You can call this if
+ * you want to use specific proxies, rather than using the system
+ * default proxy settings.
+ *
+ * Note that whether or not the proxy resolver is actually used
+ * depends on the setting of #GSocketClient:enable-proxy, which is not
+ * changed by this function (but which is %TRUE by default)
+ *
+ * Since: 2.36
+ */
+void
+g_socket_client_set_proxy_resolver (GSocketClient  *client,
+                                    GProxyResolver *proxy_resolver)
+{
+  /* We have to be careful to avoid calling
+   * g_proxy_resolver_get_default() until we're sure we need it,
+   * because trying to load the default proxy resolver module will
+   * break some test programs that aren't expecting it (eg,
+   * tests/gsettings).
+   */
+
+  if (client->priv->proxy_resolver)
+    g_object_unref (client->priv->proxy_resolver);
+
+  client->priv->proxy_resolver = proxy_resolver;
+
+  if (client->priv->proxy_resolver)
+    g_object_ref (client->priv->proxy_resolver);
+}
+
 static void
 g_socket_client_class_init (GSocketClientClass *class)
 {
@@ -881,6 +952,22 @@ g_socket_client_class_init (GSocketClientClass *class)
                                                       G_PARAM_CONSTRUCT |
                                                       G_PARAM_READWRITE |
                                                       G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GSocketClient:proxy-resolver:
+   *
+   * The proxy resolver to use
+   *
+   * Since: 2.36
+   */
+  g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
+                                   g_param_spec_object ("proxy-resolver",
+                                                        P_("Proxy resolver"),
+                                                        P_("The proxy resolver to use"),
+                                                        G_TYPE_PROXY_RESOLVER,
+                                                        G_PARAM_CONSTRUCT |
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -936,7 +1023,15 @@ g_socket_client_connect (GSocketClient       *client,
   last_error = NULL;
 
   if (can_use_proxy (client))
-    enumerator = g_socket_connectable_proxy_enumerate (connectable);
+    {
+      enumerator = g_socket_connectable_proxy_enumerate (connectable);
+      if (client->priv->proxy_resolver &&
+          G_IS_PROXY_ADDRESS_ENUMERATOR (enumerator))
+        {
+          g_object_set (G_OBJECT (enumerator), "proxy-resolver",
+                        client->priv->proxy_resolver);
+        }
+    }
   else
     enumerator = g_socket_connectable_enumerate (connectable);
 
@@ -1605,9 +1700,17 @@ g_socket_client_connect_async (GSocketClient       *client,
   data->connectable = g_object_ref (connectable);
 
   if (can_use_proxy (client))
+    {
       data->enumerator = g_socket_connectable_proxy_enumerate (connectable);
+      if (client->priv->proxy_resolver &&
+          G_IS_PROXY_ADDRESS_ENUMERATOR (data->enumerator))
+        {
+          g_object_set (G_OBJECT (data->enumerator), "proxy-resolver",
+                        client->priv->proxy_resolver);
+        }
+    }
   else
-      data->enumerator = g_socket_connectable_enumerate (connectable);
+    data->enumerator = g_socket_connectable_enumerate (connectable);
 
   data->task = g_task_new (client, cancellable, callback, user_data);
   g_task_set_task_data (data->task, data, (GDestroyNotify)g_socket_client_async_connect_data_free);
diff --git a/gio/gsocketclient.h b/gio/gsocketclient.h
index 11748ba..0cf6bf5 100644
--- a/gio/gsocketclient.h
+++ b/gio/gsocketclient.h
@@ -117,6 +117,11 @@ GTlsCertificateFlags    g_socket_client_get_tls_validation_flags        (GSocket
 GLIB_AVAILABLE_IN_ALL
 void                    g_socket_client_set_tls_validation_flags        (GSocketClient        *client,
                                                                         GTlsCertificateFlags  flags);
+GLIB_AVAILABLE_IN_2_36
+GProxyResolver         *g_socket_client_get_proxy_resolver              (GSocketClient        *client);
+GLIB_AVAILABLE_IN_2_36
+void                    g_socket_client_set_proxy_resolver              (GSocketClient        *client,
+                                                                         GProxyResolver       
*proxy_resolver);
 
 GLIB_AVAILABLE_IN_ALL
 GSocketConnection *     g_socket_client_connect                         (GSocketClient        *client,
diff --git a/gio/tests/proxy-test.c b/gio/tests/proxy-test.c
index da0e837..2ab27aa 100644
--- a/gio/tests/proxy-test.c
+++ b/gio/tests/proxy-test.c
@@ -26,7 +26,7 @@
 /* Overview:
  *
  * We have an echo server, two proxy servers, two GProxy
- * implementations, and a GProxyResolver implementation.
+ * implementations, and two GProxyResolver implementations.
  *
  * The echo server runs at @server.server_addr (on
  * @server.server_port).
@@ -42,9 +42,10 @@
  * hostname resolution (but it just ignores the hostname and always
  * connects to @server_addr anyway).
  *
- * The GProxyResolver (GTestProxyResolver) looks at its URI and
- * returns [ "direct://" ] for "simple://" URIs, and [ proxy_a.uri,
- * proxy_b.uri ] for other URIs.
+ * The default GProxyResolver (GTestProxyResolver) looks at its URI
+ * and returns [ "direct://" ] for "simple://" URIs, and [
+ * proxy_a.uri, proxy_b.uri ] for other URIs. The other GProxyResolver
+ * (GTestAltProxyResolver) always returns [ proxy_a.uri ].
  */
 
 typedef struct {
@@ -163,7 +164,7 @@ g_test_proxy_resolver_lookup_async (GProxyResolver      *resolver,
   GTask *task;
   gchar **proxies;
 
-  proxies = g_test_proxy_resolver_lookup (resolver, uri, cancellable, &error);
+  proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
 
   task = g_task_new (resolver, NULL, callback, user_data);
   if (proxies == NULL)
@@ -196,6 +197,56 @@ g_test_proxy_resolver_iface_init (GProxyResolverInterface *iface)
   iface->lookup_finish = g_test_proxy_resolver_lookup_finish;
 }
 
+/****************************/
+/* Alternate GProxyResolver */
+/****************************/
+
+typedef GTestProxyResolver GTestAltProxyResolver;
+typedef GTestProxyResolverClass GTestAltProxyResolverClass;
+
+static void g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface);
+
+static GType _g_test_alt_proxy_resolver_get_type (void);
+#define g_test_alt_proxy_resolver_get_type _g_test_alt_proxy_resolver_get_type
+G_DEFINE_TYPE_WITH_CODE (GTestAltProxyResolver, g_test_alt_proxy_resolver, g_test_proxy_resolver_get_type (),
+                        G_IMPLEMENT_INTERFACE (G_TYPE_PROXY_RESOLVER,
+                                               g_test_alt_proxy_resolver_iface_init);
+                         )
+
+static void
+g_test_alt_proxy_resolver_init (GTestProxyResolver *resolver)
+{
+}
+
+static gchar **
+g_test_alt_proxy_resolver_lookup (GProxyResolver  *resolver,
+                                  const gchar     *uri,
+                                  GCancellable    *cancellable,
+                                  GError         **error)
+{
+  gchar **proxies;
+
+  proxies = g_new (gchar *, 2);
+
+  proxies[0] = g_strdup (proxy_a.uri);
+  proxies[1] = NULL;
+
+  last_proxies = g_strdupv (proxies);
+
+  return proxies;
+}
+
+static void
+g_test_alt_proxy_resolver_class_init (GTestProxyResolverClass *resolver_class)
+{
+}
+
+static void
+g_test_alt_proxy_resolver_iface_init (GProxyResolverInterface *iface)
+{
+  iface->lookup = g_test_alt_proxy_resolver_lookup;
+}
+
 
 /****************************************/
 /* Test proxy implementation base class */
@@ -1093,6 +1144,98 @@ test_dns (gpointer fixture,
   teardown_test (NULL, NULL);
 }
 
+static void
+assert_override (GSocketConnection *conn)
+{
+  g_assert_cmpint (g_strv_length (last_proxies), ==, 1);
+  g_assert_cmpstr (last_proxies[0], ==, proxy_a.uri);
+
+  if (conn)
+    g_assert_no_error (proxy_a.last_error);
+  else
+    g_assert_error (proxy_a.last_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+}
+
+static void
+test_override (gpointer fixture,
+               gconstpointer user_data)
+{
+  GProxyResolver *alt_resolver;
+  GSocketConnection *conn;
+  GError *error = NULL;
+  gchar *uri;
+
+  g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
+  alt_resolver = g_object_new (g_test_alt_proxy_resolver_get_type (), NULL);
+  g_socket_client_set_proxy_resolver (client, alt_resolver);
+  g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
+
+  /* Alt proxy resolver always returns Proxy A, so alpha:// should
+   * succeed, and simple:// and beta:// should fail.
+   */
+
+  /* simple */
+  uri = g_strdup_printf ("simple://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  teardown_test (NULL, NULL);
+
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_error, &error);
+  while (error == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  /* alpha */
+  uri = g_strdup_printf ("alpha://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_no_error (error);
+  assert_override (conn);
+  do_echo_test (conn);
+  g_clear_object (&conn);
+  teardown_test (NULL, NULL);
+
+  conn = NULL;
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_conn, &conn);
+  while (conn == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  assert_override (conn);
+  do_echo_test (conn);
+  g_clear_object (&conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  /* beta */
+  uri = g_strdup_printf ("beta://127.0.0.1:%u", server.server_port);
+  conn = g_socket_client_connect_to_uri (client, uri, 0, NULL, &error);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  teardown_test (NULL, NULL);
+
+  g_socket_client_connect_to_uri_async (client, uri, 0, NULL,
+                                       async_got_error, &error);
+  while (error == NULL)
+    g_main_context_iteration (NULL, TRUE);
+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED);
+  g_clear_error (&error);
+  assert_override (conn);
+  g_free (uri);
+  teardown_test (NULL, NULL);
+
+  g_assert (g_socket_client_get_proxy_resolver (client) == alt_resolver);
+  g_socket_client_set_proxy_resolver (client, NULL);
+  g_assert (g_socket_client_get_proxy_resolver (client) == g_proxy_resolver_get_default ());
+  g_object_unref (alt_resolver);
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -1132,6 +1275,7 @@ main (int   argc,
   g_test_add_vtable ("/proxy/multiple_sync", 0, NULL, setup_test, test_multiple_sync, teardown_test);
   g_test_add_vtable ("/proxy/multiple_async", 0, NULL, setup_test, test_multiple_async, teardown_test);
   g_test_add_vtable ("/proxy/dns", 0, NULL, setup_test, test_dns, teardown_test);
+  g_test_add_vtable ("/proxy/override", 0, NULL, setup_test, test_override, teardown_test);
 
   result = g_test_run();
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]