From c524540f1eb7c1d68597227ab677b47345bc54b5 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Wed, 30 Nov 2011 13:34:43 +0100 Subject: [PATCH] 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; -- 2.7.4