summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garcia Campos <cgarcia@igalia.com>2022-08-30 15:28:59 +0200
committerCarlos Garcia Campos <cgarcia@igalia.com>2022-08-31 11:09:26 +0200
commitbba8c0faed1fcbfc6742530bbfe516837636991b (patch)
treeffb3132eb38123349d1ced530c7edbc8e0ac12e0
parent1b60814b152c973d3a71b1ef9e149b6632a9ecd0 (diff)
downloadlibsoup-bba8c0faed1fcbfc6742530bbfe516837636991b.tar.gz
server: make sure we don't call nghttp2 IO functions from callbacks
-rw-r--r--libsoup/server/http2/soup-server-message-io-http2.c40
1 files changed, 38 insertions, 2 deletions
diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c
index 81a5dd3c..e9e2fbfb 100644
--- a/libsoup/server/http2/soup-server-message-io-http2.c
+++ b/libsoup/server/http2/soup-server-message-io-http2.c
@@ -66,6 +66,8 @@ typedef struct {
gpointer started_user_data;
GHashTable *messages;
+
+ guint in_callback;
} SoupServerMessageIOHTTP2;
static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io,
@@ -324,6 +326,7 @@ io_write (SoupServerMessageIOHTTP2 *io,
if (io->write_buffer == NULL) {
io->written_bytes = 0;
+ g_assert (io->in_callback == 0);
io->write_buffer_size = nghttp2_session_mem_send (io->session, (const guint8**)&io->write_buffer);
if (io->write_buffer_size == 0) {
/* Done */
@@ -382,10 +385,10 @@ io_try_write (SoupServerMessageIOHTTP2 *io)
g_object_ref (conn);
- while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && nghttp2_session_want_write (io->session))
+ while (!error && soup_server_connection_get_io_data (conn) == (SoupServerMessageIO *)io && !io->in_callback && nghttp2_session_want_write (io->session))
io_write (io, &error);
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
+ if (io->in_callback || g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
g_clear_error (&error);
io->write_source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (io->ostream), NULL);
g_source_set_name (io->write_source, "Soup server HTTP/2 write source");
@@ -418,6 +421,7 @@ io_read (SoupServerMessageIOHTTP2 *io,
return FALSE;
}
+ g_assert (io->in_callback == 0);
ret = nghttp2_session_mem_recv (io->session, buffer, read);
if (ret < 0) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "HTTP/2 IO error: %s", nghttp2_strerror (ret));
@@ -496,6 +500,8 @@ on_begin_headers_callback (nghttp2_session *session,
if (frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_REQUEST)
return 0;
+ io->in_callback++;
+
msg_io = soup_server_message_io_http2_get_or_create_msg_io (io, frame->hd.stream_id);
h2_debug (io, msg_io, "[SESSION] Message IO created");
@@ -506,6 +512,8 @@ on_begin_headers_callback (nghttp2_session *session,
advance_state_from (msg_io, STATE_NONE, STATE_READ_HEADERS);
+ io->in_callback--;
+
return 0;
}
@@ -519,6 +527,7 @@ on_header_callback (nghttp2_session *session,
uint8_t flags,
void *user_data)
{
+ SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
SoupMessageIOHTTP2 *msg_io;
SoupServerMessage *msg;
@@ -532,6 +541,8 @@ on_header_callback (nghttp2_session *session,
if (!msg_io)
return 0;
+ io->in_callback++;
+
msg = msg_io->msg;
if (name[0] == ':') {
if (strcmp ((char *)name, ":method") == 0)
@@ -544,11 +555,14 @@ on_header_callback (nghttp2_session *session,
msg_io->path = g_strndup ((char *)value, valuelen);
else
g_debug ("Unknown header: %s = %s", name, value);
+ io->in_callback--;
return 0;
}
soup_message_headers_append_untrusted_data (soup_server_message_get_request_headers (msg),
(const char*)name, (const char*)value);
+
+ io->in_callback--;
return 0;
}
@@ -560,6 +574,7 @@ on_data_chunk_recv_callback (nghttp2_session *session,
size_t len,
void *user_data)
{
+ SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
SoupMessageIOHTTP2 *msg_io;
GBytes *bytes;
@@ -569,11 +584,15 @@ on_data_chunk_recv_callback (nghttp2_session *session,
h2_debug (user_data, msg_io, "[DATA] Received chunk, len=%zu, flags=%u, paused=%d", len, flags, msg_io->paused);
+ io->in_callback++;
+
bytes = g_bytes_new (data, len);
soup_message_body_got_chunk (soup_server_message_get_request_body (msg_io->msg), bytes);
soup_server_message_got_chunk (msg_io->msg, bytes);
g_bytes_unref (bytes);
+ io->in_callback--;
+
return 0;
}
@@ -586,10 +605,13 @@ on_data_source_read_callback (nghttp2_session *session,
nghttp2_data_source *source,
void *user_data)
{
+ SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
SoupMessageIOHTTP2 *msg_io;
gsize bytes_written = 0;
SoupMessageBody *response_body = (SoupMessageBody *)source->ptr;
+ io->in_callback++;
+
msg_io = nghttp2_session_get_stream_user_data (session, stream_id);
h2_debug (user_data, msg_io, "[SEND_BODY] paused=%d", msg_io->paused);
@@ -625,6 +647,8 @@ on_data_source_read_callback (nghttp2_session *session,
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
}
+ io->in_callback--;
+
return bytes_written;
}
@@ -689,6 +713,8 @@ on_frame_recv_callback (nghttp2_session *session,
if (!msg_io)
return 0;
+ io->in_callback++;
+
switch (frame->hd.type) {
case NGHTTP2_HEADERS: {
char *uri_string;
@@ -707,6 +733,7 @@ on_frame_recv_callback (nghttp2_session *session,
case NGHTTP2_DATA:
break;
default:
+ io->in_callback--;
return 0;
}
@@ -716,6 +743,7 @@ on_frame_recv_callback (nghttp2_session *session,
soup_server_message_io_http2_send_response (io, msg_io);
}
+ io->in_callback--;
return 0;
}
@@ -724,8 +752,11 @@ on_frame_send_callback (nghttp2_session *session,
const nghttp2_frame *frame,
void *user_data)
{
+ SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
SoupMessageIOHTTP2 *msg_io;
+ io->in_callback++;
+
msg_io = nghttp2_session_get_stream_user_data (session, frame->hd.stream_id);
h2_debug (user_data, msg_io, "[SEND] [%s]", soup_http2_frame_type_to_string (frame->hd.type));
@@ -747,6 +778,7 @@ on_frame_send_callback (nghttp2_session *session,
break;
}
+ io->in_callback--;
return 0;
}
@@ -756,6 +788,7 @@ on_stream_close_callback (nghttp2_session *session,
uint32_t error_code,
void *user_data)
{
+ SoupServerMessageIOHTTP2 *io = (SoupServerMessageIOHTTP2 *)user_data;
SoupMessageIOHTTP2 *msg_io;
msg_io = nghttp2_session_get_stream_user_data (session, stream_id);
@@ -763,9 +796,12 @@ on_stream_close_callback (nghttp2_session *session,
if (!msg_io)
return 0;
+ io->in_callback++;
+
if (!msg_io->paused)
soup_server_message_finish (msg_io->msg);
+ io->in_callback--;
return 0;
}