Compare commits
No commits in common. 'c9' and 'i8c-beta' have entirely different histories.
@ -1 +1 @@
|
||||
SOURCES/libsoup-2.72.0.tar.xz
|
||||
SOURCES/libsoup-2.62.3.tar.xz
|
||||
|
@ -1 +1 @@
|
||||
6aaed6b49b13e287b7c3bba546ba49fec4ea72a5 SOURCES/libsoup-2.72.0.tar.xz
|
||||
8b9c743348b1f9fc044c6abf3431899154e93ad1 SOURCES/libsoup-2.62.3.tar.xz
|
||||
|
@ -0,0 +1,95 @@
|
||||
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,
|
@ -0,0 +1,152 @@
|
||||
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
|
||||
|
@ -0,0 +1,299 @@
|
||||
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
|
||||
|
@ -0,0 +1,356 @@
|
||||
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;
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
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,145 +0,0 @@
|
||||
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.
|
||||
*/
|
||||
|
||||
+ /* No '\0's are allowed */
|
||||
+ if (memchr (str, '\0', len))
|
||||
+ return FALSE;
|
||||
+
|
||||
/* Skip over the Request-Line / Status-Line */
|
||||
headers_start = memchr (str, '\n', len);
|
||||
if (!headers_start)
|
||||
return FALSE;
|
||||
- /* No '\0's in the Request-Line / Status-Line */
|
||||
- if (memchr (str, '\0', headers_start - str))
|
||||
- return FALSE;
|
||||
|
||||
/* 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
|
||||
@@ -69,14 +70,6 @@ soup_headers_parse (const char *str, int len, SoupMessageHeaders *dest)
|
||||
headers_copy[copy_len] = '\0';
|
||||
value_end = headers_copy;
|
||||
|
||||
- /* There shouldn't be any '\0's in the headers already, but
|
||||
- * this is the web we're talking about.
|
||||
- */
|
||||
- while ((p = memchr (headers_copy, '\0', copy_len))) {
|
||||
- memmove (p, p + 1, copy_len - (p - headers_copy));
|
||||
- copy_len--;
|
||||
- }
|
||||
-
|
||||
while (*(value_end + 1)) {
|
||||
name = value_end + 1;
|
||||
name_end = strchr (name, ':');
|
||||
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 {
|
||||
}
|
||||
},
|
||||
|
||||
- { "NUL in header name", "760832",
|
||||
- "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36,
|
||||
- SOUP_STATUS_OK,
|
||||
- "GET", "/", SOUP_HTTP_1_1,
|
||||
- { { "Host", "example.com" },
|
||||
- { NULL }
|
||||
- }
|
||||
- },
|
||||
-
|
||||
- { "NUL in header value", "760832",
|
||||
- "GET / HTTP/1.1\r\nHost: example\x00" "com\r\n", 35,
|
||||
- SOUP_STATUS_OK,
|
||||
- "GET", "/", SOUP_HTTP_1_1,
|
||||
- { { "Host", "examplecom" },
|
||||
- { NULL }
|
||||
- }
|
||||
- },
|
||||
-
|
||||
/************************/
|
||||
/*** INVALID REQUESTS ***/
|
||||
/************************/
|
||||
@@ -448,6 +430,21 @@ static struct RequestTest {
|
||||
SOUP_STATUS_EXPECTATION_FAILED,
|
||||
NULL, NULL, -1,
|
||||
{ { NULL } }
|
||||
+ },
|
||||
+
|
||||
+ // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377
|
||||
+ { "NUL in header name", NULL,
|
||||
+ "GET / HTTP/1.1\r\nHost\x00: example.com\r\n", 36,
|
||||
+ SOUP_STATUS_BAD_REQUEST,
|
||||
+ NULL, NULL, -1,
|
||||
+ { { NULL } }
|
||||
+ },
|
||||
+
|
||||
+ { "NUL in header value", NULL,
|
||||
+ "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28,
|
||||
+ SOUP_STATUS_BAD_REQUEST,
|
||||
+ NULL, NULL, -1,
|
||||
+ { { NULL } }
|
||||
}
|
||||
};
|
||||
static const int num_reqtests = G_N_ELEMENTS (reqtests);
|
||||
@@ -620,22 +617,6 @@ static struct ResponseTest {
|
||||
{ NULL } }
|
||||
},
|
||||
|
||||
- { "NUL in header name", "760832",
|
||||
- "HTTP/1.1 200 OK\r\nF\x00oo: bar\r\n", 28,
|
||||
- SOUP_HTTP_1_1, SOUP_STATUS_OK, "OK",
|
||||
- { { "Foo", "bar" },
|
||||
- { NULL }
|
||||
- }
|
||||
- },
|
||||
-
|
||||
- { "NUL in header value", "760832",
|
||||
- "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28,
|
||||
- SOUP_HTTP_1_1, SOUP_STATUS_OK, "OK",
|
||||
- { { "Foo", "bar" },
|
||||
- { NULL }
|
||||
- }
|
||||
- },
|
||||
-
|
||||
/********************************/
|
||||
/*** VALID CONTINUE RESPONSES ***/
|
||||
/********************************/
|
||||
@@ -768,6 +749,19 @@ static struct ResponseTest {
|
||||
{ { NULL }
|
||||
}
|
||||
},
|
||||
+
|
||||
+ // https://gitlab.gnome.org/GNOME/libsoup/-/issues/377
|
||||
+ { "NUL in header name", NULL,
|
||||
+ "HTTP/1.1 200 OK\r\nF\x00oo: bar\r\n", 28,
|
||||
+ -1, 0, NULL,
|
||||
+ { { NULL } }
|
||||
+ },
|
||||
+
|
||||
+ { "NUL in header value", "760832",
|
||||
+ "HTTP/1.1 200 OK\r\nFoo: b\x00" "ar\r\n", 28,
|
||||
+ -1, 0, NULL,
|
||||
+ { { NULL } }
|
||||
+ },
|
||||
};
|
||||
static const int num_resptests = G_N_ELEMENTS (resptests);
|
||||
|
||||
--
|
||||
2.45.2
|
||||
|
@ -1,129 +0,0 @@
|
||||
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
|
||||
params
|
||||
|
||||
If you pass invalid input to a function such as soup_header_parse_param_list_strict()
|
||||
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, 24 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/libsoup/soup-headers.c b/libsoup/soup-headers.c
|
||||
index f30ee467..613e1905 100644
|
||||
--- a/libsoup/soup-headers.c
|
||||
+++ b/libsoup/soup-headers.c
|
||||
@@ -646,8 +646,9 @@ soup_header_contains (const char *header, const char *token)
|
||||
}
|
||||
|
||||
static void
|
||||
-decode_quoted_string (char *quoted_string)
|
||||
+decode_quoted_string_inplace (GString *quoted_gstring)
|
||||
{
|
||||
+ char *quoted_string = quoted_gstring->str;
|
||||
char *src, *dst;
|
||||
|
||||
src = quoted_string + 1;
|
||||
@@ -661,10 +662,11 @@ decode_quoted_string (char *quoted_string)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-decode_rfc5987 (char *encoded_string)
|
||||
+decode_rfc5987_inplace (GString *encoded_gstring)
|
||||
{
|
||||
char *q, *decoded;
|
||||
gboolean iso_8859_1 = FALSE;
|
||||
+ const char *encoded_string = encoded_gstring->str;
|
||||
|
||||
q = strchr (encoded_string, '\'');
|
||||
if (!q)
|
||||
@@ -696,14 +698,7 @@ decode_rfc5987 (char *encoded_string)
|
||||
decoded = utf8;
|
||||
}
|
||||
|
||||
- /* If encoded_string was UTF-8, then each 3-character %-escape
|
||||
- * will be converted to a single byte, and so decoded is
|
||||
- * shorter than encoded_string. If encoded_string was
|
||||
- * iso-8859-1, then each 3-character %-escape will be
|
||||
- * converted into at most 2 bytes in UTF-8, and so it's still
|
||||
- * shorter.
|
||||
- */
|
||||
- strcpy (encoded_string, decoded);
|
||||
+ g_string_assign (encoded_gstring, decoded);
|
||||
g_free (decoded);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -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, duplicated;
|
||||
|
||||
params = g_hash_table_new_full (soup_str_case_hash,
|
||||
soup_str_case_equal,
|
||||
- g_free, NULL);
|
||||
+ g_free, g_free);
|
||||
|
||||
list = parse_list (header, delim);
|
||||
for (iter = list; iter; iter = iter->next) {
|
||||
+ char *item, *eq, *name_end;
|
||||
+ gboolean override, duplicated;
|
||||
+ GString *parsed_value = NULL;
|
||||
+
|
||||
item = iter->data;
|
||||
override = FALSE;
|
||||
|
||||
@@ -736,19 +733,19 @@ parse_param_list (const char *header, char delim, gboolean strict)
|
||||
|
||||
*name_end = '\0';
|
||||
|
||||
- value = (char *)skip_lws (eq + 1);
|
||||
+ parsed_value = g_string_new ((char *)skip_lws (eq + 1));
|
||||
|
||||
if (name_end[-1] == '*' && name_end > item + 1) {
|
||||
name_end[-1] = '\0';
|
||||
- if (!decode_rfc5987 (value)) {
|
||||
+ if (!decode_rfc5987_inplace (parsed_value)) {
|
||||
+ g_string_free (parsed_value, TRUE);
|
||||
g_free (item);
|
||||
continue;
|
||||
}
|
||||
override = TRUE;
|
||||
- } else if (*value == '"')
|
||||
- decode_quoted_string (value);
|
||||
- } else
|
||||
- value = NULL;
|
||||
+ } else if (parsed_value->str[0] == '"')
|
||||
+ decode_quoted_string_inplace (parsed_value);
|
||||
+ }
|
||||
|
||||
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)
|
||||
+ g_string_free (parsed_value, TRUE);
|
||||
g_free (item);
|
||||
+ }
|
||||
}
|
||||
|
||||
g_slist_free (list);
|
||||
--
|
||||
GitLab
|
||||
|
@ -1,96 +0,0 @@
|
||||
diff -up libsoup-2.62.3/libsoup/soup-websocket-connection.c.cve-2024-52532 libsoup-2.62.3/libsoup/soup-websocket-connection.c
|
||||
--- libsoup-2.62.3/libsoup/soup-websocket-connection.c.cve-2024-52532 2024-11-12 12:00:27.183570627 +0100
|
||||
+++ libsoup-2.62.3/libsoup/soup-websocket-connection.c 2024-11-12 12:01:02.334987409 +0100
|
||||
@@ -1041,9 +1041,9 @@ soup_websocket_connection_read (SoupWebs
|
||||
}
|
||||
|
||||
pv->incoming->len = len + count;
|
||||
- } while (count > 0);
|
||||
+ process_incoming (self);
|
||||
+ } while (count > 0 && !pv->close_sent && !pv->io_closing);
|
||||
|
||||
- process_incoming (self);
|
||||
|
||||
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,123 +0,0 @@
|
||||
From c720f9c696b3b39d8c386abf8c8a9ddad447cda0 Mon Sep 17 00:00:00 2001
|
||||
From: Carlos Garcia Campos <cgarcia@igalia.com>
|
||||
Date: Wed, 9 Sep 2020 14:44:25 +0200
|
||||
Subject: [PATCH 1/2] tests: fix SSL test with glib-networking >= 2.65.90
|
||||
|
||||
To make SSL tests fail with our testing certificate we create and empty
|
||||
GTlsDatabase passing /dev/null to g_tls_file_database_new(). This no
|
||||
longer works with newer glib-networking, since an empty file is
|
||||
considered an error by gnutls and
|
||||
g_tls_file_database_gnutls_populate_trust_list() now handles gnutls
|
||||
errors properly. Instead, we can just use the system CA file that won't
|
||||
contain our testing certificate for sure.
|
||||
|
||||
Fixes #201
|
||||
---
|
||||
tests/ssl-test.c | 12 +++---------
|
||||
1 file changed, 3 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/tests/ssl-test.c b/tests/ssl-test.c
|
||||
index 735ba416..2c93ca85 100644
|
||||
--- a/tests/ssl-test.c
|
||||
+++ b/tests/ssl-test.c
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "test-utils.h"
|
||||
|
||||
SoupURI *uri;
|
||||
-GTlsDatabase *null_tlsdb;
|
||||
|
||||
static void
|
||||
do_properties_test_for_session (SoupSession *session)
|
||||
@@ -37,7 +36,7 @@ do_async_properties_tests (void)
|
||||
|
||||
session = soup_test_session_new (SOUP_TYPE_SESSION_ASYNC, NULL);
|
||||
g_object_set (G_OBJECT (session),
|
||||
- SOUP_SESSION_TLS_DATABASE, null_tlsdb,
|
||||
+ SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
|
||||
SOUP_SESSION_SSL_STRICT, FALSE,
|
||||
NULL);
|
||||
do_properties_test_for_session (session);
|
||||
@@ -53,7 +52,7 @@ do_sync_properties_tests (void)
|
||||
|
||||
session = soup_test_session_new (SOUP_TYPE_SESSION_SYNC, NULL);
|
||||
g_object_set (G_OBJECT (session),
|
||||
- SOUP_SESSION_TLS_DATABASE, null_tlsdb,
|
||||
+ SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
|
||||
SOUP_SESSION_SSL_STRICT, FALSE,
|
||||
NULL);
|
||||
do_properties_test_for_session (session);
|
||||
@@ -106,7 +105,7 @@ do_strictness_test (gconstpointer data)
|
||||
}
|
||||
if (!test->with_ca_list) {
|
||||
g_object_set (G_OBJECT (session),
|
||||
- SOUP_SESSION_TLS_DATABASE, null_tlsdb,
|
||||
+ SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@@ -433,7 +432,6 @@ main (int argc, char **argv)
|
||||
{
|
||||
SoupServer *server = NULL;
|
||||
int i, ret;
|
||||
- GError *error = NULL;
|
||||
|
||||
test_init (argc, argv, NULL);
|
||||
|
||||
@@ -441,9 +439,6 @@ main (int argc, char **argv)
|
||||
server = soup_test_server_new (SOUP_TEST_SERVER_IN_THREAD);
|
||||
soup_server_add_handler (server, NULL, server_handler, NULL, NULL);
|
||||
uri = soup_test_server_get_uri (server, "https", "127.0.0.1");
|
||||
-
|
||||
- null_tlsdb = g_tls_file_database_new ("/dev/null", &error);
|
||||
- g_assert_no_error (error);
|
||||
} else
|
||||
uri = NULL;
|
||||
|
||||
@@ -463,7 +458,6 @@ main (int argc, char **argv)
|
||||
if (tls_available) {
|
||||
soup_uri_free (uri);
|
||||
soup_test_server_quit_unref (server);
|
||||
- g_object_unref (null_tlsdb);
|
||||
}
|
||||
|
||||
test_cleanup ();
|
||||
--
|
||||
2.43.5
|
||||
|
||||
|
||||
From 0fbc7e8220c32f4848d6f1407efe81cc13ab18ef Mon Sep 17 00:00:00 2001
|
||||
From: Michael Catanzaro <mcatanzaro@redhat.com>
|
||||
Date: Sat, 18 Jan 2025 01:20:24 -0600
|
||||
Subject: [PATCH 2/2] Add workaround for flaky ssl-test connection failures
|
||||
|
||||
---
|
||||
tests/ssl-test.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/tests/ssl-test.c b/tests/ssl-test.c
|
||||
index 2c93ca85..1b48c6aa 100644
|
||||
--- a/tests/ssl-test.c
|
||||
+++ b/tests/ssl-test.c
|
||||
@@ -348,6 +348,19 @@ got_connection (GThreadedSocketService *service,
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
+ // Work around a race condition where do_tls_interaction_test's call to
|
||||
+ // soup_session_send_message() fails due to the server having closed the
|
||||
+ // connection:
|
||||
+ //
|
||||
+ // ERROR:../tests/ssl-test.c:405:do_tls_interaction_test: Unexpected status 7 Connection terminated unexpectedly (expected 200 OK)
|
||||
+ //
|
||||
+ // This bug is already fixed upstream, so no sense in spending a bunch
|
||||
+ // of time trying to find a proper fix.
|
||||
+ //
|
||||
+ // I'm not certain, but I suspect it's fixed by:
|
||||
+ // https://gitlab.gnome.org/GNOME/libsoup/-/commit/bd6de90343839125bd07c43c97e1000deb0b40c3
|
||||
+ sleep (1);
|
||||
+
|
||||
g_io_stream_close (tls, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
--
|
||||
2.43.5
|
||||
|
Loading…
Reference in new issue