[libsoup] soup-session: fix some http-aliases/https-aliases problems



commit c524540f1eb7c1d68597227ab677b47345bc54b5
Author: Dan Winship <danw gnome org>
Date:   Wed Nov 30 13:34:43 2011 +0100

    soup-session: fix some http-aliases/https-aliases problems
    
    and add a test to misc-test

 libsoup/soup-session.c |   78 ++++++++++++++++++++++++++++++-----
 libsoup/soup-uri.c     |    4 --
 tests/misc-test.c      |  106 ++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 171 insertions(+), 17 deletions(-)
---
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 94b50a2..3babab4 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -73,6 +73,8 @@ typedef struct {
 	GSource     *keep_alive_src;
 	SoupSession *session;
 } SoupSessionHost;
+static guint soup_host_uri_hash (gconstpointer key);
+gboolean soup_host_uri_equal (gconstpointer v1, gconstpointer v2);
 
 typedef struct {
 	GTlsDatabase *tlsdb;
@@ -88,7 +90,7 @@ typedef struct {
 	GSList *features;
 	GHashTable *features_cache;
 
-	GHashTable *hosts; /* char* -> SoupSessionHost */
+	GHashTable *http_hosts, *https_hosts; /* char* -> SoupSessionHost */
 	GHashTable *conns; /* SoupConnection -> SoupSessionHost */
 	guint num_conns;
 	guint max_conns, max_conns_per_host;
@@ -186,9 +188,12 @@ soup_session_init (SoupSession *session)
 	priv->queue = soup_message_queue_new (session);
 
 	g_mutex_init (&priv->host_lock);
-	priv->hosts = g_hash_table_new_full (soup_uri_host_hash,
-					     soup_uri_host_equal,
-					     NULL, (GDestroyNotify)free_host);
+	priv->http_hosts = g_hash_table_new_full (soup_host_uri_hash,
+						  soup_host_uri_equal,
+						  NULL, (GDestroyNotify)free_host);
+	priv->https_hosts = g_hash_table_new_full (soup_host_uri_hash,
+						   soup_host_uri_equal,
+						   NULL, (GDestroyNotify)free_host);
 	priv->conns = g_hash_table_new (NULL, NULL);
 
 	priv->max_conns = SOUP_SESSION_MAX_CONNS_DEFAULT;
@@ -241,7 +246,8 @@ finalize (GObject *object)
 	soup_message_queue_destroy (priv->queue);
 
 	g_mutex_clear (&priv->host_lock);
-	g_hash_table_destroy (priv->hosts);
+	g_hash_table_destroy (priv->http_hosts);
+	g_hash_table_destroy (priv->https_hosts);
 	g_hash_table_destroy (priv->conns);
 
 	g_free (priv->user_agent);
@@ -1048,12 +1054,18 @@ load_ssl_ca_file (SoupSessionPrivate *priv)
 static void
 set_aliases (char ***variable, char **value)
 {
-	int len = g_strv_length (value), i;
+	int len, i;
 
 	if (*variable)
 		g_free (*variable);
 
-	*variable = g_new (char *, len);
+	if (!value) {
+		*variable = NULL;
+		return;
+	}
+
+	len = g_strv_length (value);
+	*variable = g_new (char *, len + 1);
 	for (i = 0; i < len; i++)
 		(*variable)[i] = (char *)g_intern_string (value[i]);
 	(*variable)[i] = NULL;
@@ -1358,6 +1370,32 @@ soup_session_get_async_context (SoupSession *session)
 
 /* Hosts */
 
+static guint
+soup_host_uri_hash (gconstpointer key)
+{
+	const SoupURI *uri = key;
+
+	g_return_val_if_fail (uri != NULL && uri->host != NULL, 0);
+
+	return uri->port + soup_str_case_hash (uri->host);
+}
+
+gboolean
+soup_host_uri_equal (gconstpointer v1, gconstpointer v2)
+{
+	const SoupURI *one = v1;
+	const SoupURI *two = v2;
+
+	g_return_val_if_fail (one != NULL && two != NULL, one == two);
+	g_return_val_if_fail (one->host != NULL && two->host != NULL, one->host == two->host);
+
+	if (one->port != two->port)
+		return FALSE;
+
+	return g_ascii_strcasecmp (one->host, two->host) == 0;
+}
+
+
 static SoupSessionHost *
 soup_session_host_new (SoupSession *session, SoupURI *uri)
 {
@@ -1365,6 +1403,16 @@ soup_session_host_new (SoupSession *session, SoupURI *uri)
 
 	host = g_slice_new0 (SoupSessionHost);
 	host->uri = soup_uri_copy_host (uri);
+	if (host->uri->scheme != SOUP_URI_SCHEME_HTTP &&
+	    host->uri->scheme != SOUP_URI_SCHEME_HTTPS) {
+		SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
+
+		if (uri_is_https (priv, host->uri))
+			host->uri->scheme = SOUP_URI_SCHEME_HTTPS;
+		else
+			host->uri->scheme = SOUP_URI_SCHEME_HTTP;
+	}
+
 	host->addr = soup_address_new (host->uri->host, host->uri->port);
 	host->keep_alive_src = NULL;
 	host->session = session;
@@ -1379,12 +1427,19 @@ get_host_for_uri (SoupSession *session, SoupURI *uri)
 	SoupSessionPrivate *priv = SOUP_SESSION_GET_PRIVATE (session);
 	SoupSessionHost *host;
 
-	host = g_hash_table_lookup (priv->hosts, uri);
+	if (uri_is_https (priv, uri))
+		host = g_hash_table_lookup (priv->https_hosts, uri);
+	else
+		host = g_hash_table_lookup (priv->http_hosts, uri);
 	if (host)
 		return host;
 
 	host = soup_session_host_new (session, uri);
-	g_hash_table_insert (priv->hosts, host->uri, host);
+
+	if (uri_is_https (priv, uri))
+		g_hash_table_insert (priv->https_hosts, host->uri, host);
+	else
+		g_hash_table_insert (priv->http_hosts, host->uri, host);
 
 	return host;
 }
@@ -1684,7 +1739,10 @@ free_unused_host (gpointer user_data)
 	/* This will free the host in addition to removing it from the
 	 * hash table
 	 */
-	g_hash_table_remove (priv->hosts, host->uri);
+	if (host->uri->scheme == SOUP_URI_SCHEME_HTTPS)
+		g_hash_table_remove (priv->https_hosts, host->uri);
+	else
+		g_hash_table_remove (priv->http_hosts, host->uri);
 	g_mutex_unlock (&priv->host_lock);
 
 	return FALSE;
diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c
index 9170feb..cb7c5ce 100644
--- a/libsoup/soup-uri.c
+++ b/libsoup/soup-uri.c
@@ -742,10 +742,6 @@ soup_uri_normalize (const char *part, const char *unescape_extra)
 gboolean
 soup_uri_uses_default_port (SoupURI *uri)
 {
-	g_return_val_if_fail (uri->scheme == SOUP_URI_SCHEME_HTTP ||
-			      uri->scheme == SOUP_URI_SCHEME_HTTPS ||
-			      uri->scheme == SOUP_URI_SCHEME_FTP, FALSE);
-
 	return uri->port == soup_scheme_default_port (uri->scheme);
 }
 
diff --git a/tests/misc-test.c b/tests/misc-test.c
index b1bc2e7..332e938 100644
--- a/tests/misc-test.c
+++ b/tests/misc-test.c
@@ -18,8 +18,8 @@
 
 #include "test-utils.h"
 
-SoupServer *server;
-SoupURI *base_uri;
+SoupServer *server, *ssl_server;
+SoupURI *base_uri, *ssl_base_uri;
 GMutex server_mutex;
 
 static gboolean
@@ -117,6 +117,7 @@ server_callback (SoupServer *server, SoupMessage *msg,
 		 SoupClientContext *context, gpointer data)
 {
 	SoupURI *uri = soup_message_get_uri (msg);
+	const char *server_protocol = data;
 
 	/* The way this gets used in the tests, we don't actually
 	 * need to hold it through the whole function, so it's simpler
@@ -145,6 +146,34 @@ server_callback (SoupServer *server, SoupMessage *msg,
 		return;
 	}
 
+	if (!strcmp (path, "/alias-redirect")) {
+		SoupURI *redirect_uri;
+		char *redirect_string;
+		const char *redirect_protocol;
+
+		redirect_protocol = soup_message_headers_get_one (msg->request_headers, "X-Redirect-Protocol");
+
+		redirect_uri = soup_uri_copy (uri);
+		soup_uri_set_scheme (redirect_uri, "foo");
+		if (!g_strcmp0 (redirect_protocol, "https"))
+			soup_uri_set_port (redirect_uri, ssl_base_uri->port);
+		else
+			soup_uri_set_port (redirect_uri, base_uri->port);
+		soup_uri_set_path (redirect_uri, "/alias-redirected");
+		redirect_string = soup_uri_to_string (redirect_uri, FALSE);
+
+		soup_message_set_redirect (msg, SOUP_STATUS_FOUND, redirect_string);
+		g_free (redirect_string);
+		soup_uri_free (redirect_uri);
+		return;
+	} else if (!strcmp (path, "/alias-redirected")) {
+		soup_message_set_status (msg, SOUP_STATUS_OK);
+		soup_message_headers_append (msg->response_headers,
+					     "X-Redirected-Protocol",
+					     server_protocol);
+		return;
+	}
+
 	if (g_str_has_prefix (path, "/content-length/")) {
 		gboolean too_long = strcmp (path, "/content-length/long") == 0;
 		gboolean no_close = strcmp (path, "/content-length/noclose") == 0;
@@ -1011,6 +1040,69 @@ do_cancel_while_reading_test (void)
 	soup_test_session_abort_unref (session);
 }
 
+static void
+do_aliases_test_for_session (SoupSession *session,
+			     const char *redirect_protocol)
+{
+	SoupMessage *msg;
+	SoupURI *uri;
+	const char *redirected_protocol;
+
+	uri = soup_uri_new_with_base (base_uri, "/alias-redirect");
+	msg = soup_message_new_from_uri ("GET", uri);
+	if (redirect_protocol)
+		soup_message_headers_append (msg->request_headers, "X-Redirect-Protocol", redirect_protocol);
+	soup_uri_free (uri);
+	soup_session_send_message (session, msg);
+
+	redirected_protocol = soup_message_headers_get_one (msg->response_headers, "X-Redirected-Protocol");
+
+	if (g_strcmp0 (redirect_protocol, redirected_protocol)) {
+		debug_printf (1, "    redirect went to %s, should have gone to %s!\n",
+			      redirected_protocol ? redirected_protocol : "(none)",
+			      redirect_protocol ? redirect_protocol : "(none)");
+		errors++;
+	} else if (redirect_protocol && !SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+		debug_printf (1, "    msg failed? (%d %s)\n",
+			      msg->status_code, msg->reason_phrase);
+		errors++;
+	} else if (!redirect_protocol && SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+		debug_printf (1, "    msg succeeded? (%d %s)\n",
+			      msg->status_code, msg->reason_phrase);
+		errors++;
+	}
+
+	g_object_unref (msg);
+}
+
+static void
+do_aliases_test (void)
+{
+	SoupSession *session;
+	char *aliases[] = { "foo", NULL };
+
+	debug_printf (1, "\nhttp-aliases / https-aliases\n");
+
+	debug_printf (1, "  Default behavior\n");
+	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
+	do_aliases_test_for_session (session, "http");
+	soup_test_session_abort_unref (session);
+
+	debug_printf (1, "  foo-means-https\n");
+	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+					 SOUP_SESSION_HTTPS_ALIASES, aliases,
+					 NULL);
+	do_aliases_test_for_session (session, "https");
+	soup_test_session_abort_unref (session);
+
+	debug_printf (1, "  foo-means-nothing\n");
+	session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC,
+					 SOUP_SESSION_HTTP_ALIASES, NULL,
+					 NULL);
+	do_aliases_test_for_session (session, NULL);
+	soup_test_session_abort_unref (session);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -1019,7 +1111,7 @@ main (int argc, char **argv)
 	test_init (argc, argv, NULL);
 
 	server = soup_test_server_new (TRUE);
-	soup_server_add_handler (server, NULL, server_callback, NULL, NULL);
+	soup_server_add_handler (server, NULL, server_callback, "http", NULL);
 	base_uri = soup_uri_new ("http://127.0.0.1/";);
 	soup_uri_set_port (base_uri, soup_server_get_port (server));
 
@@ -1031,6 +1123,11 @@ main (int argc, char **argv)
 	soup_server_add_auth_domain (server, auth_domain);
 	g_object_unref (auth_domain);
 
+	ssl_server = soup_test_server_new_ssl (TRUE);
+	soup_server_add_handler (ssl_server, NULL, server_callback, "https", NULL);
+	ssl_base_uri = soup_uri_new ("https://127.0.0.1/";);
+	soup_uri_set_port (ssl_base_uri, soup_server_get_port (ssl_server));
+
 	do_host_test ();
 	do_callback_unref_test ();
 	do_msg_reuse_test ();
@@ -1041,9 +1138,12 @@ main (int argc, char **argv)
 	do_persistent_connection_timeout_test ();
 	do_max_conns_test ();
 	do_cancel_while_reading_test ();
+	do_aliases_test ();
 
 	soup_uri_free (base_uri);
+	soup_uri_free (ssl_base_uri);
 	soup_test_server_quit_unref (server);
+	soup_test_server_quit_unref (ssl_server);
 
 	test_cleanup ();
 	return errors != 0;



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