public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/libsoup3] rawhide: Update to 3.7.3 and drop upstreamed CVE patches
@ 2026-09-24 18:36 Petr Schindler
  0 siblings, 0 replies; only message in thread
From: Petr Schindler @ 2026-09-24 18:36 UTC (permalink / raw)
  To: git-commits

A new commit has been pushed.

Repo   : rpms/libsoup3
Branch : rawhide
Commit : 8323f6109b28bfc9248ff4810e36c464d4b5f3ee
Author : Petr Schindler <pschindl@redhat.com>
Date   : 2026-09-24T20:26:32+02:00
Stats  : +2/-1952 in 8 file(s)
URL    : https://src.fedoraproject.org/rpms/libsoup3/c/8323f6109b28bfc9248ff4810e36c464d4b5f3ee?branch=rawhide

Log:
Update to 3.7.3 and drop upstreamed CVE patches

---
diff --git a/CVE-2026-15709.patch b/CVE-2026-15709.patch
deleted file mode 100644
index 799c378..0000000
--- a/CVE-2026-15709.patch
+++ /dev/null
@@ -1,782 +0,0 @@
-From a4294044466df66ea98492d67bb74172ed3f8762 Mon Sep 17 00:00:00 2001
-From: Zayd Rajab <zaydr@amazon.com>
-Date: Fri, 4 Sep 2026 14:17:23 -0500
-Subject: [PATCH] websocket: Bound decompressed message size during inflation
-
-Pass each connection's remaining max-total-message-size allowance through
-the generic WebSocket extension processing path via a new
-process_incoming_message_with_limit vfunc, falling back to
-process_incoming_message for extensions that don't implement it. Bound
-permessage-deflate output growth to that allowance and use a one-byte
-probe to detect output beyond an exact boundary without allocating
-another normal output chunk.
-
-Preserve the documented unlimited default for clients and direct
-connections. SoupServer continues applying its existing 128 KiB default,
-while callers can configure the limit explicitly in either receive
-direction.
-
-Add boundary, generic-extension fallback, receive-direction, SoupServer,
-fragmentation, and unlimited-mode coverage.
-
-This addresses CVE-2026-15709.
-
-Reported-by: Tristan Madani <secientist@gmail.com>
-Closes !543
----
- libsoup/websocket/soup-websocket-connection.c |  34 +-
- .../soup-websocket-extension-deflate.c        | 144 ++++++---
- libsoup/websocket/soup-websocket-extension.c  |  53 +++
- libsoup/websocket/soup-websocket-extension.h  |  14 +-
- tests/websocket-test.c                        | 306 +++++++++++++++++-
- 5 files changed, 506 insertions(+), 45 deletions(-)
-
-diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c
-index ffd713ef..f07d4219 100644
---- a/libsoup/websocket/soup-websocket-connection.c
-+++ b/libsoup/websocket/soup-websocket-connection.c
-@@ -990,8 +990,15 @@ process_contents (SoupWebsocketConnection *self,
- 		case 0x02:
- 			/* Safety valve */
- 			if (priv->max_total_message_size > 0 &&
--			    (priv->message_data->len + payload_len) > priv->max_total_message_size) {
--				too_big_message_error_and_close (self, (priv->message_data->len + payload_len));
-+			    (priv->message_data->len > priv->max_total_message_size ||
-+			     payload_len > priv->max_total_message_size - priv->message_data->len)) {
-+				guint64 message_size = priv->message_data->len;
-+
-+				if (payload_len > G_MAXUINT64 - message_size)
-+					message_size = G_MAXUINT64;
-+				else
-+					message_size += payload_len;
-+				too_big_message_error_and_close (self, message_size);
- 				return;
- 			}
- 			g_byte_array_append (priv->message_data, payload, payload_len);
-@@ -1036,6 +1043,21 @@ process_contents (SoupWebsocketConnection *self,
- 	}
- }
- 
-+static guint64
-+get_remaining_message_size (SoupWebsocketConnectionPrivate *priv)
-+{
-+	if (priv->max_total_message_size == 0)
-+		return G_MAXUINT64;
-+
-+	if (!priv->message_data)
-+		return priv->max_total_message_size;
-+
-+	if (priv->message_data->len >= priv->max_total_message_size)
-+		return 0;
-+
-+	return priv->max_total_message_size - priv->message_data->len;
-+}
-+
- static gboolean
- process_frame (SoupWebsocketConnection *self)
- {
-@@ -1051,6 +1073,7 @@ process_frame (SoupWebsocketConnection *self)
- 	gsize len;
- 	gsize at;
- 	GBytes *filtered_bytes;
-+	guint64 max_output_size;
- 	GList *l;
- 	GError *error = NULL;
- 
-@@ -1165,11 +1188,16 @@ process_frame (SoupWebsocketConnection *self)
- 	}
- 
- 	filtered_bytes = g_bytes_new_static (payload, payload_len);
-+	max_output_size = get_remaining_message_size (priv);
- 	for (l = priv->extensions; l != NULL; l = g_list_next (l)) {
- 		SoupWebsocketExtension *extension;
- 
- 		extension = (SoupWebsocketExtension *)l->data;
--		filtered_bytes = soup_websocket_extension_process_incoming_message (extension, priv->incoming->data, filtered_bytes, &error);
-+		filtered_bytes = soup_websocket_extension_process_incoming_message_with_limit (extension,
-+											       priv->incoming->data,
-+											       filtered_bytes,
-+											       max_output_size,
-+											       &error);
- 		if (error) {
- 			emit_error_and_close (self, error, FALSE);
- 			return FALSE;
-diff --git a/libsoup/websocket/soup-websocket-extension-deflate.c b/libsoup/websocket/soup-websocket-extension-deflate.c
-index fa98a2e2..2c649a88 100644
---- a/libsoup/websocket/soup-websocket-extension-deflate.c
-+++ b/libsoup/websocket/soup-websocket-extension-deflate.c
-@@ -359,19 +359,29 @@ soup_websocket_extension_deflate_process_outgoing_message (SoupWebsocketExtensio
-         return g_byte_array_free_to_bytes (buffer);
- }
- 
-+static void
-+inflater_reset (Inflater *inflater)
-+{
-+        inflateReset (&inflater->zstream);
-+        inflater->uncompress_ongoing = FALSE;
-+}
-+
- static GBytes *
--soup_websocket_extension_deflate_process_incoming_message (SoupWebsocketExtension *extension,
--                                                           guint8                 *header,
--                                                           GBytes                 *payload,
--                                                           GError                **error)
-+soup_websocket_extension_deflate_process_incoming_message_with_limit (SoupWebsocketExtension *extension,
-+                                                                      guint8                 *header,
-+                                                                      GBytes                 *payload,
-+                                                                      guint64                 max_output_size,
-+                                                                      GError                **error)
- {
-         const guint8 *payload_data;
-         gsize payload_length;
-         gboolean fin, control, compressed;
-         GByteArray *buffer;
--        gsize bytes_read, bytes_written;
-+        gsize input_offset, bytes_written;
-         int result;
-         gboolean tail_added = FALSE;
-+        gboolean using_limit_probe = FALSE;
-+        guint8 limit_probe;
-         SoupWebsocketExtensionDeflatePrivate *priv;
- 
-         priv = soup_websocket_extension_deflate_get_instance_private (SOUP_WEBSOCKET_EXTENSION_DEFLATE (extension));
-@@ -394,6 +404,7 @@ soup_websocket_extension_deflate_process_incoming_message (SoupWebsocketExtensio
-                                      SOUP_WEBSOCKET_ERROR,
-                                      SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR,
-                                      "Received a non-first frame with RSV1 flag set");
-+                inflater_reset (&priv->inflater);
-                 g_bytes_unref (payload);
-                 return NULL;
-         }
-@@ -410,64 +421,122 @@ soup_websocket_extension_deflate_process_incoming_message (SoupWebsocketExtensio
- 
-         buffer = g_byte_array_new ();
- 
--        bytes_read = 0;
--        priv->inflater.zstream.next_in = (void *)payload_data;
--        priv->inflater.zstream.avail_in = payload_length;
--
-+        input_offset = 0;
-+        priv->inflater.zstream.avail_in = 0;
-         bytes_written = 0;
-         priv->inflater.zstream.avail_out = 0;
- 
--        do {
--                gsize read_remaining;
--                gsize write_remaining;
-+        while (TRUE) {
-+                uInt input_before, output_before;
-+                uInt input_consumed, output_produced;
- 
--                if (priv->inflater.zstream.avail_out == 0) {
--                        guint current_position;
-+                if (priv->inflater.zstream.avail_in == 0 && input_offset < payload_length) {
-+                        gsize input_length = MIN (payload_length - input_offset, G_MAXUINT);
- 
--                        priv->inflater.zstream.avail_out = BUFFER_SIZE;
--                        current_position = buffer->len;
--                        g_byte_array_set_size (buffer, buffer->len + BUFFER_SIZE);
--                        priv->inflater.zstream.next_out = buffer->data + current_position;
-+                        priv->inflater.zstream.next_in = (void *)(payload_data + input_offset);
-+                        priv->inflater.zstream.avail_in = (uInt)input_length;
-+                        input_offset += input_length;
-                 }
- 
--                if (priv->inflater.zstream.avail_in == 0 && !tail_added && fin) {
-+                if (priv->inflater.zstream.avail_in == 0 &&
-+                    input_offset == payload_length &&
-+                    !tail_added && fin) {
-                         /* Append 4 octets of 0x00 0x00 0xff 0xff to the tail end */
-                         priv->inflater.zstream.next_in = (void *)"\x00\x00\xff\xff";
-                         priv->inflater.zstream.avail_in = 4;
--                        bytes_read = 0;
-                         tail_added = TRUE;
-                 }
- 
--                read_remaining = tail_added ? 4 : payload_length - bytes_read;
--                write_remaining = buffer->len - bytes_written;
-+                if (priv->inflater.zstream.avail_out == 0) {
-+                        guint output_length = BUFFER_SIZE;
-+
-+                        if (bytes_written >= max_output_size || buffer->len == G_MAXUINT) {
-+                                priv->inflater.zstream.next_out = &limit_probe;
-+                                priv->inflater.zstream.avail_out = 1;
-+                                using_limit_probe = TRUE;
-+                        } else {
-+                                guint64 remaining = max_output_size - bytes_written;
-+                                guint current_position = buffer->len;
-+
-+                                output_length = MIN ((guint64)output_length, remaining);
-+                                output_length = MIN (output_length, G_MAXUINT - buffer->len);
-+                                g_assert (output_length > 0);
-+
-+                                g_byte_array_set_size (buffer, buffer->len + output_length);
-+                                priv->inflater.zstream.next_out = buffer->data + current_position;
-+                                priv->inflater.zstream.avail_out = output_length;
-+                                using_limit_probe = FALSE;
-+                        }
-+                }
-+
-+                input_before = priv->inflater.zstream.avail_in;
-+                output_before = priv->inflater.zstream.avail_out;
-                 result = inflate (&priv->inflater.zstream, tail_added ? Z_FINISH : Z_NO_FLUSH);
--                bytes_read += read_remaining - priv->inflater.zstream.avail_in;
--                bytes_written += write_remaining - priv->inflater.zstream.avail_out;
-+                input_consumed = input_before - priv->inflater.zstream.avail_in;
-+                output_produced = output_before - priv->inflater.zstream.avail_out;
-+
-+                if (using_limit_probe && output_produced > 0)
-+                        goto output_too_large;
-+
-+                bytes_written += output_produced;
-+
-                 if (!tail_added && result == Z_STREAM_END) {
-                         /* Received a block with BFINAL set to 1. Reset decompression state. */
-                         result = inflateReset (&priv->inflater.zstream);
-                 }
- 
--                if ((!fin && bytes_read == payload_length) || (fin && tail_added && bytes_read == 4))
--                        break;
--        } while (result == Z_OK || result == Z_BUF_ERROR);
--
--        g_bytes_unref (payload);
-+                if (result != Z_OK && result != Z_BUF_ERROR)
-+                        goto invalid_data;
- 
--        if (result != Z_OK && result != Z_BUF_ERROR) {
--                priv->inflater.uncompress_ongoing = FALSE;
--                g_set_error_literal (error,
--                                     SOUP_WEBSOCKET_ERROR,
--                                     SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR,
--                                     "Failed to uncompress incoming frame");
--                g_byte_array_unref (buffer);
-+                if (priv->inflater.zstream.avail_in == 0 &&
-+                    input_offset == payload_length &&
-+                    ((!fin && !tail_added) || (fin && tail_added)) &&
-+                    priv->inflater.zstream.avail_out > 0)
-+                        break;
- 
--                return NULL;
-+                if (input_consumed == 0 && output_produced == 0)
-+                        goto invalid_data;
-         }
- 
-+        g_bytes_unref (payload);
-         g_byte_array_set_size (buffer, bytes_written);
- 
-         return g_byte_array_free_to_bytes (buffer);
-+
-+output_too_large:
-+        inflater_reset (&priv->inflater);
-+        g_bytes_unref (payload);
-+        g_byte_array_unref (buffer);
-+        g_set_error_literal (error,
-+                             SOUP_WEBSOCKET_ERROR,
-+                             SOUP_WEBSOCKET_CLOSE_TOO_BIG,
-+                             "Decompressed WebSocket message exceeds configured maximum size");
-+
-+        return NULL;
-+
-+invalid_data:
-+        inflater_reset (&priv->inflater);
-+        g_bytes_unref (payload);
-+        g_byte_array_unref (buffer);
-+        g_set_error_literal (error,
-+                             SOUP_WEBSOCKET_ERROR,
-+                             SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR,
-+                             "Failed to uncompress incoming frame");
-+
-+        return NULL;
-+}
-+
-+static GBytes *
-+soup_websocket_extension_deflate_process_incoming_message (SoupWebsocketExtension *extension,
-+                                                           guint8                 *header,
-+                                                           GBytes                 *payload,
-+                                                           GError                **error)
-+{
-+        return soup_websocket_extension_deflate_process_incoming_message_with_limit (extension,
-+                                                                                     header,
-+                                                                                     payload,
-+                                                                                     G_MAXUINT64,
-+                                                                                     error);
- }
- 
- static void
-@@ -483,6 +552,7 @@ soup_websocket_extension_deflate_class_init (SoupWebsocketExtensionDeflateClass
-         extension_class->get_response_params = soup_websocket_extension_deflate_get_response_params;
-         extension_class->process_outgoing_message = soup_websocket_extension_deflate_process_outgoing_message;
-         extension_class->process_incoming_message = soup_websocket_extension_deflate_process_incoming_message;
-+        extension_class->process_incoming_message_with_limit = soup_websocket_extension_deflate_process_incoming_message_with_limit;
- 
-         object_class->finalize = soup_websocket_extension_deflate_finalize;
- }
-diff --git a/libsoup/websocket/soup-websocket-extension.c b/libsoup/websocket/soup-websocket-extension.c
-index 8882d2c0..95719e8c 100644
---- a/libsoup/websocket/soup-websocket-extension.c
-+++ b/libsoup/websocket/soup-websocket-extension.c
-@@ -47,6 +47,9 @@
-  *    before it's sent. Reserved bits of the header should be changed.
-  * @process_incoming_message: called to process the payload data of a message
-  *    after it's received. Reserved bits of the header should be cleared.
-+ * @process_incoming_message_with_limit: called to process the payload data of
-+ *    a message after it's received without exceeding the requested maximum
-+ *    output size. If unset, @process_incoming_message is used. Since 3.8
-  *
-  * The class structure for the [class@WebsocketExtension].
-  */
-@@ -216,3 +219,53 @@ soup_websocket_extension_process_incoming_message (SoupWebsocketExtension *exten
- 
- 	return klass->process_incoming_message (extension, header, payload, error);
- }
-+
-+/**
-+ * soup_websocket_extension_process_incoming_message_with_limit:
-+ * @extension: a #SoupWebsocketExtension
-+ * @header: (inout): the message header
-+ * @payload: (transfer full): the payload data
-+ * @max_output_size: the maximum size in bytes of the processed payload
-+ * @error: return location for a #GError
-+ *
-+ * Process a message after it's received, without producing more than
-+ * @max_output_size bytes of output.
-+ *
-+ * This behaves like [method@WebsocketExtension.process_incoming_message],
-+ * but extensions that expand their input (such as `permessage-deflate`)
-+ * stop and return an error with [error@WebsocketError.CLOSE_TOO_BIG]
-+ * instead of producing output larger than @max_output_size. Extensions
-+ * that don't implement this fall back to
-+ * [method@WebsocketExtension.process_incoming_message].
-+ *
-+ * Returns: (transfer full): the message payload data, or %NULL in case of error
-+ *
-+ * Since: 3.8
-+ */
-+GBytes *
-+soup_websocket_extension_process_incoming_message_with_limit (SoupWebsocketExtension *extension,
-+                                                              guint8                 *header,
-+                                                              GBytes                 *payload,
-+                                                              guint64                 max_output_size,
-+                                                              GError                **error)
-+{
-+	SoupWebsocketExtensionClass *klass;
-+
-+	g_return_val_if_fail (SOUP_IS_WEBSOCKET_EXTENSION (extension), NULL);
-+	g_return_val_if_fail (header != NULL, NULL);
-+	g_return_val_if_fail (payload != NULL, NULL);
-+	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-+
-+	klass = SOUP_WEBSOCKET_EXTENSION_GET_CLASS (extension);
-+	if (!klass->process_incoming_message_with_limit)
-+		return soup_websocket_extension_process_incoming_message (extension,
-+									  header,
-+									  payload,
-+									  error);
-+
-+	return klass->process_incoming_message_with_limit (extension,
-+							   header,
-+							   payload,
-+							   max_output_size,
-+							   error);
-+}
-diff --git a/libsoup/websocket/soup-websocket-extension.h b/libsoup/websocket/soup-websocket-extension.h
-index 1931a264..a9d5e35c 100644
---- a/libsoup/websocket/soup-websocket-extension.h
-+++ b/libsoup/websocket/soup-websocket-extension.h
-@@ -55,8 +55,14 @@ struct _SoupWebsocketExtensionClass {
- 					       GBytes                     *payload,
-                                                GError                    **error);
- 
-+	GBytes  *(* process_incoming_message_with_limit) (SoupWebsocketExtension *extension,
-+	                                                  guint8                 *header,
-+	                                                  GBytes                 *payload,
-+	                                                  guint64                 max_output_size,
-+	                                                  GError                **error);
-+
-         /* <private> */
--	gpointer padding[6];
-+	gpointer padding[5];
- };
- 
- SOUP_AVAILABLE_IN_ALL
-@@ -80,5 +86,11 @@ GBytes                  *soup_websocket_extension_process_incoming_message (Soup
- 									    guint8                     *header,
- 									    GBytes                     *payload,
- 									    GError                    **error);
-+SOUP_AVAILABLE_IN_3_8
-+GBytes                  *soup_websocket_extension_process_incoming_message_with_limit (SoupWebsocketExtension *extension,
-+											       guint8                 *header,
-+											       GBytes                 *payload,
-+											       guint64                 max_output_size,
-+											       GError                **error);
- 
- G_END_DECLS
-diff --git a/tests/websocket-test.c b/tests/websocket-test.c
-index db088a55..5f94b5f6 100644
---- a/tests/websocket-test.c
-+++ b/tests/websocket-test.c
-@@ -73,6 +73,18 @@ on_error_copy (SoupWebsocketConnection *ws,
- 	*copy = g_error_copy (error);
- }
- 
-+static void
-+on_error_copy_once (SoupWebsocketConnection *ws,
-+		    GError *error,
-+		    gpointer user_data)
-+{
-+	GError **copy = user_data;
-+
-+	g_assert_null (*copy);
-+	*copy = g_error_copy (error);
-+	g_signal_handlers_disconnect_by_func (ws, G_CALLBACK (on_error_copy_once), user_data);
-+}
-+
- static void
- setup_listener (Test *test)
- {
-@@ -649,7 +661,7 @@ test_send_big_packets_soup (Test *test,
- 	g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->client), ==, 128 * 1024);
- 	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0);
- 
--	/* Max total message size defaults to 0 (unlimited), but SoupServer applies its own limit by default. */
-+	/* SoupServer applies its own total message size limit by default. */
- 	g_assert_cmpuint (soup_websocket_connection_get_max_incoming_payload_size (test->server), ==, 128 * 1024);
- 	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024);
- 
-@@ -756,9 +768,7 @@ test_send_exceeding_server_max_message_size (Test *test,
- 	soup_websocket_connection_set_max_total_message_size (test->client, 0);
- 	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->client), ==, 0);
- 
--	/* Set the server message total message size manually, because its
--	 * default is different for direct connection vs. soup connection.
--	 */
-+	/* The direct server connection defaults to unlimited. */
- 	soup_websocket_connection_set_max_total_message_size (test->server, 128 * 1024);
- 	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (test->server), ==, 128 * 1024);
- 
-@@ -1670,6 +1680,222 @@ send_fragments_server_thread (gpointer user_data)
- 	return NULL;
- }
- 
-+typedef struct {
-+	SoupWebsocketExtension parent_instance;
-+} LegacyWebsocketExtension;
-+
-+typedef struct {
-+	SoupWebsocketExtensionClass parent_class;
-+} LegacyWebsocketExtensionClass;
-+
-+GType legacy_websocket_extension_get_type (void);
-+
-+#define LEGACY_TYPE_WEBSOCKET_EXTENSION (legacy_websocket_extension_get_type ())
-+G_DEFINE_TYPE (LegacyWebsocketExtension, legacy_websocket_extension, SOUP_TYPE_WEBSOCKET_EXTENSION)
-+
-+static gboolean legacy_extension_processed;
-+
-+static GBytes *
-+legacy_websocket_extension_process_incoming_message (SoupWebsocketExtension *extension,
-+						     guint8                 *header,
-+						     GBytes                 *payload,
-+						     GError                **error)
-+{
-+	legacy_extension_processed = TRUE;
-+
-+	return payload;
-+}
-+
-+static void
-+legacy_websocket_extension_class_init (LegacyWebsocketExtensionClass *klass)
-+{
-+	SoupWebsocketExtensionClass *extension_class = SOUP_WEBSOCKET_EXTENSION_CLASS (klass);
-+
-+	extension_class->process_incoming_message = legacy_websocket_extension_process_incoming_message;
-+}
-+
-+static void
-+legacy_websocket_extension_init (LegacyWebsocketExtension *extension)
-+{
-+}
-+
-+static void
-+test_websocket_extension_limit_fallback (void)
-+{
-+	SoupWebsocketExtension *extension;
-+	GBytes *payload;
-+	GBytes *output;
-+	GError *error = NULL;
-+	guint8 header = 0x82;
-+
-+	legacy_extension_processed = FALSE;
-+	extension = g_object_new (LEGACY_TYPE_WEBSOCKET_EXTENSION, NULL);
-+	payload = g_bytes_new_static ("x", 1);
-+	output = soup_websocket_extension_process_incoming_message_with_limit (extension,
-+									       &header,
-+									       payload,
-+									       1,
-+									       &error);
-+
-+	g_assert_no_error (error);
-+	g_assert_true (legacy_extension_processed);
-+	g_assert_true (output == payload);
-+
-+	g_bytes_unref (output);
-+	g_object_unref (extension);
-+}
-+
-+typedef struct {
-+	gsize output_size;
-+	guint64 max_output_size;
-+	gboolean expect_too_big;
-+} DeflateOutputLimitTest;
-+
-+static void
-+test_deflate_output_limit (gconstpointer data)
-+{
-+	const DeflateOutputLimitTest *config = data;
-+	SoupWebsocketExtension *sender;
-+	SoupWebsocketExtension *receiver;
-+	GBytes *compressed;
-+	GBytes *output;
-+	GError *error = NULL;
-+	guint8 header = 0x82;
-+
-+	sender = g_object_new (SOUP_TYPE_WEBSOCKET_EXTENSION_DEFLATE, NULL);
-+	g_assert_true (soup_websocket_extension_configure (sender,
-+							   SOUP_WEBSOCKET_CONNECTION_SERVER,
-+							   NULL, &error));
-+	g_assert_no_error (error);
-+
-+	receiver = g_object_new (SOUP_TYPE_WEBSOCKET_EXTENSION_DEFLATE, NULL);
-+	g_assert_true (soup_websocket_extension_configure (receiver,
-+							   SOUP_WEBSOCKET_CONNECTION_CLIENT,
-+							   NULL, &error));
-+	g_assert_no_error (error);
-+
-+	compressed = g_bytes_new_take (g_malloc0 (config->output_size), config->output_size);
-+	compressed = soup_websocket_extension_process_outgoing_message (sender, &header,
-+									compressed, &error);
-+	g_assert_no_error (error);
-+	g_assert_nonnull (compressed);
-+	g_assert_true (header & 0x40);
-+	g_assert_cmpuint (g_bytes_get_size (compressed), <, config->output_size);
-+
-+	output = soup_websocket_extension_process_incoming_message_with_limit (receiver,
-+									       &header,
-+									       compressed,
-+									       config->max_output_size,
-+									       &error);
-+	if (config->expect_too_big) {
-+		g_assert_null (output);
-+		g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_TOO_BIG);
-+		g_clear_error (&error);
-+	} else {
-+		g_assert_no_error (error);
-+		g_assert_nonnull (output);
-+		g_assert_cmpuint (g_bytes_get_size (output), ==, config->output_size);
-+		g_bytes_unref (output);
-+	}
-+
-+	g_object_unref (receiver);
-+	g_object_unref (sender);
-+}
-+
-+static const DeflateOutputLimitTest deflate_output_below_limit = {
-+	4095, 4096, FALSE
-+};
-+static const DeflateOutputLimitTest deflate_output_at_limit = {
-+	4096, 4096, FALSE
-+};
-+static const DeflateOutputLimitTest deflate_output_over_limit = {
-+	4097, 4096, TRUE
-+};
-+
-+typedef struct {
-+	gboolean server_receives;
-+	gboolean configure_limit;
-+} DeflateMessageLimitTest;
-+
-+static void
-+test_deflate_exceeds_message_limit (Test *test,
-+				    gconstpointer data)
-+{
-+	const DeflateMessageLimitTest *config = data;
-+	SoupWebsocketConnection *receiver;
-+	SoupWebsocketConnection *sender;
-+	GBytes *received = NULL;
-+	GError *error = NULL;
-+	guint8 *message;
-+
-+	if (config->server_receives) {
-+		receiver = test->server;
-+		sender = test->client;
-+	} else {
-+		receiver = test->client;
-+		sender = test->server;
-+	}
-+
-+	if (config->configure_limit)
-+		soup_websocket_connection_set_max_total_message_size (receiver, 128 * 1024);
-+
-+	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (receiver),
-+			  ==, 128 * 1024);
-+
-+	g_signal_connect (receiver, "error", G_CALLBACK (on_error_copy_once), &error);
-+	g_signal_connect (receiver, "message", G_CALLBACK (on_binary_message), &received);
-+
-+	message = g_malloc0 (128 * 1024 + 1);
-+	soup_websocket_connection_send_binary (sender, message, 128 * 1024 + 1);
-+	g_free (message);
-+
-+	WAIT_UNTIL (error != NULL || received != NULL);
-+	g_assert_null (received);
-+	g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_TOO_BIG);
-+	g_clear_error (&error);
-+
-+	WAIT_UNTIL (soup_websocket_connection_get_state (sender) == SOUP_WEBSOCKET_STATE_CLOSED);
-+	g_assert_null (received);
-+	g_assert_cmpuint (soup_websocket_connection_get_close_code (sender),
-+			  ==, SOUP_WEBSOCKET_CLOSE_TOO_BIG);
-+}
-+
-+static void
-+test_deflate_default_unlimited_message_size (Test *test,
-+					     gconstpointer data)
-+{
-+	const DeflateMessageLimitTest *config = data;
-+	SoupWebsocketConnection *receiver;
-+	SoupWebsocketConnection *sender;
-+	GBytes *received = NULL;
-+	guint8 *message;
-+
-+	if (config->server_receives) {
-+		receiver = test->server;
-+		sender = test->client;
-+	} else {
-+		receiver = test->client;
-+		sender = test->server;
-+	}
-+
-+	g_assert_false (config->configure_limit);
-+	g_assert_cmpuint (soup_websocket_connection_get_max_total_message_size (receiver), ==, 0);
-+	g_signal_connect (receiver, "message", G_CALLBACK (on_binary_message), &received);
-+
-+	message = g_malloc0 (128 * 1024 + 1);
-+	soup_websocket_connection_send_binary (sender, message, 128 * 1024 + 1);
-+	g_free (message);
-+
-+	WAIT_UNTIL (received != NULL);
-+	g_assert_cmpuint (g_bytes_get_size (received), ==, 128 * 1024 + 1);
-+	g_bytes_unref (received);
-+}
-+
-+static const DeflateMessageLimitTest deflate_server_receives_configured = { TRUE, TRUE };
-+static const DeflateMessageLimitTest deflate_client_receives_configured = { FALSE, TRUE };
-+static const DeflateMessageLimitTest deflate_server_receives_default = { TRUE, FALSE };
-+static const DeflateMessageLimitTest deflate_client_receives_default = { FALSE, FALSE };
-+
- static void
- do_deflate (z_stream *zstream,
-             const char *str,
-@@ -1771,6 +1997,31 @@ test_receive_fragmented (Test *test,
- 	WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
- }
- 
-+static void
-+test_deflate_receive_fragmented_too_big (Test *test,
-+					 gconstpointer data)
-+{
-+	GThread *thread;
-+	GBytes *received = NULL;
-+	GError *error = NULL;
-+
-+	soup_websocket_connection_set_max_total_message_size (test->client, 12);
-+	g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy_once), &error);
-+	g_signal_connect (test->client, "message", G_CALLBACK (on_text_message), &received);
-+
-+	thread = g_thread_new ("deflate-fragment-too-big-thread",
-+			       send_compressed_fragments_server_thread,
-+			       test);
-+
-+	WAIT_UNTIL (error != NULL || received != NULL);
-+	g_assert_null (received);
-+	g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_TOO_BIG);
-+	g_clear_error (&error);
-+
-+	g_thread_join (thread);
-+	WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
-+}
-+
- typedef struct {
- 	Test *test;
- 	const char *header;
-@@ -2798,6 +3049,18 @@ main (int argc,
- 		    test_deflate_negotiate_direct,
- 		    NULL);
- 
-+	g_test_add_func ("/websocket/extension/incoming-limit-legacy-fallback",
-+			 test_websocket_extension_limit_fallback);
-+	g_test_add_data_func ("/websocket/deflate/output-limit/below",
-+			      &deflate_output_below_limit,
-+			      test_deflate_output_limit);
-+	g_test_add_data_func ("/websocket/deflate/output-limit/exact",
-+			      &deflate_output_at_limit,
-+			      test_deflate_output_limit);
-+	g_test_add_data_func ("/websocket/deflate/output-limit/over",
-+			      &deflate_output_over_limit,
-+			      test_deflate_output_limit);
-+
- 	g_test_add ("/websocket/direct/deflate-disabled-in-message", Test, NULL, NULL,
- 		    test_deflate_disabled_in_message_direct,
- 		    NULL);
-@@ -2823,6 +3086,37 @@ main (int argc,
- 		    test_send_server_to_client,
- 		    teardown_soup_connection);
- 
-+	g_test_add ("/websocket/direct/deflate-configured-limit/client-to-server",
-+		    Test, &deflate_server_receives_configured,
-+		    setup_direct_connection_with_extensions,
-+		    test_deflate_exceeds_message_limit,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/deflate-configured-limit/server-to-client",
-+		    Test, &deflate_client_receives_configured,
-+		    setup_direct_connection_with_extensions,
-+		    test_deflate_exceeds_message_limit,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/soup/deflate-default-server-limit/client-to-server",
-+		    Test, &deflate_server_receives_default,
-+		    setup_soup_connection_with_extensions,
-+		    test_deflate_exceeds_message_limit,
-+		    teardown_soup_connection);
-+	g_test_add ("/websocket/soup/deflate-configured-client-limit/server-to-client",
-+		    Test, &deflate_client_receives_configured,
-+		    setup_soup_connection_with_extensions,
-+		    test_deflate_exceeds_message_limit,
-+		    teardown_soup_connection);
-+	g_test_add ("/websocket/direct/deflate-default-unlimited/client-to-server",
-+		    Test, &deflate_server_receives_default,
-+		    setup_direct_connection_with_extensions,
-+		    test_deflate_default_unlimited_message_size,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/deflate-default-unlimited/server-to-client",
-+		    Test, &deflate_client_receives_default,
-+		    setup_direct_connection_with_extensions,
-+		    test_deflate_default_unlimited_message_size,
-+		    teardown_direct_connection);
-+
- 	g_test_add ("/websocket/direct/deflate-send-big-packets", Test, NULL,
- 		    setup_direct_connection_with_extensions,
- 		    test_send_big_packets_direct,
-@@ -2845,6 +3139,10 @@ main (int argc,
- 		    setup_half_direct_connection_with_extensions,
- 		    test_receive_fragmented,
- 		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/deflate-receive-fragmented-too-big", Test, NULL,
-+		    setup_half_direct_connection_with_extensions,
-+		    test_deflate_receive_fragmented_too_big,
-+		    teardown_direct_connection);
- 	g_test_add ("/websocket/direct/deflate-receive-fragmented-error", Test, NULL,
- 		    setup_half_direct_connection_with_extensions,
- 		    test_deflate_receive_fragmented_error,
--- 
-GitLab
-

diff --git a/CVE-2026-15711.patch b/CVE-2026-15711.patch
deleted file mode 100644
index 22ab57b..0000000
--- a/CVE-2026-15711.patch
+++ /dev/null
@@ -1,172 +0,0 @@
-From 60aa1ce2bdc7bb5da33be9062f50bcec7db67fca Mon Sep 17 00:00:00 2001
-From: Zayd Rajab <zaydr@amazon.com>
-Date: Thu, 16 Jul 2026 02:32:19 +0000
-Subject: [PATCH] websocket: Reject oversized control frames
-
-RFC 6455 section 5.5 limits control frame payloads to 125 bytes.
-Reject extended payload length indicators as soon as the base header is
-available, before waiting for additional length or payload bytes.
-
-Add regression coverage for both extended length indicators and both
-receive directions.
-
-This is CVE-2026-15711.
-
-Closes #515
----
- libsoup/websocket/soup-websocket-connection.c |   7 ++
- tests/websocket-test.c                        | 113 ++++++++++++++++++
- 2 files changed, 120 insertions(+)
-
-diff --git a/libsoup/websocket/soup-websocket-connection.c b/libsoup/websocket/soup-websocket-connection.c
-index 14dcd630..ffd713ef 100644
---- a/libsoup/websocket/soup-websocket-connection.c
-+++ b/libsoup/websocket/soup-websocket-connection.c
-@@ -1082,6 +1082,13 @@ process_frame (SoupWebsocketConnection *self)
-                 return FALSE;
-         }
- 
-+	/* RFC 6455 section 5.5 limits control frame payloads to 125 bytes. */
-+	if (control && (header[1] & 0x7f) > 125) {
-+		g_debug ("received oversized control frame");
-+		protocol_error_and_close (self);
-+		return FALSE;
-+	}
-+
- 	switch (header[1] & 0x7f) {
- 	case 126:
- 		/* If 126, the following 2 bytes interpreted as a 16-bit
-diff --git a/tests/websocket-test.c b/tests/websocket-test.c
-index b8f71300..db088a55 100644
---- a/tests/websocket-test.c
-+++ b/tests/websocket-test.c
-@@ -835,6 +835,98 @@ test_send_bad_data (Test *test,
- 	g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_BAD_DATA);
- }
- 
-+static gboolean
-+on_timeout_set_flag (gpointer user_data)
-+{
-+	gboolean *timed_out = user_data;
-+
-+	*timed_out = TRUE;
-+
-+	return G_SOURCE_REMOVE;
-+}
-+
-+static void
-+wait_for_websocket_error (GError **error)
-+{
-+	gboolean timed_out = FALSE;
-+	guint timeout_id;
-+
-+	timeout_id = g_timeout_add_seconds (1, on_timeout_set_flag, &timed_out);
-+	WAIT_UNTIL (*error != NULL || timed_out);
-+
-+	if (!timed_out)
-+		g_source_remove (timeout_id);
-+	g_assert_false (timed_out);
-+}
-+
-+static void
-+write_oversized_control_frame_header (GIOStream *io,
-+				      guint8 length_indicator,
-+				      gboolean masked)
-+{
-+	guint8 frame[] = { 0x8a, length_indicator };
-+	GError *error = NULL;
-+	gsize written;
-+
-+	g_assert_true (length_indicator == 126 || length_indicator == 127);
-+
-+	if (masked)
-+		frame[1] |= 0x80;
-+
-+	g_output_stream_write_all (g_io_stream_get_output_stream (io),
-+				   frame, sizeof (frame), &written, NULL, &error);
-+	g_assert_no_error (error);
-+	g_assert_cmpuint (written, ==, sizeof (frame));
-+}
-+
-+typedef struct {
-+	guint8 length_indicator;
-+	gboolean server_receives;
-+} OversizedControlFrameTest;
-+
-+static void
-+test_receive_oversized_control_frame (Test *test,
-+				      gconstpointer data)
-+{
-+	const OversizedControlFrameTest *config = data;
-+	SoupWebsocketConnection *receiver;
-+	SoupWebsocketConnection *sender;
-+	GError *error = NULL;
-+	GIOStream *io;
-+	gulong error_id;
-+	gboolean close_event = FALSE;
-+
-+	if (config->server_receives) {
-+		receiver = test->server;
-+		sender = test->client;
-+	} else {
-+		receiver = test->client;
-+		sender = test->server;
-+	}
-+
-+	g_signal_handlers_disconnect_by_func (receiver, on_error_not_reached, NULL);
-+	error_id = g_signal_connect (receiver, "error", G_CALLBACK (on_error_copy), &error);
-+	g_signal_connect (sender, "closed", G_CALLBACK (on_close_set_flag), &close_event);
-+
-+	io = soup_websocket_connection_get_io_stream (sender);
-+	write_oversized_control_frame_header (io, config->length_indicator,
-+					      config->server_receives);
-+	wait_for_websocket_error (&error);
-+	g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
-+	g_clear_error (&error);
-+	g_signal_handler_disconnect (receiver, error_id);
-+
-+	WAIT_UNTIL (soup_websocket_connection_get_state (sender) == SOUP_WEBSOCKET_STATE_CLOSED);
-+	g_assert_true (close_event);
-+	g_assert_cmpuint (soup_websocket_connection_get_close_code (sender), ==,
-+			  SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
-+}
-+
-+static const OversizedControlFrameTest oversized_control_frame_16_server = { 126, TRUE };
-+static const OversizedControlFrameTest oversized_control_frame_64_server = { 127, TRUE };
-+static const OversizedControlFrameTest oversized_control_frame_16_client = { 126, FALSE };
-+static const OversizedControlFrameTest oversized_control_frame_64_client = { 127, FALSE };
-+
- static const char *negotiate_client_protocols[] = { "bbb", "ccc", NULL };
- static const char *negotiate_server_protocols[] = { "aaa", "bbb", "ccc", NULL };
- static const char *negotiated_protocol = "bbb";
-@@ -2574,6 +2666,27 @@ main (int argc,
- 		    test_send_bad_data,
- 		    teardown_soup_connection);
- 
-+	g_test_add ("/websocket/direct/server-receive-oversized-control-frame/16-bit",
-+		    Test, &oversized_control_frame_16_server,
-+		    setup_direct_connection,
-+		    test_receive_oversized_control_frame,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/server-receive-oversized-control-frame/64-bit",
-+		    Test, &oversized_control_frame_64_server,
-+		    setup_direct_connection,
-+		    test_receive_oversized_control_frame,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/client-receive-oversized-control-frame/16-bit",
-+		    Test, &oversized_control_frame_16_client,
-+		    setup_direct_connection,
-+		    test_receive_oversized_control_frame,
-+		    teardown_direct_connection);
-+	g_test_add ("/websocket/direct/client-receive-oversized-control-frame/64-bit",
-+		    Test, &oversized_control_frame_64_client,
-+		    setup_direct_connection,
-+		    test_receive_oversized_control_frame,
-+		    teardown_direct_connection);
-+
- 	g_test_add ("/websocket/direct/close-clean-client", Test, NULL, NULL,
- 		    test_close_clean_client_direct,
- 		    NULL);
--- 
-GitLab
-

diff --git a/CVE-2026-15712.patch b/CVE-2026-15712.patch
deleted file mode 100644
index 5616dec..0000000
--- a/CVE-2026-15712.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 3a6fb56a0cba42d11f5fd1db6dedcc7c2e92757b Mon Sep 17 00:00:00 2001
-From: Mike Gorse <mgorse@suse.com>
-Date: Fri, 4 Sep 2026 14:05:04 -0500
-Subject: [PATCH] http2: Don't assume that GOAWAY opaque data is NUL-terminated
-
-nghttp2 allocates frame->goaway.opaque_data with exactly opaque_data_len
-bytes and no terminator, so passing it to a "%s" format in h2_debug()
-reads past the end of the buffer when debug logging is enabled.
-
-Use "%.*s" with opaque_data_len as the precision so the read is bounded
-without allocating a copy.
-
-Closes #540
----
- libsoup/http2/soup-client-message-io-http2.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c
-index ab52003d..b6742924 100644
---- a/libsoup/http2/soup-client-message-io-http2.c
-+++ b/libsoup/http2/soup-client-message-io-http2.c
-@@ -813,10 +813,11 @@ on_frame_recv_callback (nghttp2_session     *session,
- 
-                 switch (frame->hd.type) {
-                 case NGHTTP2_GOAWAY:
--                        h2_debug (io, NULL, "[RECV] GOAWAY: error=%s, last_stream_id=%d %s",
-+                        h2_debug (io, NULL, "[RECV] GOAWAY: error=%s, last_stream_id=%d %.*s",
-                                   nghttp2_http2_strerror (frame->goaway.error_code),
-                                   frame->goaway.last_stream_id,
--                                  frame->goaway.opaque_data ? (char *)frame->goaway.opaque_data : "");
-+                                  (int)frame->goaway.opaque_data_len,
-+                                  frame->goaway.opaque_data ? (const char *)frame->goaway.opaque_data : "");
-                         handle_goaway (io, frame->goaway.error_code, frame->goaway.last_stream_id);
-                         io->is_shutdown = TRUE;
-                         soup_client_message_io_http2_terminate_session (io);
--- 
-GitLab
-

diff --git a/CVE-2026-15713.patch b/CVE-2026-15713.patch
deleted file mode 100644
index ef84ebb..0000000
--- a/CVE-2026-15713.patch
+++ /dev/null
@@ -1,148 +0,0 @@
-From 24fb645fa949ece7d7e10363b77cf2d5fa2c2469 Mon Sep 17 00:00:00 2001
-From: Milan Crha <mcrha@redhat.com>
-Date: Fri, 4 Sep 2026 10:34:22 +0200
-Subject: [PATCH] cache: Reject caching authenticated responses in shared
- caches
-
-RFC 7234 Section 3.2 forbids to save to a shared cache a response to
-a request containing an Authorization header unless the response
-explicitly allows it with public, must-revalidate or s-maxage.
-
-This is CVE-2026-15713.
-
-Closes https://gitlab.gnome.org/GNOME/libsoup/-/work_items/541
----
- libsoup/cache/soup-cache.c | 15 +++++++++++
- tests/cache-test.c         | 55 ++++++++++++++++++++++++++++++++++++++
- 2 files changed, 70 insertions(+)
-
-diff --git a/libsoup/cache/soup-cache.c b/libsoup/cache/soup-cache.c
-index 47e1ee70..5225382d 100644
---- a/libsoup/cache/soup-cache.c
-+++ b/libsoup/cache/soup-cache.c
-@@ -174,6 +174,7 @@ get_cacheability (SoupCache *cache, SoupMessage *msg)
- 	SoupCacheability cacheability;
- 	const char *cache_control, *content_type;
- 	gboolean has_max_age = FALSE;
-+	gboolean permits_authorized_shared_caching = FALSE;
- 
- 	/* 1. The request method must be cacheable */
- 	if (soup_message_get_method (msg) == SOUP_METHOD_GET)
-@@ -201,6 +202,11 @@ get_cacheability (SoupCache *cache, SoupMessage *msg)
- 				soup_header_free_param_list (hash);
- 				return SOUP_CACHE_UNCACHEABLE;
- 			}
-+
-+			permits_authorized_shared_caching =
-+				g_hash_table_lookup_extended (hash, "public", NULL, NULL) ||
-+				g_hash_table_lookup_extended (hash, "must-revalidate", NULL, NULL) ||
-+				g_hash_table_lookup_extended (hash, "s-maxage", NULL, NULL);
- 		}
- 
- 		/* 2. The 'no-store' cache directive does not appear in the
-@@ -225,6 +231,15 @@ get_cacheability (SoupCache *cache, SoupMessage *msg)
- 		soup_header_free_param_list (hash);
- 	}
- 
-+	/* RFC 7234 Section 3.2: a shared cache MUST NOT store a response to
-+	 * a request containing an Authorization header unless the response
-+	 * explicitly allows it with public, must-revalidate or s-maxage.
-+	 */
-+	if (priv->cache_type == SOUP_CACHE_SHARED &&
-+	    !permits_authorized_shared_caching &&
-+	    soup_message_headers_get_one_common (soup_message_get_request_headers (msg), SOUP_HEADER_AUTHORIZATION))
-+		return SOUP_CACHE_UNCACHEABLE;
-+
- 	/* Section 13.9 */
- 	if ((g_uri_get_query (soup_message_get_uri (msg))) &&
- 	    !soup_message_headers_get_one_common (soup_message_get_response_headers (msg), SOUP_HEADER_EXPIRES) &&
-diff --git a/tests/cache-test.c b/tests/cache-test.c
-index ef2ebeb3..dff6bd35 100644
---- a/tests/cache-test.c
-+++ b/tests/cache-test.c
-@@ -95,6 +95,7 @@ server_callback (SoupServer        *server,
- 	if (status == SOUP_STATUS_OK) {
- 		GChecksum *sum;
- 		const char *body;
-+		const char *authorization;
- 
- 		sum = g_checksum_new (G_CHECKSUM_SHA256);
- 		g_checksum_update (sum, (guchar *)path, strlen (path));
-@@ -102,6 +103,9 @@ server_callback (SoupServer        *server,
- 			g_checksum_update (sum, (guchar *)last_modified, strlen (last_modified));
- 		if (etag)
- 			g_checksum_update (sum, (guchar *)etag, strlen (etag));
-+		authorization = soup_message_headers_get_one (request_headers, "Authorization");
-+		if (authorization)
-+			g_checksum_update (sum, (guchar *)authorization, strlen (authorization));
- 		body = g_checksum_get_string (sum);
- 		soup_server_message_set_response (msg, "text/plain",
- 						  SOUP_MEMORY_COPY,
-@@ -736,6 +740,56 @@ do_leaks_test (gconstpointer data)
- 	g_free (cache_dir);
- }
- 
-+static void
-+do_shared_cache_authorization_test (gconstpointer data)
-+{
-+	GUri *base_uri = (GUri *)data;
-+	SoupSession *attacker_session;
-+	SoupSession *victim_session;
-+	SoupCache *attacker_cache;
-+	SoupCache *victim_cache;
-+	char *cache_dir;
-+	char *attacker_body;
-+	char *victim_body;
-+
-+	cache_dir = g_dir_make_tmp ("cache-test-XXXXXX", NULL);
-+	debug_printf (2, "  Caching to %s\n", cache_dir);
-+
-+	attacker_cache = soup_cache_new (cache_dir, SOUP_CACHE_SHARED);
-+	attacker_session = soup_test_session_new (NULL);
-+	soup_session_add_feature (attacker_session, SOUP_SESSION_FEATURE (attacker_cache));
-+
-+	attacker_body = do_request (attacker_session, base_uri, "GET", "/authz-shared-cache", NULL,
-+				    "Authorization", "Bearer ATTACKER_SECRET",
-+				    "Test-Set-Cache-Control", "max-age=600",
-+				    NULL);
-+	g_assert_true (last_request_hit_network);
-+
-+	soup_cache_dump (attacker_cache);
-+	soup_test_session_abort_unref (attacker_session);
-+	g_object_unref (attacker_cache);
-+
-+	victim_cache = soup_cache_new (cache_dir, SOUP_CACHE_SHARED);
-+	soup_cache_load (victim_cache);
-+	victim_session = soup_test_session_new (NULL);
-+	soup_session_add_feature (victim_session, SOUP_SESSION_FEATURE (victim_cache));
-+
-+	victim_body = do_request (victim_session, base_uri, "GET", "/authz-shared-cache", NULL,
-+				  "Authorization", "Bearer VICTIM_SECRET",
-+				  "Test-Set-Cache-Control", "max-age=600",
-+				  NULL);
-+
-+	g_assert_true (last_request_hit_network);
-+	g_assert_cmpstr (attacker_body, !=, victim_body);
-+
-+	g_free (attacker_body);
-+	g_free (victim_body);
-+
-+	soup_test_session_abort_unref (victim_session);
-+	g_object_unref (victim_cache);
-+	g_free (cache_dir);
-+}
-+
- static void
- do_metrics_test (gconstpointer data)
- {
-@@ -1108,6 +1162,7 @@ main (int argc, char **argv)
- 	g_test_add_data_func ("/cache/cancellation", base_uri, do_cancel_test);
- 	g_test_add_data_func ("/cache/refcounting", base_uri, do_refcounting_test);
- 	g_test_add_data_func ("/cache/headers", base_uri, do_headers_test);
-+	g_test_add_data_func ("/cache/shared-cache-authorization", base_uri, do_shared_cache_authorization_test);
- 	g_test_add_data_func ("/cache/leaks", base_uri, do_leaks_test);
-         g_test_add_data_func ("/cache/metrics", base_uri, do_metrics_test);
-         g_test_add_data_func ("/cache/threads", base_uri, do_threads_test);
--- 
-GitLab
-

diff --git a/CVE-2026-15714.patch b/CVE-2026-15714.patch
deleted file mode 100644
index 451f767..0000000
--- a/CVE-2026-15714.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From 79a52cadc490360e249cc2b23038d532b44dbf23 Mon Sep 17 00:00:00 2001
-From: Mike Gorse <mgorse@suse.com>
-Date: Fri, 4 Sep 2026 14:10:46 -0500
-Subject: [PATCH] multipart: Fix out-of-bounds read in case of an excessively
- long boundary
-
-soup_multipart_input_stream_read_headers() compared meta_buf against the
-boundary using the boundary length without checking that meta_buf held
-that many bytes, so a server sending a boundary longer than the read
-buffer could make strncmp() read past the end of the allocation. It also
-computed read_buf + nread - 4 before verifying nread was large enough,
-and asserted rather than failing when a line did not end in a newline.
-
-Only compare once enough bytes have been read, index read_buf after the
-length checks, and treat an unterminated line as end of parsing.
-
-Closes !546
----
- libsoup/soup-multipart-input-stream.c | 12 ++++-----
- tests/multipart-test.c                | 37 +++++++++++++++++++++++++++
- 2 files changed, 43 insertions(+), 6 deletions(-)
-
-diff --git a/libsoup/soup-multipart-input-stream.c b/libsoup/soup-multipart-input-stream.c
-index b7f1ed72..22cce102 100644
---- a/libsoup/soup-multipart-input-stream.c
-+++ b/libsoup/soup-multipart-input-stream.c
-@@ -361,7 +361,6 @@ soup_multipart_input_stream_read_headers (SoupMultipartInputStream  *multipart,
- {
- 	SoupMultipartInputStreamPrivate *priv = soup_multipart_input_stream_get_instance_private (multipart);
- 	guchar read_buf[RESPONSE_BLOCK_SIZE];
--	guchar *buf;
- 	gboolean got_boundary = FALSE;
- 	gboolean got_lf = FALSE;
- 	gssize nread = 0;
-@@ -383,22 +382,23 @@ soup_multipart_input_stream_read_headers (SoupMultipartInputStream  *multipart,
- 		 * may get the multipart end indicator without getting a new line.
- 		 */
- 		if (!got_boundary &&
-+		    priv->meta_buf->len >= priv->boundary_size &&
- 		    !strncmp ((char *)priv->meta_buf->data,
- 			      priv->boundary,
- 			      priv->boundary_size)) {
- 			got_boundary = TRUE;
- 
- 			/* Now check for possible multipart termination. */
--			buf = &read_buf[nread - 4];
--			if ((nread >= 4 && !memcmp (buf, "--\r\n", 4)) ||
--			    (nread >= 3 && !memcmp (buf + 1, "--\n", 3)) ||
--			    (nread >= 3 && !memcmp (buf + 2, "--", 2))) {
-+			if ((nread >= 4 && !memcmp (read_buf + nread - 4, "--\r\n", 4)) ||
-+			    (nread >= 3 && !memcmp (read_buf + nread - 3, "--\n", 3)) ||
-+			    (nread >= 3 && !memcmp (read_buf + nread - 2, "--", 2))) {
- 				g_byte_array_set_size (priv->meta_buf, 0);
- 				return FALSE;
- 			}
- 		}
- 
--		g_return_val_if_fail (got_lf, FALSE);
-+		if (!got_lf)
-+			return FALSE;
- 
- 		/* Discard pre-boundary lines. */
- 		if (!got_boundary) {
-diff --git a/tests/multipart-test.c b/tests/multipart-test.c
-index b1bf5bb8..a598a1c8 100644
---- a/tests/multipart-test.c
-+++ b/tests/multipart-test.c
-@@ -596,6 +596,42 @@ test_multipart_bounds_bad_3 (void)
-         g_object_unref (msg);
- }
- 
-+static void
-+test_multipart_bounds_bad_4 (void)
-+{
-+        SoupMessage *msg;
-+        SoupMessageHeaders *headers;
-+        GInputStream *in;
-+        GInputStream *next_part;
-+        SoupMultipartInputStream *multipart;
-+        GError *error = NULL;
-+        gchar *boundary;
-+        gchar *content_type;
-+        gchar *raw_data;
-+
-+        boundary = g_new (gchar, 20001);
-+        memset (boundary, 'a', 20000);
-+        boundary[20000] = '\0';
-+
-+        msg = soup_message_new(SOUP_METHOD_POST, "http://foo/upload");
-+        headers = soup_message_get_response_headers (msg);
-+        content_type = g_strconcat ("multipart/form-data; boundary=\"", boundary, "\"", NULL);
-+        soup_message_headers_replace (headers, "Content-Type", content_type);
-+
-+        raw_data = g_strconcat ("--", boundary, "\r\nContent-Type: text-plain\r\n\r\nX\r\n", NULL);
-+        in = g_memory_input_stream_new_from_data (raw_data, strlen (raw_data), NULL);
-+        multipart = soup_multipart_input_stream_new (msg, in);
-+        g_object_unref (in);
-+        next_part = soup_multipart_input_stream_next_part (multipart, NULL, &error);
-+        g_assert_no_error (error);
-+        g_assert_null (next_part);
-+        g_object_unref (multipart);
-+        g_object_unref (msg);
-+        g_free (raw_data);
-+        g_free (content_type);
-+        g_free (boundary);
-+}
-+
- static void
- test_multipart_too_large (void)
- {
-@@ -666,6 +702,7 @@ main (int argc, char **argv)
- 	g_test_add_func ("/multipart/bounds-bad", test_multipart_bounds_bad);
- 	g_test_add_func ("/multipart/bounds-bad-2", test_multipart_bounds_bad_2);
-         g_test_add_func ("/multipart/bounds-bad-3", test_multipart_bounds_bad_3);
-+        g_test_add_func ("/multipart/bounds-bad-4", test_multipart_bounds_bad_4);
- 	g_test_add_func ("/multipart/too-large", test_multipart_too_large);
- 
- 	ret = g_test_run ();
--- 
-GitLab
-

diff --git a/CVE-2026-77680.patch b/CVE-2026-77680.patch
deleted file mode 100644
index 2e142b0..0000000
--- a/CVE-2026-77680.patch
+++ /dev/null
@@ -1,681 +0,0 @@
-From e82c13ba03defcee10f981ac964f4d570b21a251 Mon Sep 17 00:00:00 2001
-From: Patrick Griffis <pgriffis@igalia.com>
-Date: Wed, 12 Aug 2026 14:21:52 -0500
-Subject: [PATCH] message-headers: Fix Range parsing overflows and coalescing
- cost
-
-A suffix range longer than the body drove the range start negative, which
-then reached a g_assert() and aborted the process. Clamp it to select the
-whole body instead, as RFC 9110 section 14.1.2 requires. Range starts and
-ends which overflow the goffset they are parsed into are now rejected and
-clamped respectively, rather than wrapping negative and reaching the same
-assertion.
-
-Ranges are no longer coalesced by removing each merged element in turn,
-which was quadratic in their number, and a Range header listing more than
-MAX_RANGES ranges is now answered with 416 instead of being served; RFC
-9110 section 15.5.17 names an excessive number of ranges as a reason for
-that status.
-
-Finally, sort_ranges() returned a goffset difference truncated to int, so
-it reported the wrong order for ranges more than G_MAXINT apart, and the
-merge below it then dropped ranges from responses over 2GB.
-
-Fixes #516
-Fixes #519
-Fixes #535
-Fixes #538
-Fixes #544
-Fixes #547
-Fixes #548
----
- libsoup/soup-message-headers-private.h |   2 +
- libsoup/soup-message-headers.c         |  89 +++++--
- tests/range-test.c                     | 347 +++++++++++++++++++++++++
- tests/server-mem-limit-test.c          |  61 +++--
- 4 files changed, 464 insertions(+), 35 deletions(-)
-
-diff --git a/libsoup/soup-message-headers-private.h b/libsoup/soup-message-headers-private.h
-index 708afe98..2e96af34 100644
---- a/libsoup/soup-message-headers-private.h
-+++ b/libsoup/soup-message-headers-private.h
-@@ -12,6 +12,8 @@ G_BEGIN_DECLS
- 
- #define MAX_HEADERS_BUFFER_SIZE 256 * 1024 /* 256K */
- 
-+#define MAX_RANGES 200
-+
- typedef enum {
-         SOUP_HEADER_VALUE_UNTRUSTED,
-         SOUP_HEADER_VALUE_TRUSTED
-diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
-index b2ec036c..7e2e6583 100644
---- a/libsoup/soup-message-headers.c
-+++ b/libsoup/soup-message-headers.c
-@@ -1226,7 +1226,12 @@ sort_ranges (gconstpointer a, gconstpointer b)
- 	SoupRange *ra = (SoupRange *)a;
- 	SoupRange *rb = (SoupRange *)b;
- 
--	return ra->start - rb->start;
-+	if (ra->start < rb->start)
-+		return -1;
-+	else if (ra->start > rb->start)
-+		return 1;
-+	else
-+		return 0;
- }
- 
- /* like soup_message_headers_get_ranges(), except it returns:
-@@ -1270,6 +1275,17 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders  *hdrs,
- 	if (!range_list)
- 		return SOUP_STATUS_OK;  /* invalid list */
- 
-+	/* Reject the header outright if it asks for more ranges than we are
-+	 * willing to serve, rather than answering with the whole body: a client
-+	 * asking for this many ranges wants to be told so, and RFC 9110 §14.2
-+	 * allows rejecting such a header for exactly this reason.
-+	 */
-+	if (g_slist_length (range_list) > MAX_RANGES) {
-+		soup_header_free_list (range_list);
-+		return check_satisfiable ? SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE
-+					 : SOUP_STATUS_OK;
-+	}
-+
- 	/* Loop through the ranges and modify the status accordingly. Default to
- 	 * status 200 (OK, ignoring the ranges). Switch to status 206 (Partial
- 	 * Content) if there is at least one partially valid range. Switch to
-@@ -1281,15 +1297,48 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders  *hdrs,
- 
- 		spec = r->data;
- 		if (*spec == '-') {
--			cur.start = g_ascii_strtoll (spec, &end, 10) + total_length;
-+			gint64 suffix_length;
-+
-+			errno = 0;
-+			suffix_length = g_ascii_strtoll (spec, &end, 10);
-+
-+			/* A suffix range asks for the last -suffix_length bytes
-+			 * of the body. If the body is shorter than that then the
-+			 * whole body is used, per RFC 9110 §14.1.2; without
-+			 * clamping, the start would go negative and reach the
-+			 * assertion below.
-+			 */
-+			if (errno == ERANGE || suffix_length <= -total_length)
-+				cur.start = 0;
-+			else
-+				cur.start = total_length + suffix_length;
-+
- 			cur.end = total_length - 1;
- 		} else {
--			cur.start = g_ascii_strtoull (spec, &end, 10);
-+			guint64 value;
-+
-+			errno = 0;
-+			value = g_ascii_strtoull (spec, &end, 10);
-+			if (errno == ERANGE || value > G_MAXINT64) {
-+				is_all_valid = FALSE;
-+				continue;
-+			}
-+			cur.start = (goffset) value;
-+
- 			if (*end == '-')
- 				end++;
--			if (*end)
--				cur.end = g_ascii_strtoull (end, &end, 10);
--			else
-+			if (*end) {
-+				errno = 0;
-+				value = g_ascii_strtoull (end, &end, 10);
-+
-+				/* An end this large is clamped to the end of the
-+				 * body below, like any other end past it.
-+				 */
-+				if (errno == ERANGE || value > G_MAXINT64)
-+					cur.end = G_MAXINT64;
-+				else
-+					cur.end = (goffset) value;
-+			} else
- 				cur.end = total_length - 1;
- 		}
- 
-@@ -1330,19 +1379,24 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders  *hdrs,
- 	}
- 
- 	if (total_length) {
--		guint i;
-+		SoupRange *data;
-+		guint i, last = 0;
- 
- 		g_array_sort (array, sort_ranges);
--		for (i = 1; i < array->len; i++) {
--			SoupRange *cur = &((SoupRange *)array->data)[i];
--			SoupRange *prev = &((SoupRange *)array->data)[i - 1];
- 
--			if (cur->start <= prev->end) {
--				prev->end = MAX (prev->end, cur->end);
--				g_array_remove_index (array, i);
--				i--;
--			}
-+		/* Merge overlapping ranges into the run being built at @last.
-+		 * Removing the merged elements one at a time instead made this
-+		 * quadratic in the number of ranges.
-+		 */
-+		data = (SoupRange *)array->data;
-+		for (i = 1; i < array->len; i++) {
-+			if (data[i].start <= data[last].end)
-+				data[last].end = MAX (data[last].end, data[i].end);
-+			else
-+				data[++last] = data[i];
- 		}
-+
-+		g_array_set_size (array, last + 1);
- 	}
- 
- 	*ranges = (SoupRange *)array->data;
-@@ -1375,6 +1429,11 @@ soup_message_headers_get_ranges_internal (SoupMessageHeaders  *hdrs,
-  * Beware that even if given a @total_length, this function does not
-  * check that the ranges are satisfiable.
-  *
-+ * A Range header requesting more than 200 ranges is rejected, since serving
-+ * that many ranges costs far more than the request asking for them.
-+ * [class@Server] answers such a request with
-+ * %SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE.
-+ *
-  * [class@Server] has built-in handling for range requests. If your
-  * server handler returns a %SOUP_STATUS_OK response containing the
-  * complete response body (rather than pausing the message and
-diff --git a/tests/range-test.c b/tests/range-test.c
-index cfd5f613..9e4ed2c9 100644
---- a/tests/range-test.c
-+++ b/tests/range-test.c
-@@ -3,6 +3,8 @@
- #include "config.h"
- 
- #include "test-utils.h"
-+#include "soup-message-headers-private.h"
-+#include "soup-misc.h"
- 
- GBytes *full_response;
- int total_length;
-@@ -161,6 +163,21 @@ request_single_range_by_string (SoupSession *session, const char *uri,
- 	g_object_unref (msg);
- }
- 
-+/* Like request_single_range_by_string(), but able to check the ranges of a
-+ * successful 206 as well. */
-+static void
-+request_single_range_by_string_full (SoupSession *session, const char *uri,
-+				     const char *range, SoupStatus expected_status,
-+				     int expected_start, int expected_end)
-+{
-+	SoupMessage *msg;
-+
-+	msg = soup_message_new ("GET", uri);
-+	soup_message_headers_replace (soup_message_get_request_headers (msg), "Range", range);
-+
-+	do_single_range (session, msg, 0, 0, expected_status, expected_start, expected_end);
-+}
-+
- static void
- do_multi_range (SoupSession *session, SoupMessage *msg,
- 		int expected_return_ranges)
-@@ -445,6 +462,290 @@ do_range_test (SoupSession *session, const char *uri,
- 					SOUP_STATUS_OK);
- }
- 
-+/* Tests for the Range parser itself. Unlike the tests above, these don't need
-+ * a server, so they can use total lengths which would be impractical to
-+ * actually serve, and they can check the exact status which the server would
-+ * use rather than only the ones a client can distinguish.
-+ */
-+typedef struct {
-+	const char *description;
-+	const char *bugref;
-+	const char *range;
-+	goffset total_length;
-+	guint expected_status;
-+	int expected_n_ranges;
-+	SoupRange expected_ranges[3];
-+} RangeParsingTest;
-+
-+static const RangeParsingTest range_parsing_tests[] = {
-+	/* Valid ranges against a ten byte body, as a baseline. */
-+	{ "simple range", NULL,
-+	  "bytes=0-4", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 4 } } },
-+	{ "whole body", NULL,
-+	  "bytes=0-9", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "open ended range", NULL,
-+	  "bytes=5-", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 5, 9 } } },
-+	{ "final byte", NULL,
-+	  "bytes=9-", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 9, 9 } } },
-+	{ "end past the body is clamped", NULL,
-+	  "bytes=1-100", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 1, 9 } } },
-+	{ "suffix range", NULL,
-+	  "bytes=-5", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 5, 9 } } },
-+	{ "single byte suffix range", NULL,
-+	  "bytes=-1", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 9, 9 } } },
-+	{ "whitespace around the ranges", NULL,
-+	  "bytes \t = \t 0-4", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 4 } } },
-+
-+	/* Unsatisfiable and invalid ranges. */
-+	{ "start past the body", NULL,
-+	  "bytes=10-20", 10, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, 0, { } },
-+	{ "end before start", NULL,
-+	  "bytes=10-1", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "zero length suffix range", NULL,
-+	  "bytes=-0", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "trailing garbage", NULL,
-+	  "bytes=0-10 but with weird trailing content", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "invalid range dash", NULL,
-+	  "bytes=0a10", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "unknown range unit", NULL,
-+	  "horses=0-10", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "missing equals", NULL,
-+	  "bytes 0-10", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "delimiters but no ranges", NULL,
-+	  "bytes=, ,,\t, ", 10, SOUP_STATUS_OK, 0, { } },
-+
-+	/* A suffix length at least as long as the body selects the whole body,
-+	 * per RFC 9110 §14.1.2. These used to drive the range start negative,
-+	 * which aborted the process at the g_assert() below the parse.
-+	 */
-+	{ "suffix range the length of the body", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/516",
-+	  "bytes=-10", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range one longer than the body", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/516",
-+	  "bytes=-11", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range much longer than the body", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/548",
-+	  "bytes=-999999", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range of G_MININT", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/547",
-+	  "bytes=-2147483648", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range larger than a guint32", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/547",
-+	  "bytes=-4294967296", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range of G_MAXINT64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/547",
-+	  "bytes=-9223372036854775807", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range of G_MININT64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/547",
-+	  "bytes=-9223372036854775808", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "suffix range overflowing gint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=-99999999999999999999", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "oversized suffix range merged with a valid range", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/548",
-+	  "bytes=-999999,4-5", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+
-+	/* Range starts and ends which overflow the signed goffset they are
-+	 * parsed into. An overflowing start is treated like any other start
-+	 * beyond the end of the body, and an overflowing end is clamped like
-+	 * any other end beyond the end of the body.
-+	 */
-+	{ "start overflowing gint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=9888888888888019900-", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "start overflowing gint64 with no dash", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=9888888888888019900", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "start of G_MAXINT64 + 1", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=9223372036854775808-", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "start overflowing guint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=18446744073709551616-", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "start and end overflowing gint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=9888888888888019900-9888888888888019901", 10, SOUP_STATUS_OK, 0, { } },
-+	{ "end overflowing gint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=0-9888888888888019900", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+	{ "end overflowing guint64", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/535",
-+	  "bytes=0-18446744073709551616", 10, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 9 } } },
-+
-+	/* Zero length bodies. soup_message_headers_get_ranges() is public API,
-+	 * so it can be called with one even though the server never does.
-+	 */
-+	{ "range against an empty body", NULL,
-+	  "bytes=0-9", 0, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, 0, { } },
-+	{ "suffix range against an empty body", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/548",
-+	  "bytes=-5", 0, SOUP_STATUS_OK, 0, { } },
-+
-+	/* Merging. */
-+	{ "overlapping ranges are merged", NULL,
-+	  "bytes=0-10,5-20", 100, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 20 } } },
-+	{ "contained ranges are merged", NULL,
-+	  "bytes=0-20,5-10", 100, SOUP_STATUS_PARTIAL_CONTENT, 1, { { 0, 20 } } },
-+	{ "touching ranges are not merged", NULL,
-+	  "bytes=0-4,5-9", 100, SOUP_STATUS_PARTIAL_CONTENT, 2, { { 0, 4 }, { 5, 9 } } },
-+	{ "ranges are sorted", NULL,
-+	  "bytes=20-29,0-9", 100, SOUP_STATUS_PARTIAL_CONTENT, 2, { { 0, 9 }, { 20, 29 } } },
-+	{ "invalid ranges do not prevent valid ones", NULL,
-+	  "bytes=0-9,50-40,20-29", 100, SOUP_STATUS_PARTIAL_CONTENT, 2, { { 0, 9 }, { 20, 29 } } },
-+
-+	/* The comparison function used to sort the ranges before merging them
-+	 * used to truncate a goffset difference to int, which flips its sign
-+	 * for bodies over 2GB and silently dropped ranges from the response.
-+	 */
-+	{ "ranges more than G_MAXINT apart", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/519",
-+	  "bytes=0-100, 2500000000-2500000100, 4999999000-4999999100", 5000000000,
-+	  SOUP_STATUS_PARTIAL_CONTENT, 3,
-+	  { { 0, 100 }, { 2500000000, 2500000100 }, { 4999999000, 4999999100 } } },
-+	{ "unsorted ranges more than G_MAXINT apart", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/519",
-+	  "bytes=4999999000-4999999100, 0-100, 2500000000-2500000100", 5000000000,
-+	  SOUP_STATUS_PARTIAL_CONTENT, 3,
-+	  { { 0, 100 }, { 2500000000, 2500000100 }, { 4999999000, 4999999100 } } },
-+};
-+
-+static void
-+check_parsed_ranges (const char *range,
-+		     goffset     total_length,
-+		     guint       expected_status,
-+		     int         expected_n_ranges,
-+		     const SoupRange *expected_ranges)
-+{
-+	SoupMessageHeaders *hdrs;
-+	SoupRange *ranges = NULL;
-+	int n_ranges = 0;
-+	guint status;
-+	int i;
-+
-+	hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
-+	soup_message_headers_replace (hdrs, "Range", range);
-+
-+	status = soup_message_headers_get_ranges_internal (hdrs, total_length, TRUE,
-+							   &ranges, &n_ranges);
-+
-+	g_assert_cmpuint (status, ==, expected_status);
-+
-+	if (status == SOUP_STATUS_PARTIAL_CONTENT) {
-+		g_assert_nonnull (ranges);
-+		g_assert_cmpint (n_ranges, ==, expected_n_ranges);
-+
-+		for (i = 0; i < n_ranges; i++) {
-+			debug_printf (2, "    [%d]: %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT "\n",
-+				      i, ranges[i].start, ranges[i].end);
-+
-+			g_assert_cmpint (ranges[i].start, ==, expected_ranges[i].start);
-+			g_assert_cmpint (ranges[i].end, ==, expected_ranges[i].end);
-+
-+			/* Whatever the input, the parsed ranges must be usable
-+			 * as offsets into a buffer of total_length bytes.
-+			 */
-+			g_assert_cmpint (ranges[i].start, >=, 0);
-+			g_assert_cmpint (ranges[i].end, >=, ranges[i].start);
-+			g_assert_cmpint (ranges[i].end, <, total_length);
-+		}
-+	}
-+
-+	soup_message_headers_free_ranges (hdrs, ranges);
-+	soup_message_headers_unref (hdrs);
-+}
-+
-+static void
-+do_range_parsing_test (void)
-+{
-+	guint i;
-+
-+	for (i = 0; i < G_N_ELEMENTS (range_parsing_tests); i++) {
-+		const RangeParsingTest *test = &range_parsing_tests[i];
-+
-+		debug_printf (1, "%2u. %s: '%s' against %" G_GOFFSET_FORMAT " bytes\n",
-+			      i + 1, test->description, test->range, test->total_length);
-+
-+		if (test->bugref)
-+			g_test_message ("Bug reference: %s", test->bugref);
-+
-+		check_parsed_ranges (test->range, test->total_length,
-+				     test->expected_status, test->expected_n_ranges,
-+				     test->expected_ranges);
-+	}
-+}
-+
-+/* A single Range header can list far more ranges than are reasonable to serve:
-+ * the only limit on the wire is the maximum request header size. */
-+static void
-+do_range_count_test (void)
-+{
-+	struct {
-+		int n_ranges;
-+		gboolean identical;
-+		guint expected_status;
-+		int expected_n_ranges;
-+	} tests[] = {
-+		/* Distinct ranges, up to and then past the limit. Going past it
-+		 * is rejected rather than ignored.
-+		 */
-+		{ 100, FALSE, SOUP_STATUS_PARTIAL_CONTENT, 100 },
-+		{ MAX_RANGES, FALSE, SOUP_STATUS_PARTIAL_CONTENT, MAX_RANGES },
-+		{ MAX_RANGES + 1, FALSE, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, 0 },
-+
-+		/* Identical ranges, which all merge into one. This is the
-+		 * shape which used to be quadratic.
-+		 */
-+		{ MAX_RANGES, TRUE, SOUP_STATUS_PARTIAL_CONTENT, 1 },
-+		{ MAX_RANGES + 1, TRUE, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, 0 },
-+		{ 25585, TRUE, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE, 0 },
-+	};
-+	guint i;
-+	int j;
-+
-+	for (i = 0; i < G_N_ELEMENTS (tests); i++) {
-+		SoupMessageHeaders *hdrs;
-+		SoupRange *ranges = NULL;
-+		int n_ranges = 0;
-+		guint status;
-+		GString *range;
-+
-+		debug_printf (1, "%2u. %d %s ranges\n", i + 1, tests[i].n_ranges,
-+			      tests[i].identical ? "identical" : "distinct");
-+
-+		range = g_string_new ("bytes=");
-+		for (j = 0; j < tests[i].n_ranges; j++) {
-+			int start = tests[i].identical ? 0 : j * 2;
-+
-+			if (j > 0)
-+				g_string_append_c (range, ',');
-+			g_string_append_printf (range, "%d-%d", start, start);
-+		}
-+
-+		hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
-+		soup_message_headers_replace (hdrs, "Range", range->str);
-+		g_string_free (range, TRUE);
-+
-+		status = soup_message_headers_get_ranges_internal (hdrs, 1000000, TRUE,
-+								   &ranges, &n_ranges);
-+
-+		g_assert_cmpuint (status, ==, tests[i].expected_status);
-+		if (status == SOUP_STATUS_PARTIAL_CONTENT)
-+			g_assert_cmpint (n_ranges, ==, tests[i].expected_n_ranges);
-+
-+		soup_message_headers_free_ranges (hdrs, ranges);
-+		soup_message_headers_unref (hdrs);
-+	}
-+
-+	/* Callers which don't ask about satisfiability, such as the public
-+	 * soup_message_headers_get_ranges(), can't be told 416, so an
-+	 * over-limit header just reports no ranges to them.
-+	 */
-+	{
-+		SoupMessageHeaders *hdrs;
-+		SoupRange *ranges = NULL;
-+		int n_ranges = 0;
-+		GString *range;
-+
-+		range = g_string_new ("bytes=0-0");
-+		for (j = 0; j < MAX_RANGES; j++)
-+			g_string_append (range, ",0-0");
-+
-+		hdrs = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
-+		soup_message_headers_replace (hdrs, "Range", range->str);
-+		g_string_free (range, TRUE);
-+
-+		g_assert_cmpuint (soup_message_headers_get_ranges_internal (hdrs, 1000000, FALSE,
-+									    &ranges, &n_ranges),
-+				  ==, SOUP_STATUS_OK);
-+		g_assert_false (soup_message_headers_get_ranges (hdrs, 1000000, &ranges, &n_ranges));
-+
-+		soup_message_headers_free_ranges (hdrs, ranges);
-+		soup_message_headers_unref (hdrs);
-+	}
-+}
-+
- #ifdef HAVE_APACHE
- static void
- do_apache_range_test (void)
-@@ -473,6 +774,49 @@ server_handler (SoupServer        *server,
- 					full_response);
- }
- 
-+static void
-+do_libsoup_only_range_test (SoupSession *session, const char *uri)
-+{
-+	gsize full_response_length = g_bytes_get_size (full_response);
-+	GString *range;
-+	int i;
-+
-+	/* A suffix length at least as long as the body selects the whole body. */
-+	debug_printf (1, "Requesting (suffix range the length of the body) -%d\n",
-+		      (int) full_response_length);
-+	request_single_range (session, uri,
-+			      -((int) full_response_length), -1,
-+			      SOUP_STATUS_PARTIAL_CONTENT, 0, -1);
-+
-+	debug_printf (1, "Requesting (suffix range longer than the body) -999999\n");
-+	request_single_range_by_string_full (session, uri, "bytes=-999999",
-+					     SOUP_STATUS_PARTIAL_CONTENT, 0, -1);
-+
-+	debug_printf (1, "Requesting (suffix range overflowing gint64) -99999999999999999999\n");
-+	request_single_range_by_string_full (session, uri, "bytes=-99999999999999999999",
-+					     SOUP_STATUS_PARTIAL_CONTENT, 0, -1);
-+
-+	/* A start which overflows gint64 is treated like any other start past
-+	 * the end of the body.
-+	 * https://gitlab.gnome.org/GNOME/libsoup/-/issues/535
-+	 */
-+	debug_printf (1, "Requesting (start overflowing gint64) 9888888888888019900-\n");
-+	request_single_range_by_string (session, uri, "bytes=9888888888888019900-",
-+					SOUP_STATUS_OK);
-+
-+	/* More ranges than the server is willing to coalesce, which is
-+	 * rejected rather than answered with the whole body.
-+	 * https://gitlab.gnome.org/GNOME/libsoup/-/issues/538
-+	 */
-+	debug_printf (1, "Requesting (more ranges than the limit)\n");
-+	range = g_string_new ("bytes=");
-+	for (i = 0; i < MAX_RANGES + 1; i++)
-+		g_string_append (range, i > 0 ? ",0-0" : "0-0");
-+	request_single_range_by_string (session, uri, range->str,
-+					SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
-+	g_string_free (range, TRUE);
-+}
-+
- static void
- do_libsoup_range_test (void)
- {
-@@ -488,6 +832,7 @@ do_libsoup_range_test (void)
- 	base_uri = soup_test_server_get_uri (server, "http", NULL);
- 	base_uri_str = g_uri_to_string (base_uri);
- 	do_range_test (session, base_uri_str, TRUE, TRUE);
-+	do_libsoup_only_range_test (session, base_uri_str);
- 	g_uri_unref (base_uri);
- 	g_free (base_uri_str);
- 	soup_test_server_quit_unref (server);
-@@ -512,6 +857,8 @@ main (int argc, char **argv)
- 	g_test_add_func ("/ranges/apache", do_apache_range_test);
- #endif
- 	g_test_add_func ("/ranges/libsoup", do_libsoup_range_test);
-+	g_test_add_func ("/ranges/parsing", do_range_parsing_test);
-+	g_test_add_func ("/ranges/count", do_range_count_test);
- 
- 	ret = g_test_run ();
- 
-diff --git a/tests/server-mem-limit-test.c b/tests/server-mem-limit-test.c
-index 65dc875e..ee20ba9b 100644
---- a/tests/server-mem-limit-test.c
-+++ b/tests/server-mem-limit-test.c
-@@ -4,6 +4,7 @@
-  */
- 
- #include "test-utils.h"
-+#include "soup-message-headers-private.h"
- 
- #include <sys/resource.h>
- 
-@@ -81,46 +82,66 @@ server_file_callback (SoupServer        *server,
- }
- 
- static void
--do_ranges_overlaps_test (ServerData *sd, gconstpointer test_data)
-+request_ranges (ServerData *sd, const char *range, SoupStatus expected_status)
- {
- 	SoupSession *session;
- 	SoupMessage *msg;
--	GString *range;
- 	GUri *uri;
--	const char *chunk = ",0,0,0,0,0,0,0,0,0,0,0";
--
--	g_test_bug ("428");
--
--	#ifdef G_OS_WIN32
--	g_test_skip ("Cannot run under windows");
--	return;
--	#endif
--
--	range = g_string_sized_new (99 * 1024);
--	g_string_append (range, "bytes=1024");
--	while (range->len < 99 * 1024)
--		g_string_append (range, chunk);
- 
- 	session = soup_test_session_new (NULL);
--	server_add_handler (sd, "/file", server_file_callback, NULL, NULL);
- 
- 	uri = g_uri_parse_relative (sd->base_uri, "/file", SOUP_HTTP_URI_FLAGS, NULL);
- 
- 	msg = soup_message_new_from_uri ("GET", uri);
--	soup_message_headers_append (soup_message_get_request_headers (msg), "Range", range->str);
-+	soup_message_headers_append (soup_message_get_request_headers (msg), "Range", range);
- 
- 	soup_test_session_send_message (session, msg);
- 
--	soup_test_assert_message_status (msg, SOUP_STATUS_PARTIAL_CONTENT);
-+	soup_test_assert_message_status (msg, expected_status);
- 
- 	g_object_unref (msg);
--
--	g_string_free (range, TRUE);
- 	g_uri_unref (uri);
- 
- 	soup_test_session_abort_unref (session);
- }
- 
-+static void
-+do_ranges_overlaps_test (ServerData *sd, gconstpointer test_data)
-+{
-+	GString *range;
-+	const char *chunk = ",0,0,0,0,0,0,0,0,0,0,0";
-+	int i;
-+
-+	g_test_bug ("428");
-+
-+	#ifdef G_OS_WIN32
-+	g_test_skip ("Cannot run under windows");
-+	return;
-+	#endif
-+
-+	server_add_handler (sd, "/file", server_file_callback, NULL, NULL);
-+
-+	/* Requesting the same range many times over used to make the server
-+	 * allocate a response proportional to the number of ranges instead of
-+	 * coalescing them into one. Each "0" here is an open ended range
-+	 * covering the whole body, so they all collapse into a single range.
-+	 */
-+	range = g_string_new ("bytes=1024");
-+	for (i = 1; i < MAX_RANGES; i++)
-+		g_string_append (range, ",0");
-+	request_ranges (sd, range->str, SOUP_STATUS_PARTIAL_CONTENT);
-+	g_string_free (range, TRUE);
-+
-+	/* A header listing more ranges than the server is willing to coalesce
-+	 * is rejected outright. */
-+	range = g_string_sized_new ((gsize)99 * 1024);
-+	g_string_append (range, "bytes=1024");
-+	while (range->len < (gssize)99 * 1024)
-+		g_string_append (range, chunk);
-+	request_ranges (sd, range->str, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE);
-+	g_string_free (range, TRUE);
-+}
-+
- int
- main (int argc, char **argv)
- {
--- 
-GitLab
-

diff --git a/libsoup3.spec b/libsoup3.spec
index ae1bbeb..fcbc341 100644
--- a/libsoup3.spec
+++ b/libsoup3.spec
@@ -7,7 +7,7 @@
 %endif
 
 Name:    libsoup3
-Version: 3.7.2
+Version: 3.7.3
 Release: %autorelease
 Summary: Soup, an HTTP library implementation
 
@@ -21,14 +21,6 @@ Patch:   no-ntlm-in-fips-mode.patch
 # https://gitlab.gnome.org/GNOME/libsoup/-/work_items/530
 Patch:   skip-logger-test-on-32bit.patch
 
-Patch:   CVE-2026-77680.patch
-Patch:   CVE-2026-15711.patch
-Patch:   CVE-2026-15714.patch
-Patch:   CVE-2026-15709.patch
-Patch:   CVE-2026-15713.patch
-Patch:   CVE-2026-15712.patch
-
-
 BuildRequires: gcc
 BuildRequires: gettext
 BuildRequires: glib-networking >= %{glib2_version}

diff --git a/sources b/sources
index d56d967..151acd1 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (libsoup-3.7.2.tar.xz) = 89642fe052557754e151f0d705fa6bca135bc01b1f5e3d2b1f8da67b708a9ffba4b40f923b6a1019a6e2fa28fedb7dc30bed64f98613e4b7139e98dc197fca49
+SHA512 (libsoup-3.7.3.tar.xz) = 44e166742ba649e9b0e6b00d4bcbc80685be8f328a425fcbe1efd960121c33c89b668b19fef2723c93c92af6729d953b5353d133c47d4d18d74886537daa36f6

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-24 18:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-24 18:36 [rpms/libsoup3] rawhide: Update to 3.7.3 and drop upstreamed CVE patches Petr Schindler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox