Compare commits
No commits in common. "c8" and "c9-beta" have entirely different histories.
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/libsoup-2.62.3.tar.xz
|
||||
SOURCES/libsoup-2.72.0.tar.xz
|
||||
|
||||
@ -1 +1 @@
|
||||
8b9c743348b1f9fc044c6abf3431899154e93ad1 SOURCES/libsoup-2.62.3.tar.xz
|
||||
6aaed6b49b13e287b7c3bba546ba49fec4ea72a5 SOURCES/libsoup-2.72.0.tar.xz
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
From d9c729aa5a7991182fa7bdb8d94442f8f0cf055b Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Fri, 19 Jul 2019 14:56:05 +0200
|
||||
Subject: [PATCH] WebSockets: ignore any messages after close has been sent and
|
||||
received
|
||||
|
||||
We currently ignore data frames when close has been received, but we
|
||||
should also ignore any frame after close has been sent and received.
|
||||
Currently, if we receive two close frames we end up with the code and
|
||||
reason of the second frame, while the RFC says: "The WebSocket
|
||||
Connection Close Code is defined as the status code contained in the
|
||||
first Close control frame received by the application implementing
|
||||
this protocol."
|
||||
---
|
||||
libsoup/soup-websocket-connection.c | 3 ++
|
||||
tests/websocket-test.c | 48 +++++++++++++++++++++++++++++
|
||||
2 files changed, 51 insertions(+)
|
||||
|
||||
diff --git libsoup/soup-websocket-connection.c libsoup/soup-websocket-connection.c
|
||||
--- a/libsoup/soup-websocket-connection.c
|
||||
+++ b/libsoup/soup-websocket-connection.c
|
||||
@@ -690,6 +690,9 @@
|
||||
SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
GBytes *message;
|
||||
|
||||
+ if (pv->close_sent && pv->close_received)
|
||||
+ return;
|
||||
+
|
||||
if (control) {
|
||||
/* Control frames must never be fragmented */
|
||||
if (!fin) {
|
||||
--- a/tests/websocket-test.c
|
||||
+++ b/tests/websocket-test.c
|
||||
@@ -707,6 +707,49 @@
|
||||
}
|
||||
|
||||
static gpointer
|
||||
+close_after_close_server_thread (gpointer user_data)
|
||||
+{
|
||||
+ Test *test = user_data;
|
||||
+ gsize written;
|
||||
+ const char frames[] =
|
||||
+ "\x88\x09\x03\xe8""reason1"
|
||||
+ "\x88\x09\x03\xe8""reason2";
|
||||
+ GError *error = NULL;
|
||||
+
|
||||
+ g_mutex_lock (&test->mutex);
|
||||
+ g_mutex_unlock (&test->mutex);
|
||||
+
|
||||
+ g_output_stream_write_all (g_io_stream_get_output_stream (test->raw_server),
|
||||
+ frames, sizeof (frames) -1, &written, NULL, &error);
|
||||
+ g_assert_no_error (error);
|
||||
+ g_assert_cmpuint (written, ==, sizeof (frames) - 1);
|
||||
+ g_io_stream_close (test->raw_server, NULL, &error);
|
||||
+ g_assert_no_error (error);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_close_after_close (Test *test,
|
||||
+ gconstpointer data)
|
||||
+{
|
||||
+ GThread *thread;
|
||||
+
|
||||
+ g_mutex_lock (&test->mutex);
|
||||
+
|
||||
+ thread = g_thread_new ("close-after-close-thread", close_after_close_server_thread, test);
|
||||
+
|
||||
+ soup_websocket_connection_close (test->client, SOUP_WEBSOCKET_CLOSE_NORMAL, "reason1");
|
||||
+ g_mutex_unlock (&test->mutex);
|
||||
+
|
||||
+ g_thread_join (thread);
|
||||
+
|
||||
+ WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
|
||||
+ g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_NORMAL);
|
||||
+ g_assert_cmpstr (soup_websocket_connection_get_close_data (test->client), ==, "reason1");
|
||||
+}
|
||||
+
|
||||
+static gpointer
|
||||
timeout_server_thread (gpointer user_data)
|
||||
{
|
||||
Test *test = user_data;
|
||||
@@ -918,6 +961,11 @@
|
||||
test_message_after_closing,
|
||||
teardown_soup_connection);
|
||||
|
||||
+ g_test_add ("/websocket/direct/close-after-close", Test, NULL,
|
||||
+ setup_half_direct_connection,
|
||||
+ test_close_after_close,
|
||||
+ teardown_direct_connection);
|
||||
+
|
||||
|
||||
g_test_add ("/websocket/direct/protocol-negotiate", Test, NULL, NULL,
|
||||
test_protocol_negotiate_direct,
|
||||
@ -1,152 +0,0 @@
|
||||
From 109bb2f692c746bc63a0ade8737b584aecb0b1ad Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Thu, 27 Jun 2019 16:03:21 +0200
|
||||
Subject: [PATCH] WebSockets: allow null characters in text messages data
|
||||
|
||||
RFC 6455 says that text messages should contains valid UTF-8, and null
|
||||
characters valid according to RFC 3629. However, we are using
|
||||
g_utf8_validate(), which considers null characters as errors, to
|
||||
validate WebSockets text messages. This patch adds an internal
|
||||
utf8_validate() function based on g_utf8_validate() but allowing null
|
||||
characters and just returning a gboolean since we are always ignoring
|
||||
the end parameter in case of errors.
|
||||
soup_websocket_connection_send_text() assumes the given text is null
|
||||
terminated, so we need a new public function to allow sending text
|
||||
messages containing null characters. This patch adds
|
||||
soup_websocket_connection_send_message() that receives a
|
||||
SoupWebsocketDataType and GBytes, which is consistent with
|
||||
SoupWebsocketConnection::message signal.
|
||||
|
||||
For RHEL backport, drop the addition of soup_websocket_connection_send_message()
|
||||
as we don't need it and don't want to expose new API.
|
||||
diff --git libsoup/soup-websocket-connection.c libsoup/soup-websocket-connection.c
|
||||
index 66bd6871..67a98731 100644
|
||||
--- a/libsoup/soup-websocket-connection.c
|
||||
+++ b/libsoup/soup-websocket-connection.c
|
||||
@@ -155,6 +155,82 @@
|
||||
|
||||
static void protocol_error_and_close (SoupWebsocketConnection *self);
|
||||
|
||||
+/* Code below is based on g_utf8_validate() implementation,
|
||||
+ * but handling NULL characters as valid, as expected by
|
||||
+ * WebSockets and compliant with RFC 3629.
|
||||
+ */
|
||||
+#define VALIDATE_BYTE(mask, expect) \
|
||||
+ G_STMT_START { \
|
||||
+ if (G_UNLIKELY((*(guchar *)p & (mask)) != (expect))) \
|
||||
+ return FALSE; \
|
||||
+ } G_STMT_END
|
||||
+
|
||||
+/* see IETF RFC 3629 Section 4 */
|
||||
+static gboolean
|
||||
+utf8_validate (const char *str,
|
||||
+ gsize max_len)
|
||||
+
|
||||
+{
|
||||
+ const gchar *p;
|
||||
+
|
||||
+ for (p = str; ((p - str) < max_len); p++) {
|
||||
+ if (*(guchar *)p < 128)
|
||||
+ /* done */;
|
||||
+ else {
|
||||
+ if (*(guchar *)p < 0xe0) { /* 110xxxxx */
|
||||
+ if (G_UNLIKELY (max_len - (p - str) < 2))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (G_UNLIKELY (*(guchar *)p < 0xc2))
|
||||
+ return FALSE;
|
||||
+ } else {
|
||||
+ if (*(guchar *)p < 0xf0) { /* 1110xxxx */
|
||||
+ if (G_UNLIKELY (max_len - (p - str) < 3))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ switch (*(guchar *)p++ & 0x0f) {
|
||||
+ case 0:
|
||||
+ VALIDATE_BYTE(0xe0, 0xa0); /* 0xa0 ... 0xbf */
|
||||
+ break;
|
||||
+ case 0x0d:
|
||||
+ VALIDATE_BYTE(0xe0, 0x80); /* 0x80 ... 0x9f */
|
||||
+ break;
|
||||
+ default:
|
||||
+ VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
||||
+ }
|
||||
+ } else if (*(guchar *)p < 0xf5) { /* 11110xxx excluding out-of-range */
|
||||
+ if (G_UNLIKELY (max_len - (p - str) < 4))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ switch (*(guchar *)p++ & 0x07) {
|
||||
+ case 0:
|
||||
+ VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
||||
+ if (G_UNLIKELY((*(guchar *)p & 0x30) == 0))
|
||||
+ return FALSE;
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ VALIDATE_BYTE(0xf0, 0x80); /* 0x80 ... 0x8f */
|
||||
+ break;
|
||||
+ default:
|
||||
+ VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
||||
+ }
|
||||
+ p++;
|
||||
+ VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
||||
+ } else {
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ p++;
|
||||
+ VALIDATE_BYTE(0xc0, 0x80); /* 10xxxxxx */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+#undef VALIDATE_BYTE
|
||||
+
|
||||
static void
|
||||
frame_free (gpointer data)
|
||||
{
|
||||
@@ -629,7 +705,7 @@
|
||||
data += 2;
|
||||
len -= 2;
|
||||
|
||||
- if (!g_utf8_validate ((char *)data, len, NULL)) {
|
||||
+ if (!utf8_validate ((const char *)data, len)) {
|
||||
g_debug ("received non-UTF8 close data: %d '%.*s' %d", (int)len, (int)len, (char *)data, (int)data[0]);
|
||||
protocol_error_and_close (self);
|
||||
return;
|
||||
@@ -777,9 +853,8 @@
|
||||
/* Actually deliver the message? */
|
||||
if (fin) {
|
||||
if (pv->message_opcode == 0x01 &&
|
||||
- !g_utf8_validate((char *)pv->message_data->data,
|
||||
- pv->message_data->len,
|
||||
- NULL)) {
|
||||
+ !utf8_validate((const char *)pv->message_data->data,
|
||||
+ pv->message_data->len)) {
|
||||
|
||||
g_debug ("received invalid non-UTF8 text data");
|
||||
|
||||
@@ -1699,7 +1774,9 @@
|
||||
* @self: the WebSocket
|
||||
* @text: the message contents
|
||||
*
|
||||
- * Send a text (UTF-8) message to the peer.
|
||||
+ * Send a %NULL-terminated text (UTF-8) message to the peer. If you need
|
||||
+ * to send text messages containing %NULL characters use
|
||||
+ * soup_websocket_connection_send_message() instead.
|
||||
*
|
||||
* The message is queued to be sent and will be sent when the main loop
|
||||
* is run.
|
||||
@@ -1717,7 +1794,7 @@
|
||||
g_return_if_fail (text != NULL);
|
||||
|
||||
length = strlen (text);
|
||||
- g_return_if_fail (g_utf8_validate (text, length, NULL));
|
||||
+ g_return_if_fail (utf8_validate (text, length));
|
||||
|
||||
send_message (self, SOUP_WEBSOCKET_QUEUE_NORMAL, 0x01, (const guint8 *) text, length);
|
||||
}
|
||||
--
|
||||
2.26.2
|
||||
|
||||
@ -1,299 +0,0 @@
|
||||
From 35f1bac5ff9ec694e64b65e51f0e7a3226aa3aaf Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Wed, 28 Aug 2019 10:51:18 +0200
|
||||
Subject: [PATCH] WebSockets: only poll IO stream when needed
|
||||
|
||||
Instead of having two pollable sources constantly running, always try to
|
||||
read/write without blocking and start polling if the operation returns
|
||||
G_IO_ERROR_WOULD_BLOCK. This patch also fixes test
|
||||
/websocket/direct/close-after-close that was passing but not actually
|
||||
testing what we wanted, because the client close was never sent. When
|
||||
the mutex is released, the frame has been queued, but not sent.
|
||||
|
||||
diff --git libsoup/soup-websocket-connection.c libsoup/soup-websocket-connection.c
|
||||
index 345040fe..6afbbe67 100644
|
||||
--- a/libsoup/soup-websocket-connection.c
|
||||
+++ b/libsoup/soup-websocket-connection.c
|
||||
@@ -147,6 +147,7 @@
|
||||
};
|
||||
|
||||
#define MAX_INCOMING_PAYLOAD_SIZE_DEFAULT 128 * 1024
|
||||
+#define READ_BUFFER_SIZE 1024
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (SoupWebsocketConnection, soup_websocket_connection, G_TYPE_OBJECT)
|
||||
|
||||
@@ -155,6 +156,11 @@
|
||||
|
||||
static void protocol_error_and_close (SoupWebsocketConnection *self);
|
||||
|
||||
+static gboolean on_web_socket_input (GObject *pollable_stream,
|
||||
+ gpointer user_data);
|
||||
+static gboolean on_web_socket_output (GObject *pollable_stream,
|
||||
+ gpointer user_data);
|
||||
+
|
||||
/* Code below is based on g_utf8_validate() implementation,
|
||||
* but handling NULL characters as valid, as expected by
|
||||
* WebSockets and compliant with RFC 3629.
|
||||
@@ -283,7 +289,20 @@
|
||||
}
|
||||
|
||||
static void
|
||||
-stop_input (SoupWebsocketConnection *self)
|
||||
+soup_websocket_connection_start_input_source (SoupWebsocketConnection *self)
|
||||
+{
|
||||
+ SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
+
|
||||
+ if (pv->input_source)
|
||||
+ return;
|
||||
+
|
||||
+ pv->input_source = g_pollable_input_stream_create_source (pv->input, NULL);
|
||||
+ g_source_set_callback (pv->input_source, (GSourceFunc)on_web_socket_input, self, NULL);
|
||||
+ g_source_attach (pv->input_source, pv->main_context);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+soup_websocket_connection_stop_input_source (SoupWebsocketConnection *self)
|
||||
{
|
||||
SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
|
||||
@@ -296,7 +315,20 @@
|
||||
}
|
||||
|
||||
static void
|
||||
-stop_output (SoupWebsocketConnection *self)
|
||||
+soup_websocket_connection_start_output_source (SoupWebsocketConnection *self)
|
||||
+{
|
||||
+ SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
+
|
||||
+ if (pv->output_source)
|
||||
+ return;
|
||||
+
|
||||
+ pv->output_source = g_pollable_output_stream_create_source (pv->output, NULL);
|
||||
+ g_source_set_callback (pv->output_source, (GSourceFunc)on_web_socket_output, self, NULL);
|
||||
+ g_source_attach (pv->output_source, pv->main_context);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+soup_websocket_connection_stop_output_source (SoupWebsocketConnection *self)
|
||||
{
|
||||
SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
|
||||
@@ -341,8 +373,8 @@
|
||||
close_io_stop_timeout (self);
|
||||
|
||||
if (!pv->io_closing) {
|
||||
- stop_input (self);
|
||||
- stop_output (self);
|
||||
+ soup_websocket_connection_stop_input_source (self);
|
||||
+ soup_websocket_connection_stop_output_source (self);
|
||||
pv->io_closing = TRUE;
|
||||
g_debug ("closing io stream");
|
||||
g_io_stream_close_async (pv->io_stream, G_PRIORITY_DEFAULT,
|
||||
@@ -359,7 +391,7 @@
|
||||
GSocket *socket;
|
||||
GError *error = NULL;
|
||||
|
||||
- stop_output (self);
|
||||
+ soup_websocket_connection_stop_output_source (self);
|
||||
|
||||
if (G_IS_SOCKET_CONNECTION (pv->io_stream)) {
|
||||
socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (pv->io_stream));
|
||||
@@ -612,9 +644,6 @@
|
||||
self->pv->connection_type == SOUP_WEBSOCKET_CONNECTION_SERVER ? "server" : "client",
|
||||
payload_len, self->pv->max_incoming_payload_size);
|
||||
emit_error_and_close (self, error, TRUE);
|
||||
-
|
||||
- /* The input is in an invalid state now */
|
||||
- stop_input (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -981,32 +1010,31 @@
|
||||
;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
-on_web_socket_input (GObject *pollable_stream,
|
||||
- gpointer user_data)
|
||||
+static void
|
||||
+soup_websocket_connection_read (SoupWebsocketConnection *self)
|
||||
{
|
||||
- SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (user_data);
|
||||
SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
GError *error = NULL;
|
||||
gboolean end = FALSE;
|
||||
gssize count;
|
||||
gsize len;
|
||||
|
||||
+ soup_websocket_connection_stop_input_source (self);
|
||||
+
|
||||
do {
|
||||
len = pv->incoming->len;
|
||||
- g_byte_array_set_size (pv->incoming, len + 1024);
|
||||
+ g_byte_array_set_size (pv->incoming, len + READ_BUFFER_SIZE);
|
||||
|
||||
count = g_pollable_input_stream_read_nonblocking (pv->input,
|
||||
pv->incoming->data + len,
|
||||
- 1024, NULL, &error);
|
||||
-
|
||||
+ READ_BUFFER_SIZE, NULL, &error);
|
||||
if (count < 0) {
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
g_error_free (error);
|
||||
count = 0;
|
||||
} else {
|
||||
emit_error_and_close (self, error, TRUE);
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
} else if (count == 0) {
|
||||
end = TRUE;
|
||||
@@ -1026,16 +1054,24 @@
|
||||
}
|
||||
|
||||
close_io_stream (self);
|
||||
+ return;
|
||||
}
|
||||
|
||||
- return TRUE;
|
||||
+ soup_websocket_connection_start_input_source (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-on_web_socket_output (GObject *pollable_stream,
|
||||
- gpointer user_data)
|
||||
+on_web_socket_input (GObject *pollable_stream,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ soup_websocket_connection_read (SOUP_WEBSOCKET_CONNECTION (user_data));
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+soup_websocket_connection_write (SoupWebsocketConnection *self)
|
||||
{
|
||||
- SoupWebsocketConnection *self = SOUP_WEBSOCKET_CONNECTION (user_data);
|
||||
SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
const guint8 *data;
|
||||
GError *error = NULL;
|
||||
@@ -1043,19 +1079,18 @@
|
||||
gssize count;
|
||||
gsize len;
|
||||
|
||||
+ soup_websocket_connection_stop_output_source (self);
|
||||
+
|
||||
if (soup_websocket_connection_get_state (self) == SOUP_WEBSOCKET_STATE_CLOSED) {
|
||||
g_debug ("Ignoring message since the connection is closed");
|
||||
- stop_output (self);
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
|
||||
frame = g_queue_peek_head (&pv->outgoing);
|
||||
|
||||
/* No more frames to send */
|
||||
- if (frame == NULL) {
|
||||
- stop_output (self);
|
||||
- return TRUE;
|
||||
- }
|
||||
+ if (frame == NULL)
|
||||
+ return;
|
||||
|
||||
data = g_bytes_get_data (frame->data, &len);
|
||||
g_assert (len > 0);
|
||||
@@ -1075,7 +1110,7 @@
|
||||
frame->pending = TRUE;
|
||||
} else {
|
||||
emit_error_and_close (self, error, TRUE);
|
||||
- return FALSE;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1093,23 +1128,21 @@
|
||||
}
|
||||
}
|
||||
frame_free (frame);
|
||||
+
|
||||
+ if (g_queue_is_empty (&pv->outgoing))
|
||||
+ return;
|
||||
}
|
||||
|
||||
- return TRUE;
|
||||
+ soup_websocket_connection_start_output_source (self);
|
||||
}
|
||||
|
||||
-static void
|
||||
-start_output (SoupWebsocketConnection *self)
|
||||
+static gboolean
|
||||
+on_web_socket_output (GObject *pollable_stream,
|
||||
+ gpointer user_data)
|
||||
{
|
||||
- SoupWebsocketConnectionPrivate *pv = self->pv;
|
||||
-
|
||||
- if (pv->output_source)
|
||||
- return;
|
||||
+ soup_websocket_connection_write (SOUP_WEBSOCKET_CONNECTION (user_data));
|
||||
|
||||
- g_debug ("starting output source");
|
||||
- pv->output_source = g_pollable_output_stream_create_source (pv->output, NULL);
|
||||
- g_source_set_callback (pv->output_source, (GSourceFunc)on_web_socket_output, self, NULL);
|
||||
- g_source_attach (pv->output_source, pv->main_context);
|
||||
+ return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1150,7 +1183,7 @@
|
||||
g_queue_push_tail (&pv->outgoing, frame);
|
||||
}
|
||||
|
||||
- start_output (self);
|
||||
+ soup_websocket_connection_write (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1175,9 +1208,7 @@
|
||||
pv->output = G_POLLABLE_OUTPUT_STREAM (os);
|
||||
g_return_if_fail (g_pollable_output_stream_can_poll (pv->output));
|
||||
|
||||
- pv->input_source = g_pollable_input_stream_create_source (pv->input, NULL);
|
||||
- g_source_set_callback (pv->input_source, (GSourceFunc)on_web_socket_input, self, NULL);
|
||||
- g_source_attach (pv->input_source, pv->main_context);
|
||||
+ soup_websocket_connection_start_input_source (self);
|
||||
}
|
||||
|
||||
static void
|
||||
diff --git tests/websocket-test.c tests/websocket-test.c
|
||||
index 146fdf82..26d064df 100644
|
||||
--- a/tests/websocket-test.c
|
||||
+++ b/tests/websocket-test.c
|
||||
@@ -733,6 +733,7 @@
|
||||
const char frames[] =
|
||||
"\x88\x09\x03\xe8""reason1"
|
||||
"\x88\x09\x03\xe8""reason2";
|
||||
+ GSocket *socket;
|
||||
GError *error = NULL;
|
||||
|
||||
g_mutex_lock (&test->mutex);
|
||||
@@ -742,7 +743,8 @@
|
||||
frames, sizeof (frames) -1, &written, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_assert_cmpuint (written, ==, sizeof (frames) - 1);
|
||||
- g_io_stream_close (test->raw_server, NULL, &error);
|
||||
+ socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (test->raw_server));
|
||||
+ g_socket_shutdown (socket, FALSE, TRUE, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
return NULL;
|
||||
@@ -766,6 +768,7 @@
|
||||
WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
|
||||
g_assert_cmpuint (soup_websocket_connection_get_close_code (test->client), ==, SOUP_WEBSOCKET_CLOSE_NORMAL);
|
||||
g_assert_cmpstr (soup_websocket_connection_get_close_data (test->client), ==, "reason1");
|
||||
+ g_io_stream_close (test->raw_server, NULL, NULL);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
--
|
||||
2.26.2
|
||||
|
||||
@ -1,356 +0,0 @@
|
||||
diff -up libsoup-2.62.3/libsoup/soup-auth-ntlm.c.4 libsoup-2.62.3/libsoup/soup-auth-ntlm.c
|
||||
--- libsoup-2.62.3/libsoup/soup-auth-ntlm.c.4 2021-03-12 07:30:03.366088932 +0100
|
||||
+++ libsoup-2.62.3/libsoup/soup-auth-ntlm.c 2021-03-12 07:30:25.296043405 +0100
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
+#include <stdio.h>
|
||||
+
|
||||
#include <glib.h>
|
||||
|
||||
#include "soup-auth-ntlm.h"
|
||||
@@ -26,14 +28,20 @@ static char *soup_ntlm_request
|
||||
static gboolean soup_ntlm_parse_challenge (const char *challenge,
|
||||
char **nonce,
|
||||
char **default_domain,
|
||||
- gboolean *ntlmv2_session);
|
||||
-static char *soup_ntlm_response (const char *nonce,
|
||||
+ gboolean *ntlmv2_session,
|
||||
+ gboolean *negotiate_target,
|
||||
+ char **target_info,
|
||||
+ size_t *target_info_sz);
|
||||
+static char *soup_ntlm_response (const char *nonce,
|
||||
const char *user,
|
||||
guchar nt_hash[21],
|
||||
guchar lm_hash[21],
|
||||
const char *host,
|
||||
const char *domain,
|
||||
- gboolean ntlmv2_session);
|
||||
+ gboolean ntlmv2_session,
|
||||
+ gboolean negotiate_target,
|
||||
+ const char *target_info,
|
||||
+ size_t target_info_sz);
|
||||
|
||||
typedef enum {
|
||||
SOUP_NTLM_NEW,
|
||||
@@ -49,6 +57,9 @@ typedef struct {
|
||||
char *nonce;
|
||||
char *response_header;
|
||||
gboolean ntlmv2_session;
|
||||
+ gboolean negotiate_target;
|
||||
+ char *target_info;
|
||||
+ size_t target_info_sz;
|
||||
} SoupNTLMConnectionState;
|
||||
|
||||
typedef enum {
|
||||
@@ -280,6 +291,7 @@ soup_auth_ntlm_free_connection_state (So
|
||||
|
||||
g_free (conn->nonce);
|
||||
g_free (conn->response_header);
|
||||
+ g_free (conn->target_info);
|
||||
g_slice_free (SoupNTLMConnectionState, conn);
|
||||
}
|
||||
|
||||
@@ -339,7 +351,8 @@ soup_auth_ntlm_update_connection (SoupCo
|
||||
|
||||
if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
|
||||
priv->domain ? NULL : &priv->domain,
|
||||
- &conn->ntlmv2_session)) {
|
||||
+ &conn->ntlmv2_session, &conn->negotiate_target,
|
||||
+ &conn->target_info, &conn->target_info_sz)) {
|
||||
conn->state = SOUP_NTLM_FAILED;
|
||||
return FALSE;
|
||||
}
|
||||
@@ -521,7 +534,10 @@ soup_auth_ntlm_get_connection_authorizat
|
||||
priv->lm_hash,
|
||||
NULL,
|
||||
priv->domain,
|
||||
- conn->ntlmv2_session);
|
||||
+ conn->ntlmv2_session,
|
||||
+ conn->negotiate_target,
|
||||
+ conn->target_info,
|
||||
+ conn->target_info_sz);
|
||||
}
|
||||
g_clear_pointer (&conn->nonce, g_free);
|
||||
conn->state = SOUP_NTLM_SENT_RESPONSE;
|
||||
@@ -647,14 +663,20 @@ typedef struct {
|
||||
#define NTLM_CHALLENGE_NONCE_OFFSET 24
|
||||
#define NTLM_CHALLENGE_NONCE_LENGTH 8
|
||||
#define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
|
||||
+#define NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET 40
|
||||
|
||||
#define NTLM_CHALLENGE_FLAGS_OFFSET 20
|
||||
#define NTLM_FLAGS_NEGOTIATE_NTLMV2 0x00080000
|
||||
+#define NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION 0x00800000
|
||||
+#define NTLM_FLAGS_REQUEST_TARGET 0x00000004
|
||||
|
||||
#define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
|
||||
#define NTLM_RESPONSE_FLAGS 0x8201
|
||||
+#define NTLM_RESPONSE_TARGET_INFORMATION_OFFSET 44
|
||||
#define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000
|
||||
|
||||
+#define HMAC_MD5_LENGTH 16
|
||||
+
|
||||
typedef struct {
|
||||
guchar header[12];
|
||||
|
||||
@@ -686,10 +708,14 @@ static gboolean
|
||||
soup_ntlm_parse_challenge (const char *challenge,
|
||||
char **nonce,
|
||||
char **default_domain,
|
||||
- gboolean *ntlmv2_session)
|
||||
+ gboolean *ntlmv2_session,
|
||||
+ gboolean *negotiate_target,
|
||||
+ char **target_info,
|
||||
+ size_t *target_info_sz)
|
||||
{
|
||||
gsize clen;
|
||||
NTLMString domain;
|
||||
+ NTLMString target;
|
||||
guchar *chall;
|
||||
guint32 flags;
|
||||
|
||||
@@ -703,6 +729,14 @@ soup_ntlm_parse_challenge (const char *c
|
||||
memcpy (&flags, chall + NTLM_CHALLENGE_FLAGS_OFFSET, sizeof(flags));
|
||||
flags = GUINT_FROM_LE (flags);
|
||||
*ntlmv2_session = (flags & NTLM_FLAGS_NEGOTIATE_NTLMV2) ? TRUE : FALSE;
|
||||
+ /* To know if NTLMv2 responses should be calculated */
|
||||
+ *negotiate_target = (flags & NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION ) ? TRUE : FALSE;
|
||||
+ if (*negotiate_target) {
|
||||
+ if (clen < NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET + sizeof (target)) {
|
||||
+ g_free (chall);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if (default_domain) {
|
||||
memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
|
||||
@@ -723,6 +757,19 @@ soup_ntlm_parse_challenge (const char *c
|
||||
*nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
|
||||
NTLM_CHALLENGE_NONCE_LENGTH);
|
||||
}
|
||||
+ /* For NTLMv2 response */
|
||||
+ if (*negotiate_target && target_info) {
|
||||
+ memcpy (&target, chall + NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET, sizeof (target));
|
||||
+ target.length = GUINT16_FROM_LE (target.length);
|
||||
+ target.offset = GUINT16_FROM_LE (target.offset);
|
||||
+
|
||||
+ if (clen < target.length + target.offset) {
|
||||
+ g_free (chall);
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+ *target_info = g_memdup (chall + target.offset, target.length);
|
||||
+ *target_info_sz = target.length;
|
||||
+ }
|
||||
|
||||
g_free (chall);
|
||||
return TRUE;
|
||||
@@ -761,6 +808,115 @@ calc_ntlm2_session_response (const char
|
||||
calc_response (nt_hash, ntlmv2_hash, nt_resp);
|
||||
}
|
||||
|
||||
+/* Compute HMAC-MD5 with Glib function*/
|
||||
+static void
|
||||
+calc_hmac_md5 (unsigned char *hmac, const guchar *key, gsize key_sz, const guchar *data, gsize data_sz)
|
||||
+{
|
||||
+ char *hmac_hex, *hex_pos;
|
||||
+ size_t count;
|
||||
+
|
||||
+ hmac_hex = g_compute_hmac_for_data(G_CHECKSUM_MD5, key, key_sz, data, data_sz);
|
||||
+ hex_pos = hmac_hex;
|
||||
+ for (count = 0; count < HMAC_MD5_LENGTH; count++)
|
||||
+ {
|
||||
+ /* The 'hh' sscanf format modifier is C99, so we enable it on
|
||||
+ * non-Windows or if __USE_MINGW_ANSI_STDIO is enabled or`
|
||||
+ * if we are building on Visual Studio 2015 or later
|
||||
+ */
|
||||
+#if !defined (G_OS_WIN32) || (__USE_MINGW_ANSI_STDIO == 1) || (_MSC_VER >= 1900)
|
||||
+ sscanf(hex_pos, "%2hhx", &hmac[count]);
|
||||
+#else
|
||||
+ unsigned int tmp_hmac;
|
||||
+ sscanf(hex_pos, "%2x", &tmp_hmac);
|
||||
+ hmac[count] = (guint8)tmp_hmac;
|
||||
+#endif
|
||||
+
|
||||
+ hex_pos += 2;
|
||||
+ }
|
||||
+ g_free(hmac_hex);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+calc_ntlmv2_response (const char *user, const char *domain,
|
||||
+ const guchar *nt_hash, const gsize nt_hash_sz,
|
||||
+ const guchar *nonce,
|
||||
+ const char *target_info, size_t target_info_sz,
|
||||
+ guchar *lm_resp, size_t lm_resp_sz,
|
||||
+ guchar *nt_resp, size_t nt_resp_sz)
|
||||
+{
|
||||
+ const unsigned char blob_signature[] = {0x01,0x01,0x00,0x00};
|
||||
+ const unsigned char blob_reserved[] = {0x00,0x00,0x00,0x00};
|
||||
+ gint64 blob_timestamp;
|
||||
+ unsigned char client_nonce[8];
|
||||
+ const unsigned char blob_unknown[] = {0x00,0x00,0x00,0x00};
|
||||
+
|
||||
+ unsigned char ntv2_hash[HMAC_MD5_LENGTH];
|
||||
+ guchar *nonce_blob, *blob, *p_blob;
|
||||
+ unsigned char nonce_blob_hash[HMAC_MD5_LENGTH];
|
||||
+ unsigned char nonce_client_nonce[16], nonce_client_nonce_hash[HMAC_MD5_LENGTH];
|
||||
+ gchar *user_uppercase, *user_domain, *user_domain_conv;
|
||||
+ gsize user_domain_conv_sz;
|
||||
+ size_t blob_sz;
|
||||
+ int i;
|
||||
+
|
||||
+ /* create HMAC-MD5 hash of Unicode uppercase username and Unicode domain */
|
||||
+ user_uppercase = g_utf8_strup (user, strlen (user));
|
||||
+ user_domain = g_strconcat (user_uppercase, domain, NULL);
|
||||
+ user_domain_conv = g_convert (user_domain, -1, "UCS-2LE", "UTF-8", NULL, &user_domain_conv_sz, NULL);
|
||||
+ calc_hmac_md5 (ntv2_hash, nt_hash, nt_hash_sz, (const guchar *)user_domain_conv, user_domain_conv_sz);
|
||||
+ g_free (user_uppercase);
|
||||
+ g_free (user_domain);
|
||||
+ g_free (user_domain_conv);
|
||||
+
|
||||
+ /* create random client nonce */
|
||||
+ for (i = 0; i < sizeof (client_nonce); i++)
|
||||
+ {
|
||||
+ client_nonce[i] = g_random_int();
|
||||
+ }
|
||||
+
|
||||
+ /* create timestamp for blob
|
||||
+ * LE, 64-bit signed value, number of tenths of a ms since January 1, 1601.*/
|
||||
+ blob_timestamp = GINT64_TO_LE(((unsigned long)time(NULL) + 11644473600) * 10000000);
|
||||
+
|
||||
+ /* create blob */
|
||||
+ blob_sz = sizeof (blob_signature) + sizeof (blob_reserved) +
|
||||
+ sizeof (blob_timestamp) + sizeof (client_nonce) +
|
||||
+ sizeof (blob_unknown) + target_info_sz;
|
||||
+ p_blob = blob = g_malloc (blob_sz);
|
||||
+ memset (blob, 0, blob_sz);
|
||||
+ memcpy (p_blob, blob_signature, sizeof (blob_signature));
|
||||
+ memcpy (p_blob += sizeof (blob_signature), blob_reserved, sizeof (blob_reserved));
|
||||
+ memcpy (p_blob += sizeof (blob_reserved), &blob_timestamp, sizeof (blob_timestamp));
|
||||
+ memcpy (p_blob += sizeof (blob_timestamp), client_nonce, sizeof (client_nonce));
|
||||
+ memcpy (p_blob += sizeof (client_nonce), blob_unknown, sizeof (blob_unknown));
|
||||
+ memcpy (p_blob += sizeof (blob_unknown), target_info, target_info_sz);
|
||||
+
|
||||
+ /* create HMAC-MD5 hash of concatenated nonce and blob */
|
||||
+ nonce_blob = g_malloc (NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
|
||||
+ memcpy (nonce_blob, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
|
||||
+ memcpy (nonce_blob + NTLM_CHALLENGE_NONCE_LENGTH, blob, blob_sz);
|
||||
+ calc_hmac_md5 (nonce_blob_hash, (const guchar *)ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_blob, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
|
||||
+ g_free (nonce_blob);
|
||||
+
|
||||
+ /* create NTv2 response */
|
||||
+ memset (nt_resp, 0, nt_resp_sz);
|
||||
+ memcpy (nt_resp, nonce_blob_hash, sizeof (nonce_blob_hash));
|
||||
+ memcpy (nt_resp + sizeof (nonce_blob_hash), blob, blob_sz);
|
||||
+
|
||||
+ g_free (blob);
|
||||
+
|
||||
+ /* LMv2
|
||||
+ * create HMAC-MD5 hash of concatenated nonce and client nonce
|
||||
+ */
|
||||
+ memcpy (nonce_client_nonce, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
|
||||
+ memcpy (nonce_client_nonce + NTLM_CHALLENGE_NONCE_LENGTH, client_nonce, sizeof (client_nonce));
|
||||
+ calc_hmac_md5 (nonce_client_nonce_hash, (const guchar *) ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_client_nonce, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + sizeof (client_nonce));
|
||||
+
|
||||
+ /* create LMv2 response */
|
||||
+ memset (lm_resp, 0, lm_resp_sz);
|
||||
+ memcpy (lm_resp, nonce_client_nonce_hash, sizeof (nonce_client_nonce_hash));
|
||||
+ memcpy (lm_resp + sizeof (nonce_client_nonce_hash), client_nonce, sizeof (client_nonce));
|
||||
+}
|
||||
|
||||
static char *
|
||||
soup_ntlm_response (const char *nonce,
|
||||
@@ -769,23 +925,45 @@ soup_ntlm_response (const char *nonce,
|
||||
guchar lm_hash[21],
|
||||
const char *host,
|
||||
const char *domain,
|
||||
- gboolean ntlmv2_session)
|
||||
+ gboolean ntlmv2_session,
|
||||
+ gboolean negotiate_target,
|
||||
+ const char *target_info,
|
||||
+ size_t target_info_sz)
|
||||
{
|
||||
+
|
||||
int offset;
|
||||
- gsize hlen, dlen, ulen;
|
||||
- guchar lm_resp[24], nt_resp[24];
|
||||
+ gsize hlen, dlen, ulen, nt_resp_sz;
|
||||
+ guchar lm_resp[24], *nt_resp;
|
||||
char *user_conv, *host_conv, *domain_conv;
|
||||
NTLMResponse resp;
|
||||
char *out, *p;
|
||||
int state, save;
|
||||
|
||||
- if (ntlmv2_session) {
|
||||
+ if (negotiate_target)
|
||||
+ {
|
||||
+ /* nonce_blob_hash 16 + blob_signature 4 + blob_reserved 4 +
|
||||
+ * blob_timestamp 8 + client_nonce 8 + blob_unknown 4 +
|
||||
+ * target_info*/
|
||||
+ nt_resp_sz = NTLM_RESPONSE_TARGET_INFORMATION_OFFSET + target_info_sz;
|
||||
+ } else {
|
||||
+ nt_resp_sz = 24;
|
||||
+ }
|
||||
+ nt_resp = g_malloc (nt_resp_sz);
|
||||
+
|
||||
+ if (ntlmv2_session && !negotiate_target) {
|
||||
calc_ntlm2_session_response (nonce, nt_hash, lm_hash,
|
||||
lm_resp, sizeof(lm_resp), nt_resp);
|
||||
- } else {
|
||||
- /* Compute a regular response */
|
||||
+ } else if (!negotiate_target){
|
||||
+ /* Compute a regular NTLMv1 response */
|
||||
calc_response (nt_hash, (guchar *) nonce, nt_resp);
|
||||
calc_response (lm_hash, (guchar *) nonce, lm_resp);
|
||||
+ } else {
|
||||
+ calc_ntlmv2_response (user, domain,
|
||||
+ nt_hash, 21,
|
||||
+ (guchar *) nonce,
|
||||
+ target_info, target_info_sz,
|
||||
+ lm_resp, sizeof (lm_resp),
|
||||
+ nt_resp, (size_t) nt_resp_sz);
|
||||
}
|
||||
|
||||
memset (&resp, 0, sizeof (resp));
|
||||
@@ -793,7 +971,8 @@ soup_ntlm_response (const char *nonce,
|
||||
resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
|
||||
if (ntlmv2_session)
|
||||
resp.flags |= GUINT32_TO_LE (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
|
||||
-
|
||||
+ if (negotiate_target)
|
||||
+ resp.flags |= GUINT32_TO_LE (NTLM_FLAGS_REQUEST_TARGET);
|
||||
offset = sizeof (resp);
|
||||
|
||||
if (!host)
|
||||
@@ -807,10 +986,10 @@ soup_ntlm_response (const char *nonce,
|
||||
ntlm_set_string (&resp.user, &offset, ulen);
|
||||
ntlm_set_string (&resp.host, &offset, hlen);
|
||||
ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
|
||||
- ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
|
||||
+ ntlm_set_string (&resp.nt_resp, &offset, nt_resp_sz);
|
||||
|
||||
out = g_malloc (((offset + 3) * 4) / 3 + 6);
|
||||
- strncpy (out, "NTLM ", 5);
|
||||
+ memcpy (out, "NTLM ", 5);
|
||||
p = out + 5;
|
||||
|
||||
state = save = 0;
|
||||
@@ -825,7 +1004,7 @@ soup_ntlm_response (const char *nonce,
|
||||
FALSE, p, &state, &save);
|
||||
p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
|
||||
FALSE, p, &state, &save);
|
||||
- p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
|
||||
+ p += g_base64_encode_step (nt_resp, nt_resp_sz,
|
||||
FALSE, p, &state, &save);
|
||||
p += g_base64_encode_close (FALSE, p, &state, &save);
|
||||
*p = '\0';
|
||||
@@ -833,6 +1012,7 @@ soup_ntlm_response (const char *nonce,
|
||||
g_free (domain_conv);
|
||||
g_free (user_conv);
|
||||
g_free (host_conv);
|
||||
+ g_free (nt_resp);
|
||||
|
||||
return out;
|
||||
}
|
||||
@ -1,84 +0,0 @@
|
||||
From 87e8c2ab9f3bc79befb0e3b25ec513cfd36fefe9 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Tue, 21 Jan 2020 11:41:37 +0100
|
||||
Subject: [PATCH] WebSockets: do not start the input source when IO is closing
|
||||
|
||||
We should not schedule a new read after reading the close message, since
|
||||
we don't expect more input. This fixes a crash due to an assert that
|
||||
checks that the input source is NULL when the connection is destroyed
|
||||
that happens when the connection is destroyed in the closed callback.
|
||||
|
||||
Fixes #181
|
||||
---
|
||||
libsoup/soup-websocket-connection.c | 3 ++-
|
||||
tests/websocket-test.c | 33 +++++++++++++++++++++++++++++
|
||||
2 files changed, 35 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c
|
||||
index 2c7fc1161..a4095e1c9 100644
|
||||
--- a/libsoup/soup-websocket-connection.c
|
||||
+++ b/libsoup/soup-websocket-connection.c
|
||||
@@ -1156,7 +1156,8 @@ soup_websocket_connection_read (SoupWebsocketConnection *self)
|
||||
return;
|
||||
}
|
||||
|
||||
- soup_websocket_connection_start_input_source (self);
|
||||
+ if (!pv->io_closing)
|
||||
+ soup_websocket_connection_start_input_source (self);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
|
||||
index b5142612e..5e40cf364 100644
|
||||
--- a/tests/websocket-test.c
|
||||
+++ b/tests/websocket-test.c
|
||||
@@ -1067,6 +1067,34 @@ test_close_after_close (Test *test,
|
||||
g_io_stream_close (test->raw_server, NULL, NULL);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+on_close_unref_connection (SoupWebsocketConnection *ws,
|
||||
+ gpointer user_data)
|
||||
+{
|
||||
+ Test *test = user_data;
|
||||
+
|
||||
+ g_assert_true (test->server == ws);
|
||||
+ g_clear_object (&test->server);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+test_server_unref_connection_on_close (Test *test,
|
||||
+ gconstpointer data)
|
||||
+{
|
||||
+ gboolean close_event_client = FALSE;
|
||||
+
|
||||
+ g_signal_connect (test->client, "closed", G_CALLBACK (on_close_set_flag), &close_event_client);
|
||||
+ g_signal_connect (test->server, "closed", G_CALLBACK (on_close_unref_connection), test);
|
||||
+ soup_websocket_connection_close (test->client, SOUP_WEBSOCKET_CLOSE_GOING_AWAY, "client closed");
|
||||
+ g_assert_cmpint (soup_websocket_connection_get_state (test->client), ==, SOUP_WEBSOCKET_STATE_CLOSING);
|
||||
+
|
||||
+ WAIT_UNTIL (test->server == NULL);
|
||||
+ WAIT_UNTIL (soup_websocket_connection_get_state (test->client) == SOUP_WEBSOCKET_STATE_CLOSED);
|
||||
+
|
||||
+ g_assert_true (close_event_client);
|
||||
+}
|
||||
+
|
||||
static gpointer
|
||||
timeout_server_thread (gpointer user_data)
|
||||
{
|
||||
@@ -1923,6 +1951,11 @@ main (int argc,
|
||||
test_close_after_close,
|
||||
teardown_direct_connection);
|
||||
|
||||
+ g_test_add ("/websocket/soup/server-unref-connection-on-close", Test, NULL,
|
||||
+ setup_soup_connection,
|
||||
+ test_server_unref_connection_on_close,
|
||||
+ teardown_soup_connection);
|
||||
+
|
||||
|
||||
g_test_add ("/websocket/direct/protocol-negotiate", Test, NULL, NULL,
|
||||
test_protocol_negotiate_direct,
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,7 +1,19 @@
|
||||
diff -up libsoup-2.62.2/libsoup/soup-headers.c.cve-2024-52530 libsoup-2.62.2/libsoup/soup-headers.c
|
||||
--- libsoup-2.62.2/libsoup/soup-headers.c.cve-2024-52530 2018-03-23 14:44:54.000000000 +0100
|
||||
+++ libsoup-2.62.2/libsoup/soup-headers.c 2024-11-12 10:23:16.693272087 +0100
|
||||
@@ -50,13 +50,14 @@ soup_headers_parse (const char *str, int
|
||||
From 04df03bc092ac20607f3e150936624d4f536e68b Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Mon, 8 Jul 2024 12:33:15 -0500
|
||||
Subject: [PATCH] headers: Strictly don't allow NUL bytes
|
||||
|
||||
In the past (2015) this was allowed for some problematic sites. However Chromium also does not allow NUL bytes in either header names or values these days. So this should no longer be a problem.
|
||||
---
|
||||
libsoup/soup-headers.c | 15 +++------
|
||||
tests/header-parsing-test.c | 62 +++++++++++++++++--------------------
|
||||
2 files changed, 32 insertions(+), 45 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index a0cf351a..f30ee467 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -51,13 +51,14 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
|
||||
* ignorable trailing whitespace.
|
||||
*/
|
||||
|
||||
@ -19,7 +31,7 @@ diff -up libsoup-2.62.2/libsoup/soup-headers.c.cve-2024-52530 libsoup-2.62.2/lib
|
||||
|
||||
/* We work on a copy of the headers, which we can write '\0's
|
||||
* into, so that we don't have to individually g_strndup and
|
||||
@@ -68,14 +69,6 @@ soup_headers_parse (const char *str, int
|
||||
@@ -69,14 +70,6 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
|
||||
headers_copy[copy_len] = '\0';
|
||||
value_end = headers_copy;
|
||||
|
||||
@ -34,9 +46,10 @@ diff -up libsoup-2.62.2/libsoup/soup-headers.c.cve-2024-52530 libsoup-2.62.2/lib
|
||||
while (*(value_end + 1)) {
|
||||
name = value_end + 1;
|
||||
name_end = strchr (name, ':');
|
||||
diff -up libsoup-2.62.2/tests/header-parsing.c.cve-2024-52530 libsoup-2.62.2/tests/header-parsing.c
|
||||
--- libsoup-2.62.2/tests/header-parsing.c.cve-2024-52530 2024-11-12 10:25:26.452447520 +0100
|
||||
+++ libsoup-2.62.2/tests/header-parsing.c 2024-11-12 10:28:05.738158891 +0100
|
||||
diff --git a/tests/header-parsing-test.c b/tests/header-parsing-test.c
|
||||
index edf8eebb..715c2c6f 100644
|
||||
--- a/tests/header-parsing-test.c
|
||||
+++ b/tests/header-parsing-test.c
|
||||
@@ -358,24 +358,6 @@ static struct RequestTest {
|
||||
}
|
||||
},
|
||||
@ -127,3 +140,6 @@ diff -up libsoup-2.62.2/tests/header-parsing.c.cve-2024-52530 libsoup-2.62.2/tes
|
||||
};
|
||||
static const int num_resptests = G_N_ELEMENTS (resptests);
|
||||
|
||||
--
|
||||
2.45.2
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From bbeb7d59f98d0073291ca4a7ee9ce1a946842734 Mon Sep 17 00:00:00 2001
|
||||
From a35222dd0bfab2ac97c10e86b95f762456628283 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Tue, 27 Aug 2024 13:53:26 -0500
|
||||
Subject: [PATCH] headers: Be more robust against invalid input when parsing
|
||||
@ -10,14 +10,14 @@ it can cause an overflow if it decodes the input to UTF-8.
|
||||
This should never happen with valid UTF-8 input which libsoup's client API
|
||||
ensures, however it's server API does not currently.
|
||||
---
|
||||
libsoup/soup-headers.c | 46 +++++++++++++++++++++---------------------
|
||||
1 file changed, 23 insertions(+), 23 deletions(-)
|
||||
libsoup/soup-headers.c | 46 ++++++++++++++++++++++--------------------
|
||||
1 file changed, 24 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index 271d2a63..8657483f 100644
|
||||
index f30ee467..613e1905 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -650,8 +650,9 @@ soup_header_contains (const char *header, const char *token)
|
||||
@@ -646,8 +646,9 @@ soup_header_contains (const char *header, const char *token)
|
||||
}
|
||||
|
||||
static void
|
||||
@ -28,7 +28,7 @@ index 271d2a63..8657483f 100644
|
||||
char *src, *dst;
|
||||
|
||||
src = quoted_string + 1;
|
||||
@@ -665,10 +666,11 @@ decode_quoted_string (char *quoted_string)
|
||||
@@ -661,10 +662,11 @@ decode_quoted_string (char *quoted_string)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -41,7 +41,7 @@ index 271d2a63..8657483f 100644
|
||||
|
||||
q = strchr (encoded_string, '\'');
|
||||
if (!q)
|
||||
@@ -697,14 +699,7 @@ decode_rfc5987 (char *encoded_string)
|
||||
@@ -696,14 +698,7 @@ decode_rfc5987 (char *encoded_string)
|
||||
decoded = utf8;
|
||||
}
|
||||
|
||||
@ -57,12 +57,12 @@ index 271d2a63..8657483f 100644
|
||||
g_free (decoded);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -714,15 +709,17 @@ parse_param_list (const char *header, char delim)
|
||||
@@ -713,15 +708,17 @@ parse_param_list (const char *header, char delim, gboolean strict)
|
||||
{
|
||||
GHashTable *params;
|
||||
GSList *list, *iter;
|
||||
- char *item, *eq, *name_end, *value;
|
||||
- gboolean override;
|
||||
- gboolean override, duplicated;
|
||||
|
||||
params = g_hash_table_new_full (soup_str_case_hash,
|
||||
soup_str_case_equal,
|
||||
@ -78,7 +78,7 @@ index 271d2a63..8657483f 100644
|
||||
item = iter->data;
|
||||
override = FALSE;
|
||||
|
||||
@@ -737,24 +734,27 @@ parse_param_list (const char *header, char delim)
|
||||
@@ -736,19 +733,19 @@ parse_param_list (const char *header, char delim, gboolean strict)
|
||||
|
||||
*name_end = '\0';
|
||||
|
||||
@ -98,15 +98,23 @@ index 271d2a63..8657483f 100644
|
||||
- decode_quoted_string (value);
|
||||
- } else
|
||||
- value = NULL;
|
||||
-
|
||||
- if (override || !g_hash_table_lookup (params, item))
|
||||
- g_hash_table_replace (params, item, value);
|
||||
- else
|
||||
+ } else if (parsed_value->str[0] == '"')
|
||||
+ decode_quoted_string_inplace (parsed_value);
|
||||
+ }
|
||||
+
|
||||
+ if (override || !g_hash_table_lookup (params, item)) {
|
||||
|
||||
duplicated = g_hash_table_lookup_extended (params, item, NULL, NULL);
|
||||
|
||||
@@ -756,11 +753,16 @@ parse_param_list (const char *header, char delim, gboolean strict)
|
||||
soup_header_free_param_list (params);
|
||||
params = NULL;
|
||||
g_slist_foreach (iter, (GFunc)g_free, NULL);
|
||||
+ if (parsed_value)
|
||||
+ g_string_free (parsed_value, TRUE);
|
||||
break;
|
||||
- } else if (override || !duplicated)
|
||||
- g_hash_table_replace (params, item, value);
|
||||
- else
|
||||
+ } else if (override || !duplicated) {
|
||||
+ g_hash_table_replace (params, item, parsed_value ? g_string_free (parsed_value, FALSE) : NULL);
|
||||
+ } else {
|
||||
+ if (parsed_value)
|
||||
@ -117,5 +125,5 @@ index 271d2a63..8657483f 100644
|
||||
|
||||
g_slist_free (list);
|
||||
--
|
||||
2.48.1
|
||||
GitLab
|
||||
|
||||
|
||||
@ -13,3 +13,84 @@ diff -up libsoup-2.62.3/libsoup/soup-websocket-connection.c.cve-2024-52532 libso
|
||||
|
||||
if (end) {
|
||||
if (!pv->close_sent || !pv->close_received) {
|
||||
|
||||
From 29b96fab2512666d7241e46c98cc45b60b795c0c Mon Sep 17 00:00:00 2001
|
||||
From: Ignacio Casal Quinteiro <qignacio@amazon.com>
|
||||
Date: Wed, 2 Oct 2024 11:17:19 +0200
|
||||
Subject: [PATCH 2/2] websocket-test: disconnect error copy after the test ends
|
||||
|
||||
Otherwise the server will have already sent a few more wrong
|
||||
bytes and the client will continue getting errors to copy
|
||||
but the error is already != NULL and it will assert
|
||||
---
|
||||
tests/websocket-test.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
|
||||
index 06c443bb..6a48c1f9 100644
|
||||
--- a/tests/websocket-test.c
|
||||
+++ b/tests/websocket-test.c
|
||||
@@ -1539,8 +1539,9 @@ test_receive_invalid_encode_length_64 (Test *test,
|
||||
GError *error = NULL;
|
||||
InvalidEncodeLengthTest context = { test, NULL };
|
||||
guint i;
|
||||
+ guint error_id;
|
||||
|
||||
- g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error);
|
||||
+ error_id = g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error);
|
||||
g_signal_connect (test->client, "message", G_CALLBACK (on_binary_message), &received);
|
||||
|
||||
/* We use 127(\x7f) as payload length with 65535 extended length */
|
||||
@@ -1553,6 +1554,7 @@ test_receive_invalid_encode_length_64 (Test *test,
|
||||
WAIT_UNTIL (error != NULL || received != NULL);
|
||||
g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
|
||||
g_clear_error (&error);
|
||||
+ g_signal_handler_disconnect (test->client, error_id);
|
||||
g_assert_null (received);
|
||||
|
||||
g_thread_join (thread);
|
||||
--
|
||||
2.45.2
|
||||
|
||||
From 4c9e75c6676a37b6485620c332e568e1a3f530ff Mon Sep 17 00:00:00 2001
|
||||
From: Simon McVittie <smcv@debian.org>
|
||||
Date: Wed, 13 Nov 2024 14:14:23 +0000
|
||||
Subject: [PATCH] websocket-test: Disconnect error signal in another place
|
||||
|
||||
This is the same change as commit 29b96fab "websocket-test: disconnect
|
||||
error copy after the test ends", and is done for the same reason, but
|
||||
replicating it into a different function.
|
||||
|
||||
Fixes: 6adc0e3e "websocket: process the frame as soon as we read data"
|
||||
Resolves: https://gitlab.gnome.org/GNOME/libsoup/-/issues/399
|
||||
Signed-off-by: Simon McVittie <smcv@debian.org>
|
||||
---
|
||||
tests/websocket-test.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/websocket-test.c b/tests/websocket-test.c
|
||||
index 6a48c1f9..723f2857 100644
|
||||
--- a/tests/websocket-test.c
|
||||
+++ b/tests/websocket-test.c
|
||||
@@ -1508,8 +1508,9 @@ test_receive_invalid_encode_length_16 (Test *test,
|
||||
GError *error = NULL;
|
||||
InvalidEncodeLengthTest context = { test, NULL };
|
||||
guint i;
|
||||
+ guint error_id;
|
||||
|
||||
- g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error);
|
||||
+ error_id = g_signal_connect (test->client, "error", G_CALLBACK (on_error_copy), &error);
|
||||
g_signal_connect (test->client, "message", G_CALLBACK (on_binary_message), &received);
|
||||
|
||||
/* We use 126(~) as payload length with 125 extended length */
|
||||
@@ -1522,6 +1523,7 @@ test_receive_invalid_encode_length_16 (Test *test,
|
||||
WAIT_UNTIL (error != NULL || received != NULL);
|
||||
g_assert_error (error, SOUP_WEBSOCKET_ERROR, SOUP_WEBSOCKET_CLOSE_PROTOCOL_ERROR);
|
||||
g_clear_error (&error);
|
||||
+ g_signal_handler_disconnect (test->client, error_id);
|
||||
g_assert_null (received);
|
||||
|
||||
g_thread_join (thread);
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
From b7213fc6c639b5ca6c91e215aee18cea36d9dc95 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Tue, 18 Feb 2025 14:29:50 -0600
|
||||
Subject: [PATCH] sniffer: Add better coverage of skip_insignificant_space()
|
||||
|
||||
---
|
||||
libsoup/soup-content-sniffer.c | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c
|
||||
index 698d05e4..3fb29adf 100644
|
||||
--- a/libsoup/soup-content-sniffer.c
|
||||
+++ b/libsoup/soup-content-sniffer.c
|
||||
@@ -612,8 +612,11 @@ sniff_text_or_binary (SoupContentSniffer *sniffer, SoupBuffer *buffer)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-skip_insignificant_space (const char *resource, int *pos, int resource_length)
|
||||
+skip_insignificant_space (const char *resource, gsize *pos, gsize resource_length)
|
||||
{
|
||||
+ if (*pos >= resource_length)
|
||||
+ return TRUE;
|
||||
+
|
||||
while ((resource[*pos] == '\x09') ||
|
||||
(resource[*pos] == '\x20') ||
|
||||
(resource[*pos] == '\x0A') ||
|
||||
@@ -632,7 +635,7 @@ sniff_feed_or_html (SoupContentSniffer *sniffer, SoupBuffer *buffer)
|
||||
{
|
||||
const char *resource = (const char *)buffer->data;
|
||||
int resource_length = MIN (512, buffer->length);
|
||||
- int pos = 0;
|
||||
+ gsize pos = 0;
|
||||
|
||||
if (resource_length < 3)
|
||||
goto text_html;
|
||||
@@ -642,9 +645,6 @@ sniff_feed_or_html (SoupContentSniffer *sniffer, SoupBuffer *buffer)
|
||||
pos = 3;
|
||||
|
||||
look_for_tag:
|
||||
- if (pos > resource_length)
|
||||
- goto text_html;
|
||||
-
|
||||
if (skip_insignificant_space (resource, &pos, resource_length))
|
||||
goto text_html;
|
||||
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 6ec7c5be50b48d6ce0a09aa3468f2c5725406a97 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Wed, 21 May 2025 10:42:51 -0500
|
||||
Subject: [PATCH] Add size limit for total message size
|
||||
|
||||
This size limit could break applications, but it will close the denial
|
||||
of service issue.
|
||||
---
|
||||
libsoup/soup-websocket-connection.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/libsoup/soup-websocket-connection.c b/libsoup/soup-websocket-connection.c
|
||||
index 36524d04..f8764aff 100644
|
||||
--- a/libsoup/soup-websocket-connection.c
|
||||
+++ b/libsoup/soup-websocket-connection.c
|
||||
@@ -913,6 +913,11 @@ process_contents (SoupWebsocketConnection *self,
|
||||
switch (pv->message_opcode) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
+ /* Safety valve */
|
||||
+ if (pv->message_data->len + payload_len > pv->max_incoming_payload_size) {
|
||||
+ too_big_error_and_close (self, (pv->message_data->len + payload_len));
|
||||
+ return;
|
||||
+ }
|
||||
g_byte_array_append (pv->message_data, payload, payload_len);
|
||||
break;
|
||||
default:
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
From 9bb0a55de55c6940ced811a64fbca82fe93a9323 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Mon, 28 Oct 2024 12:29:48 -0500
|
||||
Subject: [PATCH] Fix using int instead of size_t for strcspn return
|
||||
|
||||
---
|
||||
libsoup/soup-headers.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index 613e1905..a5f7a7f6 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -907,7 +907,7 @@ append_param_quoted (GString *string,
|
||||
const char *name,
|
||||
const char *value)
|
||||
{
|
||||
- int len;
|
||||
+ gsize len;
|
||||
|
||||
g_string_append (string, name);
|
||||
g_string_append (string, "=\"");
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
From 1542173d11df64e39e71367f10596e8160481290 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Sat, 16 Nov 2024 12:07:30 -0600
|
||||
Subject: [PATCH] Fix heap buffer overflow in soup_content_sniffer_sniff
|
||||
|
||||
Co-Author: Ar Jun <pkillarjun@protonmail.com>
|
||||
---
|
||||
libsoup/soup-content-sniffer.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c
|
||||
index 967ec614..26c65bbd 100644
|
||||
--- a/libsoup/soup-content-sniffer.c
|
||||
+++ b/libsoup/soup-content-sniffer.c
|
||||
@@ -504,7 +504,7 @@ sniff_unknown (SoupContentSniffer *sniffer, SoupBuffer *buffer,
|
||||
guint index_pattern = 0;
|
||||
gboolean skip_row = FALSE;
|
||||
|
||||
- while ((index_stream < resource_length) &&
|
||||
+ while ((index_stream < resource_length - 1) &&
|
||||
(index_pattern <= type_row->pattern_length)) {
|
||||
/* Skip insignificant white space ("WS" in the spec) */
|
||||
if (type_row->pattern[index_pattern] == ' ') {
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
From 8e1793e2ddd8c2648b9a28f06bf21fd13bd12b39 Mon Sep 17 00:00:00 2001
|
||||
From: Ar Jun <pkillarjun@protonmail.com>
|
||||
Date: Mon, 18 Nov 2024 14:59:51 -0600
|
||||
Subject: [PATCH] Fix heap buffer overflow in
|
||||
soup-content-sniffer.c:sniff_feed_or_html()
|
||||
|
||||
---
|
||||
libsoup/soup-content-sniffer.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-content-sniffer.c b/libsoup/soup-content-sniffer.c
|
||||
index 26c65bbd..698d05e4 100644
|
||||
--- a/libsoup/soup-content-sniffer.c
|
||||
+++ b/libsoup/soup-content-sniffer.c
|
||||
@@ -620,7 +620,7 @@ skip_insignificant_space (const char *resource, int *pos, int resource_length)
|
||||
(resource[*pos] == '\x0D')) {
|
||||
*pos = *pos + 1;
|
||||
|
||||
- if (*pos > resource_length)
|
||||
+ if (*pos >= resource_length)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -682,7 +682,7 @@ sniff_feed_or_html (SoupContentSniffer *sniffer, SoupBuffer *buffer)
|
||||
do {
|
||||
pos++;
|
||||
|
||||
- if (pos > resource_length)
|
||||
+ if ((pos + 1) > resource_length)
|
||||
goto text_html;
|
||||
} while (resource[pos] != '>');
|
||||
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
From 1f509f31b6f8420a3661c3f990424ab7b9164931 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Tue, 11 Feb 2025 14:36:26 -0600
|
||||
Subject: [PATCH 1/2] headers: Handle parsing edge case
|
||||
|
||||
This version number is specifically crafted to pass sanity checks allowing it to go one byte out of bounds.
|
||||
---
|
||||
libsoup/soup-headers.c | 2 +-
|
||||
tests/header-parsing-test.c | 12 ++++++++++++
|
||||
2 files changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index 85385cea..9d6d00a3 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -225,7 +225,7 @@ soup_headers_parse_request (const char *str,
|
||||
!g_ascii_isdigit (version[5]))
|
||||
return SOUP_STATUS_BAD_REQUEST;
|
||||
major_version = strtoul (version + 5, &p, 10);
|
||||
- if (*p != '.' || !g_ascii_isdigit (p[1]))
|
||||
+ if (p + 1 >= str + len || *p != '.' || !g_ascii_isdigit (p[1]))
|
||||
return SOUP_STATUS_BAD_REQUEST;
|
||||
minor_version = strtoul (p + 1, &p, 10);
|
||||
version_end = p;
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
||||
From af5b9a4a3945c52b940d5ac181ef51bb12011f1f Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Wed, 12 Feb 2025 11:30:02 -0600
|
||||
Subject: [PATCH 2/2] headers: Handle parsing only newlines
|
||||
|
||||
Closes #404
|
||||
Closes #407
|
||||
---
|
||||
libsoup/soup-headers.c | 4 ++--
|
||||
tests/header-parsing-test.c | 13 ++++++++++++-
|
||||
2 files changed, 14 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index 9d6d00a3..52ef2ece 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -186,7 +186,7 @@ soup_headers_parse_request (const char *str,
|
||||
/* RFC 2616 4.1 "servers SHOULD ignore any empty line(s)
|
||||
* received where a Request-Line is expected."
|
||||
*/
|
||||
- while ((*str == '\r' || *str == '\n') && len > 0) {
|
||||
+ while (len > 0 && (*str == '\r' || *str == '\n')) {
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
@@ -371,7 +371,7 @@ soup_headers_parse_response (const char *str,
|
||||
* after a response, which we then see prepended to the next
|
||||
* response on that connection.
|
||||
*/
|
||||
- while ((*str == '\r' || *str == '\n') && len > 0) {
|
||||
+ while (len > 0 && (*str == '\r' || *str == '\n')) {
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
--
|
||||
GitLab
|
||||
|
||||
@ -1,67 +0,0 @@
|
||||
From f2d316341c00a343d0b46edd590efa8c102521c3 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Fri, 27 Dec 2024 17:53:50 -0600
|
||||
Subject: [PATCH 1/2] soup_message_headers_get_content_disposition: Fix NULL
|
||||
deref
|
||||
|
||||
---
|
||||
libsoup/soup-message-headers.c | 13 +++++++++----
|
||||
tests/header-parsing-test.c | 13 +++++++++++++
|
||||
2 files changed, 22 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
|
||||
index 5c8c7cb9..ccf31233 100644
|
||||
--- a/libsoup/soup-message-headers.c
|
||||
+++ b/libsoup/soup-message-headers.c
|
||||
@@ -1443,10 +1443,15 @@ soup_message_headers_get_content_disposition (SoupMessageHeaders *hdrs,
|
||||
*/
|
||||
if (params && g_hash_table_lookup_extended (*params, "filename",
|
||||
&orig_key, &orig_value)) {
|
||||
- char *filename = strrchr (orig_value, '/');
|
||||
-
|
||||
- if (filename)
|
||||
- g_hash_table_insert (*params, g_strdup (orig_key), filename + 1);
|
||||
+ if (orig_value) {
|
||||
+ char *filename = strrchr (orig_value, '/');
|
||||
+
|
||||
+ if (filename)
|
||||
+ g_hash_table_insert (*params, g_strdup (orig_key), filename + 1);
|
||||
+ } else {
|
||||
+ /* filename with no value isn't valid. */
|
||||
+ g_hash_table_remove (*params, "filename");
|
||||
+ }
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
--
|
||||
2.49.0
|
||||
|
||||
|
||||
From dd3a245941f117832dd1fdda4f8bc68b44e2810d Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Fri, 27 Dec 2024 18:00:39 -0600
|
||||
Subject: [PATCH 2/2] soup_message_headers_get_content_disposition: strdup
|
||||
truncated filenames
|
||||
|
||||
This table frees the strings it contains.
|
||||
---
|
||||
libsoup/soup-message-headers.c | 2 +-
|
||||
tests/header-parsing-test.c | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-message-headers.c b/libsoup/soup-message-headers.c
|
||||
index ccf31233..64847e30 100644
|
||||
--- a/libsoup/soup-message-headers.c
|
||||
+++ b/libsoup/soup-message-headers.c
|
||||
@@ -1447,7 +1447,7 @@ soup_message_headers_get_content_disposition (SoupMessageHeaders *hdrs,
|
||||
char *filename = strrchr (orig_value, '/');
|
||||
|
||||
if (filename)
|
||||
- g_hash_table_insert (*params, g_strdup (orig_key), filename + 1);
|
||||
+ g_hash_table_insert (*params, g_strdup (orig_key), g_strdup (filename + 1));
|
||||
} else {
|
||||
/* filename with no value isn't valid. */
|
||||
g_hash_table_remove (*params, "filename");
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 51c25f470f85b485818c253718594a4d59b39931 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Tue, 15 Apr 2025 09:03:00 +0200
|
||||
Subject: [PATCH] multipart: Fix read out of buffer bounds under
|
||||
soup_multipart_new_from_message()
|
||||
|
||||
This is CVE-2025-32914, special crafted input can cause read out of buffer bounds
|
||||
of the body argument.
|
||||
|
||||
Closes #436
|
||||
---
|
||||
libsoup/soup-multipart.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
|
||||
index a7e550f1..dd939739 100644
|
||||
--- a/libsoup/soup-multipart.c
|
||||
+++ b/libsoup/soup-multipart.c
|
||||
@@ -181,7 +181,7 @@ soup_multipart_new_from_message (SoupMessageHeaders *headers,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- split = strstr (start, "\r\n\r\n");
|
||||
+ split = g_strstr_len (start, body_end - start, "\r\n\r\n");
|
||||
if (!split || split > end) {
|
||||
soup_multipart_free (multipart);
|
||||
soup_buffer_free (flattened);
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
From 355d7979ac27c6a83684e079d5bc6cf148e7bc16 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Thu, 26 Dec 2024 18:31:42 -0600
|
||||
Subject: [PATCH] soup_header_parse_quality_list: Fix leak
|
||||
|
||||
When iterating over the parsed list we now steal the allocated strings that we want and then free_full the list which may contain remaining strings.
|
||||
---
|
||||
libsoup/soup-headers.c | 11 +++++------
|
||||
1 file changed, 5 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index eec28adf..3e922816 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -535,7 +535,7 @@ soup_header_parse_quality_list (const char *header, GSList **unacceptable)
|
||||
GSList *unsorted;
|
||||
QualityItem *array;
|
||||
GSList *sorted, *iter;
|
||||
- char *item, *semi;
|
||||
+ char *semi;
|
||||
const char *param, *equal, *value;
|
||||
double qval;
|
||||
int n;
|
||||
@@ -548,9 +548,8 @@ soup_header_parse_quality_list (const char *header, GSList **unacceptable)
|
||||
unsorted = soup_header_parse_list (header);
|
||||
array = g_new0 (QualityItem, g_slist_length (unsorted));
|
||||
for (iter = unsorted, n = 0; iter; iter = iter->next) {
|
||||
- item = iter->data;
|
||||
qval = 1.0;
|
||||
- for (semi = strchr (item, ';'); semi; semi = strchr (semi + 1, ';')) {
|
||||
+ for (semi = strchr (iter->data, ';'); semi; semi = strchr (semi + 1, ';')) {
|
||||
param = skip_lws (semi + 1);
|
||||
if (*param != 'q')
|
||||
continue;
|
||||
@@ -582,15 +581,15 @@ soup_header_parse_quality_list (const char *header, GSList **unacceptable)
|
||||
if (qval == 0.0) {
|
||||
if (unacceptable) {
|
||||
*unacceptable = g_slist_prepend (*unacceptable,
|
||||
- item);
|
||||
+ g_steal_pointer (&iter->data));
|
||||
}
|
||||
} else {
|
||||
- array[n].item = item;
|
||||
+ array[n].item = g_steal_pointer (&iter->data);
|
||||
array[n].qval = qval;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
- g_slist_free (unsorted);
|
||||
+ g_slist_free_full (unsorted, g_free);
|
||||
|
||||
qsort (array, n, sizeof (QualityItem), sort_by_qval);
|
||||
sorted = NULL;
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
From 4329a7e88c72079ae3eedbb1558b929851507464 Mon Sep 17 00:00:00 2001
|
||||
From: Patrick Griffis <pgriffis@igalia.com>
|
||||
Date: Wed, 5 Feb 2025 16:18:10 -0600
|
||||
Subject: [PATCH] session: Strip authentication credentails on cross-origin
|
||||
redirect
|
||||
|
||||
This should match the behavior of Firefox and Safari but not of Chromium.
|
||||
---
|
||||
libsoup/soup-session.c | 6 ++++
|
||||
tests/auth-test.c | 77 ++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 83 insertions(+)
|
||||
|
||||
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
|
||||
index dd3cdc46..82ca8bf9 100644
|
||||
--- a/libsoup/soup-session.c
|
||||
+++ b/libsoup/soup-session.c
|
||||
@@ -1187,6 +1187,12 @@ soup_session_redirect_message (SoupSession *session, SoupMessage *msg)
|
||||
SOUP_ENCODING_NONE);
|
||||
}
|
||||
|
||||
+ /* Strip all credentials on cross-origin redirect. */
|
||||
+ if (!soup_uri_host_equal (soup_message_get_uri (msg), new_uri)) {
|
||||
+ soup_message_headers_remove (msg->request_headers, "Authorization");
|
||||
+ soup_message_set_auth (msg, NULL);
|
||||
+ }
|
||||
+
|
||||
soup_message_set_uri (msg, new_uri);
|
||||
soup_uri_free (new_uri);
|
||||
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,931 +0,0 @@
|
||||
From 52825c2eb7043698d7a0668cfe6bb5a23da87cf5 Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Thu, 15 May 2025 07:59:14 +0200
|
||||
Subject: [PATCH 1/2] soup-date-utils: Add value checks for date/time parsing
|
||||
|
||||
Reject date/time when it does not represent a valid value.
|
||||
|
||||
Closes https://gitlab.gnome.org/GNOME/libsoup/-/issues/448
|
||||
---
|
||||
libsoup/soup-date.c | 23 ++-
|
||||
tests/cookies-test.c | 10 +
|
||||
tests/date-test.c | 434 +++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 459 insertions(+), 8 deletions(-)
|
||||
create mode 100644 tests/date-test.c
|
||||
|
||||
diff --git a/libsoup/soup-date.c b/libsoup/soup-date.c
|
||||
index dabae9d4..8b2beea4 100644
|
||||
--- a/libsoup/soup-date.c
|
||||
+++ b/libsoup/soup-date.c
|
||||
@@ -284,7 +284,7 @@ parse_day (SoupDate *date, const char **date_string)
|
||||
while (*end == ' ' || *end == '-')
|
||||
end++;
|
||||
*date_string = end;
|
||||
- return TRUE;
|
||||
+ return date->day >= 1 && date->day <= 31;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -324,7 +324,7 @@ parse_year (SoupDate *date, const char **date_string)
|
||||
while (*end == ' ' || *end == '-')
|
||||
end++;
|
||||
*date_string = end;
|
||||
- return TRUE;
|
||||
+ return date->year > 0 && date->year < 9999;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -348,7 +348,7 @@ parse_time (SoupDate *date, const char **date_string)
|
||||
while (*p == ' ')
|
||||
p++;
|
||||
*date_string = p;
|
||||
- return TRUE;
|
||||
+ return date->hour >= 0 && date->hour < 24 && date->minute >= 0 && date->minute < 60 && date->second >= 0 && date->second < 60;
|
||||
}
|
||||
|
||||
static inline gboolean
|
||||
@@ -361,9 +361,14 @@ parse_timezone (SoupDate *date, const char **date_string)
|
||||
gulong val;
|
||||
int sign = (**date_string == '+') ? -1 : 1;
|
||||
val = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
- if (**date_string == ':')
|
||||
- val = 60 * val + strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
- else
|
||||
+ if (val > 9999)
|
||||
+ return FALSE;
|
||||
+ if (**date_string == ':') {
|
||||
+ gulong val2 = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
+ if (val > 99 || val2 > 99)
|
||||
+ return FALSE;
|
||||
+ val = 60 * val + val2;
|
||||
+ } else
|
||||
val = 60 * (val / 100) + (val % 100);
|
||||
date->offset = sign * val;
|
||||
date->utc = (sign == -1) && !val;
|
||||
@@ -407,7 +412,8 @@ parse_textual_date (SoupDate *date, const char *date_string)
|
||||
if (!parse_month (date, &date_string) ||
|
||||
!parse_day (date, &date_string) ||
|
||||
!parse_time (date, &date_string) ||
|
||||
- !parse_year (date, &date_string))
|
||||
+ !parse_year (date, &date_string) ||
|
||||
+ !g_date_valid_dmy (date->day, date->month, date->year))
|
||||
return FALSE;
|
||||
|
||||
/* There shouldn't be a timezone, but check anyway */
|
||||
@@ -419,7 +425,8 @@ parse_textual_date (SoupDate *date, const char *date_string)
|
||||
if (!parse_day (date, &date_string) ||
|
||||
!parse_month (date, &date_string) ||
|
||||
!parse_year (date, &date_string) ||
|
||||
- !parse_time (date, &date_string))
|
||||
+ !parse_time (date, &date_string) ||
|
||||
+ !g_date_valid_dmy (date->day, date->month, date->year))
|
||||
return FALSE;
|
||||
|
||||
/* This time there *should* be a timezone, but we
|
||||
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
||||
index 17b77f29..61adfac5 100644
|
||||
--- a/tests/cookies-test.c
|
||||
+++ b/tests/cookies-test.c
|
||||
@@ -288,6 +288,15 @@ do_cookies_parsing_nopath_nullorigin (void)
|
||||
soup_cookie_free (cookie);
|
||||
}
|
||||
|
||||
+static void
|
||||
+do_cookies_parsing_int32_overflow (void)
|
||||
+{
|
||||
+ SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL);
|
||||
+ g_assert_nonnull (cookie);
|
||||
+ g_assert_null (soup_cookie_get_expires (cookie));
|
||||
+ soup_cookie_free (cookie);
|
||||
+}
|
||||
+
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@@ -309,6 +318,7 @@ main (int argc, char **argv)
|
||||
g_test_add_func ("/cookies/accept-policy-subdomains", do_cookies_subdomain_policy_test);
|
||||
g_test_add_func ("/cookies/parsing", do_cookies_parsing_test);
|
||||
g_test_add_func ("/cookies/parsing/no-path-null-origin", do_cookies_parsing_nopath_nullorigin);
|
||||
+ g_test_add_func ("/cookies/parsing/int32-overflow", do_cookies_parsing_int32_overflow);
|
||||
|
||||
ret = g_test_run ();
|
||||
|
||||
diff --git a/tests/date-test.c b/tests/date-test.c
|
||||
new file mode 100644
|
||||
index 00000000..38f27335
|
||||
--- /dev/null
|
||||
+++ b/tests/date-test.c
|
||||
@@ -0,0 +1,434 @@
|
||||
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
|
||||
+/*
|
||||
+ * Copyright (C) 2005 Novell, Inc.
|
||||
+ */
|
||||
+
|
||||
+#include "test-utils.h"
|
||||
+
|
||||
+static void check_ok (gconstpointer data);
|
||||
+
|
||||
+static SoupDate *
|
||||
+make_date (const char *strdate)
|
||||
+{
|
||||
+ char *dup;
|
||||
+ SoupDate *date;
|
||||
+
|
||||
+ /* We do it this way so that if soup_date_new_from_string()
|
||||
+ * reads off the end of the string, it will trigger an error
|
||||
+ * when valgrinding, rather than just reading the start of the
|
||||
+ * next const string.
|
||||
+ */
|
||||
+ dup = g_strdup (strdate);
|
||||
+ date = soup_date_new_from_string (dup);
|
||||
+ g_free (dup);
|
||||
+ return date;
|
||||
+}
|
||||
+
|
||||
+static SoupDate *
|
||||
+check_correct_date (const char *strdate)
|
||||
+{
|
||||
+ SoupDate *date;
|
||||
+
|
||||
+ date = make_date (strdate);
|
||||
+ if (!date) {
|
||||
+ g_assert_nonnull (date);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ g_assert_cmpint (date->year, ==, 2004);
|
||||
+ g_assert_cmpint (date->month, ==, 11);
|
||||
+ g_assert_cmpint (date->day, ==, 6);
|
||||
+ g_assert_cmpint (date->hour, ==, 8);
|
||||
+ g_assert_cmpint (date->minute, ==, 9);
|
||||
+ g_assert_cmpint (date->second, ==, 7);
|
||||
+
|
||||
+ return date;
|
||||
+}
|
||||
+
|
||||
+typedef struct {
|
||||
+ SoupDateFormat format;
|
||||
+ const char *date;
|
||||
+ const char *bugref;
|
||||
+} GoodDate;
|
||||
+
|
||||
+static const GoodDate good_dates[] = {
|
||||
+ { SOUP_DATE_HTTP, "Sat, 06 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { SOUP_DATE_COOKIE, "Sat, 06-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { SOUP_DATE_RFC2822, "Sat, 6 Nov 2004 08:09:07 -0430", "579055" },
|
||||
+ { SOUP_DATE_ISO8601_COMPACT, "20041106T080907", NULL },
|
||||
+ { SOUP_DATE_ISO8601_FULL, "2004-11-06T08:09:07", NULL },
|
||||
+ { SOUP_DATE_ISO8601_XMLRPC, "20041106T08:09:07", NULL }
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+check_good (gconstpointer data)
|
||||
+{
|
||||
+ GoodDate *good = (GoodDate *)data;
|
||||
+ SoupDate *date;
|
||||
+ char *strdate2;
|
||||
+
|
||||
+ if (good->bugref)
|
||||
+ g_test_bug (good->bugref);
|
||||
+
|
||||
+ date = check_correct_date (good->date);
|
||||
+ if (!date)
|
||||
+ return;
|
||||
+
|
||||
+ strdate2 = soup_date_to_string (date, good->format);
|
||||
+ soup_date_free (date);
|
||||
+
|
||||
+ soup_test_assert (strcmp (good->date, strdate2) == 0,
|
||||
+ "restringification failed: '%s' -> '%s'\n",
|
||||
+ good->date, strdate2);
|
||||
+ g_free (strdate2);
|
||||
+}
|
||||
+
|
||||
+typedef struct {
|
||||
+ const char *date;
|
||||
+ const char *bugref;
|
||||
+} OkDate;
|
||||
+
|
||||
+static const OkDate ok_dates[] = {
|
||||
+ /* rfc1123-date, and broken variants */
|
||||
+ { "Sat, 06 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 08:09:07", NULL },
|
||||
+ { "06 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "SAT, 06 NOV 2004 08:09:07 +1000", "644048" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 -10000", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +01:30", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +0:180", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 +100:100", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 Z", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+
|
||||
+ /* rfc850-date, and broken variants */
|
||||
+ { "Saturday, 06-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 6-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 6-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-104 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 6-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 6-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-04 08:09:07", NULL },
|
||||
+ { "06-Nov-04 08:09:07 GMT", NULL },
|
||||
+
|
||||
+ /* asctime-date, and broken variants */
|
||||
+ { "Sat Nov 6 08:09:07 2004", NULL },
|
||||
+ { "Sat Nov 06 08:09:07 2004", NULL },
|
||||
+ { "Sat Nov 6 08:09:07 2004", NULL },
|
||||
+ { "Sat Nov 6 08:09:07 2004 GMT", NULL },
|
||||
+ { "Sat Nov 6 08:09:07 2004 NoZone", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+ { "Sat Nov 6 08:09:07 2004 UTC", "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" },
|
||||
+
|
||||
+ /* ISO 8601 */
|
||||
+ { "2004-11-06T08:09:07Z", NULL },
|
||||
+ { "20041106T08:09:07Z", NULL },
|
||||
+ { "20041106T08:09:07+00:00", NULL },
|
||||
+ { "20041106T080907+00:00", NULL },
|
||||
+
|
||||
+ /* Netscape cookie spec date, and broken variants */
|
||||
+ { "Sat, 06-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:09:07", NULL },
|
||||
+
|
||||
+ /* Original version of Netscape cookie spec, and broken variants */
|
||||
+ { "Sat, 06-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 6-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-104 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-04 08:09:07", NULL },
|
||||
+
|
||||
+ /* Miscellaneous broken formats seen on the web */
|
||||
+ { "Sat 06-Nov-2004 08:9:07", NULL },
|
||||
+ { "Saturday, 06-Nov-04 8:9:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 08:09:7 GMT", NULL }
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+check_ok (gconstpointer data)
|
||||
+{
|
||||
+ OkDate *ok = (OkDate *)data;
|
||||
+ SoupDate *date;
|
||||
+
|
||||
+ if (ok->bugref)
|
||||
+ g_test_bug (ok->bugref);
|
||||
+
|
||||
+ date = check_correct_date (ok->date);
|
||||
+ if (!date)
|
||||
+ return;
|
||||
+ soup_date_free (date);
|
||||
+}
|
||||
+
|
||||
+#define TIME_T 1099728547L
|
||||
+#define TIME_T_STRING "1099728547"
|
||||
+
|
||||
+static void
|
||||
+check_ok_time_t (void)
|
||||
+{
|
||||
+ SoupDate *date;
|
||||
+
|
||||
+ date = soup_date_new_from_time_t (TIME_T);
|
||||
+
|
||||
+ g_assert_cmpint (date->year, ==, 2004);
|
||||
+ g_assert_cmpint (date->month, ==, 11);
|
||||
+ g_assert_cmpint (date->day, ==, 6);
|
||||
+ g_assert_cmpint (date->hour, ==, 8);
|
||||
+ g_assert_cmpint (date->minute, ==, 9);
|
||||
+ g_assert_cmpint (date->second, ==, 7);
|
||||
+
|
||||
+ g_assert_cmpuint (TIME_T, ==, soup_date_to_time_t (date));
|
||||
+
|
||||
+ soup_date_free (date);
|
||||
+}
|
||||
+
|
||||
+typedef struct {
|
||||
+ const char *date;
|
||||
+ const char *bugref;
|
||||
+} BadDate;
|
||||
+
|
||||
+static const BadDate bad_dates[] = {
|
||||
+ /* broken rfc1123-date */
|
||||
+ { ", 06 Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, Nov 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06 2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 :09:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 09:07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 08::07 GMT", NULL },
|
||||
+ { "Sat, 06 Nov 2004 08:09: GMT", NULL },
|
||||
+
|
||||
+ /* broken rfc850-date */
|
||||
+ { ", 06-Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, -Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, Nov-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06--04 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov- 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov 08:09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-04 :09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-04 09:07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-04 08::07 GMT", NULL },
|
||||
+ { "Saturday, 06-Nov-04 08:09: GMT", NULL },
|
||||
+
|
||||
+ /* broken asctime-date */
|
||||
+ { "Nov 6 08:09:07 2004", NULL },
|
||||
+ { "Sat 6 08:09:07 2004", NULL },
|
||||
+ { "Sat Nov 08:09:07 2004", NULL },
|
||||
+ { "Sat Nov 6 :09:07 2004", NULL },
|
||||
+ { "Sat Nov 6 09:07 2004", NULL },
|
||||
+ { "Sat Nov 6 08::07 2004", NULL },
|
||||
+ { "Sat Nov 6 08:09: 2004", NULL },
|
||||
+ { "Sat Nov 6 08:09:07", NULL },
|
||||
+ { "Sat Nov 6 08:09:07 GMT 2004", NULL },
|
||||
+
|
||||
+ /* range constraints added "https://gitlab.gnome.org/GNOME/libsoup/-/issues/448" */
|
||||
+ { "Sat, 00-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 32-Nov-2004 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-0 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-9999 08:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 0-1:09:07 GMT", NULL },
|
||||
+ { "(Sat), Nov 6 -1:09:07 2004", NULL },
|
||||
+ { "Sat, 06-Nov-2004 24:09:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:-1:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:60:07 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:09:-10 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-2004 08:09:60 GMT", NULL },
|
||||
+ { "Sat, 06-Nov-71 08:09:99 UTC", NULL },
|
||||
+ { "Sat, 31-Feb-2004 08:09:07 UTC", NULL },
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+check_bad (gconstpointer data)
|
||||
+{
|
||||
+ BadDate *bad = (BadDate *)data;
|
||||
+ SoupDate *date;
|
||||
+
|
||||
+ if (bad->bugref)
|
||||
+ g_test_bug (bad->bugref);
|
||||
+
|
||||
+ date = make_date (bad->date);
|
||||
+ soup_test_assert (date == NULL,
|
||||
+ "date parsing succeeded for '%s': %d %d %d - %d %d %d",
|
||||
+ bad->date,
|
||||
+ date->year, date->month, date->day,
|
||||
+ date->hour, date->minute, date->second);
|
||||
+ g_clear_pointer (&date, soup_date_free);
|
||||
+}
|
||||
+
|
||||
+typedef struct {
|
||||
+ const char *source;
|
||||
+ const char *http, *cookie, *rfc2822, *compact, *full, *xmlrpc;
|
||||
+} DateConversion;
|
||||
+
|
||||
+static const DateConversion conversions[] = {
|
||||
+ /* SOUP_DATE_HTTP */
|
||||
+ { "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 08:09:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 +0000",
|
||||
+ "20041106T080907Z",
|
||||
+ "2004-11-06T08:09:07Z",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* RFC2822 GMT */
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 +0000",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 08:09:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 +0000",
|
||||
+ "20041106T080907Z",
|
||||
+ "2004-11-06T08:09:07Z",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* RFC2822 with positive offset */
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 +0430",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 04:39:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 04:39:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 +0430",
|
||||
+ "20041106T080907+0430",
|
||||
+ "2004-11-06T08:09:07+04:30",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* RFC2822 with negative offset */
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 -0430",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 12:39:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 12:39:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 -0430",
|
||||
+ "20041106T080907-0430",
|
||||
+ "2004-11-06T08:09:07-04:30",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* RFC2822 floating */
|
||||
+ { "Sat, 6 Nov 2004 08:09:07 -0000",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 08:09:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 -0000",
|
||||
+ "20041106T080907",
|
||||
+ "2004-11-06T08:09:07",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* ISO GMT */
|
||||
+ { "2004-11-06T08:09:07Z",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 08:09:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 +0000",
|
||||
+ "20041106T080907Z",
|
||||
+ "2004-11-06T08:09:07Z",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* ISO with positive offset */
|
||||
+ { "2004-11-06T08:09:07+04:30",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 04:39:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 04:39:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 +0430",
|
||||
+ "20041106T080907+0430",
|
||||
+ "2004-11-06T08:09:07+04:30",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* ISO with negative offset */
|
||||
+ { "2004-11-06T08:09:07-04:30",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 12:39:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 12:39:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 -0430",
|
||||
+ "20041106T080907-0430",
|
||||
+ "2004-11-06T08:09:07-04:30",
|
||||
+ "20041106T08:09:07" },
|
||||
+
|
||||
+ /* ISO floating */
|
||||
+ { "2004-11-06T08:09:07",
|
||||
+
|
||||
+ "Sat, 06 Nov 2004 08:09:07 GMT",
|
||||
+ "Sat, 06-Nov-2004 08:09:07 GMT",
|
||||
+ "Sat, 6 Nov 2004 08:09:07 -0000",
|
||||
+ "20041106T080907",
|
||||
+ "2004-11-06T08:09:07",
|
||||
+ "20041106T08:09:07" }
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+check_conversion (gconstpointer data)
|
||||
+{
|
||||
+ const DateConversion *conv = data;
|
||||
+ SoupDate *date;
|
||||
+ char *str;
|
||||
+
|
||||
+ date = make_date (conv->source);
|
||||
+ if (!date) {
|
||||
+ soup_test_assert (FALSE, "date parsing failed for '%s'.", conv->source);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_HTTP);
|
||||
+ g_assert_cmpstr (str, ==, conv->http);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_COOKIE);
|
||||
+ g_assert_cmpstr (str, ==, conv->cookie);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_RFC2822);
|
||||
+ g_assert_cmpstr (str, ==, conv->rfc2822);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_ISO8601_COMPACT);
|
||||
+ g_assert_cmpstr (str, ==, conv->compact);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_ISO8601_FULL);
|
||||
+ g_assert_cmpstr (str, ==, conv->full);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ str = soup_date_to_string (date, SOUP_DATE_ISO8601_XMLRPC);
|
||||
+ g_assert_cmpstr (str, ==, conv->xmlrpc);
|
||||
+ g_free (str);
|
||||
+
|
||||
+ soup_date_free (date);
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+main (int argc, char **argv)
|
||||
+{
|
||||
+ int i, ret;
|
||||
+ char *path;
|
||||
+
|
||||
+ test_init (argc, argv, NULL);
|
||||
+
|
||||
+ for (i = 0; i < G_N_ELEMENTS (good_dates); i++) {
|
||||
+ path = g_strdup_printf ("/date/good/%s", good_dates[i].date);
|
||||
+ g_test_add_data_func (path, &good_dates[i], check_good);
|
||||
+ g_free (path);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < G_N_ELEMENTS (ok_dates); i++) {
|
||||
+ path = g_strdup_printf ("/date/ok/%s", ok_dates[i].date);
|
||||
+ g_test_add_data_func (path, &ok_dates[i], check_ok);
|
||||
+ g_free (path);
|
||||
+ }
|
||||
+ g_test_add_func ("/date/ok/" TIME_T_STRING, check_ok_time_t);
|
||||
+
|
||||
+ for (i = 0; i < G_N_ELEMENTS (bad_dates); i++) {
|
||||
+ path = g_strdup_printf ("/date/bad/%s", bad_dates[i].date);
|
||||
+ g_test_add_data_func (path, &bad_dates[i], check_bad);
|
||||
+ g_free (path);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < G_N_ELEMENTS (conversions); i++) {
|
||||
+ path = g_strdup_printf ("/date/conversions/%s", conversions[i].source);
|
||||
+ g_test_add_data_func (path, &conversions[i], check_conversion);
|
||||
+ g_free (path);
|
||||
+ }
|
||||
+
|
||||
+ ret = g_test_run ();
|
||||
+
|
||||
+ test_cleanup ();
|
||||
+ return ret;
|
||||
+}
|
||||
--
|
||||
2.51.0
|
||||
|
||||
|
||||
From 724efae52bcf2c0b8a247f736103285ad68d1b15 Mon Sep 17 00:00:00 2001
|
||||
From: Brian Yurko <155515-byurko@users.noreply.gitlab.gnome.org>
|
||||
Date: Wed, 11 Jun 2025 11:00:56 -0400
|
||||
Subject: [PATCH 2/2] tests: Add tests for date-time including timezone
|
||||
validation work
|
||||
|
||||
These tests are built on top of earlier work in a related pull request.
|
||||
|
||||
Closes #448
|
||||
---
|
||||
libsoup/soup-date-utils.c | 339 ++++++++++++++++++++++++++++++++++++++
|
||||
tests/cookies-test.c | 1 +
|
||||
2 files changed, 340 insertions(+)
|
||||
create mode 100644 libsoup/soup-date-utils.c
|
||||
|
||||
diff --git a/libsoup/soup-date-utils.c b/libsoup/soup-date-utils.c
|
||||
new file mode 100644
|
||||
index 00000000..73f80ab6
|
||||
--- /dev/null
|
||||
+++ b/libsoup/soup-date-utils.c
|
||||
@@ -0,0 +1,339 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2020 Igalia, S.L.
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Library General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Library General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Library General Public License
|
||||
+ * along with this library; see the file COPYING.LIB. If not, write to
|
||||
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
+ * Boston, MA 02110-1301, USA.
|
||||
+ */
|
||||
+
|
||||
+#ifdef HAVE_CONFIG_H
|
||||
+#include <config.h>
|
||||
+#endif
|
||||
+
|
||||
+#include <stdlib.h>
|
||||
+
|
||||
+#include "soup-date-utils.h"
|
||||
+#include "soup-date-utils-private.h"
|
||||
+
|
||||
+/**
|
||||
+ * soup_date_time_is_past:
|
||||
+ * @date: a #GDateTime
|
||||
+ *
|
||||
+ * Determines if @date is in the past.
|
||||
+ *
|
||||
+ * Returns: %TRUE if @date is in the past
|
||||
+ */
|
||||
+gboolean
|
||||
+soup_date_time_is_past (GDateTime *date)
|
||||
+{
|
||||
+ g_return_val_if_fail (date != NULL, TRUE);
|
||||
+
|
||||
+ /* optimization */
|
||||
+ if (g_date_time_get_year (date) < 2025)
|
||||
+ return TRUE;
|
||||
+
|
||||
+ return g_date_time_to_unix (date) < time (NULL);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * SoupDateFormat:
|
||||
+ * @SOUP_DATE_HTTP: RFC 1123 format, used by the HTTP "Date" header. Eg
|
||||
+ * "Sun, 06 Nov 1994 08:49:37 GMT".
|
||||
+ * @SOUP_DATE_COOKIE: The format for the "Expires" timestamp in the
|
||||
+ * Netscape cookie specification. Eg, "Sun, 06-Nov-1994 08:49:37 GMT".
|
||||
+ *
|
||||
+ * Date formats that [func@date_time_to_string] can use.
|
||||
+ *
|
||||
+ * @SOUP_DATE_HTTP and @SOUP_DATE_COOKIE always coerce the time to
|
||||
+ * UTC.
|
||||
+ *
|
||||
+ * This enum may be extended with more values in future releases.
|
||||
+ **/
|
||||
+
|
||||
+/* Do not internationalize */
|
||||
+static const char *const months[] = {
|
||||
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
+};
|
||||
+
|
||||
+/* Do not internationalize */
|
||||
+static const char *const days[] = {
|
||||
+ "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * soup_date_time_to_string:
|
||||
+ * @date: a #GDateTime
|
||||
+ * @format: the format to generate the date in
|
||||
+ *
|
||||
+ * Converts @date to a string in the format described by @format.
|
||||
+ *
|
||||
+ * Returns: (transfer full): @date as a string or %NULL
|
||||
+ **/
|
||||
+char *
|
||||
+soup_date_time_to_string (GDateTime *date,
|
||||
+ SoupDateFormat format)
|
||||
+{
|
||||
+ g_return_val_if_fail (date != NULL, NULL);
|
||||
+
|
||||
+ if (format == SOUP_DATE_HTTP || format == SOUP_DATE_COOKIE) {
|
||||
+ /* HTTP and COOKIE formats require UTC timestamp, so coerce
|
||||
+ * @date if it's non-UTC.
|
||||
+ */
|
||||
+ GDateTime *utcdate = g_date_time_to_utc (date);
|
||||
+ char *date_format;
|
||||
+ char *formatted_date;
|
||||
+
|
||||
+ // We insert days/months ourselves to avoid locale specific formatting
|
||||
+ if (format == SOUP_DATE_HTTP) {
|
||||
+ /* "Sun, 06 Nov 1994 08:49:37 GMT" */
|
||||
+ date_format = g_strdup_printf ("%s, %%d %s %%Y %%T GMT",
|
||||
+ days[g_date_time_get_day_of_week (utcdate) - 1],
|
||||
+ months[g_date_time_get_month (utcdate) - 1]);
|
||||
+ } else {
|
||||
+ /* "Sun, 06-Nov-1994 08:49:37 GMT" */
|
||||
+ date_format = g_strdup_printf ("%s, %%d-%s-%%Y %%T GMT",
|
||||
+ days[g_date_time_get_day_of_week (utcdate) - 1],
|
||||
+ months[g_date_time_get_month (utcdate) - 1]);
|
||||
+ }
|
||||
+
|
||||
+ formatted_date = g_date_time_format (utcdate, (const char*)date_format);
|
||||
+ g_date_time_unref (utcdate);
|
||||
+ g_free (date_format);
|
||||
+ return formatted_date;
|
||||
+ }
|
||||
+
|
||||
+ g_return_val_if_reached (NULL);
|
||||
+}
|
||||
+
|
||||
+static inline gboolean
|
||||
+parse_day (int *day, const char **date_string)
|
||||
+{
|
||||
+ char *end;
|
||||
+
|
||||
+ *day = strtoul (*date_string, &end, 10);
|
||||
+ if (end == (char *)*date_string)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ while (*end == ' ' || *end == '-')
|
||||
+ end++;
|
||||
+ *date_string = end;
|
||||
+ return *day >= 1 && *day <= 31;
|
||||
+}
|
||||
+
|
||||
+static inline gboolean
|
||||
+parse_month (int *month, const char **date_string)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < G_N_ELEMENTS (months); i++) {
|
||||
+ if (!g_ascii_strncasecmp (*date_string, months[i], 3)) {
|
||||
+ *month = i + 1;
|
||||
+ *date_string += 3;
|
||||
+ while (**date_string == ' ' || **date_string == '-')
|
||||
+ (*date_string)++;
|
||||
+ return TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+ return FALSE;
|
||||
+}
|
||||
+
|
||||
+static inline gboolean
|
||||
+parse_year (int *year, const char **date_string)
|
||||
+{
|
||||
+ char *end;
|
||||
+
|
||||
+ *year = strtoul (*date_string, &end, 10);
|
||||
+ if (end == (char *)*date_string)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (end == (char *)*date_string + 2) {
|
||||
+ if (*year < 70)
|
||||
+ *year += 2000;
|
||||
+ else
|
||||
+ *year += 1900;
|
||||
+ } else if (end == (char *)*date_string + 3)
|
||||
+ *year += 1900;
|
||||
+
|
||||
+ while (*end == ' ' || *end == '-')
|
||||
+ end++;
|
||||
+ *date_string = end;
|
||||
+ return *year > 0 && *year < 9999;
|
||||
+}
|
||||
+
|
||||
+static inline gboolean
|
||||
+parse_time (int *hour, int *minute, int *second, const char **date_string)
|
||||
+{
|
||||
+ char *p, *end;
|
||||
+
|
||||
+ *hour = strtoul (*date_string, &end, 10);
|
||||
+ if (end == (char *)*date_string || *end++ != ':')
|
||||
+ return FALSE;
|
||||
+ p = end;
|
||||
+ *minute = strtoul (p, &end, 10);
|
||||
+ if (end == p || *end++ != ':')
|
||||
+ return FALSE;
|
||||
+ p = end;
|
||||
+ *second = strtoul (p, &end, 10);
|
||||
+ if (end == p)
|
||||
+ return FALSE;
|
||||
+ p = end;
|
||||
+
|
||||
+ while (*p == ' ')
|
||||
+ p++;
|
||||
+ *date_string = p;
|
||||
+ return *hour >= 0 && *hour < 24 && *minute >= 0 && *minute < 60 && *second >= 0 && *second < 60;
|
||||
+}
|
||||
+
|
||||
+static inline gboolean
|
||||
+parse_timezone (GTimeZone **timezone, const char **date_string)
|
||||
+{
|
||||
+ gint32 offset_minutes;
|
||||
+ gboolean utc;
|
||||
+
|
||||
+ if (!**date_string) {
|
||||
+ utc = FALSE;
|
||||
+ offset_minutes = 0;
|
||||
+ } else if (**date_string == '+' || **date_string == '-') {
|
||||
+ gulong val;
|
||||
+ int sign = (**date_string == '+') ? 1 : -1;
|
||||
+ val = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
+ if (val > 9999)
|
||||
+ return FALSE;
|
||||
+ if (**date_string == ':') {
|
||||
+ gulong val2 = strtoul (*date_string + 1, (char **)date_string, 10);
|
||||
+ if (val > 99 || val2 > 99)
|
||||
+ return FALSE;
|
||||
+ val = 60 * val + val2;
|
||||
+ } else
|
||||
+ val = 60 * (val / 100) + (val % 100);
|
||||
+ offset_minutes = sign * val;
|
||||
+ utc = (sign == -1) && !val;
|
||||
+ } else if (**date_string == 'Z') {
|
||||
+ offset_minutes = 0;
|
||||
+ utc = TRUE;
|
||||
+ (*date_string)++;
|
||||
+ } else if (!strcmp (*date_string, "GMT") ||
|
||||
+ !strcmp (*date_string, "UTC")) {
|
||||
+ offset_minutes = 0;
|
||||
+ utc = TRUE;
|
||||
+ (*date_string) += 3;
|
||||
+ } else if (strchr ("ECMP", **date_string) &&
|
||||
+ ((*date_string)[1] == 'D' || (*date_string)[1] == 'S') &&
|
||||
+ (*date_string)[2] == 'T') {
|
||||
+ offset_minutes = -60 * (5 * strcspn ("ECMP", *date_string));
|
||||
+ if ((*date_string)[1] == 'D')
|
||||
+ offset_minutes += 60;
|
||||
+ utc = FALSE;
|
||||
+ } else
|
||||
+ return FALSE;
|
||||
+
|
||||
+ if (utc)
|
||||
+ *timezone = g_time_zone_new_utc ();
|
||||
+ else
|
||||
+ *timezone = g_time_zone_new_offset (offset_minutes * 60);
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
+static GDateTime *
|
||||
+parse_textual_date (const char *date_string)
|
||||
+{
|
||||
+ int month, day, year, hour, minute, second;
|
||||
+ GTimeZone *tz = NULL;
|
||||
+ GDateTime *date;
|
||||
+
|
||||
+ /* If it starts with a word, it must be a weekday, which we skip */
|
||||
+ if (g_ascii_isalpha (*date_string)) {
|
||||
+ while (g_ascii_isalpha (*date_string))
|
||||
+ date_string++;
|
||||
+ if (*date_string == ',')
|
||||
+ date_string++;
|
||||
+ while (g_ascii_isspace (*date_string))
|
||||
+ date_string++;
|
||||
+ }
|
||||
+
|
||||
+ /* If there's now another word, this must be an asctime-date */
|
||||
+ if (g_ascii_isalpha (*date_string)) {
|
||||
+ /* (Sun) Nov 6 08:49:37 1994 */
|
||||
+ if (!parse_month (&month, &date_string) ||
|
||||
+ !parse_day (&day, &date_string) ||
|
||||
+ !parse_time (&hour, &minute, &second, &date_string) ||
|
||||
+ !parse_year (&year, &date_string) ||
|
||||
+ !g_date_valid_dmy (day, month, year))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* There shouldn't be a timezone, but check anyway */
|
||||
+ parse_timezone (&tz, &date_string);
|
||||
+ } else {
|
||||
+ /* Non-asctime date, so some variation of
|
||||
+ * (Sun,) 06 Nov 1994 08:49:37 GMT
|
||||
+ */
|
||||
+ if (!parse_day (&day, &date_string) ||
|
||||
+ !parse_month (&month, &date_string) ||
|
||||
+ !parse_year (&year, &date_string) ||
|
||||
+ !parse_time (&hour, &minute, &second, &date_string) ||
|
||||
+ !g_date_valid_dmy (day, month, year))
|
||||
+ return NULL;
|
||||
+
|
||||
+ /* This time there *should* be a timezone, but we
|
||||
+ * survive if there isn't.
|
||||
+ */
|
||||
+ parse_timezone (&tz, &date_string);
|
||||
+ }
|
||||
+
|
||||
+ if (!tz)
|
||||
+ tz = g_time_zone_new_utc ();
|
||||
+
|
||||
+ date = g_date_time_new (tz, year, month, day, hour, minute, second);
|
||||
+ g_time_zone_unref (tz);
|
||||
+
|
||||
+ return date;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * soup_date_time_new_from_http_string:
|
||||
+ * @date_string: The date as a string
|
||||
+ *
|
||||
+ * Parses @date_string and tries to extract a date from it.
|
||||
+ *
|
||||
+ * This recognizes all of the "HTTP-date" formats from RFC 2616, RFC 2822 dates,
|
||||
+ * and reasonable approximations thereof. (Eg, it is lenient about whitespace,
|
||||
+ * leading "0"s, etc.)
|
||||
+ *
|
||||
+ * Returns: (nullable): a new #GDateTime, or %NULL if @date_string
|
||||
+ * could not be parsed.
|
||||
+ **/
|
||||
+GDateTime *
|
||||
+soup_date_time_new_from_http_string (const char *date_string)
|
||||
+{
|
||||
+ g_return_val_if_fail (date_string != NULL, NULL);
|
||||
+
|
||||
+ while (g_ascii_isspace (*date_string))
|
||||
+ date_string++;
|
||||
+
|
||||
+ /* If it starts with a digit, it's either an ISO 8601 date, or
|
||||
+ * an RFC2822 date without the optional weekday; in the later
|
||||
+ * case, there will be a month name later on, so look for one
|
||||
+ * of the month-start letters.
|
||||
+ * Previous versions of this library supported parsing iso8601 strings
|
||||
+ * however g_date_time_new_from_iso8601() should be used now. Just
|
||||
+ * catch those in case for testing.
|
||||
+ */
|
||||
+ if (G_UNLIKELY (g_ascii_isdigit (*date_string) && !strpbrk (date_string, "JFMASOND"))) {
|
||||
+ g_debug ("Unsupported format passed to soup_date_time_new_from_http_string(): %s", date_string);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ return parse_textual_date (date_string);
|
||||
+}
|
||||
diff --git a/tests/cookies-test.c b/tests/cookies-test.c
|
||||
index 61adfac5..aa719cdc 100644
|
||||
--- a/tests/cookies-test.c
|
||||
+++ b/tests/cookies-test.c
|
||||
@@ -292,6 +292,7 @@ static void
|
||||
do_cookies_parsing_int32_overflow (void)
|
||||
{
|
||||
SoupCookie *cookie = soup_cookie_parse ("Age=1;expires=3Mar9 999:9:9+ 999999999-age=main=gne=", NULL);
|
||||
+ g_test_bug ("https://gitlab.gnome.org/GNOME/libsoup/-/issues/448");
|
||||
g_assert_nonnull (cookie);
|
||||
g_assert_null (soup_cookie_get_expires (cookie));
|
||||
soup_cookie_free (cookie);
|
||||
--
|
||||
2.51.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From 592db079bc2dfea75708751ed0b7533ac9fd36df Mon Sep 17 00:00:00 2001
|
||||
From: Milan Crha <mcrha@redhat.com>
|
||||
Date: Thu, 15 May 2025 17:49:11 +0200
|
||||
Subject: [PATCH] soup-multipart: Verify boundary limits for multipart body
|
||||
|
||||
It could happen that the boundary started at a place which resulted into
|
||||
a negative number, which in an unsigned integer is a very large value.
|
||||
Check the body size is not a negative value before setting it.
|
||||
|
||||
Closes https://gitlab.gnome.org/GNOME/libsoup/-/issues/449
|
||||
---
|
||||
libsoup/soup-multipart.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsoup/soup-multipart.c b/libsoup/soup-multipart.c
|
||||
index dd939739..ce2fc109 100644
|
||||
--- a/libsoup/soup-multipart.c
|
||||
+++ b/libsoup/soup-multipart.c
|
||||
@@ -214,7 +214,7 @@ soup_multipart_new_from_message (SoupMessageHeaders *headers,
|
||||
*/
|
||||
part_body = soup_buffer_new_subbuffer (flattened,
|
||||
split - flattened->data,
|
||||
- end - 2 - split);
|
||||
+ end - 2 >= split ? end - 2 - split : 0);
|
||||
g_ptr_array_add (multipart->bodies, part_body);
|
||||
|
||||
start = end;
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
From 9ff306aa714efd06ceeafacee03298a3665055b1 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Wed, 30 Apr 2025 14:13:41 -0500
|
||||
Subject: [PATCH] test-utils: fix deadlock in add_listener_in_thread()
|
||||
|
||||
The mutex is locked in the wrong place here.
|
||||
|
||||
Hopefully fixes #379
|
||||
---
|
||||
tests/test-utils.c | 6 ++++--
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/tests/test-utils.c b/tests/test-utils.c
|
||||
index df4cee44..5c1e316c 100644
|
||||
--- a/tests/test-utils.c
|
||||
+++ b/tests/test-utils.c
|
||||
@@ -607,9 +607,11 @@ static gboolean
|
||||
add_listener_in_thread (gpointer user_data)
|
||||
{
|
||||
AddListenerData *data = user_data;
|
||||
+ SoupURI *uri;
|
||||
|
||||
- data->uri = add_listener (data->server, data->scheme, data->host);
|
||||
+ uri = add_listener (data->server, data->scheme, data->host);
|
||||
g_mutex_lock (&data->mutex);
|
||||
+ data->uri = uri;
|
||||
g_cond_signal (&data->cond);
|
||||
g_mutex_unlock (&data->mutex);
|
||||
|
||||
@@ -641,9 +643,9 @@ soup_test_server_get_uri (SoupServer *server,
|
||||
data.host = host;
|
||||
data.uri = NULL;
|
||||
|
||||
- g_mutex_lock (&data.mutex);
|
||||
soup_add_completion (context, add_listener_in_thread, &data);
|
||||
|
||||
+ g_mutex_lock (&data.mutex);
|
||||
while (!data.uri)
|
||||
g_cond_wait (&data.cond, &data.mutex);
|
||||
|
||||
--
|
||||
GitLab
|
||||
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
From 2dafd907586f52291b38c46362e72c7379558626 Mon Sep 17 00:00:00 2001
|
||||
From: "Bernhard M. Wiedemann" <bwiedemann@suse.de>
|
||||
Date: Thu, 18 Feb 2021 09:13:40 +0100
|
||||
Subject: [PATCH] Extend test cert to 2049
|
||||
|
||||
used certtool -u \
|
||||
--load-ca-privkey ./tests/test-key.pem \
|
||||
--load-ca-certificate ./tests/test-cert.pem \
|
||||
--load-certificate ./tests/test-cert.pem
|
||||
|
||||
Without this patch, 3 tests failed in 2027
|
||||
11/29 misc-test FAIL 0.67s (exit status 1)
|
||||
21/29 server-test FAIL 0.12s (exit status 1)
|
||||
25/29 timeout-test FAIL 4.08s (killed by signal 5 SIGTRAP)
|
||||
|
||||
Background:
|
||||
As part of my work on reproducible builds for openSUSE, I check that software still gives identical build results in the future.
|
||||
The usual offset is +15 years, because that is how long I expect some software will be used in some places.
|
||||
This showed up failing tests in our package build.
|
||||
See https://reproducible-builds.org/ for why this matters.
|
||||
|
||||
(cherry picked from commit 38a65f080a3168e8af78bdd3e4928debeea2dbd8)
|
||||
---
|
||||
tests/test-cert.pem | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/tests/test-cert.pem b/tests/test-cert.pem
|
||||
index ff863b4d1..4b8b180dc 100644
|
||||
--- a/tests/test-cert.pem
|
||||
+++ b/tests/test-cert.pem
|
||||
@@ -1,6 +1,6 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC2zCCAcOgAwIBAgIJALRbg2WnuAAqMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
|
||||
-BAMMCTEyNy4wLjAuMTAeFw0xNzA2MjAxNDI3MzBaFw0yNzA2MTgxNDI3MzBaMBQx
|
||||
+BAMMCTEyNy4wLjAuMTAeFw0yMTAyMTgwODA3MzBaFw00OTEyMzEwODA3MzRaMBQx
|
||||
EjAQBgNVBAMMCTEyNy4wLjAuMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAKs4fuRuW77nORhOT9kbbU6BsjKW3GEsMc+ZSmXjINQWpfkES2hV+DQyzhm5
|
||||
qh4OLi1vYtXoSbdQNDCbA8ybZJqR8m9F3ed8vobdSSQGxWpPdXTgz27x+TpiAc9P
|
||||
@@ -8,11 +8,11 @@ w83UuPvlu/0AxHJBFXVAg+id0yFu3wmGWYJHoAtvFi2xeRtAXurNuPtjZyO+gfM9
|
||||
BKTRCkGsRSmPpJyGbU2Q96fjxnVfV9oYvQXeugUcSx/pTUCM/kDgD9QZCxG2rflX
|
||||
NWcqDFY3uO6ZR68Qwi/KouOa8rzrgAcwhFUI6Wz0Zwi1rzRtWK5WqC24aBUYz/tK
|
||||
hl8i88UDXSMh7spChdYDBGLhZyUCAwEAAaMwMC4wLAYDVR0RBCUwI4IJbG9jYWxo
|
||||
-b3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQBj
|
||||
-+U8tebwg5/pof5Rht6TMHqeg6Fcr4OJkL2ph2g+T/AMTS7kEGeFIKJN5AZ+S/qIY
|
||||
-cdoDKHwc8+bCK/mG6DPmJ4z/2Eamb85YhplOLVrLRwfxRebTK9CtnjcjnflAiU9H
|
||||
-7vPVwXIvkwebhBSQNKTdkBlPXKaTNWXuygeFG2OVQkPf/KAxSdtg2R+owv/s802Z
|
||||
-HISk26wY9oFIQz6AiXWdrY1QqNOltZ7rlU5iofAH7X+9ryZlxPWj/gHg2YQRvvLl
|
||||
-dq6nCF+ED0ke7h0lg5nU0beKEygwli8DlLVbu0JK0PkARFp5t7wUtzC9DCjzvfOc
|
||||
-gxR44PyZX7/2oaTDm4PS
|
||||
+b3N0hwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQAz
|
||||
+/qYTUuBGHgp7T1cfaJPnhx6U1SMfdJRtFoWOXDx+MNCK9GYkdMEabzRGUP5uNHO+
|
||||
+PiZP/bMIHlpsbRA5AyyVf9Xv8JCujvYh24qYcBbwgZrfvNTm0D52P9JJm0SalTXS
|
||||
+kwwTj00DWGVfVzJR+wiwYGHRIlyXbHqQSRzv6+z9f/xY5gXw/KpCNYTuOJcXW7w6
|
||||
+JfMrUnc9pphRUpcLkuuzOMKuB0dtWRc0mZIr7PZHt+0gitNZWA0bDYI3JI9tlK17
|
||||
+nxBUSpGtJwDgH//b8ek/P0P9a5VzQbBC6lXtQUMdxg7ovfAI//IS8ekBoRKI0Wde
|
||||
+r2IpM9hKSBU3c2gGXcJC
|
||||
-----END CERTIFICATE-----
|
||||
--
|
||||
GitLab
|
||||
|
||||
14
SOURCES/test-timeouts.patch
Normal file
14
SOURCES/test-timeouts.patch
Normal file
@ -0,0 +1,14 @@
|
||||
diff --git a/tests/meson.build b/tests/meson.build
|
||||
index 5482aa86..bd90df15 100644
|
||||
--- a/tests/meson.build
|
||||
+++ b/tests/meson.build
|
||||
@@ -190,7 +190,7 @@ foreach test: tests
|
||||
)
|
||||
# Increase the timeout as on some architectures the tests could be slower
|
||||
# than the default 30 seconds.
|
||||
- test(test_name, test_target, env : env, is_parallel : test[1], timeout : 60)
|
||||
+ test(test_name, test_target, env : env, is_parallel : test[1], timeout : 300)
|
||||
endforeach
|
||||
|
||||
executable('ntlm-test-helper', 'ntlm-test-helper.c',
|
||||
|
||||
@ -1,61 +1,46 @@
|
||||
%define glib2_version 2.38.0
|
||||
%define glib2_version 2.58.0
|
||||
|
||||
# Coverity scan can override this to 0, to skip checking in gtk-doc generated code
|
||||
%{!?with_docs: %global with_docs 1}
|
||||
|
||||
Name: libsoup
|
||||
Version: 2.62.3
|
||||
Version: 2.72.0
|
||||
Release: 10%{?dist}
|
||||
Summary: Soup, an HTTP library implementation
|
||||
|
||||
License: LGPLv2
|
||||
URL: https://wiki.gnome.org/Projects/libsoup
|
||||
Source0: https://download.gnome.org/sources/%{name}/2.62/%{name}-%{version}.tar.xz
|
||||
Source0: https://download.gnome.org/sources/%{name}/2.72/%{name}-%{version}.tar.xz
|
||||
|
||||
Patch0001: 0001-WebSockets-ignore-any-messages-after-close-has-been-.patch
|
||||
Patch0002: 0002-WebSockets-allow-null-characters-in-text-messages-da.patch
|
||||
Patch0003: 0003-WebSockets-only-poll-IO-stream-when-needed.patch
|
||||
Patch0004: 0004-ntlmv2.patch
|
||||
Patch0005: 0005-WebSockets-do-not-start-the-input-source-when-IO-is-closing.patch
|
||||
Patch0006: CVE-2024-52530.patch
|
||||
Patch0007: CVE-2024-52531.patch
|
||||
Patch0008: CVE-2024-52532.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/446
|
||||
Patch0009: test-cert-expiration.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/415
|
||||
Patch0010: CVE-2025-32050.patch
|
||||
Patch0011: CVE-2025-32052.patch
|
||||
Patch0012: CVE-2025-32053.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/440
|
||||
Patch0013: CVE-2025-32906.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/422
|
||||
Patch0014: CVE-2025-32911-CVE-2025-32913.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/421
|
||||
Patch0015: CVE-2025-46420.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/436
|
||||
Patch0016: CVE-2025-46421.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/408 (simplified)
|
||||
Patch0017: CVE-2025-32049.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/450
|
||||
Patch0018: CVE-2025-32914.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/issues/422
|
||||
Patch0019: CVE-2025-2784.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/463
|
||||
Patch0020: CVE-2025-4948.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/426
|
||||
Patch: test-timeouts.patch
|
||||
# https://issues.redhat.com/browse/RHEL-76426
|
||||
Patch0021: fix-ssl-test.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/454
|
||||
Patch0022: server-test-timeouts.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/473
|
||||
Patch0023: CVE-2025-4945-CVE-2025-11021.patch
|
||||
Patch: fix-ssl-test.patch
|
||||
|
||||
BuildRequires: chrpath
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/402
|
||||
Patch: CVE-2024-52530.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/407
|
||||
Patch: CVE-2024-52531.patch
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/410
|
||||
# https://gitlab.gnome.org/GNOME/libsoup/-/merge_requests/414
|
||||
Patch: CVE-2024-52532.patch
|
||||
|
||||
BuildRequires: gettext
|
||||
BuildRequires: glib2-devel >= %{glib2_version}
|
||||
BuildRequires: glib-networking
|
||||
BuildRequires: intltool
|
||||
BuildRequires: krb5-devel >= 1.11
|
||||
%if %{with_docs}
|
||||
BuildRequires: gtk-doc
|
||||
%endif
|
||||
BuildRequires: krb5-devel
|
||||
BuildRequires: meson
|
||||
BuildRequires: pkgconfig(gobject-introspection-1.0)
|
||||
BuildRequires: pkgconfig(libbrotlidec)
|
||||
BuildRequires: pkgconfig(libxml-2.0)
|
||||
BuildRequires: pkgconfig(libpsl)
|
||||
BuildRequires: pkgconfig(sqlite3)
|
||||
BuildRequires: python3-devel
|
||||
BuildRequires: pkgconfig(sysprof-capture-4)
|
||||
BuildRequires: vala
|
||||
BuildRequires: /usr/bin/ntlm_auth
|
||||
|
||||
Requires: glib2%{?_isa} >= %{glib2_version}
|
||||
Requires: glib-networking%{?_isa} >= %{glib2_version}
|
||||
@ -79,99 +64,213 @@ Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
Libsoup is an HTTP library implementation in C. This package allows
|
||||
you to develop applications that use the libsoup library.
|
||||
|
||||
%if %{with_docs}
|
||||
|
||||
%package doc
|
||||
Summary: Documentation files for %{name}
|
||||
BuildArch: noarch
|
||||
|
||||
%description doc
|
||||
This package contains developer documentation for %{name}.
|
||||
|
||||
# %%{with_docs}
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%autosetup -p1
|
||||
|
||||
%build
|
||||
%configure --disable-static
|
||||
%if %{with_docs}
|
||||
%define gtkdoc_flags -Dgtk_doc=true
|
||||
%else
|
||||
%define gtkdoc_flags -Dgtk_doc=false
|
||||
%endif
|
||||
|
||||
# Omit unused direct shared library dependencies.
|
||||
sed --in-place --expression 's! -shared ! -Wl,--as-needed\0!g' libtool
|
||||
|
||||
make %{?_smp_mflags}
|
||||
%meson %gtkdoc_flags
|
||||
%meson_build
|
||||
|
||||
%install
|
||||
%make_install
|
||||
%meson_install
|
||||
|
||||
rm -f $RPM_BUILD_ROOT/%{_libdir}/*.la
|
||||
|
||||
# Remove lib64 rpaths
|
||||
chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so
|
||||
%check
|
||||
%meson_test
|
||||
|
||||
%find_lang libsoup
|
||||
|
||||
%files -f libsoup.lang
|
||||
%license COPYING
|
||||
%doc README NEWS AUTHORS
|
||||
%{_libdir}/lib*.so.*
|
||||
%{_libdir}/libsoup-2.4.so.1*
|
||||
%{_libdir}/libsoup-gnome-2.4.so.1*
|
||||
%dir %{_libdir}/girepository-1.0
|
||||
%{_libdir}/girepository-1.0/Soup*2.4.typelib
|
||||
|
||||
%files devel
|
||||
%{_includedir}/%{name}-2.4
|
||||
%{_includedir}/%{name}-gnome-2.4
|
||||
%{_libdir}/*.so
|
||||
%{_includedir}/libsoup-2.4
|
||||
%{_includedir}/libsoup-gnome-2.4
|
||||
%{_libdir}/libsoup-2.4.so
|
||||
%{_libdir}/libsoup-gnome-2.4.so
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
%dir %{_datadir}/gir-1.0
|
||||
%{_datadir}/gir-1.0/Soup*2.4.gir
|
||||
%{_datadir}/gtk-doc/html/%{name}-2.4
|
||||
%dir %{_datadir}/vala
|
||||
%dir %{_datadir}/vala/vapi
|
||||
%{_datadir}/vala/vapi/libsoup-2.4.deps
|
||||
%{_datadir}/vala/vapi/libsoup-2.4.vapi
|
||||
|
||||
%if %{with_docs}
|
||||
|
||||
%files doc
|
||||
%dir %{_datadir}/gtk-doc
|
||||
%dir %{_datadir}/gtk-doc/html
|
||||
%{_datadir}/gtk-doc/html/%{name}-2.4
|
||||
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Thu Oct 30 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.62.3-10
|
||||
- Backport patch for CVE-2025-4945 and CVE-2025-11021
|
||||
* Tue Jan 28 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.72.0-10
|
||||
- Enable tests in check, and add patches to fix tests
|
||||
Resolves: RHEL-76426
|
||||
|
||||
* Thu May 22 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.62.3-9
|
||||
- Add patches to improve test reliability
|
||||
- Backport patches for various CVEs
|
||||
Resolves: RHEL-85879
|
||||
Resolves: RHEL-92280
|
||||
Resolves: RHEL-93031
|
||||
Resolves: RHEL-93032
|
||||
* Fri Jan 10 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.72.0-9
|
||||
- Add patches for CVE-2024-52530, CVE-2024-52531, and CVE-2024-52532
|
||||
Resolves: RHEL-67069
|
||||
Resolves: RHEL-67081
|
||||
|
||||
* Thu May 01 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.62.3-8
|
||||
- Backport patches for various CVEs, plus test improvements
|
||||
Resolves: RHEL-85887
|
||||
Resolves: RHEL-85900
|
||||
Resolves: RHEL-85901
|
||||
Resolves: RHEL-87039
|
||||
Resolves: RHEL-87094
|
||||
Resolves: RHEL-87114
|
||||
Resolves: RHEL-88348
|
||||
Resolves: RHEL-88351
|
||||
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.72.0-8
|
||||
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
|
||||
Related: rhbz#1991688
|
||||
|
||||
* Tue Jan 28 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.62.3-7
|
||||
- Backport upstream patch for CVE-2024-52531 - buffer overflow via UTF-8 conversion in soup_header_parse_param_list_strict
|
||||
Resolves: RHEL-76376
|
||||
* Fri Apr 16 2021 Mohan Boddu <mboddu@redhat.com> - 2.72.0-7
|
||||
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
|
||||
|
||||
* Tue Nov 12 2024 Tomas Popela <tpopela@redhat.com> - 2.62.3-6
|
||||
- Backport upstream patch for CVE-2024-52530 - HTTP request smuggling via stripping null bytes from the ends of header names
|
||||
- Backport upstream patch for CVE-2024-52532 - infinite loop while reading websocket data
|
||||
- Resolves: RHEL-67076
|
||||
- Resolves: RHEL-67067
|
||||
* Fri Mar 26 2021 Kalev Lember <klember@redhat.com> - 2.72.0-6
|
||||
- Rebuild to fix sysprof-capture symbols leaking into libraries consuming it
|
||||
|
||||
* Tue Sep 05 2023 Milan Crha <mcrha@redhat.com> - 2.62.3-5
|
||||
- Resolves: RHEL-2240 (Correct BuildRequires for python3)
|
||||
* Wed Feb 24 2021 Kalev Lember <klember@redhat.com> - 2.72.0-5
|
||||
- Don't try to avoid sysprof dep any more now that sysprof-capture-devel is
|
||||
split out to a separate subpackage
|
||||
|
||||
* Mon May 15 2023 Milan Crha <mcrha@redhat.com> - 2.62.3-4
|
||||
- Resolves: #2203398 (WebSocket server asserts when a client is closing the connection)
|
||||
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.72.0-4
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
|
||||
|
||||
* Fri Sep 16 2022 Milan Crha <mcrha@redhat.com> - 2.62.3-3
|
||||
- Resolves: #1938011 (Support for NTLMv2 Authentication)
|
||||
* Sun Sep 20 2020 Kalev Lember <klember@redhat.com> - 2.72.0-3
|
||||
- Try harder to avoid sysprof-devel dependency
|
||||
|
||||
* Thu Aug 27 2020 Martin Pitt <mpitt@redhat.com> - 2.62.3-2
|
||||
- Some WebSocket fixes to unbreak cockpit-desktop (rhbz#1872270)
|
||||
* Sun Sep 20 2020 Kalev Lember <klember@redhat.com> - 2.72.0-2
|
||||
- Tighten soname globs
|
||||
- Avoid automatic requires on sysprof-devel package
|
||||
- Update required glib2 version
|
||||
|
||||
* Mon Sep 14 2020 Kalev Lember <klember@redhat.com> - 2.72.0-1
|
||||
- Update to 2.72.0
|
||||
|
||||
* Sun Sep 06 2020 Kalev Lember <klember@redhat.com> - 2.71.1-1
|
||||
- Update to 2.71.1
|
||||
|
||||
* Tue Jul 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.71.0-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
|
||||
|
||||
* Mon Jul 20 2020 Kalev Lember <klember@redhat.com> - 2.71.0-1
|
||||
- Update to 2.71.0
|
||||
|
||||
* Sat Mar 07 2020 Kalev Lember <klember@redhat.com> - 2.70.0-1
|
||||
- Update to 2.70.0
|
||||
|
||||
* Mon Feb 03 2020 Kalev Lember <klember@redhat.com> - 2.69.90-1
|
||||
- Update to 2.69.90
|
||||
|
||||
* Wed Jan 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.68.3-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
|
||||
|
||||
* Wed Dec 04 2019 Kalev Lember <klember@redhat.com> - 2.68.3-1
|
||||
- Update to 2.68.3
|
||||
|
||||
* Wed Oct 09 2019 Kalev Lember <klember@redhat.com> - 2.68.2-1
|
||||
- Update to 2.68.2
|
||||
|
||||
* Wed Sep 11 2019 Kalev Lember <klember@redhat.com> - 2.68.1-1
|
||||
- Update to 2.68.1
|
||||
|
||||
* Wed Sep 11 2019 Kalev Lember <klember@redhat.com> - 2.68.0-1
|
||||
- Update to 2.68.0
|
||||
|
||||
* Tue Sep 03 2019 Kalev Lember <klember@redhat.com> - 2.67.93-1
|
||||
- Update to 2.67.93
|
||||
|
||||
* Tue Aug 20 2019 Kalev Lember <klember@redhat.com> - 2.67.92-1
|
||||
- Update to 2.67.92
|
||||
|
||||
* Mon Aug 12 2019 Kalev Lember <klember@redhat.com> - 2.67.91-1
|
||||
- Update to 2.67.91
|
||||
|
||||
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.67.3-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
|
||||
|
||||
* Thu Jul 18 2019 Kalev Lember <klember@redhat.com> - 2.67.3-1
|
||||
- Update to 2.67.3
|
||||
|
||||
* Mon Jun 17 2019 Kalev Lember <klember@redhat.com> - 2.67.2-1
|
||||
- Update to 2.67.2
|
||||
|
||||
* Thu May 23 2019 Kalev Lember <klember@redhat.com> - 2.67.1-1
|
||||
- Update to 2.67.1
|
||||
|
||||
* Wed May 15 2019 Kalev Lember <klember@redhat.com> - 2.66.2-1
|
||||
- Update to 2.66.2
|
||||
|
||||
* Tue Apr 16 2019 Adam Williamson <awilliam@redhat.com> - 2.66.1-2
|
||||
- Rebuild with Meson fix for #1699099
|
||||
|
||||
* Tue Apr 09 2019 Kalev Lember <klember@redhat.com> - 2.66.1-1
|
||||
- Update to 2.66.1
|
||||
|
||||
* Tue Mar 12 2019 Kalev Lember <klember@redhat.com> - 2.66.0-1
|
||||
- Update to 2.66.0
|
||||
|
||||
* Tue Mar 05 2019 Kalev Lember <klember@redhat.com> - 2.65.92-1
|
||||
- Update to 2.65.92
|
||||
|
||||
* Wed Feb 20 2019 Kalev Lember <klember@redhat.com> - 2.65.91-1
|
||||
- Update to 2.65.91
|
||||
|
||||
* Tue Feb 05 2019 Kalev Lember <klember@redhat.com> - 2.65.90-1
|
||||
- Update to 2.65.90
|
||||
|
||||
* Fri Feb 01 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.65.2-2
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
|
||||
|
||||
* Wed Jan 23 2019 Kalev Lember <klember@redhat.com> - 2.65.2-1
|
||||
- Update to 2.65.2
|
||||
- Switch to the meson build system
|
||||
- Co-own gir and gtk-doc directories
|
||||
|
||||
* Tue Oct 09 2018 Kalev Lember <klember@redhat.com> - 2.65.1-1
|
||||
- Update to 2.65.1
|
||||
|
||||
* Tue Sep 25 2018 Kalev Lember <klember@redhat.com> - 2.64.1-1
|
||||
- Update to 2.64.1
|
||||
|
||||
* Fri Sep 07 2018 Kalev Lember <klember@redhat.com> - 2.64.0-2
|
||||
- Rebuilt against fixed atk (#1626575)
|
||||
|
||||
* Wed Sep 05 2018 Kalev Lember <klember@redhat.com> - 2.64.0-1
|
||||
- Update to 2.64.0
|
||||
|
||||
* Sun Aug 12 2018 Kalev Lember <klember@redhat.com> - 2.63.90-1
|
||||
- Update to 2.63.90
|
||||
|
||||
* Fri Aug 10 2018 Kalev Lember <klember@redhat.com> - 2.62.3-1
|
||||
- Update to 2.62.3
|
||||
|
||||
* Thu Jul 19 2018 Milan Crha <mcrha@redhat.com> - 2.62.2-2
|
||||
- Address some of the Coverity Scan and clang issues
|
||||
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.62.2-3
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
|
||||
|
||||
* Wed Jul 04 2018 Milan Crha <mcrha@redhat.com> - 2.62.2-1
|
||||
* Thu Jun 28 2018 Kalev Lember <klember@redhat.com> - 2.62.2-2
|
||||
- Backport an upstream patch for CVE-2018-12910
|
||||
|
||||
* Tue May 08 2018 Kalev Lember <klember@redhat.com> - 2.62.2-1
|
||||
- Update to 2.62.2
|
||||
- Backport upstream patch for CVE-2018-12910 - Crash in soup_cookie_jar.c:get_cookies() on empty hostnames
|
||||
|
||||
* Mon Apr 09 2018 Kalev Lember <klember@redhat.com> - 2.62.1-1
|
||||
- Update to 2.62.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user