[libsoup] Reorganize proxy resolution, and support SOCKS and other proxy types



commit a4910d0ca8f5034d75e35dd69059332f01a64ac0
Author: Dan Winship <danw gnome org>
Date:   Wed Nov 30 19:16:36 2011 +0100

    Reorganize proxy resolution, and support SOCKS and other proxy types
    
    Push the proxy resolution code from SoupSession down into
    SoupConnection and SoupSocket. If using a SoupProxyResolverDefault,
    just enable proxy support on the GSocketClient instead (after adding
    "http" as an application protocol). This way we get support for SOCKS
    proxies (and any other proxies supported by GProxy types).
    
    https://bugzilla.gnome.org/show_bug.cgi?id=553269

 configure.ac                 |    3 +-
 libsoup/soup-address.c       |   50 ++++++++-
 libsoup/soup-address.h       |    1 +
 libsoup/soup-connection.c    |  259 +++++++++++++++++++++++++-----------------
 libsoup/soup-connection.h    |   11 +-
 libsoup/soup-message-queue.h |    4 -
 libsoup/soup-misc-private.h  |    4 +
 libsoup/soup-session-async.c |   99 +----------------
 libsoup/soup-session-sync.c  |   36 +------
 libsoup/soup-session.c       |   38 ++-----
 libsoup/soup-socket.c        |   44 +++++++
 11 files changed, 276 insertions(+), 273 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9774193..51757fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,8 +72,7 @@ dnl ***********************
 dnl *** Checks for glib ***
 dnl ***********************
 
-dnl FIXME: should actually be 2.33.0, but glib hasn't bumped yet
-GLIB_REQUIRED=2.32.2
+GLIB_REQUIRED=2.33.1
 AM_PATH_GLIB_2_0($GLIB_REQUIRED,,,gobject gio)
 if test "$GLIB_LIBS" = ""; then
    AC_MSG_ERROR(GLIB $GLIB_REQUIRED or later is required to build libsoup)
diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c
index 1ac2d32..5f5040f 100644
--- a/libsoup/soup-address.c
+++ b/libsoup/soup-address.c
@@ -38,6 +38,7 @@ enum {
 	PROP_NAME,
 	PROP_FAMILY,
 	PROP_PORT,
+	PROP_PROTOCOL,
 	PROP_PHYSICAL,
 	PROP_SOCKADDR,
 
@@ -50,6 +51,7 @@ typedef struct {
 
 	char *name, *physical;
 	guint port;
+	const char *protocol;
 
 	GMutex lock;
 	GSList *async_lookups;
@@ -106,6 +108,7 @@ static void get_property (GObject *object, guint prop_id,
 
 static void soup_address_connectable_iface_init (GSocketConnectableIface *connectable_iface);
 static GSocketAddressEnumerator *soup_address_connectable_enumerate (GSocketConnectable *connectable);
+static GSocketAddressEnumerator *soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable);
 
 G_DEFINE_TYPE_WITH_CODE (SoupAddress, soup_address, G_TYPE_OBJECT,
 			 G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
@@ -192,6 +195,19 @@ soup_address_class_init (SoupAddressClass *address_class)
 				  -1, 65535, -1,
 				  G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 	/**
+	 * SOUP_ADDRESS_PROTOCOL:
+	 *
+	 * Alias for the #SoupAddress:protocol property. (The URI scheme
+	 * used with this address.)
+	 **/
+	g_object_class_install_property (
+		object_class, PROP_PROTOCOL,
+		g_param_spec_string (SOUP_ADDRESS_PROTOCOL,
+				     "Protocol",
+				     "URI scheme for this address",
+				     NULL,
+				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	/**
 	 * SOUP_ADDRESS_PHYSICAL:
 	 *
 	 * An alias for the #SoupAddress:physical property. (The
@@ -221,7 +237,8 @@ soup_address_class_init (SoupAddressClass *address_class)
 static void
 soup_address_connectable_iface_init (GSocketConnectableIface *connectable_iface)
 {
-  connectable_iface->enumerate  = soup_address_connectable_enumerate;
+  connectable_iface->enumerate       = soup_address_connectable_enumerate;
+  connectable_iface->proxy_enumerate = soup_address_connectable_proxy_enumerate;
 }
 
 static GObject *
@@ -289,6 +306,10 @@ set_property (GObject *object, guint prop_id,
 			SOUP_ADDRESS_SET_PORT (priv, htons (port));
 		break;
 
+	case PROP_PROTOCOL:
+		priv->protocol = g_intern_string (g_value_get_string (value));
+		break;
+
 	case PROP_SOCKADDR:
 		sa = g_value_get_pointer (value);
 		if (!sa)
@@ -328,6 +349,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_PHYSICAL:
 		g_value_set_string (value, soup_address_get_physical (SOUP_ADDRESS (object)));
 		break;
+	case PROP_PROTOCOL:
+		g_value_set_string (value, priv->protocol);
+		break;
 	case PROP_SOCKADDR:
 		g_value_set_pointer (value, priv->sockaddr);
 		break;
@@ -1197,3 +1221,27 @@ soup_address_connectable_enumerate (GSocketConnectable *connectable)
 
 	return (GSocketAddressEnumerator *)addr_enum;
 }
+
+static GSocketAddressEnumerator *
+soup_address_connectable_proxy_enumerate (GSocketConnectable *connectable)
+{
+	SoupAddress *addr = SOUP_ADDRESS (connectable);
+	SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
+	GSocketAddressEnumerator *proxy_enum;
+	char *uri;
+
+	/* We cheerily assume "http" here because you shouldn't be
+	 * using SoupAddress any more if you're not doing HTTP anyway.
+	 */
+	uri = g_strdup_printf ("%s://%s:%u",
+			       priv->protocol ? priv->protocol : "http",
+			       priv->name ? priv->name : soup_address_get_physical (addr),
+			       priv->port);
+	proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR,
+				   "connectable", connectable,
+				   "uri", uri,
+				   NULL);
+	g_free (uri);
+
+	return proxy_enum;
+}
diff --git a/libsoup/soup-address.h b/libsoup/soup-address.h
index 3cea001..579d1d3 100644
--- a/libsoup/soup-address.h
+++ b/libsoup/soup-address.h
@@ -38,6 +38,7 @@ typedef struct {
 #define SOUP_ADDRESS_NAME     "name"
 #define SOUP_ADDRESS_FAMILY   "family"
 #define SOUP_ADDRESS_PORT     "port"
+#define SOUP_ADDRESS_PROTOCOL "protocol"
 #define SOUP_ADDRESS_PHYSICAL "physical"
 #define SOUP_ADDRESS_SOCKADDR "sockaddr"
 
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index fffa954..9b079fa 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -25,6 +25,8 @@
 #include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-misc-private.h"
+#include "soup-proxy-uri-resolver.h"
+#include "soup-proxy-resolver-default.h"
 #include "soup-socket.h"
 #include "soup-uri.h"
 #include "soup-enum-types.h"
@@ -32,10 +34,11 @@
 typedef struct {
 	SoupSocket  *socket;
 
-	SoupAddress *remote_addr, *tunnel_addr;
-	SoupURI     *proxy_uri;
+	SoupURI *remote_uri, *proxy_uri;
+	SoupProxyURIResolver *proxy_resolver;
+	gboolean use_gproxyresolver;
 	GTlsDatabase *tlsdb;
-	gboolean     ssl, ssl_strict, ssl_fallback;
+	gboolean ssl, ssl_strict, ssl_fallback;
 
 	GMainContext *async_context;
 	gboolean      use_thread_context;
@@ -61,9 +64,8 @@ static guint signals[LAST_SIGNAL] = { 0 };
 enum {
 	PROP_0,
 
-	PROP_REMOTE_ADDRESS,
-	PROP_TUNNEL_ADDRESS,
-	PROP_PROXY_URI,
+	PROP_REMOTE_URI,
+	PROP_PROXY_RESOLVER,
 	PROP_SSL,
 	PROP_SSL_CREDS,
 	PROP_SSL_STRICT,
@@ -94,7 +96,6 @@ static void clear_current_item (SoupConnection *conn);
 static void
 soup_connection_init (SoupConnection *conn)
 {
-	;
 }
 
 static void
@@ -102,14 +103,15 @@ finalize (GObject *object)
 {
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
 
-	if (priv->remote_addr)
-		g_object_unref (priv->remote_addr);
-	if (priv->tunnel_addr)
-		g_object_unref (priv->tunnel_addr);
+	if (priv->remote_uri)
+		soup_uri_free (priv->remote_uri);
 	if (priv->proxy_uri)
 		soup_uri_free (priv->proxy_uri);
 	if (priv->tlsdb)
 		g_object_unref (priv->tlsdb);
+	if (priv->proxy_resolver)
+		g_object_unref (priv->proxy_resolver);
+
 	if (priv->async_context)
 		g_main_context_unref (priv->async_context);
 
@@ -173,26 +175,19 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 
 	/* properties */
 	g_object_class_install_property (
-		object_class, PROP_REMOTE_ADDRESS,
-		g_param_spec_object (SOUP_CONNECTION_REMOTE_ADDRESS,
-				     "Remote address",
-				     "The address of the HTTP or proxy server",
-				     SOUP_TYPE_ADDRESS,
-				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-	g_object_class_install_property (
-		object_class, PROP_TUNNEL_ADDRESS,
-		g_param_spec_object (SOUP_CONNECTION_TUNNEL_ADDRESS,
-				     "Tunnel address",
-				     "The address of the HTTPS server this tunnel connects to",
-				     SOUP_TYPE_ADDRESS,
-				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-	g_object_class_install_property (
-		object_class, PROP_PROXY_URI,
-		g_param_spec_boxed (SOUP_CONNECTION_PROXY_URI,
-				    "Proxy URI",
-				    "URI of the HTTP proxy this connection connects to",
+		object_class, PROP_REMOTE_URI,
+		g_param_spec_boxed (SOUP_CONNECTION_REMOTE_URI,
+				    "Remote URI",
+				    "The URI of the HTTP server",
 				    SOUP_TYPE_URI,
-				    G_PARAM_READWRITE));
+				    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (
+		object_class, PROP_PROXY_RESOLVER,
+		g_param_spec_object (SOUP_CONNECTION_PROXY_RESOLVER,
+				     "Proxy resolver",
+				     "SoupProxyURIResolver to use",
+				     SOUP_TYPE_PROXY_URI_RESOLVER,
+				     G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
 	g_object_class_install_property (
 		object_class, PROP_SSL,
 		g_param_spec_boolean (SOUP_CONNECTION_SSL,
@@ -264,38 +259,23 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 				     G_PARAM_READABLE));
 }
 
-
-SoupConnection *
-soup_connection_new (const char *propname1, ...)
-{
-	SoupConnection *conn;
-	va_list ap;
-
-	va_start (ap, propname1);
-	conn = (SoupConnection *)g_object_new_valist (SOUP_TYPE_CONNECTION,
-						      propname1, ap);
-	va_end (ap);
-
-	return conn;
-}
-
 static void
 set_property (GObject *object, guint prop_id,
 	      const GValue *value, GParamSpec *pspec)
 {
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
+	SoupProxyURIResolver *proxy_resolver;
 
 	switch (prop_id) {
-	case PROP_REMOTE_ADDRESS:
-		priv->remote_addr = g_value_dup_object (value);
-		break;
-	case PROP_TUNNEL_ADDRESS:
-		priv->tunnel_addr = g_value_dup_object (value);
+	case PROP_REMOTE_URI:
+		priv->remote_uri = g_value_dup_boxed (value);
 		break;
-	case PROP_PROXY_URI:
-		if (priv->proxy_uri)
-			soup_uri_free (priv->proxy_uri);
-		priv->proxy_uri = g_value_dup_boxed (value);
+	case PROP_PROXY_RESOLVER:
+		proxy_resolver = g_value_get_object (value);
+		if (proxy_resolver && SOUP_IS_PROXY_RESOLVER_DEFAULT (proxy_resolver))
+			priv->use_gproxyresolver = TRUE;
+		else if (proxy_resolver)
+			priv->proxy_resolver = g_object_ref (proxy_resolver);
 		break;
 	case PROP_SSL:
 		priv->ssl = g_value_get_boolean (value);
@@ -341,14 +321,8 @@ get_property (GObject *object, guint prop_id,
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (object);
 
 	switch (prop_id) {
-	case PROP_REMOTE_ADDRESS:
-		g_value_set_object (value, priv->remote_addr);
-		break;
-	case PROP_TUNNEL_ADDRESS:
-		g_value_set_object (value, priv->tunnel_addr);
-		break;
-	case PROP_PROXY_URI:
-		g_value_set_boxed (value, priv->proxy_uri);
+	case PROP_REMOTE_URI:
+		g_value_set_boxed (value, priv->remote_uri);
 		break;
 	case PROP_SSL:
 		g_value_set_boolean (value, priv->ssl);
@@ -531,7 +505,6 @@ typedef struct {
 	gpointer callback_data;
 	GCancellable *cancellable;
 	guint event_id;
-	gboolean tls_handshake;
 } SoupConnectionAsyncConnectData;
 
 static void
@@ -546,12 +519,12 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
 		g_signal_connect (priv->socket, "disconnected",
 				  G_CALLBACK (socket_disconnected), data->conn);
 
-		if (data->tls_handshake) {
+		if (priv->ssl && !priv->proxy_uri) {
 			soup_connection_event (data->conn,
 					       G_SOCKET_CLIENT_TLS_HANDSHAKED,
 					       NULL);
 		}
-		if (!priv->ssl || !priv->tunnel_addr) {
+		if (!priv->ssl || !priv->proxy_uri) {
 			soup_connection_event (data->conn,
 					       G_SOCKET_CLIENT_COMPLETE,
 					       NULL);
@@ -580,9 +553,17 @@ static void
 socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 {
 	SoupConnectionAsyncConnectData *data = user_data;
+	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+
+	if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+		socket_connect_finished (sock, status, data);
+		return;
+	}
 
-	if (SOUP_STATUS_IS_SUCCESSFUL (status) &&
-	    data->tls_handshake) {
+	if (priv->use_gproxyresolver)
+		priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+
+	if (priv->ssl && !priv->proxy_uri) {
 		if (soup_socket_start_ssl (sock, data->cancellable)) {
 			soup_connection_event (data->conn,
 					       G_SOCKET_CLIENT_TLS_HANDSHAKING,
@@ -598,6 +579,54 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 	socket_connect_finished (sock, status, data);
 }
 
+static void
+connect_async_to_uri (SoupConnectionAsyncConnectData *data, SoupURI *uri)
+{
+	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+	SoupAddress *remote_addr;
+
+	remote_addr = soup_address_new (uri->host, uri->port);
+	priv->socket =
+		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
+				 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
+				 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
+				 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
+				 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
+				 SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
+				 SOUP_SOCKET_USE_PROXY, priv->use_gproxyresolver,
+				 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
+				 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
+				 NULL);
+	g_object_unref (remote_addr);
+
+	data->event_id = g_signal_connect (priv->socket, "event",
+					   G_CALLBACK (proxy_socket_event),
+					   data->conn);
+
+	soup_socket_connect_async (priv->socket, data->cancellable,
+				   socket_connect_result, data);
+}
+
+static void
+proxy_resolver_result (SoupProxyURIResolver *resolver,
+		       guint status, SoupURI *proxy_uri,
+		       gpointer user_data)
+{
+	SoupConnectionAsyncConnectData *data = user_data;
+	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
+
+	if (status != SOUP_STATUS_OK) {
+		socket_connect_finished (NULL, status, data);
+		return;
+	}
+
+	if (proxy_uri) {
+		priv->proxy_uri = soup_uri_copy (proxy_uri);
+		connect_async_to_uri (data, proxy_uri);
+	} else 
+		connect_async_to_uri (data, priv->remote_uri);
+}
+
 void
 soup_connection_connect_async (SoupConnection *conn,
 			       GCancellable *cancellable,
@@ -606,6 +635,7 @@ soup_connection_connect_async (SoupConnection *conn,
 {
 	SoupConnectionAsyncConnectData *data;
 	SoupConnectionPrivate *priv;
+	GMainContext *async_context;
 
 	g_return_if_fail (SOUP_IS_CONNECTION (conn));
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -618,23 +648,23 @@ soup_connection_connect_async (SoupConnection *conn,
 	data->callback = callback;
 	data->callback_data = user_data;
 	data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
-	data->tls_handshake = (priv->ssl && !priv->tunnel_addr);
 
-	priv->socket =
-		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
-				 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
-				 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
-				 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
-				 SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
-				 SOUP_SOCKET_USE_THREAD_CONTEXT, priv->use_thread_context,
-				 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
-				 "clean-dispose", TRUE,
-				 NULL);
-	data->event_id = g_signal_connect (priv->socket, "event",
-					   G_CALLBACK (proxy_socket_event),
-					   conn);
-	soup_socket_connect_async (priv->socket, cancellable,
-				   socket_connect_result, data);
+	if (!priv->proxy_resolver) {
+		connect_async_to_uri (data, priv->remote_uri);
+		return;
+	}
+
+	if (priv->use_thread_context)
+		async_context = g_main_context_get_thread_default ();
+	else
+		async_context = priv->async_context;
+
+	soup_proxy_uri_resolver_get_proxy_uri_async (priv->proxy_resolver,
+						     priv->remote_uri,
+						     async_context,
+						     cancellable,
+						     proxy_resolver_result,
+						     data);
 }
 
 guint
@@ -642,6 +672,8 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 {
 	SoupConnectionPrivate *priv;
 	guint status, event_id;
+	SoupURI *connect_uri;
+	SoupAddress *remote_addr;
 
 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -649,15 +681,33 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 
 	soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
+	if (priv->proxy_resolver) {
+		status = soup_proxy_uri_resolver_get_proxy_uri_sync (priv->proxy_resolver,
+								     priv->remote_uri,
+								     cancellable,
+								     &priv->proxy_uri);
+		if (status != SOUP_STATUS_OK)
+			goto fail;
+
+		if (priv->proxy_uri)
+			connect_uri = priv->proxy_uri;
+		else
+			connect_uri = priv->remote_uri;
+	} else
+		connect_uri = priv->remote_uri;
+
+	remote_addr = soup_address_new (connect_uri->host, connect_uri->port);
 	priv->socket =
-		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
+		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, remote_addr,
+				 SOUP_SOCKET_USE_PROXY, priv->use_gproxyresolver,
 				 SOUP_SOCKET_SSL_CREDENTIALS, priv->tlsdb,
 				 SOUP_SOCKET_SSL_STRICT, priv->ssl_strict,
 				 SOUP_SOCKET_SSL_FALLBACK, priv->ssl_fallback,
 				 SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
 				 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
-				 "clean-dispose", TRUE,
+				 SOUP_SOCKET_CLEAN_DISPOSE, TRUE,
 				 NULL);
+	g_object_unref (remote_addr);
 
 	event_id = g_signal_connect (priv->socket, "event",
 				     G_CALLBACK (proxy_socket_event), conn);
@@ -665,8 +715,11 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 
 	if (!SOUP_STATUS_IS_SUCCESSFUL (status))
 		goto fail;
-		
-	if (priv->ssl && !priv->tunnel_addr) {
+
+	if (priv->use_gproxyresolver)
+		priv->proxy_uri = soup_socket_get_http_proxy_uri (priv->socket);
+
+	if (priv->ssl && !priv->proxy_uri) {
 		if (!soup_socket_start_ssl (priv->socket, cancellable))
 			status = SOUP_STATUS_SSL_FAILED;
 		else {
@@ -689,7 +742,7 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 		g_signal_connect (priv->socket, "disconnected",
 				  G_CALLBACK (socket_disconnected), conn);
 
-		if (!priv->ssl || !priv->tunnel_addr) {
+		if (!priv->ssl || !priv->proxy_uri) {
 			soup_connection_event (conn,
 					       G_SOCKET_CLIENT_COMPLETE,
 					       NULL);
@@ -714,15 +767,15 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 	return status;
 }
 
-SoupAddress *
-soup_connection_get_tunnel_addr (SoupConnection *conn)
+gboolean
+soup_connection_is_tunnelled (SoupConnection *conn)
 {
 	SoupConnectionPrivate *priv;
 
-	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
-	return priv->tunnel_addr;
+	return priv->ssl && priv->proxy_uri != NULL;
 }
 
 guint
@@ -730,16 +783,13 @@ soup_connection_start_ssl_sync (SoupConnection *conn,
 				GCancellable   *cancellable)
 {
 	SoupConnectionPrivate *priv;
-	const char *server_name;
 	guint status;
 
 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), FALSE);
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
-	server_name = soup_address_get_name (priv->tunnel_addr ?
-					     priv->tunnel_addr :
-					     priv->remote_addr);
-	if (!soup_socket_start_proxy_ssl (priv->socket, server_name,
+	if (!soup_socket_start_proxy_ssl (priv->socket,
+					  priv->remote_uri->host,
 					  cancellable))
 		return SOUP_STATUS_SSL_FAILED;
 
@@ -789,7 +839,6 @@ soup_connection_start_ssl_async (SoupConnection   *conn,
 				 gpointer          user_data)
 {
 	SoupConnectionPrivate *priv;
-	const char *server_name;
 	SoupConnectionAsyncConnectData *data;
 	GMainContext *async_context;
 
@@ -806,10 +855,8 @@ soup_connection_start_ssl_async (SoupConnection   *conn,
 	else
 		async_context = priv->async_context;
 
-	server_name = soup_address_get_name (priv->tunnel_addr ?
-					     priv->tunnel_addr :
-					     priv->remote_addr);
-	if (!soup_socket_start_proxy_ssl (priv->socket, server_name,
+	if (!soup_socket_start_proxy_ssl (priv->socket,
+					  priv->remote_uri->host,
 					  cancellable)) {
 		soup_add_completion (async_context,
 				     idle_start_ssl_completed, data);
@@ -867,6 +914,14 @@ soup_connection_get_socket (SoupConnection *conn)
 }
 
 SoupURI *
+soup_connection_get_remote_uri (SoupConnection *conn)
+{
+	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
+
+	return SOUP_CONNECTION_GET_PRIVATE (conn)->remote_uri;
+}
+
+SoupURI *
 soup_connection_get_proxy_uri (SoupConnection *conn)
 {
 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h
index 72e6106..52e638f 100644
--- a/libsoup/soup-connection.h
+++ b/libsoup/soup-connection.h
@@ -39,9 +39,8 @@ typedef void  (*SoupConnectionCallback)        (SoupConnection   *conn,
 						guint             status,
 						gpointer          data);
 
-#define SOUP_CONNECTION_REMOTE_ADDRESS  "remote-address"
-#define SOUP_CONNECTION_TUNNEL_ADDRESS  "tunnel-address"
-#define SOUP_CONNECTION_PROXY_URI       "proxy-uri"
+#define SOUP_CONNECTION_REMOTE_URI      "remote-uri"
+#define SOUP_CONNECTION_PROXY_RESOLVER  "proxy-resolver"
 #define SOUP_CONNECTION_SSL             "ssl"
 #define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
 #define SOUP_CONNECTION_SSL_STRICT      "ssl-strict"
@@ -53,16 +52,12 @@ typedef void  (*SoupConnectionCallback)        (SoupConnection   *conn,
 #define SOUP_CONNECTION_STATE           "state"
 #define SOUP_CONNECTION_MESSAGE         "message"
 
-SoupConnection *soup_connection_new            (const char       *propname1,
-						...) G_GNUC_NULL_TERMINATED;
-
 void            soup_connection_connect_async  (SoupConnection   *conn,
 						GCancellable     *cancellable,
 						SoupConnectionCallback callback,
 						gpointer          user_data);
 guint           soup_connection_connect_sync   (SoupConnection   *conn,
 						GCancellable     *cancellable);
-SoupAddress    *soup_connection_get_tunnel_addr(SoupConnection   *conn);
 guint           soup_connection_start_ssl_sync   (SoupConnection   *conn,
 						  GCancellable     *cancellable);
 void            soup_connection_start_ssl_async  (SoupConnection   *conn,
@@ -73,8 +68,10 @@ void            soup_connection_start_ssl_async  (SoupConnection   *conn,
 void            soup_connection_disconnect     (SoupConnection   *conn);
 
 SoupSocket     *soup_connection_get_socket     (SoupConnection   *conn);
+SoupURI        *soup_connection_get_remote_uri (SoupConnection   *conn);
 SoupURI        *soup_connection_get_proxy_uri  (SoupConnection   *conn);
 gboolean        soup_connection_is_via_proxy   (SoupConnection   *conn);
+gboolean        soup_connection_is_tunnelled   (SoupConnection   *conn);
 
 SoupConnectionState soup_connection_get_state  (SoupConnection   *conn);
 void                soup_connection_set_state  (SoupConnection   *conn,
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index a9242a1..7e7a308 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -15,10 +15,6 @@ G_BEGIN_DECLS
 
 typedef enum {
 	SOUP_MESSAGE_STARTING,
-	SOUP_MESSAGE_RESOLVING_PROXY_URI,
-	SOUP_MESSAGE_RESOLVED_PROXY_URI,
-	SOUP_MESSAGE_RESOLVING_PROXY_ADDRESS,
-	SOUP_MESSAGE_RESOLVED_PROXY_ADDRESS,
 	SOUP_MESSAGE_AWAITING_CONNECTION,
 	SOUP_MESSAGE_GOT_CONNECTION,
 	SOUP_MESSAGE_CONNECTING,
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index 018d66a..06978e8 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -22,4 +22,8 @@ GSocket   *soup_socket_get_gsocket    (SoupSocket *sock);
 GIOStream *soup_socket_get_connection (SoupSocket *sock);
 GIOStream *soup_socket_get_iostream   (SoupSocket *sock);
 
+#define SOUP_SOCKET_CLEAN_DISPOSE "clean-dispose"
+#define SOUP_SOCKET_USE_PROXY     "use-proxy"
+SoupURI *soup_socket_get_http_proxy_uri (SoupSocket *sock);
+
 #endif /* SOUP_URI_PRIVATE_H */
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 90526dc..ea2820a 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -19,7 +19,6 @@
 #include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-password-manager.h"
-#include "soup-proxy-uri-resolver.h"
 #include "soup-uri.h"
 
 /**
@@ -131,90 +130,6 @@ 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)) {
-		item->state = SOUP_MESSAGE_FINISHING;
-		if (!item->msg->status_code)
-			soup_session_set_item_status (item->session, item, status);
-		do_idle_run_queue (item->session);
-		soup_message_queue_item_unref (item);
-		return TRUE;
-	}
-
-	return FALSE;
-}
-
-static void
-resolved_proxy_addr (SoupAddress *addr, guint status, gpointer user_data)
-{
-	SoupMessageQueueItem *item = user_data;
-	SoupSession *session = item->session;
-
-	if (item_failed (item, soup_status_proxify (status)))
-		return;
-
-	item->proxy_addr = g_object_ref (addr);
-	item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-
-	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->state = SOUP_MESSAGE_RESOLVING_PROXY_ADDRESS;
-
-		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->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-	soup_message_queue_item_unref (item);
-
-	/* If we got here we know session still exists */
-	run_queue ((SoupSessionAsync *)session);
-}
-
-static void
-resolve_proxy_addr (SoupMessageQueueItem *item,
-		    SoupProxyURIResolver *proxy_resolver)
-{
-	item->state = SOUP_MESSAGE_RESOLVING_PROXY_URI;
-
-	soup_message_queue_item_ref (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
 connection_closed (SoupConnection *conn, gpointer session)
 {
@@ -315,7 +230,6 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
 {
 	SoupMessageQueueItem *item = user_data;
 	SoupSession *session = item->session;
-	SoupAddress *tunnel_addr;
 
 	if (item->state != SOUP_MESSAGE_CONNECTING) {
 		soup_connection_disconnect (conn);
@@ -344,8 +258,7 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
 		return;
 	}
 
-	tunnel_addr = soup_connection_get_tunnel_addr (conn);
-	if (tunnel_addr) {
+	if (soup_connection_is_tunnelled (conn)) {
 		SoupMessageQueueItem *tunnel_item;
 
 		item->state = SOUP_MESSAGE_TUNNELING;
@@ -370,7 +283,6 @@ process_queue_item (SoupMessageQueueItem *item,
 		    gboolean              loop)
 {
 	SoupSession *session = item->session;
-	SoupProxyURIResolver *proxy_resolver;
 
 	if (item->async_context != soup_session_get_async_context (session))
 		return;
@@ -381,13 +293,8 @@ process_queue_item (SoupMessageQueueItem *item,
 
 		switch (item->state) {
 		case SOUP_MESSAGE_STARTING:
-			proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, item->msg);
-			if (!proxy_resolver) {
-				item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-				break;
-			}
-			resolve_proxy_addr (item, proxy_resolver);
-			return;
+			item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
+			break;
 
 		case SOUP_MESSAGE_AWAITING_CONNECTION:
 			if (!soup_session_get_connection (session, item, should_prune))
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index a09c5b4..039779a 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -19,7 +19,6 @@
 #include "soup-message-queue.h"
 #include "soup-misc.h"
 #include "soup-password-manager.h"
-#include "soup-proxy-uri-resolver.h"
 #include "soup-uri.h"
 
 /**
@@ -224,7 +223,7 @@ try_again:
 		return;
 	}
 
-	if (soup_connection_get_tunnel_addr (item->conn)) {
+	if (soup_connection_is_tunnelled (item->conn)) {
 		status = tunnel_connect (session, item);
 		if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
 			soup_connection_disconnect (item->conn);
@@ -258,9 +257,6 @@ process_queue_item (SoupMessageQueueItem *item)
 {
 	SoupSession *session = item->session;
 	SoupSessionSyncPrivate *priv = SOUP_SESSION_SYNC_GET_PRIVATE (session);
-	SoupMessage *msg = item->msg;
-	SoupProxyURIResolver *proxy_resolver;
-	guint status;
 
 	soup_message_queue_item_ref (item);
 
@@ -274,35 +270,7 @@ process_queue_item (SoupMessageQueueItem *item)
 
 		switch (item->state) {
 		case SOUP_MESSAGE_STARTING:
-			proxy_resolver = (SoupProxyURIResolver *)soup_session_get_feature_for_message (session, SOUP_TYPE_PROXY_URI_RESOLVER, msg);
-			if (!proxy_resolver) {
-				item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-				break;
-			}
-
-			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_set_item_status (session, item, status);
-				item->state = SOUP_MESSAGE_FINISHING;
-				break;
-			}
-			if (!item->proxy_uri) {
-				item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-				break;
-			}
-
-			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))
-				item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-			else {
-				soup_session_set_item_status (session, item, soup_status_proxify (status));
-				item->state = SOUP_MESSAGE_FINISHING;
-			}
+			item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
 			break;
 
 		case SOUP_MESSAGE_AWAITING_CONNECTION:
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 200a25a..be630a8 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1494,7 +1494,11 @@ soup_session_host_new (SoupSession *session, SoupURI *uri)
 			host->uri->scheme = SOUP_URI_SCHEME_HTTP;
 	}
 
-	host->addr = soup_address_new (host->uri->host, host->uri->port);
+	host->addr = g_object_new (SOUP_TYPE_ADDRESS,
+				   SOUP_ADDRESS_NAME, host->uri->host,
+				   SOUP_ADDRESS_PORT, host->uri->port,
+				   SOUP_ADDRESS_PROTOCOL, host->uri->scheme,
+				   NULL);
 	host->keep_alive_src = NULL;
 	host->session = session;
 
@@ -1885,19 +1889,13 @@ soup_session_make_connect_message (SoupSession    *session,
 				   SoupConnection *conn)
 {
 	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
-	SoupAddress *server_addr = soup_connection_get_tunnel_addr (conn);
 	SoupURI *uri;
 	SoupMessage *msg;
 	SoupMessageQueueItem *item;
 
-	uri = soup_uri_new (NULL);
-	soup_uri_set_scheme (uri, SOUP_URI_SCHEME_HTTPS);
-	soup_uri_set_host (uri, soup_address_get_name (server_addr));
-	soup_uri_set_port (uri, soup_address_get_port (server_addr));
-	soup_uri_set_path (uri, "");
+	uri = soup_connection_get_remote_uri (conn);
 	msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT, uri);
 	soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
-	soup_uri_free (uri);
 
 	/* Call the base implementation of soup_session_queue_message
 	 * directly, to add msg to the SoupMessageQueue and cause all
@@ -1921,10 +1919,8 @@ soup_session_get_connection (SoupSession *session,
 	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
 	SoupConnection *conn;
 	SoupSessionHost *host;
-	SoupAddress *remote_addr, *tunnel_addr;
 	GSList *conns;
 	int num_pending = 0;
-	SoupURI *uri;
 	gboolean need_new_connection;
 
 	if (item->conn) {
@@ -1971,23 +1967,11 @@ soup_session_get_connection (SoupSession *session,
 		return FALSE;
 	}
 
-	if (item->proxy_addr) {
-		remote_addr = item->proxy_addr;
-		tunnel_addr = NULL;
-	} else {
-		remote_addr = host->addr;
-		tunnel_addr = NULL;
-	}
-
-	uri = soup_message_get_uri (item->msg);
-	if (uri_is_https (priv, uri) && item->proxy_addr)
-		tunnel_addr = host->addr;
-
-	conn = soup_connection_new (
-		SOUP_CONNECTION_REMOTE_ADDRESS, remote_addr,
-		SOUP_CONNECTION_TUNNEL_ADDRESS, tunnel_addr,
-		SOUP_CONNECTION_PROXY_URI, item->proxy_uri,
-		SOUP_CONNECTION_SSL, uri_is_https (priv, uri),
+	conn = g_object_new (
+		SOUP_TYPE_CONNECTION,
+		SOUP_CONNECTION_REMOTE_URI, host->uri,
+		SOUP_CONNECTION_PROXY_RESOLVER, soup_session_get_feature (session, SOUP_TYPE_PROXY_URI_RESOLVER),
+		SOUP_CONNECTION_SSL, uri_is_https (priv, soup_message_get_uri (item->msg)),
 		SOUP_CONNECTION_SSL_CREDENTIALS, priv->tlsdb,
 		SOUP_CONNECTION_SSL_STRICT, (priv->tlsdb != NULL) && priv->ssl_strict,
 		SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 1658d09..feb1162 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -23,6 +23,7 @@
 #include "soup-marshal.h"
 #include "soup-misc.h"
 #include "soup-misc-private.h"
+#include "soup-uri.h"
 
 /**
  * SECTION:soup-socket
@@ -64,6 +65,7 @@ enum {
 	PROP_CLEAN_DISPOSE,
 	PROP_TLS_CERTIFICATE,
 	PROP_TLS_ERRORS,
+	PROP_USE_PROXY,
 
 	LAST_PROP
 };
@@ -83,6 +85,7 @@ typedef struct {
 	guint ssl_fallback:1;
 	guint clean_dispose:1;
 	guint use_thread_context:1;
+	guint use_proxy:1;
 	gpointer ssl_creds;
 
 	GMainContext   *async_context;
@@ -501,6 +504,14 @@ soup_socket_class_init (SoupSocketClass *socket_class)
 				    "Errors with the peer's TLS certificate",
 				    G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
 				    G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class, PROP_USE_PROXY,
+		g_param_spec_boolean (SOUP_SOCKET_USE_PROXY,
+				      "Use proxy",
+				      "Use #GProxyResolver",
+				      FALSE,
+				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 
@@ -560,6 +571,9 @@ set_property (GObject *object, guint prop_id,
 		if (priv->conn)
 			g_socket_set_timeout (priv->gsock, priv->timeout);
 		break;
+	case PROP_USE_PROXY:
+		priv->use_proxy = g_value_get_boolean (value);
+		break;
 	case PROP_CLEAN_DISPOSE:
 		priv->clean_dispose = g_value_get_boolean (value);
 		break;
@@ -618,6 +632,9 @@ get_property (GObject *object, guint prop_id,
 	case PROP_TLS_ERRORS:
 		g_value_set_flags (value, priv->tls_errors);
 		break;
+	case PROP_USE_PROXY:
+		g_value_set_boolean (value, priv->use_proxy);
+		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -768,6 +785,10 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
 	client = g_socket_client_new ();
 	g_signal_connect (client, "event",
 			  G_CALLBACK (proxy_socket_client_event), sock);
+	if (priv->use_proxy)
+		g_socket_client_add_application_proxy (client, "http");
+	else
+		g_socket_client_set_enable_proxy (client, FALSE);
 	if (priv->timeout)
 		g_socket_client_set_timeout (client, priv->timeout);
 	g_socket_client_connect_async (client,
@@ -813,6 +834,10 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
 	client = g_socket_client_new ();
 	g_signal_connect (client, "event",
 			  G_CALLBACK (proxy_socket_client_event), sock);
+	if (priv->use_proxy)
+		g_socket_client_add_application_proxy (client, "http");
+	else
+		g_socket_client_set_enable_proxy (client, FALSE);
 	if (priv->timeout)
 		g_socket_client_set_timeout (client, priv->timeout);
 	conn = g_socket_client_connect (client,
@@ -1328,6 +1353,25 @@ soup_socket_get_remote_address (SoupSocket *sock)
 	return priv->remote_addr;
 }
 
+SoupURI *
+soup_socket_get_http_proxy_uri (SoupSocket *sock)
+{
+	SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+	GSocketAddress *addr;
+	GProxyAddress *paddr;
+
+	if (!priv->gsock)
+		return NULL;
+	addr = g_socket_get_remote_address (priv->gsock, NULL);
+	if (!addr || !G_IS_PROXY_ADDRESS (addr))
+		return NULL;
+
+	paddr = G_PROXY_ADDRESS (addr);
+	if (strcmp (g_proxy_address_get_protocol (paddr), "http") != 0)
+		return NULL;
+
+	return soup_uri_new (g_proxy_address_get_uri (paddr));
+}
 
 static gboolean
 socket_read_watch (GObject *pollable, gpointer user_data)



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