[libsoup/gnome-2-26] Implement SoupProxyURIResolver, to replace SoupProxyResolver



commit 7708d899bf1aa4bf5ce75ec75b087d398155597d
Author: Dan Winship <danw gnome org>
Date:   Sat Jun 6 18:57:51 2009 -0400

    Implement SoupProxyURIResolver, to replace SoupProxyResolver
    
    Simplifies implementations, allows for non-http proxy resolution, and
    allows authentication information to be passed.
    
    http://bugzilla.gnome.org/show_bug.cgi?id=580051

 libsoup/Makefile.am                 |    2 +
 libsoup/soup-auth-manager.c         |   21 +++--
 libsoup/soup-connection.c           |   41 +++++---
 libsoup/soup-connection.h           |    3 +-
 libsoup/soup-message-queue.c        |    3 +
 libsoup/soup-message-queue.h        |    1 +
 libsoup/soup-proxy-resolver-gnome.c |  184 +++++++++++++++++------------------
 libsoup/soup-proxy-resolver-gnome.h |    1 -
 libsoup/soup-proxy-resolver.c       |  164 +++++++++++++++++++++++++------
 libsoup/soup-proxy-resolver.h       |    4 +
 libsoup/soup-proxy-uri-resolver.c   |   97 ++++++++++++++++++
 libsoup/soup-proxy-uri-resolver.h   |   57 +++++++++++
 libsoup/soup-session-async.c        |   75 +++++++++++---
 libsoup/soup-session-private.h      |    4 +-
 libsoup/soup-session-sync.c         |   25 ++++-
 libsoup/soup-session.c              |   40 +++++---
 16 files changed, 537 insertions(+), 185 deletions(-)
---
diff --git a/libsoup/Makefile.am b/libsoup/Makefile.am
index dc9ff55..949f243 100644
--- a/libsoup/Makefile.am
+++ b/libsoup/Makefile.am
@@ -70,6 +70,7 @@ soup_headers =			\
 	soup-multipart.h     	\
 	soup-portability.h	\
 	soup-proxy-resolver.h	\
+	soup-proxy-uri-resolver.h \
 	soup-server.h		\
 	soup-session.h		\
 	soup-session-async.h	\
@@ -146,6 +147,7 @@ libsoup_2_4_la_SOURCES =		\
 	soup-proxy-resolver.c		\
 	soup-proxy-resolver-static.h	\
 	soup-proxy-resolver-static.c	\
+	soup-proxy-uri-resolver.c	\
 	soup-server.c			\
 	soup-session.c			\
 	soup-session-async.c		\
diff --git a/libsoup/soup-auth-manager.c b/libsoup/soup-auth-manager.c
index c49cf3b..5d1d1bc 100644
--- a/libsoup/soup-auth-manager.c
+++ b/libsoup/soup-auth-manager.c
@@ -16,9 +16,11 @@
 #include "soup-headers.h"
 #include "soup-marshal.h"
 #include "soup-message-private.h"
+#include "soup-message-queue.h"
 #include "soup-path-map.h"
 #include "soup-session.h"
 #include "soup-session-feature.h"
+#include "soup-session-private.h"
 #include "soup-uri.h"
 
 static void soup_auth_manager_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
@@ -363,21 +365,26 @@ authenticate_auth (SoupAuthManager *manager, SoupAuth *auth,
 		return TRUE;
 
 	if (proxy) {
-		g_object_get (G_OBJECT (priv->session),
-			      SOUP_SESSION_PROXY_URI, &uri,
-			      NULL);
-		/* FIXME: temporary workaround for proxy auth brokenness */
+		SoupMessageQueue *queue;
+		SoupMessageQueueItem *item;
+
+		queue = soup_session_get_queue (priv->session);
+		item = soup_message_queue_lookup (queue, msg);
+		if (item) {
+			uri = soup_connection_get_proxy_uri (item->conn);
+			soup_message_queue_item_unref (item);
+		} else
+			uri = NULL;
+
 		if (!uri)
 			return FALSE;
 	} else
-		uri = soup_uri_copy (soup_message_get_uri (msg));
+		uri = soup_message_get_uri (msg);
 
 	if (uri->password && !prior_auth_failed) {
 		soup_auth_authenticate (auth, uri->user, uri->password);
-		soup_uri_free (uri);
 		return TRUE;
 	}
-	soup_uri_free (uri);
 
 	if (can_interact) {
 		soup_auth_manager_emit_authenticate (manager, msg, auth,
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index a6d8670..0d731c0 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -31,7 +31,7 @@ typedef struct {
 	SoupSocket  *socket;
 
 	SoupAddress *remote_addr, *tunnel_addr;
-	gboolean     is_proxy;
+	SoupURI     *proxy_uri;
 	gpointer     ssl_creds;
 
 	GMainContext      *async_context;
@@ -58,7 +58,7 @@ enum {
 
 	PROP_REMOTE_ADDRESS,
 	PROP_TUNNEL_ADDRESS,
-	PROP_IS_PROXY,
+	PROP_PROXY_URI,
 	PROP_SSL_CREDS,
 	PROP_ASYNC_CONTEXT,
 	PROP_TIMEOUT,
@@ -152,12 +152,12 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 				     SOUP_TYPE_ADDRESS,
 				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (
-		object_class, PROP_IS_PROXY,
-		g_param_spec_boolean (SOUP_CONNECTION_IS_PROXY,
-				      "Is proxy",
-				      "Whether or not this is a connection to an HTTP Proxy",
-				      FALSE,
-				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+		object_class, PROP_PROXY_URI,
+		g_param_spec_boxed (SOUP_CONNECTION_PROXY_URI,
+				    "Proxy URI",
+				    "URI of the HTTP proxy this connection connects to",
+				    SOUP_TYPE_URI,
+				    G_PARAM_READWRITE));
 	g_object_class_install_property (
 		object_class, PROP_SSL_CREDS,
 		g_param_spec_pointer (SOUP_CONNECTION_SSL_CREDENTIALS,
@@ -214,8 +214,10 @@ set_property (GObject *object, guint prop_id,
 	case PROP_TUNNEL_ADDRESS:
 		priv->tunnel_addr = g_value_dup_object (value);
 		break;
-	case PROP_IS_PROXY:
-		priv->is_proxy = g_value_get_boolean (value);
+	case PROP_PROXY_URI:
+		if (priv->proxy_uri)
+			soup_uri_free (priv->proxy_uri);
+		priv->proxy_uri = g_value_dup_boxed (value);
 		break;
 	case PROP_SSL_CREDS:
 		priv->ssl_creds = g_value_get_pointer (value);
@@ -250,8 +252,8 @@ get_property (GObject *object, guint prop_id,
 	case PROP_TUNNEL_ADDRESS:
 		g_value_set_object (value, priv->tunnel_addr);
 		break;
-	case PROP_IS_PROXY:
-		g_value_set_boolean (value, priv->is_proxy);
+	case PROP_PROXY_URI:
+		g_value_set_boxed (value, priv->proxy_uri);
 		break;
 	case PROP_SSL_CREDS:
 		g_value_set_pointer (value, priv->ssl_creds);
@@ -375,7 +377,7 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 
  done:
 	if (data->callback) {
-		if (priv->is_proxy)
+		if (priv->proxy_uri != NULL)
 			status = soup_status_proxify (status);
 		data->callback (data->conn, status, data->callback_data);
 	}
@@ -472,7 +474,7 @@ soup_connection_connect_sync (SoupConnection *conn)
 		}
 	}
 
-	if (priv->is_proxy)
+	if (priv->proxy_uri != NULL)
 		status = soup_status_proxify (status);
 	return status;
 }
@@ -585,6 +587,14 @@ soup_connection_get_socket (SoupConnection *conn)
 	return SOUP_CONNECTION_GET_PRIVATE (conn)->socket;
 }
 
+SoupURI *
+soup_connection_get_proxy_uri (SoupConnection *conn)
+{
+	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+
+	return SOUP_CONNECTION_GET_PRIVATE (conn)->proxy_uri;
+}
+
 SoupConnectionState
 soup_connection_get_state (SoupConnection *conn)
 {
@@ -643,5 +653,6 @@ soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
 
 	if (req != priv->cur_req)
 		set_current_request (priv, req);
-	soup_message_send_request (req, priv->socket, conn, priv->is_proxy);
+	soup_message_send_request (req, priv->socket, conn,
+				   priv->proxy_uri != NULL);
 }
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index d4fe465..68a36ab 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -49,7 +49,7 @@ typedef enum {
 
 #define SOUP_CONNECTION_REMOTE_ADDRESS  "remote-address"
 #define SOUP_CONNECTION_TUNNEL_ADDRESS  "tunnel-address"
-#define SOUP_CONNECTION_IS_PROXY        "is-proxy"
+#define SOUP_CONNECTION_PROXY_URI       "proxy-uri"
 #define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
 #define SOUP_CONNECTION_ASYNC_CONTEXT   "async-context"
 #define SOUP_CONNECTION_TIMEOUT         "timeout"
@@ -68,6 +68,7 @@ gboolean        soup_connection_start_ssl      (SoupConnection   *conn);
 void            soup_connection_disconnect     (SoupConnection   *conn);
 
 SoupSocket     *soup_connection_get_socket     (SoupConnection   *conn);
+SoupURI        *soup_connection_get_proxy_uri  (SoupConnection   *conn);
 
 SoupConnectionState soup_connection_get_state  (SoupConnection   *conn);
 void                soup_connection_set_state  (SoupConnection   *conn,
diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 7a7c363..bce5a16 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -11,6 +11,7 @@
 #endif
 
 #include "soup-message-queue.h"
+#include "soup-uri.h"
 
 /**
  * SECTION:soup-message-queue
@@ -166,6 +167,8 @@ soup_message_queue_item_unref (SoupMessageQueueItem *item)
 	g_object_unref (item->cancellable);
 	if (item->proxy_addr)
 		g_object_unref (item->proxy_addr);
+	if (item->proxy_uri)
+		soup_uri_free (item->proxy_uri);
 	if (item->conn)
 		g_object_unref (item->conn);
 	g_slice_free (SoupMessageQueueItem, item);
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index 8487498..b7bc5d1 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -28,6 +28,7 @@ struct SoupMessageQueueItem {
 
 	GCancellable *cancellable;
 	SoupAddress *proxy_addr;
+	SoupURI *proxy_uri;
 	SoupConnection *conn;
 
 	guint resolving_proxy_addr : 1;
diff --git a/libsoup/soup-proxy-resolver-gnome.c b/libsoup/soup-proxy-resolver-gnome.c
index 4371d5a..1873fbb 100644
--- a/libsoup/soup-proxy-resolver-gnome.c
+++ b/libsoup/soup-proxy-resolver-gnome.c
@@ -13,8 +13,7 @@
 #include <stdlib.h>
 
 #include "soup-proxy-resolver-gnome.h"
-#include "soup-address.h"
-#include "soup-dns.h"
+#include "soup-proxy-uri-resolver.h"
 #include "soup-message.h"
 #include "soup-misc.h"
 #include "soup-session-feature.h"
@@ -37,15 +36,16 @@ typedef enum {
 G_LOCK_DEFINE_STATIC (resolver_gnome);
 static SoupProxyResolverGNOMEMode proxy_mode;
 static GConfClient *gconf_client;
+static char *proxy_user, *proxy_password;
 
 static pxProxyFactory *libproxy_factory;
 static GThreadPool *libproxy_threadpool;
 
-static void soup_proxy_resolver_gnome_interface_init (SoupProxyResolverInterface *proxy_resolver_interface);
+static void soup_proxy_resolver_gnome_interface_init (SoupProxyURIResolverInterface *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))
+			G_IMPLEMENT_INTERFACE (SOUP_TYPE_PROXY_URI_RESOLVER, soup_proxy_resolver_gnome_interface_init))
 
 static void gconf_value_changed (GConfClient *client, const char *key,
 				 GConfValue *value, gpointer user_data);
@@ -53,16 +53,16 @@ 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);
+static void get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
+				 SoupURI               *uri,
+				 GMainContext          *async_context,
+				 GCancellable          *cancellable,
+				 SoupProxyURIResolverCallback callback,
+				 gpointer               user_data);
+static guint get_proxy_uri_sync (SoupProxyURIResolver  *proxy_uri_resolver,
+				 SoupURI               *uri,
+				 GCancellable          *cancellable,
+				 SoupURI              **proxy_uri);
 
 typedef struct {
 	GMutex *lock;
@@ -149,16 +149,19 @@ soup_proxy_resolver_gnome_class_init (SoupProxyResolverGNOMEClass *gconf_class)
 }
 
 static void
-soup_proxy_resolver_gnome_interface_init (SoupProxyResolverInterface *proxy_resolver_interface)
+soup_proxy_resolver_gnome_interface_init (SoupProxyURIResolverInterface *proxy_uri_resolver_interface)
 {
-	proxy_resolver_interface->get_proxy_async = get_proxy_async;
-	proxy_resolver_interface->get_proxy_sync = get_proxy_sync;
+	proxy_uri_resolver_interface->get_proxy_uri_async = get_proxy_uri_async;
+	proxy_uri_resolver_interface->get_proxy_uri_sync = get_proxy_uri_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_HTTP_USE_AUTH        "/system/http_proxy/use_authentication"
+#define SOUP_GCONF_HTTP_PROXY_USER      "/system/http_proxy/authentication_user"
+#define SOUP_GCONF_HTTP_PROXY_PASSWORD  "/system/http_proxy/authentication_password"
 #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"
@@ -179,6 +182,16 @@ update_proxy_settings (void)
 
 	/* resolver_gnome is locked */
 
+	if (proxy_user) {
+		g_free (proxy_user);
+		proxy_user = NULL;
+	}
+	if (proxy_password) {
+		memset (proxy_password, 0, strlen (proxy_password));
+		g_free (proxy_password);
+		proxy_password = NULL;
+	}
+
 	/* Get new settings */
 	mode = gconf_client_get_string (
 		gconf_client, SOUP_GCONF_PROXY_MODE, NULL);
@@ -244,6 +257,13 @@ update_proxy_settings (void)
 			}
 			g_free (host);
 		}
+
+		if (gconf_client_get_bool (gconf_client, SOUP_GCONF_HTTP_USE_AUTH, NULL)) {
+			proxy_user = gconf_client_get_string (
+				gconf_client, SOUP_GCONF_HTTP_PROXY_USER, NULL);
+			proxy_password = gconf_client_get_string (
+				gconf_client, SOUP_GCONF_HTTP_PROXY_PASSWORD, NULL);
+		}
 	}
 
 	ignore = gconf_client_get_list (
@@ -304,33 +324,31 @@ gconf_value_changed (GConfClient *client, const char *key,
 }
 
 static guint
-get_proxy_for_message (SoupMessage *msg, SoupAddress **addr)
+get_proxy_for_uri (SoupURI *uri, SoupURI **proxy_uri)
 {
-	char *msg_uri, **proxies;
-	SoupURI *proxy_uri;
+	char *uristr, **proxies;
 	gboolean got_proxy;
 	int i;
 
+	*proxy_uri = NULL;
+
 	/* 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);
+	uristr = soup_uri_to_string (uri, FALSE);
+	proxies = px_proxy_factory_get_proxies (libproxy_factory, uristr);
+	g_free (uristr);
 
-	if (!proxies) {
-		*addr = NULL;
+	if (!proxies)
 		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]);
+			*proxy_uri = soup_uri_new (proxies[i]);
 			got_proxy = TRUE;
 			break;
 		}
@@ -339,55 +357,45 @@ get_proxy_for_message (SoupMessage *msg, SoupAddress **addr)
 		free (proxies[i]);
 	free (proxies);
 
-	if (!got_proxy) {
-		*addr = NULL;
-		return SOUP_STATUS_CANT_RESOLVE_PROXY;
-	}
+	if (got_proxy) {
+		if (*proxy_uri && proxy_user) {
+			soup_uri_set_user (*proxy_uri, proxy_user);
+			soup_uri_set_password (*proxy_uri, proxy_password);
+		}
 
-	if (proxy_uri) {
-		*addr = soup_address_new (proxy_uri->host, proxy_uri->port);
-		soup_uri_free (proxy_uri);
+		return SOUP_STATUS_OK;
 	} else
-		*addr = NULL;
-	return SOUP_STATUS_OK;
+		return SOUP_STATUS_CANT_RESOLVE_PROXY;
 }
 
 typedef struct {
-	SoupProxyResolver *proxy_resolver;
-	SoupMessage *msg;
-	SoupAddress *addr;
+	SoupProxyURIResolver *proxy_uri_resolver;
+	SoupURI *uri, *proxy_uri;
 	GMainContext *async_context;
 	GCancellable *cancellable;
 	guint status;
-	SoupProxyResolverCallback callback;
+	SoupProxyURIResolverCallback callback;
 	gpointer user_data;
 } SoupGNOMEAsyncData;
 
-static void
-resolved_address (SoupAddress *addr, guint status, gpointer data)
+static gboolean
+resolved_proxy (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);
+	sgad->callback (sgad->proxy_uri_resolver, sgad->status,
+			sgad->proxy_uri, sgad->user_data);
+	g_object_unref (sgad->proxy_uri_resolver);
+	if (sgad->uri)
+		soup_uri_free (sgad->uri);
 	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);
+	if (sgad->proxy_uri)
+		soup_uri_free (sgad->proxy_uri);
 	g_slice_free (SoupGNOMEAsyncData, sgad);
-}
 
-static gboolean
-idle_resolved_address (gpointer data)
-{
-	SoupGNOMEAsyncData *sgad = data;
-
-	resolved_address (sgad->addr, sgad->status, data);
 	return FALSE;
 }
 
@@ -396,36 +404,35 @@ 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...
+	/* We don't just call get_proxy_for_uri 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);
+	sgad->status = get_proxy_uri_sync (sgad->proxy_uri_resolver,
+					   sgad->uri, sgad->cancellable,
+					   &sgad->proxy_uri);
+	soup_add_completion (sgad->async_context, resolved_proxy, sgad);
 }
 
 static void
-get_proxy_async (SoupProxyResolver  *proxy_resolver,
-		 SoupMessage        *msg,
-		 GMainContext       *async_context,
-		 GCancellable       *cancellable,
-		 SoupProxyResolverCallback callback,
-		 gpointer            user_data)
+get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
+		     SoupURI               *uri,
+		     GMainContext          *async_context,
+		     GCancellable          *cancellable,
+		     SoupProxyURIResolverCallback 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->proxy_uri_resolver = g_object_ref (proxy_uri_resolver);
 	sgad->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	sgad->async_context = async_context ? g_main_context_ref (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->proxy_uri = NULL;
 		sgad->status = SOUP_STATUS_OK;
 		break;
 
@@ -433,48 +440,37 @@ get_proxy_async (SoupProxyResolver  *proxy_resolver,
 		/* 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);
+		sgad->status = get_proxy_for_uri (uri, &sgad->proxy_uri);
 		break;
 
 	case SOUP_PROXY_RESOLVER_GNOME_MODE_AUTO:
 		/* FIXME: cancellable */
+		sgad->uri = soup_uri_copy (uri);
+		sgad->async_context = async_context ? g_main_context_ref (async_context) : NULL;
 		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);
+	soup_add_completion (async_context, resolved_proxy, sgad);
 }
 
 static guint
-get_proxy_sync (SoupProxyResolver  *proxy_resolver,
-		SoupMessage        *msg,
-		GCancellable       *cancellable,
-		SoupAddress       **addr)
+get_proxy_uri_sync (SoupProxyURIResolver  *proxy_uri_resolver,
+		    SoupURI               *uri,
+		    GCancellable          *cancellable,
+		    SoupURI              **proxy_uri)
 {
 	guint status;
 
 	G_LOCK (resolver_gnome);
 	if (proxy_mode == SOUP_PROXY_RESOLVER_GNOME_MODE_NONE) {
-		*addr = NULL;
+		*proxy_uri = NULL;
 		status = SOUP_STATUS_OK;
 	} else
-		status = get_proxy_for_message (msg, addr);
+		status = get_proxy_for_uri (uri, proxy_uri);
 	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);
+	return status;
 }
diff --git a/libsoup/soup-proxy-resolver-gnome.h b/libsoup/soup-proxy-resolver-gnome.h
index 9f29842..2f87921 100644
--- a/libsoup/soup-proxy-resolver-gnome.h
+++ b/libsoup/soup-proxy-resolver-gnome.h
@@ -6,7 +6,6 @@
 #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()
diff --git a/libsoup/soup-proxy-resolver.c b/libsoup/soup-proxy-resolver.c
index 630c10c..33a908c 100644
--- a/libsoup/soup-proxy-resolver.c
+++ b/libsoup/soup-proxy-resolver.c
@@ -10,7 +10,14 @@
 #endif
 
 #include "soup-proxy-resolver.h"
+#include "soup-proxy-uri-resolver.h"
+#include "soup-address.h"
+#include "soup-message.h"
 #include "soup-session-feature.h"
+#include "soup-uri.h"
+
+static void soup_proxy_resolver_interface_init (GTypeInterface *interface);
+static void soup_proxy_resolver_uri_resolver_interface_init (SoupProxyURIResolverInterface *uri_resolver_interface);
 
 GType
 soup_proxy_resolver_get_type (void)
@@ -22,7 +29,7 @@ soup_proxy_resolver_get_type (void)
         g_type_register_static_simple (G_TYPE_INTERFACE,
                                        g_intern_static_string ("SoupProxyResolver"),
                                        sizeof (SoupProxyResolverInterface),
-                                       (GClassInitFunc)NULL,
+                                       (GClassInitFunc)soup_proxy_resolver_interface_init,
                                        0,
                                        (GInstanceInitFunc)NULL,
                                        (GTypeFlags) 0);
@@ -33,20 +40,44 @@ soup_proxy_resolver_get_type (void)
   return g_define_type_id__volatile;
 }
 
-/**
- * soup_proxy_resolver_get_proxy_async:
- * @proxy_resolver: the #SoupProxyResolver
- * @msg: the #SoupMessage you want a proxy for
- * @async_context: the #GMainContext to invoke @callback in
- * @cancellable: a #GCancellable, or %NULL
- * @callback: callback to invoke with the proxy address
- * @user_data: data for @callback
- *
- * Asynchronously determines a proxy server address to use for @msg
- * and calls @callback.
- *
- * Since: 2.26
- **/
+static void
+proxy_resolver_interface_check (gpointer func_data, gpointer g_iface)
+{
+	GTypeInterface *interface = g_iface;
+	GTypeClass *klass;
+
+	if (interface->g_type != SOUP_TYPE_PROXY_RESOLVER)
+		return;
+
+	klass = g_type_class_peek (interface->g_instance_type);
+	/* If the class hasn't already declared that it implements
+	 * SoupProxyURIResolver, add our own compat implementation.
+	 */
+	if (!g_type_interface_peek (klass, SOUP_TYPE_PROXY_URI_RESOLVER)) {
+		const GInterfaceInfo uri_resolver_interface_info = {
+			(GInterfaceInitFunc) soup_proxy_resolver_uri_resolver_interface_init, NULL, NULL
+		};
+		g_type_add_interface_static (interface->g_instance_type,
+					     SOUP_TYPE_PROXY_URI_RESOLVER,
+					     &uri_resolver_interface_info);
+	}
+}
+
+
+static void
+soup_proxy_resolver_interface_init (GTypeInterface *interface)
+{
+	/* Add an interface_check where we can kludgily add the
+	 * SoupProxyURIResolver interface to all SoupProxyResolvers.
+	 * (SoupProxyResolver can't just implement
+	 * SoupProxyURIResolver itself because interface types can't
+	 * implement other interfaces.) This is an ugly hack, but it
+	 * only gets used if someone actually creates a
+	 * SoupProxyResolver...
+	 */
+	g_type_add_interface_check (NULL, proxy_resolver_interface_check);
+}
+
 void
 soup_proxy_resolver_get_proxy_async (SoupProxyResolver  *proxy_resolver,
 				     SoupMessage        *msg,
@@ -61,22 +92,6 @@ soup_proxy_resolver_get_proxy_async (SoupProxyResolver  *proxy_resolver,
 				 callback, user_data);
 }
 
-/**
- * soup_proxy_resolver_get_proxy_sync:
- * @proxy_resolver: the #SoupProxyResolver
- * @msg: the #SoupMessage you want a proxy for
- * @cancellable: a #GCancellable, or %NULL
- * @addr: on return, will contain the proxy address
- *
- * Synchronously determines a proxy server address to use for @msg. If
- * @msg should be sent via proxy, * addr will be set to the address of
- * the proxy, else it will be set to %NULL.
- *
- * Return value: SOUP_STATUS_OK if successful, or a transport-level
- * error.
- *
- * Since: 2.26
- **/
 guint
 soup_proxy_resolver_get_proxy_sync (SoupProxyResolver  *proxy_resolver,
 				    SoupMessage        *msg,
@@ -86,3 +101,90 @@ soup_proxy_resolver_get_proxy_sync (SoupProxyResolver  *proxy_resolver,
 	return SOUP_PROXY_RESOLVER_GET_CLASS (proxy_resolver)->
 		get_proxy_sync (proxy_resolver, msg, cancellable, addr);
 }
+
+/* SoupProxyURIResolver implementation */
+
+static SoupURI *
+uri_from_address (SoupAddress *addr)
+{
+	SoupURI *proxy_uri;
+
+	proxy_uri = soup_uri_new (NULL);
+	soup_uri_set_scheme (proxy_uri, SOUP_URI_SCHEME_HTTP);
+	soup_uri_set_host (proxy_uri, soup_address_get_name (addr));
+	soup_uri_set_port (proxy_uri, soup_address_get_port (addr));
+	return proxy_uri;
+}
+
+typedef struct {
+	SoupProxyURIResolverCallback callback;
+	gpointer user_data;
+} ProxyURIResolverAsyncData;
+
+static void
+compat_got_proxy (SoupProxyResolver *proxy_resolver,
+		  SoupMessage *msg, guint status, SoupAddress *proxy_addr,
+		  gpointer user_data)
+{
+	ProxyURIResolverAsyncData *purad = user_data;
+	SoupURI *proxy_uri;
+
+	proxy_uri = proxy_addr ? uri_from_address (proxy_addr) : NULL;
+	purad->callback (SOUP_PROXY_URI_RESOLVER (proxy_resolver),
+			 status, proxy_uri, purad->user_data);
+	g_object_unref (msg);
+	if (proxy_uri)
+		soup_uri_free (proxy_uri);
+	g_slice_free (ProxyURIResolverAsyncData, purad);
+}
+
+static void
+compat_get_proxy_uri_async (SoupProxyURIResolver *proxy_uri_resolver,
+			    SoupURI *uri, GMainContext *async_context,
+			    GCancellable *cancellable,
+			    SoupProxyURIResolverCallback callback,
+			    gpointer user_data)
+{
+	SoupMessage *dummy_msg;
+	ProxyURIResolverAsyncData *purad;
+
+	dummy_msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+
+	purad = g_slice_new (ProxyURIResolverAsyncData);
+	purad->callback = callback;
+	purad->user_data = user_data;
+
+	soup_proxy_resolver_get_proxy_async (
+		SOUP_PROXY_RESOLVER (proxy_uri_resolver), dummy_msg,
+		async_context, cancellable,
+		compat_got_proxy, purad);
+}
+
+static guint
+compat_get_proxy_uri_sync (SoupProxyURIResolver *proxy_uri_resolver,
+			   SoupURI *uri, GCancellable *cancellable,
+			   SoupURI **proxy_uri)
+{
+	SoupMessage *dummy_msg;
+	SoupAddress *proxy_addr = NULL;
+	guint status;
+
+	dummy_msg = soup_message_new_from_uri (SOUP_METHOD_GET, uri);
+	status = soup_proxy_resolver_get_proxy_sync (
+		SOUP_PROXY_RESOLVER (proxy_uri_resolver), dummy_msg,
+		cancellable, &proxy_addr);
+	g_object_unref (dummy_msg);
+	if (!proxy_addr)
+		return status;
+
+	*proxy_uri = uri_from_address (proxy_addr);
+	g_object_unref (proxy_addr);
+	return status;
+}
+
+static void
+soup_proxy_resolver_uri_resolver_interface_init (SoupProxyURIResolverInterface *uri_resolver_interface)
+{
+	uri_resolver_interface->get_proxy_uri_async = compat_get_proxy_uri_async;
+	uri_resolver_interface->get_proxy_uri_sync = compat_get_proxy_uri_sync;
+}
diff --git a/libsoup/soup-proxy-resolver.h b/libsoup/soup-proxy-resolver.h
index f91f3e1..161ae76 100644
--- a/libsoup/soup-proxy-resolver.h
+++ b/libsoup/soup-proxy-resolver.h
@@ -11,6 +11,8 @@
 
 G_BEGIN_DECLS
 
+#ifndef LIBSOUP_DISABLE_DEPRECATED
+
 #define SOUP_TYPE_PROXY_RESOLVER            (soup_proxy_resolver_get_type ())
 #define SOUP_PROXY_RESOLVER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PROXY_RESOLVER, SoupProxyResolver))
 #define SOUP_PROXY_RESOLVER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PROXY_RESOLVER, SoupProxyResolverInterface))
@@ -48,6 +50,8 @@ guint soup_proxy_resolver_get_proxy_sync  (SoupProxyResolver  *proxy_resolver,
 					   GCancellable       *cancellable,
 					   SoupAddress       **addr);
 
+#endif
+
 G_END_DECLS
 
 #endif /*SOUP_PROXY_RESOLVER_H*/
diff --git a/libsoup/soup-proxy-uri-resolver.c b/libsoup/soup-proxy-uri-resolver.c
new file mode 100644
index 0000000..bb86f18
--- /dev/null
+++ b/libsoup/soup-proxy-uri-resolver.c
@@ -0,0 +1,97 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-proxy-uri-resolver.c: HTTP proxy resolver interface, take 2
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "soup-proxy-uri-resolver.h"
+#include "soup-session-feature.h"
+
+GType
+soup_proxy_uri_resolver_get_type (void)
+{
+  static volatile gsize g_define_type_id__volatile = 0;
+  if (g_once_init_enter (&g_define_type_id__volatile))
+    {
+      GType g_define_type_id =
+        g_type_register_static_simple (G_TYPE_INTERFACE,
+                                       g_intern_static_string ("SoupProxyURIResolver"),
+                                       sizeof (SoupProxyURIResolverInterface),
+                                       (GClassInitFunc)NULL,
+                                       0,
+                                       (GInstanceInitFunc)NULL,
+                                       (GTypeFlags) 0);
+      g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
+      g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+    }
+  return g_define_type_id__volatile;
+}
+
+/**
+ * SoupProxyURIResolverCallback:
+ * @resolver: the #SoupProxyURIResolver
+ * @status: a #SoupKnownStatusCode
+ * @proxy_uri: the resolved proxy URI, or %NULL
+ * @user_data: data passed to soup_proxy_uri_resolver_get_proxy_uri_async()
+ *
+ * Callback for soup_proxy_uri_resolver_get_proxy_uri_async()
+ **/
+
+/**
+ * soup_proxy_uri_resolver_get_proxy_uri_async:
+ * @proxy_uri_resolver: the #SoupProxyURIResolver
+ * @uri: the #SoupURI you want a proxy for
+ * @async_context: the #GMainContext to invoke @callback in
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: callback to invoke with the proxy address
+ * @user_data: data for @callback
+ *
+ * Asynchronously determines a proxy URI to use for @msg and calls
+ * @callback.
+ *
+ * Since: 2.26.3
+ **/
+void
+soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
+					     SoupURI               *uri,
+					     GMainContext          *async_context,
+					     GCancellable          *cancellable,
+					     SoupProxyURIResolverCallback callback,
+					     gpointer               user_data)
+{
+	SOUP_PROXY_URI_RESOLVER_GET_CLASS (proxy_uri_resolver)->
+		get_proxy_uri_async (proxy_uri_resolver, uri,
+				     async_context, cancellable,
+				     callback, user_data);
+}
+
+/**
+ * soup_proxy_uri_resolver_get_proxy_uri_sync:
+ * @proxy_uri_resolver: the #SoupProxyURIResolver
+ * @uri: the #SoupURI you want a proxy for
+ * @cancellable: a #GCancellable, or %NULL
+ * @proxy_uri: on return, will contain the proxy URI
+ *
+ * Synchronously determines a proxy URI to use for @uri. If @uri
+ * should be sent via proxy, * proxy_uri will be set to the URI of the
+ * proxy, else it will be set to %NULL.
+ *
+ * Return value: %SOUP_STATUS_OK if successful, or a transport-level
+ * error.
+ *
+ * Since: 2.26.3
+ **/
+guint
+soup_proxy_uri_resolver_get_proxy_uri_sync (SoupProxyURIResolver  *proxy_uri_resolver,
+					    SoupURI               *uri,
+					    GCancellable          *cancellable,
+					    SoupURI              **proxy_uri)
+{
+	return SOUP_PROXY_URI_RESOLVER_GET_CLASS (proxy_uri_resolver)->
+		get_proxy_uri_sync (proxy_uri_resolver, uri, cancellable, proxy_uri);
+}
diff --git a/libsoup/soup-proxy-uri-resolver.h b/libsoup/soup-proxy-uri-resolver.h
new file mode 100644
index 0000000..97476cb
--- /dev/null
+++ b/libsoup/soup-proxy-uri-resolver.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef SOUP_PROXY_URI_RESOLVER_H
+#define SOUP_PROXY_URI_RESOLVER_H 1
+
+#include <libsoup/soup-proxy-resolver.h>
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_PROXY_URI_RESOLVER            (soup_proxy_uri_resolver_get_type ())
+#define SOUP_PROXY_URI_RESOLVER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), SOUP_TYPE_PROXY_URI_RESOLVER, SoupProxyURIResolver))
+#define SOUP_PROXY_URI_RESOLVER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_PROXY_URI_RESOLVER, SoupProxyURIResolverInterface))
+#define SOUP_IS_PROXY_URI_RESOLVER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), SOUP_TYPE_PROXY_URI_RESOLVER))
+#define SOUP_IS_PROXY_URI_RESOLVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SOUP_TYPE_PROXY_URI_RESOLVER))
+#define SOUP_PROXY_URI_RESOLVER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), SOUP_TYPE_PROXY_URI_RESOLVER, SoupProxyURIResolverInterface))
+
+typedef struct _SoupProxyURIResolver SoupProxyURIResolver;
+
+typedef void (*SoupProxyURIResolverCallback) (SoupProxyURIResolver *,
+					      guint, SoupURI *, gpointer);
+
+typedef struct {
+	GTypeInterface base;
+
+	/* virtual methods */
+	void (*get_proxy_uri_async) (SoupProxyURIResolver *, SoupURI *,
+				     GMainContext *, GCancellable *,
+				     SoupProxyURIResolverCallback, gpointer);
+	guint (*get_proxy_uri_sync) (SoupProxyURIResolver *, SoupURI *,
+				     GCancellable *, SoupURI **);
+
+	/* Padding for future expansion */
+	void (*_libsoup_reserved1) (void);
+	void (*_libsoup_reserved2) (void);
+	void (*_libsoup_reserved3) (void);
+	void (*_libsoup_reserved4) (void);
+} SoupProxyURIResolverInterface;
+
+GType soup_proxy_uri_resolver_get_type (void);
+
+void  soup_proxy_uri_resolver_get_proxy_uri_async (SoupProxyURIResolver  *proxy_uri_resolver,
+						   SoupURI               *uri,
+						   GMainContext          *async_context,
+						   GCancellable          *cancellable,
+						   SoupProxyURIResolverCallback callback,
+						   gpointer                user_data);
+guint soup_proxy_uri_resolver_get_proxy_uri_sync  (SoupProxyURIResolver  *proxy_uri_resolver,
+						   SoupURI               *uri,
+						   GCancellable          *cancellable,
+						   SoupURI              **proxy_uri);
+
+G_END_DECLS
+
+#endif /*SOUP_PROXY_URI_RESOLVER_H*/
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 29422a9..f505710 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -15,6 +15,8 @@
 #include "soup-address.h"
 #include "soup-message-private.h"
 #include "soup-misc.h"
+#include "soup-proxy-uri-resolver.h"
+#include "soup-uri.h"
 
 /**
  * SECTION:soup-session-async
@@ -108,30 +110,69 @@ soup_session_async_new_with_options (const char *optname1, ...)
 	return session;
 }
 
+static gboolean
+item_failed (SoupMessageQueueItem *item, guint status)
+{
+	if (item->removed) {
+		soup_message_queue_item_unref (item);
+		return TRUE;
+	}
+
+	if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+		if (status != SOUP_STATUS_CANCELLED)
+			soup_session_cancel_message (item->session, item->msg, status);
+		soup_message_queue_item_unref (item);
+		return TRUE;
+	}
+
+	return FALSE;
+}
 
 static void
-resolved_proxy_addr (SoupProxyResolver *proxy_resolver, SoupMessage *msg,
-		     guint status, SoupAddress *proxy_addr, gpointer user_data)
+resolved_proxy_addr (SoupAddress *addr, guint status, gpointer user_data)
 {
 	SoupMessageQueueItem *item = user_data;
 	SoupSession *session = item->session;
 
-	if (item->removed) {
-		/* Message was cancelled before its proxy addr resolved */
-		soup_message_queue_item_unref (item);
+	if (item_failed (item, status))
 		return;
-	}
 
-	if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
-		soup_session_cancel_message (session, item->msg, status);
-		soup_message_queue_item_unref (item);
+	item->proxy_addr = g_object_ref (addr);
+	item->resolving_proxy_addr = FALSE;
+	item->resolved_proxy_addr = TRUE;
+
+	soup_message_queue_item_unref (item);
+
+	/* If we got here we know session still exists */
+	run_queue ((SoupSessionAsync *)session);
+}
+
+static void
+resolved_proxy_uri (SoupProxyURIResolver *proxy_resolver,
+		    guint status, SoupURI *proxy_uri, gpointer user_data)
+{
+	SoupMessageQueueItem *item = user_data;
+	SoupSession *session = item->session;
+
+	if (item_failed (item, status))
+		return;
+
+	if (proxy_uri) {
+		SoupAddress *proxy_addr;
+
+		item->proxy_uri = soup_uri_copy (proxy_uri);
+		proxy_addr = soup_address_new (proxy_uri->host,
+					       proxy_uri->port);
+		soup_address_resolve_async (proxy_addr,
+					    soup_session_get_async_context (session),
+					    item->cancellable,
+					    resolved_proxy_addr, item);
+		g_object_unref (proxy_addr);
 		return;
 	}
 
 	item->resolving_proxy_addr = FALSE;
 	item->resolved_proxy_addr = TRUE;
-	item->proxy_addr = proxy_addr ? g_object_ref (proxy_addr) : NULL;
-
 	soup_message_queue_item_unref (item);
 
 	/* If we got here we know session still exists */
@@ -140,17 +181,17 @@ resolved_proxy_addr (SoupProxyResolver *proxy_resolver, SoupMessage *msg,
 
 static void
 resolve_proxy_addr (SoupMessageQueueItem *item,
-		    SoupProxyResolver *proxy_resolver)
+		    SoupProxyURIResolver *proxy_resolver)
 {
 	if (item->resolving_proxy_addr)
 		return;
 	item->resolving_proxy_addr = TRUE;
 
 	soup_message_queue_item_ref (item);
-	soup_proxy_resolver_get_proxy_async (proxy_resolver, item->msg,
-					     soup_session_get_async_context (item->session),
-					     item->cancellable,
-					     resolved_proxy_addr, item);
+	soup_proxy_uri_resolver_get_proxy_uri_async (
+		proxy_resolver, soup_message_get_uri (item->msg),
+		soup_session_get_async_context (item->session),
+		item->cancellable, resolved_proxy_uri, item);
 }
 
 static void
@@ -255,7 +296,7 @@ run_queue (SoupSessionAsync *sa)
 	SoupSession *session = SOUP_SESSION (sa);
 	SoupMessageQueue *queue = soup_session_get_queue (session);
 	SoupMessageQueueItem *item;
-	SoupProxyResolver *proxy_resolver =
+	SoupProxyURIResolver *proxy_resolver =
 		soup_session_get_proxy_resolver (session);
 	SoupMessage *msg;
 	SoupMessageIOStatus cur_io_status = SOUP_MESSAGE_IO_STATUS_CONNECTING;
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index 324e42b..765ea06 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -9,7 +9,7 @@
 #include "soup-session.h"
 #include "soup-connection.h"
 #include "soup-message-queue.h"
-#include "soup-proxy-resolver.h"
+#include "soup-proxy-uri-resolver.h"
 
 G_BEGIN_DECLS
 
@@ -26,7 +26,7 @@ void                  soup_session_connection_failed    (SoupSession          *s
 							 SoupConnection       *conn,
 							 guint                 status);
 
-SoupProxyResolver    *soup_session_get_proxy_resolver   (SoupSession          *session);
+SoupProxyURIResolver *soup_session_get_proxy_resolver   (SoupSession          *session);
 
 void                  soup_session_send_queue_item      (SoupSession          *session,
 							 SoupMessageQueueItem *item,
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index d084b00..8c2e56b 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -14,7 +14,9 @@
 #include "soup-session-private.h"
 #include "soup-address.h"
 #include "soup-message-private.h"
+#include "soup-proxy-uri-resolver.h"
 #include "soup-misc.h"
+#include "soup-uri.h"
 
 /**
  * SECTION:soup-session-sync
@@ -162,19 +164,34 @@ wait_for_connection (SoupMessageQueueItem *item)
 	SoupMessage *msg = item->msg;
 	SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
 	gboolean try_pruning = FALSE;
-	SoupProxyResolver *proxy_resolver;
+	SoupProxyURIResolver *proxy_resolver;
 	SoupAddress *tunnel_addr;
 	SoupConnection *conn;
 	guint status;
 
 	proxy_resolver = soup_session_get_proxy_resolver (session);
 	if (proxy_resolver && !item->resolved_proxy_addr) {
-		status = soup_proxy_resolver_get_proxy_sync (
-			proxy_resolver, msg, NULL, &item->proxy_addr);
+		status = soup_proxy_uri_resolver_get_proxy_uri_sync (
+			proxy_resolver, soup_message_get_uri (msg),
+			item->cancellable, &item->proxy_uri);
 		if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
-			soup_session_cancel_message (session, msg, status);
+			if (status != SOUP_STATUS_CANCELLED)
+				soup_session_cancel_message (session, msg, status);
 			return NULL;
 		}
+
+		if (item->proxy_uri) {
+			item->proxy_addr = soup_address_new (
+				item->proxy_uri->host, item->proxy_uri->port);
+			status = soup_address_resolve_sync (item->proxy_addr,
+							    item->cancellable);
+			if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+				if (status != SOUP_STATUS_CANCELLED)
+					soup_session_cancel_message (session, msg, status);
+				return NULL;
+			}
+		}
+
 		item->resolved_proxy_addr = TRUE;
 	}
 
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 14f10e9..b9b74f7 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -24,6 +24,7 @@
 #include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-proxy-resolver-static.h"
+#include "soup-proxy-uri-resolver.h"
 #include "soup-session.h"
 #include "soup-session-feature.h"
 #include "soup-session-private.h"
@@ -66,7 +67,7 @@ typedef struct {
 } SoupSessionHost;
 
 typedef struct {
-	SoupProxyResolver *proxy_resolver;
+	SoupProxyURIResolver *proxy_resolver;
 
 	char *ssl_ca_file;
 	SoupSSLCredentials *ssl_creds;
@@ -623,7 +624,7 @@ set_property (GObject *object, guint prop_id,
 
 		if (uri) {
 			soup_session_remove_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER);
-			priv->proxy_resolver = soup_proxy_resolver_static_new (uri);
+			priv->proxy_resolver = SOUP_PROXY_URI_RESOLVER (soup_proxy_resolver_static_new (uri));
 			soup_session_add_feature (session, SOUP_SESSION_FEATURE (priv->proxy_resolver));
 			g_object_unref (priv->proxy_resolver);
 		} else if (priv->proxy_resolver && SOUP_IS_PROXY_RESOLVER_STATIC (priv->proxy_resolver))
@@ -1021,6 +1022,23 @@ soup_session_connection_failed (SoupSession *session,
 	g_object_unref (session);
 }
 
+static void
+tunnel_connected (SoupSession *session, SoupMessage *msg, gpointer user_data)
+{
+	if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+		SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+		SoupMessageQueueItem *item =
+			soup_message_queue_lookup (priv->queue, msg);
+
+		/* Clear the connection's proxy_uri, since it is now
+		 * (effectively) directly connected.
+		 */
+		g_object_set (item->conn,
+			      SOUP_CONNECTION_PROXY_URI, NULL,
+			      NULL);
+	}
+}
+
 SoupMessageQueueItem *
 soup_session_make_connect_message (SoupSession *session,
 				   SoupAddress *server_addr)
@@ -1042,7 +1060,7 @@ soup_session_make_connect_message (SoupSession *session,
 	 * directly, to add msg to the SoupMessageQueue and cause all
 	 * the right signals to be emitted.
 	 */
-	queue_message (session, msg, NULL, NULL);
+	queue_message (session, msg, tunnel_connected, NULL);
 	return soup_message_queue_lookup (priv->queue, msg);
 }
 
@@ -1092,7 +1110,7 @@ soup_session_get_connection (SoupSession *session,
 	SoupAddress *remote_addr, *tunnel_addr;
 	SoupSSLCredentials *ssl_creds;
 	GSList *conns;
-	gboolean has_pending = FALSE, is_proxy;
+	gboolean has_pending = FALSE;
 	SoupURI *uri;
 
 	g_mutex_lock (priv->host_lock);
@@ -1130,11 +1148,9 @@ soup_session_get_connection (SoupSession *session,
 	if (item->proxy_addr) {
 		remote_addr = item->proxy_addr;
 		tunnel_addr = NULL;
-		is_proxy = TRUE;
 	} else {
 		remote_addr = host->addr;
 		tunnel_addr = NULL;
-		is_proxy = FALSE;
 	}
 
 	uri = soup_message_get_uri (item->msg);
@@ -1143,17 +1159,15 @@ soup_session_get_connection (SoupSession *session,
 			priv->ssl_creds = soup_ssl_get_client_credentials (priv->ssl_ca_file);
 		ssl_creds = priv->ssl_creds;
 
-		if (is_proxy) {
-			is_proxy = FALSE;
+		if (item->proxy_addr)
 			tunnel_addr = host->addr;
-		}
 	} else
 		ssl_creds = NULL;
 
 	conn = soup_connection_new (
 		SOUP_CONNECTION_REMOTE_ADDRESS, remote_addr,
 		SOUP_CONNECTION_TUNNEL_ADDRESS, tunnel_addr,
-		SOUP_CONNECTION_IS_PROXY, is_proxy,
+		SOUP_CONNECTION_PROXY_URI, item->proxy_uri,
 		SOUP_CONNECTION_SSL_CREDENTIALS, ssl_creds,
 		SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
 		SOUP_CONNECTION_TIMEOUT, priv->io_timeout,
@@ -1482,8 +1496,8 @@ soup_session_add_feature (SoupSession *session, SoupSessionFeature *feature)
 	priv->features = g_slist_prepend (priv->features, g_object_ref (feature));
 	soup_session_feature_attach (feature, session);
 
-	if (SOUP_IS_PROXY_RESOLVER (feature))
-		priv->proxy_resolver = SOUP_PROXY_RESOLVER (feature);
+	if (SOUP_IS_PROXY_URI_RESOLVER (feature))
+		priv->proxy_resolver = SOUP_PROXY_URI_RESOLVER (feature);
 }
 
 /**
@@ -1629,7 +1643,7 @@ soup_session_get_feature (SoupSession *session, GType feature_type)
 	return NULL;
 }
 
-SoupProxyResolver *
+SoupProxyURIResolver *
 soup_session_get_proxy_resolver (SoupSession *session)
 {
 	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);



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