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