commit 101b8c10c92603f9e0af4ccd8686ead02345c6d9
Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
Date:   Tue Mar 30 16:59:54 2010 -0400

    Implemented GProxyResolver, a libproxy wrapper

diff --git a/configure.in b/configure.in
index 863171c..f32982f 100644
--- a/configure.in
+++ b/configure.in
@@ -456,6 +456,17 @@ fi
 
 AC_MSG_RESULT($enable_iconv_cache)
 
+dnl
+dnl proxy support
+dnl
+found_proxy=no
+AC_CHECK_LIB(proxy, px_proxy_factory_new, [AC_CHECK_HEADER(proxy.h, found_proxy=yes)])
+
+if test "x$found_proxy" = "xno" ; then
+   AC_MSG_ERROR([*** Working proxy library and headers not found ***])
+fi
+PROXY_LIBS='-lproxy'
+AC_SUBST(PROXY_LIBS)
 
 dnl
 dnl zlib support
diff --git a/gio/Makefile.am b/gio/Makefile.am
index b49d65c..864812e 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -248,6 +248,8 @@ libgio_2_0_la_SOURCES =		\
 	goutputstream.c 	\
 	gpollfilemonitor.c 	\
 	gpollfilemonitor.h 	\
+	gproxyresolver.c	\
+	gproxyresolver.h	\
 	gresolver.c		\
 	gseekable.c 		\
 	gsimpleasyncresult.c 	\
@@ -296,6 +298,7 @@ libgio_2_0_la_LIBADD = \
 	$(top_builddir)/gobject/libgobject-2.0.la 	\
 	$(top_builddir)/gmodule/libgmodule-2.0.la 	\
 	$(platform_libadd) 				\
+	$(PROXY_LIBS)					\
 	$(ZLIB_LIBS)					\
 	$(SELINUX_LIBS) 				\
 	$(GLIB_LIBS) 					\
diff --git a/gio/gio.h b/gio/gio.h
index 861f172..a34dcf6 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -74,6 +74,7 @@
 #include <gio/gnetworkaddress.h>
 #include <gio/gnetworkservice.h>
 #include <gio/goutputstream.h>
+#include <gio/gproxyresolver.h>
 #include <gio/gresolver.h>
 #include <gio/gseekable.h>
 #include <gio/gsimpleasyncresult.h>
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 798ab9a..ad160a1 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1037,6 +1037,16 @@ g_socket_address_to_native
 #endif
 #endif
 
+#if IN_HEADER(__G_PROXY_RESOLVER_H__)
+#if IN_FILE(__G_PROXY_RESOLVER_C__)
+g_proxy_resolver_get_default
+g_proxy_resolver_get_type
+g_proxy_resolver_lookup
+g_proxy_resolver_lookup_async
+g_proxy_resolver_lookup_finish
+#endif
+#endif
+
 #if IN_HEADER(__G_RESOLVER_H__)
 #if IN_FILE(__G_RESOLVER_C__)
 g_resolver_error_quark
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 2abc87d..3e48b5d 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -113,6 +113,7 @@ typedef struct _GNetworkAddress               GNetworkAddress;
 typedef struct _GNetworkService               GNetworkService;
 typedef struct _GOutputStream                 GOutputStream;
 typedef struct _GIOStream                     GIOStream;
+typedef struct _GProxyResolver                GProxyResolver;
 typedef struct _GResolver                     GResolver;
 typedef struct _GSeekable                     GSeekable;
 typedef struct _GSimpleAsyncResult            GSimpleAsyncResult;
diff --git a/gio/gproxyresolver.c b/gio/gproxyresolver.c
new file mode 100644
index 0000000..a283e70
--- /dev/null
+++ b/gio/gproxyresolver.c
@@ -0,0 +1,253 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2010 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include "gproxyresolver.h"
+
+#include <proxy.h>
+#include <glib.h>
+#include "glibintl.h"
+
+#include "gasyncresult.h"
+#include "gcancellable.h"
+#include "gioerror.h"
+#include "gsimpleasyncresult.h"
+
+#include "gioalias.h"
+
+/**
+ * SECTION:gproxyresolver
+ * @short_description: Asynchronous and cancellable proxy resolver
+ * @include: gio/gio.h
+ *
+ * #GProxyResolver provides an synchronous and asynchronous proxy resolution.
+ * #GProxyResolver is used withing #GClientSocket through method
+ * g_socket_connectable_proxy_enumerate().
+ */
+
+struct _GProxyResolverPrivate {
+  pxProxyFactory *factory;
+};
+
+/**
+ * GProxyResolver:
+ *
+ * The object that handles proxy resolution. Use g_proxy_resolver_get_default()
+ * to get the default proxy_resolver.
+ */
+G_DEFINE_TYPE (GProxyResolver, g_proxy_resolver, G_TYPE_OBJECT)
+
+
+static void
+g_proxy_resolver_dispose (GObject *object)
+{
+  GProxyResolver *resolver = G_PROXY_RESOLVER (object);
+  
+  if (resolver->priv->factory)
+    {
+      px_proxy_factory_free (resolver->priv->factory);
+      resolver->priv->factory = NULL;
+    }
+}
+
+
+static void
+g_proxy_resolver_class_init (GProxyResolverClass *resolver_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (resolver_class);
+
+  g_type_class_add_private (resolver_class, sizeof (GProxyResolverPrivate));
+
+  object_class->dispose = g_proxy_resolver_dispose;
+}
+
+static void
+g_proxy_resolver_init (GProxyResolver *resolver)
+{
+  resolver->priv = G_TYPE_INSTANCE_GET_PRIVATE (resolver, G_TYPE_PROXY_RESOLVER, GProxyResolverPrivate);
+  resolver->priv->factory = px_proxy_factory_new ();
+}
+
+static GProxyResolver *default_proxy_resolver;
+
+/**
+ * g_proxy_resolver_get_default:
+ *
+ * Gets the default #GProxyResolver. You should unref it when you are done
+ * with it.
+ *
+ * Return value: the default #GProxyResolver.
+ *
+ * Since: 2.24
+ */
+GProxyResolver *
+g_proxy_resolver_get_default (void)
+{
+  if (!default_proxy_resolver)
+        default_proxy_resolver = g_object_new (G_TYPE_PROXY_RESOLVER, NULL);
+
+  return g_object_ref (default_proxy_resolver);
+}
+
+/**
+ * g_proxy_resolver_lookup:
+ * @resolver: a #GProxyResolver
+ * @uri: a URI representing the destination to proxy
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Lookup into system configuration for which proxies that could be used to
+ * connect to specified URI. The returned proxies are of the form:
+ *     <protocol>://[user[:password]@]host:port
+ *     direct://
+ * 
+ * Where <protocol> could be http, rtsp, socks or other proxying protocol.
+ * direct:// is used when no proxy is needed. Direct connection should not
+ * be attempted unless it's part of the array of proxy.
+ *
+ * Return value: A NULL-terminated array of proxy URI. Must be freed with
+ *               g_freestrv().
+ *
+ * Since: 2.24
+ */
+gchar **
+g_proxy_resolver_lookup (GProxyResolver  *resolver,
+			 const gchar     *uri,
+			 GCancellable    *cancellable,
+			 GError         **error)
+{
+  gchar **proxies;
+
+  g_return_val_if_fail (G_IS_PROXY_RESOLVER (resolver), NULL);
+  g_return_val_if_fail (uri != NULL, NULL);
+
+  if (g_cancellable_is_cancelled (cancellable))
+    {
+      g_cancellable_set_error_if_cancelled (cancellable, error);
+      return NULL;
+    }
+
+  proxies =  px_proxy_factory_get_proxies (resolver->priv->factory, uri);
+
+  if (!proxies)
+      *error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
+	                    "Proxy resolver internal error.");
+
+  return proxies;
+}
+
+static void
+_lookup_async (GSimpleAsyncResult *simple,
+	       GObject *object,
+	       GCancellable *cancellable)
+{
+  GProxyResolver *resolver = G_PROXY_RESOLVER (object);
+  GError *error = NULL;
+  gchar **proxies = NULL;
+  gchar *uri;
+
+  uri = g_simple_async_result_get_op_res_gpointer (simple);
+  g_simple_async_result_set_op_res_gpointer (simple, NULL, NULL);
+
+  proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
+  g_simple_async_result_set_op_res_gpointer (simple, proxies, NULL);
+  g_free (uri);
+
+  if (error)
+    {
+      g_simple_async_result_set_from_error (simple, error);
+      g_error_free (error);
+    }
+}
+
+/**
+ * g_proxy_resolver_lookup_async:
+ * @resolver: a #GProxyResolver
+ * @uri: a URI representing the destination to proxy
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to call after resolution completes
+ * @user_data: data for @callback
+ *
+ * Asynchronous lookup of proxy, see g_proxy_resolver_lookup() for more
+ * details. It is recommended to enable threading while using this function,
+ * see g_thread_init() for more details.
+ *
+ * Since: 2.24
+ */
+void
+g_proxy_resolver_lookup_async (GProxyResolver      *resolver,
+			       const gchar         *uri,
+			       GCancellable        *cancellable,
+			       GAsyncReadyCallback  callback,
+			       gpointer             user_data)
+{
+  GSimpleAsyncResult *simple;
+
+  g_return_val_if_fail (G_IS_PROXY_RESOLVER (resolver), NULL);
+  g_return_val_if_fail (uri != NULL, NULL);
+  
+  simple = g_simple_async_result_new (G_OBJECT (resolver),
+				      callback, user_data,
+				      g_proxy_resolver_lookup_async);
+  g_simple_async_result_set_op_res_gpointer (simple, g_strdup (uri), NULL);
+  g_simple_async_result_run_in_thread (simple, _lookup_async,
+				      G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (simple);
+}
+
+/**
+ * g_proxy_resolver_lookup_by_name_finish:
+ * @resolver: a #GProxyResolver
+ * @result: the result passed to your #GAsyncReadyCallback
+ * @error: return location for a #GError, or %NULL
+ *
+ * Call this function to obtain the array of proxy URI when 
+ * g_proxy_resolver_lookup_async() as complete.
+ *
+ * Return value: A NULL-terminated array of proxy URI. Must be freed with
+ *               g_freestrv().
+ *
+ * Since: 2.24
+ */
+gchar **
+g_proxy_resolver_lookup_finish (GProxyResolver     *resolver,
+				GAsyncResult       *result,
+				GError            **error)
+{
+  g_return_val_if_fail (G_IS_PROXY_RESOLVER (resolver), NULL);
+  
+  if (G_IS_SIMPLE_ASYNC_RESULT (result))
+    {
+      GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+
+      if (g_simple_async_result_propagate_error (simple, error))
+        return NULL;
+
+      return g_simple_async_result_get_op_res_gpointer (simple);
+    }
+
+  return NULL;
+}
+
+#define __G_PROXY_RESOLVER_C__
+#include "gioaliasdef.c"
diff --git a/gio/gproxyresolver.h b/gio/gproxyresolver.h
new file mode 100644
index 0000000..398a234
--- /dev/null
+++ b/gio/gproxyresolver.h
@@ -0,0 +1,72 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2010 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ */
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#ifndef __G_PROXY_RESOLVER_H__
+#define __G_PROXY_RESOLVER_H__
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_PROXY_RESOLVER         (g_proxy_resolver_get_type ())
+#define G_PROXY_RESOLVER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_PROXY_RESOLVER, GProxyResolver))
+#define G_PROXY_RESOLVER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_PROXY_RESOLVER, GProxyResolverClass))
+#define G_IS_PROXY_RESOLVER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_PROXY_RESOLVER))
+#define G_IS_PROXY_RESOLVER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_RESOLVER))
+#define G_PROXY_RESOLVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_PROXY_RESOLVER, GProxyResolverClass))
+
+typedef struct _GProxyResolverPrivate GProxyResolverPrivate;
+typedef struct _GProxyResolverClass   GProxyResolverClass;
+
+struct _GProxyResolver {
+  GObject parent_instance;
+  GProxyResolverPrivate *priv;
+};
+
+struct _GProxyResolverClass {
+  GObjectClass parent_class;
+};
+
+GType		g_proxy_resolver_get_type       (void) G_GNUC_CONST;
+GProxyResolver *g_proxy_resolver_get_default    (void);
+
+gchar	      **g_proxy_resolver_lookup		(GProxyResolver       *proxy_resolver,
+						 const gchar          *uri,
+						 GCancellable         *cancellable,
+						 GError              **error);
+void		g_proxy_resolver_lookup_async   (GProxyResolver       *proxy_resolver,
+						 const gchar          *uri,
+						 GCancellable         *cancellable,
+						 GAsyncReadyCallback   callback,
+						 gpointer              user_data);
+gchar	      **g_proxy_resolver_lookup_finish  (GProxyResolver       *proxy_resolver,
+						 GAsyncResult         *result,
+						 GError              **error);
+
+
+G_END_DECLS
+
+#endif /* __G_PROXY_RESOLVER_H__ */
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 8f9f483..c4aa1e3 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -41,7 +41,9 @@ SAMPLE_PROGS = 			\
 	echo-server		\
 	httpd			\
 	send-data		\
-	filter-cat
+	filter-cat		\
+	proxy
+
 
 if OS_UNIX
 TEST_PROGS += live-g-file unix-streams desktop-app-info unix-fd
@@ -133,4 +135,8 @@ contexts_SOURCES	  = contexts.c
 contexts_LDADD		  = $(progs_ldadd) \
 	$(top_builddir)/gthread/libgthread-2.0.la
 
+proxy_SOURCES	  	  = proxy.c
+proxy_LDADD		  = $(progs_ldadd) \
+	$(top_builddir)/gthread/libgthread-2.0.la
+
 DISTCLEAN_FILES = applications/mimeinfo.cache
diff --git a/gio/tests/proxy.c b/gio/tests/proxy.c
new file mode 100644
index 0000000..ac0d4b1
--- /dev/null
+++ b/gio/tests/proxy.c
@@ -0,0 +1,152 @@
+/* GLib testing framework examples and tests
+ * 
+ * Copyright (C) 2010 Collabora, Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "glibintl.h"
+
+
+static void G_GNUC_NORETURN
+usage (void)
+{
+  fprintf (stderr, "Usage: proxy [-t] [-s] uri\n");
+  fprintf (stderr, "       Use -t to enable threading.\n");
+  fprintf (stderr, "       Use -s to do synchronous lookups.\n");
+  fprintf (stderr, "       Use -c to cancel operation.\n");
+  exit (1);
+}
+
+static const gchar *uri;
+
+static void
+print_proxies (const gchar *uri, gchar **proxies)
+{
+  printf ("Proxies for URI '%s' are:\n", uri);
+
+  if (proxies == NULL || proxies[0] == NULL)
+    printf ("\tnone\n");
+  else
+    for (; proxies[0]; proxies++)
+      printf ("\t%s\n", proxies[0]);
+}
+
+static void
+_proxy_lookup_cb (GObject *source_object,
+		  GAsyncResult *result,
+		  gpointer user_data)
+{
+  GError *error = NULL;
+  gchar **proxies;
+  GMainLoop *loop = user_data;
+
+  proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (source_object),
+					    result,
+					    &error);
+  if (error)
+    {
+      g_debug ("Failed to obtain proxies: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      print_proxies (uri, proxies);
+      g_strfreev (proxies);
+    }
+
+  g_main_loop_quit (loop);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+  GProxyResolver *resolver;
+  gboolean synchronous = FALSE;
+  gboolean cancel = FALSE;
+  GCancellable *cancellable;
+
+  g_type_init ();
+
+  while (argc >= 2 && argv[1][0] == '-')
+    {
+      if (!strcmp (argv[1], "-t"))
+	g_thread_init (NULL);
+      else if (!strcmp (argv[1], "-s"))
+        synchronous = TRUE;
+      else if (!strcmp (argv[1], "-c"))
+        cancel = TRUE;
+      else
+	usage ();
+
+      argv++;
+      argc--;
+    }
+
+  if (argc != 2)
+    usage ();
+
+  /* Save URI for asyncrhonous callback */
+  uri = argv[1];
+
+  resolver = g_proxy_resolver_get_default ();
+
+  if (cancel)
+    {
+      cancellable = g_cancellable_new ();
+      g_cancellable_cancel (cancellable);
+    }
+
+  if (synchronous)
+    {
+      GError *error = NULL;
+      gchar **proxies;
+      
+      proxies = g_proxy_resolver_lookup (resolver, uri, cancellable, &error);
+      if (error)
+	{
+	  fprintf (stderr, "Proxy resolving failed: %s\n", error->message);
+	  exit (2);
+	}
+      print_proxies (uri, proxies);
+      g_strfreev (proxies);
+    }
+  else
+    {
+      GMainLoop *loop = g_main_loop_new (NULL, FALSE);
+
+      g_proxy_resolver_lookup_async (resolver,
+				     uri,
+				     cancellable,
+				     _proxy_lookup_cb,
+				     loop);
+
+      g_main_loop_run (loop);
+    }
+
+  return 0;
+}
