From 167ef0c6817658c1a089c75c462482209e207db4 Mon Sep 17 00:00:00 2001
From: Carlos Garcia Campos <cgarcia@igalia.com>
Date: Thu, 22 Jan 2026 15:26:18 +0100
Subject: [PATCH] uri-utils: do host validation when checking if a GUri is
valid
Currently we only check if the host is not NULL and not empty, but it
might contain invalid characters not allowed for a host name in a URL.
This patch replaces the SOUP_URI_IS_VALID internal macro by a function
that in addition to the existing checks, it also validates the host.
Closes #488
Conflict:Adapted libsoup2 based on libsoup3 and remove tests/uri-parsing-test.c
Reference: https://github.com/GNOME/libsoup/commit/167ef0c6817658c1a089c75c462482209e207db4
libsoup/soup-auth.c | 2 +-
libsoup/soup-message.c | 6 ++++-
libsoup/soup-uri.c | 60 ++++++++++++++++++++++++++++++++++++++++++
libsoup/soup-uri.h | 3 +++
4 files changed, 69 insertions(+), 2 deletions(-)
@@ -535,7 +535,7 @@ GSList *
soup_auth_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
{
g_return_val_if_fail (SOUP_IS_AUTH (auth), NULL);
- g_return_val_if_fail (source_uri != NULL, NULL);
+ g_return_val_if_fail (soup_uri_is_valid (source_uri), NULL);
return SOUP_AUTH_GET_CLASS (auth)->get_protection_space (auth, source_uri);
}
@@ -1044,7 +1044,7 @@ soup_message_new (const char *method, const char *uri_string)
uri = soup_uri_new (uri_string);
if (!uri)
return NULL;
- if (!uri->host) {
+ if (!soup_uri_is_valid (uri)) {
soup_uri_free (uri);
return NULL;
}
@@ -1066,6 +1066,8 @@ soup_message_new (const char *method, const char *uri_string)
SoupMessage *
soup_message_new_from_uri (const char *method, SoupURI *uri)
{
+ g_return_val_if_fail (soup_uri_is_valid (uri), NULL);
+
return g_object_new (SOUP_TYPE_MESSAGE,
SOUP_MESSAGE_METHOD, method,
SOUP_MESSAGE_URI, uri,
@@ -1676,6 +1678,8 @@ soup_message_set_uri (SoupMessage *msg, SoupURI *uri)
SoupMessagePrivate *priv;
g_return_if_fail (SOUP_IS_MESSAGE (msg));
+ g_return_if_fail (soup_uri_is_valid (uri));
+
priv = soup_message_get_instance_private (msg);
if (priv->uri)
@@ -1342,6 +1342,66 @@ soup_uri_host_equal (gconstpointer v1, gconstpointer v2)
return g_ascii_strcasecmp (one->host, two->host) == 0;
}
+static gboolean
+is_valid_character_for_host (char c)
+{
+ static const char forbidden_chars[] = { '\t', '\n', '\r', ' ', '#', '/', ':', '<', '>', '?', '@', '[', '\\', ']', '^', '|' };
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS (forbidden_chars); ++i) {
+ if (c == forbidden_chars[i])
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+is_host_valid (const char* host)
+{
+ int i;
+ gboolean is_valid;
+ char *ascii_host = NULL;
+
+ if (!host || !host[0])
+ return FALSE;
+
+ if (g_hostname_is_non_ascii (host)) {
+ ascii_host = g_hostname_to_ascii (host);
+ if (!ascii_host)
+ return FALSE;
+
+ host = ascii_host;
+ }
+
+ if ((g_ascii_isdigit (host[0]) || strchr (host, ':')) && g_hostname_is_ip_address (host)) {
+ g_free (ascii_host);
+ return TRUE;
+ }
+
+ is_valid = TRUE;
+ for (i = 0; host[i] && is_valid; i++)
+ is_valid = is_valid_character_for_host (host[i]);
+
+ g_free (ascii_host);
+
+ return is_valid;
+}
+
+gboolean
+soup_uri_is_valid (SoupURI *uri)
+{
+ if (!uri)
+ return FALSE;
+
+ if (!is_host_valid (soup_uri_get_host (uri)))
+ return FALSE;
+
+ /* FIXME: validate other URI components? */
+
+ return TRUE;
+}
+
gboolean
soup_uri_is_http (SoupURI *uri, char **aliases)
{
@@ -46,6 +46,9 @@ SOUP_VAR gpointer _SOUP_URI_SCHEME_FTP;
SOUP_VAR gpointer _SOUP_URI_SCHEME_FILE, _SOUP_URI_SCHEME_DATA, _SOUP_URI_SCHEME_RESOURCE;
SOUP_VAR gpointer _SOUP_URI_SCHEME_WS, _SOUP_URI_SCHEME_WSS;
+SOUP_AVAILABLE_IN_2_4
+gboolean soup_uri_is_valid (SoupURI *uri);
+
SOUP_AVAILABLE_IN_2_4
SoupURI *soup_uri_new_with_base (SoupURI *base,
const char *uri_string);
--
2.33.0