summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2009-04-08 17:16:52 +0000
committerDan Winship <danw@src.gnome.org>2009-04-08 17:16:52 +0000
commit6131e45752d904d634e74eb230fbd7d8557de2c0 (patch)
tree361936c345bd0db3fd83cb0f66be02f7b25f3d71
parent8cdf7a894222109c145c1e3e13e39dfbb54862de (diff)
downloadlibsoup-6131e45752d904d634e74eb230fbd7d8557de2c0.tar.gz
Re-fix GNOME proxy resolution (qv bug 571527)
* libsoup/soup-proxy-resolver-gnome.c: New and improved GNOME proxy resolver; gets information out of GConf in a thread-safe manner, and then passes it on to libproxy via environment variables, so that libproxy won't try to access GConf itself, but we still can use it for PAC, WPAD, and ignore_hosts. * libsoup/soup-proxy-resolver-gconf.c: * libsoup/soup-proxy-resolver-libproxy.c: gone now * libsoup/soup-gnome-features.c: update for the fact that SoupProxyResolverGNOME is actually a real type now, not compile-time-defined alias svn path=/trunk/; revision=1267
-rw-r--r--ChangeLog17
-rw-r--r--libsoup/Makefile.am6
-rw-r--r--libsoup/soup-gnome-features.c8
-rw-r--r--libsoup/soup-proxy-resolver-gconf.c316
-rw-r--r--libsoup/soup-proxy-resolver-gconf.h32
-rw-r--r--libsoup/soup-proxy-resolver-gnome.c473
-rw-r--r--libsoup/soup-proxy-resolver-gnome.h32
-rw-r--r--libsoup/soup-proxy-resolver-libproxy.c208
-rw-r--r--libsoup/soup-proxy-resolver-libproxy.h32
9 files changed, 525 insertions, 599 deletions
diff --git a/ChangeLog b/ChangeLog
index ba969a4c..114b4b13 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
2009-04-08 Dan Winship <danw@gnome.org>
+ Re-fix GNOME proxy resolution (qv bug 571527)
+
+ * libsoup/soup-proxy-resolver-gnome.c: New and improved GNOME
+ proxy resolver; gets information out of GConf in a thread-safe
+ manner, and then passes it on to libproxy via environment
+ variables, so that libproxy won't try to access GConf itself, but
+ we still can use it for PAC, WPAD, and ignore_hosts.
+
+ * libsoup/soup-proxy-resolver-gconf.c:
+ * libsoup/soup-proxy-resolver-libproxy.c: gone now
+
+ * libsoup/soup-gnome-features.c: update for the fact that
+ SoupProxyResolverGNOME is actually a real type now, not
+ compile-time-defined alias
+
+2009-04-08 Dan Winship <danw@gnome.org>
+
Fix ISO 8601 parsing to accept either "." or ","
* libsoup/soup-date.c (parse_iso8601_date): accept either "." or
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index 11ca32be..dc9ff551 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -182,10 +182,8 @@ libsoup_gnome_2_4_la_LIBADD = \
libsoup_gnome_2_4_la_SOURCES = \
soup-cookie-jar-sqlite.c \
soup-gnome-features.c \
- soup-proxy-resolver-gconf.h \
- soup-proxy-resolver-gconf.c \
- soup-proxy-resolver-libproxy.h \
- soup-proxy-resolver-libproxy.c
+ soup-proxy-resolver-gnome.h \
+ soup-proxy-resolver-gnome.c
endif
diff --git a/libsoup/soup-gnome-features.c b/libsoup/soup-gnome-features.c
index 549af391..cfd5220a 100644
--- a/libsoup/soup-gnome-features.c
+++ b/libsoup/soup-gnome-features.c
@@ -11,8 +11,6 @@
#include "soup-gnome-features.h"
-#include "soup-proxy-resolver-gconf.h"
-
/**
* SOUP_TYPE_PROXY_RESOLVER_GNOME:
*
@@ -27,11 +25,7 @@
*
* Since: 2.26
**/
-GType
-soup_proxy_resolver_gnome_get_type (void)
-{
- return SOUP_TYPE_PROXY_RESOLVER_GCONF;
-}
+/* This is actually declared in soup-proxy-resolver-gnome now */
/**
* SOUP_TYPE_GNOME_FEATURES_2_26:
diff --git a/libsoup/soup-proxy-resolver-gconf.c b/libsoup/soup-proxy-resolver-gconf.c
deleted file mode 100644
index f3063b24..00000000
--- a/libsoup/soup-proxy-resolver-gconf.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * soup-proxy-resolver-gconf.c: GConf-based proxy resolution
- *
- * Copyright (C) 2008 Red Hat, Inc.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include "soup-proxy-resolver-gconf.h"
-#include "soup-address.h"
-#include "soup-dns.h"
-#include "soup-message.h"
-#include "soup-misc.h"
-#include "soup-session-feature.h"
-
-#include <gconf/gconf-client.h>
-
-typedef struct {
- GMutex *lock;
- GConfClient *gconf;
-
- SoupAddress *proxy_addr;
- char *user, *password;
-
- GSList *ignore_hosts;
-} SoupProxyResolverGConfPrivate;
-#define SOUP_PROXY_RESOLVER_GCONF_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_PROXY_RESOLVER_GCONF, SoupProxyResolverGConfPrivate))
-
-static void soup_proxy_resolver_gconf_interface_init (SoupProxyResolverInterface *proxy_resolver_interface);
-
-G_DEFINE_TYPE_EXTENDED (SoupProxyResolverGConf, soup_proxy_resolver_gconf, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
- G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_RESOLVER, soup_proxy_resolver_gconf_interface_init))
-
-static void gconf_value_changed (GConfClient *client, const char *key,
- GConfValue *value, gpointer user_data);
-static void update_proxy_settings (SoupProxyResolverGConfPrivate *priv);
-static void free_proxy_settings (SoupProxyResolverGConfPrivate *priv);
-
-static void get_proxy_async (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GMainContext *async_context,
- GCancellable *cancellable,
- SoupProxyResolverCallback callback,
- gpointer user_data);
-static guint get_proxy_sync (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GCancellable *cancellable,
- SoupAddress **addr);
-
-static void
-soup_proxy_resolver_gconf_init (SoupProxyResolverGConf *resolver_gconf)
-{
- SoupProxyResolverGConfPrivate *priv =
- SOUP_PROXY_RESOLVER_GCONF_GET_PRIVATE (resolver_gconf);
-
- priv->lock = g_mutex_new ();
- priv->gconf = gconf_client_get_default ();
-
- gconf_client_add_dir (priv->gconf, "/system/http_proxy",
- GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
- g_signal_connect (priv->gconf, "value_changed",
- G_CALLBACK (gconf_value_changed),
- resolver_gconf);
- update_proxy_settings (priv);
-}
-
-static void
-finalize (GObject *object)
-{
- SoupProxyResolverGConfPrivate *priv =
- SOUP_PROXY_RESOLVER_GCONF_GET_PRIVATE (object);
-
- g_signal_handlers_disconnect_by_func (priv->gconf, gconf_value_changed,
- object);
- free_proxy_settings (priv);
- g_object_unref (priv->gconf);
- g_mutex_free (priv->lock);
-
- G_OBJECT_CLASS (soup_proxy_resolver_gconf_parent_class)->finalize (object);
-}
-
-static void
-soup_proxy_resolver_gconf_class_init (SoupProxyResolverGConfClass *gconf_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (gconf_class);
-
- g_type_class_add_private (gconf_class, sizeof (SoupProxyResolverGConfPrivate));
-
- object_class->finalize = finalize;
-}
-
-static void
-soup_proxy_resolver_gconf_interface_init (SoupProxyResolverInterface *proxy_resolver_interface)
-{
- proxy_resolver_interface->get_proxy_async = get_proxy_async;
- proxy_resolver_interface->get_proxy_sync = get_proxy_sync;
-}
-
-SoupProxyResolver *
-soup_proxy_resolver_gconf_new (void)
-{
- return g_object_new (SOUP_TYPE_PROXY_RESOLVER_GCONF, NULL);
-}
-
-static void
-free_proxy_settings (SoupProxyResolverGConfPrivate *priv)
-{
- GSList *l;
-
- if (priv->proxy_addr) {
- g_object_unref (priv->proxy_addr);
- priv->proxy_addr = NULL;
- }
- g_free (priv->user);
- priv->user = NULL;
- g_free (priv->password);
- priv->password = NULL;
-
- for (l = priv->ignore_hosts; l; l = l->next)
- g_free (l->data);
- g_slist_free (priv->ignore_hosts);
- priv->ignore_hosts = NULL;
-}
-
-#define SOUP_GCONF_PROXY_ENABLED "/system/http_proxy/use_http_proxy"
-#define SOUP_GCONF_PROXY_USE_AUTH "/system/http_proxy/use_authentication"
-#define SOUP_GCONF_PROXY_HOST "/system/http_proxy/host"
-#define SOUP_GCONF_PROXY_PORT "/system/http_proxy/port"
-#define SOUP_GCONF_PROXY_USER "/system/http_proxy/authentication_user"
-#define SOUP_GCONF_PROXY_PASSWORD "/system/http_proxy/authentication_password"
-#define SOUP_GCONF_PROXY_IGNORE_HOSTS "/system/http_proxy/ignore_hosts"
-
-static void
-update_proxy_settings (SoupProxyResolverGConfPrivate *priv)
-{
- GSList *ignore_hosts, *i;
- char *host;
- guint port;
-
- if (!gconf_client_get_bool (priv->gconf, SOUP_GCONF_PROXY_ENABLED, NULL))
- return;
-
- host = gconf_client_get_string (
- priv->gconf, SOUP_GCONF_PROXY_HOST, NULL);
- if (!host)
- return;
- port = gconf_client_get_int (
- priv->gconf, SOUP_GCONF_PROXY_PORT, NULL);
- priv->proxy_addr = soup_address_new (host, port);
- g_free (host);
-
- if (gconf_client_get_bool (priv->gconf, SOUP_GCONF_PROXY_USE_AUTH, NULL)) {
- priv->user = gconf_client_get_string (
- priv->gconf, SOUP_GCONF_PROXY_USER, NULL);
- priv->password = gconf_client_get_string (
- priv->gconf, SOUP_GCONF_PROXY_PASSWORD, NULL);
- }
-
- ignore_hosts = gconf_client_get_list (
- priv->gconf, SOUP_GCONF_PROXY_IGNORE_HOSTS,
- GCONF_VALUE_STRING, NULL);
- for (i = ignore_hosts; i; i = i->next) {
- host = i->data;
-
- /* FIXME: not right. Need to handle addresses, masks */
- priv->ignore_hosts = g_slist_prepend (
- priv->ignore_hosts,
- g_ascii_strdown (host, -1));
- g_free (host);
- }
- g_slist_free (ignore_hosts);
-}
-
-static void
-gconf_value_changed (GConfClient *client, const char *key,
- GConfValue *value, gpointer user_data)
-{
- SoupProxyResolverGConf *resolver_gconf = user_data;
- SoupProxyResolverGConfPrivate *priv =
- SOUP_PROXY_RESOLVER_GCONF_GET_PRIVATE (resolver_gconf);
-
- free_proxy_settings (priv);
- update_proxy_settings (priv);
-}
-
-static gboolean
-message_has_ignored_address (SoupProxyResolverGConfPrivate *priv,
- SoupMessage *msg)
-{
- SoupAddress *addr;
- struct sockaddr *sockaddr;
- const char *name, *ignore_name;
- char *hostname;
- GSList *l;
- int len;
-
- if (!priv->ignore_hosts)
- return FALSE;
-
- addr = soup_message_get_address (msg);
- name = soup_address_get_name (addr);
- sockaddr = soup_address_get_sockaddr (addr, &len);
- g_return_val_if_fail (name != NULL && sockaddr != NULL, FALSE);
-
- hostname = g_ascii_strdown (name, -1);
- for (l = priv->ignore_hosts; l; l = l->next) {
- ignore_name = l->data;
-
- if (*ignore_name == '*') {
- if (g_str_has_suffix (hostname, ignore_name + 1)) {
- g_free (hostname);
- return TRUE;
- }
- } else if (strcmp (hostname, ignore_name) == 0) {
- g_free (hostname);
- return TRUE;
- }
- }
- g_free (hostname);
-
- return FALSE;
-}
-
-static SoupAddress *
-get_proxy_for_message (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg)
-{
- SoupProxyResolverGConfPrivate *priv =
- SOUP_PROXY_RESOLVER_GCONF_GET_PRIVATE (proxy_resolver);
- SoupAddress *addr;
-
- g_mutex_lock (priv->lock);
-
- if (!priv->proxy_addr || message_has_ignored_address (priv, msg)) {
- g_mutex_unlock (priv->lock);
- return NULL;
- }
-
- addr = g_object_ref (priv->proxy_addr);
- g_mutex_unlock (priv->lock);
- return addr;
-}
-
-typedef struct {
- SoupProxyResolver *proxy_resolver;
- SoupMessage *msg;
- SoupAddress *addr;
- SoupProxyResolverCallback callback;
- gpointer user_data;
-} SoupGConfAsyncData;
-
-static void
-resolved_address (SoupAddress *addr, guint status, gpointer data)
-{
- SoupGConfAsyncData *sgad = data;
-
- sgad->callback (sgad->proxy_resolver, sgad->msg,
- soup_status_proxify (status), addr,
- sgad->user_data);
- g_object_unref (sgad->proxy_resolver);
- g_object_unref (sgad->msg);
- if (addr)
- g_object_unref (addr);
- g_slice_free (SoupGConfAsyncData, sgad);
-}
-
-static gboolean
-resolved_no_address (gpointer data)
-{
- resolved_address (NULL, SOUP_STATUS_OK, data);
- return FALSE;
-}
-
-static void
-get_proxy_async (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GMainContext *async_context,
- GCancellable *cancellable,
- SoupProxyResolverCallback callback,
- gpointer user_data)
-{
- SoupGConfAsyncData *sgad;
-
- sgad = g_slice_new0 (SoupGConfAsyncData);
- sgad->proxy_resolver = g_object_ref (proxy_resolver);
- sgad->msg = g_object_ref (msg);
- sgad->callback = callback;
- sgad->user_data = user_data;
- sgad->addr = get_proxy_for_message (proxy_resolver, msg);
-
- if (sgad->addr) {
- soup_address_resolve_async (sgad->addr, async_context,
- cancellable, resolved_address,
- sgad);
- } else
- soup_add_idle (async_context, resolved_no_address, sgad);
-}
-
-static guint
-get_proxy_sync (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GCancellable *cancellable,
- SoupAddress **addr)
-{
- *addr = get_proxy_for_message (proxy_resolver, msg);
- if (*addr)
- return soup_status_proxify (soup_address_resolve_sync (*addr, cancellable));
- else
- return SOUP_STATUS_OK;
-}
diff --git a/libsoup/soup-proxy-resolver-gconf.h b/libsoup/soup-proxy-resolver-gconf.h
deleted file mode 100644
index d14f7f33..00000000
--- a/libsoup/soup-proxy-resolver-gconf.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2008 Red Hat, Inc.
- */
-
-#ifndef SOUP_PROXY_RESOLVER_GCONF_H
-#define SOUP_PROXY_RESOLVER_GCONF_H 1
-
-#include <libsoup/soup-proxy-resolver.h>
-
-#define SOUP_TYPE_PROXY_RESOLVER_GCONF (soup_proxy_resolver_gconf_get_type ())
-#define SOUP_PROXY_RESOLVER_GCONF(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PROXY_RESOLVER_GCONF, SoupProxyResolverGConf))
-#define SOUP_PROXY_RESOLVER_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PROXY_RESOLVER_GCONF, SoupProxyResolverGConfClass))
-#define SOUP_IS_PROXY_RESOLVER_GCONF(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PROXY_RESOLVER_GCONF))
-#define SOUP_IS_PROXY_RESOLVER_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PROXY_RESOLVER_GCONF))
-#define SOUP_PROXY_RESOLVER_GCONF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_PROXY_RESOLVER_GCONF, SoupProxyResolverGConfClass))
-
-typedef struct {
- GObject parent;
-
-} SoupProxyResolverGConf;
-
-typedef struct {
- GObjectClass parent_class;
-
-} SoupProxyResolverGConfClass;
-
-GType soup_proxy_resolver_gconf_get_type (void);
-
-SoupProxyResolver *soup_proxy_resolver_gconf_new (void);
-
-#endif /*SOUP_PROXY_RESOLVER_GCONF_H*/
diff --git a/libsoup/soup-proxy-resolver-gnome.c b/libsoup/soup-proxy-resolver-gnome.c
new file mode 100644
index 00000000..a5a30732
--- /dev/null
+++ b/libsoup/soup-proxy-resolver-gnome.c
@@ -0,0 +1,473 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-proxy-resolver-gnome.c: GNOME proxy resolution
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "soup-proxy-resolver-gnome.h"
+#include "soup-address.h"
+#include "soup-dns.h"
+#include "soup-message.h"
+#include "soup-misc.h"
+#include "soup-session-feature.h"
+#include "soup-uri.h"
+
+#include <gconf/gconf-client.h>
+#include <proxy.h>
+
+typedef enum {
+ SOUP_PROXY_RESOLVER_GNOME_MODE_NONE,
+ SOUP_PROXY_RESOLVER_GNOME_MODE_MANUAL,
+ SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO
+} SoupProxyResolverGNOMEMode;
+
+/* Since GConf is not thread-safe, making it annoying for us to deal
+ * with, we make all of these static variables rather than instance
+ * variables, so that we only have to deal with it once, rather than
+ * per-resolver.
+ */
+G_LOCK_DEFINE_STATIC (resolver_gnome);
+static SoupProxyResolverGNOMEMode proxy_mode;
+static GConfClient *gconf_client;
+
+static pxProxyFactory *libproxy_factory;
+static GThreadPool *libproxy_threadpool;
+
+static void soup_proxy_resolver_gnome_interface_init (SoupProxyResolverInterface *proxy_resolver_interface);
+
+G_DEFINE_TYPE_EXTENDED (SoupProxyResolverGNOME, soup_proxy_resolver_gnome, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
+ G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_RESOLVER, soup_proxy_resolver_gnome_interface_init))
+
+static void gconf_value_changed (GConfClient *client, const char *key,
+ GConfValue *value, gpointer user_data);
+static void update_proxy_settings (void);
+
+static void libproxy_threadpool_func (gpointer thread_data, gpointer user_data);
+
+static void get_proxy_async (SoupProxyResolver *proxy_resolver,
+ SoupMessage *msg,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupProxyResolverCallback callback,
+ gpointer user_data);
+static guint get_proxy_sync (SoupProxyResolver *proxy_resolver,
+ SoupMessage *msg,
+ GCancellable *cancellable,
+ SoupAddress **addr);
+
+typedef struct {
+ GMutex *lock;
+ GCond *cond;
+} SoupProxyResolverGNOMEInitData;
+
+static gboolean
+init_gconf (gpointer user_data)
+{
+ SoupProxyResolverGNOMEInitData *id = user_data;
+
+ if (id)
+ g_mutex_lock (id->lock);
+
+ /* resolver_gnome is locked */
+
+ gconf_client = gconf_client_get_default ();
+
+ gconf_client_add_dir (gconf_client, "/system/proxy",
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ gconf_client_add_dir (gconf_client, "/system/http_proxy",
+ GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+ g_signal_connect (gconf_client, "value_changed",
+ G_CALLBACK (gconf_value_changed),
+ NULL);
+ update_proxy_settings ();
+
+ if (id) {
+ g_mutex_unlock (id->lock);
+ g_cond_signal (id->cond);
+ }
+ return FALSE;
+}
+
+static void
+soup_proxy_resolver_gnome_init (SoupProxyResolverGNOME *resolver_gnome)
+{
+ GMainContext *default_context;
+
+ G_LOCK (resolver_gnome);
+ if (!gconf_client) {
+ /* GConf is not thread-safe, and we might be running
+ * in some random thread right now while other
+ * GConf-related activity is going on in the main
+ * thread. To prevent badness, we try to claim the
+ * default GMainContext; if we succeed, then either
+ * we're in the thread of the default GMainContext, or
+ * else there isn't currently any thread running the
+ * default GMainContext (meaning either the main loop
+ * hasn't been started yet, or else there is no main
+ * loop). Either way, it's safe to use GConf.
+ *
+ * If we can't manage to acquire the default
+ * GMainContext, then that means another thread
+ * already has it, so we use g_idle_add() to ask that
+ * thread to do the GConf initialization, and wait
+ * for that thread to finish.
+ */
+ default_context = g_main_context_default ();
+ if (g_main_context_acquire (default_context)) {
+ init_gconf (NULL);
+ g_main_context_release (default_context);
+ } else {
+ SoupProxyResolverGNOMEInitData id;
+
+ id.lock = g_mutex_new ();
+ id.cond = g_cond_new ();
+
+ g_mutex_lock (id.lock);
+ g_idle_add (init_gconf, &id);
+ g_cond_wait (id.cond, id.lock);
+
+ g_cond_free (id.cond);
+ g_mutex_free (id.lock);
+ }
+ }
+ G_UNLOCK(resolver_gnome);
+}
+
+static void
+soup_proxy_resolver_gnome_class_init (SoupProxyResolverGNOMEClass *gconf_class)
+{
+}
+
+static void
+soup_proxy_resolver_gnome_interface_init (SoupProxyResolverInterface *proxy_resolver_interface)
+{
+ proxy_resolver_interface->get_proxy_async = get_proxy_async;
+ proxy_resolver_interface->get_proxy_sync = get_proxy_sync;
+}
+
+#define SOUP_GCONF_PROXY_MODE "/system/proxy/mode"
+#define SOUP_GCONF_PROXY_AUTOCONFIG_URL "/system/proxy/autoconfig_url"
+#define SOUP_GCONF_HTTP_PROXY_HOST "/system/http_proxy/host"
+#define SOUP_GCONF_HTTP_PROXY_PORT "/system/http_proxy/port"
+#define SOUP_GCONF_HTTPS_PROXY_HOST "/system/proxy/secure_host"
+#define SOUP_GCONF_HTTPS_PROXY_PORT "/system/proxy/secure_port"
+#define SOUP_GCONF_USE_SAME_PROXY "/system/http_proxy/use_same_proxy"
+#define SOUP_GCONF_PROXY_IGNORE_HOSTS "/system/http_proxy/ignore_hosts"
+
+static GConfEnumStringPair proxy_mode_map [] = {
+ { SOUP_PROXY_RESOLVER_GNOME_MODE_NONE, "none" },
+ { SOUP_PROXY_RESOLVER_GNOME_MODE_MANUAL, "manual" },
+ { SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO, "auto" },
+ { 0, NULL }
+};
+
+static void
+update_proxy_settings (void)
+{
+ char *mode, *http_proxy, *https_proxy = NULL, *no_proxy = NULL;
+ GSList *ignore;
+
+ /* resolver_gnome is locked */
+
+ /* Get new settings */
+ mode = gconf_client_get_string (
+ gconf_client, SOUP_GCONF_PROXY_MODE, NULL);
+ if (!mode || !gconf_string_to_enum (proxy_mode_map, mode,
+ (int *)&proxy_mode)) {
+ proxy_mode = SOUP_PROXY_RESOLVER_GNOME_MODE_NONE;
+ g_free (mode);
+ return;
+ }
+ g_free (mode);
+
+ if (proxy_mode == SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO) {
+ char *autoconfig_url;
+
+ autoconfig_url = gconf_client_get_string (
+ gconf_client, SOUP_GCONF_PROXY_AUTOCONFIG_URL, NULL);
+ if (autoconfig_url && !strncmp (autoconfig_url, "http", 4))
+ http_proxy = g_strconcat ("pac+", autoconfig_url, NULL);
+ else
+ http_proxy = g_strdup ("wpad://");
+ g_free (autoconfig_url);
+ } else /* SOUP_PROXY_RESOLVER_GNOME_MODE_MANUAL */ {
+ char *host;
+ guint port;
+
+ host = gconf_client_get_string (
+ gconf_client, SOUP_GCONF_HTTP_PROXY_HOST, NULL);
+ if (!host && !*host) {
+ g_free (host);
+ proxy_mode = SOUP_PROXY_RESOLVER_GNOME_MODE_NONE;
+ return;
+ }
+ port = gconf_client_get_int (
+ gconf_client, SOUP_GCONF_HTTP_PROXY_PORT, NULL);
+
+ if (port) {
+ http_proxy = g_strdup_printf ("http://%s:%u",
+ host, port);
+ } else
+ http_proxy = g_strdup_printf ("http://%s", host);
+ g_free (host);
+
+ if (!gconf_client_get_bool (gconf_client, SOUP_GCONF_USE_SAME_PROXY, NULL)) {
+ host = gconf_client_get_string (
+ gconf_client, SOUP_GCONF_HTTPS_PROXY_HOST, NULL);
+ port = gconf_client_get_int (
+ gconf_client, SOUP_GCONF_HTTPS_PROXY_PORT, NULL);
+
+ if (host && *host) {
+ if (port) {
+ https_proxy = g_strdup_printf (
+ "http://%s:%u", host, port);
+ } else {
+ https_proxy = g_strdup_printf (
+ "http://%s", host);
+ }
+ }
+ g_free (host);
+ }
+ }
+
+ ignore = gconf_client_get_list (
+ gconf_client, SOUP_GCONF_PROXY_IGNORE_HOSTS,
+ GCONF_VALUE_STRING, NULL);
+ if (ignore) {
+ GString *ignore_list;
+ GSList *i;
+
+ ignore_list = g_string_new (NULL);
+ for (i = ignore; i; i = i->next) {
+ if (ignore_list->len)
+ g_string_append_c (ignore_list, ',');
+ g_string_append (ignore_list, i->data);
+ g_free (i->data);
+ }
+ g_slist_free (ignore);
+ no_proxy = g_string_free (ignore_list, FALSE);
+ }
+
+ g_setenv ("PX_CONFIG_ORDER", "envvar", TRUE);
+ g_setenv ("http_proxy", http_proxy, TRUE);
+ g_free (http_proxy);
+ if (https_proxy) {
+ g_setenv ("https_proxy", https_proxy, TRUE);
+ g_free (https_proxy);
+ } else
+ g_unsetenv ("https_proxy");
+ if (no_proxy) {
+ g_setenv ("no_proxy", no_proxy, TRUE);
+ g_free (no_proxy);
+ } else
+ g_unsetenv ("no_proxy");
+
+ /* If we haven't created a proxy factory or thread pool yet,
+ * do so. If we already have one, we don't need to update
+ * anything, because it rechecks the environment variables
+ * every time.
+ */
+ if (!libproxy_factory)
+ libproxy_factory = px_proxy_factory_new ();
+
+ if (proxy_mode == SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO &&
+ !libproxy_threadpool) {
+ libproxy_threadpool =
+ g_thread_pool_new (libproxy_threadpool_func,
+ NULL, -1, FALSE, NULL);
+ }
+}
+
+static void
+gconf_value_changed (GConfClient *client, const char *key,
+ GConfValue *value, gpointer user_data)
+{
+ G_LOCK (resolver_gnome);
+ update_proxy_settings ();
+ G_UNLOCK (resolver_gnome);
+}
+
+static guint
+get_proxy_for_message (SoupMessage *msg, SoupAddress **addr)
+{
+ char *msg_uri, **proxies;
+ SoupURI *proxy_uri;
+ gboolean got_proxy;
+ int i;
+
+ /* resolver_gnome is locked */
+
+ msg_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
+ proxies = px_proxy_factory_get_proxies (libproxy_factory, msg_uri);
+ g_free (msg_uri);
+
+ if (!proxies) {
+ *addr = NULL;
+ return SOUP_STATUS_OK;
+ }
+
+ got_proxy = FALSE;
+ for (i = 0; proxies[i]; i++) {
+ if (!strcmp (proxies[i], "direct://")) {
+ proxy_uri = NULL;
+ got_proxy = TRUE;
+ break;
+ }
+ if (strncmp (proxies[i], "http://", 7) == 0) {
+ proxy_uri = soup_uri_new (proxies[i]);
+ got_proxy = TRUE;
+ break;
+ }
+ }
+ for (i = 0; proxies[i]; i++)
+ free (proxies[i]);
+ free (proxies);
+
+ if (!got_proxy) {
+ *addr = NULL;
+ return SOUP_STATUS_CANT_RESOLVE_PROXY;
+ }
+
+ if (proxy_uri) {
+ *addr = soup_address_new (proxy_uri->host, proxy_uri->port);
+ soup_uri_free (proxy_uri);
+ } else
+ *addr = NULL;
+ return SOUP_STATUS_OK;
+}
+
+typedef struct {
+ SoupProxyResolver *proxy_resolver;
+ SoupMessage *msg;
+ SoupAddress *addr;
+ GMainContext *async_context;
+ GCancellable *cancellable;
+ guint status;
+ SoupProxyResolverCallback callback;
+ gpointer user_data;
+} SoupGNOMEAsyncData;
+
+static void
+resolved_address (SoupAddress *addr, guint status, gpointer data)
+{
+ SoupGNOMEAsyncData *sgad = data;
+
+ sgad->callback (sgad->proxy_resolver, sgad->msg,
+ soup_status_proxify (status), addr,
+ sgad->user_data);
+ g_object_unref (sgad->proxy_resolver);
+ g_object_unref (sgad->msg);
+ if (sgad->async_context)
+ g_main_context_unref (sgad->async_context);
+ if (sgad->cancellable)
+ g_object_unref (sgad->cancellable);
+ if (addr)
+ g_object_unref (addr);
+ g_slice_free (SoupGNOMEAsyncData, sgad);
+}
+
+static gboolean
+idle_resolved_address (gpointer data)
+{
+ SoupGNOMEAsyncData *sgad = data;
+
+ resolved_address (sgad->addr, sgad->status, data);
+ return FALSE;
+}
+
+static void
+libproxy_threadpool_func (gpointer user_data, gpointer thread_data)
+{
+ SoupGNOMEAsyncData *sgad = user_data;
+
+ /* We don't just call get_libproxy_proxy_for_message here,
+ * since it's possible that the proxy mode has changed...
+ */
+ sgad->status = get_proxy_sync (NULL, sgad->msg, sgad->cancellable,
+ &sgad->addr);
+ soup_add_completion (sgad->async_context, idle_resolved_address, sgad);
+}
+
+static void
+get_proxy_async (SoupProxyResolver *proxy_resolver,
+ SoupMessage *msg,
+ GMainContext *async_context,
+ GCancellable *cancellable,
+ SoupProxyResolverCallback callback,
+ gpointer user_data)
+{
+ SoupGNOMEAsyncData *sgad;
+
+ sgad = g_slice_new0 (SoupGNOMEAsyncData);
+ sgad->proxy_resolver = g_object_ref (proxy_resolver);
+ sgad->msg = g_object_ref (msg);
+ sgad->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+ sgad->async_context = async_context ? g_main_context_ref (sgad->async_context) : NULL;
+ sgad->callback = callback;
+ sgad->user_data = user_data;
+
+ G_LOCK (resolver_gnome);
+ switch (proxy_mode) {
+ case SOUP_PROXY_RESOLVER_GNOME_MODE_NONE:
+ sgad->addr = NULL;
+ sgad->status = SOUP_STATUS_OK;
+ break;
+
+ case SOUP_PROXY_RESOLVER_GNOME_MODE_MANUAL:
+ /* We know libproxy won't do PAC or WPAD in this case,
+ * so we can make a "blocking" call to it.
+ */
+ sgad->status = get_proxy_for_message (msg, &sgad->addr);
+ break;
+
+ case SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO:
+ /* FIXME: cancellable */
+ g_thread_pool_push (libproxy_threadpool, sgad, NULL);
+ G_UNLOCK (resolver_gnome);
+ return;
+ }
+ G_UNLOCK (resolver_gnome);
+
+ if (sgad->addr) {
+ soup_address_resolve_async (sgad->addr, async_context,
+ cancellable, resolved_address,
+ sgad);
+ } else
+ soup_add_idle (async_context, idle_resolved_address, sgad);
+}
+
+static guint
+get_proxy_sync (SoupProxyResolver *proxy_resolver,
+ SoupMessage *msg,
+ GCancellable *cancellable,
+ SoupAddress **addr)
+{
+ guint status;
+
+ G_LOCK (resolver_gnome);
+ if (proxy_mode == SOUP_PROXY_RESOLVER_GNOME_MODE_NONE) {
+ *addr = NULL;
+ status = SOUP_STATUS_OK;
+ } else
+ status = get_proxy_for_message (msg, addr);
+ G_UNLOCK (resolver_gnome);
+
+ if (!*addr || status != SOUP_STATUS_OK)
+ return status;
+
+ status = soup_address_resolve_sync (*addr, cancellable);
+ if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+ g_object_unref (*addr);
+ *addr = NULL;
+ }
+ return soup_status_proxify (status);
+}
diff --git a/libsoup/soup-proxy-resolver-gnome.h b/libsoup/soup-proxy-resolver-gnome.h
new file mode 100644
index 00000000..9f29842c
--- /dev/null
+++ b/libsoup/soup-proxy-resolver-gnome.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Red Hat, Inc.
+ */
+
+#ifndef SOUP_PROXY_RESOLVER_GNOME_H
+#define SOUP_PROXY_RESOLVER_GNOME_H 1
+
+#include "soup-proxy-resolver.h"
+#include "soup-gnome-features.h"
+
+/* SOUP_TYPE_PROXY_RESOLVER_GNOME and soup_proxy_resolver_gnome_get_type()
+ * are declared in soup-gnome-features.h.
+ */
+
+#define SOUP_PROXY_RESOLVER_GNOME(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PROXY_RESOLVER_GNOME, SoupProxyResolverGNOME))
+#define SOUP_PROXY_RESOLVER_GNOME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PROXY_RESOLVER_GNOME, SoupProxyResolverGNOMEClass))
+#define SOUP_IS_PROXY_RESOLVER_GNOME(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PROXY_RESOLVER_GNOME))
+#define SOUP_IS_PROXY_RESOLVER_GNOME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PROXY_RESOLVER_GNOME))
+#define SOUP_PROXY_RESOLVER_GNOME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_PROXY_RESOLVER_GNOME, SoupProxyResolverGNOMEClass))
+
+typedef struct {
+ GObject parent;
+
+} SoupProxyResolverGNOME;
+
+typedef struct {
+ GObjectClass parent_class;
+
+} SoupProxyResolverGNOMEClass;
+
+#endif /*SOUP_PROXY_RESOLVER_GNOME_H*/
diff --git a/libsoup/soup-proxy-resolver-libproxy.c b/libsoup/soup-proxy-resolver-libproxy.c
deleted file mode 100644
index bc51f09b..00000000
--- a/libsoup/soup-proxy-resolver-libproxy.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * soup-proxy-resolver-libproxy.c: libproxy-based proxy resolution
- *
- * Copyright (C) 2008 Red Hat, Inc.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "soup-proxy-resolver-libproxy.h"
-#include "soup-address.h"
-#include "soup-message.h"
-#include "soup-misc.h"
-#include "soup-session-feature.h"
-#include "soup-uri.h"
-
-#include <proxy.h>
-
-typedef struct {
- pxProxyFactory *factory;
-} SoupProxyResolverLibproxyPrivate;
-
-#define SOUP_PROXY_RESOLVER_LIBPROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY, SoupProxyResolverLibproxyPrivate))
-
-static void soup_proxy_resolver_libproxy_interface_init (SoupProxyResolverInterface *proxy_resolver_interface);
-
-G_DEFINE_TYPE_EXTENDED (SoupProxyResolverLibproxy, soup_proxy_resolver_libproxy, G_TYPE_OBJECT, 0,
- G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE, NULL)
- G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_RESOLVER, soup_proxy_resolver_libproxy_interface_init))
-
-static void get_proxy_async (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GMainContext *async_context,
- GCancellable *cancellable,
- SoupProxyResolverCallback callback,
- gpointer user_data);
-static guint get_proxy_sync (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GCancellable *cancellable,
- SoupAddress **addr);
-
-static void
-soup_proxy_resolver_libproxy_init (SoupProxyResolverLibproxy *libproxy)
-{
- SoupProxyResolverLibproxyPrivate *priv =
- SOUP_PROXY_RESOLVER_LIBPROXY_GET_PRIVATE (libproxy);
-
- priv->factory = px_proxy_factory_new ();
-}
-
-static void
-finalize (GObject *object)
-{
- SoupProxyResolverLibproxyPrivate *priv =
- SOUP_PROXY_RESOLVER_LIBPROXY_GET_PRIVATE (object);
-
- px_proxy_factory_free (priv->factory);
-
- G_OBJECT_CLASS (soup_proxy_resolver_libproxy_parent_class)->finalize (object);
-}
-
-static void
-soup_proxy_resolver_libproxy_class_init (SoupProxyResolverLibproxyClass *libproxy_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (libproxy_class);
-
- g_type_class_add_private (libproxy_class, sizeof (SoupProxyResolverLibproxyPrivate));
-
- object_class->finalize = finalize;
-}
-
-static void
-soup_proxy_resolver_libproxy_interface_init (SoupProxyResolverInterface *proxy_resolver_interface)
-{
- proxy_resolver_interface->get_proxy_async = get_proxy_async;
- proxy_resolver_interface->get_proxy_sync = get_proxy_sync;
-}
-
-SoupProxyResolver *
-soup_proxy_resolver_libproxy_new (void)
-{
- return g_object_new (SOUP_TYPE_PROXY_RESOLVER_LIBPROXY, NULL);
-}
-
-typedef struct {
- SoupProxyResolver *proxy_resolver;
- SoupMessage *msg;
- GMainContext *async_context;
- GCancellable *cancellable;
- guint status;
- SoupAddress *addr;
- SoupProxyResolverCallback callback;
- gpointer user_data;
-} SoupLibproxyAsyncData;
-
-static gboolean
-resolve_callback (gpointer data)
-{
- SoupLibproxyAsyncData *slad = data;
-
- slad->callback (slad->proxy_resolver, slad->msg,
- slad->status, slad->addr, slad->user_data);
- g_object_unref (slad->proxy_resolver);
- g_object_unref (slad->msg);
- if (slad->addr)
- g_object_unref (slad->addr);
- g_slice_free (SoupLibproxyAsyncData, slad);
-
- return FALSE;
-}
-
-static gpointer
-resolve_thread (gpointer data)
-{
- SoupLibproxyAsyncData *slad = data;
-
- slad->status = get_proxy_sync (slad->proxy_resolver,
- slad->msg,
- slad->cancellable,
- &slad->addr);
- soup_add_idle (slad->async_context, resolve_callback, slad);
- return NULL;
-}
-
-static void
-get_proxy_async (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GMainContext *async_context,
- GCancellable *cancellable,
- SoupProxyResolverCallback callback,
- gpointer user_data)
-{
- SoupLibproxyAsyncData *slad;
-
- slad = g_slice_new0 (SoupLibproxyAsyncData);
- slad->proxy_resolver = g_object_ref (proxy_resolver);
- slad->msg = g_object_ref (msg);
- slad->async_context = async_context;
- slad->cancellable = cancellable;
- slad->callback = callback;
- slad->user_data = user_data;
-
- g_thread_create (resolve_thread, slad, FALSE, NULL);
-}
-
-static void
-free_proxies (char **proxies)
-{
- int i;
-
- for (i = 0; proxies[i]; i++)
- free (proxies[i]);
- free (proxies);
-}
-
-static guint
-get_proxy_sync (SoupProxyResolver *proxy_resolver,
- SoupMessage *msg,
- GCancellable *cancellable,
- SoupAddress **addr)
-{
- SoupProxyResolverLibproxyPrivate *priv =
- SOUP_PROXY_RESOLVER_LIBPROXY_GET_PRIVATE (proxy_resolver);
- char *msg_uri, **proxies;
- SoupURI *proxy_uri;
- int i;
-
- msg_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
- proxies = px_proxy_factory_get_proxies (priv->factory, msg_uri);
- g_free (msg_uri);
-
- if (!proxies) {
- *addr = NULL;
- return SOUP_STATUS_OK;
- }
-
- if (proxies[0] && !strcmp (proxies[0], "direct://")) {
- free_proxies (proxies);
- *addr = NULL;
- return SOUP_STATUS_OK;
- }
-
- for (i = 0; proxies[i]; i++) {
- if (strncmp (proxies[i], "http://", 7) == 0)
- break;
- }
- if (!proxies[i]) {
- free_proxies (proxies);
- *addr = NULL;
- return SOUP_STATUS_CANT_RESOLVE_PROXY;
- }
-
- proxy_uri = soup_uri_new (proxies[i]);
- free_proxies (proxies);
- if (!proxy_uri) {
- *addr = NULL;
- return SOUP_STATUS_CANT_RESOLVE_PROXY;
- }
-
- *addr = soup_address_new (proxy_uri->host, proxy_uri->port);
- soup_uri_free (proxy_uri);
- return soup_status_proxify (soup_address_resolve_sync (*addr, cancellable));
-}
diff --git a/libsoup/soup-proxy-resolver-libproxy.h b/libsoup/soup-proxy-resolver-libproxy.h
deleted file mode 100644
index 1c4aed4e..00000000
--- a/libsoup/soup-proxy-resolver-libproxy.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2008 Red Hat, Inc.
- */
-
-#ifndef SOUP_PROXY_RESOLVER_LIBPROXY_H
-#define SOUP_PROXY_RESOLVER_LIBPROXY_H 1
-
-#include <libsoup/soup-proxy-resolver.h>
-
-#define SOUP_TYPE_PROXY_RESOLVER_LIBPROXY (soup_proxy_resolver_libproxy_get_type ())
-#define SOUP_PROXY_RESOLVER_LIBPROXY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY, SoupProxyResolverLibproxy))
-#define SOUP_PROXY_RESOLVER_LIBPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY, SoupProxyResolverLibproxyClass))
-#define SOUP_IS_PROXY_RESOLVER_LIBPROXY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY))
-#define SOUP_IS_PROXY_RESOLVER_LIBPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY))
-#define SOUP_PROXY_RESOLVER_LIBPROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_PROXY_RESOLVER_LIBPROXY, SoupProxyResolverLibproxyClass))
-
-typedef struct {
- GObject parent;
-
-} SoupProxyResolverLibproxy;
-
-typedef struct {
- GObjectClass parent_class;
-
-} SoupProxyResolverLibproxyClass;
-
-GType soup_proxy_resolver_libproxy_get_type (void);
-
-SoupProxyResolver *soup_proxy_resolver_libproxy_new (void);
-
-#endif /*SOUP_PROXY_RESOLVER_LIBPROXY_H*/