diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c
index d73ec82..6674f6e 100644
--- a/libsoup/soup-address.c
+++ b/libsoup/soup-address.c
@@ -61,6 +61,10 @@ typedef struct {
 
 	char *name, *physical;
 	guint port;
+	GMutex *lock;
+	/* Is async_resolution_data != NULL then an async address resolution is
+	   taking place */
+	GList *async_resolution_data;
 } SoupAddressPrivate;
 #define SOUP_ADDRESS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_ADDRESS, SoupAddressPrivate))
 
@@ -368,13 +372,19 @@ get_property (GObject *object, guint prop_id,
 SoupAddress *
 soup_address_new (const char *name, guint port)
 {
+	SoupAddressPrivate *priv;
+	SoupAddress *addr;
 	g_return_val_if_fail (name != NULL, NULL);
 	g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
 
-	return g_object_new (SOUP_TYPE_ADDRESS,
+	addr = g_object_new (SOUP_TYPE_ADDRESS,
 			     SOUP_ADDRESS_NAME, name,
 			     SOUP_ADDRESS_PORT, port,
 			     NULL);
+
+	priv = SOUP_ADDRESS_GET_PRIVATE (addr);
+	priv->lock = g_mutex_new();
+	return addr;
 }
 
 /**
@@ -390,13 +400,18 @@ soup_address_new (const char *name, guint port)
 SoupAddress *
 soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
 {
+	SoupAddressPrivate *priv;
+	SoupAddress *addr;
 	g_return_val_if_fail (sa != NULL, NULL);
 	g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (sa->sa_family), NULL);
 	g_return_val_if_fail (len == SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (sa->sa_family), NULL);
 
-	return g_object_new (SOUP_TYPE_ADDRESS,
+	addr = g_object_new (SOUP_TYPE_ADDRESS,
 			     SOUP_ADDRESS_SOCKADDR, sa,
 			     NULL);
+	priv = SOUP_ADDRESS_GET_PRIVATE (addr);
+	priv->lock = g_mutex_new();
+	return addr;
 }
 
 /**
@@ -432,13 +447,18 @@ soup_address_new_from_sockaddr (struct sockaddr *sa, int len)
 SoupAddress *
 soup_address_new_any (SoupAddressFamily family, guint port)
 {
+	SoupAddress *addr;
+	SoupAddressPrivate *priv;
 	g_return_val_if_fail (SOUP_ADDRESS_FAMILY_IS_VALID (family), NULL);
 	g_return_val_if_fail (SOUP_ADDRESS_PORT_IS_VALID (port), NULL);
 
-	return g_object_new (SOUP_TYPE_ADDRESS,
+	addr = g_object_new (SOUP_TYPE_ADDRESS,
 			     SOUP_ADDRESS_FAMILY, family,
 			     SOUP_ADDRESS_PORT, port,
 			     NULL);
+	priv = SOUP_ADDRESS_GET_PRIVATE (addr);
+	priv->lock = g_mutex_new();
+	return addr;
 }
 
 /**
@@ -627,35 +647,53 @@ complete_resolve_async (SoupAddressResolveAsyncData *res_data)
 }
 
 static void
+lookup_resolved_handle_element (gpointer element, gpointer st)
+{
+	SoupAddressResolveAsyncData *data = element;
+	guint *status = st;
+	if (status) data->status = *status;
+	complete_resolve_async(data);
+}
+
+static void
 lookup_resolved (GObject *source, GAsyncResult *result, gpointer user_data)
 {
 	GResolver *resolver = G_RESOLVER (source);
-	SoupAddressResolveAsyncData *res_data = user_data;
-	SoupAddress *addr = res_data->addr;
+	SoupAddress *addr = user_data;
 	SoupAddressPrivate *priv = SOUP_ADDRESS_GET_PRIVATE (addr);
 	GError *error = NULL;
+	GList *elements;
+	guint status;
+
+	g_return_if_fail (SOUP_IS_ADDRESS (addr));
+
+	g_mutex_lock (priv->lock);
 
 	if (!priv->sockaddr) {
 		GList *addrs;
 
 		addrs = g_resolver_lookup_by_name_finish (resolver, result,
 							  &error);
-		res_data->status = update_addrs (addr, addrs, error);
+		status = update_addrs (addr, addrs, error);
 		g_resolver_free_addresses (addrs);
 	} else if (!priv->name) {
 		char *name;
 
 		name = g_resolver_lookup_by_address_finish (resolver, result,
 							    &error);
-		res_data->status = update_name (addr, name, error);
+		status = update_name (addr, name, error);
 		g_free (name);
 	} else
-		res_data->status = SOUP_STATUS_OK;
+		status = SOUP_STATUS_OK;
 
 	if (error)
 		g_error_free (error);
 
-	complete_resolve_async (res_data);
+	elements = priv->async_resolution_data;
+	priv->async_resolution_data = NULL;
+	g_mutex_unlock(priv->lock);
+	g_list_foreach(elements, lookup_resolved_handle_element, &status);
+	g_list_free(elements);
 }
 
 static gboolean
@@ -706,42 +744,52 @@ soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
 	priv = SOUP_ADDRESS_GET_PRIVATE (addr);
 	g_return_if_fail (priv->name || priv->sockaddr);
 
+	g_mutex_lock (priv->lock);
+
 	res_data = g_slice_new0 (SoupAddressResolveAsyncData);
 	res_data->addr          = g_object_ref (addr);
 	res_data->callback      = callback;
 	res_data->callback_data = user_data;
 
 	if (priv->name && priv->sockaddr) {
+		g_mutex_unlock (priv->lock);
 		res_data->status = SOUP_STATUS_OK;
 		soup_add_completion (async_context, idle_complete_resolve, res_data);
 		return;
 	}
 
-	resolver = g_resolver_get_default ();
+	if (!priv->async_resolution_data) {
 
-	if (async_context && async_context != g_main_context_default ())
-		g_main_context_push_thread_default (async_context);
+		resolver = g_resolver_get_default ();
 
-	if (priv->name) {
-		res_data->lookup_name = TRUE;
-		g_resolver_lookup_by_name_async (resolver, priv->name,
-						 cancellable,
-						 lookup_resolved, res_data);
-	} else {
-		GInetAddress *gia;
+		if (async_context && async_context != g_main_context_default ())
+			g_main_context_push_thread_default (async_context);
 
-		res_data->lookup_name = FALSE;
-		gia = soup_address_make_inet_address (addr);
-		g_resolver_lookup_by_address_async (resolver, gia,
-						    cancellable,
-						    lookup_resolved, res_data);
-		g_object_unref (gia);
-	}
+		if (priv->name) {
+			res_data->lookup_name = TRUE;
+			g_resolver_lookup_by_name_async (resolver, priv->name,
+							 cancellable,
+							 lookup_resolved, addr);
+		} else {
+			GInetAddress *gia;
 
-	if (async_context && async_context != g_main_context_default ())
-		g_main_context_pop_thread_default (async_context);
+			res_data->lookup_name = FALSE;
+			gia = soup_address_make_inet_address (addr);
+			g_resolver_lookup_by_address_async (resolver, gia,
+							    cancellable,
+							    lookup_resolved, addr);
+			g_object_unref (gia);
+		}
 
-	g_object_unref (resolver);
+		if (async_context && async_context != g_main_context_default ())
+			g_main_context_pop_thread_default (async_context);
+
+		g_object_unref (resolver);
+	}
+	priv->async_resolution_data = g_list_append (priv->async_resolution_data,
+							    res_data);
+	g_mutex_unlock (priv->lock);
+	return;
 }
 
 /**
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index 731138c..ee9549a 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -40,6 +40,8 @@ static guint send_message    (SoupSession *session, SoupMessage *req);
 static void  auth_required   (SoupSession *session, SoupMessage *msg,
 			      SoupAuth *auth, gboolean retrying);
 
+static void  prepare_for_uri (SoupSession *session, SoupURI *uri);
+
 G_DEFINE_TYPE (SoupSessionAsync, soup_session_async, SOUP_TYPE_SESSION)
 
 typedef struct {
@@ -76,6 +78,7 @@ soup_session_async_class_init (SoupSessionAsyncClass *soup_session_async_class)
 	session_class->queue_message = queue_message;
 	session_class->send_message = send_message;
 	session_class->auth_required = auth_required;
+	session_class->prepare_for_uri = prepare_for_uri;
 
 	object_class->finalize = finalize;
 }
@@ -210,6 +213,20 @@ connection_closed (SoupConnection *conn, gpointer session)
 	do_idle_run_queue (session);
 }
 
+static void
+prepare_for_uri (SoupSession *session, SoupURI *uri)
+{
+	/*if (soup_session_get_proxy_uri(session))
+		return;*/
+
+	SoupAddress *address;
+
+	address = soup_session_get_address_for_uri(session, uri);
+	if (!soup_address_get_sockaddr (address, NULL)) {
+		soup_address_resolve_async (address, NULL, NULL, NULL, NULL);
+	}
+}
+
 typedef struct {
 	SoupSession *session;
 	SoupConnection *conn;
diff --git a/libsoup/soup-session-private.h b/libsoup/soup-session-private.h
index 72b79c5..1cd5c46 100644
--- a/libsoup/soup-session-private.h
+++ b/libsoup/soup-session-private.h
@@ -10,6 +10,7 @@
 #include "soup-connection.h"
 #include "soup-message-queue.h"
 #include "soup-proxy-uri-resolver.h"
+#include "soup-address.h"
 
 G_BEGIN_DECLS
 
@@ -27,6 +28,9 @@ void                  soup_session_connection_failed    (SoupSession          *s
 							 SoupConnection       *conn,
 							 guint                 status);
 
+SoupAddress          *soup_session_get_address_for_uri (SoupSession *session,
+							 SoupURI *uri);
+
 void                  soup_session_send_queue_item      (SoupSession          *session,
 							 SoupMessageQueueItem *item,
 							 SoupConnection       *conn);
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index eba77e4..b7b3849 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -60,6 +60,8 @@ static void  cancel_message (SoupSession *session, SoupMessage *msg,
 static void  auth_required  (SoupSession *session, SoupMessage *msg,
 			     SoupAuth *auth, gboolean retrying);
 
+static void  prepare_for_uri (SoupSession *session, SoupURI *uri);
+
 G_DEFINE_TYPE (SoupSessionSync, soup_session_sync, SOUP_TYPE_SESSION)
 
 static void
@@ -95,6 +97,7 @@ soup_session_sync_class_init (SoupSessionSyncClass *session_sync_class)
 	session_class->send_message = send_message;
 	session_class->cancel_message = cancel_message;
 	session_class->auth_required = auth_required;
+	session_class->prepare_for_uri = prepare_for_uri;
 	object_class->finalize = finalize;
 }
 
@@ -351,3 +354,9 @@ auth_required (SoupSession *session, SoupMessage *msg,
 	SOUP_SESSION_CLASS (soup_session_sync_parent_class)->
 		auth_required (session, msg, auth, retrying);
 }
+
+static void
+prepare_for_uri (SoupSession *session, SoupURI *uri)
+{
+	/* Not implemented */
+}
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 783fbfb..9dcf27f 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -932,6 +932,31 @@ redirect_handler (SoupMessage *msg, gpointer user_data)
 	soup_session_requeue_message (session, msg);
 }
 
+/*
+* Gets the address associated with the host of a uri.
+* The function may create the address if the host does not have any associated.
+* This function may be called from one SoupSession subclass.
+*/
+SoupAddress *
+soup_session_get_address_for_uri (SoupSession *session,
+			      SoupURI *uri)
+{
+	SoupSessionHost *host;
+	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+
+	g_mutex_lock (priv->host_lock);
+	host = g_hash_table_lookup (priv->hosts, uri);
+	if (host) {
+		g_mutex_unlock (priv->host_lock);
+		return host->addr;
+	}
+
+	host = soup_session_host_new (session, uri);
+	g_hash_table_insert (priv->hosts, host->uri, host);
+	g_mutex_unlock (priv->host_lock);
+	return host->addr;
+}
+
 void
 soup_session_send_queue_item (SoupSession *session,
 			      SoupMessageQueueItem *item,
@@ -1351,7 +1376,6 @@ soup_session_send_message (SoupSession *session, SoupMessage *msg)
 	return SOUP_SESSION_GET_CLASS (session)->send_message (session, msg);
 }
 
-
 /**
  * soup_session_pause_message:
  * @session: a #SoupSession
@@ -1498,6 +1522,25 @@ soup_session_abort (SoupSession *session)
 }
 
 /**
+* soup_session_prepare_for_uri:
+* @session: a #SoupSession
+* @uri: a #SoupURI which may be required
+*
+* This function can be called to indicate a session that a URI may be requested
+* shortly, and so the session can try to prepare (resove domain name, obtain
+* proxy address, etc.) in order to work more quickly once the URI is really
+* requested
+*
+* Since: 2.30
+**/
+void
+soup_session_prepare_for_uri (SoupSession *session, SoupURI *uri)
+{
+	g_return_if_fail (SOUP_IS_SESSION (session));
+	return SOUP_SESSION_GET_CLASS (session)->prepare_for_uri (session, uri);
+}
+
+/**
  * soup_session_add_feature:
  * @session: a #SoupSession
  * @feature: an object that implements #SoupSessionFeature
diff --git a/libsoup/soup-session.h b/libsoup/soup-session.h
index 598ee45..c54eec4 100644
--- a/libsoup/soup-session.h
+++ b/libsoup/soup-session.h
@@ -49,9 +49,10 @@ typedef struct {
 	void  (*auth_required)   (SoupSession *session, SoupMessage *msg,
 				  SoupAuth *auth, gboolean retrying);
 
+	void  (*prepare_for_uri) (SoupSession *session, SoupURI *uri);
+
 
 	/* Padding for future expansion */
-	void (*_libsoup_reserved2) (void);
 	void (*_libsoup_reserved3) (void);
 	void (*_libsoup_reserved4) (void);
 } SoupSessionClass;
@@ -93,6 +94,8 @@ void            soup_session_cancel_message   (SoupSession           *session,
 					       guint                  status_code);
 void            soup_session_abort            (SoupSession           *session);
 
+void            soup_session_prepare_for_uri  (SoupSession           *session,
+					       SoupURI               *uri);
 
 void                soup_session_add_feature            (SoupSession        *session,
 							 SoupSessionFeature *feature);
