File libsoup-CVE-2026-1536.patch of Package libsoup

From 7481c8ffc4d3a66ed827c6ca3314b8916a641638 Mon Sep 17 00:00:00 2001
From: Jonathan Kang <jonathankang@gnome.org>
Date: Fri, 30 Jan 2026 15:02:29 +0800
Subject: [PATCH] Always validate the headers value when coming from untrusted
 source

Add trusted_value parameter to soup_message_headers_append_common() and
soup_message_headers_replace_common() and check that the value is valid
when FALSE is passed.

Closes #486
---
 libsoup/auth/soup-auth-manager.c              |   2 +-
 libsoup/auth/soup-auth-ntlm.c                 |   2 +-
 libsoup/cache/soup-cache.c                    |   4 +-
 .../content-decoder/soup-content-decoder.c    |   2 +-
 libsoup/cookies/soup-cookie-jar.c             |   2 +-
 libsoup/cookies/soup-cookie.c                 |   4 +-
 libsoup/http1/soup-client-message-io-http1.c  |   2 +-
 .../http1/soup-server-message-io-http1.c      |   4 +-
 libsoup/server/soup-auth-domain.c             |   2 +-
 libsoup/server/soup-server-message.c          |   4 +-
 libsoup/server/soup-server.c                  |   4 +-
 libsoup/soup-message-headers-private.h        |   6 +-
 libsoup/soup-message-headers.c                |  58 ++++++----
 libsoup/soup-message.c                        |   8 +-
 libsoup/soup-multipart.c                      |   4 +-
 libsoup/soup-session.c                        |   4 +-
 libsoup/websocket/soup-websocket.c            |  28 ++---
 tests/header-parsing-test.c                   | 108 ++++++++++++++----
 tests/http2-test.c                            |   4 +-
 19 files changed, 165 insertions(+), 87 deletions(-)

diff --git a/libsoup/auth/soup-auth-manager.c b/libsoup/auth/soup-auth-manager.c
index e3d35181..3cb51ac3 100644
--- a/libsoup/auth/soup-auth-manager.c
+++ b/libsoup/auth/soup-auth-manager.c
@@ -441,7 +441,7 @@ update_authorization_header (SoupMessage *msg, SoupAuth *auth, gboolean is_proxy
 	if (!token)
 		return;
 
-	soup_message_headers_replace_common (soup_message_get_request_headers (msg), authorization_header, token);
+	soup_message_headers_replace_common (soup_message_get_request_headers (msg), authorization_header, token, TRUE);
 	g_free (token);
 }
 
diff --git a/libsoup/auth/soup-auth-ntlm.c b/libsoup/auth/soup-auth-ntlm.c
index 7108a32c..b4fc1d1c 100644
--- a/libsoup/auth/soup-auth-ntlm.c
+++ b/libsoup/auth/soup-auth-ntlm.c
@@ -328,7 +328,7 @@ soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
 			conn->state = SOUP_NTLM_FAILED;
 			if (soup_message_is_keepalive (msg)) {
 				soup_message_headers_append_common (soup_message_get_response_headers (msg),
-                                                                    SOUP_HEADER_CONNECTION, "close");
+                                                                    SOUP_HEADER_CONNECTION, "close", TRUE);
 			}
 			return TRUE;
 		}
diff --git a/libsoup/cache/soup-cache.c b/libsoup/cache/soup-cache.c
index fa5fb973..f20c021a 100644
--- a/libsoup/cache/soup-cache.c
+++ b/libsoup/cache/soup-cache.c
@@ -1471,11 +1471,11 @@ soup_cache_generate_conditional_request (SoupCache *cache, SoupMessage *original
 	if (last_modified)
 		soup_message_headers_append_common (soup_message_get_request_headers (msg),
                                                     SOUP_HEADER_IF_MODIFIED_SINCE,
-                                                    last_modified);
+                                                    last_modified, TRUE);
 	if (etag)
 		soup_message_headers_append_common (soup_message_get_request_headers (msg),
                                                     SOUP_HEADER_IF_NONE_MATCH,
-                                                    etag);
+                                                    etag, TRUE);
 
 	return msg;
 }
diff --git a/libsoup/content-decoder/soup-content-decoder.c b/libsoup/content-decoder/soup-content-decoder.c
index f75ebce4..2fdad667 100644
--- a/libsoup/content-decoder/soup-content-decoder.c
+++ b/libsoup/content-decoder/soup-content-decoder.c
@@ -249,7 +249,7 @@ soup_content_decoder_request_queued (SoupSessionFeature *feature,
 #endif
 
 		soup_message_headers_append_common (soup_message_get_request_headers (msg),
-                                                    SOUP_HEADER_ACCEPT_ENCODING, header);
+                                                    SOUP_HEADER_ACCEPT_ENCODING, header, TRUE);
 	}
 }
 
diff --git a/libsoup/cookies/soup-cookie-jar.c b/libsoup/cookies/soup-cookie-jar.c
index fac53a5f..7ffa3e5a 100644
--- a/libsoup/cookies/soup-cookie-jar.c
+++ b/libsoup/cookies/soup-cookie-jar.c
@@ -899,7 +899,7 @@ msg_starting_cb (SoupMessage *msg, gpointer feature)
 							               soup_message_get_is_top_level_navigation (msg));
 	if (cookies != NULL) {
 		char *cookie_header = soup_cookies_to_cookie_header (cookies);
-		soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header);
+		soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_COOKIE, cookie_header, TRUE);
 		g_free (cookie_header);
 		g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free);
 	} else {
diff --git a/libsoup/cookies/soup-cookie.c b/libsoup/cookies/soup-cookie.c
index cc80d001..7bab6a1b 100644
--- a/libsoup/cookies/soup-cookie.c
+++ b/libsoup/cookies/soup-cookie.c
@@ -987,7 +987,7 @@ soup_cookies_to_response (GSList *cookies, SoupMessage *msg)
 	while (cookies) {
 		serialize_cookie (cookies->data, header, TRUE);
 		soup_message_headers_append_common (soup_message_get_response_headers (msg),
-                                                    SOUP_HEADER_SET_COOKIE, header->str);
+                                                    SOUP_HEADER_SET_COOKIE, header->str, TRUE);
 		g_string_truncate (header, 0);
 		cookies = cookies->next;
 	}
@@ -1018,7 +1018,7 @@ soup_cookies_to_request (GSList *cookies, SoupMessage *msg)
 		cookies = cookies->next;
 	}
 	soup_message_headers_replace_common (soup_message_get_request_headers (msg),
-                                             SOUP_HEADER_COOKIE, header->str);
+                                             SOUP_HEADER_COOKIE, header->str, TRUE);
 	g_string_free (header, TRUE);
 }
 
diff --git a/libsoup/http1/soup-client-message-io-http1.c b/libsoup/http1/soup-client-message-io-http1.c
index 65a6fecb..739e2e19 100644
--- a/libsoup/http1/soup-client-message-io-http1.c
+++ b/libsoup/http1/soup-client-message-io-http1.c
@@ -568,7 +568,7 @@ io_read (SoupClientMessageIOHTTP1 *client_io,
                          * closed when we're done.
                          */
                         soup_message_headers_append_common (soup_message_get_request_headers (msg),
-                                                            SOUP_HEADER_CONNECTION, "close");
+                                                            SOUP_HEADER_CONNECTION, "close", TRUE);
                         soup_message_set_metrics_timestamp (msg, SOUP_MESSAGE_METRICS_RESPONSE_END);
                         io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
                         break;
diff --git a/libsoup/server/http1/soup-server-message-io-http1.c b/libsoup/server/http1/soup-server-message-io-http1.c
index 8a3bce29..073913f7 100644
--- a/libsoup/server/http1/soup-server-message-io-http1.c
+++ b/libsoup/server/http1/soup-server-message-io-http1.c
@@ -305,7 +305,7 @@ handle_partial_get (SoupServerMessage *msg)
                         if (content_type) {
                                 soup_message_headers_append_common (part_headers,
                                                                     SOUP_HEADER_CONTENT_TYPE,
-                                                                    content_type);
+                                                                    content_type, TRUE);
                         }
                         soup_message_headers_set_content_range (part_headers,
                                                                 ranges[i].start,
@@ -763,7 +763,7 @@ io_read (SoupServerMessageIOHTTP1 *server_io,
                          * closed when we're done.
                          */
                         soup_server_message_set_status (msg, status, NULL);
-                        soup_message_headers_append_common (request_headers, SOUP_HEADER_CONNECTION, "close");
+                        soup_message_headers_append_common (request_headers, SOUP_HEADER_CONNECTION, "close", TRUE);
                         io->read_state = SOUP_MESSAGE_IO_STATE_FINISHING;
                         break;
                 }
diff --git a/libsoup/server/soup-auth-domain.c b/libsoup/server/soup-auth-domain.c
index c901bd2f..b4718b80 100644
--- a/libsoup/server/soup-auth-domain.c
+++ b/libsoup/server/soup-auth-domain.c
@@ -581,6 +581,6 @@ soup_auth_domain_challenge (SoupAuthDomain    *domain,
                                             priv->proxy ?
                                             SOUP_HEADER_PROXY_AUTHENTICATE :
                                             SOUP_HEADER_WWW_AUTHENTICATE,
-                                            challenge);
+                                            challenge, FALSE);
 	g_free (challenge);
 }
diff --git a/libsoup/server/soup-server-message.c b/libsoup/server/soup-server-message.c
index 7d902d51..c95f514b 100644
--- a/libsoup/server/soup-server-message.c
+++ b/libsoup/server/soup-server-message.c
@@ -939,7 +939,7 @@ soup_server_message_set_response (SoupServerMessage *msg,
 
                 soup_message_headers_replace_common (msg->response_headers,
                                                      SOUP_HEADER_CONTENT_TYPE,
-                                                     content_type);
+                                                     content_type, FALSE);
                 soup_message_body_append (msg->response_body, resp_use,
                                           resp_body, resp_length);
         } else {
@@ -980,7 +980,7 @@ soup_server_message_set_redirect (SoupServerMessage *msg,
 	soup_server_message_set_status (msg, status_code, NULL);
 	location_str = g_uri_to_string (location);
 	soup_message_headers_replace_common (msg->response_headers, SOUP_HEADER_LOCATION,
-                                             location_str);
+                                             location_str, FALSE);
 	g_free (location_str);
 	g_uri_unref (location);
 }
diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c
index 229f42d9..48c16d54 100644
--- a/libsoup/server/soup-server.c
+++ b/libsoup/server/soup-server.c
@@ -852,7 +852,7 @@ got_headers (SoupServer        *server,
 
 	date = g_date_time_new_now_utc ();
 	date_string = soup_date_time_to_string (date, SOUP_DATE_HTTP);
-	soup_message_headers_replace_common (headers, SOUP_HEADER_DATE, date_string);
+	soup_message_headers_replace_common (headers, SOUP_HEADER_DATE, date_string, TRUE);
 	g_free (date_string);
 	g_date_time_unref (date);
 
@@ -1036,7 +1036,7 @@ request_started_cb (SoupServer           *server,
 
                 headers = soup_server_message_get_response_headers (msg);
                 soup_message_headers_append_common (headers, SOUP_HEADER_SERVER,
-                                                    priv->server_header);
+                                                    priv->server_header, FALSE);
         }
 
         g_signal_emit (server, signals[REQUEST_STARTED], 0, msg);
diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h
index 98154645..86c95c0f 100644
--- a/libsoup/soup-message-headers-private.h
+++ b/libsoup/soup-message-headers-private.h
@@ -15,7 +15,8 @@ void        soup_message_headers_append_untrusted_data  (SoupMessageHeaders *hdr
                                                          const char         *value);
 void        soup_message_headers_append_common          (SoupMessageHeaders *hdrs,
                                                          SoupHeaderName      name,
-                                                         const char         *value);
+                                                         const char         *value,
+                                                         gboolean            trusted_value);
 const char *soup_message_headers_get_one_common         (SoupMessageHeaders *hdrs,
                                                          SoupHeaderName      name);
 const char *soup_message_headers_get_list_common        (SoupMessageHeaders *hdrs,
@@ -24,7 +25,8 @@ void        soup_message_headers_remove_common          (SoupMessageHeaders *hdr
                                                          SoupHeaderName      name);
 void        soup_message_headers_replace_common         (SoupMessageHeaders *hdrs,
                                                          SoupHeaderName      name,
-                                                         const char         *value);
+                                                         const char         *value,
+                                                         gboolean            trusted_value);
 gboolean    soup_message_headers_header_contains_common (SoupMessageHeaders *hdrs,
                                                          SoupHeaderName      name,
                                                          const char         *token);
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
index ee7a3cb1..f44e1307 100644
--- a/libsoup/soup-message-headers.c
+++ b/libsoup/soup-message-headers.c
@@ -273,13 +273,29 @@ soup_message_headers_clean_connection_headers (SoupMessageHeaders *hdrs)
 	soup_header_free_list (tokens);
 }
 
+static inline gboolean is_valid_header_name (const char *name)
+{
+        return name && *name && strpbrk (name, " \t\r\n:") == NULL;
+}
+
+static inline gboolean is_valid_header_value (const char *value)
+{
+        return value && strpbrk (value, "\r\n") == NULL;
+}
+
 void
 soup_message_headers_append_common (SoupMessageHeaders *hdrs,
                                     SoupHeaderName      name,
-                                    const char         *value)
+                                    const char         *value,
+                                    gboolean            trusted_value)
 {
         SoupCommonHeader header;
 
+        if (!trusted_value && !is_valid_header_value (value)) {
+                g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value);
+                return FALSE;
+        }
+
         if (!hdrs->common_headers)
                 hdrs->common_headers = g_array_sized_new (FALSE, FALSE, sizeof (SoupCommonHeader), 6);
 
@@ -318,28 +334,19 @@ soup_message_headers_append (SoupMessageHeaders *hdrs,
 	g_return_if_fail (name != NULL);
 	g_return_if_fail (value != NULL);
 
-	/* Setting a syntactically invalid header name or value is
-	 * considered to be a programming error. However, it can also
-	 * be a security hole, so we want to fail here even if
-	 * compiled with G_DISABLE_CHECKS.
-	 */
-#ifndef G_DISABLE_CHECKS
-	g_return_if_fail (*name && strpbrk (name, " \t\r\n:") == NULL);
-	g_return_if_fail (strpbrk (value, "\r\n") == NULL);
-#else
-	if (*name && strpbrk (name, " \t\r\n:")) {
+        if (!is_valid_header_name (name)) {
 		g_warning ("soup_message_headers_append: Ignoring bad name '%s'", name);
 		return;
 	}
-	if (strpbrk (value, "\r\n")) {
-		g_warning ("soup_message_headers_append: Ignoring bad value '%s'", value);
-		return;
-	}
-#endif
 
         header_name = soup_header_name_from_string (name);
         if (header_name != SOUP_HEADER_UNKNOWN) {
-                soup_message_headers_append_common (hdrs, header_name, value);
+                soup_message_headers_append_common (hdrs, header_name, value, FALSE);
+                return;
+        }
+
+        if (!is_valid_header_value (value)) {
+                g_warning ("soup_message_headers_append: Rejecting bad value '%s'", value);
                 return;
         }
 
@@ -371,10 +378,11 @@ soup_message_headers_append_untrusted_data (SoupMessageHeaders *hdrs,
 void
 soup_message_headers_replace_common (SoupMessageHeaders *hdrs,
                                      SoupHeaderName      name,
-                                     const char         *value)
+                                     const char         *value,
+                                     gboolean            trusted_value)
 {
         soup_message_headers_remove_common (hdrs, name);
-        soup_message_headers_append_common (hdrs, name, value);
+        soup_message_headers_append_common (hdrs, name, value, trusted_value);
 }
 
 /**
@@ -1008,7 +1016,7 @@ soup_message_headers_set_encoding (SoupMessageHeaders *hdrs,
 
 	case SOUP_ENCODING_CHUNKED:
 		soup_message_headers_remove_common (hdrs, SOUP_HEADER_CONTENT_LENGTH);
-		soup_message_headers_replace_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING, "chunked");
+		soup_message_headers_replace_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING, "chunked", TRUE);
 		break;
 
 	default:
@@ -1071,7 +1079,7 @@ soup_message_headers_set_content_length (SoupMessageHeaders *hdrs,
 	g_snprintf (length, sizeof (length), "%" G_GUINT64_FORMAT,
 		    content_length);
 	soup_message_headers_remove_common (hdrs, SOUP_HEADER_TRANSFER_ENCODING);
-	soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_LENGTH, length);
+	soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_LENGTH, length, TRUE);
 }
 
 /**
@@ -1124,7 +1132,7 @@ soup_message_headers_set_expectations (SoupMessageHeaders *hdrs,
 	g_return_if_fail ((expectations & ~SOUP_EXPECTATION_CONTINUE) == 0);
 
 	if (expectations & SOUP_EXPECTATION_CONTINUE)
-		soup_message_headers_replace_common (hdrs, SOUP_HEADER_EXPECT, "100-continue");
+		soup_message_headers_replace_common (hdrs, SOUP_HEADER_EXPECT, "100-continue", TRUE);
 	else
 		soup_message_headers_remove_common (hdrs, SOUP_HEADER_EXPECT);
 }
@@ -1361,7 +1369,7 @@ soup_message_headers_set_ranges (SoupMessageHeaders  *hdrs,
 		}
 	}
 
-	soup_message_headers_replace_common (hdrs, SOUP_HEADER_RANGE, header->str);
+	soup_message_headers_replace_common (hdrs, SOUP_HEADER_RANGE, header->str, TRUE);
 	g_string_free (header, TRUE);
 }
 
@@ -1482,7 +1490,7 @@ soup_message_headers_set_content_range (SoupMessageHeaders  *hdrs,
 		header = g_strdup_printf ("bytes %" G_GINT64_FORMAT "-%"
 					  G_GINT64_FORMAT "/*", start, end);
 	}
-	soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_RANGE, header);
+	soup_message_headers_replace_common (hdrs, SOUP_HEADER_CONTENT_RANGE, header, TRUE);
 	g_free (header);
 }
 
@@ -1557,7 +1565,7 @@ set_content_foo (SoupMessageHeaders *hdrs,
 		}
 	}
 
-	soup_message_headers_replace_common (hdrs, header_name, str->str);
+	soup_message_headers_replace_common (hdrs, header_name, str->str, FALSE);
 	g_string_free (str, TRUE);
 }
 
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 555fe015..04d965bb 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -1158,7 +1158,7 @@ soup_message_set_request_body (SoupMessage  *msg,
                         g_warn_if_fail (strchr (content_type, '/') != NULL);
 
                         if (soup_message_headers_get_content_type (priv->request_headers, NULL) != content_type)
-                                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE, content_type);
+                                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_CONTENT_TYPE, content_type, FALSE);
                 }
 
                 if (content_length == -1)
@@ -3235,12 +3235,12 @@ soup_message_set_request_host_from_uri (SoupMessage *msg,
 
         host = soup_uri_get_host_for_headers (uri);
         if (soup_uri_uses_default_port (uri))
-                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, host);
+                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, host, FALSE);
         else {
                 char *value;
 
                 value = g_strdup_printf ("%s:%d", host, g_uri_get_port (uri));
-                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, value);
+                soup_message_headers_replace_common (priv->request_headers, SOUP_HEADER_HOST, value, FALSE);
                 g_free (value);
         }
         g_free (host);
@@ -3280,7 +3280,7 @@ soup_message_force_keep_alive_if_needed (SoupMessage *msg)
         if (!soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive") &&
             !soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "close") &&
             !soup_message_headers_header_contains_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Upgrade")) {
-                soup_message_headers_append_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive");
+                soup_message_headers_append_common (priv->request_headers, SOUP_HEADER_CONNECTION, "Keep-Alive", TRUE);
         }
 }
 
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
index 2421c91f..655ac588 100644
--- a/libsoup/soup-multipart.c
+++ b/libsoup/soup-multipart.c
@@ -354,12 +354,12 @@ soup_multipart_append_form_file (SoupMultipart *multipart,
 		soup_header_g_string_append_param_quoted (disposition, "filename", filename);
 	}
 	soup_message_headers_append_common (headers, SOUP_HEADER_CONTENT_DISPOSITION,
-                                            disposition->str);
+                                            disposition->str, FALSE);
 	g_string_free (disposition, TRUE);
 
 	if (content_type) {
 		soup_message_headers_append_common (headers, SOUP_HEADER_CONTENT_TYPE,
-                                                    content_type);
+                                                    content_type, FALSE);
 	}
 
 	g_ptr_array_add (multipart->headers, headers);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index 931708d1..3878d52b 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1437,10 +1437,10 @@ soup_session_send_queue_item (SoupSession *session,
 
 	request_headers = soup_message_get_request_headers (item->msg);
 	if (priv->user_agent)
-		soup_message_headers_replace_common (request_headers, SOUP_HEADER_USER_AGENT, priv->user_agent);
+		soup_message_headers_replace_common (request_headers, SOUP_HEADER_USER_AGENT, priv->user_agent, FALSE);
 
 	if (priv->accept_language && !soup_message_headers_get_list_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE))
-		soup_message_headers_append_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE, priv->accept_language);
+		soup_message_headers_append_common (request_headers, SOUP_HEADER_ACCEPT_LANGUAGE, priv->accept_language, FALSE);
 
         conn = soup_message_get_connection (item->msg);
         soup_message_set_http_version (item->msg, soup_connection_get_negotiated_protocol (conn));
diff --git a/libsoup/websocket/soup-websocket.c b/libsoup/websocket/soup-websocket.c
index 64e66fd0..9863e94e 100644
--- a/libsoup/websocket/soup-websocket.c
+++ b/libsoup/websocket/soup-websocket.c
@@ -257,21 +257,21 @@ soup_websocket_client_prepare_handshake (SoupMessage *msg,
 
 	g_return_if_fail (SOUP_IS_MESSAGE (msg));
 
-	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_UPGRADE, "websocket");
-	soup_message_headers_append_common (soup_message_get_request_headers (msg), SOUP_HEADER_CONNECTION, "Upgrade");
+	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_UPGRADE, "websocket", TRUE);
+	soup_message_headers_append_common (soup_message_get_request_headers (msg), SOUP_HEADER_CONNECTION, "Upgrade", TRUE);
 
 	raw[0] = g_random_int ();
 	raw[1] = g_random_int ();
 	raw[2] = g_random_int ();
 	raw[3] = g_random_int ();
 	key = g_base64_encode ((const guchar *)raw, sizeof (raw));
-	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_KEY, key);
+	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_KEY, key, TRUE);
 	g_free (key);
 
-	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_VERSION, "13");
+	soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_SEC_WEBSOCKET_VERSION, "13", TRUE);
 
 	if (origin)
-		soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_ORIGIN, origin);
+		soup_message_headers_replace_common (soup_message_get_request_headers (msg), SOUP_HEADER_ORIGIN, origin, FALSE);
 
 	if (protocols && *protocols) {
 		char *protocols_str;
@@ -279,7 +279,7 @@ soup_websocket_client_prepare_handshake (SoupMessage *msg,
 		protocols_str = g_strjoinv (", ", protocols);
 		if (*protocols_str)
 			soup_message_headers_replace_common (soup_message_get_request_headers (msg),
-                                                         SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, protocols_str);
+                                                             SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, protocols_str, TRUE);
 		g_free (protocols_str);
 	}
 
@@ -316,7 +316,7 @@ soup_websocket_client_prepare_handshake (SoupMessage *msg,
 		if (extensions->len > 0) {
 			soup_message_headers_replace_common (soup_message_get_request_headers (msg),
                                                              SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS,
-                                                             extensions->str);
+                                                             extensions->str, FALSE);
 		} else {
 			soup_message_headers_remove_common (soup_message_get_request_headers (msg),
                                                             SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
@@ -633,7 +633,7 @@ respond_handshake_forbidden (SoupServerMessage *msg)
 {
 	soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN, NULL);
 	soup_message_headers_append_common (soup_server_message_get_response_headers (msg),
-                                            SOUP_HEADER_CONNECTION, "close");
+                                            SOUP_HEADER_CONNECTION, "close", TRUE);
 	soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_COPY,
 					  RESPONSE_FORBIDDEN, strlen (RESPONSE_FORBIDDEN));
 }
@@ -650,7 +650,7 @@ respond_handshake_bad (SoupServerMessage *msg,
 	text = g_strdup_printf (RESPONSE_BAD, why);
 	soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
 	soup_message_headers_append_common (soup_server_message_get_response_headers (msg),
-                                            SOUP_HEADER_CONNECTION, "close");
+                                            SOUP_HEADER_CONNECTION, "close", TRUE);
 	soup_server_message_set_response (msg, "text/html", SOUP_MEMORY_TAKE,
 					  text, strlen (text));
 }
@@ -716,18 +716,18 @@ soup_websocket_server_process_handshake (SoupServerMessage *msg,
 
 	soup_server_message_set_status (msg, SOUP_STATUS_SWITCHING_PROTOCOLS, NULL);
 	response_headers = soup_server_message_get_response_headers (msg);
-	soup_message_headers_replace_common (response_headers, SOUP_HEADER_UPGRADE, "websocket");
-	soup_message_headers_append_common (response_headers, SOUP_HEADER_CONNECTION, "Upgrade");
+	soup_message_headers_replace_common (response_headers, SOUP_HEADER_UPGRADE, "websocket", TRUE);
+	soup_message_headers_append_common (response_headers, SOUP_HEADER_CONNECTION, "Upgrade", TRUE);
 
 	request_headers = soup_server_message_get_request_headers (msg);
 	key = soup_message_headers_get_one_common (request_headers, SOUP_HEADER_SEC_WEBSOCKET_KEY);
 	accept_key = compute_accept_key (key);
-	soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_ACCEPT, accept_key);
+	soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_ACCEPT, accept_key, TRUE);
 	g_free (accept_key);
 
 	choose_subprotocol (msg, (const char **) protocols, &chosen_protocol);
 	if (chosen_protocol)
-		soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, chosen_protocol);
+		soup_message_headers_append_common (response_headers, SOUP_HEADER_SEC_WEBSOCKET_PROTOCOL, chosen_protocol, TRUE);
 
 	extensions = soup_message_headers_get_list_common (request_headers, SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
 	if (extensions && *extensions) {
@@ -758,7 +758,7 @@ soup_websocket_server_process_handshake (SoupServerMessage *msg,
 			if (response_extensions->len > 0) {
 				soup_message_headers_replace_common (response_headers,
                                                                      SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS,
-                                                                     response_extensions->str);
+                                                                     response_extensions->str, FALSE);
 			} else {
 				soup_message_headers_remove_common (response_headers,
                                                                     SOUP_HEADER_SEC_WEBSOCKET_EXTENSIONS);
diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c
index 4faafbd6..d2221fff 100644
--- a/tests/header-parsing-test.c
+++ b/tests/header-parsing-test.c
@@ -1283,34 +1283,102 @@ do_append_param_tests (void)
 
 static const struct {
 	const char *description, *name, *value;
-} bad_headers[] = {
-	{ "Empty name", "", "value" },
-	{ "Name with spaces", "na me", "value" },
-	{ "Name with colon", "na:me", "value" },
-	{ "Name with CR", "na\rme", "value" },
-	{ "Name with LF", "na\nme", "value" },
-	{ "Name with tab", "na\tme", "value" },
-	{ "Value with CR", "name", "val\rue" },
-	{ "Value with LF", "name", "val\nue" },
-	{ "Value with LWS", "name", "val\r\n ue" }
+} bad_header_names[] = {
+	{ "empty name", "", "value" },
+	{ "name with spaces", "na me", "value" },
+	{ "name with colon", "na:me", "value" },
+	{ "name with CR", "na\rme", "value" },
+	{ "name with LF", "na\nme", "value" },
+	{ "name with tab", "na\tme", "value" }
 };
 
-static void
-do_bad_header_tests (void)
+static const struct {
+        const char *description, *name, *value;
+} bad_header_values[] = {
+        { "value with CR", "name", "val\rue" },
+        { "value with LF", "name", "val\nue" },
+        { "value with LWS", "name", "val\r\n ue" }
+}
+
+static void do_bad_header_tests (void)
 {
 	SoupMessageHeaders *hdrs;
 	int i;
 
 	hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_MULTIPART);
-	for (i = 0; i < G_N_ELEMENTS (bad_headers); i++) {
-		debug_printf (1, "  %s\n", bad_headers[i].description);
-
-		g_test_expect_message ("libsoup", G_LOG_LEVEL_CRITICAL,
-				       "*soup_message_headers_append*assertion*failed*");
-		soup_message_headers_append (hdrs, bad_headers[i].name,
-					     bad_headers[i].value);
-		g_test_assert_expected_messages ();
+
+        /* soup_message_headers_append: bad names */
+	for (i = 0; i < G_N_ELEMENTS (bad_header_names); i++) {
+		debug_printf (1, "  Append %s\n", bad_header_names[i].description);
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad name*");
+		soup_message_headers_append (hdrs, bad_header_names[i].name,
+					     bad_header_names[i].value);
+                g_test_assert_expected_messages ();
+	}
+
+        /* soup_message_headers_append: bad values */
+        for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
+		debug_printf (1, "  Append %s\n", bad_header_values[i].description);
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+		soup_message_headers_append (hdrs, bad_header_values[i].name,
+					     bad_header_values[i].value);
+                g_test_assert_expected_messages ();
+	}
+
+        /* soup_message_headers_replace: bad values */
+        for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
+		debug_printf (1, "  Replace %s\n", bad_header_values[i].description);
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+		soup_message_headers_replace (hdrs, bad_header_values[i].name,
+                                              bad_header_values[i].value);
+                g_test_assert_expected_messages ();
 	}
+
+        /* soup_message_headers_set_content_type: bad values */
+        for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
+                GHashTable *params;
+
+                debug_printf (1, "  Content type with %s\n", bad_header_values[i].description);
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+                soup_message_headers_set_content_type (hdrs, bad_header_values[i].value, NULL);
+                g_test_assert_expected_messages ();
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+                params = g_hash_table_new (g_str_hash, g_str_equal);
+                g_hash_table_insert (params, CONTENT_TYPE_TEST_ATTRIBUTE, (gpointer)bad_header_values[i].value);
+                soup_message_headers_set_content_type (hdrs, CONTENT_TYPE_TEST_MIME_TYPE, params);
+                g_hash_table_destroy (params);
+                g_test_assert_expected_messages ();
+        }
+
+        /* soup_message_headers_set_content_disposition: bad values */
+        for (i = 0; i < G_N_ELEMENTS (bad_header_values); i++) {
+                GHashTable *params;
+
+                debug_printf (1, "  Content disposition with %s\n", bad_header_values[i].description);
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+                soup_message_headers_set_content_disposition (hdrs, bad_header_values[i].value, NULL);
+                g_test_assert_expected_messages ();
+
+                g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
+                                       "*soup_message_headers_append*Rejecting bad value*");
+                params = g_hash_table_new (g_str_hash, g_str_equal);
+                g_hash_table_insert (params, "filename", (gpointer)bad_header_values[i].value);
+                soup_message_headers_set_content_disposition (hdrs, "attachment", params);
+                g_hash_table_destroy (params);
+                g_test_assert_expected_messages ();
+        }
 	soup_message_headers_unref (hdrs);
 }
 
diff --git a/tests/http2-test.c b/tests/http2-test.c
index ef097f4e..33b937e5 100644
--- a/tests/http2-test.c
+++ b/tests/http2-test.c
@@ -1341,8 +1341,8 @@ server_handler (SoupServer        *server,
                 SoupMessageHeaders *response_headers;
 
                 response_headers = soup_server_message_get_response_headers (msg);
-                /* Use soup_message_headers_append_common to skip the validation check. */
-                soup_message_headers_append_common (response_headers, SOUP_HEADER_CONTENT_TYPE, "\r");
+                /* Use soup_message_headers_append_common with trusted_value=TRUE to skip the validation check. */
+                soup_message_headers_append_common (response_headers, SOUP_HEADER_CONTENT_TYPE, "\r", TRUE);
                 soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
         } else if (strcmp (path, "/invalid-header-rfc9113") == 0) {
                 SoupMessageHeaders *response_headers;
-- 
2.52.0

openSUSE Build Service is sponsored by